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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines