ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/background.C
Revision: 1.62
Committed: Sun Oct 3 21:44:13 2010 UTC (13 years, 7 months ago) by sf-exg
Content type: text/plain
Branch: MAIN
Changes since 1.61: +12 -7 lines
Log Message:
Really implement 'propscale' pixmap operation.

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