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.142 by sf-exg, Thu Jan 27 17:37:18 2011 UTC vs.
Revision 1.206 by sf-exg, Thu Apr 12 10:22:50 2012 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines