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.228 by sf-exg, Thu May 31 20:23:51 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 63# ifdef BG_IMAGE_FROM_FILE
58 if (original_asim) 64 for (vector<rxvt_image>::iterator bg_image = image_vec.begin (); bg_image < image_vec.end (); bg_image++)
59 safe_asimage_destroy (original_asim); 65 bg_image->destroy ();
60 if (asv)
61 destroy_asvisual (asv, 0);
62 if (asimman)
63 destroy_image_manager (asimman, 0);
64#endif 66# endif
65
66#ifdef HAVE_PIXBUF
67 if (pixbuf)
68 g_object_unref (pixbuf);
69#endif
70 67
71 if (bg_pixmap) 68 if (bg_pixmap)
72 XFreePixmap (dpy, bg_pixmap); 69 XFreePixmap (dpy, bg_pixmap);
73} 70}
74 71
93 if (bg_flags & BG_IS_TRANSPARENT) 90 if (bg_flags & BG_IS_TRANSPARENT)
94 return true; 91 return true;
95# endif 92# endif
96 93
97# ifdef BG_IMAGE_FROM_FILE 94# ifdef BG_IMAGE_FROM_FILE
98 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++)
99 { 96 {
100 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)
101 return true; 100 return true;
102 } 101 }
103# endif 102# endif
104 103
105 return false; 104 return false;
112 if (bg_flags & BG_IS_TRANSPARENT) 111 if (bg_flags & BG_IS_TRANSPARENT)
113 return true; 112 return true;
114# endif 113# endif
115 114
116# ifdef BG_IMAGE_FROM_FILE 115# ifdef BG_IMAGE_FROM_FILE
117 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++)
118 { 117 {
119 if (bg_flags & BG_ROOT_ALIGN) 118 if (bg_image->flags & IM_ROOT_ALIGN)
120 return true; 119 return true;
121 } 120 }
122# endif 121# endif
123 122
124 return false; 123 return false;
125} 124}
126 125
127# ifdef BG_IMAGE_FROM_FILE 126# 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 127static inline int
163make_align_position (int align, int window_size, int image_size) 128make_align_position (int align, int window_size, int image_size)
164{ 129{
165 int diff = window_size - image_size;
166 int smaller = min (image_size, window_size);
167
168 if (align >= 0 && align <= 100) 130 if (align >= 0 && align <= 100)
169 return diff * align / 100; 131 return lerp (0, window_size - image_size, align);
170 else if (align > 100 && align <= 200) 132 else if (align > 100)
171 return ((align - 100) * smaller / 100) + window_size - smaller; 133 return lerp (window_size - image_size, window_size, align - 100);
172 else if (align >= -100 && align < 0) 134 else
173 return ((align + 100) * smaller / 100) - image_size; 135 return lerp (-image_size, 0, align + 100);
174 return 0;
175} 136}
176 137
177static inline int 138static inline int
178make_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)
179{ 140{
185 src_pos = -pos; 146 src_pos = -pos;
186 dst_pos = 0; 147 dst_pos = 0;
187 dst_size += pos; 148 dst_size += pos;
188 } 149 }
189 150
190 if (dst_pos + dst_size > target_size)
191 dst_size = target_size - dst_pos; 151 min_it (dst_size, target_size - dst_pos);
192 return src_pos; 152 return src_pos;
193} 153}
194 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
195bool 190bool
196rxvt_term::bg_set_geometry (const char *geom, bool update) 191rxvt_image::set_geometry (const char *geom, bool update)
197{ 192{
198 bool changed = false; 193 bool changed = false;
199 int geom_flags = 0; 194 int geom_flags = 0;
200 int x = 0, y = 0; 195 int x = h_align;
196 int y = v_align;
201 unsigned int w = 0, h = 0; 197 unsigned int w = h_scale;
202 unsigned long new_flags = (bg_flags & (~BG_GEOMETRY_FLAGS)); 198 unsigned int h = v_scale;
199 uint8_t new_flags = 0;
203 200
204 if (geom == NULL) 201 if (geom == NULL)
205 return false; 202 return false;
206 203
207 if (geom[0]) 204 if (geom[0])
208 { 205 {
209 char **arr = rxvt_strsplit (':', geom); 206 char **arr = rxvt_strsplit (':', geom);
210 207
211 for (int i = 0; arr[i]; i++) 208 for (int i = 0; arr[i]; i++)
212 { 209 {
213 if (!strcasecmp (arr[i], "style=tiled")) 210 if (!strncasecmp (arr[i], "style=", 6))
214 { 211 {
215 new_flags = BG_TILE; 212 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; 213 geom_flags = WidthValue|HeightValue|XValue|YValue;
219 } 214 }
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")) 215 else if (!strcasecmp (arr[i], "op=tile"))
247 new_flags |= BG_TILE; 216 new_flags |= IM_TILE;
248 else if (!strcasecmp (arr[i], "op=pscale")) 217 else if (!strcasecmp (arr[i], "op=keep-aspect"))
249 new_flags |= BG_PROP_SCALE; 218 new_flags |= IM_KEEP_ASPECT;
250 else if (!strcasecmp (arr[i], "op=root")) 219 else if (!strcasecmp (arr[i], "op=root-align"))
251 new_flags |= BG_ROOT_ALIGN; 220 new_flags |= IM_ROOT_ALIGN;
252 221
253 // deprecated 222 // deprecated
254 else if (!strcasecmp (arr[i], "tile")) 223 else if (!strcasecmp (arr[i], "tile"))
255 { 224 {
256 new_flags |= BG_TILE; 225 new_flags |= IM_TILE;
257 w = h = noScale; 226 w = h = noScale;
258 geom_flags |= WidthValue|HeightValue; 227 geom_flags |= WidthValue|HeightValue;
259 } 228 }
260 else if (!strcasecmp (arr[i], "propscale")) 229 else if (!strcasecmp (arr[i], "propscale"))
261 { 230 {
262 new_flags |= BG_PROP_SCALE; 231 new_flags |= IM_KEEP_ASPECT;
232 w = h = windowScale;
233 geom_flags |= WidthValue|HeightValue;
263 } 234 }
264 else if (!strcasecmp (arr[i], "hscale")) 235 else if (!strcasecmp (arr[i], "hscale"))
265 { 236 {
266 new_flags |= BG_TILE; 237 new_flags |= IM_TILE;
267 w = windowScale; 238 w = windowScale;
268 h = noScale; 239 h = noScale;
269 geom_flags |= WidthValue|HeightValue; 240 geom_flags |= WidthValue|HeightValue;
270 } 241 }
271 else if (!strcasecmp (arr[i], "vscale")) 242 else if (!strcasecmp (arr[i], "vscale"))
272 { 243 {
273 new_flags |= BG_TILE; 244 new_flags |= IM_TILE;
274 h = windowScale; 245 h = windowScale;
275 w = noScale; 246 w = noScale;
276 geom_flags |= WidthValue|HeightValue; 247 geom_flags |= WidthValue|HeightValue;
277 } 248 }
278 else if (!strcasecmp (arr[i], "scale")) 249 else if (!strcasecmp (arr[i], "scale"))
286 x = y = centerAlign; 257 x = y = centerAlign;
287 geom_flags |= WidthValue|HeightValue|XValue|YValue; 258 geom_flags |= WidthValue|HeightValue|XValue|YValue;
288 } 259 }
289 else if (!strcasecmp (arr[i], "root")) 260 else if (!strcasecmp (arr[i], "root"))
290 { 261 {
291 new_flags |= BG_TILE|BG_ROOT_ALIGN; 262 new_flags |= IM_TILE|IM_ROOT_ALIGN;
292 w = h = noScale; 263 w = h = noScale;
293 geom_flags |= WidthValue|HeightValue; 264 geom_flags |= WidthValue|HeightValue;
294 } 265 }
295 266
296 else 267 else
297 geom_flags |= XParseGeometry (arr[i], &x, &y, &w, &h); 268 geom_flags |= XParseGeometry (arr[i], &x, &y, &w, &h);
298 } /* done parsing ops */ 269 } /* done parsing ops */
299 270
300 rxvt_free_strsplit (arr); 271 rxvt_free_strsplit (arr);
301 } 272 }
273
274 new_flags |= flags & ~IM_GEOMETRY_FLAGS;
302 275
303 if (!update) 276 if (!update)
304 { 277 {
305 if (!(geom_flags & XValue)) 278 if (!(geom_flags & XValue))
306 x = y = defaultAlign; 279 x = y = defaultAlign;
311 w = h = defaultScale; 284 w = h = defaultScale;
312 else if (!(geom_flags & HeightValue)) 285 else if (!(geom_flags & HeightValue))
313 h = w; 286 h = w;
314 else if (!(geom_flags & WidthValue)) 287 else if (!(geom_flags & WidthValue))
315 w = h; 288 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 { 289 }
290
291 clamp_it (x, -100, 200);
292 clamp_it (y, -100, 200);
293
294 if (flags != new_flags
295 || h_scale != w
296 || v_scale != h
297 || h_align != x
298 || v_align != y)
299 {
327 bg_flags = new_flags; 300 flags = new_flags;
301 h_scale = w;
302 v_scale = h;
303 h_align = x;
304 v_align = y;
328 changed = true; 305 changed = true;
329 } 306 }
330 307
308 if (is_size_sensitive ())
309 flags |= IM_IS_SIZE_SENSITIVE;
310 else
311 flags &= ~IM_IS_SIZE_SENSITIVE;
312
331 return changed; 313 return changed;
332} 314}
333 315
334void 316void
335rxvt_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)
336{ 318{
319 int image_width = image.width ();
320 int image_height = image.height ();
337 int target_width = szHint.width; 321 int target_width = szHint.width;
338 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);
339 325
340 w = h_scale * target_width / 100; 326 w = h_scale * target_width / 100;
341 h = v_scale * target_height / 100; 327 h = v_scale * target_height / 100;
342 328
343 if (bg_flags & BG_PROP_SCALE) 329 if (image.flags & IM_KEEP_ASPECT)
344 { 330 {
345 float scale = (float)w / image_width; 331 float scale = (float)w / image_width;
346 min_it (scale, (float)h / image_height); 332 min_it (scale, (float)h / image_height);
347 w = image_width * scale + 0.5; 333 w = image_width * scale + 0.5;
348 h = image_height * scale + 0.5; 334 h = image_height * scale + 0.5;
349 } 335 }
350 336
351 if (!w) w = image_width; 337 if (!w) w = image_width;
352 if (!h) h = image_height; 338 if (!h) h = image_height;
353 339
354 if (bg_flags & BG_ROOT_ALIGN) 340 if (image.flags & IM_ROOT_ALIGN)
355 { 341 {
356 x = -target_x; 342 x = -target_x;
357 y = -target_y; 343 y = -target_y;
358 } 344 }
359 else 345 else
360 { 346 {
361 x = make_align_position (h_align, target_width, w); 347 x = make_align_position (image.h_align, target_width, w);
362 y = make_align_position (v_align, target_height, h); 348 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 { 349 }
388 ShadingInfo as_shade; 350}
389 as_shade.shading = shade;
390 351
391 rgba c (rgba::MAX_CC,rgba::MAX_CC,rgba::MAX_CC); 352# ifdef HAVE_PIXBUF
392 if (bg_flags & BG_TINT_SET) 353bool
393 tint.get (c); 354rxvt_term::pixbuf_to_pixmap (GdkPixbuf *pixbuf, Pixmap pixmap, GC gc,
394 as_shade.tintColor.red = c.r; 355 int src_x, int src_y, int dst_x, int dst_y,
395 as_shade.tintColor.green = c.g; 356 unsigned int width, unsigned int height, bool argb)
396 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;
397 366
398 background_tint = shading2tint32 (&as_shade); 367 if (visual->c_class != TrueColor)
368 return false;
369
370 if (argb)
399 } 371 {
400 372 red_mask = 0xff << 16;
401 if ((tr_flags & BG_NEEDS_BLUR) && background != NULL) 373 green_mask = 0xff << 8;
374 blue_mask = 0xff;
375 alpha_mask = 0xff << 24;
402 { 376 }
403 ASImage *tmp = blur_asimage_gauss (asv, background, h_blurRadius, v_blurRadius, 0xFFFFFFFF, 377 else
404 (original_asim == NULL || tint == TINT_LEAVE_SAME) ? ASA_XImage : ASA_ASImage, 378 {
405 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);
406 if (tmp) 384 if (format)
407 { 385 alpha_mask = (uint32_t)format->direct.alphaMask << format->direct.alpha;
408 destroy_asimage (&background); 386 else
409 background = tmp; 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++)
410 } 439 {
411 } 440 unsigned char *pixel = row + x * channels;
412# endif 441 uint32_t value;
442 unsigned char r, g, b, a;
413 443
414 ASImage *result = 0; 444 if (channels == 4)
445 {
446 a = pixel[3];
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);
468 }
469
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);
415 496
416 int target_width = szHint.width; 497 int target_width = szHint.width;
417 int target_height = szHint.height; 498 int target_height = szHint.height;
418 int new_pmap_width = target_width; 499 int new_pmap_width = target_width;
419 int new_pmap_height = target_height; 500 int new_pmap_height = target_height;
421 int x = 0; 502 int x = 0;
422 int y = 0; 503 int y = 0;
423 int w = 0; 504 int w = 0;
424 int h = 0; 505 int h = 0;
425 506
426 if (original_asim) 507 get_image_geometry (image, w, h, x, y);
427 get_image_geometry (original_asim->width, original_asim->height, w, h, x, y);
428 508
429 if (!original_asim 509 if (!(image.flags & IM_ROOT_ALIGN)
430 || (!(bg_flags & BG_ROOT_ALIGN)
431 && (x >= target_width 510 && (x >= target_width
432 || y >= target_height 511 || y >= target_height
433 || (x + w <= 0) 512 || x + w <= 0
434 || (y + h <= 0)))) 513 || y + h <= 0))
435 { 514 return false;
436 if (background)
437 {
438 new_pmap_width = background->width;
439 new_pmap_height = background->height;
440 result = background;
441 515
442 if (background_tint != TINT_LEAVE_SAME) 516 result = pixbuf;
443 { 517
444 ASImage *tmp = tile_asimage (asv, background, 0, 0, 518 if (w != image_width
445 target_width, target_height, background_tint, 519 || h != image_height)
446 ASA_XImage, 100, ASIMAGE_QUALITY_DEFAULT);
447 if (tmp)
448 result = tmp;
449 }
450 }
451 else
452 new_pmap_width = new_pmap_height = 0;
453 } 520 {
521 result = gdk_pixbuf_scale_simple (pixbuf,
522 w, h,
523 GDK_INTERP_BILINEAR);
524 }
525
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);
454 else 540 else
455 { 541 {
456 result = original_asim; 542 // optimise bg pixmap size when tiling, but only if there are no
457 543 // other pixbufs to render. Otherwise, the bg pixmap size must
458 if ((w != original_asim->width) 544 // be equal to the window size.
459 || (h != original_asim->height)) 545 if ((image.flags & IM_TILE)
460 { 546 && image_vec.size () == 1)
461 result = scale_asimage (asv, original_asim,
462 w, h,
463 background ? ASA_ASImage : ASA_XImage,
464 100, ASIMAGE_QUALITY_DEFAULT);
465 } 547 {
466 548 new_pmap_width = min (image_width, target_width);
467 if (background == NULL) 549 new_pmap_height = min (image_height, target_height);
468 { 550 }
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 551
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 552 if (bg_pixmap == None
561 || bg_pmap_width != new_pmap_width 553 || bg_pmap_width != new_pmap_width
562 || bg_pmap_height != new_pmap_height) 554 || bg_pmap_height != new_pmap_height)
563 { 555 {
564 if (bg_pixmap) 556 if (bg_pixmap)
565 XFreePixmap (dpy, bg_pixmap); 557 XFreePixmap (dpy, bg_pixmap);
566 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);
567 bg_pmap_width = new_pmap_width; 559 bg_pmap_width = new_pmap_width;
568 bg_pmap_height = new_pmap_height; 560 bg_pmap_height = new_pmap_height;
569 } 561 }
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 562
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; 563 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 } 564 }
773 565
774 gcv.foreground = pix_colors[Color_bg]; 566 gcv.foreground = pix_colors[Color_bg];
775 gc = XCreateGC (dpy, vt, GCForeground, &gcv); 567 gc = XCreateGC (dpy, tmp_pixmap, GCForeground, &gcv);
776 568
777 if (gc) 569 if (gc)
778 { 570 {
779 if (bg_flags & BG_TILE) 571 if (image.flags & IM_TILE)
780 { 572 {
781 Pixmap tile = XCreatePixmap (dpy, vt, image_width, image_height, depth); 573 Pixmap tile = XCreatePixmap (dpy, vt, image_width, image_height, need_blend ? 32 : depth);
782 pixbuf_to_pixmap (result, tile, gc, 574 pixbuf_to_pixmap (result, tile, gc,
783 0, 0, 575 0, 0,
784 0, 0, 576 0, 0,
785 image_width, image_height); 577 image_width, image_height, need_blend);
786 578
787 gcv.tile = tile; 579 gcv.tile = tile;
788 gcv.fill_style = FillTiled; 580 gcv.fill_style = FillTiled;
789 gcv.ts_x_origin = x; 581 gcv.ts_x_origin = x;
790 gcv.ts_y_origin = y; 582 gcv.ts_y_origin = y;
791 XChangeGC (dpy, gc, GCFillStyle | GCTile | GCTileStipXOrigin | GCTileStipYOrigin, &gcv); 583 XChangeGC (dpy, gc, GCFillStyle | GCTile | GCTileStipXOrigin | GCTileStipYOrigin, &gcv);
792 584
793 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);
794 XFreePixmap (dpy, tile); 586 XFreePixmap (dpy, tile);
795 } 587 }
796 else 588 else
797 { 589 {
798 int src_x, src_y, dst_x, dst_y; 590 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); 594 src_y = make_clip_rectangle (y, image_height, new_pmap_height, dst_y, dst_height);
803 595
804 if (dst_x > 0 || dst_y > 0 596 if (dst_x > 0 || dst_y > 0
805 || dst_x + dst_width < new_pmap_width 597 || dst_x + dst_width < new_pmap_width
806 || dst_y + dst_height < new_pmap_height) 598 || dst_y + dst_height < new_pmap_height)
807 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);
808 600
809 if (dst_x < new_pmap_width && dst_y < new_pmap_height) 601 if (dst_x < new_pmap_width && dst_y < new_pmap_height)
810 pixbuf_to_pixmap (result, bg_pixmap, gc, 602 pixbuf_to_pixmap (result, tmp_pixmap, gc,
811 src_x, src_y, 603 src_x, src_y,
812 dst_x, dst_y, 604 dst_x, dst_y,
813 dst_width, dst_height); 605 dst_width, dst_height, need_blend);
814 } 606 }
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);
815 612
816#if XRENDER 613#if XRENDER
817 if (tr_flags) 614 if (need_blend)
818 { 615 {
819 XRenderPictureAttributes pa; 616 XRenderPictFormat *argb_format = XRenderFindStandardFormat (dpy, PictStandardARGB32);
820
821 XRenderPictFormat *src_format = XRenderFindVisualFormat (dpy, visual); 617 XRenderPictFormat *format = XRenderFindVisualFormat (dpy, visual);
618
822 Picture src = XRenderCreatePicture (dpy, root_pmap, src_format, 0, &pa); 619 Picture src = XRenderCreatePicture (dpy, tmp_pixmap, argb_format, 0, 0);
823 620
824 XRenderPictFormat *dst_format = XRenderFindVisualFormat (dpy, visual);
825 Picture dst = XRenderCreatePicture (dpy, bg_pixmap, dst_format, 0, &pa); 621 Picture dst = XRenderCreatePicture (dpy, bg_pixmap, format, 0, 0);
826 622
827 pa.repeat = True; 623 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 624
833 XRenderColor mask_c; 625 XRenderColor mask_c;
834 626
835 mask_c.alpha = 0x8000; 627 mask_c.alpha = image.alpha;
836 mask_c.red = 0; 628 mask_c.red =
837 mask_c.green = 0; 629 mask_c.green =
838 mask_c.blue = 0; 630 mask_c.blue = 0;
839 XRenderFillRectangle (dpy, PictOpSrc, mask, &mask_c, 0, 0, 1, 1); 631 XRenderFillRectangle (dpy, PictOpSrc, mask, &mask_c, 0, 0, 1, 1);
632
840 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);
841 634
842 XRenderFreePicture (dpy, src); 635 XRenderFreePicture (dpy, src);
843 XRenderFreePicture (dpy, dst); 636 XRenderFreePicture (dpy, dst);
844 XRenderFreePicture (dpy, mask); 637 XRenderFreePicture (dpy, mask);
851 } 644 }
852 645
853 if (result != pixbuf) 646 if (result != pixbuf)
854 g_object_unref (result); 647 g_object_unref (result);
855 648
856 if (tr_flags) 649 if (need_blend)
857 XFreePixmap (dpy, root_pmap); 650 XFreePixmap (dpy, tmp_pixmap);
858 651
859 return ret; 652 return ret;
860} 653}
861# endif /* HAVE_PIXBUF */ 654# endif /* HAVE_PIXBUF */
862 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
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)
881 ASImage *image = get_asimage (asimman, file, 0xFFFFFFFF, 100); 723 set_geometry (p ? 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 = 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 flags |= IM_IS_SET;
745
904 return false; 746 return ret;
905} 747}
906 748
907# endif /* BG_IMAGE_FROM_FILE */ 749# endif /* BG_IMAGE_FROM_FILE */
908 750
909# ifdef ENABLE_TRANSPARENCY
910bool 751bool
911rxvt_term::bg_set_transparent () 752image_effects::set_blur (const char *geom)
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
923rxvt_term::bg_set_blur (const char *geom)
924{ 753{
925 bool changed = false; 754 bool changed = false;
926 unsigned int hr, vr; 755 unsigned int hr, vr;
927 int junk; 756 int junk;
928 int geom_flags = XParseGeometry (geom, &junk, &junk, &hr, &vr); 757 int geom_flags = XParseGeometry (geom, &junk, &junk, &hr, &vr);
945 { 774 {
946 changed = true; 775 changed = true;
947 v_blurRadius = vr; 776 v_blurRadius = vr;
948 } 777 }
949 778
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; 779 return changed;
956} 780}
957 781
958void
959rxvt_term::set_tint_shade_flags ()
960{
961 rgba c (rgba::MAX_CC,rgba::MAX_CC,rgba::MAX_CC);
962 bool has_shade = shade != 100;
963
964 bg_flags &= ~BG_TINT_FLAGS;
965
966 if (bg_flags & BG_TINT_SET)
967 {
968 tint.get (c);
969 if (!has_shade
970 && (c.r <= 0x00ff || c.r >= 0xff00)
971 && (c.g <= 0x00ff || c.g >= 0xff00)
972 && (c.b <= 0x00ff || c.b >= 0xff00))
973 bg_flags |= BG_TINT_BITAND;
974 }
975
976 if (has_shade || (bg_flags & BG_TINT_SET))
977 bg_flags |= BG_NEEDS_TINT;
978}
979
980bool 782bool
981rxvt_term::bg_set_tint (rxvt_color &new_tint) 783image_effects::set_tint (const rxvt_color &new_tint)
982{ 784{
983 if (!(bg_flags & BG_TINT_SET) || tint != new_tint) 785 if (!tint_set || tint != new_tint)
984 { 786 {
985 tint = new_tint; 787 tint = new_tint;
986 bg_flags |= BG_TINT_SET; 788 tint_set = true;
987 set_tint_shade_flags (); 789
988 return true; 790 return true;
989 } 791 }
990 792
991 return false; 793 return false;
992} 794}
993 795
994bool 796bool
995rxvt_term::bg_set_shade (const char *shade_str) 797image_effects::set_shade (const char *shade_str)
996{ 798{
997 int new_shade = (shade_str) ? atoi (shade_str) : 100; 799 int new_shade = atoi (shade_str);
998 800
999 clamp_it (new_shade, -100, 200); 801 clamp_it (new_shade, -100, 200);
1000 if (new_shade < 0) 802 if (new_shade < 0)
1001 new_shade = 200 - (100 + new_shade); 803 new_shade = 200 - (100 + new_shade);
1002 804
1003 if (new_shade != shade) 805 if (new_shade != shade)
1004 { 806 {
1005 shade = new_shade; 807 shade = new_shade;
1006 set_tint_shade_flags ();
1007 return true; 808 return true;
1008 } 809 }
1009 810
1010 return false; 811 return false;
1011} 812}
1032 params[i+2] = XDoubleToFixed (kernel[i] / sum); 833 params[i+2] = XDoubleToFixed (kernel[i] / sum);
1033} 834}
1034#endif 835#endif
1035 836
1036bool 837bool
1037rxvt_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)
1038{ 839{
1039 bool ret = false; 840 bool ret = false;
1040#if XRENDER 841#if XRENDER
842 if (!(bg_flags & BG_HAS_RENDER_CONV))
843 return false;
844
1041 int size = max (h_blurRadius, v_blurRadius) * 2 + 1; 845 int size = max (h_blurRadius, v_blurRadius) * 2 + 1;
1042 double *kernel = (double *)malloc (size * sizeof (double)); 846 double *kernel = (double *)malloc (size * sizeof (double));
1043 XFixed *params = (XFixed *)malloc ((size + 2) * sizeof (XFixed)); 847 XFixed *params = (XFixed *)malloc ((size + 2) * sizeof (XFixed));
1044 848
1045 XRenderPictureAttributes pa; 849 XRenderPictureAttributes pa;
1046 XRenderPictFormat *format = XRenderFindVisualFormat (dpy, visual); 850 XRenderPictFormat *format = argb ? XRenderFindStandardFormat (dpy, PictStandardARGB32)
851 : XRenderFindVisualFormat (dpy, visual);
1047 852
853 pa.repeat = RepeatPad;
1048 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);
1049 Picture dst = XRenderCreatePicture (dpy, pixmap, format, 0, &pa); 856 Picture dst = XRenderCreatePicture (dpy, tmp, format, CPRepeat, &pa);
857 XFreePixmap (dpy, tmp);
1050 858
1051 if (kernel && params) 859 if (kernel && params)
1052 { 860 {
1053 if (h_blurRadius)
1054 {
1055 size = h_blurRadius * 2 + 1; 861 size = h_blurRadius * 2 + 1;
1056 get_gaussian_kernel (h_blurRadius, size, kernel, params); 862 get_gaussian_kernel (h_blurRadius, size, kernel, params);
1057 863
1058 XRenderSetPictureFilter (dpy, src, FilterConvolution, params, size+2); 864 XRenderSetPictureFilter (dpy, src, FilterConvolution, params, size+2);
1059 XRenderComposite (dpy, 865 XRenderComposite (dpy,
1060 PictOpSrc, 866 PictOpSrc,
1061 src, 867 src,
1062 None, 868 None,
1063 dst, 869 dst,
1064 0, 0, 870 0, 0,
1065 0, 0, 871 0, 0,
1066 0, 0, 872 0, 0,
1067 width, height); 873 width, height);
1068 }
1069 874
1070 if (v_blurRadius) 875 ::swap (src, dst);
1071 { 876
1072 size = v_blurRadius * 2 + 1; 877 size = v_blurRadius * 2 + 1;
1073 get_gaussian_kernel (v_blurRadius, size, kernel, params); 878 get_gaussian_kernel (v_blurRadius, size, kernel, params);
1074 ::swap (params[0], params[1]); 879 ::swap (params[0], params[1]);
1075 880
1076 XRenderSetPictureFilter (dpy, src, FilterConvolution, params, size+2); 881 XRenderSetPictureFilter (dpy, src, FilterConvolution, params, size+2);
1077 XRenderComposite (dpy, 882 XRenderComposite (dpy,
1078 PictOpSrc, 883 PictOpSrc,
1079 src, 884 src,
1080 None, 885 None,
1081 dst, 886 dst,
1082 0, 0, 887 0, 0,
1083 0, 0, 888 0, 0,
1084 0, 0, 889 0, 0,
1085 width, height); 890 width, height);
1086 }
1087 891
1088 ret = true; 892 ret = true;
1089 } 893 }
1090 894
1091 free (kernel); 895 free (kernel);
1095#endif 899#endif
1096 return ret; 900 return ret;
1097} 901}
1098 902
1099bool 903bool
1100rxvt_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)
1101{ 905{
1102 bool ret = false; 906 bool ret = false;
1103 907
1104 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))
1105 { 917 {
1106 XGCValues gcv; 918 XGCValues gcv;
1107 GC gc; 919 GC gc;
1108 920
1109 /* In this case we can tint image server-side getting significant 921 /* In this case we can tint image server-side getting significant
1118 XFillRectangle (dpy, pixmap, gc, 0, 0, width, height); 930 XFillRectangle (dpy, pixmap, gc, 0, 0, width, height);
1119 ret = true; 931 ret = true;
1120 XFreeGC (dpy, gc); 932 XFreeGC (dpy, gc);
1121 } 933 }
1122 } 934 }
1123 else
1124 {
1125# if XRENDER 935# if XRENDER
1126 rgba c (rgba::MAX_CC, rgba::MAX_CC, rgba::MAX_CC); 936 else if (bg_flags & BG_HAS_RENDER)
1127 937 {
1128 if (bg_flags & BG_TINT_SET)
1129 tint.get (c);
1130
1131 if (shade <= 100) 938 if (shade <= 100)
1132 { 939 {
1133 c.r = c.r * shade / 100; 940 c.r = c.r * shade / 100;
1134 c.g = c.g * shade / 100; 941 c.g = c.g * shade / 100;
1135 c.b = c.b * shade / 100; 942 c.b = c.b * shade / 100;
1139 c.r = c.r * (200 - shade) / 100; 946 c.r = c.r * (200 - shade) / 100;
1140 c.g = c.g * (200 - shade) / 100; 947 c.g = c.g * (200 - shade) / 100;
1141 c.b = c.b * (200 - shade) / 100; 948 c.b = c.b * (200 - shade) / 100;
1142 } 949 }
1143 950
1144 XRenderPictFormat *solid_format = XRenderFindStandardFormat (dpy, PictStandardARGB32); 951 XRenderPictFormat *format = argb ? XRenderFindStandardFormat (dpy, PictStandardARGB32)
1145 XRenderPictFormat *format = XRenderFindVisualFormat (dpy, visual); 952 : XRenderFindVisualFormat (dpy, visual);
1146 XRenderPictureAttributes pa;
1147 953
1148 Picture back_pic = XRenderCreatePicture (dpy, pixmap, format, 0, &pa); 954 Picture back_pic = XRenderCreatePicture (dpy, pixmap, format, 0, 0);
1149 955
1150 pa.repeat = True; 956 Picture overlay_pic = create_xrender_mask (dpy, pixmap, True, False);
1151 957
1152 Pixmap overlay_pmap = XCreatePixmap (dpy, pixmap, 1, 1, 32); 958 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 959
1161 XRenderColor mask_c; 960 XRenderColor mask_c;
1162 961
1163 mask_c.alpha = 0xffff; 962 mask_c.alpha = 0xffff;
1164 mask_c.red = 963 mask_c.red =
1169 mask_c.alpha = 0; 968 mask_c.alpha = 0;
1170 mask_c.red = 0xffff - c.r; 969 mask_c.red = 0xffff - c.r;
1171 mask_c.green = 0xffff - c.g; 970 mask_c.green = 0xffff - c.g;
1172 mask_c.blue = 0xffff - c.b; 971 mask_c.blue = 0xffff - c.b;
1173 XRenderFillRectangle (dpy, PictOpSrc, mask_pic, &mask_c, 0, 0, 1, 1); 972 XRenderFillRectangle (dpy, PictOpSrc, mask_pic, &mask_c, 0, 0, 1, 1);
973
1174 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);
1175 975
1176 if (shade > 100) 976 if (shade > 100)
1177 { 977 {
1178 mask_c.red = mask_c.green = mask_c.blue = 0xffff * (shade - 100) / 100;
1179 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;
1180 XRenderFillRectangle (dpy, PictOpSrc, overlay_pic, &mask_c, 0, 0, 1, 1); 982 XRenderFillRectangle (dpy, PictOpSrc, overlay_pic, &mask_c, 0, 0, 1, 1);
1181 983
1182 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);
1183 } 985 }
1184 986
1185 ret = true; 987 ret = true;
1186 988
1187 XRenderFreePicture (dpy, mask_pic); 989 XRenderFreePicture (dpy, mask_pic);
1188 XRenderFreePicture (dpy, overlay_pic); 990 XRenderFreePicture (dpy, overlay_pic);
1189 XRenderFreePicture (dpy, back_pic); 991 XRenderFreePicture (dpy, back_pic);
992 }
1190# endif 993# endif
1191 }
1192 994
1193 return ret; 995 return ret;
1194} 996}
1195 997
998# ifdef ENABLE_TRANSPARENCY
1196/* 999/*
1197 * 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
1198 * 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
1199 * our window. 1002 * our window.
1200 */ 1003 */
1201unsigned long 1004bool
1202rxvt_term::make_transparency_pixmap () 1005rxvt_term::render_root_image ()
1203{ 1006{
1204 unsigned long result = 0; 1007 bool ret = false;
1205 1008
1206 /* 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
1207 * be always up-to-date, so let's use it : 1010 * be always up-to-date, so let's use it :
1208 */ 1011 */
1209 int screen = display->screen; 1012 int screen = display->screen;
1247#if XRENDER 1050#if XRENDER
1248 if (bg_flags & BG_HAS_RENDER) 1051 if (bg_flags & BG_HAS_RENDER)
1249 { 1052 {
1250 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);
1251 1054
1252 XRenderPictureAttributes pa;
1253
1254 XRenderPictFormat *src_format = XRenderFindVisualFormat (dpy, DefaultVisual (dpy, screen)); 1055 XRenderPictFormat *src_format = XRenderFindVisualFormat (dpy, DefaultVisual (dpy, screen));
1255 Picture src = XRenderCreatePicture (dpy, root_pixmap, src_format, 0, &pa); 1056 Picture src = XRenderCreatePicture (dpy, root_pixmap, src_format, 0, 0);
1256 1057
1257 XRenderPictFormat *dst_format = XRenderFindVisualFormat (dpy, visual); 1058 XRenderPictFormat *dst_format = XRenderFindVisualFormat (dpy, visual);
1258 Picture dst = XRenderCreatePicture (dpy, recoded_root_pmap, dst_format, 0, &pa); 1059 Picture dst = XRenderCreatePicture (dpy, recoded_root_pmap, dst_format, 0, 0);
1259 1060
1260 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);
1261 1062
1262 XRenderFreePicture (dpy, src); 1063 XRenderFreePicture (dpy, src);
1263 XRenderFreePicture (dpy, dst); 1064 XRenderFreePicture (dpy, dst);
1280 bg_pmap_width = window_width; 1081 bg_pmap_width = window_width;
1281 bg_pmap_height = window_height; 1082 bg_pmap_height = window_height;
1282 } 1083 }
1283 1084
1284 /* straightforward pixmap copy */ 1085 /* straightforward pixmap copy */
1285 while (sx < 0) sx += root_width; 1086 while (sx < 0) sx += root_pmap_width;
1286 while (sy < 0) sy += root_height; 1087 while (sy < 0) sy += root_pmap_height;
1287 1088
1288 gcv.tile = recoded_root_pmap; 1089 gcv.tile = recoded_root_pmap;
1289 gcv.fill_style = FillTiled; 1090 gcv.fill_style = FillTiled;
1290 gcv.ts_x_origin = -sx; 1091 gcv.ts_x_origin = -sx;
1291 gcv.ts_y_origin = -sy; 1092 gcv.ts_y_origin = -sy;
1292 gc = XCreateGC (dpy, vt, GCFillStyle | GCTile | GCTileStipXOrigin | GCTileStipYOrigin, &gcv); 1093 gc = XCreateGC (dpy, vt, GCFillStyle | GCTile | GCTileStipXOrigin | GCTileStipYOrigin, &gcv);
1293 1094
1294 if (gc) 1095 if (gc)
1295 { 1096 {
1296 XFillRectangle (dpy, bg_pixmap, gc, 0, 0, window_width, window_height); 1097 XFillRectangle (dpy, bg_pixmap, gc, 0, 0, window_width, window_height);
1297 result |= BG_IS_VALID | (bg_flags & BG_EFFECTS_FLAGS); 1098 ret = true;
1099 bool need_blur = root_effects.need_blur ();
1100 bool need_tint = root_effects.need_tint ();
1101
1102 if (need_blur)
1103 {
1104 if (blur_pixmap (bg_pixmap, window_width, window_height, false,
1105 root_effects.h_blurRadius, root_effects.v_blurRadius))
1106 need_blur = false;
1107 }
1108 if (need_tint)
1109 {
1110 if (tint_pixmap (bg_pixmap, window_width, window_height, false,
1111 root_effects.tint, root_effects.tint_set, root_effects.shade))
1112 need_tint = false;
1113 }
1114 if (need_tint)
1115 {
1116 XImage *ximage = XGetImage (dpy, bg_pixmap, 0, 0, bg_pmap_width, bg_pmap_height, AllPlanes, ZPixmap);
1117 if (ximage)
1118 {
1119 /* our own client-side tinting */
1120 tint_ximage (ximage, root_effects.tint, root_effects.tint_set, root_effects.shade);
1121
1122 XPutImage (dpy, bg_pixmap, gc, ximage, 0, 0, 0, 0, ximage->width, ximage->height);
1123 XDestroyImage (ximage);
1124 }
1125 }
1126
1298 XFreeGC (dpy, gc); 1127 XFreeGC (dpy, gc);
1299
1300 if (!(bg_flags & BG_CLIENT_RENDER))
1301 {
1302 if ((bg_flags & BG_NEEDS_BLUR)
1303 && (bg_flags & BG_HAS_RENDER_CONV))
1304 {
1305 if (blur_pixmap (bg_pixmap, visual, window_width, window_height))
1306 result &= ~BG_NEEDS_BLUR;
1307 }
1308 if ((bg_flags & BG_NEEDS_TINT)
1309 && (bg_flags & (BG_TINT_BITAND | BG_HAS_RENDER)))
1310 {
1311 if (tint_pixmap (bg_pixmap, visual, window_width, window_height))
1312 result &= ~BG_NEEDS_TINT;
1313 }
1314 } /* server side rendering completed */
1315 } 1128 }
1316 1129
1317 if (recoded_root_pmap != root_pixmap) 1130 if (recoded_root_pmap != root_pixmap)
1318 XFreePixmap (dpy, recoded_root_pmap); 1131 XFreePixmap (dpy, recoded_root_pmap);
1319 1132
1320 return result; 1133 return ret;
1321} 1134}
1322 1135
1323void 1136void
1324rxvt_term::bg_set_root_pixmap () 1137rxvt_term::bg_set_root_pixmap ()
1325{ 1138{
1329 1142
1330 root_pixmap = new_root_pixmap; 1143 root_pixmap = new_root_pixmap;
1331} 1144}
1332# endif /* ENABLE_TRANSPARENCY */ 1145# endif /* ENABLE_TRANSPARENCY */
1333 1146
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 1147bool
1339rxvt_term::bg_render () 1148rxvt_term::bg_render ()
1340{ 1149{
1341 unsigned long tr_flags = 0;
1342
1343 bg_invalidate (); 1150 bg_invalidate ();
1344# ifdef ENABLE_TRANSPARENCY 1151# ifdef ENABLE_TRANSPARENCY
1345 if (bg_flags & BG_IS_TRANSPARENT) 1152 if (bg_flags & BG_IS_TRANSPARENT)
1346 { 1153 {
1347 /* we need to re-generate transparency pixmap in that case ! */ 1154 /* we need to re-generate transparency pixmap in that case ! */
1348 tr_flags = make_transparency_pixmap (); 1155 if (render_root_image ())
1349 if (tr_flags == 0)
1350 return false;
1351 else if (!(tr_flags & BG_EFFECTS_FLAGS))
1352 bg_flags |= BG_IS_VALID; 1156 bg_flags |= BG_IS_VALID;
1353 } 1157 }
1354# endif 1158# endif
1355 1159
1356# ifdef BG_IMAGE_FROM_FILE 1160# ifdef BG_IMAGE_FROM_FILE
1357 if ((bg_flags & BG_IS_FROM_FILE) 1161 for (vector<rxvt_image>::iterator bg_image = image_vec.begin (); bg_image < image_vec.end (); bg_image++)
1358 || (tr_flags & BG_EFFECTS_FLAGS))
1359 { 1162 {
1360 if (render_image (tr_flags)) 1163 if (render_image (*bg_image))
1361 bg_flags |= BG_IS_VALID; 1164 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 } 1165 }
1396# endif 1166# endif
1397 1167
1398 if (!(bg_flags & BG_IS_VALID)) 1168 if (!(bg_flags & BG_IS_VALID))
1399 { 1169 {
1413} 1183}
1414 1184
1415void 1185void
1416rxvt_term::bg_init () 1186rxvt_term::bg_init ()
1417{ 1187{
1418#ifdef ENABLE_TRANSPARENCY
1419 shade = 100;
1420#endif
1421
1422 bg_flags &= ~(BG_HAS_RENDER | BG_HAS_RENDER_CONV); 1188 bg_flags &= ~(BG_HAS_RENDER | BG_HAS_RENDER_CONV);
1423#if XRENDER 1189#if XRENDER
1424 int major, minor; 1190 int major, minor;
1425 if (XRenderQueryVersion (dpy, &major, &minor)) 1191 if (XRenderQueryVersion (dpy, &major, &minor))
1426 bg_flags |= BG_HAS_RENDER; 1192 bg_flags |= BG_HAS_RENDER;
1432 bg_flags |= BG_HAS_RENDER_CONV; 1198 bg_flags |= BG_HAS_RENDER_CONV;
1433 1199
1434 XFree (filters); 1200 XFree (filters);
1435 } 1201 }
1436#endif 1202#endif
1437}
1438 1203
1439#endif /* HAVE_BG_PIXMAP */ 1204#ifdef BG_IMAGE_FROM_FILE
1205 if (rs[Rs_backgroundPixmap])
1206 {
1207 rxvt_image *image = new_image ();
1208 if (!image->set_file_geometry (rs[Rs_backgroundPixmap]))
1209 image_vec.pop_back ();
1210 }
1440 1211
1441#if defined(ENABLE_TRANSPARENCY) && !defined(HAVE_AFTERIMAGE) 1212# ifndef NO_RESOURCES
1213 find_resources ("image", "Image", XrmEnumAllLevels, rxvt_define_image);
1214 vector<rxvt_image>::iterator bg_image = image_vec.begin ();
1215 while (bg_image != image_vec.end ())
1216 {
1217 if (!(bg_image->flags & IM_IS_SET))
1218 bg_image = image_vec.erase (bg_image);
1219 else
1220 {
1221 if (bg_image->is_size_sensitive ())
1222 bg_image->flags |= IM_IS_SIZE_SENSITIVE;
1223
1224 bg_image++;
1225 }
1226 }
1227# endif
1228
1229 if (image_vec.size () > 0
1230 && !bg_window_position_sensitive ())
1231 update_background ();
1232#endif
1233}
1234
1442/* taken from aterm-0.4.2 */ 1235/* based on code from aterm-0.4.2 */
1443 1236
1444static void 1237static inline void
1445shade_ximage (Visual *visual, XImage *ximage, int shade, const rgba &c) 1238fill_lut (uint32_t *lookup, uint32_t mask, int sh, unsigned short low, unsigned short high)
1446{ 1239{
1240 for (int i = 0; i <= mask >> sh; i++)
1241 {
1242 uint32_t tmp;
1243 tmp = i * high;
1244 tmp += (mask >> sh) * low;
1245 lookup[i] = (tmp / 0xffff) << sh;
1246 }
1247}
1248
1249void
1250rxvt_term::tint_ximage (XImage *ximage, rxvt_color &tint, bool tint_set, int shade)
1251{
1252 unsigned int size_r, size_g, size_b;
1447 int sh_r, sh_g, sh_b; 1253 int sh_r, sh_g, sh_b;
1448 uint32_t mask_r, mask_g, mask_b; 1254 uint32_t mask_r, mask_g, mask_b;
1449 uint32_t *lookup, *lookup_r, *lookup_g, *lookup_b; 1255 uint32_t *lookup, *lookup_r, *lookup_g, *lookup_b;
1450 rgba low; 1256 unsigned short low;
1451 rgba high;
1452 int i;
1453 int host_byte_order = ecb_big_endian () ? MSBFirst : LSBFirst; 1257 int host_byte_order = ecb_big_endian () ? MSBFirst : LSBFirst;
1454 1258
1455 if (visual->c_class != TrueColor || ximage->format != ZPixmap) return; 1259 if (visual->c_class != TrueColor || ximage->format != ZPixmap) return;
1456 1260
1457 /* for convenience */ 1261 /* for convenience */
1458 mask_r = visual->red_mask; 1262 mask_r = visual->red_mask;
1459 mask_g = visual->green_mask; 1263 mask_g = visual->green_mask;
1460 mask_b = visual->blue_mask; 1264 mask_b = visual->blue_mask;
1461 1265
1462 /* boring lookup table pre-initialization */ 1266 /* boring lookup table pre-initialization */
1463 switch (ximage->depth) 1267 sh_r = ecb_ctz32 (mask_r);
1464 { 1268 sh_g = ecb_ctz32 (mask_g);
1465 case 15: 1269 sh_b = ecb_ctz32 (mask_b);
1466 if ((mask_r != 0x7c00) || 1270
1467 (mask_g != 0x03e0) || 1271 size_r = mask_r >> sh_r;
1468 (mask_b != 0x001f)) 1272 size_g = mask_g >> sh_g;
1273 size_b = mask_b >> sh_b;
1274
1275 if (size_r++ > 255 || size_g++ > 255 || size_b++ > 255)
1469 return; 1276 return;
1470 lookup = (uint32_t *) malloc (sizeof (uint32_t)*(32+32+32)); 1277
1278 lookup = (uint32_t *)malloc (sizeof (uint32_t) * (size_r + size_g + size_b));
1471 lookup_r = lookup; 1279 lookup_r = lookup;
1472 lookup_g = lookup+32; 1280 lookup_g = lookup + size_r;
1473 lookup_b = lookup+32+32; 1281 lookup_b = lookup + size_r + size_g;
1474 sh_r = 10; 1282
1475 sh_g = 5; 1283 rgba c (rgba::MAX_CC, rgba::MAX_CC, rgba::MAX_CC);
1476 sh_b = 0; 1284
1477 break; 1285 if (tint_set)
1478 case 16: 1286 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 1287
1521 /* prepare limits for color transformation (each channel is handled separately) */ 1288 /* prepare limits for color transformation (each channel is handled separately) */
1522 if (shade > 100) 1289 if (shade > 100)
1523 { 1290 {
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; 1291 c.r = c.r * (200 - shade) / 100;
1531 low.g = 65535 * (100 - shade) / 100; 1292 c.g = c.g * (200 - shade) / 100;
1532 low.b = 65535 * (100 - shade) / 100; 1293 c.b = c.b * (200 - shade) / 100;
1294
1295 low = 0xffff * (shade - 100) / 100;
1533 } 1296 }
1534 else 1297 else
1535 { 1298 {
1536 high.r = c.r * shade / 100; 1299 c.r = c.r * shade / 100;
1537 high.g = c.g * shade / 100; 1300 c.g = c.g * shade / 100;
1538 high.b = c.b * shade / 100; 1301 c.b = c.b * shade / 100;
1539 1302
1540 low.r = low.g = low.b = 0; 1303 low = 0;
1541 } 1304 }
1542 1305
1543 /* fill our lookup tables */ 1306 /* fill our lookup tables */
1544 for (i = 0; i <= mask_r>>sh_r; i++) 1307 fill_lut (lookup_r, mask_r, sh_r, low, c.r);
1545 { 1308 fill_lut (lookup_g, mask_g, sh_g, low, c.g);
1546 uint32_t tmp; 1309 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 1310
1566 /* apply table to input image (replacing colors by newly calculated ones) */ 1311 /* apply table to input image (replacing colors by newly calculated ones) */
1567 if (ximage->bits_per_pixel == 32 1312 if (ximage->bits_per_pixel == 32
1568 && (ximage->depth == 24 || ximage->depth == 32)
1569 && ximage->byte_order == host_byte_order) 1313 && ximage->byte_order == host_byte_order)
1570 { 1314 {
1571 uint32_t *p1, *pf, *p, *pl; 1315 char *line = ximage->data;
1572 p1 = (uint32_t *) ximage->data;
1573 pf = (uint32_t *) (ximage->data + ximage->height * ximage->bytes_per_line);
1574 1316
1575 while (p1 < pf) 1317 for (int y = 0; y < ximage->height; y++)
1576 { 1318 {
1577 p = p1; 1319 uint32_t *p = (uint32_t *)line;
1578 pl = p1 + ximage->width; 1320 for (int x = 0; x < ximage->width; x++)
1579 for (; p < pl; p++)
1580 { 1321 {
1581 *p = lookup_r[(*p & 0xff0000) >> 16] | 1322 *p = lookup_r[(*p & mask_r) >> sh_r] |
1582 lookup_g[(*p & 0x00ff00) >> 8] | 1323 lookup_g[(*p & mask_g) >> sh_g] |
1583 lookup_b[(*p & 0x0000ff)] | 1324 lookup_b[(*p & mask_b) >> sh_b];
1584 (*p & 0xff000000); 1325 p++;
1585 } 1326 }
1586 p1 = (uint32_t *) ((char *) p1 + ximage->bytes_per_line); 1327 line += ximage->bytes_per_line;
1587 } 1328 }
1588 } 1329 }
1589 else 1330 else
1590 { 1331 {
1591 for (int y = 0; y < ximage->height; y++) 1332 for (int y = 0; y < ximage->height; y++)
1599 } 1340 }
1600 } 1341 }
1601 1342
1602 free (lookup); 1343 free (lookup);
1603} 1344}
1604#endif /* defined(ENABLE_TRANSPARENCY) && !defined(HAVE_AFTERIMAGE) */ 1345
1346#endif /* HAVE_BG_PIXMAP */

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines