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.210 by sf-exg, Sat May 12 09:43:06 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;
649 ret = true;
650 }
651# endif
652
653 if (ret)
654 {
655 if (p)
656 bg_set_geometry (p + 1);
657 else
658 bg_set_default_geometry ();
659 }
660
661 return ret;
662}
663
664# endif /* BG_IMAGE_FROM_FILE */
665
666# ifdef ENABLE_TRANSPARENCY
667bool
668rxvt_term::bg_set_transparent ()
669{
670 if (!(bg_flags & BG_IS_TRANSPARENT))
671 {
672 bg_flags |= BG_IS_TRANSPARENT;
863 return true; 673 return true;
864 } 674 }
865# endif
866 675
867 return false; 676 return false;
868} 677}
869 678
870# endif /* BG_IMAGE_FROM_FILE */
871
872# ifdef ENABLE_TRANSPARENCY
873bool 679bool
874bgPixmap_t::set_transparent () 680rxvt_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{ 681{
888 bool changed = false; 682 bool changed = false;
889 unsigned int hr, vr; 683 unsigned int hr, vr;
890 int junk; 684 int junk;
891 int geom_flags = XParseGeometry (geom, &junk, &junk, &hr, &vr); 685 int geom_flags = XParseGeometry (geom, &junk, &junk, &hr, &vr);
908 { 702 {
909 changed = true; 703 changed = true;
910 v_blurRadius = vr; 704 v_blurRadius = vr;
911 } 705 }
912 706
913 if (v_blurRadius == 0 && h_blurRadius == 0) 707 if (h_blurRadius && v_blurRadius)
914 flags &= ~blurNeeded; 708 bg_flags |= BG_NEEDS_BLUR;
915 else 709 else
916 flags |= blurNeeded; 710 bg_flags &= ~BG_NEEDS_BLUR;
917 711
918 return changed; 712 return changed;
919} 713}
920 714
921static inline unsigned long 715void
922compute_tint_shade_flags (rxvt_color *tint, int shade) 716rxvt_term::set_tint_shade_flags ()
923{ 717{
924 unsigned long flags = 0; 718 if (shade != 100 || (bg_flags & BG_TINT_SET))
925 rgba c (rgba::MAX_CC,rgba::MAX_CC,rgba::MAX_CC); 719 bg_flags |= BG_NEEDS_TINT;
926 bool has_shade = shade != 100; 720 else
721 bg_flags &= ~BG_NEEDS_TINT;
722}
927 723
928 if (tint) 724bool
929 { 725rxvt_term::bg_set_tint (rxvt_color &new_tint)
930 tint->get (c); 726{
931# define IS_COMPONENT_WHOLESOME(cmp) ((cmp) <= 0x000700 || (cmp) >= 0x00f700) 727 if (!(bg_flags & BG_TINT_SET) || tint != new_tint)
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 } 728 {
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; 729 tint = new_tint;
960 flags = (flags & ~tintFlags) | new_flags | tintSet; 730 bg_flags |= BG_TINT_SET;
731
732 rgba c;
733 tint.get (c);
734 if ((c.r <= 0x00ff || c.r >= 0xff00)
735 && (c.g <= 0x00ff || c.g >= 0xff00)
736 && (c.b <= 0x00ff || c.b >= 0xff00))
737 bg_flags |= BG_TINT_BITAND;
738 else
739 bg_flags &= ~BG_TINT_BITAND;
740
741 set_tint_shade_flags ();
961 return true; 742 return true;
962 } 743 }
963 744
964 return false; 745 return false;
965} 746}
966 747
967bool 748bool
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) 749rxvt_term::bg_set_shade (const char *shade_str)
983{ 750{
984 int new_shade = (shade_str) ? atoi (shade_str) : 100; 751 int new_shade = atoi (shade_str);
985 752
986 clamp_it (new_shade, -100, 200); 753 clamp_it (new_shade, -100, 200);
987 if (new_shade < 0) 754 if (new_shade < 0)
988 new_shade = 200 - (100 + new_shade); 755 new_shade = 200 - (100 + new_shade);
989 756
990 if (new_shade != shade) 757 if (new_shade != shade)
991 { 758 {
992 unsigned long new_flags = compute_tint_shade_flags ((flags & tintSet) ? &tint : NULL, new_shade);
993 shade = new_shade; 759 shade = new_shade;
994 flags = (flags & (~tintFlags | tintSet)) | new_flags; 760 set_tint_shade_flags ();
995 return true; 761 return true;
996 } 762 }
997 763
998 return false; 764 return false;
999} 765}
1020 params[i+2] = XDoubleToFixed (kernel[i] / sum); 786 params[i+2] = XDoubleToFixed (kernel[i] / sum);
1021} 787}
1022#endif 788#endif
1023 789
1024bool 790bool
1025bgPixmap_t::blur_pixmap (Pixmap pixmap, Visual *visual, int width, int height) 791rxvt_term::blur_pixmap (Pixmap pixmap, Visual *visual, int width, int height, int depth)
1026{ 792{
1027 bool ret = false; 793 bool ret = false;
1028#if XRENDER 794#if XRENDER
795 if (!(bg_flags & BG_HAS_RENDER_CONV))
796 return false;
797
1029 int size = max (h_blurRadius, v_blurRadius) * 2 + 1; 798 int size = max (h_blurRadius, v_blurRadius) * 2 + 1;
1030 double *kernel = (double *)malloc (size * sizeof (double)); 799 double *kernel = (double *)malloc (size * sizeof (double));
1031 XFixed *params = (XFixed *)malloc ((size + 2) * sizeof (XFixed)); 800 XFixed *params = (XFixed *)malloc ((size + 2) * sizeof (XFixed));
1032 801
1033 Display *dpy = target->dpy;
1034 XRenderPictureAttributes pa; 802 XRenderPictureAttributes pa;
1035 XRenderPictFormat *format = XRenderFindVisualFormat (dpy, visual); 803 XRenderPictFormat *format = XRenderFindVisualFormat (dpy, visual);
1036 804
805 pa.repeat = RepeatPad;
1037 Picture src = XRenderCreatePicture (dpy, pixmap, format, 0, &pa); 806 Picture src = XRenderCreatePicture (dpy, pixmap, format, CPRepeat, &pa);
807 Pixmap tmp = XCreatePixmap (dpy, pixmap, width, height, depth);
1038 Picture dst = XRenderCreatePicture (dpy, pixmap, format, 0, &pa); 808 Picture dst = XRenderCreatePicture (dpy, tmp, format, CPRepeat, &pa);
809 XFreePixmap (dpy, tmp);
1039 810
1040 if (kernel && params && src && dst) 811 if (kernel && params)
1041 { 812 {
1042 if (h_blurRadius)
1043 {
1044 size = h_blurRadius * 2 + 1; 813 size = h_blurRadius * 2 + 1;
1045 get_gaussian_kernel (h_blurRadius, size, kernel, params); 814 get_gaussian_kernel (h_blurRadius, size, kernel, params);
1046 815
1047 XRenderSetPictureFilter (dpy, src, FilterConvolution, params, size+2); 816 XRenderSetPictureFilter (dpy, src, FilterConvolution, params, size+2);
1048 XRenderComposite (dpy, 817 XRenderComposite (dpy,
1049 PictOpSrc, 818 PictOpSrc,
1050 src, 819 src,
1051 None, 820 None,
1052 dst, 821 dst,
1053 0, 0, 822 0, 0,
1054 0, 0, 823 0, 0,
1055 0, 0, 824 0, 0,
1056 width, height); 825 width, height);
1057 }
1058 826
1059 if (v_blurRadius) 827 ::swap (src, dst);
1060 { 828
1061 size = v_blurRadius * 2 + 1; 829 size = v_blurRadius * 2 + 1;
1062 get_gaussian_kernel (v_blurRadius, size, kernel, params); 830 get_gaussian_kernel (v_blurRadius, size, kernel, params);
1063 swap (params[0], params[1]); 831 ::swap (params[0], params[1]);
1064 832
1065 XRenderSetPictureFilter (dpy, src, FilterConvolution, params, size+2); 833 XRenderSetPictureFilter (dpy, src, FilterConvolution, params, size+2);
1066 XRenderComposite (dpy, 834 XRenderComposite (dpy,
1067 PictOpSrc, 835 PictOpSrc,
1068 src, 836 src,
1069 None, 837 None,
1070 dst, 838 dst,
1071 0, 0, 839 0, 0,
1072 0, 0, 840 0, 0,
1073 0, 0, 841 0, 0,
1074 width, height); 842 width, height);
1075 }
1076 843
1077 ret = true; 844 ret = true;
1078 } 845 }
1079 846
1080 free (kernel); 847 free (kernel);
1084#endif 851#endif
1085 return ret; 852 return ret;
1086} 853}
1087 854
1088bool 855bool
1089bgPixmap_t::tint_pixmap (Pixmap pixmap, Visual *visual, int width, int height) 856rxvt_term::tint_pixmap (Pixmap pixmap, Visual *visual, int width, int height)
1090{ 857{
1091 Display *dpy = target->dpy;
1092 bool ret = false; 858 bool ret = false;
1093 859
1094 if (flags & tintWholesome) 860 if (shade == 100 && (bg_flags & BG_TINT_BITAND))
1095 { 861 {
1096 XGCValues gcv; 862 XGCValues gcv;
1097 GC gc; 863 GC gc;
1098 864
1099 /* In this case we can tint image server-side getting significant 865 /* In this case we can tint image server-side getting significant
1108 XFillRectangle (dpy, pixmap, gc, 0, 0, width, height); 874 XFillRectangle (dpy, pixmap, gc, 0, 0, width, height);
1109 ret = true; 875 ret = true;
1110 XFreeGC (dpy, gc); 876 XFreeGC (dpy, gc);
1111 } 877 }
1112 } 878 }
1113 else
1114 {
1115# if XRENDER 879# if XRENDER
880 else if (bg_flags & BG_HAS_RENDER)
881 {
1116 rgba c (rgba::MAX_CC,rgba::MAX_CC,rgba::MAX_CC); 882 rgba c (rgba::MAX_CC, rgba::MAX_CC, rgba::MAX_CC);
1117 883
1118 if (flags & tintSet) 884 if (bg_flags & BG_TINT_SET)
1119 tint.get (c); 885 tint.get (c);
1120 886
1121 if (shade <= 100) 887 if (shade <= 100)
1122 { 888 {
1123 c.r = (c.r * shade) / 100; 889 c.r = c.r * shade / 100;
1124 c.g = (c.g * shade) / 100; 890 c.g = c.g * shade / 100;
1125 c.b = (c.b * shade) / 100; 891 c.b = c.b * shade / 100;
1126 } 892 }
1127 else 893 else
1128 { 894 {
1129 c.r = ((0xffff - c.r) * (200 - shade)) / 100; 895 c.r = c.r * (200 - shade) / 100;
1130 c.g = ((0xffff - c.g) * (200 - shade)) / 100; 896 c.g = c.g * (200 - shade) / 100;
1131 c.b = ((0xffff - c.b) * (200 - shade)) / 100; 897 c.b = c.b * (200 - shade) / 100;
1132 } 898 }
1133 899
1134 XRenderPictFormat *solid_format = XRenderFindStandardFormat (dpy, PictStandardARGB32);
1135 XRenderPictFormat *format = XRenderFindVisualFormat (dpy, visual); 900 XRenderPictFormat *format = XRenderFindVisualFormat (dpy, visual);
1136 XRenderPictureAttributes pa;
1137 901
1138 Picture back_pic = XRenderCreatePicture (dpy, pixmap, format, 0, &pa); 902 Picture back_pic = XRenderCreatePicture (dpy, pixmap, format, 0, 0);
1139 903
1140 pa.repeat = True; 904 Picture overlay_pic = create_xrender_mask (dpy, pixmap, True, False);
1141 905
1142 Pixmap overlay_pmap = XCreatePixmap (dpy, pixmap, 1, 1, 32); 906 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 907
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; 908 XRenderColor mask_c;
1154 909
1155 mask_c.red = mask_c.green = mask_c.blue = shade > 100 ? 0xffff : 0;
1156 mask_c.alpha = 0xffff; 910 mask_c.alpha = 0xffff;
911 mask_c.red =
912 mask_c.green =
913 mask_c.blue = 0;
914 XRenderFillRectangle (dpy, PictOpSrc, overlay_pic, &mask_c, 0, 0, 1, 1);
915
916 mask_c.alpha = 0;
917 mask_c.red = 0xffff - c.r;
918 mask_c.green = 0xffff - c.g;
919 mask_c.blue = 0xffff - c.b;
920 XRenderFillRectangle (dpy, PictOpSrc, mask_pic, &mask_c, 0, 0, 1, 1);
921
922 XRenderComposite (dpy, PictOpOver, overlay_pic, mask_pic, back_pic, 0, 0, 0, 0, 0, 0, width, height);
923
924 if (shade > 100)
925 {
926 mask_c.alpha = 0;
927 mask_c.red =
928 mask_c.green =
929 mask_c.blue = 0xffff * (shade - 100) / 100;
1157 XRenderFillRectangle (dpy, PictOpSrc, overlay_pic, &mask_c, 0, 0, 1, 1); 930 XRenderFillRectangle (dpy, PictOpSrc, overlay_pic, &mask_c, 0, 0, 1, 1);
1158 931
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); 932 XRenderComposite (dpy, PictOpOver, overlay_pic, None, back_pic, 0, 0, 0, 0, 0, 0, width, height);
1165 ret = true;
1166 } 933 }
934
935 ret = true;
1167 936
1168 XRenderFreePicture (dpy, mask_pic); 937 XRenderFreePicture (dpy, mask_pic);
1169 XRenderFreePicture (dpy, overlay_pic); 938 XRenderFreePicture (dpy, overlay_pic);
1170 XRenderFreePicture (dpy, back_pic); 939 XRenderFreePicture (dpy, back_pic);
940 }
1171# endif 941# endif
1172 }
1173 942
1174 return ret; 943 return ret;
1175} 944}
1176 945
1177/* make_transparency_pixmap() 946/*
1178 * Builds a pixmap of the same size as the terminal window that contains 947 * 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 948 * the tiled portion of the root pixmap that is supposed to be covered by
1180 * our window. 949 * our window.
1181 */ 950 */
1182unsigned long 951bool
1183bgPixmap_t::make_transparency_pixmap () 952rxvt_term::make_transparency_pixmap ()
1184{ 953{
1185 unsigned long result = 0; 954 bool ret = false;
1186
1187 if (target == NULL)
1188 return 0;
1189 955
1190 /* root dimensions may change from call to call - but Display structure should 956 /* root dimensions may change from call to call - but Display structure should
1191 * be always up-to-date, so let's use it : 957 * be always up-to-date, so let's use it :
1192 */ 958 */
1193 int screen = target->display->screen; 959 int screen = display->screen;
1194 Display *dpy = target->dpy;
1195 int root_depth = DefaultDepth (dpy, screen); 960 int root_depth = DefaultDepth (dpy, screen);
1196 int root_width = DisplayWidth (dpy, screen); 961 int root_width = DisplayWidth (dpy, screen);
1197 int root_height = DisplayHeight (dpy, screen); 962 int root_height = DisplayHeight (dpy, screen);
1198 unsigned int root_pmap_width, root_pmap_height; 963 unsigned int root_pmap_width, root_pmap_height;
1199 int window_width = target->szHint.width; 964 int window_width = szHint.width;
1200 int window_height = target->szHint.height; 965 int window_height = szHint.height;
1201 int sx, sy; 966 int sx, sy;
1202 XGCValues gcv; 967 XGCValues gcv;
1203 GC gc; 968 GC gc;
1204 969
1205 target->get_window_origin (sx, sy); 970 sx = target_x;
971 sy = target_y;
1206 972
1207 /* check if we are outside of the visible part of the virtual screen : */ 973 /* check if we are outside of the visible part of the virtual screen : */
1208 if (sx + window_width <= 0 || sy + window_height <= 0 974 if (sx + window_width <= 0 || sy + window_height <= 0
1209 || sx >= root_width || sy >= root_height) 975 || sx >= root_width || sy >= root_height)
1210 return 0; 976 return 0;
1214 { 980 {
1215 Window wdummy; 981 Window wdummy;
1216 int idummy; 982 int idummy;
1217 unsigned int udummy; 983 unsigned int udummy;
1218 984
1219 target->allowedxerror = -1; 985 allowedxerror = -1;
1220 986
1221 if (!XGetGeometry (dpy, root_pixmap, &wdummy, &idummy, &idummy, &root_pmap_width, &root_pmap_height, &udummy, &udummy)) 987 if (!XGetGeometry (dpy, root_pixmap, &wdummy, &idummy, &idummy, &root_pmap_width, &root_pmap_height, &udummy, &udummy))
1222 root_pixmap = None; 988 root_pixmap = None;
1223 989
1224 target->allowedxerror = 0; 990 allowedxerror = 0;
1225 } 991 }
1226 992
1227 Pixmap recoded_root_pmap = root_pixmap; 993 Pixmap recoded_root_pmap = root_pixmap;
1228 994
1229 if (root_pixmap != None && root_depth != target->depth) 995 if (root_pixmap != None && root_depth != depth)
1230 { 996 {
1231#if XRENDER 997#if XRENDER
1232 if (flags & HAS_RENDER) 998 if (bg_flags & BG_HAS_RENDER)
1233 { 999 {
1234 XRenderPictureAttributes pa; 1000 recoded_root_pmap = XCreatePixmap (dpy, vt, root_pmap_width, root_pmap_height, depth);
1235 1001
1236 XRenderPictFormat *src_format = XRenderFindVisualFormat (dpy, DefaultVisual (dpy, screen)); 1002 XRenderPictFormat *src_format = XRenderFindVisualFormat (dpy, DefaultVisual (dpy, screen));
1237 Picture src = XRenderCreatePicture (dpy, root_pixmap, src_format, 0, &pa); 1003 Picture src = XRenderCreatePicture (dpy, root_pixmap, src_format, 0, 0);
1238 1004
1239 recoded_root_pmap = XCreatePixmap (dpy, target->vt, root_pmap_width, root_pmap_height, target->depth);
1240 XRenderPictFormat *dst_format = XRenderFindVisualFormat (dpy, target->visual); 1005 XRenderPictFormat *dst_format = XRenderFindVisualFormat (dpy, visual);
1241 Picture dst = XRenderCreatePicture (dpy, recoded_root_pmap, dst_format, 0, &pa); 1006 Picture dst = XRenderCreatePicture (dpy, recoded_root_pmap, dst_format, 0, 0);
1242 1007
1243 if (src && dst)
1244 XRenderComposite (dpy, PictOpSrc, src, None, dst, 0, 0, 0, 0, 0, 0, root_pmap_width, root_pmap_height); 1008 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 1009
1251 XRenderFreePicture (dpy, src); 1010 XRenderFreePicture (dpy, src);
1252 XRenderFreePicture (dpy, dst); 1011 XRenderFreePicture (dpy, dst);
1253 } 1012 }
1254 else 1013 else
1255#endif 1014#endif
1256 root_pixmap = None; 1015 recoded_root_pmap = None;
1257 } 1016 }
1258 1017
1259 if (root_pixmap == None) 1018 if (recoded_root_pmap == None)
1260 return 0; 1019 return 0;
1261 1020
1021 if (bg_pixmap == None
1022 || bg_pmap_width != window_width
1023 || bg_pmap_height != window_height)
1024 {
1025 if (bg_pixmap)
1026 XFreePixmap (dpy, bg_pixmap);
1262 Pixmap tiled_root_pmap = XCreatePixmap (dpy, target->vt, window_width, window_height, target->depth); 1027 bg_pixmap = XCreatePixmap (dpy, vt, window_width, window_height, depth);
1263 1028 bg_pmap_width = window_width;
1264 if (tiled_root_pmap == None) /* something really bad happened - abort */ 1029 bg_pmap_height = window_height;
1265 return 0; 1030 }
1266 1031
1267 /* straightforward pixmap copy */ 1032 /* straightforward pixmap copy */
1033 while (sx < 0) sx += root_pmap_width;
1034 while (sy < 0) sy += root_pmap_height;
1035
1268 gcv.tile = recoded_root_pmap; 1036 gcv.tile = recoded_root_pmap;
1269 gcv.fill_style = FillTiled; 1037 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; 1038 gcv.ts_x_origin = -sx;
1275 gcv.ts_y_origin = -sy; 1039 gcv.ts_y_origin = -sy;
1276 gc = XCreateGC (dpy, target->vt, GCFillStyle | GCTile | GCTileStipXOrigin | GCTileStipYOrigin, &gcv); 1040 gc = XCreateGC (dpy, vt, GCFillStyle | GCTile | GCTileStipXOrigin | GCTileStipYOrigin, &gcv);
1277 1041
1278 if (gc) 1042 if (gc)
1279 { 1043 {
1280 XFillRectangle (dpy, tiled_root_pmap, gc, 0, 0, window_width, window_height); 1044 XFillRectangle (dpy, bg_pixmap, gc, 0, 0, window_width, window_height);
1281 result |= transpPmapTiled; 1045 ret = true;
1046 unsigned long tr_flags = bg_flags & BG_EFFECTS_FLAGS;
1047
1048 if (!(bg_flags & BG_CLIENT_RENDER))
1049 {
1050 if (bg_flags & BG_NEEDS_BLUR)
1051 {
1052 if (blur_pixmap (bg_pixmap, visual, window_width, window_height, depth))
1053 tr_flags &= ~BG_NEEDS_BLUR;
1054 }
1055 if (bg_flags & BG_NEEDS_TINT)
1056 {
1057 if (tint_pixmap (bg_pixmap, visual, window_width, window_height))
1058 tr_flags &= ~BG_NEEDS_TINT;
1059 }
1060 if (tr_flags & BG_NEEDS_TINT)
1061 {
1062 XImage *ximage = XGetImage (dpy, bg_pixmap, 0, 0, bg_pmap_width, bg_pmap_height, AllPlanes, ZPixmap);
1063 if (ximage)
1064 {
1065 /* our own client-side tinting */
1066 tint_ximage (DefaultVisual (dpy, display->screen), ximage);
1067
1068 XPutImage (dpy, bg_pixmap, gc, ximage, 0, 0, 0, 0, ximage->width, ximage->height);
1069 XDestroyImage (ximage);
1070 }
1071 }
1072 } /* server side rendering completed */
1073
1282 XFreeGC (dpy, gc); 1074 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 } 1075 }
1308 else
1309 XFreePixmap (dpy, tiled_root_pmap);
1310 1076
1311 if (recoded_root_pmap != root_pixmap) 1077 if (recoded_root_pmap != root_pixmap)
1312 XFreePixmap (dpy, recoded_root_pmap); 1078 XFreePixmap (dpy, recoded_root_pmap);
1313 1079
1314 return result; 1080 return ret;
1315} 1081}
1316 1082
1317void 1083void
1318bgPixmap_t::set_root_pixmap () 1084rxvt_term::bg_set_root_pixmap ()
1319{ 1085{
1320 Pixmap new_root_pixmap = target->get_pixmap_property (XA_XROOTPMAP_ID); 1086 Pixmap new_root_pixmap = get_pixmap_property (xa[XA_XROOTPMAP_ID]);
1321 if (new_root_pixmap == None) 1087 if (new_root_pixmap == None)
1322 new_root_pixmap = target->get_pixmap_property (XA_ESETROOT_PMAP_ID); 1088 new_root_pixmap = get_pixmap_property (xa[XA_ESETROOT_PMAP_ID]);
1323 1089
1324 root_pixmap = new_root_pixmap; 1090 root_pixmap = new_root_pixmap;
1325} 1091}
1326# endif /* ENABLE_TRANSPARENCY */ 1092# endif /* ENABLE_TRANSPARENCY */
1327 1093
1328#if defined(ENABLE_TRANSPARENCY) && !defined(HAVE_AFTERIMAGE) 1094bool
1329static void ShadeXImage(Visual *visual, XImage *srcImage, int shade, const rgba &c); 1095rxvt_term::bg_render ()
1096{
1097 bool transparent = false;
1098
1099 bg_invalidate ();
1100# ifdef ENABLE_TRANSPARENCY
1101 if (bg_flags & BG_IS_TRANSPARENT)
1102 {
1103 /* we need to re-generate transparency pixmap in that case ! */
1104 transparent = make_transparency_pixmap ();
1105 if (transparent)
1106 bg_flags |= BG_IS_VALID;
1107 }
1330# endif 1108# endif
1331 1109
1332bool 1110# ifdef BG_IMAGE_FROM_FILE
1333bgPixmap_t::render () 1111 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 { 1112 {
1344 /* we need to re-generate transparency pixmap in that case ! */ 1113 if (render_image (transparent))
1345 background_flags = make_transparency_pixmap (); 1114 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 } 1115 }
1351# endif 1116# endif
1352 1117
1353# ifdef BG_IMAGE_FROM_FILE 1118 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 } 1119 {
1360# endif 1120 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 { 1121 {
1375 rgba c (rgba::MAX_CC,rgba::MAX_CC,rgba::MAX_CC); 1122 XFreePixmap (dpy, bg_pixmap);
1376 if (flags & tintSet) 1123 bg_pixmap = None;
1377 tint.get (c);
1378 ShadeXImage (DefaultVisual (target->dpy, target->display->screen), result, shade, c);
1379 } 1124 }
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 { 1125 }
1397 if (pixmap != None)
1398 {
1399 XFreePixmap (target->dpy, pixmap);
1400 pixmap = None;
1401 }
1402 }
1403 1126
1404 apply (); 1127 scr_recolour (false);
1128 bg_flags |= BG_NEEDS_REFRESH;
1405 1129
1406 valid_since = ev::now (); 1130 bg_valid_since = ev::now ();
1407 1131
1408 return true; 1132 return true;
1409} 1133}
1410 1134
1411void 1135void
1412bgPixmap_t::set_target (rxvt_term *new_target) 1136rxvt_term::bg_init ()
1413{ 1137{
1414 target = new_target; 1138#ifdef ENABLE_TRANSPARENCY
1139 shade = 100;
1140#endif
1415 1141
1416 flags &= ~(HAS_RENDER | HAS_RENDER_CONV); 1142 bg_flags &= ~(BG_HAS_RENDER | BG_HAS_RENDER_CONV);
1417#if XRENDER 1143#if XRENDER
1418 int major, minor; 1144 int major, minor;
1419 if (XRenderQueryVersion (target->dpy, &major, &minor)) 1145 if (XRenderQueryVersion (dpy, &major, &minor))
1420 flags |= HAS_RENDER; 1146 bg_flags |= BG_HAS_RENDER;
1421 XFilters *filters = XRenderQueryFilters (target->dpy, target->vt); 1147 XFilters *filters = XRenderQueryFilters (dpy, vt);
1422 if (filters) 1148 if (filters)
1423 { 1149 {
1424 for (int i = 0; i < filters->nfilter; i++) 1150 for (int i = 0; i < filters->nfilter; i++)
1425 if (!strcmp (filters->filter[i], FilterConvolution)) 1151 if (!strcmp (filters->filter[i], FilterConvolution))
1426 flags |= HAS_RENDER_CONV; 1152 bg_flags |= BG_HAS_RENDER_CONV;
1427 1153
1428 XFree (filters); 1154 XFree (filters);
1429 } 1155 }
1430#endif 1156#endif
1431} 1157}
1432 1158
1159#endif /* HAVE_BG_PIXMAP */
1160
1161#ifdef ENABLE_TRANSPARENCY
1162/* based on code from aterm-0.4.2 */
1163
1164static inline void
1165fill_lut (uint32_t *lookup, uint32_t mask, int sh, unsigned short low, unsigned short high)
1166{
1167 for (int i = 0; i <= mask >> sh; i++)
1168 {
1169 uint32_t tmp;
1170 tmp = i * high;
1171 tmp += (mask >> sh) * low;
1172 lookup[i] = (tmp / 0xffff) << sh;
1173 }
1174}
1175
1433void 1176void
1434bgPixmap_t::apply () 1177rxvt_term::tint_ximage (Visual *visual, XImage *ximage)
1435{ 1178{
1436 if (target == NULL) 1179 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; 1180 int sh_r, sh_g, sh_b;
1496 uint32_t mask_r, mask_g, mask_b; 1181 uint32_t mask_r, mask_g, mask_b;
1497 uint32_t *lookup, *lookup_r, *lookup_g, *lookup_b; 1182 uint32_t *lookup, *lookup_r, *lookup_g, *lookup_b;
1498 rgba low; 1183 unsigned short low;
1499 rgba high;
1500 int i;
1501 int host_byte_order = byteorder.big_endian () ? MSBFirst : LSBFirst; 1184 int host_byte_order = ecb_big_endian () ? MSBFirst : LSBFirst;
1502 1185
1503 if (visual->c_class != TrueColor || srcImage->format != ZPixmap) return; 1186 if (visual->c_class != TrueColor || ximage->format != ZPixmap) return;
1504 1187
1505 /* for convenience */ 1188 /* for convenience */
1506 mask_r = visual->red_mask; 1189 mask_r = visual->red_mask;
1507 mask_g = visual->green_mask; 1190 mask_g = visual->green_mask;
1508 mask_b = visual->blue_mask; 1191 mask_b = visual->blue_mask;
1509 1192
1510 /* boring lookup table pre-initialization */ 1193 /* boring lookup table pre-initialization */
1511 switch (srcImage->depth) 1194 sh_r = ecb_ctz32 (mask_r);
1512 { 1195 sh_g = ecb_ctz32 (mask_g);
1513 case 15: 1196 sh_b = ecb_ctz32 (mask_b);
1514 if ((mask_r != 0x7c00) || 1197
1515 (mask_g != 0x03e0) || 1198 size_r = mask_r >> sh_r;
1516 (mask_b != 0x001f)) 1199 size_g = mask_g >> sh_g;
1200 size_b = mask_b >> sh_b;
1201
1202 if (size_r++ > 255 || size_g++ > 255 || size_b++ > 255)
1517 return; 1203 return;
1518 lookup = (uint32_t *) malloc (sizeof (uint32_t)*(32+32+32)); 1204
1205 lookup = (uint32_t *)malloc (sizeof (uint32_t) * (size_r + size_g + size_b));
1519 lookup_r = lookup; 1206 lookup_r = lookup;
1520 lookup_g = lookup+32; 1207 lookup_g = lookup + size_r;
1521 lookup_b = lookup+32+32; 1208 lookup_b = lookup + size_r + size_g;
1522 sh_r = 10; 1209
1523 sh_g = 5; 1210 rgba c (rgba::MAX_CC, rgba::MAX_CC, rgba::MAX_CC);
1524 sh_b = 0; 1211
1525 break; 1212 if (bg_flags & BG_TINT_SET)
1526 case 16: 1213 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 1214
1569 /* prepare limits for color transformation (each channel is handled separately) */ 1215 /* prepare limits for color transformation (each channel is handled separately) */
1570 if (shade > 100) 1216 if (shade > 100)
1571 { 1217 {
1572 shade = 200 - shade; 1218 c.r = c.r * (200 - shade) / 100;
1219 c.g = c.g * (200 - shade) / 100;
1220 c.b = c.b * (200 - shade) / 100;
1573 1221
1574 high.r = (65535 - c.r) * shade / 100; 1222 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 } 1223 }
1582 else 1224 else
1583 { 1225 {
1584 high.r = c.r * shade / 100; 1226 c.r = c.r * shade / 100;
1585 high.g = c.g * shade / 100; 1227 c.g = c.g * shade / 100;
1586 high.b = c.b * shade / 100; 1228 c.b = c.b * shade / 100;
1587 1229
1588 low.r = low.g = low.b = 0; 1230 low = 0;
1589 } 1231 }
1590 1232
1591 /* fill our lookup tables */ 1233 /* fill our lookup tables */
1592 for (i = 0; i <= mask_r>>sh_r; i++) 1234 fill_lut (lookup_r, mask_r, sh_r, low, c.r);
1593 { 1235 fill_lut (lookup_g, mask_g, sh_g, low, c.g);
1594 uint32_t tmp; 1236 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 1237
1614 /* apply table to input image (replacing colors by newly calculated ones) */ 1238 /* apply table to input image (replacing colors by newly calculated ones) */
1615 if (srcImage->bits_per_pixel == 32 1239 if (ximage->bits_per_pixel == 32
1616 && (srcImage->depth == 24 || srcImage->depth == 32)
1617 && srcImage->byte_order == host_byte_order) 1240 && ximage->byte_order == host_byte_order)
1618 { 1241 {
1619 uint32_t *p1, *pf, *p, *pl; 1242 char *line = ximage->data;
1620 p1 = (uint32_t *) srcImage->data;
1621 pf = (uint32_t *) (srcImage->data + srcImage->height * srcImage->bytes_per_line);
1622 1243
1623 while (p1 < pf) 1244 for (int y = 0; y < ximage->height; y++)
1624 {
1625 p = p1;
1626 pl = p1 + srcImage->width;
1627 for (; p < pl; p++)
1628 { 1245 {
1629 *p = lookup_r[(*p & 0xff0000) >> 16] | 1246 uint32_t *p = (uint32_t *)line;
1630 lookup_g[(*p & 0x00ff00) >> 8] | 1247 for (int x = 0; x < ximage->width; x++)
1631 lookup_b[(*p & 0x0000ff)] |
1632 (*p & 0xff000000);
1633 } 1248 {
1634 p1 = (uint32_t *) ((char *) p1 + srcImage->bytes_per_line); 1249 *p = lookup_r[(*p & mask_r) >> sh_r] |
1250 lookup_g[(*p & mask_g) >> sh_g] |
1251 lookup_b[(*p & mask_b) >> sh_b];
1252 p++;
1253 }
1254 line += ximage->bytes_per_line;
1635 } 1255 }
1636 } 1256 }
1637 else 1257 else
1638 { 1258 {
1639 for (int y = 0; y < srcImage->height; y++) 1259 for (int y = 0; y < ximage->height; y++)
1640 for (int x = 0; x < srcImage->width; x++) 1260 for (int x = 0; x < ximage->width; x++)
1641 { 1261 {
1642 unsigned long pixel = XGetPixel (srcImage, x, y); 1262 unsigned long pixel = XGetPixel (ximage, x, y);
1643 pixel = lookup_r[(pixel & mask_r) >> sh_r] | 1263 pixel = lookup_r[(pixel & mask_r) >> sh_r] |
1644 lookup_g[(pixel & mask_g) >> sh_g] | 1264 lookup_g[(pixel & mask_g) >> sh_g] |
1645 lookup_b[(pixel & mask_b) >> sh_b]; 1265 lookup_b[(pixel & mask_b) >> sh_b];
1646 XPutPixel (srcImage, x, y, pixel); 1266 XPutPixel (ximage, x, y, pixel);
1647 } 1267 }
1648 } 1268 }
1649 1269
1650 free (lookup); 1270 free (lookup);
1651} 1271}
1652#endif /* defined(ENABLE_TRANSPARENCY) && !defined(HAVE_AFTERIMAGE) */ 1272#endif /* ENABLE_TRANSPARENCY */

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines