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.155 by sf-exg, Mon May 30 18:39:02 2011 UTC vs.
Revision 1.208 by sf-exg, Fri May 11 08:16:58 2012 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines