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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines