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.159 by sf-exg, Wed Aug 10 07:34:35 2011 UTC vs.
Revision 1.226 by sf-exg, Thu May 31 05:53:46 2012 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines