ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/background.C
(Generate patch)

Comparing rxvt-unicode/src/background.C (file contents):
Revision 1.102 by sf-exg, Sun Oct 31 09:34:23 2010 UTC vs.
Revision 1.213 by sf-exg, Sun May 13 21:12:01 2012 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines