ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/xpm.C
Revision: 1.75
Committed: Mon Aug 27 21:02:41 2007 UTC (16 years, 9 months ago) by ayin
Content type: text/plain
Branch: MAIN
Changes since 1.74: +4 -4 lines
Log Message:
Fix coding style.

File Contents

# User Rev Content
1 root 1.34 /*----------------------------------------------------------------------*
2 pcg 1.12 * File: xpm.C
3 pcg 1.1 *----------------------------------------------------------------------*
4     *
5     * All portions of code are copyright by their respective author/s.
6     * Copyright (c) 1997 Carsten Haitzler <raster@zip.com.au>
7     * Copyright (c) 1997,1998 Oezguer Kesim <kesim@math.fu-berlin.de>
8     * Copyright (c) 1998-2001 Geoff Wing <gcw@pobox.com>
9 root 1.33 * Copyright (c) 2005-2006 Marc Lehmann <pcg@goof.com>
10 pcg 1.1 *
11     * This program is free software; you can redistribute it and/or modify
12     * it under the terms of the GNU General Public License as published by
13     * the Free Software Foundation; either version 2 of the License, or
14     * (at your option) any later version.
15     *
16     * This program is distributed in the hope that it will be useful,
17     * but WITHOUT ANY WARRANTY; without even the implied warranty of
18     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19     * GNU General Public License for more details.
20     *
21     * You should have received a copy of the GNU General Public License
22     * along with this program; if not, write to the Free Software
23     * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24     *---------------------------------------------------------------------*/
25    
26     #include "../config.h" /* NECESSARY */
27     #include "rxvt.h" /* NECESSARY */
28    
29 sasha 1.72 #define DO_TIMING_TEST 0
30    
31     #if DO_TIMING_TEST
32     #define TIMING_TEST_START(id) \
33     struct timeval timing_test_##id##_stv;\
34     gettimeofday (&timing_test_##id##_stv, NULL);
35    
36     #define TIMING_TEST_PRINT_RESULT(id) \
37     do{ struct timeval tv;gettimeofday (&tv, NULL); tv.tv_sec -= (timing_test_##id##_stv).tv_sec;\
38     fprintf (stderr, "%s: %s: %d: elapsed %ld usec\n", #id, __FILE__, __LINE__,\
39     tv.tv_sec * 1000000 + tv.tv_usec - (timing_test_##id##_stv).tv_usec);}while (0)
40    
41     #else
42     #define TIMING_TEST_START(id) do{}while (0)
43     #define TIMING_TEST_PRINT_RESULT(id) do{}while (0)
44     #endif
45    
46 pcg 1.1 /*
47 sasha 1.56 * Pixmap geometry string interpretation :
48     * Each geometry string contains zero or one scale/position
49     * adjustment and may optionally be followed by a colon and one or more
50     * colon-delimited pixmap operations.
51     * The following table shows the valid geometry strings and their
52     * affects on the background image :
53     *
54     * WxH+X+Y Set scaling to W% by H%, and position to X% by Y%.
55     * W and H are percentages of the terminal window size.
56     * X and Y are also percentages; e.g., +50+50 centers
57     * the image in the window.
58     * WxH+X Assumes Y == X
59     * WxH Assumes Y == X == 50 (centers the image)
60     * W+X+Y Assumes H == W
61     * W+X Assumes H == W and Y == X
62     * W Assumes H == W and Y == X == 50
63 pcg 1.1 *
64 sasha 1.56 * Adjusting position only :
65     * =+X+Y Set position to X% by Y% (absolute).
66     * =+X Set position to X% by X%.
67     * +X+Y Adjust position horizontally X% and vertically Y%
68     * from current position (relative).
69 sasha 1.58 * +X Adjust position horizontally X% and vertically X%
70 sasha 1.56 * from current position.
71 pcg 1.1 *
72 sasha 1.56 * Adjusting scale only :
73     * Wx0 Multiply horizontal scaling factor by W%
74     * 0xH Multiply vertical scaling factor by H%
75     * 0x0 No scaling (show image at normal size).
76     *
77     * Pixmap Operations : (should be prepended by a colon)
78     * tile Tile image. Scaling/position modifiers above will affect
79     * the tile size and origin.
80     * propscale When scaling, scale proportionally. That is, maintain the
81     * proper aspect ratio for the image. Any portion of the
82     * background not covered by the image is filled with the
83     * current background color.
84     * hscale Scale horizontally, tile vertically ?
85     * vscale Tile horizontally, scale vertically ?
86     * scale Scale both up and down
87     * auto Same as 100x100+50+50
88 pcg 1.1 */
89 sasha 1.56
90     #ifdef HAVE_BG_PIXMAP
91     bool
92     bgPixmap_t::window_size_sensitive ()
93     {
94 sasha 1.63 # ifdef XPM_BACKGROUND
95     # ifdef HAVE_AFTERIMAGE
96 sasha 1.58 if (original_asim != NULL)
97 sasha 1.63 # endif
98 sasha 1.58 {
99     if (h_scale != 0 || v_scale != 0)
100     return true;
101     }
102 sasha 1.63 # endif
103     # ifdef ENABLE_TRANSPARENCY
104 sasha 1.65 if (flags & isTransparent)
105 sasha 1.58 return true;
106 sasha 1.63 # endif
107 sasha 1.58 return false;
108 sasha 1.56 }
109    
110 sasha 1.70 bool bgPixmap_t::need_client_side_rendering ()
111     {
112     # ifdef HAVE_AFTERIMAGE
113     if (original_asim != NULL)
114     return true;
115 sasha 1.71 # endif
116 sasha 1.70 # ifdef ENABLE_TRANSPARENCY
117     if (flags & isTransparent)
118     {
119     if ((flags & blurNeeded)
120     || ((flags & tintNeeded) && !(flags & tintServerSide)))
121     return true;
122     }
123     # endif
124     return false;
125     }
126    
127 sasha 1.63 # ifdef XPM_BACKGROUND
128 sasha 1.58 static inline bool
129     check_set_scale_value (int geom_flags, int flag, unsigned int &scale, unsigned int new_value)
130     {
131     if (geom_flags & flag)
132     {
133     if (new_value > 1000)
134     new_value = 1000;
135     if (new_value != scale)
136     {
137     scale = new_value;
138     return true;
139     }
140     }
141     return false;
142     }
143    
144     static inline bool
145     check_set_align_value (int geom_flags, int flag, int &align, int new_value)
146     {
147     if (geom_flags & flag)
148     {
149     if (new_value < -100)
150     new_value = -100;
151     else if (new_value > 200)
152     new_value = 200;
153     if (new_value != align)
154     {
155     align = new_value;
156     return true;
157     }
158     }
159     return false;
160     }
161    
162 sasha 1.59 static inline int
163     make_align_position (int align, int window_size, int image_size)
164     {
165     int diff = window_size - image_size;
166     int smaller = MIN (image_size,window_size);
167    
168     if (align >= 0 && align <= 50)
169     return diff * align / 100;
170     else if (align > 50 && align <= 100)
171 sasha 1.62 return window_size - image_size - diff * (100 - align) / 100;
172 sasha 1.59 else if (align > 100 && align <= 200 )
173     return ((align - 100) * smaller / 100) + window_size - smaller;
174     else if (align > -100 && align < 0)
175     return ((align + 100) * smaller / 100) - image_size;
176     return 0;
177     }
178    
179 sasha 1.62 static inline int
180     make_clip_rectangle (int pos, int size, int target_size, int &dst_pos, int &dst_size)
181 sasha 1.59 {
182 sasha 1.62 int src_pos = 0;
183     dst_pos = 0;
184     dst_size = size;
185     if (pos < 0 && size > target_size)
186     {
187     src_pos = -pos;
188     dst_size += pos;
189     }
190     else if (pos > 0)
191     dst_pos = pos;
192    
193     if (dst_pos + dst_size > target_size)
194     dst_size = target_size - dst_pos;
195     return src_pos;
196 sasha 1.59 }
197    
198 sasha 1.56 bool
199 sasha 1.65 bgPixmap_t::set_geometry (const char *geom)
200 pcg 1.1 {
201 sasha 1.58 int geom_flags = 0, changed = 0;
202 root 1.28 int x = 0, y = 0;
203     unsigned int w = 0, h = 0;
204     unsigned int n;
205 sasha 1.65 unsigned long new_flags = (flags & (~geometryFlags));
206 root 1.28 char *p;
207 sasha 1.63 # define MAXLEN_GEOM 256 /* could be longer then regular geometry string */
208 pcg 1.1
209 pcg 1.7 if (geom == NULL)
210 sasha 1.56 return false;
211 root 1.28
212     char str[MAXLEN_GEOM];
213    
214 sasha 1.58 while (isspace(*geom)) ++geom;
215 root 1.17 if ((p = strchr (geom, ';')) == NULL)
216     p = strchr (geom, '\0');
217 root 1.28
218 pcg 1.7 n = (p - geom);
219 root 1.35 if (n < MAXLEN_GEOM)
220 pcg 1.7 {
221 sasha 1.58 char *ops;
222 sasha 1.65 new_flags |= geometrySet;
223 sasha 1.56
224 root 1.17 strncpy (str, geom, n);
225 pcg 1.7 str[n] = '\0';
226 sasha 1.58 if (str[0] == ':')
227     ops = &str[0];
228     else if (str[0] != 'x' && str[0] != 'X' && isalpha(str[0]))
229     ops = &str[0];
230 sasha 1.38 else
231     {
232 sasha 1.58 char *tmp;
233     ops = strchr (str, ':');
234     if (ops != NULL)
235     {
236     for (tmp = ops-1; tmp >= str && isspace(*tmp); --tmp);
237     *(++tmp) = '\0';
238     if (ops == tmp) ++ops;
239     }
240 sasha 1.38 }
241 root 1.28
242 sasha 1.58 if (ops > str || ops == NULL)
243 pcg 1.7 {
244 sasha 1.58 /* we have geometry string - let's handle it prior to applying ops */
245     geom_flags = XParseGeometry (str, &x, &y, &w, &h);
246 root 1.28
247 sasha 1.58 if ((geom_flags & XValue) && !(geom_flags & YValue))
248 pcg 1.7 {
249 sasha 1.58 y = x;
250     geom_flags |= YValue;
251 pcg 1.7 }
252 sasha 1.58
253 sasha 1.65 if (flags & geometrySet)
254 sasha 1.58 {/* new geometry is an adjustment to the old one ! */
255     if ((geom_flags & WidthValue) && (geom_flags & HeightValue))
256     {
257     if (w == 0 && h != 0)
258     {
259     w = h_scale;
260     h = (v_scale * h) / 100;
261     }
262     else if (h == 0 && w != 0)
263     {
264     w = (h_scale * w) / 100;
265     h = v_scale;
266     }
267     }
268     if (geom_flags & XValue)
269     {
270     if (str[0] != '=')
271     {
272     y += v_align;
273     x += h_align;
274     }
275     }
276 pcg 1.7 }
277 sasha 1.58 else /* setting up geometry from scratch */
278 pcg 1.7 {
279 sasha 1.58 if (!(geom_flags & XValue))
280     {/* use default geometry - centered */
281 sasha 1.65 x = y = defaultAlign;
282 sasha 1.58 }
283     else if (!(geom_flags & YValue))
284     y = x;
285 root 1.28
286 sasha 1.58 if ((geom_flags & (WidthValue|HeightValue)) == 0)
287     {/* use default geometry - scaled */
288 sasha 1.65 w = h = defaultScale;
289 sasha 1.58 }
290     else if (geom_flags & WidthValue)
291     {
292     if (!(geom_flags & HeightValue))
293 sasha 1.62 h = w;
294 sasha 1.58 }
295     else
296 sasha 1.62 w = h;
297 pcg 1.7 }
298 sasha 1.58 } /* done parsing geometry string */
299 sasha 1.65 else if (!(flags & geometrySet))
300 sasha 1.58 { /* default geometry - scaled and centered */
301 sasha 1.65 x = y = defaultAlign;
302     w = h = defaultScale;
303 sasha 1.58 }
304    
305 sasha 1.65 if (!(flags & geometrySet))
306 sasha 1.58 geom_flags |= WidthValue|HeightValue|XValue|YValue;
307 root 1.28
308 sasha 1.58 if (ops)
309 pcg 1.7 {
310 sasha 1.58 while (*ops)
311     {
312     while (*ops == ':' || isspace(*ops)) ++ops;
313 sasha 1.63 # define CHECK_GEOM_OPS(op_str) (strncasecmp (ops, (op_str), sizeof(op_str)-1) == 0)
314 sasha 1.58 if (CHECK_GEOM_OPS("tile"))
315     {
316     w = h = 0;
317     geom_flags |= WidthValue|HeightValue;
318     }
319     else if (CHECK_GEOM_OPS("propscale"))
320     {
321     if (w == 0 && h == 0)
322     {
323     w = 100;
324     geom_flags |= WidthValue;
325     }
326 sasha 1.65 new_flags |= propScale;
327 sasha 1.58 }
328     else if (CHECK_GEOM_OPS("hscale"))
329     {
330     if (w == 0)
331     w = 100;
332     h = 0;
333     geom_flags |= WidthValue|HeightValue;
334     }
335     else if (CHECK_GEOM_OPS("vscale"))
336     {
337     if (h == 0)
338     h = 100;
339     w = 0;
340     geom_flags |= WidthValue|HeightValue;
341     }
342     else if (CHECK_GEOM_OPS("scale"))
343     {
344     if (h == 0)
345     h = 100;
346     if (w == 0)
347     w = 100;
348     geom_flags |= WidthValue|HeightValue;
349     }
350     else if (CHECK_GEOM_OPS("auto"))
351     {
352     w = h = 100;
353     x = y = 50;
354     geom_flags |= WidthValue|HeightValue|XValue|YValue;
355     }
356 sasha 1.63 # undef CHECK_GEOM_OPS
357 sasha 1.58 while (*ops != ':' && *ops != '\0') ++ops;
358     } /* done parsing ops */
359 pcg 1.7 }
360 sasha 1.56
361 sasha 1.58 if (check_set_scale_value (geom_flags, WidthValue, h_scale, w))
362     ++changed;
363     if (check_set_scale_value (geom_flags, HeightValue, v_scale, h))
364     ++changed;
365     if (check_set_align_value (geom_flags, XValue, h_align, x))
366     ++changed;
367     if (check_set_align_value (geom_flags, YValue, v_align, y))
368     ++changed;
369 pcg 1.1 }
370 root 1.28
371 sasha 1.56 if (new_flags != flags)
372     {
373     flags = new_flags;
374     changed++;
375     }
376 sasha 1.58 //fprintf( stderr, "flags = %lX, scale = %ux%u, align=%+d%+d\n",
377     // flags, h_scale, v_scale, h_align, v_align);
378 sasha 1.56 return (changed > 0);
379 pcg 1.1 }
380    
381 sasha 1.63 # ifdef HAVE_AFTERIMAGE
382 sasha 1.60 bool
383 sasha 1.63 bgPixmap_t::render_asim (ASImage *background, ARGB32 background_tint)
384 sasha 1.59 {
385 sasha 1.60 if (target == NULL)
386     return false;
387 sasha 1.59
388     int target_width = (int)target->szHint.width;
389     int target_height = (int)target->szHint.height;
390 sasha 1.60 int new_pmap_width = target_width, new_pmap_height = target_height;
391     ASImage *result = NULL;
392    
393     int x = 0;
394     int y = 0;
395 sasha 1.59 int w = h_scale * target_width / 100;
396     int h = v_scale * target_height / 100;
397    
398 sasha 1.72 TIMING_TEST_START (asim);
399    
400 sasha 1.60 if (original_asim)
401     {
402     x = make_align_position (h_align, target_width, w > 0 ? w : (int)original_asim->width);
403     y = make_align_position (v_align, target_height, h > 0 ? h : (int)original_asim->height);
404     }
405    
406 sasha 1.62 if (original_asim == NULL
407     || x >= target_width
408     || y >= target_height
409     || (w > 0 && x + w <= 0)
410     || (h > 0 && y + h <= 0))
411 sasha 1.60 {
412     if (background)
413     {
414 sasha 1.62 new_pmap_width = background->width;
415     new_pmap_height = background->height;
416     result = background;
417     if (background_tint != TINT_LEAVE_SAME)
418     {
419     ASImage* tmp = tile_asimage (target->asv, background, 0, 0,
420     target_width, target_height, background_tint,
421     ASA_XImage, 100, ASIMAGE_QUALITY_DEFAULT);
422     if (tmp)
423     result = tmp;
424     }
425 sasha 1.60 }
426     else
427 sasha 1.62 new_pmap_width = new_pmap_height = 0;
428 sasha 1.60 }
429     else
430     {
431     result = original_asim;
432     if ((w > 0 && w != original_asim->width)
433     || (h > 0 && h != original_asim->height))
434     {
435     result = scale_asimage (target->asv, original_asim,
436     w > 0 ? w : original_asim->width,
437     h > 0 ? h : original_asim->height,
438     background ? ASA_ASImage : ASA_XImage,
439     100, ASIMAGE_QUALITY_DEFAULT);
440     }
441     if (background == NULL)
442     {/* if tiling - pixmap has to be sized exactly as the image */
443     if (h_scale == 0)
444     new_pmap_width = result->width;
445     if (v_scale == 0)
446     new_pmap_height = result->height;
447 sasha 1.62 /* we also need to tile our image in one or both directions */
448     if (h_scale == 0 || v_scale == 0)
449     {
450     ASImage *tmp = tile_asimage (target->asv, result,
451     (h_scale > 0) ? 0 : (int)result->width - x,
452     (v_scale > 0) ? 0 : (int)result->height - y,
453     result->width, result->height,
454     TINT_LEAVE_SAME, ASA_XImage,
455     100, ASIMAGE_QUALITY_DEFAULT);
456     if (tmp)
457     {
458     if (result != original_asim)
459     destroy_asimage (&result);
460     result = tmp;
461     }
462     }
463 sasha 1.60 }
464     else
465     {/* if blending background and image - pixmap has to be sized same as target window */
466     ASImageLayer *layers = create_image_layers (2);
467     ASImage *merged_im = NULL;
468    
469     layers[0].im = background;
470     layers[0].clip_width = target_width;
471     layers[0].clip_height = target_height;
472     layers[0].tint = background_tint;
473     layers[1].im = result;
474     if (w <= 0)
475     {/* tile horizontally */
476 sasha 1.62 while (x > 0) x -= (int)result->width;
477     layers[1].dst_x = x;
478     layers[1].clip_width = result->width+target_width;
479 sasha 1.60 }
480     else
481     {/* clip horizontally */
482 sasha 1.62 layers[1].dst_x = x;
483     layers[1].clip_width = result->width;
484 sasha 1.60 }
485     if (h <= 0)
486     {
487 sasha 1.62 while (y > 0) y -= (int)result->height;
488     layers[1].dst_y = y;
489     layers[1].clip_height = result->height + target_height;
490 sasha 1.60 }
491     else
492     {
493 sasha 1.62 layers[1].dst_y = y;
494     layers[1].clip_height = result->height;
495 sasha 1.60 }
496     if (target->rs[Rs_blendtype])
497     {
498     layers[1].merge_scanlines = blend_scanlines_name2func (target->rs[Rs_blendtype]);
499     if (layers[1].merge_scanlines == NULL)
500     layers[1].merge_scanlines = alphablend_scanlines;
501     }
502     ASImage *tmp = merge_layers (target->asv, layers, 2, target_width, target_height,
503     ASA_XImage, 0, ASIMAGE_QUALITY_DEFAULT);
504     if (tmp)
505     {
506     if (result != original_asim)
507     destroy_asimage (&result);
508     result = tmp;
509     }
510     free (layers);
511     }
512     }
513 sasha 1.72 TIMING_TEST_PRINT_RESULT (asim);
514 sasha 1.60
515     if (pixmap)
516     {
517     if (result == NULL
518     || pmap_width != new_pmap_width
519     || pmap_height != new_pmap_height
520     || pmap_depth != target->depth)
521     {
522     XFreePixmap (target->dpy, pixmap);
523     pixmap = None;
524     }
525     }
526    
527     if (result)
528     {
529     XGCValues gcv;
530     GC gc;
531    
532     /* create Pixmap */
533     if (pixmap == None)
534     {
535     pixmap = XCreatePixmap (target->dpy, target->vt, new_pmap_width, new_pmap_height, target->depth);
536     pmap_width = new_pmap_width;
537     pmap_height = new_pmap_height;
538     pmap_depth = target->depth;
539     }
540     /* fill with background color ( if result's not completely overlapping it)*/
541     gcv.foreground = target->pix_colors[Color_bg];
542     gc = XCreateGC (target->dpy, target->vt, GCForeground, &gcv);
543    
544 sasha 1.62 int src_x = 0, src_y = 0, dst_x = 0, dst_y = 0;
545     int dst_width = result->width, dst_height = result->height;
546     if (background == NULL)
547 sasha 1.60 {
548 sasha 1.62 if (h_scale > 0)
549     src_x = make_clip_rectangle (x, result->width, new_pmap_width, dst_x, dst_width);
550     if (v_scale > 0)
551     src_y = make_clip_rectangle (y, result->height, new_pmap_height, dst_y, dst_height);
552    
553     if (dst_x > 0 || dst_y > 0
554     || dst_x + dst_width < new_pmap_width
555     || dst_y + dst_height < new_pmap_height)
556     {
557     XFillRectangle (target->dpy, pixmap, gc, 0, 0, new_pmap_width, new_pmap_height);
558     }
559 sasha 1.60 }
560 sasha 1.62
561 sasha 1.60 /* put result on pixmap */
562 sasha 1.62 if (dst_x < new_pmap_width && dst_y < new_pmap_height)
563     asimage2drawable (target->asv, pixmap, result, gc, src_x, src_y, dst_x, dst_y, dst_width, dst_height, True);
564    
565     if (result != background && result != original_asim)
566     destroy_asimage (&result);
567 sasha 1.60
568     XFreeGC (target->dpy, gc);
569 sasha 1.72 TIMING_TEST_PRINT_RESULT (asim);
570 sasha 1.60 }
571 sasha 1.59
572 sasha 1.60 return true;
573 sasha 1.59 }
574 sasha 1.63 # endif /* HAVE_AFTERIMAGE */
575 sasha 1.59
576 sasha 1.65 bool
577     bgPixmap_t::set_file (const char *file)
578 pcg 1.1 {
579 root 1.21 char *f;
580 pcg 1.1
581 pcg 1.9 assert (file != NULL);
582 pcg 1.1
583 pcg 1.7 if (*file != '\0')
584     {
585 sasha 1.63 # ifdef HAVE_AFTERIMAGE
586 sasha 1.65 if (target->asimman == NULL)
587 ayin 1.75 target->asimman = create_generic_imageman (target->rs[Rs_path]);
588 sasha 1.38 if ((f = strchr (file, ';')) == NULL)
589 ayin 1.75 original_asim = get_asimage (target->asimman, file, 0xFFFFFFFF, 100);
590 sasha 1.38 else
591     {
592 ayin 1.42 size_t len = f - file;
593     f = (char *)malloc (len + 1);
594     strncpy (f, file, len);
595     f[len] = '\0';
596 ayin 1.75 original_asim = get_asimage (target->asimman, f, 0xFFFFFFFF, 100);
597     free (f);
598 sasha 1.38 }
599 sasha 1.65 return (original_asim != NULL);
600 sasha 1.63 # endif
601 pcg 1.1 }
602 sasha 1.65 return false;
603 pcg 1.1 }
604    
605 sasha 1.63 # endif /* XPM_BACKGROUND */
606    
607     # ifdef ENABLE_TRANSPARENCY
608 sasha 1.65 bool
609     bgPixmap_t::set_transparent ()
610     {
611     if (!(flags & isTransparent))
612     {
613     flags |= isTransparent;
614     return true;
615     }
616 ayin 1.73 return false;
617 sasha 1.65 }
618    
619     bool
620     bgPixmap_t::set_blur_radius (const char *geom)
621     {
622     int changed = 0;
623     unsigned int hr, vr;
624     int junk;
625     int geom_flags = XParseGeometry (geom, &junk, &junk, &hr, &vr);
626     if (!(geom_flags&WidthValue))
627     hr = 1;
628     if (!(geom_flags&HeightValue))
629     vr = hr;
630    
631     if (h_blurRadius != hr)
632     {
633     ++changed;
634     h_blurRadius = hr;
635     }
636     if (v_blurRadius != vr)
637     {
638     ++changed;
639     v_blurRadius = vr;
640     }
641 sasha 1.70 if (v_blurRadius == 0 && h_blurRadius == 0)
642     flags &= ~blurNeeded;
643     else
644     flags |= blurNeeded;
645 sasha 1.65 return (changed>0);
646     }
647    
648     static inline unsigned long
649     compute_tint_shade_flags (rxvt_color *tint, int shade)
650     {
651     unsigned long flags = 0;
652 sasha 1.72 rgba c (rgba::MAX_CC,rgba::MAX_CC,rgba::MAX_CC);
653    
654     if (tint)
655     {
656     tint->get (c);
657     # define IS_COMPONENT_WHOLESOME(cmp) ((cmp) <= 0x000700 || (cmp) >= 0x00f700)
658     if (IS_COMPONENT_WHOLESOME (c.r)
659     && IS_COMPONENT_WHOLESOME (c.g)
660     && IS_COMPONENT_WHOLESOME (c.b))
661     flags |= bgPixmap_t::tintWholesome;
662     # undef IS_COMPONENT_WHOLESOME
663     }
664 sasha 1.65
665 sasha 1.72 if ((shade > 0 && shade < 100) || (shade > 100 && shade < 200))
666 sasha 1.65 flags |= bgPixmap_t::tintNeeded;
667     else if (tint)
668     {
669     if ((c.r > 0x000700 || c.g > 0x000700 || c.b > 0x000700)
670     && (c.r < 0x00f700 || c.g < 0x00f700 || c.b < 0x00f700))
671     {
672 sasha 1.72 flags |= bgPixmap_t::tintNeeded;
673 sasha 1.65 }
674     }
675 sasha 1.72
676     if (flags & bgPixmap_t::tintNeeded)
677     {
678     if (flags & bgPixmap_t::tintWholesome)
679     flags |= bgPixmap_t::tintServerSide;
680     #if XFT
681     /* TODO: add logic for XRENDER tinting */
682     flags |= bgPixmap_t::tintServerSide;
683     #endif
684     }
685    
686 sasha 1.65 return flags;
687     }
688    
689     bool
690     bgPixmap_t::set_tint (rxvt_color &new_tint)
691     {
692     if (tint != new_tint)
693     {
694     unsigned long new_flags = compute_tint_shade_flags (&new_tint, shade);
695     tint = new_tint;
696     flags = (flags & ~tintFlags) | new_flags | tintSet;
697     return true;
698     }
699     return false;
700     }
701    
702     bool
703     bgPixmap_t::unset_tint ()
704     {
705     unsigned long new_flags = compute_tint_shade_flags (NULL, shade);
706    
707     if (new_flags != (flags & tintFlags))
708     {
709     flags = (flags&~tintFlags)|new_flags;
710     return true;
711     }
712     return false;
713     }
714    
715     bool
716     bgPixmap_t::set_shade (const char *shade_str)
717     {
718     int new_shade = (shade_str) ? atoi (shade_str) : 0;
719    
720     if (new_shade == 100)
721     new_shade = 0;
722    
723     if (new_shade != shade)
724     {
725 sasha 1.72 unsigned long new_flags = compute_tint_shade_flags ((flags & tintSet) ? &tint : NULL, new_shade);
726 sasha 1.65 shade = new_shade;
727     flags = (flags & ~tintFlags) | new_flags;
728     return true;
729     }
730     return false;
731     }
732    
733    
734 sasha 1.63 /* make_transparency_pixmap()
735     * Builds a pixmap sized the same as terminal window, with depth same as the root window
736     * that pixmap contains tiled portion of the root pixmap that is supposed to be covered by
737     * our window.
738     */
739 sasha 1.66 unsigned long
740 sasha 1.65 bgPixmap_t::make_transparency_pixmap ()
741 sasha 1.63 {
742 sasha 1.66 unsigned long result = 0;
743    
744 sasha 1.63 if (target == NULL)
745 sasha 1.66 return 0;
746 sasha 1.63
747 sasha 1.64 /* root dimentions may change from call to call - but Display structure should
748     * be always up-to-date, so let's use it :
749     */
750     Window root = target->display->root;
751     int screen = target->display->screen;
752     Display *dpy = target->dpy;
753     int root_width = DisplayWidth (dpy, screen);
754     int root_height = DisplayHeight (dpy, screen);
755     unsigned int root_pmap_width, root_pmap_height;
756     int window_width = target->szHint.width;
757     int window_height = target->szHint.height;
758 sasha 1.63 int sx, sy;
759 sasha 1.65 XGCValues gcv;
760 sasha 1.63
761 sasha 1.72 TIMING_TEST_START (tp);
762 sasha 1.64 target->get_window_origin (sx, sy);
763    
764     /* check if we are outside of the visible part of the virtual screen : */
765     if (sx + window_width <= 0 || sy + window_height <= 0
766     || sx >= root_width || sy >= root_height)
767 sasha 1.66 return 0;
768 sasha 1.64
769     if (root_pixmap != None)
770     {/* we want to validate the pixmap and get it's size at the same time : */
771     int junk;
772     unsigned int ujunk;
773     /* root pixmap may be bad - allow a error */
774     target->allowedxerror = -1;
775     if (!XGetGeometry (dpy, root_pixmap, &root, &junk, &junk, &root_pmap_width, &root_pmap_height, &ujunk, &ujunk))
776     root_pixmap = None;
777     target->allowedxerror = 0;
778     }
779    
780     Pixmap tiled_root_pmap = XCreatePixmap (dpy, root, window_width, window_height, root_depth);
781     GC gc = NULL;
782 sasha 1.63
783 sasha 1.64 if (tiled_root_pmap == None) /* something really bad happened - abort */
784 sasha 1.66 return 0;
785 sasha 1.63
786 sasha 1.64 if (root_pixmap == None)
787     { /* use tricks to obtain the root background image :*/
788     /* we want to create Overrideredirect window overlapping out window
789     with background type of Parent Relative and then grab it */
790     XSetWindowAttributes attr;
791     Window src;
792     bool success = false;
793    
794     attr.background_pixmap = ParentRelative;
795     attr.backing_store = Always;
796     attr.event_mask = ExposureMask;
797     attr.override_redirect = True;
798     src = XCreateWindow (dpy, root, sx, sy, window_width, window_height, 0,
799     CopyFromParent, CopyFromParent, CopyFromParent,
800     CWBackPixmap|CWBackingStore|CWOverrideRedirect|CWEventMask,
801     &attr);
802    
803     if (src != None)
804     {
805     XEvent event;
806     int ev_count = 0;
807     XGrabServer (dpy);
808     XMapRaised (dpy, src);
809     XSync (dpy, False);
810     /* XSync should get window where it's properly exposed,
811     * but to be on the safe side - let's check for the actuall event to arrive : */
812     while (XCheckWindowEvent (dpy, src, ExposureMask, &event))
813     ++ev_count;
814     if (ev_count > 0);
815     { /* hooray! - we can grab the image! */
816     gc = XCreateGC (dpy, root, 0, NULL);
817 sasha 1.66 if (gc)
818     {
819     XCopyArea (dpy, src, tiled_root_pmap, gc, 0, 0, window_width, window_height, 0, 0);
820     success = true;
821     }
822 sasha 1.64 }
823     XDestroyWindow (dpy, src);
824     XUngrabServer (dpy);
825     //fprintf (stderr, "%s:%d: ev_count = %d\n", __FUNCTION__, __LINE__, ev_count);
826     }
827     if (!success)
828     {
829     XFreePixmap (dpy, tiled_root_pmap);
830     tiled_root_pmap = None;
831     }
832 sasha 1.66 else
833     result |= transpPmapTiled;
834 sasha 1.64 }
835     else
836     {/* strightforward pixmap copy */
837     gcv.tile = root_pixmap;
838     gcv.fill_style = FillTiled;
839     while (sx < 0) sx += (int)window_width;
840     while (sy < 0) sy += (int)window_height;
841     gcv.ts_x_origin = -sx;
842     gcv.ts_y_origin = -sy;
843     gc = XCreateGC (dpy, root, GCFillStyle | GCTile | GCTileStipXOrigin | GCTileStipYOrigin, &gcv);
844 sasha 1.66 if (gc)
845     {
846     XFillRectangle (dpy, tiled_root_pmap, gc, 0, 0, window_width, window_height);
847     result |= transpPmapTiled;
848     }
849 sasha 1.64 }
850 sasha 1.72 TIMING_TEST_PRINT_RESULT (tp);
851 sasha 1.63
852 sasha 1.72 if (tiled_root_pmap != None)
853     {
854     if ((flags & tintNeeded) && !need_client_side_rendering ())
855     {
856     if (flags & tintWholesome)
857     {
858     /* In this case we can tint image server-side getting significant
859     * performance improvements, as we eliminate XImage transfer
860     */
861     gcv.foreground = Pixel (tint);
862     gcv.function = GXand;
863     gcv.fill_style = FillSolid;
864     if (gc)
865     XChangeGC (dpy, gc, GCFillStyle | GCForeground | GCFunction, &gcv);
866     else
867     gc = XCreateGC (dpy, root, GCFillStyle | GCForeground | GCFunction, &gcv);
868     if (gc)
869     {
870     XFillRectangle (dpy, tiled_root_pmap, gc, 0, 0, window_width, window_height);
871     result |= transpPmapTinted;
872     }
873     }
874     else
875     {
876     #if XFT /* TODO : implement proper detection of XRENDER, as XFT may be present without XRENDER ! */
877     rgba c (rgba::MAX_CC,rgba::MAX_CC,rgba::MAX_CC);
878     if (flags & tintSet)
879     tint.get (c);
880     if (shade > 0 && shade < 100)
881     {
882     c.r = (c.r * shade) / 100;
883     c.g = (c.g * shade) / 100;
884     c.b = (c.b * shade) / 100;
885     }
886     else if( shade > 100 && shade < 200)
887     {
888     c.r = (c.r * (200 - shade)) / 100;
889     c.g = (c.g * (200 - shade)) / 100;
890     c.b = (c.b * (200 - shade)) / 100;
891     }
892    
893     XRenderPictFormat pf;
894     pf.type = PictTypeDirect;
895     pf.depth = 32;
896     pf.direct.redMask = 0xff;
897     pf.direct.greenMask = 0xff;
898     pf.direct.blueMask = 0xff;
899     pf.direct.alphaMask = 0xff;
900    
901     XRenderPictFormat *solid_format = XRenderFindFormat (dpy,
902     (PictFormatType|
903     PictFormatDepth|
904     PictFormatRedMask|
905     PictFormatGreenMask|
906     PictFormatBlueMask|
907     PictFormatAlphaMask),
908     &pf,
909     0);
910     XRenderPictFormat *root_format = XRenderFindVisualFormat (dpy, DefaultVisualOfScreen (ScreenOfDisplay (dpy, target->display->screen)));
911     XRenderPictureAttributes pa ;
912    
913     Picture back_pic = XRenderCreatePicture (dpy, tiled_root_pmap, root_format, 0, &pa);
914    
915     pa.repeat = True;
916    
917     Pixmap overlay_pmap = XCreatePixmap (dpy, root, 1, 1, 32);
918     Picture overlay_pic = XRenderCreatePicture (dpy, overlay_pmap, solid_format, CPRepeat, &pa);
919     XFreePixmap (dpy, overlay_pmap);
920    
921     pa.component_alpha = True;
922     Pixmap mask_pmap = XCreatePixmap (dpy, root, 1, 1, 32);
923     Picture mask_pic = XRenderCreatePicture (dpy, mask_pmap, solid_format, CPRepeat|CPComponentAlpha, &pa);
924     XFreePixmap (dpy, mask_pmap);
925    
926     if (mask_pic && overlay_pic && back_pic)
927     {
928     XRenderColor mask_c;
929    
930     memset (&mask_c, (shade > 100) ? 0xFF : 0x0, sizeof(mask_c));
931     mask_c.alpha = 0xffff;
932     XRenderFillRectangle (dpy, PictOpSrc, overlay_pic, &mask_c, 0, 0, 1, 1);
933     memset (&mask_c, 0x0, sizeof(mask_c));
934     mask_c.alpha = 0;
935     if (c.r == c.b && c.b == c.g) /* pure shading */
936     {
937     mask_c.red = mask_c.green = mask_c.blue = 0xffff-c.r;
938     XRenderFillRectangle (dpy, PictOpSrc, mask_pic, &mask_c, 0, 0, 1, 1);
939     XRenderComposite (dpy, PictOpOver, overlay_pic, mask_pic, back_pic, 0, 0, 0, 0, 0, 0, window_width, window_height);
940     }
941     else
942     {
943     mask_c.red = 0xffff-c.r;
944     XRenderFillRectangle (dpy, PictOpSrc, mask_pic, &mask_c, 0, 0, 1, 1);
945     XRenderComposite (dpy, PictOpOver, overlay_pic, mask_pic, back_pic, 0, 0, 0, 0, 0, 0, window_width, window_height);
946     mask_c.red = 0;
947     mask_c.green = 0xffff-c.g;
948     XRenderFillRectangle (dpy, PictOpSrc, mask_pic, &mask_c, 0, 0, 1, 1);
949     XRenderComposite (dpy, PictOpOver, overlay_pic, mask_pic, back_pic, 0, 0, 0, 0, 0, 0, window_width, window_height);
950     mask_c.green = 0;
951     mask_c.blue = 0xffff-c.b;
952     XRenderFillRectangle (dpy, PictOpSrc, mask_pic, &mask_c, 0, 0, 1, 1);
953     XRenderComposite (dpy, PictOpOver, overlay_pic, mask_pic, back_pic, 0, 0, 0, 0, 0, 0, window_width, window_height);
954     }
955     result |= transpPmapTinted;
956     }
957     XRenderFreePicture (dpy, mask_pic);
958     XRenderFreePicture (dpy, overlay_pic);
959     XRenderFreePicture (dpy, back_pic);
960     #endif
961     }
962     }
963     if (pixmap)
964     XFreePixmap (dpy, pixmap);
965     pixmap = tiled_root_pmap;
966     pmap_width = window_width;
967     pmap_height = window_height;
968     pmap_depth = root_depth;
969     }
970 sasha 1.65
971 sasha 1.72 if (gc)
972     XFreeGC (dpy, gc);
973    
974     TIMING_TEST_PRINT_RESULT (tp);
975 sasha 1.66
976 sasha 1.72 return result;
977 sasha 1.63 }
978 sasha 1.64
979 sasha 1.65 bool
980     bgPixmap_t::set_root_pixmap ()
981     {
982     Pixmap new_root_pixmap = None;
983    
984     new_root_pixmap = target->get_pixmap_property (XA_XROOTPMAP_ID);
985     if (new_root_pixmap == None)
986     new_root_pixmap = target->get_pixmap_property (XA_ESETROOT_PMAP_ID);
987    
988     if (new_root_pixmap != root_pixmap)
989     {
990     root_pixmap = new_root_pixmap;
991     return true;
992     }
993     return false;
994     }
995 sasha 1.63 # endif /* ENABLE_TRANSPARENCY */
996    
997 sasha 1.67 # ifndef HAVE_AFTERIMAGE
998     static void ShadeXImage(rxvt_term *term, XImage* srcImage, int shade, int rm, int gm, int bm);
999 sasha 1.71 # endif
1000 sasha 1.67
1001    
1002 sasha 1.65 bool
1003 sasha 1.66 bgPixmap_t::render ()
1004 sasha 1.65 {
1005 sasha 1.66 unsigned long background_flags = 0;
1006    
1007     if (target == NULL)
1008     return false;
1009    
1010     invalidate();
1011 sasha 1.65 # ifdef ENABLE_TRANSPARENCY
1012     if (flags & isTransparent)
1013     {
1014     /* we need to re-generate transparency pixmap in that case ! */
1015 sasha 1.66 background_flags = make_transparency_pixmap ();
1016     if (background_flags == 0)
1017     return false;
1018 sasha 1.67 else if ((background_flags & transpTransformations) == (flags & transpTransformations)
1019     && pmap_depth == target->depth)
1020     flags = flags & ~isInvalid;
1021 sasha 1.65 }
1022     # endif
1023 sasha 1.66
1024     XImage *result = NULL;
1025 sasha 1.65 # ifdef HAVE_AFTERIMAGE
1026 sasha 1.66 if (original_asim
1027     || (background_flags & transpTransformations) != (flags & transpTransformations))
1028     {
1029     ASImage *background = NULL;
1030     ARGB32 as_tint = TINT_LEAVE_SAME;
1031     if (background_flags)
1032     background = pixmap2ximage (target->asv, pixmap, 0, 0, pmap_width, pmap_height, AllPlanes, 100);
1033    
1034 sasha 1.71 # ifdef ENABLE_TRANSPARENCY
1035 sasha 1.66 if (!(background_flags & transpPmapTinted) && (flags & tintNeeded))
1036     {
1037     ShadingInfo as_shade;
1038     as_shade.shading = (shade == 0) ? 100 : shade;
1039    
1040     rgba c (rgba::MAX_CC,rgba::MAX_CC,rgba::MAX_CC);
1041 sasha 1.68 if (flags & tintSet)
1042     tint.get (c);
1043 sasha 1.66 as_shade.tintColor.red = c.r;
1044     as_shade.tintColor.green = c.g;
1045     as_shade.tintColor.blue = c.b;
1046    
1047     as_tint = shading2tint32 (&as_shade);
1048     }
1049 sasha 1.70 if (!(background_flags & transpPmapBlured) && (flags & blurNeeded) && background != NULL)
1050     {
1051     ASImage* tmp = blur_asimage_gauss (target->asv, background, h_blurRadius, v_blurRadius, 0xFFFFFFFF,
1052     (original_asim == NULL || tint == TINT_LEAVE_SAME)?ASA_XImage:ASA_ASImage,
1053     100, ASIMAGE_QUALITY_DEFAULT);
1054     if (tmp)
1055     {
1056     destroy_asimage (&background);
1057     background = tmp;
1058     }
1059     }
1060 sasha 1.71 # endif
1061 sasha 1.70
1062 sasha 1.66 if (render_asim (background, as_tint))
1063     flags = flags & ~isInvalid;
1064     if (background)
1065     destroy_asimage (&background);
1066     }
1067     else if (background_flags && pmap_depth != target->depth)
1068     {
1069     result = XGetImage (target->dpy, pixmap, 0, 0, pmap_width, pmap_height, AllPlanes, ZPixmap);
1070     }
1071     # else /* our own client-side tinting */
1072 sasha 1.67 if (background_flags && (flags & isInvalid))
1073 sasha 1.66 {
1074     result = XGetImage (target->dpy, pixmap, 0, 0, pmap_width, pmap_height, AllPlanes, ZPixmap);
1075     if (result != NULL && !(background_flags & transpPmapTinted) && (flags & tintNeeded))
1076     {
1077     rgba c (rgba::MAX_CC,rgba::MAX_CC,rgba::MAX_CC);
1078 sasha 1.68 if (flags & tintSet)
1079     tint.get (c);
1080 sasha 1.67 ShadeXImage (target, result, shade, c.r, c.g, c.b);
1081 sasha 1.66 }
1082     }
1083 sasha 1.71 # endif /* HAVE_AFTERIMAGE */
1084 sasha 1.66 if (result != NULL)
1085     {
1086     GC gc = XCreateGC (target->dpy, target->vt, 0UL, NULL);
1087     if (gc)
1088     {
1089 sasha 1.71 if (/*pmap_depth != target->depth &&*/ pixmap != None)
1090 sasha 1.66 {
1091     XFreePixmap (target->dpy, pixmap);
1092     pixmap = None;
1093     }
1094     if (pixmap == None)
1095     {
1096     pixmap = XCreatePixmap (target->dpy, target->vt, result->width, result->height, target->depth);
1097     pmap_width = result->width;
1098     pmap_height = result->height;
1099     pmap_depth = target->depth;
1100     }
1101 sasha 1.71 if (pmap_depth != result->depth)
1102     { /* Bad Match error will ensue ! stupid X !!!! */
1103     if( result->depth == 24 && pmap_depth == 32)
1104     result->depth = 32;
1105     else if( result->depth == 32 && pmap_depth == 24)
1106     result->depth = 24;
1107     else
1108     {
1109     /* TODO: implement image recoding */
1110     }
1111     }
1112     if (pmap_depth == result->depth)
1113     XPutImage (target->dpy, pixmap, gc, result, 0, 0, 0, 0, result->width, result->height);
1114 sasha 1.66 XFreeGC (target->dpy, gc);
1115     flags = flags & ~isInvalid;
1116     }
1117     XDestroyImage (result);
1118     }
1119    
1120     if (flags & isInvalid)
1121     {
1122     if (pixmap != None)
1123     {
1124     XFreePixmap (target->dpy, pixmap);
1125     pixmap = None;
1126     }
1127     }
1128    
1129     apply ();
1130    
1131 sasha 1.65 return true;
1132     }
1133    
1134 sasha 1.64 bool
1135     bgPixmap_t::set_target (rxvt_term *new_target)
1136     {
1137     if (new_target)
1138     if (target != new_target)
1139     {
1140     target = new_target;
1141     # ifdef ENABLE_TRANSPARENCY
1142     root_depth = DefaultDepthOfScreen (ScreenOfDisplay (target->dpy, target->display->screen));
1143     # endif
1144     return true;
1145     }
1146     return false;
1147     }
1148    
1149 sasha 1.63 void
1150 sasha 1.66 bgPixmap_t::apply()
1151 sasha 1.63 {
1152     if (target)
1153     {
1154     if (pixmap != None)
1155     { /* set target's background to pixmap */
1156     # ifdef ENABLE_TRANSPARENCY
1157 sasha 1.65 if (flags & isTransparent)
1158 sasha 1.63 {
1159     XSetWindowBackgroundPixmap (target->dpy, target->parent[0], pixmap);
1160     XSetWindowBackgroundPixmap (target->dpy, target->vt, ParentRelative);
1161 sasha 1.66 # if HAVE_SCROLLBARS
1162 sasha 1.63 if (target->scrollBar.win)
1163     XSetWindowBackgroundPixmap (target->dpy, target->scrollBar.win, ParentRelative);
1164 sasha 1.66 # endif
1165 sasha 1.63 }
1166     else
1167     # endif
1168     {
1169     /* force old pixmap dereference in case it was transparent before :*/
1170 sasha 1.66 XSetWindowBackground (target->dpy, target->parent[0], target->pix_colors[Color_border]);
1171 sasha 1.63 XSetWindowBackgroundPixmap (target->dpy, target->vt, pixmap);
1172     /* do we also need to set scrollbar's background here ? */
1173 sasha 1.66 # if HAVE_SCROLLBARS
1174     if (target->scrollBar.win)
1175     XSetWindowBackground (target->dpy, target->scrollBar.win, target->pix_colors[Color_border]);
1176     # endif
1177 sasha 1.63 }
1178     }
1179     else
1180     { /* set target background to a pixel */
1181 sasha 1.66 XSetWindowBackground (target->dpy, target->parent[0], target->pix_colors[Color_border]);
1182 sasha 1.63 XSetWindowBackground (target->dpy, target->vt, target->pix_colors[Color_bg]);
1183     /* do we also need to set scrollbar's background here ? */
1184 sasha 1.66 # if HAVE_SCROLLBARS
1185     if (target->scrollBar.win)
1186     XSetWindowBackground (target->dpy, target->scrollBar.win, target->pix_colors[Color_border]);
1187     # endif
1188 sasha 1.63 }
1189     /* don't want Expose on the parent */
1190     XClearArea (target->dpy, target->parent[0], 0, 0, 0, 0, False);
1191     /* do want Expose on the vt */
1192     XClearArea (target->dpy, target->parent[0], 0, 0, 0, 0, True);
1193 sasha 1.71 # if HAVE_SCROLLBARS
1194 sasha 1.66 if (target->scrollBar.win)
1195     {
1196     target->scrollBar.setIdle ();
1197     target->scrollbar_show (0);
1198     }
1199 sasha 1.71 # endif
1200 sasha 1.69 /* Is that really neccessary? we did a XClearArea to generate Expose events alreday ! */
1201 sasha 1.71 target->want_refresh = 1;
1202     # ifdef ENABLE_TRANSPARENCY
1203     target->want_full_refresh = 1;
1204     # endif
1205 sasha 1.69 /* TODO: why do we need a flush here ??? It causes segfault on resize ! */
1206     // target->flush ();
1207 sasha 1.63 }
1208     }
1209    
1210 sasha 1.64 void
1211     rxvt_term::get_window_origin (int &x, int &y)
1212     {
1213     Window cr;
1214     XTranslateCoordinates (dpy, parent[0], display->root, 0, 0, &x, &y, &cr);
1215 sasha 1.70 /* fprintf( stderr, "origin is %+d%+d\n", x, y);*/
1216 sasha 1.64 }
1217    
1218     Pixmap
1219     rxvt_term::get_pixmap_property (int prop_id)
1220     {
1221     if (prop_id > 0 && prop_id < NUM_XA)
1222     if (xa[prop_id])
1223     {
1224 ayin 1.74 int aformat;
1225 sasha 1.64 unsigned long nitems, bytes_after;
1226     Atom atype;
1227     unsigned char *prop = NULL;
1228     int result = XGetWindowProperty (dpy, display->root, xa[prop_id],
1229     0L, 1L, False, XA_PIXMAP, &atype, &aformat,
1230     &nitems, &bytes_after, &prop);
1231     if (result == Success && prop && atype == XA_PIXMAP)
1232     {
1233     return *(Pixmap *)prop;
1234     }
1235     }
1236     return None;
1237     }
1238    
1239 sasha 1.71 /*
1240     * Check our parents are still who we think they are.
1241     * Do transparency updates if required
1242     */
1243     int
1244     rxvt_term::update_background ()
1245     {
1246     bgPixmap.invalidate();
1247     /* no chance of real time refresh if we are blurring ! */
1248     if (bgPixmap.invalid_since + 0.5 < NOW && !(bgPixmap.flags & bgPixmap_t::blurNeeded))
1249     bgPixmap.render();
1250     else
1251     {
1252     update_background_ev.stop ();
1253     if (!bgPixmap.need_client_side_rendering())
1254     update_background_ev.start (NOW + .05);
1255     else if (bgPixmap.flags & bgPixmap_t::blurNeeded)
1256     update_background_ev.start (NOW + .2); /* very slow !!! */
1257     else
1258     update_background_ev.start (NOW + .07);
1259     }
1260     return 0;
1261     }
1262    
1263     void
1264     rxvt_term::update_background_cb (time_watcher &w)
1265     {
1266     bgPixmap.render ();
1267     }
1268     #endif /* HAVE_BG_PIXMAP */
1269 sasha 1.63
1270 sasha 1.71 #if defined(ENABLE_TRANSPARENCY) && !defined(HAVE_AFTERIMAGE)
1271 ayin 1.39 /* taken from aterm-0.4.2 */
1272    
1273     typedef uint32_t RUINT32T;
1274    
1275 ayin 1.43 static void
1276     ShadeXImage(rxvt_term *term, XImage* srcImage, int shade, int rm, int gm, int bm)
1277 ayin 1.39 {
1278     int sh_r, sh_g, sh_b;
1279     RUINT32T mask_r, mask_g, mask_b;
1280     RUINT32T *lookup, *lookup_r, *lookup_g, *lookup_b;
1281     unsigned int lower_lim_r, lower_lim_g, lower_lim_b;
1282     unsigned int upper_lim_r, upper_lim_g, upper_lim_b;
1283     int i;
1284    
1285     Visual *visual = term->visual;
1286    
1287 sasha 1.67 if (visual->c_class != TrueColor || srcImage->format != ZPixmap) return ;
1288 ayin 1.39
1289 sasha 1.67 if (shade == 0)
1290     shade = 100;
1291 sasha 1.72
1292 ayin 1.39 /* for convenience */
1293     mask_r = visual->red_mask;
1294     mask_g = visual->green_mask;
1295     mask_b = visual->blue_mask;
1296    
1297     /* boring lookup table pre-initialization */
1298     switch (srcImage->bits_per_pixel) {
1299     case 15:
1300     if ((mask_r != 0x7c00) ||
1301     (mask_g != 0x03e0) ||
1302     (mask_b != 0x001f))
1303     return;
1304     lookup = (RUINT32T *) malloc (sizeof (RUINT32T)*(32+32+32));
1305     lookup_r = lookup;
1306     lookup_g = lookup+32;
1307     lookup_b = lookup+32+32;
1308     sh_r = 10;
1309     sh_g = 5;
1310     sh_b = 0;
1311     break;
1312     case 16:
1313     if ((mask_r != 0xf800) ||
1314     (mask_g != 0x07e0) ||
1315     (mask_b != 0x001f))
1316     return;
1317     lookup = (RUINT32T *) malloc (sizeof (RUINT32T)*(32+64+32));
1318     lookup_r = lookup;
1319     lookup_g = lookup+32;
1320     lookup_b = lookup+32+64;
1321     sh_r = 11;
1322     sh_g = 5;
1323     sh_b = 0;
1324     break;
1325     case 24:
1326     if ((mask_r != 0xff0000) ||
1327     (mask_g != 0x00ff00) ||
1328     (mask_b != 0x0000ff))
1329     return;
1330     lookup = (RUINT32T *) malloc (sizeof (RUINT32T)*(256+256+256));
1331     lookup_r = lookup;
1332     lookup_g = lookup+256;
1333     lookup_b = lookup+256+256;
1334     sh_r = 16;
1335     sh_g = 8;
1336     sh_b = 0;
1337     break;
1338     case 32:
1339     if ((mask_r != 0xff0000) ||
1340     (mask_g != 0x00ff00) ||
1341     (mask_b != 0x0000ff))
1342     return;
1343     lookup = (RUINT32T *) malloc (sizeof (RUINT32T)*(256+256+256));
1344     lookup_r = lookup;
1345     lookup_g = lookup+256;
1346     lookup_b = lookup+256+256;
1347     sh_r = 16;
1348     sh_g = 8;
1349     sh_b = 0;
1350     break;
1351     default:
1352     return; /* we do not support this color depth */
1353     }
1354    
1355     /* prepare limits for color transformation (each channel is handled separately) */
1356     if (shade < 0) {
1357     shade = -shade;
1358     if (shade < 0) shade = 0;
1359     if (shade > 100) shade = 100;
1360    
1361     lower_lim_r = 65535-rm;
1362     lower_lim_g = 65535-gm;
1363     lower_lim_b = 65535-bm;
1364    
1365     lower_lim_r = 65535-(unsigned int)(((RUINT32T)lower_lim_r)*((RUINT32T)shade)/100);
1366     lower_lim_g = 65535-(unsigned int)(((RUINT32T)lower_lim_g)*((RUINT32T)shade)/100);
1367     lower_lim_b = 65535-(unsigned int)(((RUINT32T)lower_lim_b)*((RUINT32T)shade)/100);
1368    
1369     upper_lim_r = upper_lim_g = upper_lim_b = 65535;
1370     } else {
1371     if (shade < 0) shade = 0;
1372     if (shade > 100) shade = 100;
1373    
1374     lower_lim_r = lower_lim_g = lower_lim_b = 0;
1375    
1376     upper_lim_r = (unsigned int)((((RUINT32T)rm)*((RUINT32T)shade))/100);
1377     upper_lim_g = (unsigned int)((((RUINT32T)gm)*((RUINT32T)shade))/100);
1378     upper_lim_b = (unsigned int)((((RUINT32T)bm)*((RUINT32T)shade))/100);
1379     }
1380    
1381     /* switch red and blue bytes if necessary, we need it for some weird XServers like XFree86 3.3.3.1 */
1382     if ((srcImage->bits_per_pixel == 24) && (mask_r >= 0xFF0000 ))
1383     {
1384     unsigned int tmp;
1385    
1386     tmp = lower_lim_r;
1387     lower_lim_r = lower_lim_b;
1388     lower_lim_b = tmp;
1389    
1390     tmp = upper_lim_r;
1391     upper_lim_r = upper_lim_b;
1392     upper_lim_b = tmp;
1393     }
1394    
1395     /* fill our lookup tables */
1396     for (i = 0; i <= mask_r>>sh_r; i++)
1397     {
1398     RUINT32T tmp;
1399     tmp = ((RUINT32T)i)*((RUINT32T)(upper_lim_r-lower_lim_r));
1400     tmp += ((RUINT32T)(mask_r>>sh_r))*((RUINT32T)lower_lim_r);
1401     lookup_r[i] = (tmp/65535)<<sh_r;
1402     }
1403     for (i = 0; i <= mask_g>>sh_g; i++)
1404     {
1405     RUINT32T tmp;
1406     tmp = ((RUINT32T)i)*((RUINT32T)(upper_lim_g-lower_lim_g));
1407     tmp += ((RUINT32T)(mask_g>>sh_g))*((RUINT32T)lower_lim_g);
1408     lookup_g[i] = (tmp/65535)<<sh_g;
1409     }
1410     for (i = 0; i <= mask_b>>sh_b; i++)
1411     {
1412     RUINT32T tmp;
1413     tmp = ((RUINT32T)i)*((RUINT32T)(upper_lim_b-lower_lim_b));
1414     tmp += ((RUINT32T)(mask_b>>sh_b))*((RUINT32T)lower_lim_b);
1415     lookup_b[i] = (tmp/65535)<<sh_b;
1416     }
1417    
1418     /* apply table to input image (replacing colors by newly calculated ones) */
1419     switch (srcImage->bits_per_pixel)
1420     {
1421     case 15:
1422     {
1423     unsigned short *p1, *pf, *p, *pl;
1424     p1 = (unsigned short *) srcImage->data;
1425     pf = (unsigned short *) (srcImage->data + srcImage->height * srcImage->bytes_per_line);
1426     while (p1 < pf)
1427     {
1428     p = p1;
1429     pl = p1 + srcImage->width;
1430     for (; p < pl; p++)
1431     {
1432     *p = lookup_r[(*p & 0x7c00)>>10] |
1433     lookup_g[(*p & 0x03e0)>> 5] |
1434     lookup_b[(*p & 0x001f)];
1435     }
1436     p1 = (unsigned short *) ((char *) p1 + srcImage->bytes_per_line);
1437     }
1438     break;
1439     }
1440     case 16:
1441     {
1442     unsigned short *p1, *pf, *p, *pl;
1443     p1 = (unsigned short *) srcImage->data;
1444     pf = (unsigned short *) (srcImage->data + srcImage->height * srcImage->bytes_per_line);
1445     while (p1 < pf)
1446     {
1447     p = p1;
1448     pl = p1 + srcImage->width;
1449     for (; p < pl; p++)
1450     {
1451     *p = lookup_r[(*p & 0xf800)>>11] |
1452     lookup_g[(*p & 0x07e0)>> 5] |
1453     lookup_b[(*p & 0x001f)];
1454     }
1455     p1 = (unsigned short *) ((char *) p1 + srcImage->bytes_per_line);
1456     }
1457     break;
1458     }
1459     case 24:
1460     {
1461     unsigned char *p1, *pf, *p, *pl;
1462     p1 = (unsigned char *) srcImage->data;
1463     pf = (unsigned char *) (srcImage->data + srcImage->height * srcImage->bytes_per_line);
1464     while (p1 < pf)
1465     {
1466     p = p1;
1467     pl = p1 + srcImage->width * 3;
1468     for (; p < pl; p += 3)
1469     {
1470     p[0] = lookup_r[(p[0] & 0xff0000)>>16];
1471     p[1] = lookup_r[(p[1] & 0x00ff00)>> 8];
1472     p[2] = lookup_r[(p[2] & 0x0000ff)];
1473     }
1474     p1 = (unsigned char *) ((char *) p1 + srcImage->bytes_per_line);
1475     }
1476     break;
1477     }
1478     case 32:
1479     {
1480     RUINT32T *p1, *pf, *p, *pl;
1481     p1 = (RUINT32T *) srcImage->data;
1482     pf = (RUINT32T *) (srcImage->data + srcImage->height * srcImage->bytes_per_line);
1483    
1484     while (p1 < pf)
1485     {
1486     p = p1;
1487     pl = p1 + srcImage->width;
1488     for (; p < pl; p++)
1489     {
1490     *p = lookup_r[(*p & 0xff0000)>>16] |
1491     lookup_g[(*p & 0x00ff00)>> 8] |
1492     lookup_b[(*p & 0x0000ff)] |
1493     (*p & ~0xffffff);
1494     }
1495     p1 = (RUINT32T *) ((char *) p1 + srcImage->bytes_per_line);
1496     }
1497     break;
1498     }
1499     }
1500    
1501     free (lookup);
1502     }
1503 sasha 1.71 #endif /* defined(ENABLE_TRANSPARENCY) && !defined(HAVE_AFTERIMAGE) */
1504 sasha 1.70
1505     #if 0 /* replaced by a bgPixmap_t::render() - leve here temporarily for reference */
1506     void
1507 ayin 1.39 rxvt_term::check_our_parents_cb (time_watcher &w)
1508     {
1509 sasha 1.66
1510 sasha 1.63 int i, aformat, rootdepth;
1511 ayin 1.39 unsigned long nitems, bytes_after;
1512     Atom atype;
1513     unsigned char *prop = NULL;
1514     Window root, oldp, *list;
1515     Pixmap rootpixmap = None;
1516     XWindowAttributes wattr, wrootattr;
1517     int sx, sy;
1518     Window cr;
1519 sasha 1.52 unsigned int rootpixmap_w = 0, rootpixmap_h = 0;
1520 ayin 1.39
1521     if (!option (Opt_transparent))
1522 sasha 1.63 return; /* Don't try any more */
1523 sasha 1.52
1524 ayin 1.39 XGetWindowAttributes (dpy, display->root, &wrootattr);
1525     rootdepth = wrootattr.depth;
1526    
1527     XGetWindowAttributes (dpy, parent[0], &wattr);
1528    
1529     if (rootdepth != wattr.depth)
1530     {
1531     if (am_transparent)
1532     {
1533     XSetWindowBackground (dpy, vt, pix_colors_focused[Color_bg]);
1534     am_transparent = am_pixmap_trans = 0;
1535     }
1536    
1537 sasha 1.63 return; /* Don't try any more */
1538 ayin 1.39 }
1539    
1540     /* Get all X ops out of the queue so that our information is up-to-date. */
1541     XSync (dpy, False);
1542    
1543     XTranslateCoordinates (dpy, parent[0], display->root,
1544     0, 0, &sx, &sy, &cr);
1545     /* check if we are outside of the visible part of the virtual screen : */
1546 ayin 1.51 if( sx + (int)szHint.width <= 0 || sy + (int)szHint.height <= 0
1547     || sx >= wrootattr.width || sy >= wrootattr.height )
1548 ayin 1.39 return /* 0 */ ;
1549     /*
1550     * Make the frame window set by the window manager have
1551     * the root background. Some window managers put multiple nested frame
1552     * windows for each client, so we have to take care about that.
1553     */
1554     i = (xa[XA_XROOTPMAP_ID]
1555     && XGetWindowProperty (dpy, display->root, xa[XA_XROOTPMAP_ID],
1556     0L, 1L, False, XA_PIXMAP, &atype, &aformat,
1557     &nitems, &bytes_after, &prop) == Success);
1558    
1559     if (!i || prop == NULL)
1560     i = (xa[XA_ESETROOT_PMAP_ID]
1561     && XGetWindowProperty (dpy, display->root, xa[XA_ESETROOT_PMAP_ID],
1562     0L, 1L, False, XA_PIXMAP, &atype, &aformat,
1563     &nitems, &bytes_after, &prop) == Success);
1564    
1565 ayin 1.61 if (!i || prop == NULL)
1566 sasha 1.52 rootpixmap = None;
1567 ayin 1.39 else
1568     {
1569 sasha 1.52 int junk;
1570     unsigned int ujunk;
1571     /* root pixmap may be bad - allow a error */
1572     allowedxerror = -1;
1573     if ((rootpixmap = *(Pixmap *)prop) != None)
1574     if (!XGetGeometry (dpy, rootpixmap, &root, &junk, &junk, &rootpixmap_w, &rootpixmap_h, &ujunk, &ujunk))
1575     rootpixmap = None;
1576     allowedxerror = 0;
1577 ayin 1.39 }
1578    
1579 sasha 1.52 if (prop != NULL)
1580     XFree (prop);
1581    
1582     if (rootpixmap != None)
1583 ayin 1.39 {
1584 sasha 1.49 Bool success = False;
1585 ayin 1.40 GC gc = NULL;
1586 ayin 1.39 XGCValues gcvalue;
1587 sasha 1.52 int shade = 100;
1588     rgba c (rgba::MAX_CC,rgba::MAX_CC,rgba::MAX_CC);
1589     Bool whole_tint = False, no_tint = True;
1590 ayin 1.51
1591 sasha 1.52 while (sx < 0) sx += (int)wrootattr.width;
1592     while (sy < 0) sy += (int)wrootattr.height;
1593 ayin 1.39
1594 sasha 1.52 if (rs[Rs_shade])
1595     shade = atoi (rs[Rs_shade]);
1596     if (ISSET_PIXCOLOR (Color_tint))
1597     pix_colors_focused [Color_tint].get (c);
1598 sasha 1.49 #define IS_COMPONENT_WHOLESOME(c) ((c) <=0x000700 || (c)>=0x00f700)
1599 sasha 1.52 if (shade >= 100)
1600     whole_tint = (IS_COMPONENT_WHOLESOME(c.r)
1601     && IS_COMPONENT_WHOLESOME(c.g)
1602     && IS_COMPONENT_WHOLESOME(c.b));
1603     no_tint = (c.r >= 0x00f700 && c.g >= 0x00f700 && c.b >= 0x00f700);
1604 sasha 1.49 #undef IS_COMPONENT_WHOLESOME
1605 sasha 1.64
1606     bgPixmap.make_transparency_pixmap();
1607 sasha 1.49
1608 sasha 1.52 if (whole_tint && !no_tint)
1609     {
1610     }
1611     success = True;
1612     #ifdef HAVE_AFTERIMAGE
1613 sasha 1.55 if (rs[Rs_blurradius] || bgPixmap.original_asim != NULL || (!whole_tint && (!no_tint || shade !=100)))
1614 sasha 1.52 {
1615     ARGB32 tint = TINT_LEAVE_SAME;
1616     ASImage *back_im = NULL;
1617    
1618 sasha 1.55 back_im = pixmap2ximage (asv, bgPixmap.pixmap, 0, 0, szHint.width, szHint.height, AllPlanes, 100);
1619 sasha 1.52 if (back_im != NULL)
1620     {
1621     if (!whole_tint && (!no_tint || shade !=100))
1622     {
1623     ShadingInfo as_shade;
1624     as_shade.shading = shade;
1625     as_shade.tintColor.red = c.r;
1626     as_shade.tintColor.green = c.g;
1627     as_shade.tintColor.blue = c.b;
1628     tint = shading2tint32 (&as_shade);
1629     }
1630    
1631     if (rs[Rs_blurradius] && back_im)
1632     {
1633 sasha 1.53 ASImage* tmp;
1634     int junk;
1635     unsigned int hr = 1, vr = 1;
1636     int flags = XParseGeometry (rs[Rs_blurradius], &junk, &junk, &hr, &vr);
1637     if (!(flags&WidthValue))
1638     hr = 1;
1639     if (!(flags&HeightValue))
1640     vr = hr;
1641     tmp = blur_asimage_gauss (asv, back_im, hr, vr, 0xFFFFFFFF,
1642 sasha 1.55 (bgPixmap.original_asim == NULL || tint == TINT_LEAVE_SAME)?ASA_XImage:ASA_ASImage,
1643 sasha 1.53 100, ASIMAGE_QUALITY_DEFAULT);
1644 sasha 1.52 if (tmp)
1645     {
1646     destroy_asimage (&back_im);
1647     back_im = tmp;
1648     }
1649     }
1650 sasha 1.62 /* TODO: temporary fix - redo the logic, so that same function can do both
1651     transparency and non-transparency */
1652 sasha 1.63 bgPixmap.render_asim (back_im, tint);
1653 sasha 1.62 destroy_asimage (&back_im);
1654 sasha 1.52
1655     } /* back_im != NULL */
1656     else
1657     success = False;
1658     }
1659     #else /* HAVE_AFTERIMAGE */
1660     if (!whole_tint && (!no_tint || shade !=100))
1661     {
1662 sasha 1.55 XImage *image = XGetImage (dpy, bgPixmap.pixmap, 0, 0, szHint.width, szHint.height, AllPlanes, ZPixmap);
1663 sasha 1.52 success = False;
1664     if (image != NULL)
1665     {
1666     if (gc == NULL)
1667     gc = XCreateGC (dpy, vt, 0UL, &gcvalue);
1668     if (ISSET_PIXCOLOR (Color_tint) || shade != 100)
1669     ShadeXImage (this, image, shade, c.r, c.g, c.b);
1670 sasha 1.55 XPutImage (dpy, bgPixmap.pixmap, gc, image, 0, 0, 0, 0, image->width, image->height);
1671 sasha 1.52 XDestroyImage (image);
1672     success = True;
1673     }
1674     }
1675 ayin 1.39 #endif /* HAVE_AFTERIMAGE */
1676 sasha 1.52
1677 ayin 1.51 if (gc != NULL)
1678 ayin 1.39 XFreeGC (dpy, gc);
1679 sasha 1.63
1680 sasha 1.66 bgPixmap.apply();
1681 ayin 1.39 if (!success)
1682     am_pixmap_trans = 0;
1683     else
1684     {
1685     am_transparent = am_pixmap_trans = 1;
1686     }
1687 sasha 1.52 } /* rootpixmap != None */
1688 ayin 1.39
1689     if (am_pixmap_trans)
1690     {
1691 sasha 1.63 if (scrollBar.win)
1692     {
1693     scrollBar.setIdle ();
1694     scrollbar_show (0);
1695     }
1696 ayin 1.39
1697 sasha 1.63 if (am_transparent)
1698     {
1699     want_refresh = want_full_refresh = 1;
1700     if (am_pixmap_trans)
1701     flush ();
1702     }
1703 ayin 1.39 }
1704 sasha 1.70 }
1705 sasha 1.66 #endif