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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines