ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/background.C
Revision: 1.22
Committed: Fri Jan 4 21:25:57 2008 UTC (16 years, 4 months ago) by sasha
Content type: text/plain
Branch: MAIN
Changes since 1.21: +4 -0 lines
Log Message:
background redrawing timing tuning

File Contents

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