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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines