ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/background.C
Revision: 1.207
Committed: Thu May 10 21:48:55 2012 UTC (12 years ago) by sf-exg
Content type: text/plain
Branch: MAIN
Changes since 1.206: +44 -6 lines
Log Message:
Properly handle the case of a bg image with alpha channel.

If the visual supports an alpha channel we copy the alpha channel of the
image and premultiply alpha as expected by existing compositing
managers. Otherwise, we composite the image with the bg color.

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.147 * Copyright (c) 2005-2008 Marc Lehmann <schmorp@schmorp.de>
7 sasha 1.1 * Copyright (c) 2007 Sasha Vasko <sasha@aftercode.net>
8 sf-exg 1.83 * Copyright (c) 2010 Emanuele Giaquinta <e.giaquinta@glauco.it>
9 sasha 1.1 *
10     * This program is free software; you can redistribute it and/or modify
11     * it under the terms of the GNU General Public License as published by
12     * the Free Software Foundation; either version 2 of the License, or
13     * (at your option) any later version.
14     *
15     * This program is distributed in the hope that it will be useful,
16     * but WITHOUT ANY WARRANTY; without even the implied warranty of
17     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18     * GNU General Public License for more details.
19     *
20     * You should have received a copy of the GNU General Public License
21     * along with this program; if not, write to the Free Software
22     * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23     *---------------------------------------------------------------------*/
24    
25 sf-exg 1.200 #include <math.h>
26 sasha 1.1 #include "../config.h" /* NECESSARY */
27     #include "rxvt.h" /* NECESSARY */
28    
29 sf-exg 1.109 #if XRENDER
30     # include <X11/extensions/Xrender.h>
31     #endif
32    
33 sf-exg 1.118 #ifndef FilterConvolution
34     #define FilterConvolution "convolution"
35     #endif
36    
37 sf-exg 1.195 #ifndef RepeatPad
38     #define RepeatPad True
39     #endif
40    
41 sasha 1.1 #ifdef HAVE_BG_PIXMAP
42 sf-exg 1.188 # if XRENDER
43     static Picture
44     create_xrender_mask (Display *dpy, Drawable drawable, Bool argb, Bool component_alpha)
45     {
46     Pixmap pixmap = XCreatePixmap (dpy, drawable, 1, 1, argb ? 32 : 8);
47    
48     XRenderPictFormat *format = XRenderFindStandardFormat (dpy, argb ? PictStandardARGB32 : PictStandardA8);
49     XRenderPictureAttributes pa;
50     pa.repeat = True;
51     pa.component_alpha = component_alpha;
52     Picture mask = XRenderCreatePicture (dpy, pixmap, format, CPRepeat | CPComponentAlpha, &pa);
53    
54     XFreePixmap (dpy, pixmap);
55    
56     return mask;
57     }
58     # endif
59    
60 root 1.14 void
61 sf-exg 1.142 rxvt_term::bg_destroy ()
62 sasha 1.11 {
63 sf-exg 1.55 #ifdef HAVE_PIXBUF
64     if (pixbuf)
65     g_object_unref (pixbuf);
66     #endif
67    
68 sf-exg 1.142 if (bg_pixmap)
69     XFreePixmap (dpy, bg_pixmap);
70 sasha 1.11 }
71 sasha 1.2
72 sasha 1.1 bool
73 sf-exg 1.142 rxvt_term::bg_set_position (int x, int y)
74 sf-exg 1.121 {
75    
76     if (target_x != x
77     || target_y != y)
78     {
79     target_x = x;
80     target_y = y;
81     return true;
82     }
83     return false;
84     }
85    
86     bool
87 sf-exg 1.142 rxvt_term::bg_window_size_sensitive ()
88 sasha 1.1 {
89 sasha 1.13 # ifdef ENABLE_TRANSPARENCY
90 sf-exg 1.143 if (bg_flags & BG_IS_TRANSPARENT)
91 sasha 1.13 return true;
92     # endif
93    
94 sasha 1.2 # ifdef BG_IMAGE_FROM_FILE
95 sf-exg 1.144 if (bg_flags & BG_IS_FROM_FILE)
96 sasha 1.1 {
97 sf-exg 1.143 if (bg_flags & BG_IS_SIZE_SENSITIVE)
98 sasha 1.1 return true;
99     }
100     # endif
101 sasha 1.13
102     return false;
103     }
104    
105 sf-exg 1.37 bool
106 sf-exg 1.142 rxvt_term::bg_window_position_sensitive ()
107 sasha 1.13 {
108 sasha 1.1 # ifdef ENABLE_TRANSPARENCY
109 sf-exg 1.143 if (bg_flags & BG_IS_TRANSPARENT)
110 sasha 1.1 return true;
111     # endif
112 sasha 1.13
113     # ifdef BG_IMAGE_FROM_FILE
114 sf-exg 1.144 if (bg_flags & BG_IS_FROM_FILE)
115 sasha 1.13 {
116 sf-exg 1.143 if (bg_flags & BG_ROOT_ALIGN)
117 sasha 1.13 return true;
118     }
119     # endif
120    
121 sasha 1.1 return false;
122 sf-exg 1.117 }
123 sasha 1.1
124 sasha 1.2 # ifdef BG_IMAGE_FROM_FILE
125 sasha 1.1 static inline int
126     make_align_position (int align, int window_size, int image_size)
127     {
128 sf-exg 1.66 if (align >= 0 && align <= 100)
129 sf-exg 1.206 return lerp (0, window_size - image_size, align);
130 sf-exg 1.205 else if (align > 100)
131 sf-exg 1.206 return lerp (window_size - image_size, window_size, align - 100);
132 sf-exg 1.205 else
133 sf-exg 1.206 return lerp (-image_size, 0, align + 100);
134 sasha 1.1 }
135    
136     static inline int
137     make_clip_rectangle (int pos, int size, int target_size, int &dst_pos, int &dst_size)
138     {
139     int src_pos = 0;
140 sf-exg 1.66 dst_pos = pos;
141 sasha 1.1 dst_size = size;
142 sf-exg 1.60 if (pos < 0)
143 sasha 1.1 {
144     src_pos = -pos;
145 sf-exg 1.66 dst_pos = 0;
146 sasha 1.1 dst_size += pos;
147     }
148    
149 sf-exg 1.197 min_it (dst_size, target_size - dst_pos);
150 sasha 1.1 return src_pos;
151     }
152    
153     bool
154 sf-exg 1.142 rxvt_term::bg_set_geometry (const char *geom, bool update)
155 sasha 1.1 {
156 sf-exg 1.110 bool changed = false;
157     int geom_flags = 0;
158 sf-exg 1.198 int x = h_align;
159     int y = v_align;
160     unsigned int w = h_scale;
161     unsigned int h = v_scale;
162 sf-exg 1.185 unsigned long new_flags = 0;
163 sasha 1.1
164     if (geom == NULL)
165     return false;
166    
167 sf-exg 1.163 if (geom[0])
168 sf-exg 1.122 {
169 sf-exg 1.163 char **arr = rxvt_strsplit (':', geom);
170 sf-exg 1.131
171 sf-exg 1.173 for (int i = 0; arr[i]; i++)
172 sasha 1.1 {
173 sf-exg 1.160 if (!strcasecmp (arr[i], "style=tiled"))
174     {
175     new_flags = BG_TILE;
176     w = h = noScale;
177     x = y = 0;
178     geom_flags = WidthValue|HeightValue|XValue|YValue;
179     }
180     else if (!strcasecmp (arr[i], "style=aspect-stretched"))
181     {
182 sf-exg 1.176 new_flags = BG_KEEP_ASPECT;
183 sf-exg 1.164 w = h = windowScale;
184 sf-exg 1.160 x = y = centerAlign;
185 sf-exg 1.164 geom_flags = WidthValue|HeightValue|XValue|YValue;
186 sf-exg 1.160 }
187     else if (!strcasecmp (arr[i], "style=stretched"))
188     {
189     new_flags = 0;
190     w = h = windowScale;
191     geom_flags = WidthValue|HeightValue;
192     }
193     else if (!strcasecmp (arr[i], "style=centered"))
194     {
195     new_flags = 0;
196     w = h = noScale;
197     x = y = centerAlign;
198     geom_flags = WidthValue|HeightValue|XValue|YValue;
199     }
200     else if (!strcasecmp (arr[i], "style=root-tiled"))
201     {
202     new_flags = BG_TILE|BG_ROOT_ALIGN;
203     w = h = noScale;
204     geom_flags = WidthValue|HeightValue;
205     }
206     else if (!strcasecmp (arr[i], "op=tile"))
207     new_flags |= BG_TILE;
208 sf-exg 1.176 else if (!strcasecmp (arr[i], "op=keep-aspect"))
209     new_flags |= BG_KEEP_ASPECT;
210     else if (!strcasecmp (arr[i], "op=root-align"))
211 sf-exg 1.160 new_flags |= BG_ROOT_ALIGN;
212    
213     // deprecated
214     else if (!strcasecmp (arr[i], "tile"))
215 sf-exg 1.122 {
216 sf-exg 1.156 new_flags |= BG_TILE;
217 sf-exg 1.122 w = h = noScale;
218     geom_flags |= WidthValue|HeightValue;
219     }
220 sf-exg 1.133 else if (!strcasecmp (arr[i], "propscale"))
221 sf-exg 1.122 {
222 sf-exg 1.176 new_flags |= BG_KEEP_ASPECT;
223 sf-exg 1.177 w = h = windowScale;
224     geom_flags |= WidthValue|HeightValue;
225 sf-exg 1.122 }
226 sf-exg 1.161 else if (!strcasecmp (arr[i], "hscale"))
227     {
228 sf-exg 1.162 new_flags |= BG_TILE;
229 sf-exg 1.161 w = windowScale;
230     h = noScale;
231     geom_flags |= WidthValue|HeightValue;
232     }
233     else if (!strcasecmp (arr[i], "vscale"))
234     {
235 sf-exg 1.162 new_flags |= BG_TILE;
236 sf-exg 1.161 h = windowScale;
237     w = noScale;
238     geom_flags |= WidthValue|HeightValue;
239     }
240 sf-exg 1.133 else if (!strcasecmp (arr[i], "scale"))
241 sf-exg 1.122 {
242 sf-exg 1.161 w = h = windowScale;
243 sf-exg 1.122 geom_flags |= WidthValue|HeightValue;
244     }
245 sf-exg 1.161 else if (!strcasecmp (arr[i], "auto"))
246     {
247     w = h = windowScale;
248     x = y = centerAlign;
249     geom_flags |= WidthValue|HeightValue|XValue|YValue;
250     }
251 sf-exg 1.133 else if (!strcasecmp (arr[i], "root"))
252 sf-exg 1.122 {
253 sf-exg 1.156 new_flags |= BG_TILE|BG_ROOT_ALIGN;
254 sf-exg 1.122 w = h = noScale;
255     geom_flags |= WidthValue|HeightValue;
256     }
257 sf-exg 1.163
258     else
259     geom_flags |= XParseGeometry (arr[i], &x, &y, &w, &h);
260 sf-exg 1.131 } /* done parsing ops */
261 root 1.26
262 sf-exg 1.131 rxvt_free_strsplit (arr);
263 sf-exg 1.122 }
264 sasha 1.1
265 sf-exg 1.185 new_flags |= bg_flags & ~BG_GEOMETRY_FLAGS;
266    
267 sf-exg 1.163 if (!update)
268     {
269     if (!(geom_flags & XValue))
270     x = y = defaultAlign;
271     else if (!(geom_flags & YValue))
272     y = x;
273    
274     if (!(geom_flags & (WidthValue|HeightValue)))
275     w = h = defaultScale;
276     else if (!(geom_flags & HeightValue))
277     h = w;
278     else if (!(geom_flags & WidthValue))
279     w = h;
280     }
281    
282 sf-exg 1.198 min_it (w, 1000);
283     min_it (h, 1000);
284     clamp_it (x, -100, 200);
285     clamp_it (y, -100, 200);
286    
287     if (bg_flags != new_flags
288     || h_scale != w
289     || v_scale != h
290     || h_align != x
291     || v_align != y)
292 sasha 1.1 {
293 sf-exg 1.142 bg_flags = new_flags;
294 sf-exg 1.198 h_scale = w;
295     v_scale = h;
296     h_align = x;
297     v_align = y;
298 sf-exg 1.110 changed = true;
299 sasha 1.1 }
300 root 1.26
301 sf-exg 1.110 return changed;
302 sasha 1.1 }
303    
304 sf-exg 1.59 void
305 sf-exg 1.142 rxvt_term::get_image_geometry (int image_width, int image_height, int &w, int &h, int &x, int &y)
306 sf-exg 1.59 {
307 sf-exg 1.142 int target_width = szHint.width;
308     int target_height = szHint.height;
309 sf-exg 1.59
310 sf-exg 1.164 w = h_scale * target_width / 100;
311     h = v_scale * target_height / 100;
312    
313 sf-exg 1.176 if (bg_flags & BG_KEEP_ASPECT)
314 sf-exg 1.62 {
315 sf-exg 1.164 float scale = (float)w / image_width;
316     min_it (scale, (float)h / image_height);
317 sf-exg 1.62 w = image_width * scale + 0.5;
318     h = image_height * scale + 0.5;
319     }
320 sf-exg 1.59
321 sf-exg 1.68 if (!w) w = image_width;
322     if (!h) h = image_height;
323    
324 sf-exg 1.143 if (bg_flags & BG_ROOT_ALIGN)
325 sf-exg 1.59 {
326 sf-exg 1.121 x = -target_x;
327     y = -target_y;
328 sf-exg 1.59 }
329 sf-exg 1.63 else
330     {
331 sf-exg 1.68 x = make_align_position (h_align, target_width, w);
332     y = make_align_position (v_align, target_height, h);
333 sf-exg 1.63 }
334 sf-exg 1.61
335 sf-exg 1.156 if (!(bg_flags & BG_TILE)
336 sf-exg 1.164 || h_scale || v_scale
337 sf-exg 1.143 || (!(bg_flags & BG_ROOT_ALIGN) && (h_align || v_align))
338 sf-exg 1.204 || image_width > target_width || image_height > target_height)
339 sf-exg 1.143 bg_flags |= BG_IS_SIZE_SENSITIVE;
340 sf-exg 1.204 else
341     bg_flags &= ~BG_IS_SIZE_SENSITIVE;
342 sf-exg 1.59 }
343    
344 sf-exg 1.55 # ifdef HAVE_PIXBUF
345     bool
346 sf-exg 1.142 rxvt_term::pixbuf_to_pixmap (GdkPixbuf *pixbuf, Pixmap pixmap, GC gc,
347     int src_x, int src_y, int dst_x, int dst_y,
348     unsigned int width, unsigned int height)
349 sf-exg 1.127 {
350     XImage *ximage;
351     char *data, *line;
352     int bytes_per_pixel;
353 sf-exg 1.207 int width_r, width_g, width_b, width_a;
354     int sh_r, sh_g, sh_b, sh_a;
355     uint32_t alpha_mask;
356 sf-exg 1.127 int rowstride;
357     int channels;
358     unsigned char *row;
359    
360     if (visual->c_class != TrueColor)
361     return false;
362    
363 sf-exg 1.207 #if XRENDER
364     XRenderPictFormat *format = XRenderFindVisualFormat (dpy, visual);
365     if (format)
366     alpha_mask = (uint32_t)format->direct.alphaMask << format->direct.alpha;
367     else
368     #endif
369     alpha_mask = 0;
370    
371 sf-exg 1.127 if (depth == 24 || depth == 32)
372     bytes_per_pixel = 4;
373     else if (depth == 15 || depth == 16)
374     bytes_per_pixel = 2;
375     else
376     return false;
377    
378 sf-exg 1.155 width_r = ecb_popcount32 (visual->red_mask);
379     width_g = ecb_popcount32 (visual->green_mask);
380     width_b = ecb_popcount32 (visual->blue_mask);
381 sf-exg 1.207 width_a = ecb_popcount32 (alpha_mask);
382 sf-exg 1.127
383 sf-exg 1.207 if (width_r > 8 || width_g > 8 || width_b > 8 || width_a > 8)
384 sf-exg 1.127 return false;
385    
386 sf-exg 1.155 sh_r = ecb_ctz32 (visual->red_mask);
387     sh_g = ecb_ctz32 (visual->green_mask);
388     sh_b = ecb_ctz32 (visual->blue_mask);
389 sf-exg 1.207 sh_a = ecb_ctz32 (alpha_mask);
390 sf-exg 1.127
391     if (width > INT_MAX / height / bytes_per_pixel)
392     return false;
393    
394     data = (char *)malloc (width * height * bytes_per_pixel);
395     if (!data)
396     return false;
397    
398 sf-exg 1.142 ximage = XCreateImage (dpy, visual, depth, ZPixmap, 0, data,
399 sf-exg 1.127 width, height, bytes_per_pixel * 8, 0);
400     if (!ximage)
401     {
402     free (data);
403     return false;
404     }
405    
406 sf-exg 1.155 ximage->byte_order = ecb_big_endian () ? MSBFirst : LSBFirst;
407 sf-exg 1.127
408     rowstride = gdk_pixbuf_get_rowstride (pixbuf);
409     channels = gdk_pixbuf_get_n_channels (pixbuf);
410     row = gdk_pixbuf_get_pixels (pixbuf) + src_y * rowstride + src_x * channels;
411     line = data;
412    
413 sf-exg 1.207 rgba c (0, 0, 0);
414    
415     if (channels == 4 && alpha_mask == 0)
416     {
417     pix_colors[Color_bg].get (c);
418     c.r >>= 8;
419     c.g >>= 8;
420     c.b >>= 8;
421     }
422    
423 sf-exg 1.127 for (int y = 0; y < height; y++)
424     {
425     for (int x = 0; x < width; x++)
426     {
427     unsigned char *pixel = row + x * channels;
428     uint32_t value;
429 sf-exg 1.207 unsigned char r, g, b, a;
430    
431     if (channels == 4)
432     {
433     a = pixel[3];
434     r = (pixel[0] * a + c.r * (0xff - a)) / 0xff;
435     g = (pixel[1] * a + c.g * (0xff - a)) / 0xff;
436     b = (pixel[2] * a + c.b * (0xff - a)) / 0xff;
437     }
438     else
439     {
440     a = 0xff;
441     r = pixel[0];
442     g = pixel[1];
443     b = pixel[2];
444     }
445 sf-exg 1.127
446 sf-exg 1.207 value = ((r >> (8 - width_r)) << sh_r)
447     | ((g >> (8 - width_g)) << sh_g)
448     | ((b >> (8 - width_b)) << sh_b)
449     | ((a >> (8 - width_a)) << sh_a);
450 sf-exg 1.127
451     if (bytes_per_pixel == 4)
452     ((uint32_t *)line)[x] = value;
453     else
454     ((uint16_t *)line)[x] = value;
455     }
456    
457     row += rowstride;
458     line += ximage->bytes_per_line;
459     }
460    
461 sf-exg 1.142 XPutImage (dpy, pixmap, gc, ximage, 0, 0, dst_x, dst_y, width, height);
462 sf-exg 1.127 XDestroyImage (ximage);
463     return true;
464     }
465    
466     bool
467 sf-exg 1.202 rxvt_term::render_image (bool transparent)
468 sf-exg 1.55 {
469     if (!pixbuf)
470     return false;
471    
472 sf-exg 1.202 if (transparent
473 sf-exg 1.143 && !(bg_flags & BG_HAS_RENDER))
474 sf-exg 1.55 return false;
475    
476     GdkPixbuf *result;
477    
478     int image_width = gdk_pixbuf_get_width (pixbuf);
479     int image_height = gdk_pixbuf_get_height (pixbuf);
480    
481 sf-exg 1.142 int target_width = szHint.width;
482     int target_height = szHint.height;
483 sf-exg 1.55 int new_pmap_width = target_width;
484     int new_pmap_height = target_height;
485    
486     int x = 0;
487     int y = 0;
488 sf-exg 1.59 int w = 0;
489     int h = 0;
490 sf-exg 1.55
491 sf-exg 1.59 get_image_geometry (image_width, image_height, w, h, x, y);
492 sf-exg 1.55
493 sf-exg 1.143 if (!(bg_flags & BG_ROOT_ALIGN)
494 sf-exg 1.67 && (x >= target_width
495     || y >= target_height
496 sf-exg 1.172 || x + w <= 0
497     || y + h <= 0))
498 sf-exg 1.55 return false;
499    
500     result = pixbuf;
501    
502 sf-exg 1.172 if (w != image_width
503     || h != image_height)
504 sf-exg 1.55 {
505     result = gdk_pixbuf_scale_simple (pixbuf,
506 sf-exg 1.68 w, h,
507 sf-exg 1.55 GDK_INTERP_BILINEAR);
508     }
509    
510 sf-exg 1.151 if (!result)
511     return false;
512    
513 sf-exg 1.55 bool ret = false;
514    
515 sf-exg 1.152 XGCValues gcv;
516     GC gc;
517     Pixmap root_pmap;
518 sf-exg 1.55
519 sf-exg 1.152 image_width = gdk_pixbuf_get_width (result);
520     image_height = gdk_pixbuf_get_height (result);
521 sf-exg 1.55
522 sf-exg 1.202 if (transparent)
523 sf-exg 1.152 {
524     root_pmap = bg_pixmap;
525     bg_pixmap = None;
526     }
527     else
528     {
529 sf-exg 1.156 if (bg_flags & BG_TILE)
530 sf-exg 1.58 {
531 sf-exg 1.152 new_pmap_width = min (image_width, target_width);
532     new_pmap_height = min (image_height, target_height);
533 sf-exg 1.58 }
534 sf-exg 1.152 }
535 sf-exg 1.55
536 sf-exg 1.152 if (bg_pixmap == None
537     || bg_pmap_width != new_pmap_width
538     || bg_pmap_height != new_pmap_height)
539     {
540     if (bg_pixmap)
541     XFreePixmap (dpy, bg_pixmap);
542     bg_pixmap = XCreatePixmap (dpy, vt, new_pmap_width, new_pmap_height, depth);
543     bg_pmap_width = new_pmap_width;
544     bg_pmap_height = new_pmap_height;
545     }
546 sf-exg 1.55
547 sf-exg 1.154 gcv.foreground = pix_colors[Color_bg];
548     gc = XCreateGC (dpy, vt, GCForeground, &gcv);
549    
550     if (gc)
551 sf-exg 1.152 {
552 sf-exg 1.156 if (bg_flags & BG_TILE)
553 sf-exg 1.154 {
554     Pixmap tile = XCreatePixmap (dpy, vt, image_width, image_height, depth);
555     pixbuf_to_pixmap (result, tile, gc,
556     0, 0,
557     0, 0,
558     image_width, image_height);
559    
560     gcv.tile = tile;
561     gcv.fill_style = FillTiled;
562     gcv.ts_x_origin = x;
563     gcv.ts_y_origin = y;
564     XChangeGC (dpy, gc, GCFillStyle | GCTile | GCTileStipXOrigin | GCTileStipYOrigin, &gcv);
565 sf-exg 1.55
566 sf-exg 1.154 XFillRectangle (dpy, bg_pixmap, gc, 0, 0, new_pmap_width, new_pmap_height);
567     XFreePixmap (dpy, tile);
568     }
569     else
570 sf-exg 1.55 {
571 sf-exg 1.154 int src_x, src_y, dst_x, dst_y;
572     int dst_width, dst_height;
573    
574     src_x = make_clip_rectangle (x, image_width , new_pmap_width , dst_x, dst_width );
575     src_y = make_clip_rectangle (y, image_height, new_pmap_height, dst_y, dst_height);
576 sf-exg 1.55
577 sf-exg 1.154 if (dst_x > 0 || dst_y > 0
578     || dst_x + dst_width < new_pmap_width
579     || dst_y + dst_height < new_pmap_height)
580     XFillRectangle (dpy, bg_pixmap, gc, 0, 0, new_pmap_width, new_pmap_height);
581    
582     if (dst_x < new_pmap_width && dst_y < new_pmap_height)
583     pixbuf_to_pixmap (result, bg_pixmap, gc,
584     src_x, src_y,
585     dst_x, dst_y,
586     dst_width, dst_height);
587     }
588 sf-exg 1.55
589 sf-exg 1.154 #if XRENDER
590 sf-exg 1.202 if (transparent)
591 sf-exg 1.154 {
592 sf-exg 1.190 XRenderPictFormat *format = XRenderFindVisualFormat (dpy, visual);
593 sf-exg 1.55
594 sf-exg 1.191 Picture src = XRenderCreatePicture (dpy, root_pmap, format, 0, 0);
595 sf-exg 1.55
596 sf-exg 1.191 Picture dst = XRenderCreatePicture (dpy, bg_pixmap, format, 0, 0);
597 sf-exg 1.152
598 sf-exg 1.188 Picture mask = create_xrender_mask (dpy, vt, False, False);
599 sf-exg 1.79
600 sf-exg 1.154 XRenderColor mask_c;
601 sf-exg 1.79
602 sf-exg 1.154 mask_c.alpha = 0x8000;
603 sf-exg 1.192 mask_c.red =
604     mask_c.green =
605     mask_c.blue = 0;
606 sf-exg 1.154 XRenderFillRectangle (dpy, PictOpSrc, mask, &mask_c, 0, 0, 1, 1);
607 sf-exg 1.192
608 sf-exg 1.154 XRenderComposite (dpy, PictOpOver, src, mask, dst, 0, 0, 0, 0, 0, 0, target_width, target_height);
609    
610     XRenderFreePicture (dpy, src);
611     XRenderFreePicture (dpy, dst);
612     XRenderFreePicture (dpy, mask);
613     }
614 sf-exg 1.152 #endif
615 sf-exg 1.79
616 sf-exg 1.154 XFreeGC (dpy, gc);
617 sf-exg 1.79
618 sf-exg 1.154 ret = true;
619 sf-exg 1.152 }
620 sf-exg 1.79
621 sf-exg 1.152 if (result != pixbuf)
622     g_object_unref (result);
623 sf-exg 1.55
624 sf-exg 1.202 if (transparent)
625 sf-exg 1.152 XFreePixmap (dpy, root_pmap);
626 sf-exg 1.55
627     return ret;
628     }
629     # endif /* HAVE_PIXBUF */
630    
631 sasha 1.1 bool
632 sf-exg 1.142 rxvt_term::bg_set_file (const char *file)
633 sasha 1.1 {
634 sf-exg 1.107 if (!file || !*file)
635     return false;
636 sasha 1.1
637 sf-exg 1.167 bool ret = false;
638     const char *p = strchr (file, ';');
639    
640     if (p)
641 sasha 1.1 {
642 sf-exg 1.107 size_t len = p - file;
643     char *f = rxvt_temp_buf<char> (len + 1);
644     memcpy (f, file, len);
645     f[len] = '\0';
646     file = f;
647     }
648 root 1.25
649 sf-exg 1.55 # ifdef HAVE_PIXBUF
650 sf-exg 1.107 GdkPixbuf *image = gdk_pixbuf_new_from_file (file, NULL);
651     if (image)
652     {
653     if (pixbuf)
654     g_object_unref (pixbuf);
655     pixbuf = image;
656 sf-exg 1.144 bg_flags |= BG_IS_FROM_FILE;
657 sf-exg 1.167 ret = true;
658 sf-exg 1.107 }
659 sf-exg 1.55 # endif
660 root 1.25
661 sf-exg 1.167 if (ret)
662     {
663     if (p)
664     bg_set_geometry (p + 1);
665     else
666     bg_set_default_geometry ();
667     }
668    
669     return ret;
670 sasha 1.1 }
671    
672 ayin 1.12 # endif /* BG_IMAGE_FROM_FILE */
673 sasha 1.1
674     # ifdef ENABLE_TRANSPARENCY
675 ayin 1.10 bool
676 sf-exg 1.142 rxvt_term::bg_set_transparent ()
677 sasha 1.1 {
678 sf-exg 1.143 if (!(bg_flags & BG_IS_TRANSPARENT))
679 sasha 1.1 {
680 sf-exg 1.143 bg_flags |= BG_IS_TRANSPARENT;
681 sasha 1.1 return true;
682     }
683 root 1.25
684 sasha 1.1 return false;
685     }
686    
687     bool
688 sf-exg 1.142 rxvt_term::bg_set_blur (const char *geom)
689 sasha 1.1 {
690 sf-exg 1.110 bool changed = false;
691 sasha 1.1 unsigned int hr, vr;
692     int junk;
693     int geom_flags = XParseGeometry (geom, &junk, &junk, &hr, &vr);
694    
695 sf-exg 1.52 if (!(geom_flags & WidthValue))
696 sasha 1.1 hr = 1;
697 sf-exg 1.52 if (!(geom_flags & HeightValue))
698 sasha 1.1 vr = hr;
699    
700 sf-exg 1.80 min_it (hr, 128);
701     min_it (vr, 128);
702    
703 sasha 1.1 if (h_blurRadius != hr)
704     {
705 sf-exg 1.110 changed = true;
706 sasha 1.1 h_blurRadius = hr;
707     }
708    
709     if (v_blurRadius != vr)
710     {
711 sf-exg 1.110 changed = true;
712 sasha 1.1 v_blurRadius = vr;
713     }
714 ayin 1.10
715 sf-exg 1.204 if (h_blurRadius && v_blurRadius)
716     bg_flags |= BG_NEEDS_BLUR;
717     else
718 sf-exg 1.143 bg_flags &= ~BG_NEEDS_BLUR;
719 sasha 1.1
720 sf-exg 1.110 return changed;
721 sasha 1.1 }
722    
723 sf-exg 1.146 void
724     rxvt_term::set_tint_shade_flags ()
725 sasha 1.1 {
726 sf-exg 1.203 if (shade != 100 || (bg_flags & BG_TINT_SET))
727 sf-exg 1.146 bg_flags |= BG_NEEDS_TINT;
728 sf-exg 1.203 else
729     bg_flags &= ~BG_NEEDS_TINT;
730 sasha 1.1 }
731    
732     bool
733 sf-exg 1.142 rxvt_term::bg_set_tint (rxvt_color &new_tint)
734 sasha 1.1 {
735 sf-exg 1.194 if (!(bg_flags & BG_TINT_SET) || tint != new_tint)
736 sasha 1.1 {
737     tint = new_tint;
738 sf-exg 1.194 bg_flags |= BG_TINT_SET;
739 sf-exg 1.203
740     rgba c;
741     tint.get (c);
742     if ((c.r <= 0x00ff || c.r >= 0xff00)
743     && (c.g <= 0x00ff || c.g >= 0xff00)
744     && (c.b <= 0x00ff || c.b >= 0xff00))
745     bg_flags |= BG_TINT_BITAND;
746     else
747     bg_flags &= ~BG_TINT_BITAND;
748    
749 sf-exg 1.146 set_tint_shade_flags ();
750 sasha 1.1 return true;
751     }
752 root 1.20
753 sasha 1.1 return false;
754     }
755    
756     bool
757 sf-exg 1.142 rxvt_term::bg_set_shade (const char *shade_str)
758 sasha 1.1 {
759 sf-exg 1.186 int new_shade = atoi (shade_str);
760 sasha 1.1
761 sf-exg 1.75 clamp_it (new_shade, -100, 200);
762     if (new_shade < 0)
763 root 1.20 new_shade = 200 - (100 + new_shade);
764 sasha 1.1
765     if (new_shade != shade)
766     {
767     shade = new_shade;
768 sf-exg 1.146 set_tint_shade_flags ();
769 sasha 1.1 return true;
770     }
771 root 1.20
772 sasha 1.1 return false;
773     }
774    
775 sf-exg 1.101 #if XRENDER
776 sf-exg 1.80 static void
777     get_gaussian_kernel (int radius, int width, double *kernel, XFixed *params)
778     {
779 sf-exg 1.89 double sigma = radius / 2.0;
780     double scale = sqrt (2.0 * M_PI) * sigma;
781     double sum = 0.0;
782 sf-exg 1.80
783 sf-exg 1.89 for (int i = 0; i < width; i++)
784     {
785     double x = i - width / 2;
786     kernel[i] = exp (-(x * x) / (2.0 * sigma * sigma)) / scale;
787     sum += kernel[i];
788     }
789 sf-exg 1.80
790 sf-exg 1.89 params[0] = XDoubleToFixed (width);
791     params[1] = XDoubleToFixed (1);
792 sf-exg 1.80
793 sf-exg 1.89 for (int i = 0; i < width; i++)
794     params[i+2] = XDoubleToFixed (kernel[i] / sum);
795 sf-exg 1.80 }
796 sf-exg 1.84 #endif
797 sf-exg 1.80
798     bool
799 sf-exg 1.196 rxvt_term::blur_pixmap (Pixmap pixmap, Visual *visual, int width, int height, int depth)
800 sf-exg 1.80 {
801     bool ret = false;
802 sf-exg 1.101 #if XRENDER
803 sf-exg 1.181 if (!(bg_flags & BG_HAS_RENDER_CONV))
804     return false;
805    
806 sf-exg 1.80 int size = max (h_blurRadius, v_blurRadius) * 2 + 1;
807     double *kernel = (double *)malloc (size * sizeof (double));
808     XFixed *params = (XFixed *)malloc ((size + 2) * sizeof (XFixed));
809    
810 sf-exg 1.195 XRenderPictureAttributes pa;
811 sf-exg 1.91 XRenderPictFormat *format = XRenderFindVisualFormat (dpy, visual);
812 sf-exg 1.80
813 sf-exg 1.195 pa.repeat = RepeatPad;
814     Picture src = XRenderCreatePicture (dpy, pixmap, format, CPRepeat, &pa);
815 sf-exg 1.196 Pixmap tmp = XCreatePixmap (dpy, pixmap, width, height, depth);
816     Picture dst = XRenderCreatePicture (dpy, tmp, format, CPRepeat, &pa);
817     XFreePixmap (dpy, tmp);
818 sf-exg 1.80
819 sf-exg 1.154 if (kernel && params)
820 sf-exg 1.80 {
821 sf-exg 1.193 size = h_blurRadius * 2 + 1;
822     get_gaussian_kernel (h_blurRadius, size, kernel, params);
823 sf-exg 1.80
824 sf-exg 1.193 XRenderSetPictureFilter (dpy, src, FilterConvolution, params, size+2);
825     XRenderComposite (dpy,
826     PictOpSrc,
827     src,
828     None,
829     dst,
830     0, 0,
831     0, 0,
832     0, 0,
833     width, height);
834    
835 sf-exg 1.196 ::swap (src, dst);
836    
837 sf-exg 1.193 size = v_blurRadius * 2 + 1;
838     get_gaussian_kernel (v_blurRadius, size, kernel, params);
839     ::swap (params[0], params[1]);
840    
841     XRenderSetPictureFilter (dpy, src, FilterConvolution, params, size+2);
842     XRenderComposite (dpy,
843     PictOpSrc,
844     src,
845     None,
846     dst,
847     0, 0,
848     0, 0,
849     0, 0,
850     width, height);
851 sf-exg 1.80
852     ret = true;
853     }
854    
855     free (kernel);
856     free (params);
857     XRenderFreePicture (dpy, src);
858     XRenderFreePicture (dpy, dst);
859     #endif
860     return ret;
861     }
862    
863 sf-exg 1.64 bool
864 sf-exg 1.142 rxvt_term::tint_pixmap (Pixmap pixmap, Visual *visual, int width, int height)
865 sf-exg 1.64 {
866     bool ret = false;
867    
868 sf-exg 1.203 if (shade == 100 && (bg_flags & BG_TINT_BITAND))
869 sf-exg 1.64 {
870     XGCValues gcv;
871     GC gc;
872    
873     /* In this case we can tint image server-side getting significant
874     * performance improvements, as we eliminate XImage transfer
875     */
876     gcv.foreground = Pixel (tint);
877     gcv.function = GXand;
878     gcv.fill_style = FillSolid;
879 sf-exg 1.77 gc = XCreateGC (dpy, pixmap, GCFillStyle | GCForeground | GCFunction, &gcv);
880 sf-exg 1.64 if (gc)
881     {
882 sf-exg 1.70 XFillRectangle (dpy, pixmap, gc, 0, 0, width, height);
883 sf-exg 1.64 ret = true;
884     XFreeGC (dpy, gc);
885     }
886     }
887 sf-exg 1.181 # if XRENDER
888     else if (bg_flags & BG_HAS_RENDER)
889 sf-exg 1.64 {
890 sf-exg 1.194 rgba c (rgba::MAX_CC, rgba::MAX_CC, rgba::MAX_CC);
891 sf-exg 1.64
892 sf-exg 1.194 if (bg_flags & BG_TINT_SET)
893     tint.get (c);
894 sf-exg 1.64
895 sf-exg 1.75 if (shade <= 100)
896 sf-exg 1.64 {
897 root 1.148 c.r = c.r * shade / 100;
898     c.g = c.g * shade / 100;
899     c.b = c.b * shade / 100;
900 sf-exg 1.64 }
901 sf-exg 1.75 else
902 sf-exg 1.64 {
903 root 1.148 c.r = c.r * (200 - shade) / 100;
904     c.g = c.g * (200 - shade) / 100;
905     c.b = c.b * (200 - shade) / 100;
906 sf-exg 1.64 }
907    
908 sf-exg 1.77 XRenderPictFormat *format = XRenderFindVisualFormat (dpy, visual);
909 sf-exg 1.64
910 sf-exg 1.191 Picture back_pic = XRenderCreatePicture (dpy, pixmap, format, 0, 0);
911 sf-exg 1.64
912 sf-exg 1.188 Picture overlay_pic = create_xrender_mask (dpy, pixmap, True, False);
913 sf-exg 1.64
914 sf-exg 1.188 Picture mask_pic = create_xrender_mask (dpy, pixmap, True, True);
915 sf-exg 1.64
916 sf-exg 1.154 XRenderColor mask_c;
917 sf-exg 1.64
918 sf-exg 1.154 mask_c.alpha = 0xffff;
919     mask_c.red =
920     mask_c.green =
921     mask_c.blue = 0;
922     XRenderFillRectangle (dpy, PictOpSrc, overlay_pic, &mask_c, 0, 0, 1, 1);
923    
924     mask_c.alpha = 0;
925     mask_c.red = 0xffff - c.r;
926     mask_c.green = 0xffff - c.g;
927     mask_c.blue = 0xffff - c.b;
928     XRenderFillRectangle (dpy, PictOpSrc, mask_pic, &mask_c, 0, 0, 1, 1);
929 sf-exg 1.192
930 sf-exg 1.154 XRenderComposite (dpy, PictOpOver, overlay_pic, mask_pic, back_pic, 0, 0, 0, 0, 0, 0, width, height);
931 sf-exg 1.64
932 sf-exg 1.154 if (shade > 100)
933     {
934 sf-exg 1.64 mask_c.alpha = 0;
935 sf-exg 1.192 mask_c.red =
936     mask_c.green =
937     mask_c.blue = 0xffff * (shade - 100) / 100;
938 sf-exg 1.154 XRenderFillRectangle (dpy, PictOpSrc, overlay_pic, &mask_c, 0, 0, 1, 1);
939 sf-exg 1.125
940 sf-exg 1.154 XRenderComposite (dpy, PictOpOver, overlay_pic, None, back_pic, 0, 0, 0, 0, 0, 0, width, height);
941     }
942 sf-exg 1.125
943 sf-exg 1.154 ret = true;
944 sf-exg 1.64
945     XRenderFreePicture (dpy, mask_pic);
946     XRenderFreePicture (dpy, overlay_pic);
947     XRenderFreePicture (dpy, back_pic);
948 sf-exg 1.181 }
949 sf-exg 1.64 # endif
950    
951     return ret;
952     }
953    
954 sf-exg 1.149 /*
955 sf-exg 1.100 * Builds a pixmap of the same size as the terminal window that contains
956     * the tiled portion of the root pixmap that is supposed to be covered by
957 sasha 1.1 * our window.
958     */
959 sf-exg 1.202 bool
960 sf-exg 1.142 rxvt_term::make_transparency_pixmap ()
961 sasha 1.1 {
962 sf-exg 1.202 bool ret = false;
963 sasha 1.1
964 sf-exg 1.39 /* root dimensions may change from call to call - but Display structure should
965 sasha 1.1 * be always up-to-date, so let's use it :
966     */
967 sf-exg 1.142 int screen = display->screen;
968 sf-exg 1.103 int root_depth = DefaultDepth (dpy, screen);
969 sasha 1.1 int root_width = DisplayWidth (dpy, screen);
970     int root_height = DisplayHeight (dpy, screen);
971 sf-exg 1.103 unsigned int root_pmap_width, root_pmap_height;
972 sf-exg 1.142 int window_width = szHint.width;
973     int window_height = szHint.height;
974 sasha 1.1 int sx, sy;
975     XGCValues gcv;
976 sf-exg 1.81 GC gc;
977 sasha 1.1
978 sf-exg 1.121 sx = target_x;
979     sy = target_y;
980 sasha 1.1
981     /* check if we are outside of the visible part of the virtual screen : */
982     if (sx + window_width <= 0 || sy + window_height <= 0
983     || sx >= root_width || sy >= root_height)
984     return 0;
985    
986 sf-exg 1.103 // validate root pixmap and get its size
987     if (root_pixmap != None)
988     {
989     Window wdummy;
990     int idummy;
991     unsigned int udummy;
992    
993 sf-exg 1.142 allowedxerror = -1;
994 sf-exg 1.103
995     if (!XGetGeometry (dpy, root_pixmap, &wdummy, &idummy, &idummy, &root_pmap_width, &root_pmap_height, &udummy, &udummy))
996     root_pixmap = None;
997    
998 sf-exg 1.142 allowedxerror = 0;
999 sf-exg 1.103 }
1000    
1001     Pixmap recoded_root_pmap = root_pixmap;
1002    
1003 sf-exg 1.142 if (root_pixmap != None && root_depth != depth)
1004 sf-exg 1.103 {
1005     #if XRENDER
1006 sf-exg 1.143 if (bg_flags & BG_HAS_RENDER)
1007 sf-exg 1.108 {
1008 sf-exg 1.152 recoded_root_pmap = XCreatePixmap (dpy, vt, root_pmap_width, root_pmap_height, depth);
1009    
1010 sf-exg 1.154 XRenderPictFormat *src_format = XRenderFindVisualFormat (dpy, DefaultVisual (dpy, screen));
1011 sf-exg 1.191 Picture src = XRenderCreatePicture (dpy, root_pixmap, src_format, 0, 0);
1012 sf-exg 1.108
1013 sf-exg 1.154 XRenderPictFormat *dst_format = XRenderFindVisualFormat (dpy, visual);
1014 sf-exg 1.191 Picture dst = XRenderCreatePicture (dpy, recoded_root_pmap, dst_format, 0, 0);
1015 sf-exg 1.103
1016 sf-exg 1.154 XRenderComposite (dpy, PictOpSrc, src, None, dst, 0, 0, 0, 0, 0, 0, root_pmap_width, root_pmap_height);
1017 sf-exg 1.103
1018 sf-exg 1.154 XRenderFreePicture (dpy, src);
1019     XRenderFreePicture (dpy, dst);
1020 sf-exg 1.108 }
1021 sf-exg 1.103 else
1022 sf-exg 1.108 #endif
1023 sf-exg 1.151 recoded_root_pmap = None;
1024 sf-exg 1.103 }
1025    
1026 sf-exg 1.151 if (recoded_root_pmap == None)
1027 sf-exg 1.81 return 0;
1028    
1029 sf-exg 1.142 if (bg_pixmap == None
1030     || bg_pmap_width != window_width
1031     || bg_pmap_height != window_height)
1032     {
1033     if (bg_pixmap)
1034     XFreePixmap (dpy, bg_pixmap);
1035     bg_pixmap = XCreatePixmap (dpy, vt, window_width, window_height, depth);
1036     bg_pmap_width = window_width;
1037     bg_pmap_height = window_height;
1038 sf-exg 1.135 }
1039 sasha 1.1
1040 sf-exg 1.154 /* straightforward pixmap copy */
1041 mikachu 1.178 while (sx < 0) sx += root_pmap_width;
1042     while (sy < 0) sy += root_pmap_height;
1043 sf-exg 1.154
1044     gcv.tile = recoded_root_pmap;
1045     gcv.fill_style = FillTiled;
1046     gcv.ts_x_origin = -sx;
1047     gcv.ts_y_origin = -sy;
1048     gc = XCreateGC (dpy, vt, GCFillStyle | GCTile | GCTileStipXOrigin | GCTileStipYOrigin, &gcv);
1049    
1050     if (gc)
1051     {
1052     XFillRectangle (dpy, bg_pixmap, gc, 0, 0, window_width, window_height);
1053 sf-exg 1.202 ret = true;
1054     unsigned long tr_flags = bg_flags & BG_EFFECTS_FLAGS;
1055 sasha 1.1
1056 sf-exg 1.154 if (!(bg_flags & BG_CLIENT_RENDER))
1057 sf-exg 1.150 {
1058 sf-exg 1.181 if (bg_flags & BG_NEEDS_BLUR)
1059 sf-exg 1.154 {
1060 sf-exg 1.196 if (blur_pixmap (bg_pixmap, visual, window_width, window_height, depth))
1061 sf-exg 1.202 tr_flags &= ~BG_NEEDS_BLUR;
1062 sf-exg 1.154 }
1063 sf-exg 1.181 if (bg_flags & BG_NEEDS_TINT)
1064 sf-exg 1.80 {
1065 sf-exg 1.154 if (tint_pixmap (bg_pixmap, visual, window_width, window_height))
1066 sf-exg 1.202 tr_flags &= ~BG_NEEDS_TINT;
1067 sf-exg 1.154 }
1068 sf-exg 1.202 if (tr_flags & BG_NEEDS_TINT)
1069 sf-exg 1.189 {
1070     XImage *ximage = XGetImage (dpy, bg_pixmap, 0, 0, bg_pmap_width, bg_pmap_height, AllPlanes, ZPixmap);
1071     if (ximage)
1072     {
1073     /* our own client-side tinting */
1074     tint_ximage (DefaultVisual (dpy, display->screen), ximage);
1075    
1076     XPutImage (dpy, bg_pixmap, gc, ximage, 0, 0, 0, 0, ximage->width, ximage->height);
1077     XDestroyImage (ximage);
1078     }
1079     }
1080 sf-exg 1.154 } /* server side rendering completed */
1081 sf-exg 1.189
1082     XFreeGC (dpy, gc);
1083 sasha 1.1 }
1084 ayin 1.10
1085 sf-exg 1.103 if (recoded_root_pmap != root_pixmap)
1086     XFreePixmap (dpy, recoded_root_pmap);
1087    
1088 sf-exg 1.202 return ret;
1089 sasha 1.1 }
1090    
1091 sf-exg 1.98 void
1092 sf-exg 1.142 rxvt_term::bg_set_root_pixmap ()
1093 sasha 1.1 {
1094 sf-exg 1.142 Pixmap new_root_pixmap = get_pixmap_property (xa[XA_XROOTPMAP_ID]);
1095 sasha 1.1 if (new_root_pixmap == None)
1096 sf-exg 1.142 new_root_pixmap = get_pixmap_property (xa[XA_ESETROOT_PMAP_ID]);
1097 sasha 1.1
1098 sf-exg 1.98 root_pixmap = new_root_pixmap;
1099 sasha 1.1 }
1100     # endif /* ENABLE_TRANSPARENCY */
1101    
1102     bool
1103 sf-exg 1.142 rxvt_term::bg_render ()
1104 sasha 1.1 {
1105 sf-exg 1.202 bool transparent = false;
1106 sasha 1.1
1107 sf-exg 1.142 bg_invalidate ();
1108 sasha 1.1 # ifdef ENABLE_TRANSPARENCY
1109 sf-exg 1.143 if (bg_flags & BG_IS_TRANSPARENT)
1110 sasha 1.1 {
1111     /* we need to re-generate transparency pixmap in that case ! */
1112 sf-exg 1.202 transparent = make_transparency_pixmap ();
1113     if (transparent)
1114 sf-exg 1.199 bg_flags |= BG_IS_VALID;
1115 sasha 1.1 }
1116     # endif
1117    
1118 sf-exg 1.50 # ifdef BG_IMAGE_FROM_FILE
1119 sf-exg 1.202 if (bg_flags & BG_IS_FROM_FILE)
1120 sasha 1.1 {
1121 sf-exg 1.202 if (render_image (transparent))
1122 sf-exg 1.143 bg_flags |= BG_IS_VALID;
1123 sasha 1.1 }
1124 sf-exg 1.46 # endif
1125 sasha 1.7
1126 sf-exg 1.143 if (!(bg_flags & BG_IS_VALID))
1127 sasha 1.1 {
1128 sf-exg 1.142 if (bg_pixmap != None)
1129 sasha 1.1 {
1130 sf-exg 1.142 XFreePixmap (dpy, bg_pixmap);
1131     bg_pixmap = None;
1132 sasha 1.1 }
1133     }
1134    
1135 sf-exg 1.142 scr_recolour (false);
1136 sf-exg 1.143 bg_flags |= BG_NEEDS_REFRESH;
1137 sasha 1.1
1138 sf-exg 1.142 bg_valid_since = ev::now ();
1139 sasha 1.22
1140 ayin 1.10 return true;
1141 sasha 1.1 }
1142    
1143 sf-exg 1.106 void
1144 sf-exg 1.142 rxvt_term::bg_init ()
1145 sasha 1.1 {
1146 sf-exg 1.142 #ifdef ENABLE_TRANSPARENCY
1147     shade = 100;
1148     #endif
1149 sf-exg 1.108
1150 sf-exg 1.143 bg_flags &= ~(BG_HAS_RENDER | BG_HAS_RENDER_CONV);
1151 sf-exg 1.108 #if XRENDER
1152     int major, minor;
1153 sf-exg 1.142 if (XRenderQueryVersion (dpy, &major, &minor))
1154 sf-exg 1.143 bg_flags |= BG_HAS_RENDER;
1155 sf-exg 1.142 XFilters *filters = XRenderQueryFilters (dpy, vt);
1156 sf-exg 1.108 if (filters)
1157     {
1158     for (int i = 0; i < filters->nfilter; i++)
1159     if (!strcmp (filters->filter[i], FilterConvolution))
1160 sf-exg 1.143 bg_flags |= BG_HAS_RENDER_CONV;
1161 sf-exg 1.108
1162     XFree (filters);
1163     }
1164     #endif
1165 sasha 1.1 }
1166    
1167 ayin 1.12 #endif /* HAVE_BG_PIXMAP */
1168 sasha 1.1
1169 sf-exg 1.201 #ifdef ENABLE_TRANSPARENCY
1170 sf-exg 1.169 /* based on code from aterm-0.4.2 */
1171 sasha 1.1
1172 sf-exg 1.179 static inline void
1173     fill_lut (uint32_t *lookup, uint32_t mask, int sh, unsigned short low, unsigned short high)
1174     {
1175     for (int i = 0; i <= mask >> sh; i++)
1176     {
1177     uint32_t tmp;
1178     tmp = i * high;
1179     tmp += (mask >> sh) * low;
1180     lookup[i] = (tmp / 0xffff) << sh;
1181     }
1182     }
1183    
1184 sf-exg 1.183 void
1185     rxvt_term::tint_ximage (Visual *visual, XImage *ximage)
1186 sasha 1.1 {
1187     int sh_r, sh_g, sh_b;
1188 sf-exg 1.94 uint32_t mask_r, mask_g, mask_b;
1189     uint32_t *lookup, *lookup_r, *lookup_g, *lookup_b;
1190 sf-exg 1.180 unsigned short low;
1191 sf-exg 1.155 int host_byte_order = ecb_big_endian () ? MSBFirst : LSBFirst;
1192 sasha 1.1
1193 sf-exg 1.126 if (visual->c_class != TrueColor || ximage->format != ZPixmap) return;
1194 sasha 1.1
1195     /* for convenience */
1196     mask_r = visual->red_mask;
1197     mask_g = visual->green_mask;
1198     mask_b = visual->blue_mask;
1199    
1200     /* boring lookup table pre-initialization */
1201 sf-exg 1.126 switch (ximage->depth)
1202 sf-exg 1.87 {
1203     case 15:
1204     if ((mask_r != 0x7c00) ||
1205     (mask_g != 0x03e0) ||
1206     (mask_b != 0x001f))
1207     return;
1208 sf-exg 1.94 lookup = (uint32_t *) malloc (sizeof (uint32_t)*(32+32+32));
1209 sasha 1.1 lookup_r = lookup;
1210     lookup_g = lookup+32;
1211     lookup_b = lookup+32+32;
1212     sh_r = 10;
1213     sh_g = 5;
1214     sh_b = 0;
1215 sf-exg 1.87 break;
1216     case 16:
1217     if ((mask_r != 0xf800) ||
1218     (mask_g != 0x07e0) ||
1219     (mask_b != 0x001f))
1220     return;
1221 sf-exg 1.94 lookup = (uint32_t *) malloc (sizeof (uint32_t)*(32+64+32));
1222 sasha 1.1 lookup_r = lookup;
1223     lookup_g = lookup+32;
1224     lookup_b = lookup+32+64;
1225     sh_r = 11;
1226     sh_g = 5;
1227     sh_b = 0;
1228 sf-exg 1.87 break;
1229     case 24:
1230     if ((mask_r != 0xff0000) ||
1231     (mask_g != 0x00ff00) ||
1232     (mask_b != 0x0000ff))
1233     return;
1234 sf-exg 1.94 lookup = (uint32_t *) malloc (sizeof (uint32_t)*(256+256+256));
1235 sasha 1.1 lookup_r = lookup;
1236     lookup_g = lookup+256;
1237     lookup_b = lookup+256+256;
1238     sh_r = 16;
1239     sh_g = 8;
1240     sh_b = 0;
1241 sf-exg 1.87 break;
1242     case 32:
1243     if ((mask_r != 0xff0000) ||
1244     (mask_g != 0x00ff00) ||
1245     (mask_b != 0x0000ff))
1246     return;
1247 sf-exg 1.94 lookup = (uint32_t *) malloc (sizeof (uint32_t)*(256+256+256));
1248 sasha 1.1 lookup_r = lookup;
1249     lookup_g = lookup+256;
1250     lookup_b = lookup+256+256;
1251     sh_r = 16;
1252     sh_g = 8;
1253     sh_b = 0;
1254 sf-exg 1.87 break;
1255     default:
1256     return; /* we do not support this color depth */
1257     }
1258 sasha 1.1
1259 sf-exg 1.194 rgba c (rgba::MAX_CC, rgba::MAX_CC, rgba::MAX_CC);
1260 sf-exg 1.183
1261 sf-exg 1.194 if (bg_flags & BG_TINT_SET)
1262     tint.get (c);
1263 sf-exg 1.183
1264 sasha 1.1 /* prepare limits for color transformation (each channel is handled separately) */
1265 sf-exg 1.87 if (shade > 100)
1266     {
1267 sf-exg 1.184 c.r = c.r * (200 - shade) / 100;
1268     c.g = c.g * (200 - shade) / 100;
1269     c.b = c.b * (200 - shade) / 100;
1270 sf-exg 1.125
1271 sf-exg 1.183 low = 0xffff * (shade - 100) / 100;
1272 sf-exg 1.87 }
1273     else
1274     {
1275 sf-exg 1.184 c.r = c.r * shade / 100;
1276     c.g = c.g * shade / 100;
1277     c.b = c.b * shade / 100;
1278 sasha 1.1
1279 sf-exg 1.180 low = 0;
1280 sf-exg 1.87 }
1281 sasha 1.1
1282     /* fill our lookup tables */
1283 sf-exg 1.184 fill_lut (lookup_r, mask_r, sh_r, low, c.r);
1284     fill_lut (lookup_g, mask_g, sh_g, low, c.g);
1285     fill_lut (lookup_b, mask_b, sh_b, low, c.b);
1286 sasha 1.1
1287     /* apply table to input image (replacing colors by newly calculated ones) */
1288 sf-exg 1.126 if (ximage->bits_per_pixel == 32
1289     && (ximage->depth == 24 || ximage->depth == 32)
1290     && ximage->byte_order == host_byte_order)
1291 sf-exg 1.93 {
1292 sf-exg 1.94 uint32_t *p1, *pf, *p, *pl;
1293 sf-exg 1.126 p1 = (uint32_t *) ximage->data;
1294     pf = (uint32_t *) (ximage->data + ximage->height * ximage->bytes_per_line);
1295 sf-exg 1.93
1296     while (p1 < pf)
1297 sf-exg 1.87 {
1298 sf-exg 1.93 p = p1;
1299 sf-exg 1.126 pl = p1 + ximage->width;
1300 sf-exg 1.93 for (; p < pl; p++)
1301 sf-exg 1.87 {
1302 sf-exg 1.93 *p = lookup_r[(*p & 0xff0000) >> 16] |
1303     lookup_g[(*p & 0x00ff00) >> 8] |
1304     lookup_b[(*p & 0x0000ff)] |
1305     (*p & 0xff000000);
1306 sf-exg 1.87 }
1307 sf-exg 1.126 p1 = (uint32_t *) ((char *) p1 + ximage->bytes_per_line);
1308 sasha 1.1 }
1309 sf-exg 1.93 }
1310     else
1311     {
1312 sf-exg 1.126 for (int y = 0; y < ximage->height; y++)
1313     for (int x = 0; x < ximage->width; x++)
1314 sf-exg 1.93 {
1315 sf-exg 1.126 unsigned long pixel = XGetPixel (ximage, x, y);
1316 sf-exg 1.93 pixel = lookup_r[(pixel & mask_r) >> sh_r] |
1317     lookup_g[(pixel & mask_g) >> sh_g] |
1318     lookup_b[(pixel & mask_b) >> sh_b];
1319 sf-exg 1.126 XPutPixel (ximage, x, y, pixel);
1320 sf-exg 1.93 }
1321 sasha 1.1 }
1322    
1323     free (lookup);
1324     }
1325 sf-exg 1.201 #endif /* ENABLE_TRANSPARENCY */