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.156 by sf-exg, Tue Aug 9 18:41:31 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 new_flags |= BG_TILE;
266 w = h = noScale;
267 geom_flags |= WidthValue|HeightValue;
268 }
269 else if (!strcasecmp (arr[i], "propscale"))
270 {
271 new_flags |= BG_PROP_SCALE;
272 }
273 else if (!strcasecmp (arr[i], "hscale"))
274 {
275 if (w == 0) w = windowScale;
276 286
277 h = noScale; 287 if (bg_flags != new_flags
278 geom_flags |= WidthValue|HeightValue; 288 || h_scale != w
279 } 289 || v_scale != h
280 else if (!strcasecmp (arr[i], "vscale")) 290 || h_align != x
281 { 291 || v_align != y)
282 if (h == 0) h = windowScale;
283
284 w = noScale;
285 geom_flags |= WidthValue|HeightValue;
286 }
287 else if (!strcasecmp (arr[i], "scale"))
288 {
289 if (h == 0) h = windowScale;
290 if (w == 0) w = windowScale;
291
292 geom_flags |= WidthValue|HeightValue;
293 }
294 else if (!strcasecmp (arr[i], "auto"))
295 {
296 w = h = windowScale;
297 x = y = centerAlign;
298 geom_flags |= WidthValue|HeightValue|XValue|YValue;
299 }
300 else if (!strcasecmp (arr[i], "root"))
301 {
302 new_flags |= BG_TILE|BG_ROOT_ALIGN;
303 w = h = noScale;
304 geom_flags |= WidthValue|HeightValue;
305 }
306 } /* done parsing ops */
307
308 rxvt_free_strsplit (arr);
309 }
310
311 if (check_set_scale_value (geom_flags, WidthValue, h_scale, w)) changed = true;
312 if (check_set_scale_value (geom_flags, HeightValue, v_scale, h)) changed = true;
313 if (check_set_align_value (geom_flags, XValue, h_align, x)) changed = true;
314 if (check_set_align_value (geom_flags, YValue, v_align, y)) changed = true;
315
316 if (new_flags != bg_flags)
317 { 292 {
318 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;
319 changed = true; 298 changed = true;
320 } 299 }
321 300
322 return changed; 301 return changed;
323} 302}
326rxvt_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)
327{ 306{
328 int target_width = szHint.width; 307 int target_width = szHint.width;
329 int target_height = szHint.height; 308 int target_height = szHint.height;
330 309
310 w = h_scale * target_width / 100;
311 h = v_scale * target_height / 100;
312
331 if (bg_flags & BG_PROP_SCALE) 313 if (bg_flags & BG_KEEP_ASPECT)
332 { 314 {
333 float scale = (float)target_width / image_width; 315 float scale = (float)w / image_width;
334 min_it (scale, (float)target_height / image_height); 316 min_it (scale, (float)h / image_height);
335 w = image_width * scale + 0.5; 317 w = image_width * scale + 0.5;
336 h = image_height * scale + 0.5; 318 h = image_height * scale + 0.5;
337 } 319 }
338 else
339 {
340 w = h_scale * target_width / 100;
341 h = v_scale * target_height / 100;
342 }
343 320
344 if (!w) w = image_width; 321 if (!w) w = image_width;
345 if (!h) h = image_height; 322 if (!h) h = image_height;
346 323
347 if (bg_flags & BG_ROOT_ALIGN) 324 if (bg_flags & BG_ROOT_ALIGN)
353 { 330 {
354 x = make_align_position (h_align, target_width, w); 331 x = make_align_position (h_align, target_width, w);
355 y = make_align_position (v_align, target_height, h); 332 y = make_align_position (v_align, target_height, h);
356 } 333 }
357 334
358 bg_flags &= ~BG_IS_SIZE_SENSITIVE;
359 if (!(bg_flags & BG_TILE) 335 if (!(bg_flags & BG_TILE)
360 || (bg_flags & BG_PROP_SCALE) || h_scale || v_scale 336 || h_scale || v_scale
361 || (!(bg_flags & BG_ROOT_ALIGN) && (h_align || v_align)) 337 || (!(bg_flags & BG_ROOT_ALIGN) && (h_align || v_align))
362 || w > target_width || h > target_height) 338 || image_width > target_width || image_height > target_height)
363 bg_flags |= BG_IS_SIZE_SENSITIVE; 339 bg_flags |= BG_IS_SIZE_SENSITIVE;
364}
365
366# ifdef HAVE_AFTERIMAGE
367bool
368rxvt_term::render_image (unsigned long tr_flags)
369{
370 init_asv ();
371
372 ASImage *background = NULL;
373 ARGB32 background_tint = TINT_LEAVE_SAME;
374
375# ifdef ENABLE_TRANSPARENCY
376 if (tr_flags)
377 background = pixmap2ximage (asv, bg_pixmap, 0, 0, bg_pmap_width, bg_pmap_height, AllPlanes, 100);
378
379 if (tr_flags & BG_NEEDS_TINT)
380 {
381 ShadingInfo as_shade;
382 as_shade.shading = shade;
383
384 rgba c (rgba::MAX_CC,rgba::MAX_CC,rgba::MAX_CC);
385 if (bg_flags & BG_TINT_SET)
386 tint.get (c);
387 as_shade.tintColor.red = c.r;
388 as_shade.tintColor.green = c.g;
389 as_shade.tintColor.blue = c.b;
390
391 background_tint = shading2tint32 (&as_shade);
392 }
393
394 if ((tr_flags & BG_NEEDS_BLUR) && background != NULL)
395 {
396 ASImage *tmp = blur_asimage_gauss (asv, background, h_blurRadius, v_blurRadius, 0xFFFFFFFF,
397 (original_asim == NULL || tint == TINT_LEAVE_SAME) ? ASA_XImage : ASA_ASImage,
398 100, ASIMAGE_QUALITY_DEFAULT);
399 if (tmp)
400 {
401 destroy_asimage (&background);
402 background = tmp;
403 }
404 }
405# endif
406
407 ASImage *result = 0;
408
409 int target_width = szHint.width;
410 int target_height = szHint.height;
411 int new_pmap_width = target_width;
412 int new_pmap_height = target_height;
413
414 int x = 0;
415 int y = 0;
416 int w = 0;
417 int h = 0;
418
419 if (original_asim)
420 get_image_geometry (original_asim->width, original_asim->height, w, h, x, y);
421
422 if (!original_asim
423 || (!(bg_flags & BG_ROOT_ALIGN)
424 && (x >= target_width
425 || y >= target_height
426 || (x + w <= 0)
427 || (y + h <= 0))))
428 {
429 if (background)
430 {
431 new_pmap_width = background->width;
432 new_pmap_height = background->height;
433 result = background;
434
435 if (background_tint != TINT_LEAVE_SAME)
436 {
437 ASImage *tmp = tile_asimage (asv, background, 0, 0,
438 target_width, target_height, background_tint,
439 ASA_XImage, 100, ASIMAGE_QUALITY_DEFAULT);
440 if (tmp)
441 result = tmp;
442 }
443 }
444 else
445 new_pmap_width = new_pmap_height = 0;
446 }
447 else 340 else
448 { 341 bg_flags &= ~BG_IS_SIZE_SENSITIVE;
449 result = original_asim;
450
451 if ((w != original_asim->width)
452 || (h != original_asim->height))
453 {
454 result = scale_asimage (asv, original_asim,
455 w, h,
456 background ? ASA_ASImage : ASA_XImage,
457 100, ASIMAGE_QUALITY_DEFAULT);
458 }
459
460 if (background == NULL)
461 {
462 if (bg_flags & BG_TILE)
463 {
464 /* if tiling - pixmap has to be sized exactly as the image,
465 but there is no need to make it bigger than the window! */
466 new_pmap_width = min (result->width, target_width);
467 new_pmap_height = min (result->height, target_height);
468
469 /* we also need to tile our image in both directions */
470 ASImage *tmp = tile_asimage (asv, result,
471 (int)result->width - x,
472 (int)result->height - y,
473 new_pmap_width,
474 new_pmap_height,
475 TINT_LEAVE_SAME, ASA_XImage,
476 100, ASIMAGE_QUALITY_DEFAULT);
477 if (tmp)
478 {
479 if (result != original_asim)
480 destroy_asimage (&result);
481
482 result = tmp;
483 }
484 }
485 }
486 else
487 {
488 /* if blending background and image - pixmap has to be sized same as target window */
489 ASImageLayer *layers = create_image_layers (2);
490
491 layers[0].im = background;
492 layers[0].clip_width = target_width;
493 layers[0].clip_height = target_height;
494 layers[0].tint = background_tint;
495 layers[1].im = result;
496
497 if (bg_flags & BG_TILE)
498 {
499 /* tile horizontally */
500 while (x > 0) x -= (int)result->width;
501 layers[1].dst_x = x;
502 layers[1].clip_width = result->width+target_width;
503 }
504 else
505 {
506 /* clip horizontally */
507 layers[1].dst_x = x;
508 layers[1].clip_width = result->width;
509 }
510
511 if (bg_flags & BG_TILE)
512 {
513 while (y > 0) y -= (int)result->height;
514 layers[1].dst_y = y;
515 layers[1].clip_height = result->height + target_height;
516 }
517 else
518 {
519 layers[1].dst_y = y;
520 layers[1].clip_height = result->height;
521 }
522
523 if (rs[Rs_blendtype])
524 {
525 layers[1].merge_scanlines = blend_scanlines_name2func (rs[Rs_blendtype]);
526 if (layers[1].merge_scanlines == NULL)
527 layers[1].merge_scanlines = alphablend_scanlines;
528 }
529
530 ASImage *tmp = merge_layers (asv, layers, 2, target_width, target_height,
531 ASA_XImage, 0, ASIMAGE_QUALITY_DEFAULT);
532
533 if (tmp)
534 {
535 if (result != original_asim)
536 destroy_asimage (&result);
537
538 result = tmp;
539 }
540
541 free (layers);
542 }
543 }
544
545 bool ret = false;
546
547 if (result)
548 {
549 XGCValues gcv;
550 GC gc;
551
552 /* create Pixmap */
553 if (bg_pixmap == None
554 || bg_pmap_width != new_pmap_width
555 || bg_pmap_height != new_pmap_height)
556 {
557 if (bg_pixmap)
558 XFreePixmap (dpy, bg_pixmap);
559 bg_pixmap = XCreatePixmap (dpy, vt, new_pmap_width, new_pmap_height, depth);
560 bg_pmap_width = new_pmap_width;
561 bg_pmap_height = new_pmap_height;
562 }
563 /* fill with background color (if result's not completely overlapping it) */
564 gcv.foreground = pix_colors[Color_bg];
565 gc = XCreateGC (dpy, vt, GCForeground, &gcv);
566
567 int src_x = 0, src_y = 0, dst_x = 0, dst_y = 0;
568 int dst_width = result->width, dst_height = result->height;
569 if (background == NULL)
570 {
571 if (!(bg_flags & BG_TILE))
572 {
573 src_x = make_clip_rectangle (x, result->width , new_pmap_width , dst_x, dst_width );
574 src_y = make_clip_rectangle (y, result->height, new_pmap_height, dst_y, dst_height);
575 }
576
577 if (dst_x > 0 || dst_y > 0
578 || dst_x + dst_width < new_pmap_width
579 || dst_y + dst_height < new_pmap_height)
580 XFillRectangle (dpy, bg_pixmap, gc, 0, 0, new_pmap_width, new_pmap_height);
581 }
582
583 /* put result on pixmap */
584 if (dst_x < new_pmap_width && dst_y < new_pmap_height)
585 asimage2drawable (asv, bg_pixmap, result, gc, src_x, src_y, dst_x, dst_y, dst_width, dst_height, True);
586
587 if (result != background && result != original_asim)
588 destroy_asimage (&result);
589
590 XFreeGC (dpy, gc);
591
592 ret = true;
593 }
594
595 if (background)
596 destroy_asimage (&background);
597
598 return ret;
599} 342}
600# endif /* HAVE_AFTERIMAGE */
601 343
602# ifdef HAVE_PIXBUF 344# ifdef HAVE_PIXBUF
603bool 345bool
604rxvt_term::pixbuf_to_pixmap (GdkPixbuf *pixbuf, Pixmap pixmap, GC gc, 346rxvt_term::pixbuf_to_pixmap (GdkPixbuf *pixbuf, Pixmap pixmap, GC gc,
605 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,
606 unsigned int width, unsigned int height) 348 unsigned int width, unsigned int height)
607{ 349{
608 XImage *ximage; 350 XImage *ximage;
609 char *data, *line; 351 char *data, *line;
610 int bytes_per_pixel; 352 int bytes_per_pixel;
611 int width_r, width_g, width_b; 353 int width_r, width_g, width_b, width_a;
612 int sh_r, sh_g, sh_b; 354 int sh_r, sh_g, sh_b, sh_a;
355 uint32_t alpha_mask;
613 int rowstride; 356 int rowstride;
614 int channels; 357 int channels;
615 unsigned char *row; 358 unsigned char *row;
616 359
617 if (visual->c_class != TrueColor) 360 if (visual->c_class != TrueColor)
618 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;
619 370
620 if (depth == 24 || depth == 32) 371 if (depth == 24 || depth == 32)
621 bytes_per_pixel = 4; 372 bytes_per_pixel = 4;
622 else if (depth == 15 || depth == 16) 373 else if (depth == 15 || depth == 16)
623 bytes_per_pixel = 2; 374 bytes_per_pixel = 2;
625 return false; 376 return false;
626 377
627 width_r = ecb_popcount32 (visual->red_mask); 378 width_r = ecb_popcount32 (visual->red_mask);
628 width_g = ecb_popcount32 (visual->green_mask); 379 width_g = ecb_popcount32 (visual->green_mask);
629 width_b = ecb_popcount32 (visual->blue_mask); 380 width_b = ecb_popcount32 (visual->blue_mask);
381 width_a = ecb_popcount32 (alpha_mask);
630 382
631 if (width_r > 8 || width_g > 8 || width_b > 8) 383 if (width_r > 8 || width_g > 8 || width_b > 8 || width_a > 8)
632 return false; 384 return false;
633 385
634 sh_r = ecb_ctz32 (visual->red_mask); 386 sh_r = ecb_ctz32 (visual->red_mask);
635 sh_g = ecb_ctz32 (visual->green_mask); 387 sh_g = ecb_ctz32 (visual->green_mask);
636 sh_b = ecb_ctz32 (visual->blue_mask); 388 sh_b = ecb_ctz32 (visual->blue_mask);
389 sh_a = ecb_ctz32 (alpha_mask);
637 390
638 if (width > INT_MAX / height / bytes_per_pixel) 391 if (width > INT_MAX / height / bytes_per_pixel)
639 return false; 392 return false;
640 393
641 data = (char *)malloc (width * height * bytes_per_pixel); 394 data = (char *)malloc (width * height * bytes_per_pixel);
655 rowstride = gdk_pixbuf_get_rowstride (pixbuf); 408 rowstride = gdk_pixbuf_get_rowstride (pixbuf);
656 channels = gdk_pixbuf_get_n_channels (pixbuf); 409 channels = gdk_pixbuf_get_n_channels (pixbuf);
657 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;
658 line = data; 411 line = data;
659 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
660 for (int y = 0; y < height; y++) 423 for (int y = 0; y < height; y++)
661 { 424 {
662 for (int x = 0; x < width; x++) 425 for (int x = 0; x < width; x++)
663 { 426 {
664 unsigned char *pixel = row + x * channels; 427 unsigned char *pixel = row + x * channels;
665 uint32_t value; 428 uint32_t value;
429 unsigned char r, g, b, a;
666 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
667 value = ((pixel[0] >> (8 - width_r)) << sh_r) 446 value = ((r >> (8 - width_r)) << sh_r)
668 | ((pixel[1] >> (8 - width_g)) << sh_g) 447 | ((g >> (8 - width_g)) << sh_g)
669 | ((pixel[2] >> (8 - width_b)) << sh_b); 448 | ((b >> (8 - width_b)) << sh_b)
449 | ((a >> (8 - width_a)) << sh_a);
670 450
671 if (bytes_per_pixel == 4) 451 if (bytes_per_pixel == 4)
672 ((uint32_t *)line)[x] = value; 452 ((uint32_t *)line)[x] = value;
673 else 453 else
674 ((uint16_t *)line)[x] = value; 454 ((uint16_t *)line)[x] = value;
682 XDestroyImage (ximage); 462 XDestroyImage (ximage);
683 return true; 463 return true;
684} 464}
685 465
686bool 466bool
687rxvt_term::render_image (unsigned long tr_flags) 467rxvt_term::render_image (bool transparent)
688{ 468{
689 if (!pixbuf) 469 if (!pixbuf)
690 return false; 470 return false;
691 471
692 if (tr_flags 472 if (transparent
693 && !(bg_flags & BG_HAS_RENDER)) 473 && !(bg_flags & BG_HAS_RENDER))
694 return false; 474 return false;
695 475
696 GdkPixbuf *result; 476 GdkPixbuf *result;
697 477
711 get_image_geometry (image_width, image_height, w, h, x, y); 491 get_image_geometry (image_width, image_height, w, h, x, y);
712 492
713 if (!(bg_flags & BG_ROOT_ALIGN) 493 if (!(bg_flags & BG_ROOT_ALIGN)
714 && (x >= target_width 494 && (x >= target_width
715 || y >= target_height 495 || y >= target_height
716 || (x + w <= 0) 496 || x + w <= 0
717 || (y + h <= 0))) 497 || y + h <= 0))
718 return false; 498 return false;
719 499
720 result = pixbuf; 500 result = pixbuf;
721 501
722 if ((w != image_width) 502 if (w != image_width
723 || (h != image_height)) 503 || h != image_height)
724 { 504 {
725 result = gdk_pixbuf_scale_simple (pixbuf, 505 result = gdk_pixbuf_scale_simple (pixbuf,
726 w, h, 506 w, h,
727 GDK_INTERP_BILINEAR); 507 GDK_INTERP_BILINEAR);
728 } 508 }
737 Pixmap root_pmap; 517 Pixmap root_pmap;
738 518
739 image_width = gdk_pixbuf_get_width (result); 519 image_width = gdk_pixbuf_get_width (result);
740 image_height = gdk_pixbuf_get_height (result); 520 image_height = gdk_pixbuf_get_height (result);
741 521
742 if (tr_flags) 522 if (transparent)
743 { 523 {
744 root_pmap = bg_pixmap; 524 root_pmap = bg_pixmap;
745 bg_pixmap = None; 525 bg_pixmap = None;
746 } 526 }
747 else 527 else
805 dst_x, dst_y, 585 dst_x, dst_y,
806 dst_width, dst_height); 586 dst_width, dst_height);
807 } 587 }
808 588
809#if XRENDER 589#if XRENDER
810 if (tr_flags) 590 if (transparent)
811 { 591 {
812 XRenderPictureAttributes pa;
813
814 XRenderPictFormat *src_format = XRenderFindVisualFormat (dpy, visual); 592 XRenderPictFormat *format = XRenderFindVisualFormat (dpy, visual);
593
815 Picture src = XRenderCreatePicture (dpy, root_pmap, src_format, 0, &pa); 594 Picture src = XRenderCreatePicture (dpy, root_pmap, format, 0, 0);
816 595
817 XRenderPictFormat *dst_format = XRenderFindVisualFormat (dpy, visual);
818 Picture dst = XRenderCreatePicture (dpy, bg_pixmap, dst_format, 0, &pa); 596 Picture dst = XRenderCreatePicture (dpy, bg_pixmap, format, 0, 0);
819 597
820 pa.repeat = True; 598 Picture mask = create_xrender_mask (dpy, vt, False, False);
821 Pixmap mask_pmap = XCreatePixmap (dpy, vt, 1, 1, 8);
822 XRenderPictFormat *mask_format = XRenderFindStandardFormat (dpy, PictStandardA8);
823 Picture mask = XRenderCreatePicture (dpy, mask_pmap, mask_format, CPRepeat, &pa);
824 XFreePixmap (dpy, mask_pmap);
825 599
826 XRenderColor mask_c; 600 XRenderColor mask_c;
827 601
828 mask_c.alpha = 0x8000; 602 mask_c.alpha = 0x8000;
829 mask_c.red = 0; 603 mask_c.red =
830 mask_c.green = 0; 604 mask_c.green =
831 mask_c.blue = 0; 605 mask_c.blue = 0;
832 XRenderFillRectangle (dpy, PictOpSrc, mask, &mask_c, 0, 0, 1, 1); 606 XRenderFillRectangle (dpy, PictOpSrc, mask, &mask_c, 0, 0, 1, 1);
607
833 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);
834 609
835 XRenderFreePicture (dpy, src); 610 XRenderFreePicture (dpy, src);
836 XRenderFreePicture (dpy, dst); 611 XRenderFreePicture (dpy, dst);
837 XRenderFreePicture (dpy, mask); 612 XRenderFreePicture (dpy, mask);
844 } 619 }
845 620
846 if (result != pixbuf) 621 if (result != pixbuf)
847 g_object_unref (result); 622 g_object_unref (result);
848 623
849 if (tr_flags) 624 if (transparent)
850 XFreePixmap (dpy, root_pmap); 625 XFreePixmap (dpy, root_pmap);
851 626
852 return ret; 627 return ret;
853} 628}
854# endif /* HAVE_PIXBUF */ 629# endif /* HAVE_PIXBUF */
857rxvt_term::bg_set_file (const char *file) 632rxvt_term::bg_set_file (const char *file)
858{ 633{
859 if (!file || !*file) 634 if (!file || !*file)
860 return false; 635 return false;
861 636
637 bool ret = false;
862 if (const char *p = strchr (file, ';')) 638 const char *p = strchr (file, ';');
639
640 if (p)
863 { 641 {
864 size_t len = p - file; 642 size_t len = p - file;
865 char *f = rxvt_temp_buf<char> (len + 1); 643 char *f = rxvt_temp_buf<char> (len + 1);
866 memcpy (f, file, len); 644 memcpy (f, file, len);
867 f[len] = '\0'; 645 f[len] = '\0';
868 file = f; 646 file = f;
869 } 647 }
870 648
871# ifdef HAVE_AFTERIMAGE
872 if (!asimman)
873 asimman = create_generic_imageman (rs[Rs_path]);
874 ASImage *image = get_asimage (asimman, file, 0xFFFFFFFF, 100);
875 if (image)
876 {
877 if (original_asim)
878 safe_asimage_destroy (original_asim);
879 original_asim = image;
880 bg_flags |= BG_IS_FROM_FILE | BG_CLIENT_RENDER;
881 return true;
882 }
883# endif
884
885# ifdef HAVE_PIXBUF 649# ifdef HAVE_PIXBUF
886 GdkPixbuf *image = gdk_pixbuf_new_from_file (file, NULL); 650 GdkPixbuf *image = gdk_pixbuf_new_from_file (file, NULL);
887 if (image) 651 if (image)
888 { 652 {
889 if (pixbuf) 653 if (pixbuf)
890 g_object_unref (pixbuf); 654 g_object_unref (pixbuf);
891 pixbuf = image; 655 pixbuf = image;
892 bg_flags |= BG_IS_FROM_FILE; 656 bg_flags |= BG_IS_FROM_FILE;
893 return true; 657 ret = true;
894 } 658 }
895# endif 659# endif
896 660
661 if (ret)
662 {
663 if (p)
664 bg_set_geometry (p + 1);
665 else
666 bg_set_default_geometry ();
667 }
668
897 return false; 669 return ret;
898} 670}
899 671
900# endif /* BG_IMAGE_FROM_FILE */ 672# endif /* BG_IMAGE_FROM_FILE */
901 673
902# ifdef ENABLE_TRANSPARENCY 674# ifdef ENABLE_TRANSPARENCY
938 { 710 {
939 changed = true; 711 changed = true;
940 v_blurRadius = vr; 712 v_blurRadius = vr;
941 } 713 }
942 714
943 if (v_blurRadius == 0 && h_blurRadius == 0) 715 if (h_blurRadius && v_blurRadius)
716 bg_flags |= BG_NEEDS_BLUR;
717 else
944 bg_flags &= ~BG_NEEDS_BLUR; 718 bg_flags &= ~BG_NEEDS_BLUR;
945 else
946 bg_flags |= BG_NEEDS_BLUR;
947 719
948 return changed; 720 return changed;
949} 721}
950 722
951void 723void
952rxvt_term::set_tint_shade_flags () 724rxvt_term::set_tint_shade_flags ()
953{ 725{
954 rgba c (rgba::MAX_CC,rgba::MAX_CC,rgba::MAX_CC); 726 if (shade != 100 || (bg_flags & BG_TINT_SET))
955 bool has_shade = shade != 100; 727 bg_flags |= BG_NEEDS_TINT;
728 else
729 bg_flags &= ~BG_NEEDS_TINT;
730}
956 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;
957 bg_flags &= ~BG_TINT_FLAGS; 738 bg_flags |= BG_TINT_SET;
958 739
959 if (bg_flags & BG_TINT_SET) 740 rgba c;
960 {
961 tint.get (c); 741 tint.get (c);
962 if (!has_shade
963 && (c.r <= 0x00ff || c.r >= 0xff00) 742 if ((c.r <= 0x00ff || c.r >= 0xff00)
964 && (c.g <= 0x00ff || c.g >= 0xff00) 743 && (c.g <= 0x00ff || c.g >= 0xff00)
965 && (c.b <= 0x00ff || c.b >= 0xff00)) 744 && (c.b <= 0x00ff || c.b >= 0xff00))
966 bg_flags |= BG_TINT_BITAND; 745 bg_flags |= BG_TINT_BITAND;
967 } 746 else
968
969 if (has_shade || (bg_flags & BG_TINT_SET))
970 bg_flags |= BG_NEEDS_TINT;
971}
972
973bool
974rxvt_term::bg_set_tint (rxvt_color &new_tint)
975{
976 if (!(bg_flags & BG_TINT_SET) || tint != new_tint)
977 {
978 tint = new_tint;
979 bg_flags |= BG_TINT_SET; 747 bg_flags &= ~BG_TINT_BITAND;
748
980 set_tint_shade_flags (); 749 set_tint_shade_flags ();
981 return true; 750 return true;
982 } 751 }
983 752
984 return false; 753 return false;
985} 754}
986 755
987bool 756bool
988rxvt_term::bg_set_shade (const char *shade_str) 757rxvt_term::bg_set_shade (const char *shade_str)
989{ 758{
990 int new_shade = (shade_str) ? atoi (shade_str) : 100; 759 int new_shade = atoi (shade_str);
991 760
992 clamp_it (new_shade, -100, 200); 761 clamp_it (new_shade, -100, 200);
993 if (new_shade < 0) 762 if (new_shade < 0)
994 new_shade = 200 - (100 + new_shade); 763 new_shade = 200 - (100 + new_shade);
995 764
1025 params[i+2] = XDoubleToFixed (kernel[i] / sum); 794 params[i+2] = XDoubleToFixed (kernel[i] / sum);
1026} 795}
1027#endif 796#endif
1028 797
1029bool 798bool
1030rxvt_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)
1031{ 800{
1032 bool ret = false; 801 bool ret = false;
1033#if XRENDER 802#if XRENDER
803 if (!(bg_flags & BG_HAS_RENDER_CONV))
804 return false;
805
1034 int size = max (h_blurRadius, v_blurRadius) * 2 + 1; 806 int size = max (h_blurRadius, v_blurRadius) * 2 + 1;
1035 double *kernel = (double *)malloc (size * sizeof (double)); 807 double *kernel = (double *)malloc (size * sizeof (double));
1036 XFixed *params = (XFixed *)malloc ((size + 2) * sizeof (XFixed)); 808 XFixed *params = (XFixed *)malloc ((size + 2) * sizeof (XFixed));
1037 809
1038 XRenderPictureAttributes pa; 810 XRenderPictureAttributes pa;
1039 XRenderPictFormat *format = XRenderFindVisualFormat (dpy, visual); 811 XRenderPictFormat *format = XRenderFindVisualFormat (dpy, visual);
1040 812
813 pa.repeat = RepeatPad;
1041 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);
1042 Picture dst = XRenderCreatePicture (dpy, pixmap, format, 0, &pa); 816 Picture dst = XRenderCreatePicture (dpy, tmp, format, CPRepeat, &pa);
817 XFreePixmap (dpy, tmp);
1043 818
1044 if (kernel && params) 819 if (kernel && params)
1045 { 820 {
1046 if (h_blurRadius)
1047 {
1048 size = h_blurRadius * 2 + 1; 821 size = h_blurRadius * 2 + 1;
1049 get_gaussian_kernel (h_blurRadius, size, kernel, params); 822 get_gaussian_kernel (h_blurRadius, size, kernel, params);
1050 823
1051 XRenderSetPictureFilter (dpy, src, FilterConvolution, params, size+2); 824 XRenderSetPictureFilter (dpy, src, FilterConvolution, params, size+2);
1052 XRenderComposite (dpy, 825 XRenderComposite (dpy,
1053 PictOpSrc, 826 PictOpSrc,
1054 src, 827 src,
1055 None, 828 None,
1056 dst, 829 dst,
1057 0, 0, 830 0, 0,
1058 0, 0, 831 0, 0,
1059 0, 0, 832 0, 0,
1060 width, height); 833 width, height);
1061 }
1062 834
1063 if (v_blurRadius) 835 ::swap (src, dst);
1064 { 836
1065 size = v_blurRadius * 2 + 1; 837 size = v_blurRadius * 2 + 1;
1066 get_gaussian_kernel (v_blurRadius, size, kernel, params); 838 get_gaussian_kernel (v_blurRadius, size, kernel, params);
1067 ::swap (params[0], params[1]); 839 ::swap (params[0], params[1]);
1068 840
1069 XRenderSetPictureFilter (dpy, src, FilterConvolution, params, size+2); 841 XRenderSetPictureFilter (dpy, src, FilterConvolution, params, size+2);
1070 XRenderComposite (dpy, 842 XRenderComposite (dpy,
1071 PictOpSrc, 843 PictOpSrc,
1072 src, 844 src,
1073 None, 845 None,
1074 dst, 846 dst,
1075 0, 0, 847 0, 0,
1076 0, 0, 848 0, 0,
1077 0, 0, 849 0, 0,
1078 width, height); 850 width, height);
1079 }
1080 851
1081 ret = true; 852 ret = true;
1082 } 853 }
1083 854
1084 free (kernel); 855 free (kernel);
1092bool 863bool
1093rxvt_term::tint_pixmap (Pixmap pixmap, Visual *visual, int width, int height) 864rxvt_term::tint_pixmap (Pixmap pixmap, Visual *visual, int width, int height)
1094{ 865{
1095 bool ret = false; 866 bool ret = false;
1096 867
1097 if (bg_flags & BG_TINT_BITAND) 868 if (shade == 100 && (bg_flags & BG_TINT_BITAND))
1098 { 869 {
1099 XGCValues gcv; 870 XGCValues gcv;
1100 GC gc; 871 GC gc;
1101 872
1102 /* In this case we can tint image server-side getting significant 873 /* In this case we can tint image server-side getting significant
1111 XFillRectangle (dpy, pixmap, gc, 0, 0, width, height); 882 XFillRectangle (dpy, pixmap, gc, 0, 0, width, height);
1112 ret = true; 883 ret = true;
1113 XFreeGC (dpy, gc); 884 XFreeGC (dpy, gc);
1114 } 885 }
1115 } 886 }
1116 else
1117 {
1118# if XRENDER 887# if XRENDER
888 else if (bg_flags & BG_HAS_RENDER)
889 {
1119 rgba c (rgba::MAX_CC, rgba::MAX_CC, rgba::MAX_CC); 890 rgba c (rgba::MAX_CC, rgba::MAX_CC, rgba::MAX_CC);
1120 891
1121 if (bg_flags & BG_TINT_SET) 892 if (bg_flags & BG_TINT_SET)
1122 tint.get (c); 893 tint.get (c);
1123 894
1132 c.r = c.r * (200 - shade) / 100; 903 c.r = c.r * (200 - shade) / 100;
1133 c.g = c.g * (200 - shade) / 100; 904 c.g = c.g * (200 - shade) / 100;
1134 c.b = c.b * (200 - shade) / 100; 905 c.b = c.b * (200 - shade) / 100;
1135 } 906 }
1136 907
1137 XRenderPictFormat *solid_format = XRenderFindStandardFormat (dpy, PictStandardARGB32);
1138 XRenderPictFormat *format = XRenderFindVisualFormat (dpy, visual); 908 XRenderPictFormat *format = XRenderFindVisualFormat (dpy, visual);
1139 XRenderPictureAttributes pa;
1140 909
1141 Picture back_pic = XRenderCreatePicture (dpy, pixmap, format, 0, &pa); 910 Picture back_pic = XRenderCreatePicture (dpy, pixmap, format, 0, 0);
1142 911
1143 pa.repeat = True; 912 Picture overlay_pic = create_xrender_mask (dpy, pixmap, True, False);
1144 913
1145 Pixmap overlay_pmap = XCreatePixmap (dpy, pixmap, 1, 1, 32); 914 Picture mask_pic = create_xrender_mask (dpy, pixmap, True, True);
1146 Picture overlay_pic = XRenderCreatePicture (dpy, overlay_pmap, solid_format, CPRepeat, &pa);
1147 XFreePixmap (dpy, overlay_pmap);
1148
1149 pa.component_alpha = True;
1150 Pixmap mask_pmap = XCreatePixmap (dpy, pixmap, 1, 1, 32);
1151 Picture mask_pic = XRenderCreatePicture (dpy, mask_pmap, solid_format, CPRepeat | CPComponentAlpha, &pa);
1152 XFreePixmap (dpy, mask_pmap);
1153 915
1154 XRenderColor mask_c; 916 XRenderColor mask_c;
1155 917
1156 mask_c.alpha = 0xffff; 918 mask_c.alpha = 0xffff;
1157 mask_c.red = 919 mask_c.red =
1162 mask_c.alpha = 0; 924 mask_c.alpha = 0;
1163 mask_c.red = 0xffff - c.r; 925 mask_c.red = 0xffff - c.r;
1164 mask_c.green = 0xffff - c.g; 926 mask_c.green = 0xffff - c.g;
1165 mask_c.blue = 0xffff - c.b; 927 mask_c.blue = 0xffff - c.b;
1166 XRenderFillRectangle (dpy, PictOpSrc, mask_pic, &mask_c, 0, 0, 1, 1); 928 XRenderFillRectangle (dpy, PictOpSrc, mask_pic, &mask_c, 0, 0, 1, 1);
929
1167 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);
1168 931
1169 if (shade > 100) 932 if (shade > 100)
1170 { 933 {
1171 mask_c.red = mask_c.green = mask_c.blue = 0xffff * (shade - 100) / 100;
1172 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;
1173 XRenderFillRectangle (dpy, PictOpSrc, overlay_pic, &mask_c, 0, 0, 1, 1); 938 XRenderFillRectangle (dpy, PictOpSrc, overlay_pic, &mask_c, 0, 0, 1, 1);
1174 939
1175 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);
1176 } 941 }
1177 942
1178 ret = true; 943 ret = true;
1179 944
1180 XRenderFreePicture (dpy, mask_pic); 945 XRenderFreePicture (dpy, mask_pic);
1181 XRenderFreePicture (dpy, overlay_pic); 946 XRenderFreePicture (dpy, overlay_pic);
1182 XRenderFreePicture (dpy, back_pic); 947 XRenderFreePicture (dpy, back_pic);
948 }
1183# endif 949# endif
1184 }
1185 950
1186 return ret; 951 return ret;
1187} 952}
1188 953
1189/* 954/*
1190 * 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
1191 * 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
1192 * our window. 957 * our window.
1193 */ 958 */
1194unsigned long 959bool
1195rxvt_term::make_transparency_pixmap () 960rxvt_term::make_transparency_pixmap ()
1196{ 961{
1197 unsigned long result = 0; 962 bool ret = false;
1198 963
1199 /* 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
1200 * be always up-to-date, so let's use it : 965 * be always up-to-date, so let's use it :
1201 */ 966 */
1202 int screen = display->screen; 967 int screen = display->screen;
1240#if XRENDER 1005#if XRENDER
1241 if (bg_flags & BG_HAS_RENDER) 1006 if (bg_flags & BG_HAS_RENDER)
1242 { 1007 {
1243 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);
1244 1009
1245 XRenderPictureAttributes pa;
1246
1247 XRenderPictFormat *src_format = XRenderFindVisualFormat (dpy, DefaultVisual (dpy, screen)); 1010 XRenderPictFormat *src_format = XRenderFindVisualFormat (dpy, DefaultVisual (dpy, screen));
1248 Picture src = XRenderCreatePicture (dpy, root_pixmap, src_format, 0, &pa); 1011 Picture src = XRenderCreatePicture (dpy, root_pixmap, src_format, 0, 0);
1249 1012
1250 XRenderPictFormat *dst_format = XRenderFindVisualFormat (dpy, visual); 1013 XRenderPictFormat *dst_format = XRenderFindVisualFormat (dpy, visual);
1251 Picture dst = XRenderCreatePicture (dpy, recoded_root_pmap, dst_format, 0, &pa); 1014 Picture dst = XRenderCreatePicture (dpy, recoded_root_pmap, dst_format, 0, 0);
1252 1015
1253 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);
1254 1017
1255 XRenderFreePicture (dpy, src); 1018 XRenderFreePicture (dpy, src);
1256 XRenderFreePicture (dpy, dst); 1019 XRenderFreePicture (dpy, dst);
1273 bg_pmap_width = window_width; 1036 bg_pmap_width = window_width;
1274 bg_pmap_height = window_height; 1037 bg_pmap_height = window_height;
1275 } 1038 }
1276 1039
1277 /* straightforward pixmap copy */ 1040 /* straightforward pixmap copy */
1278 while (sx < 0) sx += root_width; 1041 while (sx < 0) sx += root_pmap_width;
1279 while (sy < 0) sy += root_height; 1042 while (sy < 0) sy += root_pmap_height;
1280 1043
1281 gcv.tile = recoded_root_pmap; 1044 gcv.tile = recoded_root_pmap;
1282 gcv.fill_style = FillTiled; 1045 gcv.fill_style = FillTiled;
1283 gcv.ts_x_origin = -sx; 1046 gcv.ts_x_origin = -sx;
1284 gcv.ts_y_origin = -sy; 1047 gcv.ts_y_origin = -sy;
1285 gc = XCreateGC (dpy, vt, GCFillStyle | GCTile | GCTileStipXOrigin | GCTileStipYOrigin, &gcv); 1048 gc = XCreateGC (dpy, vt, GCFillStyle | GCTile | GCTileStipXOrigin | GCTileStipYOrigin, &gcv);
1286 1049
1287 if (gc) 1050 if (gc)
1288 { 1051 {
1289 XFillRectangle (dpy, bg_pixmap, gc, 0, 0, window_width, window_height); 1052 XFillRectangle (dpy, bg_pixmap, gc, 0, 0, window_width, window_height);
1290 result |= BG_IS_VALID | (bg_flags & BG_EFFECTS_FLAGS); 1053 ret = true;
1291 XFreeGC (dpy, gc); 1054 unsigned long tr_flags = bg_flags & BG_EFFECTS_FLAGS;
1292 1055
1293 if (!(bg_flags & BG_CLIENT_RENDER)) 1056 if (!(bg_flags & BG_CLIENT_RENDER))
1294 { 1057 {
1295 if ((bg_flags & BG_NEEDS_BLUR) 1058 if (bg_flags & BG_NEEDS_BLUR)
1296 && (bg_flags & BG_HAS_RENDER_CONV))
1297 { 1059 {
1298 if (blur_pixmap (bg_pixmap, visual, window_width, window_height)) 1060 if (blur_pixmap (bg_pixmap, visual, window_width, window_height, depth))
1299 result &= ~BG_NEEDS_BLUR; 1061 tr_flags &= ~BG_NEEDS_BLUR;
1300 } 1062 }
1301 if ((bg_flags & BG_NEEDS_TINT) 1063 if (bg_flags & BG_NEEDS_TINT)
1302 && (bg_flags & (BG_TINT_BITAND | BG_HAS_RENDER)))
1303 { 1064 {
1304 if (tint_pixmap (bg_pixmap, visual, window_width, window_height)) 1065 if (tint_pixmap (bg_pixmap, visual, window_width, window_height))
1305 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 }
1306 } 1079 }
1307 } /* server side rendering completed */ 1080 } /* server side rendering completed */
1081
1082 XFreeGC (dpy, gc);
1308 } 1083 }
1309 1084
1310 if (recoded_root_pmap != root_pixmap) 1085 if (recoded_root_pmap != root_pixmap)
1311 XFreePixmap (dpy, recoded_root_pmap); 1086 XFreePixmap (dpy, recoded_root_pmap);
1312 1087
1313 return result; 1088 return ret;
1314} 1089}
1315 1090
1316void 1091void
1317rxvt_term::bg_set_root_pixmap () 1092rxvt_term::bg_set_root_pixmap ()
1318{ 1093{
1322 1097
1323 root_pixmap = new_root_pixmap; 1098 root_pixmap = new_root_pixmap;
1324} 1099}
1325# endif /* ENABLE_TRANSPARENCY */ 1100# endif /* ENABLE_TRANSPARENCY */
1326 1101
1327#if defined(ENABLE_TRANSPARENCY) && !defined(HAVE_AFTERIMAGE)
1328static void shade_ximage (Visual *visual, XImage *ximage, int shade, const rgba &c);
1329# endif
1330
1331bool 1102bool
1332rxvt_term::bg_render () 1103rxvt_term::bg_render ()
1333{ 1104{
1334 unsigned long tr_flags = 0; 1105 bool transparent = false;
1335 1106
1336 bg_invalidate (); 1107 bg_invalidate ();
1337# ifdef ENABLE_TRANSPARENCY 1108# ifdef ENABLE_TRANSPARENCY
1338 if (bg_flags & BG_IS_TRANSPARENT) 1109 if (bg_flags & BG_IS_TRANSPARENT)
1339 { 1110 {
1340 /* we need to re-generate transparency pixmap in that case ! */ 1111 /* we need to re-generate transparency pixmap in that case ! */
1341 tr_flags = make_transparency_pixmap (); 1112 transparent = make_transparency_pixmap ();
1342 if (tr_flags == 0) 1113 if (transparent)
1343 return false;
1344 else if (!(tr_flags & BG_EFFECTS_FLAGS))
1345 bg_flags |= BG_IS_VALID; 1114 bg_flags |= BG_IS_VALID;
1346 } 1115 }
1347# endif 1116# endif
1348 1117
1349# ifdef BG_IMAGE_FROM_FILE 1118# ifdef BG_IMAGE_FROM_FILE
1350 if ((bg_flags & BG_IS_FROM_FILE) 1119 if (bg_flags & BG_IS_FROM_FILE)
1351 || (tr_flags & BG_EFFECTS_FLAGS))
1352 { 1120 {
1353 if (render_image (tr_flags)) 1121 if (render_image (transparent))
1354 bg_flags |= BG_IS_VALID; 1122 bg_flags |= BG_IS_VALID;
1355 }
1356# endif
1357
1358# if defined(ENABLE_TRANSPARENCY) && !defined(HAVE_AFTERIMAGE)
1359 XImage *result = NULL;
1360
1361 if (tr_flags && !(bg_flags & BG_IS_VALID))
1362 {
1363 result = XGetImage (dpy, bg_pixmap, 0, 0, bg_pmap_width, bg_pmap_height, AllPlanes, ZPixmap);
1364 }
1365
1366 if (result)
1367 {
1368 /* our own client-side tinting */
1369 if (tr_flags & BG_NEEDS_TINT)
1370 {
1371 rgba c (rgba::MAX_CC,rgba::MAX_CC,rgba::MAX_CC);
1372 if (bg_flags & BG_TINT_SET)
1373 tint.get (c);
1374 shade_ximage (DefaultVisual (dpy, display->screen), result, shade, c);
1375 }
1376
1377 GC gc = XCreateGC (dpy, vt, 0UL, NULL);
1378
1379 if (gc)
1380 {
1381 XPutImage (dpy, bg_pixmap, gc, result, 0, 0, 0, 0, result->width, result->height);
1382
1383 XFreeGC (dpy, gc);
1384 bg_flags |= BG_IS_VALID;
1385 }
1386
1387 XDestroyImage (result);
1388 } 1123 }
1389# endif 1124# endif
1390 1125
1391 if (!(bg_flags & BG_IS_VALID)) 1126 if (!(bg_flags & BG_IS_VALID))
1392 { 1127 {
1429#endif 1164#endif
1430} 1165}
1431 1166
1432#endif /* HAVE_BG_PIXMAP */ 1167#endif /* HAVE_BG_PIXMAP */
1433 1168
1434#if defined(ENABLE_TRANSPARENCY) && !defined(HAVE_AFTERIMAGE) 1169#ifdef ENABLE_TRANSPARENCY
1435/* taken from aterm-0.4.2 */ 1170/* based on code from aterm-0.4.2 */
1436 1171
1437static void 1172static inline void
1438shade_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)
1439{ 1186{
1440 int sh_r, sh_g, sh_b; 1187 int sh_r, sh_g, sh_b;
1441 uint32_t mask_r, mask_g, mask_b; 1188 uint32_t mask_r, mask_g, mask_b;
1442 uint32_t *lookup, *lookup_r, *lookup_g, *lookup_b; 1189 uint32_t *lookup, *lookup_r, *lookup_g, *lookup_b;
1443 rgba low; 1190 unsigned short low;
1444 rgba high;
1445 int i;
1446 int host_byte_order = ecb_big_endian () ? MSBFirst : LSBFirst; 1191 int host_byte_order = ecb_big_endian () ? MSBFirst : LSBFirst;
1447 1192
1448 if (visual->c_class != TrueColor || ximage->format != ZPixmap) return; 1193 if (visual->c_class != TrueColor || ximage->format != ZPixmap) return;
1449 1194
1450 /* for convenience */ 1195 /* for convenience */
1509 break; 1254 break;
1510 default: 1255 default:
1511 return; /* we do not support this color depth */ 1256 return; /* we do not support this color depth */
1512 } 1257 }
1513 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
1514 /* prepare limits for color transformation (each channel is handled separately) */ 1264 /* prepare limits for color transformation (each channel is handled separately) */
1515 if (shade > 100) 1265 if (shade > 100)
1516 { 1266 {
1517 shade = 200 - shade;
1518
1519 high.r = c.r * shade / 100;
1520 high.g = c.g * shade / 100;
1521 high.b = c.b * shade / 100;
1522
1523 low.r = 65535 * (100 - shade) / 100; 1267 c.r = c.r * (200 - shade) / 100;
1524 low.g = 65535 * (100 - shade) / 100; 1268 c.g = c.g * (200 - shade) / 100;
1525 low.b = 65535 * (100 - shade) / 100; 1269 c.b = c.b * (200 - shade) / 100;
1270
1271 low = 0xffff * (shade - 100) / 100;
1526 } 1272 }
1527 else 1273 else
1528 { 1274 {
1529 high.r = c.r * shade / 100; 1275 c.r = c.r * shade / 100;
1530 high.g = c.g * shade / 100; 1276 c.g = c.g * shade / 100;
1531 high.b = c.b * shade / 100; 1277 c.b = c.b * shade / 100;
1532 1278
1533 low.r = low.g = low.b = 0; 1279 low = 0;
1534 } 1280 }
1535 1281
1536 /* fill our lookup tables */ 1282 /* fill our lookup tables */
1537 for (i = 0; i <= mask_r>>sh_r; i++) 1283 fill_lut (lookup_r, mask_r, sh_r, low, c.r);
1538 { 1284 fill_lut (lookup_g, mask_g, sh_g, low, c.g);
1539 uint32_t tmp; 1285 fill_lut (lookup_b, mask_b, sh_b, low, c.b);
1540 tmp = i * high.r;
1541 tmp += (mask_r>>sh_r) * low.r;
1542 lookup_r[i] = (tmp/65535)<<sh_r;
1543 }
1544 for (i = 0; i <= mask_g>>sh_g; i++)
1545 {
1546 uint32_t tmp;
1547 tmp = i * high.g;
1548 tmp += (mask_g>>sh_g) * low.g;
1549 lookup_g[i] = (tmp/65535)<<sh_g;
1550 }
1551 for (i = 0; i <= mask_b>>sh_b; i++)
1552 {
1553 uint32_t tmp;
1554 tmp = i * high.b;
1555 tmp += (mask_b>>sh_b) * low.b;
1556 lookup_b[i] = (tmp/65535)<<sh_b;
1557 }
1558 1286
1559 /* apply table to input image (replacing colors by newly calculated ones) */ 1287 /* apply table to input image (replacing colors by newly calculated ones) */
1560 if (ximage->bits_per_pixel == 32 1288 if (ximage->bits_per_pixel == 32
1561 && (ximage->depth == 24 || ximage->depth == 32) 1289 && (ximage->depth == 24 || ximage->depth == 32)
1562 && ximage->byte_order == host_byte_order) 1290 && ximage->byte_order == host_byte_order)
1563 { 1291 {
1564 uint32_t *p1, *pf, *p, *pl; 1292 char *line = ximage->data;
1565 p1 = (uint32_t *) ximage->data;
1566 pf = (uint32_t *) (ximage->data + ximage->height * ximage->bytes_per_line);
1567 1293
1568 while (p1 < pf) 1294 for (int y = 0; y < ximage->height; y++)
1569 { 1295 {
1570 p = p1; 1296 uint32_t *p = (uint32_t *)line;
1571 pl = p1 + ximage->width; 1297 for (int x = 0; x < ximage->width; x++)
1572 for (; p < pl; p++)
1573 { 1298 {
1574 *p = lookup_r[(*p & 0xff0000) >> 16] | 1299 *p = lookup_r[(*p & 0xff0000) >> 16] |
1575 lookup_g[(*p & 0x00ff00) >> 8] | 1300 lookup_g[(*p & 0x00ff00) >> 8] |
1576 lookup_b[(*p & 0x0000ff)] | 1301 lookup_b[(*p & 0x0000ff)] |
1577 (*p & 0xff000000); 1302 (*p & 0xff000000);
1578 } 1303 p++;
1579 p1 = (uint32_t *) ((char *) p1 + ximage->bytes_per_line); 1304 }
1305 line += ximage->bytes_per_line;
1580 } 1306 }
1581 } 1307 }
1582 else 1308 else
1583 { 1309 {
1584 for (int y = 0; y < ximage->height; y++) 1310 for (int y = 0; y < ximage->height; y++)
1592 } 1318 }
1593 } 1319 }
1594 1320
1595 free (lookup); 1321 free (lookup);
1596} 1322}
1597#endif /* defined(ENABLE_TRANSPARENCY) && !defined(HAVE_AFTERIMAGE) */ 1323#endif /* ENABLE_TRANSPARENCY */

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines