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.213 by sf-exg, Sun May 13 21:12:01 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}
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;
213 int smaller = min (image_size, window_size);
214
215 if (align >= 0 && align <= 100) 128 if (align >= 0 && align <= 100)
216 return diff * align / 100; 129 return lerp (0, window_size - image_size, align);
217 else if (align > 100 && align <= 200) 130 else if (align > 100)
218 return ((align - 100) * smaller / 100) + window_size - smaller; 131 return lerp (window_size - image_size, window_size, align - 100);
219 else if (align >= -100 && align < 0) 132 else
220 return ((align + 100) * smaller / 100) - image_size; 133 return lerp (-image_size, 0, align + 100);
221 return 0;
222} 134}
223 135
224static inline int 136static inline int
225make_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)
226{ 138{
232 src_pos = -pos; 144 src_pos = -pos;
233 dst_pos = 0; 145 dst_pos = 0;
234 dst_size += pos; 146 dst_size += pos;
235 } 147 }
236 148
237 if (dst_pos + dst_size > target_size)
238 dst_size = target_size - dst_pos; 149 min_it (dst_size, target_size - dst_pos);
239 return src_pos; 150 return src_pos;
240} 151}
241 152
242bool 153bool
243bgPixmap_t::set_geometry (const char *geom, bool update) 154rxvt_term::bg_set_geometry (const char *geom, bool update)
244{ 155{
245 bool changed = false; 156 bool changed = false;
246 int geom_flags = 0; 157 int geom_flags = 0;
247 int x = 0, y = 0; 158 int x = h_align;
159 int y = v_align;
248 unsigned int w = 0, h = 0; 160 unsigned int w = h_scale;
249 unsigned int n; 161 unsigned int h = v_scale;
250 unsigned long new_flags = (flags & (~geometryFlags)); 162 unsigned long new_flags = 0;
251 const char *ops;
252# define MAXLEN_GEOM 256 /* could be longer than regular geometry string */
253 163
254 if (geom == NULL) 164 if (geom == NULL)
255 return false; 165 return false;
256 166
257 char str[MAXLEN_GEOM]; 167 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 { 168 {
267 memcpy (str, geom, n); 169 char **arr = rxvt_strsplit (':', geom);
268 str[n] = '\0';
269 rxvt_strtrim (str);
270 170
271 if (str[0]) 171 for (int i = 0; arr[i]; i++)
172 {
173 if (!strcasecmp (arr[i], "style=tiled"))
272 { 174 {
273 /* we have geometry string - let's handle it prior to applying ops */ 175 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; 176 w = h = noScale;
286 else if (!(geom_flags & HeightValue))
287 h = w; 177 x = y = 0;
288 else if (!(geom_flags & WidthValue))
289 w = h;
290
291 geom_flags |= WidthValue|HeightValue|XValue|YValue; 178 geom_flags = WidthValue|HeightValue|XValue|YValue;
292 }
293
294 if (ops)
295 {
296 while (*ops)
297 { 179 }
298 while (*ops == ':' || isspace(*ops)) ++ops; 180 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 { 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;
303 w = h = noScale; 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;
304 geom_flags |= WidthValue|HeightValue; 218 geom_flags |= WidthValue|HeightValue;
305 } 219 }
306 else if (CHECK_GEOM_OPS ("propscale")) 220 else if (!strcasecmp (arr[i], "propscale"))
307 { 221 {
308 new_flags |= propScale; 222 new_flags |= BG_KEEP_ASPECT;
309 }
310 else if (CHECK_GEOM_OPS ("hscale"))
311 {
312 if (w == 0) w = windowScale;
313
314 h = noScale; 223 w = h = windowScale;
315 geom_flags |= WidthValue|HeightValue; 224 geom_flags |= WidthValue|HeightValue;
316 } 225 }
317 else if (CHECK_GEOM_OPS ("vscale")) 226 else if (!strcasecmp (arr[i], "hscale"))
318 { 227 {
228 new_flags |= BG_TILE;
319 if (h == 0) h = windowScale; 229 w = windowScale;
320
321 w = noScale; 230 h = noScale;
322 geom_flags |= WidthValue|HeightValue; 231 geom_flags |= WidthValue|HeightValue;
323 } 232 }
324 else if (CHECK_GEOM_OPS ("scale")) 233 else if (!strcasecmp (arr[i], "vscale"))
325 { 234 {
235 new_flags |= BG_TILE;
326 if (h == 0) h = windowScale; 236 h = windowScale;
327 if (w == 0) w = windowScale; 237 w = noScale;
328
329 geom_flags |= WidthValue|HeightValue; 238 geom_flags |= WidthValue|HeightValue;
330 } 239 }
331 else if (CHECK_GEOM_OPS ("auto")) 240 else if (!strcasecmp (arr[i], "scale"))
332 { 241 {
333 w = h = windowScale; 242 w = h = windowScale;
243 geom_flags |= WidthValue|HeightValue;
244 }
245 else if (!strcasecmp (arr[i], "auto"))
246 {
247 w = h = windowScale;
334 x = y = centerAlign; 248 x = y = centerAlign;
335 geom_flags |= WidthValue|HeightValue|XValue|YValue; 249 geom_flags |= WidthValue|HeightValue|XValue|YValue;
336 } 250 }
337 else if (CHECK_GEOM_OPS ("root")) 251 else if (!strcasecmp (arr[i], "root"))
338 { 252 {
339 new_flags |= rootAlign; 253 new_flags |= BG_TILE|BG_ROOT_ALIGN;
340 w = h = noScale; 254 w = h = noScale;
341 geom_flags |= WidthValue|HeightValue; 255 geom_flags |= WidthValue|HeightValue;
342 } 256 }
343# undef CHECK_GEOM_OPS
344 257
345 while (*ops != ':' && *ops != '\0') ++ops; 258 else
259 geom_flags |= XParseGeometry (arr[i], &x, &y, &w, &h);
346 } /* done parsing ops */ 260 } /* done parsing ops */
347 }
348 261
349 if (check_set_scale_value (geom_flags, WidthValue, h_scale, w)) changed = true; 262 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 { 263 }
264
265 new_flags |= bg_flags & ~BG_GEOMETRY_FLAGS;
266
267 if (!update)
268 {
269 if (!(geom_flags & XValue))
270 x = y = defaultAlign;
271 else if (!(geom_flags & YValue))
272 y = x;
273
274 if (!(geom_flags & (WidthValue|HeightValue)))
275 w = h = defaultScale;
276 else if (!(geom_flags & HeightValue))
277 h = w;
278 else if (!(geom_flags & WidthValue))
279 w = h;
280 }
281
282 min_it (w, 1000);
283 min_it (h, 1000);
284 clamp_it (x, -100, 200);
285 clamp_it (y, -100, 200);
286
287 if (bg_flags != new_flags
288 || h_scale != w
289 || v_scale != h
290 || h_align != x
291 || v_align != y)
292 {
357 flags = new_flags; 293 bg_flags = new_flags;
294 h_scale = w;
295 v_scale = h;
296 h_align = x;
297 v_align = y;
358 changed = true; 298 changed = true;
359 } 299 }
360 300
361 return changed; 301 return changed;
362} 302}
363 303
364void 304void
365bgPixmap_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)
366{ 306{
367 int target_width = target->szHint.width; 307 int target_width = szHint.width;
368 int target_height = target->szHint.height; 308 int target_height = szHint.height;
369 309
370 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)
371 { 314 {
372 float scale = (float)target_width / image_width; 315 float scale = (float)w / image_width;
373 min_it (scale, (float)target_height / image_height); 316 min_it (scale, (float)h / image_height);
374 w = image_width * scale + 0.5; 317 w = image_width * scale + 0.5;
375 h = image_height * scale + 0.5; 318 h = image_height * scale + 0.5;
376 } 319 }
377 else
378 {
379 w = h_scale * target_width / 100;
380 h = v_scale * target_height / 100;
381 }
382 320
383 if (!w) w = image_width; 321 if (!w) w = image_width;
384 if (!h) h = image_height; 322 if (!h) h = image_height;
385 323
386 if (flags & rootAlign) 324 if (bg_flags & BG_ROOT_ALIGN)
387 { 325 {
388 target->get_window_origin (x, y);
389 x = -x; 326 x = -target_x;
390 y = -y; 327 y = -target_y;
391 } 328 }
392 else 329 else
393 { 330 {
394 x = make_align_position (h_align, target_width, w); 331 x = make_align_position (h_align, target_width, w);
395 y = make_align_position (v_align, target_height, h); 332 y = make_align_position (v_align, target_height, h);
396 } 333 }
397 334
398 flags &= ~sizeSensitive; 335 if (!(bg_flags & BG_TILE)
399 if ((flags & propScale) || h_scale || v_scale 336 || h_scale || v_scale
400 || (!(flags & rootAlign) && (h_align || v_align)) 337 || (!(bg_flags & BG_ROOT_ALIGN) && (h_align || v_align))
401 || w > target_width || h > target_height) 338 || image_width > target_width || image_height > target_height)
402 flags |= sizeSensitive; 339 bg_flags |= BG_IS_SIZE_SENSITIVE;
340 else
341 bg_flags &= ~BG_IS_SIZE_SENSITIVE;
403} 342}
404 343
405# ifdef HAVE_AFTERIMAGE 344# ifdef HAVE_PIXBUF
406bool 345bool
407bgPixmap_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)
408{ 349{
409 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)
410 return false; 360 return false;
411 361
412 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;
413 369
414 ASImage *background = NULL; 370 width_r = ecb_popcount32 (visual->red_mask);
415 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);
416 374
417# ifdef ENABLE_TRANSPARENCY 375 if (width_r > 8 || width_g > 8 || width_b > 8 || width_a > 8)
418 if (background_flags) 376 return false;
419 background = pixmap2ximage (target->asv, pixmap, 0, 0, pmap_width, pmap_height, AllPlanes, 100);
420 377
421 if (!(background_flags & transpPmapTinted) && (flags & tintNeeded)) 378 sh_r = ecb_ctz32 (visual->red_mask);
422 { 379 sh_g = ecb_ctz32 (visual->green_mask);
423 ShadingInfo as_shade; 380 sh_b = ecb_ctz32 (visual->blue_mask);
424 as_shade.shading = shade; 381 sh_a = ecb_ctz32 (alpha_mask);
425 382
426 rgba c (rgba::MAX_CC,rgba::MAX_CC,rgba::MAX_CC); 383 if (width > 32767 || height > 32767)
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 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)))
434 } 393 {
435 394 XDestroyImage (ximage);
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 = 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)
442 { 424 {
443 destroy_asimage (&background); 425 a = pixel[3];
444 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);
445 } 447 }
446 }
447# endif
448 448
449 ASImage *result = 0; 449 row += rowstride;
450 line += ximage->bytes_per_line;
451 }
450 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
451 int target_width = target->szHint.width; 473 int target_width = szHint.width;
452 int target_height = target->szHint.height; 474 int target_height = szHint.height;
453 int new_pmap_width = target_width; 475 int new_pmap_width = target_width;
454 int new_pmap_height = target_height; 476 int new_pmap_height = target_height;
455 477
456 int x = 0; 478 int x = 0;
457 int y = 0; 479 int y = 0;
458 int w = 0; 480 int w = 0;
459 int h = 0; 481 int h = 0;
460 482
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); 483 get_image_geometry (image_width, image_height, w, h, x, y);
676 484
677 if (!(flags & rootAlign) 485 if (!(bg_flags & BG_ROOT_ALIGN)
678 && (x >= target_width 486 && (x >= target_width
679 || y >= target_height 487 || y >= target_height
680 || (x + w <= 0) 488 || x + w <= 0
681 || (y + h <= 0))) 489 || y + h <= 0))
682 return false; 490 return false;
683 491
684 result = pixbuf; 492 result = pixbuf;
685 493
686 if ((w != image_width) 494 if (w != image_width
687 || (h != image_height)) 495 || h != image_height)
688 { 496 {
689 result = gdk_pixbuf_scale_simple (pixbuf, 497 result = gdk_pixbuf_scale_simple (pixbuf,
690 w, h, 498 w, h,
691 GDK_INTERP_BILINEAR); 499 GDK_INTERP_BILINEAR);
692 } 500 }
693 501
502 if (!result)
503 return false;
504
694 bool ret = false; 505 bool ret = false;
695 506
696 if (result)
697 {
698 XGCValues gcv; 507 XGCValues gcv;
699 GC gc; 508 GC gc;
700 Pixmap root_pmap; 509 Pixmap root_pmap;
701 510
702 image_width = gdk_pixbuf_get_width (result); 511 image_width = gdk_pixbuf_get_width (result);
703 image_height = gdk_pixbuf_get_height (result); 512 image_height = gdk_pixbuf_get_height (result);
704 513
705 if (background_flags) 514 if (transparent)
706 { 515 {
707 root_pmap = pixmap; 516 root_pmap = bg_pixmap;
708 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);
709 } 525 }
710 else 526 }
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 527
719 if (pixmap == None 528 if (bg_pixmap == None
720 || pmap_width != new_pmap_width 529 || bg_pmap_width != new_pmap_width
721 || pmap_height != new_pmap_height 530 || bg_pmap_height != new_pmap_height)
722 || pmap_depth != target->depth) 531 {
723 {
724 if (pixmap) 532 if (bg_pixmap)
725 XFreePixmap (target->dpy, pixmap); 533 XFreePixmap (dpy, bg_pixmap);
726 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);
727 pmap_width = new_pmap_width; 535 bg_pmap_width = new_pmap_width;
728 pmap_height = new_pmap_height; 536 bg_pmap_height = new_pmap_height;
729 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)
730 } 545 {
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); 546 Pixmap tile = XCreatePixmap (dpy, vt, image_width, image_height, depth);
738 gdk_pixbuf_xlib_render_to_drawable (result, tile, gc, 547 pixbuf_to_pixmap (result, tile, gc,
739 0, 0, 548 0, 0,
740 0, 0, 549 0, 0,
741 image_width, image_height, 550 image_width, image_height);
742 XLIB_RGB_DITHER_NONE,
743 0, 0);
744 551
745 gcv.tile = tile; 552 gcv.tile = tile;
746 gcv.fill_style = FillTiled; 553 gcv.fill_style = FillTiled;
747 gcv.ts_x_origin = x; 554 gcv.ts_x_origin = x;
748 gcv.ts_y_origin = y; 555 gcv.ts_y_origin = y;
749 XChangeGC (target->dpy, gc, GCFillStyle | GCTile | GCTileStipXOrigin | GCTileStipYOrigin, &gcv); 556 XChangeGC (dpy, gc, GCFillStyle | GCTile | GCTileStipXOrigin | GCTileStipYOrigin, &gcv);
750 557
751 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);
752 XFreePixmap (target->dpy, tile); 559 XFreePixmap (dpy, tile);
753 } 560 }
754 else 561 else
755 { 562 {
756 int src_x, src_y, dst_x, dst_y; 563 int src_x, src_y, dst_x, dst_y;
757 int dst_width, dst_height; 564 int dst_width, dst_height;
760 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);
761 568
762 if (dst_x > 0 || dst_y > 0 569 if (dst_x > 0 || dst_y > 0
763 || dst_x + dst_width < new_pmap_width 570 || dst_x + dst_width < new_pmap_width
764 || dst_y + dst_height < new_pmap_height) 571 || dst_y + dst_height < new_pmap_height)
765 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);
766 573
767 if (dst_x < new_pmap_width && dst_y < new_pmap_height) 574 if (dst_x < new_pmap_width && dst_y < new_pmap_height)
768 gdk_pixbuf_xlib_render_to_drawable (result, pixmap, gc, 575 pixbuf_to_pixmap (result, bg_pixmap, gc,
769 src_x, src_y, 576 src_x, src_y,
770 dst_x, dst_y, 577 dst_x, dst_y,
771 dst_width, dst_height, 578 dst_width, dst_height);
772 XLIB_RGB_DITHER_NONE,
773 0, 0);
774 } 579 }
775 580
776#if XRENDER 581#if XRENDER
777 if (background_flags) 582 if (transparent)
778 { 583 {
779 Display *dpy = target->dpy;
780 XRenderPictureAttributes pa;
781
782 XRenderPictFormat *src_format = XRenderFindVisualFormat (dpy, target->visual); 584 XRenderPictFormat *format = XRenderFindVisualFormat (dpy, visual);
585
783 Picture src = XRenderCreatePicture (dpy, root_pmap, src_format, 0, &pa); 586 Picture src = XRenderCreatePicture (dpy, root_pmap, format, 0, 0);
784 587
785 XRenderPictFormat *dst_format = XRenderFindVisualFormat (dpy, target->visual);
786 Picture dst = XRenderCreatePicture (dpy, pixmap, dst_format, 0, &pa); 588 Picture dst = XRenderCreatePicture (dpy, bg_pixmap, format, 0, 0);
787 589
788 pa.repeat = True; 590 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 591
794 if (src && dst && mask)
795 {
796 XRenderColor mask_c; 592 XRenderColor mask_c;
797 593
798 mask_c.alpha = 0x8000; 594 mask_c.alpha = 0x8000;
799 mask_c.red = 0; 595 mask_c.red =
800 mask_c.green = 0; 596 mask_c.green =
801 mask_c.blue = 0; 597 mask_c.blue = 0;
802 XRenderFillRectangle (dpy, PictOpSrc, mask, &mask_c, 0, 0, 1, 1); 598 XRenderFillRectangle (dpy, PictOpSrc, mask, &mask_c, 0, 0, 1, 1);
599
803 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);
804 }
805 601
806 XRenderFreePicture (dpy, src); 602 XRenderFreePicture (dpy, src);
807 XRenderFreePicture (dpy, dst); 603 XRenderFreePicture (dpy, dst);
808 XRenderFreePicture (dpy, mask); 604 XRenderFreePicture (dpy, mask);
809
810 XFreePixmap (dpy, root_pmap);
811 } 605 }
812#endif 606#endif
813 607
814 if (result != pixbuf)
815 g_object_unref (result);
816
817 XFreeGC (target->dpy, gc); 608 XFreeGC (dpy, gc);
818 609
819 ret = true; 610 ret = true;
820 } 611 }
821 612
613 if (result != pixbuf)
614 g_object_unref (result);
615
616 if (transparent)
617 XFreePixmap (dpy, root_pmap);
618
822 return ret; 619 return ret;
823} 620}
824# endif /* HAVE_PIXBUF */ 621# endif /* HAVE_PIXBUF */
825 622
826bool 623bool
827bgPixmap_t::set_file (const char *file) 624rxvt_term::bg_set_file (const char *file)
828{ 625{
829 if (!file || !*file) 626 if (!file || !*file)
830 return false; 627 return false;
831 628
629 bool ret = false;
832 if (const char *p = strchr (file, ';')) 630 const char *p = strchr (file, ';');
631
632 if (p)
833 { 633 {
834 size_t len = p - file; 634 size_t len = p - file;
835 char *f = rxvt_temp_buf<char> (len + 1); 635 char *f = rxvt_temp_buf<char> (len + 1);
836 memcpy (f, file, len); 636 memcpy (f, file, len);
837 f[len] = '\0'; 637 f[len] = '\0';
838 file = f; 638 file = f;
839 } 639 }
840 640
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 641# ifdef HAVE_PIXBUF
856 GdkPixbuf *image = gdk_pixbuf_new_from_file (file, NULL); 642 GdkPixbuf *image = gdk_pixbuf_new_from_file (file, NULL);
857 if (image) 643 if (image)
858 { 644 {
859 if (pixbuf) 645 if (pixbuf)
860 g_object_unref (pixbuf); 646 g_object_unref (pixbuf);
861 pixbuf = image; 647 pixbuf = image;
862 have_image = true; 648 bg_flags |= BG_IS_FROM_FILE;
863 return true; 649 ret = true;
864 } 650 }
865# endif 651# endif
866 652
653 if (ret)
654 {
655 if (p)
656 bg_set_geometry (p + 1);
657 else
658 bg_set_default_geometry ();
659 }
660
867 return false; 661 return ret;
868} 662}
869 663
870# endif /* BG_IMAGE_FROM_FILE */ 664# endif /* BG_IMAGE_FROM_FILE */
871 665
872# ifdef ENABLE_TRANSPARENCY 666# ifdef ENABLE_TRANSPARENCY
873bool 667bool
874bgPixmap_t::set_transparent () 668rxvt_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{ 669{
888 bool changed = false; 670 bool changed = false;
889 unsigned int hr, vr; 671 unsigned int hr, vr;
890 int junk; 672 int junk;
891 int geom_flags = XParseGeometry (geom, &junk, &junk, &hr, &vr); 673 int geom_flags = XParseGeometry (geom, &junk, &junk, &hr, &vr);
908 { 690 {
909 changed = true; 691 changed = true;
910 v_blurRadius = vr; 692 v_blurRadius = vr;
911 } 693 }
912 694
913 if (v_blurRadius == 0 && h_blurRadius == 0)
914 flags &= ~blurNeeded;
915 else
916 flags |= blurNeeded;
917
918 return changed; 695 return changed;
919} 696}
920 697
921static inline unsigned long 698bool
922compute_tint_shade_flags (rxvt_color *tint, int shade) 699rxvt_term::bg_set_tint (rxvt_color &new_tint)
923{ 700{
924 unsigned long flags = 0; 701 if (!(bg_flags & BG_TINT_SET) || tint != new_tint)
925 rgba c (rgba::MAX_CC,rgba::MAX_CC,rgba::MAX_CC);
926 bool has_shade = shade != 100;
927
928 if (tint)
929 {
930 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 } 702 {
938
939 if (has_shade)
940 flags |= bgPixmap_t::tintNeeded;
941 else if (tint)
942 {
943 if ((c.r > 0x000700 || c.g > 0x000700 || c.b > 0x000700)
944 && (c.r < 0x00f700 || c.g < 0x00f700 || c.b < 0x00f700))
945 {
946 flags |= bgPixmap_t::tintNeeded;
947 }
948 }
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; 703 tint = new_tint;
960 flags = (flags & ~tintFlags) | new_flags | tintSet; 704 bg_flags |= BG_TINT_SET;
705
706 rgba c;
707 tint.get (c);
708 if ((c.r <= 0x00ff || c.r >= 0xff00)
709 && (c.g <= 0x00ff || c.g >= 0xff00)
710 && (c.b <= 0x00ff || c.b >= 0xff00))
711 bg_flags |= BG_TINT_BITAND;
712 else
713 bg_flags &= ~BG_TINT_BITAND;
714
961 return true; 715 return true;
962 } 716 }
963 717
964 return false; 718 return false;
965} 719}
966 720
967bool 721bool
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) 722rxvt_term::bg_set_shade (const char *shade_str)
983{ 723{
984 int new_shade = (shade_str) ? atoi (shade_str) : 100; 724 int new_shade = atoi (shade_str);
985 725
986 clamp_it (new_shade, -100, 200); 726 clamp_it (new_shade, -100, 200);
987 if (new_shade < 0) 727 if (new_shade < 0)
988 new_shade = 200 - (100 + new_shade); 728 new_shade = 200 - (100 + new_shade);
989 729
990 if (new_shade != shade) 730 if (new_shade != shade)
991 { 731 {
992 unsigned long new_flags = compute_tint_shade_flags ((flags & tintSet) ? &tint : NULL, new_shade);
993 shade = new_shade; 732 shade = new_shade;
994 flags = (flags & (~tintFlags | tintSet)) | new_flags;
995 return true; 733 return true;
996 } 734 }
997 735
998 return false; 736 return false;
999} 737}
1020 params[i+2] = XDoubleToFixed (kernel[i] / sum); 758 params[i+2] = XDoubleToFixed (kernel[i] / sum);
1021} 759}
1022#endif 760#endif
1023 761
1024bool 762bool
1025bgPixmap_t::blur_pixmap (Pixmap pixmap, Visual *visual, int width, int height) 763rxvt_term::blur_pixmap (Pixmap pixmap, int width, int height)
1026{ 764{
1027 bool ret = false; 765 bool ret = false;
1028#if XRENDER 766#if XRENDER
767 if (!(bg_flags & BG_HAS_RENDER_CONV))
768 return false;
769
1029 int size = max (h_blurRadius, v_blurRadius) * 2 + 1; 770 int size = max (h_blurRadius, v_blurRadius) * 2 + 1;
1030 double *kernel = (double *)malloc (size * sizeof (double)); 771 double *kernel = (double *)malloc (size * sizeof (double));
1031 XFixed *params = (XFixed *)malloc ((size + 2) * sizeof (XFixed)); 772 XFixed *params = (XFixed *)malloc ((size + 2) * sizeof (XFixed));
1032 773
1033 Display *dpy = target->dpy;
1034 XRenderPictureAttributes pa; 774 XRenderPictureAttributes pa;
1035 XRenderPictFormat *format = XRenderFindVisualFormat (dpy, visual); 775 XRenderPictFormat *format = XRenderFindVisualFormat (dpy, visual);
1036 776
777 pa.repeat = RepeatPad;
1037 Picture src = XRenderCreatePicture (dpy, pixmap, format, 0, &pa); 778 Picture src = XRenderCreatePicture (dpy, pixmap, format, CPRepeat, &pa);
779 Pixmap tmp = XCreatePixmap (dpy, pixmap, width, height, depth);
1038 Picture dst = XRenderCreatePicture (dpy, pixmap, format, 0, &pa); 780 Picture dst = XRenderCreatePicture (dpy, tmp, format, CPRepeat, &pa);
781 XFreePixmap (dpy, tmp);
1039 782
1040 if (kernel && params && src && dst) 783 if (kernel && params)
1041 { 784 {
1042 if (h_blurRadius)
1043 {
1044 size = h_blurRadius * 2 + 1; 785 size = h_blurRadius * 2 + 1;
1045 get_gaussian_kernel (h_blurRadius, size, kernel, params); 786 get_gaussian_kernel (h_blurRadius, size, kernel, params);
1046 787
1047 XRenderSetPictureFilter (dpy, src, FilterConvolution, params, size+2); 788 XRenderSetPictureFilter (dpy, src, FilterConvolution, params, size+2);
1048 XRenderComposite (dpy, 789 XRenderComposite (dpy,
1049 PictOpSrc, 790 PictOpSrc,
1050 src, 791 src,
1051 None, 792 None,
1052 dst, 793 dst,
1053 0, 0, 794 0, 0,
1054 0, 0, 795 0, 0,
1055 0, 0, 796 0, 0,
1056 width, height); 797 width, height);
1057 }
1058 798
1059 if (v_blurRadius) 799 ::swap (src, dst);
1060 { 800
1061 size = v_blurRadius * 2 + 1; 801 size = v_blurRadius * 2 + 1;
1062 get_gaussian_kernel (v_blurRadius, size, kernel, params); 802 get_gaussian_kernel (v_blurRadius, size, kernel, params);
1063 swap (params[0], params[1]); 803 ::swap (params[0], params[1]);
1064 804
1065 XRenderSetPictureFilter (dpy, src, FilterConvolution, params, size+2); 805 XRenderSetPictureFilter (dpy, src, FilterConvolution, params, size+2);
1066 XRenderComposite (dpy, 806 XRenderComposite (dpy,
1067 PictOpSrc, 807 PictOpSrc,
1068 src, 808 src,
1069 None, 809 None,
1070 dst, 810 dst,
1071 0, 0, 811 0, 0,
1072 0, 0, 812 0, 0,
1073 0, 0, 813 0, 0,
1074 width, height); 814 width, height);
1075 }
1076 815
1077 ret = true; 816 ret = true;
1078 } 817 }
1079 818
1080 free (kernel); 819 free (kernel);
1084#endif 823#endif
1085 return ret; 824 return ret;
1086} 825}
1087 826
1088bool 827bool
1089bgPixmap_t::tint_pixmap (Pixmap pixmap, Visual *visual, int width, int height) 828rxvt_term::tint_pixmap (Pixmap pixmap, int width, int height)
1090{ 829{
1091 Display *dpy = target->dpy;
1092 bool ret = false; 830 bool ret = false;
1093 831
1094 if (flags & tintWholesome) 832 if (shade == 100 && (bg_flags & BG_TINT_BITAND))
1095 { 833 {
1096 XGCValues gcv; 834 XGCValues gcv;
1097 GC gc; 835 GC gc;
1098 836
1099 /* In this case we can tint image server-side getting significant 837 /* In this case we can tint image server-side getting significant
1108 XFillRectangle (dpy, pixmap, gc, 0, 0, width, height); 846 XFillRectangle (dpy, pixmap, gc, 0, 0, width, height);
1109 ret = true; 847 ret = true;
1110 XFreeGC (dpy, gc); 848 XFreeGC (dpy, gc);
1111 } 849 }
1112 } 850 }
1113 else
1114 {
1115# if XRENDER 851# if XRENDER
852 else if (bg_flags & BG_HAS_RENDER)
853 {
1116 rgba c (rgba::MAX_CC,rgba::MAX_CC,rgba::MAX_CC); 854 rgba c (rgba::MAX_CC, rgba::MAX_CC, rgba::MAX_CC);
1117 855
1118 if (flags & tintSet) 856 if (bg_flags & BG_TINT_SET)
1119 tint.get (c); 857 tint.get (c);
1120 858
1121 if (shade <= 100) 859 if (shade <= 100)
1122 { 860 {
1123 c.r = (c.r * shade) / 100; 861 c.r = c.r * shade / 100;
1124 c.g = (c.g * shade) / 100; 862 c.g = c.g * shade / 100;
1125 c.b = (c.b * shade) / 100; 863 c.b = c.b * shade / 100;
1126 } 864 }
1127 else 865 else
1128 { 866 {
1129 c.r = ((0xffff - c.r) * (200 - shade)) / 100; 867 c.r = c.r * (200 - shade) / 100;
1130 c.g = ((0xffff - c.g) * (200 - shade)) / 100; 868 c.g = c.g * (200 - shade) / 100;
1131 c.b = ((0xffff - c.b) * (200 - shade)) / 100; 869 c.b = c.b * (200 - shade) / 100;
1132 } 870 }
1133 871
1134 XRenderPictFormat *solid_format = XRenderFindStandardFormat (dpy, PictStandardARGB32);
1135 XRenderPictFormat *format = XRenderFindVisualFormat (dpy, visual); 872 XRenderPictFormat *format = XRenderFindVisualFormat (dpy, visual);
1136 XRenderPictureAttributes pa;
1137 873
1138 Picture back_pic = XRenderCreatePicture (dpy, pixmap, format, 0, &pa); 874 Picture back_pic = XRenderCreatePicture (dpy, pixmap, format, 0, 0);
1139 875
1140 pa.repeat = True; 876 Picture overlay_pic = create_xrender_mask (dpy, pixmap, True, False);
1141 877
1142 Pixmap overlay_pmap = XCreatePixmap (dpy, pixmap, 1, 1, 32); 878 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 879
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; 880 XRenderColor mask_c;
1154 881
1155 mask_c.red = mask_c.green = mask_c.blue = shade > 100 ? 0xffff : 0;
1156 mask_c.alpha = 0xffff; 882 mask_c.alpha = 0xffff;
883 mask_c.red =
884 mask_c.green =
885 mask_c.blue = 0;
886 XRenderFillRectangle (dpy, PictOpSrc, overlay_pic, &mask_c, 0, 0, 1, 1);
887
888 mask_c.alpha = 0;
889 mask_c.red = 0xffff - c.r;
890 mask_c.green = 0xffff - c.g;
891 mask_c.blue = 0xffff - c.b;
892 XRenderFillRectangle (dpy, PictOpSrc, mask_pic, &mask_c, 0, 0, 1, 1);
893
894 XRenderComposite (dpy, PictOpOver, overlay_pic, mask_pic, back_pic, 0, 0, 0, 0, 0, 0, width, height);
895
896 if (shade > 100)
897 {
898 mask_c.alpha = 0;
899 mask_c.red =
900 mask_c.green =
901 mask_c.blue = 0xffff * (shade - 100) / 100;
1157 XRenderFillRectangle (dpy, PictOpSrc, overlay_pic, &mask_c, 0, 0, 1, 1); 902 XRenderFillRectangle (dpy, PictOpSrc, overlay_pic, &mask_c, 0, 0, 1, 1);
1158 903
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); 904 XRenderComposite (dpy, PictOpOver, overlay_pic, None, back_pic, 0, 0, 0, 0, 0, 0, width, height);
1165 ret = true;
1166 } 905 }
906
907 ret = true;
1167 908
1168 XRenderFreePicture (dpy, mask_pic); 909 XRenderFreePicture (dpy, mask_pic);
1169 XRenderFreePicture (dpy, overlay_pic); 910 XRenderFreePicture (dpy, overlay_pic);
1170 XRenderFreePicture (dpy, back_pic); 911 XRenderFreePicture (dpy, back_pic);
912 }
1171# endif 913# endif
1172 }
1173 914
1174 return ret; 915 return ret;
1175} 916}
1176 917
1177/* make_transparency_pixmap() 918/*
1178 * Builds a pixmap of the same size as the terminal window that contains 919 * 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 920 * the tiled portion of the root pixmap that is supposed to be covered by
1180 * our window. 921 * our window.
1181 */ 922 */
1182unsigned long 923bool
1183bgPixmap_t::make_transparency_pixmap () 924rxvt_term::make_transparency_pixmap ()
1184{ 925{
1185 unsigned long result = 0; 926 bool ret = false;
1186
1187 if (target == NULL)
1188 return 0;
1189 927
1190 /* root dimensions may change from call to call - but Display structure should 928 /* root dimensions may change from call to call - but Display structure should
1191 * be always up-to-date, so let's use it : 929 * be always up-to-date, so let's use it :
1192 */ 930 */
1193 int screen = target->display->screen; 931 int screen = display->screen;
1194 Display *dpy = target->dpy;
1195 int root_depth = DefaultDepth (dpy, screen); 932 int root_depth = DefaultDepth (dpy, screen);
1196 int root_width = DisplayWidth (dpy, screen); 933 int root_width = DisplayWidth (dpy, screen);
1197 int root_height = DisplayHeight (dpy, screen); 934 int root_height = DisplayHeight (dpy, screen);
1198 unsigned int root_pmap_width, root_pmap_height; 935 unsigned int root_pmap_width, root_pmap_height;
1199 int window_width = target->szHint.width; 936 int window_width = szHint.width;
1200 int window_height = target->szHint.height; 937 int window_height = szHint.height;
1201 int sx, sy; 938 int sx, sy;
1202 XGCValues gcv; 939 XGCValues gcv;
1203 GC gc; 940 GC gc;
1204 941
1205 target->get_window_origin (sx, sy); 942 sx = target_x;
943 sy = target_y;
1206 944
1207 /* check if we are outside of the visible part of the virtual screen : */ 945 /* check if we are outside of the visible part of the virtual screen : */
1208 if (sx + window_width <= 0 || sy + window_height <= 0 946 if (sx + window_width <= 0 || sy + window_height <= 0
1209 || sx >= root_width || sy >= root_height) 947 || sx >= root_width || sy >= root_height)
1210 return 0; 948 return 0;
1214 { 952 {
1215 Window wdummy; 953 Window wdummy;
1216 int idummy; 954 int idummy;
1217 unsigned int udummy; 955 unsigned int udummy;
1218 956
1219 target->allowedxerror = -1; 957 allowedxerror = -1;
1220 958
1221 if (!XGetGeometry (dpy, root_pixmap, &wdummy, &idummy, &idummy, &root_pmap_width, &root_pmap_height, &udummy, &udummy)) 959 if (!XGetGeometry (dpy, root_pixmap, &wdummy, &idummy, &idummy, &root_pmap_width, &root_pmap_height, &udummy, &udummy))
1222 root_pixmap = None; 960 root_pixmap = None;
1223 961
1224 target->allowedxerror = 0; 962 allowedxerror = 0;
1225 } 963 }
1226 964
1227 Pixmap recoded_root_pmap = root_pixmap; 965 Pixmap recoded_root_pmap = root_pixmap;
1228 966
1229 if (root_pixmap != None && root_depth != target->depth) 967 if (root_pixmap != None && root_depth != depth)
1230 { 968 {
1231#if XRENDER 969#if XRENDER
1232 if (flags & HAS_RENDER) 970 if (bg_flags & BG_HAS_RENDER)
1233 { 971 {
1234 XRenderPictureAttributes pa; 972 recoded_root_pmap = XCreatePixmap (dpy, vt, root_pmap_width, root_pmap_height, depth);
1235 973
1236 XRenderPictFormat *src_format = XRenderFindVisualFormat (dpy, DefaultVisual (dpy, screen)); 974 XRenderPictFormat *src_format = XRenderFindVisualFormat (dpy, DefaultVisual (dpy, screen));
1237 Picture src = XRenderCreatePicture (dpy, root_pixmap, src_format, 0, &pa); 975 Picture src = XRenderCreatePicture (dpy, root_pixmap, src_format, 0, 0);
1238 976
1239 recoded_root_pmap = XCreatePixmap (dpy, target->vt, root_pmap_width, root_pmap_height, target->depth);
1240 XRenderPictFormat *dst_format = XRenderFindVisualFormat (dpy, target->visual); 977 XRenderPictFormat *dst_format = XRenderFindVisualFormat (dpy, visual);
1241 Picture dst = XRenderCreatePicture (dpy, recoded_root_pmap, dst_format, 0, &pa); 978 Picture dst = XRenderCreatePicture (dpy, recoded_root_pmap, dst_format, 0, 0);
1242 979
1243 if (src && dst)
1244 XRenderComposite (dpy, PictOpSrc, src, None, dst, 0, 0, 0, 0, 0, 0, root_pmap_width, root_pmap_height); 980 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 981
1251 XRenderFreePicture (dpy, src); 982 XRenderFreePicture (dpy, src);
1252 XRenderFreePicture (dpy, dst); 983 XRenderFreePicture (dpy, dst);
1253 } 984 }
1254 else 985 else
1255#endif 986#endif
1256 root_pixmap = None; 987 recoded_root_pmap = None;
1257 } 988 }
1258 989
1259 if (root_pixmap == None) 990 if (recoded_root_pmap == None)
1260 return 0; 991 return 0;
1261 992
993 if (bg_pixmap == None
994 || bg_pmap_width != window_width
995 || bg_pmap_height != window_height)
996 {
997 if (bg_pixmap)
998 XFreePixmap (dpy, bg_pixmap);
1262 Pixmap tiled_root_pmap = XCreatePixmap (dpy, target->vt, window_width, window_height, target->depth); 999 bg_pixmap = XCreatePixmap (dpy, vt, window_width, window_height, depth);
1263 1000 bg_pmap_width = window_width;
1264 if (tiled_root_pmap == None) /* something really bad happened - abort */ 1001 bg_pmap_height = window_height;
1265 return 0; 1002 }
1266 1003
1267 /* straightforward pixmap copy */ 1004 /* straightforward pixmap copy */
1005 while (sx < 0) sx += root_pmap_width;
1006 while (sy < 0) sy += root_pmap_height;
1007
1268 gcv.tile = recoded_root_pmap; 1008 gcv.tile = recoded_root_pmap;
1269 gcv.fill_style = FillTiled; 1009 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; 1010 gcv.ts_x_origin = -sx;
1275 gcv.ts_y_origin = -sy; 1011 gcv.ts_y_origin = -sy;
1276 gc = XCreateGC (dpy, target->vt, GCFillStyle | GCTile | GCTileStipXOrigin | GCTileStipYOrigin, &gcv); 1012 gc = XCreateGC (dpy, vt, GCFillStyle | GCTile | GCTileStipXOrigin | GCTileStipYOrigin, &gcv);
1277 1013
1278 if (gc) 1014 if (gc)
1279 { 1015 {
1280 XFillRectangle (dpy, tiled_root_pmap, gc, 0, 0, window_width, window_height); 1016 XFillRectangle (dpy, bg_pixmap, gc, 0, 0, window_width, window_height);
1281 result |= transpPmapTiled; 1017 ret = true;
1018 bool need_blur = h_blurRadius && v_blurRadius;
1019 bool need_tint = shade != 100 || (bg_flags & BG_TINT_SET);
1020
1021 if (!(bg_flags & BG_CLIENT_RENDER))
1022 {
1023 if (need_blur)
1024 {
1025 if (blur_pixmap (bg_pixmap, window_width, window_height))
1026 need_blur = false;
1027 }
1028 if (need_tint)
1029 {
1030 if (tint_pixmap (bg_pixmap, window_width, window_height))
1031 need_tint = false;
1032 }
1033 if (need_tint)
1034 {
1035 XImage *ximage = XGetImage (dpy, bg_pixmap, 0, 0, bg_pmap_width, bg_pmap_height, AllPlanes, ZPixmap);
1036 if (ximage)
1037 {
1038 /* our own client-side tinting */
1039 tint_ximage (ximage);
1040
1041 XPutImage (dpy, bg_pixmap, gc, ximage, 0, 0, 0, 0, ximage->width, ximage->height);
1042 XDestroyImage (ximage);
1043 }
1044 }
1045 } /* server side rendering completed */
1046
1282 XFreeGC (dpy, gc); 1047 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 } 1048 }
1308 else
1309 XFreePixmap (dpy, tiled_root_pmap);
1310 1049
1311 if (recoded_root_pmap != root_pixmap) 1050 if (recoded_root_pmap != root_pixmap)
1312 XFreePixmap (dpy, recoded_root_pmap); 1051 XFreePixmap (dpy, recoded_root_pmap);
1313 1052
1314 return result; 1053 return ret;
1315} 1054}
1316 1055
1317void 1056void
1318bgPixmap_t::set_root_pixmap () 1057rxvt_term::bg_set_root_pixmap ()
1319{ 1058{
1320 Pixmap new_root_pixmap = target->get_pixmap_property (XA_XROOTPMAP_ID); 1059 Pixmap new_root_pixmap = get_pixmap_property (xa[XA_XROOTPMAP_ID]);
1321 if (new_root_pixmap == None) 1060 if (new_root_pixmap == None)
1322 new_root_pixmap = target->get_pixmap_property (XA_ESETROOT_PMAP_ID); 1061 new_root_pixmap = get_pixmap_property (xa[XA_ESETROOT_PMAP_ID]);
1323 1062
1324 root_pixmap = new_root_pixmap; 1063 root_pixmap = new_root_pixmap;
1325} 1064}
1326# endif /* ENABLE_TRANSPARENCY */ 1065# endif /* ENABLE_TRANSPARENCY */
1327 1066
1328#if defined(ENABLE_TRANSPARENCY) && !defined(HAVE_AFTERIMAGE) 1067bool
1329static void ShadeXImage(Visual *visual, XImage *srcImage, int shade, const rgba &c); 1068rxvt_term::bg_render ()
1069{
1070 bool transparent = false;
1071
1072 bg_invalidate ();
1073# ifdef ENABLE_TRANSPARENCY
1074 if (bg_flags & BG_IS_TRANSPARENT)
1075 {
1076 /* we need to re-generate transparency pixmap in that case ! */
1077 transparent = make_transparency_pixmap ();
1078 if (transparent)
1079 bg_flags |= BG_IS_VALID;
1080 }
1330# endif 1081# endif
1331 1082
1332bool 1083# ifdef BG_IMAGE_FROM_FILE
1333bgPixmap_t::render () 1084 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 { 1085 {
1344 /* we need to re-generate transparency pixmap in that case ! */ 1086 if (render_image (transparent))
1345 background_flags = make_transparency_pixmap (); 1087 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 } 1088 }
1351# endif 1089# endif
1352 1090
1353# ifdef BG_IMAGE_FROM_FILE 1091 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 } 1092 {
1360# endif 1093 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 { 1094 {
1375 rgba c (rgba::MAX_CC,rgba::MAX_CC,rgba::MAX_CC); 1095 XFreePixmap (dpy, bg_pixmap);
1376 if (flags & tintSet) 1096 bg_pixmap = None;
1377 tint.get (c);
1378 ShadeXImage (DefaultVisual (target->dpy, target->display->screen), result, shade, c);
1379 } 1097 }
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 { 1098 }
1397 if (pixmap != None)
1398 {
1399 XFreePixmap (target->dpy, pixmap);
1400 pixmap = None;
1401 }
1402 }
1403 1099
1404 apply (); 1100 scr_recolour (false);
1101 bg_flags |= BG_NEEDS_REFRESH;
1405 1102
1406 valid_since = ev::now (); 1103 bg_valid_since = ev::now ();
1407 1104
1408 return true; 1105 return true;
1409} 1106}
1410 1107
1411void 1108void
1412bgPixmap_t::set_target (rxvt_term *new_target) 1109rxvt_term::bg_init ()
1413{ 1110{
1414 target = new_target; 1111#ifdef ENABLE_TRANSPARENCY
1112 shade = 100;
1113#endif
1415 1114
1416 flags &= ~(HAS_RENDER | HAS_RENDER_CONV); 1115 bg_flags &= ~(BG_HAS_RENDER | BG_HAS_RENDER_CONV);
1417#if XRENDER 1116#if XRENDER
1418 int major, minor; 1117 int major, minor;
1419 if (XRenderQueryVersion (target->dpy, &major, &minor)) 1118 if (XRenderQueryVersion (dpy, &major, &minor))
1420 flags |= HAS_RENDER; 1119 bg_flags |= BG_HAS_RENDER;
1421 XFilters *filters = XRenderQueryFilters (target->dpy, target->vt); 1120 XFilters *filters = XRenderQueryFilters (dpy, vt);
1422 if (filters) 1121 if (filters)
1423 { 1122 {
1424 for (int i = 0; i < filters->nfilter; i++) 1123 for (int i = 0; i < filters->nfilter; i++)
1425 if (!strcmp (filters->filter[i], FilterConvolution)) 1124 if (!strcmp (filters->filter[i], FilterConvolution))
1426 flags |= HAS_RENDER_CONV; 1125 bg_flags |= BG_HAS_RENDER_CONV;
1427 1126
1428 XFree (filters); 1127 XFree (filters);
1429 } 1128 }
1430#endif 1129#endif
1431} 1130}
1432 1131
1132#endif /* HAVE_BG_PIXMAP */
1133
1134#ifdef ENABLE_TRANSPARENCY
1135/* based on code from aterm-0.4.2 */
1136
1137static inline void
1138fill_lut (uint32_t *lookup, uint32_t mask, int sh, unsigned short low, unsigned short high)
1139{
1140 for (int i = 0; i <= mask >> sh; i++)
1141 {
1142 uint32_t tmp;
1143 tmp = i * high;
1144 tmp += (mask >> sh) * low;
1145 lookup[i] = (tmp / 0xffff) << sh;
1146 }
1147}
1148
1433void 1149void
1434bgPixmap_t::apply () 1150rxvt_term::tint_ximage (XImage *ximage)
1435{ 1151{
1436 if (target == NULL) 1152 unsigned int size_r, size_g, size_b;
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{
1495 int sh_r, sh_g, sh_b; 1153 int sh_r, sh_g, sh_b;
1496 uint32_t mask_r, mask_g, mask_b; 1154 uint32_t mask_r, mask_g, mask_b;
1497 uint32_t *lookup, *lookup_r, *lookup_g, *lookup_b; 1155 uint32_t *lookup, *lookup_r, *lookup_g, *lookup_b;
1498 rgba low; 1156 unsigned short low;
1499 rgba high;
1500 int i;
1501 int host_byte_order = byteorder.big_endian () ? MSBFirst : LSBFirst; 1157 int host_byte_order = ecb_big_endian () ? MSBFirst : LSBFirst;
1502 1158
1503 if (visual->c_class != TrueColor || srcImage->format != ZPixmap) return; 1159 if (visual->c_class != TrueColor || ximage->format != ZPixmap) return;
1504 1160
1505 /* for convenience */ 1161 /* for convenience */
1506 mask_r = visual->red_mask; 1162 mask_r = visual->red_mask;
1507 mask_g = visual->green_mask; 1163 mask_g = visual->green_mask;
1508 mask_b = visual->blue_mask; 1164 mask_b = visual->blue_mask;
1509 1165
1510 /* boring lookup table pre-initialization */ 1166 /* boring lookup table pre-initialization */
1511 switch (srcImage->depth) 1167 sh_r = ecb_ctz32 (mask_r);
1512 { 1168 sh_g = ecb_ctz32 (mask_g);
1513 case 15: 1169 sh_b = ecb_ctz32 (mask_b);
1514 if ((mask_r != 0x7c00) || 1170
1515 (mask_g != 0x03e0) || 1171 size_r = mask_r >> sh_r;
1516 (mask_b != 0x001f)) 1172 size_g = mask_g >> sh_g;
1173 size_b = mask_b >> sh_b;
1174
1175 if (size_r++ > 255 || size_g++ > 255 || size_b++ > 255)
1517 return; 1176 return;
1518 lookup = (uint32_t *) malloc (sizeof (uint32_t)*(32+32+32)); 1177
1178 lookup = (uint32_t *)malloc (sizeof (uint32_t) * (size_r + size_g + size_b));
1519 lookup_r = lookup; 1179 lookup_r = lookup;
1520 lookup_g = lookup+32; 1180 lookup_g = lookup + size_r;
1521 lookup_b = lookup+32+32; 1181 lookup_b = lookup + size_r + size_g;
1522 sh_r = 10; 1182
1523 sh_g = 5; 1183 rgba c (rgba::MAX_CC, rgba::MAX_CC, rgba::MAX_CC);
1524 sh_b = 0; 1184
1525 break; 1185 if (bg_flags & BG_TINT_SET)
1526 case 16: 1186 tint.get (c);
1527 if ((mask_r != 0xf800) ||
1528 (mask_g != 0x07e0) ||
1529 (mask_b != 0x001f))
1530 return;
1531 lookup = (uint32_t *) malloc (sizeof (uint32_t)*(32+64+32));
1532 lookup_r = lookup;
1533 lookup_g = lookup+32;
1534 lookup_b = lookup+32+64;
1535 sh_r = 11;
1536 sh_g = 5;
1537 sh_b = 0;
1538 break;
1539 case 24:
1540 if ((mask_r != 0xff0000) ||
1541 (mask_g != 0x00ff00) ||
1542 (mask_b != 0x0000ff))
1543 return;
1544 lookup = (uint32_t *) malloc (sizeof (uint32_t)*(256+256+256));
1545 lookup_r = lookup;
1546 lookup_g = lookup+256;
1547 lookup_b = lookup+256+256;
1548 sh_r = 16;
1549 sh_g = 8;
1550 sh_b = 0;
1551 break;
1552 case 32:
1553 if ((mask_r != 0xff0000) ||
1554 (mask_g != 0x00ff00) ||
1555 (mask_b != 0x0000ff))
1556 return;
1557 lookup = (uint32_t *) malloc (sizeof (uint32_t)*(256+256+256));
1558 lookup_r = lookup;
1559 lookup_g = lookup+256;
1560 lookup_b = lookup+256+256;
1561 sh_r = 16;
1562 sh_g = 8;
1563 sh_b = 0;
1564 break;
1565 default:
1566 return; /* we do not support this color depth */
1567 }
1568 1187
1569 /* prepare limits for color transformation (each channel is handled separately) */ 1188 /* prepare limits for color transformation (each channel is handled separately) */
1570 if (shade > 100) 1189 if (shade > 100)
1571 { 1190 {
1572 shade = 200 - shade; 1191 c.r = c.r * (200 - shade) / 100;
1192 c.g = c.g * (200 - shade) / 100;
1193 c.b = c.b * (200 - shade) / 100;
1573 1194
1574 high.r = (65535 - c.r) * shade / 100; 1195 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 } 1196 }
1582 else 1197 else
1583 { 1198 {
1584 high.r = c.r * shade / 100; 1199 c.r = c.r * shade / 100;
1585 high.g = c.g * shade / 100; 1200 c.g = c.g * shade / 100;
1586 high.b = c.b * shade / 100; 1201 c.b = c.b * shade / 100;
1587 1202
1588 low.r = low.g = low.b = 0; 1203 low = 0;
1589 } 1204 }
1590 1205
1591 /* fill our lookup tables */ 1206 /* fill our lookup tables */
1592 for (i = 0; i <= mask_r>>sh_r; i++) 1207 fill_lut (lookup_r, mask_r, sh_r, low, c.r);
1593 { 1208 fill_lut (lookup_g, mask_g, sh_g, low, c.g);
1594 uint32_t tmp; 1209 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 1210
1614 /* apply table to input image (replacing colors by newly calculated ones) */ 1211 /* apply table to input image (replacing colors by newly calculated ones) */
1615 if (srcImage->bits_per_pixel == 32 1212 if (ximage->bits_per_pixel == 32
1616 && (srcImage->depth == 24 || srcImage->depth == 32)
1617 && srcImage->byte_order == host_byte_order) 1213 && ximage->byte_order == host_byte_order)
1618 { 1214 {
1619 uint32_t *p1, *pf, *p, *pl; 1215 char *line = ximage->data;
1620 p1 = (uint32_t *) srcImage->data;
1621 pf = (uint32_t *) (srcImage->data + srcImage->height * srcImage->bytes_per_line);
1622 1216
1623 while (p1 < pf) 1217 for (int y = 0; y < ximage->height; y++)
1624 {
1625 p = p1;
1626 pl = p1 + srcImage->width;
1627 for (; p < pl; p++)
1628 { 1218 {
1629 *p = lookup_r[(*p & 0xff0000) >> 16] | 1219 uint32_t *p = (uint32_t *)line;
1630 lookup_g[(*p & 0x00ff00) >> 8] | 1220 for (int x = 0; x < ximage->width; x++)
1631 lookup_b[(*p & 0x0000ff)] |
1632 (*p & 0xff000000);
1633 } 1221 {
1634 p1 = (uint32_t *) ((char *) p1 + srcImage->bytes_per_line); 1222 *p = lookup_r[(*p & mask_r) >> sh_r] |
1223 lookup_g[(*p & mask_g) >> sh_g] |
1224 lookup_b[(*p & mask_b) >> sh_b];
1225 p++;
1226 }
1227 line += ximage->bytes_per_line;
1635 } 1228 }
1636 } 1229 }
1637 else 1230 else
1638 { 1231 {
1639 for (int y = 0; y < srcImage->height; y++) 1232 for (int y = 0; y < ximage->height; y++)
1640 for (int x = 0; x < srcImage->width; x++) 1233 for (int x = 0; x < ximage->width; x++)
1641 { 1234 {
1642 unsigned long pixel = XGetPixel (srcImage, x, y); 1235 unsigned long pixel = XGetPixel (ximage, x, y);
1643 pixel = lookup_r[(pixel & mask_r) >> sh_r] | 1236 pixel = lookup_r[(pixel & mask_r) >> sh_r] |
1644 lookup_g[(pixel & mask_g) >> sh_g] | 1237 lookup_g[(pixel & mask_g) >> sh_g] |
1645 lookup_b[(pixel & mask_b) >> sh_b]; 1238 lookup_b[(pixel & mask_b) >> sh_b];
1646 XPutPixel (srcImage, x, y, pixel); 1239 XPutPixel (ximage, x, y, pixel);
1647 } 1240 }
1648 } 1241 }
1649 1242
1650 free (lookup); 1243 free (lookup);
1651} 1244}
1652#endif /* defined(ENABLE_TRANSPARENCY) && !defined(HAVE_AFTERIMAGE) */ 1245#endif /* ENABLE_TRANSPARENCY */

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines