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

Comparing rxvt-unicode/src/background.C (file contents):
Revision 1.124 by sf-exg, Tue Nov 23 16:37:36 2010 UTC vs.
Revision 1.211 by sf-exg, Sun May 13 15:28:44 2012 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines