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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines