ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/xpm.C
Revision: 1.59
Committed: Sun Aug 5 06:19:01 2007 UTC (16 years, 9 months ago) by sasha
Content type: text/plain
Branch: MAIN
Changes since 1.58: +56 -0 lines
Log Message:
started implementing proper image resizing functionality with align and stuff

File Contents

# User Rev Content
1 root 1.34 /*----------------------------------------------------------------------*
2 pcg 1.12 * File: xpm.C
3 pcg 1.1 *----------------------------------------------------------------------*
4     *
5     * All portions of code are copyright by their respective author/s.
6     * Copyright (c) 1997 Carsten Haitzler <raster@zip.com.au>
7     * Copyright (c) 1997,1998 Oezguer Kesim <kesim@math.fu-berlin.de>
8     * Copyright (c) 1998-2001 Geoff Wing <gcw@pobox.com>
9 root 1.33 * Copyright (c) 2005-2006 Marc Lehmann <pcg@goof.com>
10 pcg 1.1 *
11     * This program is free software; you can redistribute it and/or modify
12     * it under the terms of the GNU General Public License as published by
13     * the Free Software Foundation; either version 2 of the License, or
14     * (at your option) any later version.
15     *
16     * This program is distributed in the hope that it will be useful,
17     * but WITHOUT ANY WARRANTY; without even the implied warranty of
18     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19     * GNU General Public License for more details.
20     *
21     * You should have received a copy of the GNU General Public License
22     * along with this program; if not, write to the Free Software
23     * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24     *---------------------------------------------------------------------*/
25    
26     #include "../config.h" /* NECESSARY */
27     #include "rxvt.h" /* NECESSARY */
28    
29     /*
30 sasha 1.56 * Pixmap geometry string interpretation :
31     * Each geometry string contains zero or one scale/position
32     * adjustment and may optionally be followed by a colon and one or more
33     * colon-delimited pixmap operations.
34     * The following table shows the valid geometry strings and their
35     * affects on the background image :
36     *
37     * WxH+X+Y Set scaling to W% by H%, and position to X% by Y%.
38     * W and H are percentages of the terminal window size.
39     * X and Y are also percentages; e.g., +50+50 centers
40     * the image in the window.
41     * WxH+X Assumes Y == X
42     * WxH Assumes Y == X == 50 (centers the image)
43     * W+X+Y Assumes H == W
44     * W+X Assumes H == W and Y == X
45     * W Assumes H == W and Y == X == 50
46 pcg 1.1 *
47 sasha 1.56 * Adjusting position only :
48     * =+X+Y Set position to X% by Y% (absolute).
49     * =+X Set position to X% by X%.
50     * +X+Y Adjust position horizontally X% and vertically Y%
51     * from current position (relative).
52 sasha 1.58 * +X Adjust position horizontally X% and vertically X%
53 sasha 1.56 * from current position.
54 pcg 1.1 *
55 sasha 1.56 * Adjusting scale only :
56     * Wx0 Multiply horizontal scaling factor by W%
57     * 0xH Multiply vertical scaling factor by H%
58     * 0x0 No scaling (show image at normal size).
59     *
60     * Pixmap Operations : (should be prepended by a colon)
61     * tile Tile image. Scaling/position modifiers above will affect
62     * the tile size and origin.
63     * propscale When scaling, scale proportionally. That is, maintain the
64     * proper aspect ratio for the image. Any portion of the
65     * background not covered by the image is filled with the
66     * current background color.
67     * hscale Scale horizontally, tile vertically ?
68     * vscale Tile horizontally, scale vertically ?
69     * scale Scale both up and down
70     * auto Same as 100x100+50+50
71 pcg 1.1 */
72 sasha 1.56
73     #ifdef HAVE_BG_PIXMAP
74     bool
75     bgPixmap_t::window_size_sensitive ()
76     {
77 sasha 1.58 #ifdef XPM_BACKGROUND
78     #ifdef HAVE_AFTERIMAGE
79     if (original_asim != NULL)
80     #endif
81     {
82     if (h_scale != 0 || v_scale != 0)
83     return true;
84     }
85     #endif
86     #ifdef ENABLE_TRANSPARENCY
87     if (flags & bgPmap_Transparent)
88     return true;
89     #endif
90     return false;
91 sasha 1.56 }
92    
93     #ifdef XPM_BACKGROUND
94 sasha 1.58 static inline bool
95     check_set_scale_value (int geom_flags, int flag, unsigned int &scale, unsigned int new_value)
96     {
97     if (geom_flags & flag)
98     {
99     if (new_value > 1000)
100     new_value = 1000;
101     if (new_value != scale)
102     {
103     scale = new_value;
104     return true;
105     }
106     }
107     return false;
108     }
109    
110     static inline bool
111     check_set_align_value (int geom_flags, int flag, int &align, int new_value)
112     {
113     if (geom_flags & flag)
114     {
115     if (new_value < -100)
116     new_value = -100;
117     else if (new_value > 200)
118     new_value = 200;
119     if (new_value != align)
120     {
121     align = new_value;
122     return true;
123     }
124     }
125     return false;
126     }
127    
128 sasha 1.59 static inline int
129     make_align_position (int align, int window_size, int image_size)
130     {
131     int diff = window_size - image_size;
132     int smaller = MIN (image_size,window_size);
133    
134     if (align >= 0 && align <= 50)
135     return diff * align / 100;
136     else if (align > 50 && align <= 100)
137     return window_size - image_size + diff * align / 100;
138     else if (align > 100 && align <= 200 )
139     return ((align - 100) * smaller / 100) + window_size - smaller;
140     else if (align > -100 && align < 0)
141     return ((align + 100) * smaller / 100) - image_size;
142     return 0;
143     }
144    
145     static inline void
146     make_clip_rectangle (int pos, int size, int target_size, short &clip_pos, unsigned short &clip_size)
147     {
148     if (pos < 0)
149     {
150     clip_pos = 0;
151     clip_size = MIN (target_size, size + pos);
152     }
153     else
154     {
155     clip_pos = pos;
156     clip_size = size;
157     if (pos < target_size && (int)clip_size > target_size - pos)
158     clip_pos = target_size - pos;
159     }
160     }
161    
162 sasha 1.56 bool
163     bgPixmap_t::handle_geometry (const char *geom)
164 pcg 1.1 {
165 sasha 1.58 int geom_flags = 0, changed = 0;
166 root 1.28 int x = 0, y = 0;
167     unsigned int w = 0, h = 0;
168     unsigned int n;
169 sasha 1.58 unsigned long new_flags = (flags&(~bgPmap_geometryFlags));
170 root 1.28 char *p;
171 sasha 1.58 #define MAXLEN_GEOM 256 /* could be longer then regular geometry string */
172 pcg 1.1
173 pcg 1.7 if (geom == NULL)
174 sasha 1.56 return false;
175 root 1.28
176     char str[MAXLEN_GEOM];
177    
178 root 1.17 if (!strcmp (geom, "?"))
179 pcg 1.7 {
180 sasha 1.56 #if 0 /* TODO: */
181 pcg 1.9 sprintf (str, "[%dx%d+%d+%d]", /* can't presume snprintf () ! */
182 sasha 1.56 min (h_scale, 32767), min (v_scale, 32767),
183     min (h_align, 32767), min (v_align, 32767));
184 pcg 1.11 process_xterm_seq (XTerm_title, str, CHAR_ST);
185 sasha 1.56 #endif
186     return false;
187 pcg 1.1 }
188 sasha 1.58 while (isspace(*geom)) ++geom;
189 root 1.17 if ((p = strchr (geom, ';')) == NULL)
190     p = strchr (geom, '\0');
191 root 1.28
192 pcg 1.7 n = (p - geom);
193 root 1.35 if (n < MAXLEN_GEOM)
194 pcg 1.7 {
195 sasha 1.58 char *ops;
196 sasha 1.56 new_flags |= bgPmap_geometrySet;
197    
198 root 1.17 strncpy (str, geom, n);
199 pcg 1.7 str[n] = '\0';
200 sasha 1.58 if (str[0] == ':')
201     ops = &str[0];
202     else if (str[0] != 'x' && str[0] != 'X' && isalpha(str[0]))
203     ops = &str[0];
204 sasha 1.38 else
205     {
206 sasha 1.58 char *tmp;
207     ops = strchr (str, ':');
208     if (ops != NULL)
209     {
210     for (tmp = ops-1; tmp >= str && isspace(*tmp); --tmp);
211     *(++tmp) = '\0';
212     if (ops == tmp) ++ops;
213     }
214 sasha 1.38 }
215 root 1.28
216 sasha 1.58 if (ops > str || ops == NULL)
217 pcg 1.7 {
218 sasha 1.58 /* we have geometry string - let's handle it prior to applying ops */
219     geom_flags = XParseGeometry (str, &x, &y, &w, &h);
220 root 1.28
221 sasha 1.58 if ((geom_flags & XValue) && !(geom_flags & YValue))
222 pcg 1.7 {
223 sasha 1.58 y = x;
224     geom_flags |= YValue;
225 pcg 1.7 }
226 sasha 1.58
227     if (flags & bgPmap_geometrySet)
228     {/* new geometry is an adjustment to the old one ! */
229     if ((geom_flags & WidthValue) && (geom_flags & HeightValue))
230     {
231     if (w == 0 && h != 0)
232     {
233     w = h_scale;
234     h = (v_scale * h) / 100;
235     }
236     else if (h == 0 && w != 0)
237     {
238     w = (h_scale * w) / 100;
239     h = v_scale;
240     }
241     }
242     if (geom_flags & XValue)
243     {
244     if (str[0] != '=')
245     {
246     y += v_align;
247     x += h_align;
248     }
249     }
250 pcg 1.7 }
251 sasha 1.58 else /* setting up geometry from scratch */
252 pcg 1.7 {
253 sasha 1.58 if (!(geom_flags & XValue))
254     {/* use default geometry - centered */
255     x = y = bgPmap_defaultAlign;
256     }
257     else if (!(geom_flags & YValue))
258     y = x;
259 root 1.28
260 sasha 1.58 if ((geom_flags & (WidthValue|HeightValue)) == 0)
261     {/* use default geometry - scaled */
262     w = h = bgPmap_defaultScale;
263     }
264     else if (geom_flags & WidthValue)
265     {
266     if (!(geom_flags & HeightValue))
267     h = w;
268     }
269     else
270     w = h;
271 pcg 1.7 }
272 sasha 1.58 } /* done parsing geometry string */
273     else if (!(flags & bgPmap_geometrySet))
274     { /* default geometry - scaled and centered */
275     x = y = bgPmap_defaultAlign;
276     w = h = bgPmap_defaultScale;
277     }
278    
279     if (!(flags & bgPmap_geometrySet))
280     geom_flags |= WidthValue|HeightValue|XValue|YValue;
281 root 1.28
282 sasha 1.58 if (ops)
283 pcg 1.7 {
284 sasha 1.58 while (*ops)
285     {
286     while (*ops == ':' || isspace(*ops)) ++ops;
287     #define CHECK_GEOM_OPS(op_str) (strncasecmp (ops, (op_str), sizeof(op_str)-1) == 0)
288     if (CHECK_GEOM_OPS("tile"))
289     {
290     w = h = 0;
291     geom_flags |= WidthValue|HeightValue;
292     }
293     else if (CHECK_GEOM_OPS("propscale"))
294     {
295     if (w == 0 && h == 0)
296     {
297     w = 100;
298     geom_flags |= WidthValue;
299     }
300     new_flags |= bgPmap_propScale;
301     }
302     else if (CHECK_GEOM_OPS("hscale"))
303     {
304     if (w == 0)
305     w = 100;
306     h = 0;
307     geom_flags |= WidthValue|HeightValue;
308     }
309     else if (CHECK_GEOM_OPS("vscale"))
310     {
311     if (h == 0)
312     h = 100;
313     w = 0;
314     geom_flags |= WidthValue|HeightValue;
315     }
316     else if (CHECK_GEOM_OPS("scale"))
317     {
318     if (h == 0)
319     h = 100;
320     if (w == 0)
321     w = 100;
322     geom_flags |= WidthValue|HeightValue;
323     }
324     else if (CHECK_GEOM_OPS("auto"))
325     {
326     w = h = 100;
327     x = y = 50;
328     geom_flags |= WidthValue|HeightValue|XValue|YValue;
329     }
330     #undef CHECK_GEOM_OPS
331     while (*ops != ':' && *ops != '\0') ++ops;
332     } /* done parsing ops */
333 pcg 1.7 }
334 sasha 1.56
335 sasha 1.58 if (check_set_scale_value (geom_flags, WidthValue, h_scale, w))
336     ++changed;
337     if (check_set_scale_value (geom_flags, HeightValue, v_scale, h))
338     ++changed;
339     if (check_set_align_value (geom_flags, XValue, h_align, x))
340     ++changed;
341     if (check_set_align_value (geom_flags, YValue, v_align, y))
342     ++changed;
343 pcg 1.1 }
344 root 1.28
345 sasha 1.56 if (new_flags != flags)
346     {
347     flags = new_flags;
348     changed++;
349     }
350 sasha 1.58 //fprintf( stderr, "flags = %lX, scale = %ux%u, align=%+d%+d\n",
351     // flags, h_scale, v_scale, h_align, v_align);
352 sasha 1.56 return (changed > 0);
353 pcg 1.1 }
354    
355 sasha 1.59 #ifdef HAVE_AFTERIMAGE
356     ASImage *
357     bgPixmap_t::resize_asim (rxvt_term *target, ASImage *background, XRectangle &dst_rect)
358     {
359     if (original_asim == NULL || target == NULL)
360     return NULL;
361    
362     int target_width = (int)target->szHint.width;
363     int target_height = (int)target->szHint.height;
364     int w = h_scale * target_width / 100;
365     int h = v_scale * target_height / 100;
366     int x = make_align_position (h_align, target_width, w);
367     int y = make_align_position (v_align, target_height, h);
368    
369     make_clip_rectangle (x, w, target_width, dst_rect.x, dst_rect.width);
370     make_clip_rectangle (y, h, target_height, dst_rect.y, dst_rect.height);
371    
372     /* TODO : actuall scaling code :) */
373    
374     }
375     #endif
376    
377 pcg 1.1 void
378 pcg 1.5 rxvt_term::resize_pixmap ()
379 pcg 1.1 {
380 root 1.27 XGCValues gcvalue;
381     GC gc;
382 sasha 1.56 unsigned int w = bgPixmap.h_scale*szHint.width/100;
383     unsigned int h = bgPixmap.v_scale*szHint.height/100;
384     int x = bgPixmap.h_align*szHint.width/100;
385     int y = bgPixmap.v_align*szHint.height/100;
386     #ifdef HAVE_AFTERIMAGE
387 sasha 1.55 ASImage *im = bgPixmap.original_asim;
388 sasha 1.56 #else
389     void *im = NULL;
390     #endif
391 sasha 1.55 /* preliminary cleanup - this needs to be integrated with check_our_parents() code */
392     if (bgPixmap.pixmap != None)
393 sasha 1.38 {
394 sasha 1.55 XFreePixmap (dpy, bgPixmap.pixmap);
395     bgPixmap.pixmap = None ;
396 sasha 1.38 }
397 root 1.41 #ifdef ENABLE_TRANSPARENCY
398 sasha 1.55 if (option(Opt_transparent) && am_transparent)
399     {
400     /* we need to re-generate transparency pixmap in that case ! */
401     check_our_parents ();
402     return;
403     }
404 ayin 1.36 #endif
405 root 1.20
406 sasha 1.56 if (im == NULL)
407 sasha 1.55 { /* So be it: I'm not using pixmaps */
408     XSetWindowBackground (dpy, vt, pix_colors[Color_bg]);
409 pcg 1.7 return;
410 pcg 1.1 }
411    
412 root 1.17 gcvalue.foreground = pix_colors[Color_bg];
413 root 1.31 gc = XCreateGC (dpy, vt, GCForeground, &gcvalue);
414 pcg 1.1
415 sasha 1.56 /* don't zoom pixmap too much nor expand really small pixmaps */
416     if (w > 16000)
417     w = 1;
418     if (h > 16000)
419     h = 1;
420    
421     #ifdef HAVE_AFTERIMAGE
422     if (w == 0)
423     w = im->width;
424     if (h == 0)
425     h = im->height;
426 pcg 1.7
427 sasha 1.55 if (w != im->width || h != im->height)
428     {
429     ASImage *tmp = scale_asimage (asv, im, w, h, (x == 0 && y == 0)?ASA_XImage:ASA_ASImage, 0, ASIMAGE_QUALITY_DEFAULT);
430     if (tmp != NULL)
431     im = tmp;
432     }
433 sasha 1.56 bgPixmap.pmap_width = MIN(w,szHint.width);
434     bgPixmap.pmap_height = MIN(h,szHint.height);
435     #if 0 /* TODO: fix that! */
436 sasha 1.55 if (x != 0 || y != 0)
437     {
438     ASImage *tmp = tile_asimage (asv, im, x, y, w, h, TINT_LEAVE_SAME, ASA_XImage, 0, ASIMAGE_QUALITY_DEFAULT);
439     if (tmp != NULL)
440 sasha 1.38 {
441 sasha 1.55 if (im != bgPixmap.original_asim)
442     destroy_asimage (&im);
443     im = tmp;
444 sasha 1.38 }
445 pcg 1.1 }
446 sasha 1.56 #endif
447     bgPixmap.pixmap = XCreatePixmap (dpy, vt, bgPixmap.pmap_width, bgPixmap.pmap_height, depth);
448 sasha 1.55 bgPixmap.pmap_depth = depth;
449    
450 sasha 1.56 asimage2drawable (asv, bgPixmap.pixmap, im, gc, 0, 0, 0, 0, bgPixmap.pmap_width, bgPixmap.pmap_height, True);
451 root 1.14
452 sasha 1.55 if (im != bgPixmap.original_asim)
453     destroy_asimage (&im);
454 sasha 1.56 #endif
455     if( bgPixmap.pixmap )
456     XSetWindowBackgroundPixmap (dpy, vt, bgPixmap.pixmap);
457 root 1.28
458 root 1.31 XFreeGC (dpy, gc);
459 pcg 1.1 }
460    
461 sasha 1.55 void
462 pcg 1.5 rxvt_term::set_bgPixmap (const char *file)
463 pcg 1.1 {
464 root 1.21 char *f;
465 pcg 1.1
466 pcg 1.9 assert (file != NULL);
467 pcg 1.1
468 pcg 1.7 if (bgPixmap.pixmap != None)
469     {
470 root 1.31 XFreePixmap (dpy, bgPixmap.pixmap);
471 pcg 1.7 bgPixmap.pixmap = None;
472 pcg 1.1 }
473 root 1.19
474 root 1.31 XSetWindowBackground (dpy, vt, pix_colors[Color_bg]);
475 pcg 1.7 if (*file != '\0')
476     {
477 sasha 1.56 #ifdef HAVE_AFTERIMAGE
478 ayin 1.51 if (asimman == NULL)
479     asimman = create_generic_imageman(rs[Rs_path]);
480 sasha 1.38 if ((f = strchr (file, ';')) == NULL)
481 sasha 1.55 bgPixmap.original_asim = get_asimage( asimman, file, 0xFFFFFFFF, 100 );
482 sasha 1.38 else
483     {
484 ayin 1.42 size_t len = f - file;
485     f = (char *)malloc (len + 1);
486     strncpy (f, file, len);
487     f[len] = '\0';
488 sasha 1.55 bgPixmap.original_asim = get_asimage( asimman, f, 0xFFFFFFFF, 100 );
489 sasha 1.38 free( f );
490     }
491 sasha 1.56 #endif
492 pcg 1.1 }
493 pcg 1.10
494 pcg 1.7 resize_pixmap ();
495 pcg 1.1 }
496    
497     #endif /* XPM_BACKGROUND */
498 sasha 1.56 #endif /* HAVE_BG_PIXMAP */
499 ayin 1.39
500 root 1.41 #ifdef ENABLE_TRANSPARENCY
501 ayin 1.57 #ifndef HAVE_AFTERIMAGE
502 ayin 1.39 /* taken from aterm-0.4.2 */
503    
504     typedef uint32_t RUINT32T;
505    
506 ayin 1.43 static void
507     ShadeXImage(rxvt_term *term, XImage* srcImage, int shade, int rm, int gm, int bm)
508 ayin 1.39 {
509     int sh_r, sh_g, sh_b;
510     RUINT32T mask_r, mask_g, mask_b;
511     RUINT32T *lookup, *lookup_r, *lookup_g, *lookup_b;
512     unsigned int lower_lim_r, lower_lim_g, lower_lim_b;
513     unsigned int upper_lim_r, upper_lim_g, upper_lim_b;
514     int i;
515    
516     Visual *visual = term->visual;
517    
518     if( visual->c_class != TrueColor || srcImage->format != ZPixmap ) return ;
519    
520     /* for convenience */
521     mask_r = visual->red_mask;
522     mask_g = visual->green_mask;
523     mask_b = visual->blue_mask;
524    
525     /* boring lookup table pre-initialization */
526     switch (srcImage->bits_per_pixel) {
527     case 15:
528     if ((mask_r != 0x7c00) ||
529     (mask_g != 0x03e0) ||
530     (mask_b != 0x001f))
531     return;
532     lookup = (RUINT32T *) malloc (sizeof (RUINT32T)*(32+32+32));
533     lookup_r = lookup;
534     lookup_g = lookup+32;
535     lookup_b = lookup+32+32;
536     sh_r = 10;
537     sh_g = 5;
538     sh_b = 0;
539     break;
540     case 16:
541     if ((mask_r != 0xf800) ||
542     (mask_g != 0x07e0) ||
543     (mask_b != 0x001f))
544     return;
545     lookup = (RUINT32T *) malloc (sizeof (RUINT32T)*(32+64+32));
546     lookup_r = lookup;
547     lookup_g = lookup+32;
548     lookup_b = lookup+32+64;
549     sh_r = 11;
550     sh_g = 5;
551     sh_b = 0;
552     break;
553     case 24:
554     if ((mask_r != 0xff0000) ||
555     (mask_g != 0x00ff00) ||
556     (mask_b != 0x0000ff))
557     return;
558     lookup = (RUINT32T *) malloc (sizeof (RUINT32T)*(256+256+256));
559     lookup_r = lookup;
560     lookup_g = lookup+256;
561     lookup_b = lookup+256+256;
562     sh_r = 16;
563     sh_g = 8;
564     sh_b = 0;
565     break;
566     case 32:
567     if ((mask_r != 0xff0000) ||
568     (mask_g != 0x00ff00) ||
569     (mask_b != 0x0000ff))
570     return;
571     lookup = (RUINT32T *) malloc (sizeof (RUINT32T)*(256+256+256));
572     lookup_r = lookup;
573     lookup_g = lookup+256;
574     lookup_b = lookup+256+256;
575     sh_r = 16;
576     sh_g = 8;
577     sh_b = 0;
578     break;
579     default:
580     return; /* we do not support this color depth */
581     }
582    
583     /* prepare limits for color transformation (each channel is handled separately) */
584     if (shade < 0) {
585     shade = -shade;
586     if (shade < 0) shade = 0;
587     if (shade > 100) shade = 100;
588    
589     lower_lim_r = 65535-rm;
590     lower_lim_g = 65535-gm;
591     lower_lim_b = 65535-bm;
592    
593     lower_lim_r = 65535-(unsigned int)(((RUINT32T)lower_lim_r)*((RUINT32T)shade)/100);
594     lower_lim_g = 65535-(unsigned int)(((RUINT32T)lower_lim_g)*((RUINT32T)shade)/100);
595     lower_lim_b = 65535-(unsigned int)(((RUINT32T)lower_lim_b)*((RUINT32T)shade)/100);
596    
597     upper_lim_r = upper_lim_g = upper_lim_b = 65535;
598     } else {
599     if (shade < 0) shade = 0;
600     if (shade > 100) shade = 100;
601    
602     lower_lim_r = lower_lim_g = lower_lim_b = 0;
603    
604     upper_lim_r = (unsigned int)((((RUINT32T)rm)*((RUINT32T)shade))/100);
605     upper_lim_g = (unsigned int)((((RUINT32T)gm)*((RUINT32T)shade))/100);
606     upper_lim_b = (unsigned int)((((RUINT32T)bm)*((RUINT32T)shade))/100);
607     }
608    
609     /* switch red and blue bytes if necessary, we need it for some weird XServers like XFree86 3.3.3.1 */
610     if ((srcImage->bits_per_pixel == 24) && (mask_r >= 0xFF0000 ))
611     {
612     unsigned int tmp;
613    
614     tmp = lower_lim_r;
615     lower_lim_r = lower_lim_b;
616     lower_lim_b = tmp;
617    
618     tmp = upper_lim_r;
619     upper_lim_r = upper_lim_b;
620     upper_lim_b = tmp;
621     }
622    
623     /* fill our lookup tables */
624     for (i = 0; i <= mask_r>>sh_r; i++)
625     {
626     RUINT32T tmp;
627     tmp = ((RUINT32T)i)*((RUINT32T)(upper_lim_r-lower_lim_r));
628     tmp += ((RUINT32T)(mask_r>>sh_r))*((RUINT32T)lower_lim_r);
629     lookup_r[i] = (tmp/65535)<<sh_r;
630     }
631     for (i = 0; i <= mask_g>>sh_g; i++)
632     {
633     RUINT32T tmp;
634     tmp = ((RUINT32T)i)*((RUINT32T)(upper_lim_g-lower_lim_g));
635     tmp += ((RUINT32T)(mask_g>>sh_g))*((RUINT32T)lower_lim_g);
636     lookup_g[i] = (tmp/65535)<<sh_g;
637     }
638     for (i = 0; i <= mask_b>>sh_b; i++)
639     {
640     RUINT32T tmp;
641     tmp = ((RUINT32T)i)*((RUINT32T)(upper_lim_b-lower_lim_b));
642     tmp += ((RUINT32T)(mask_b>>sh_b))*((RUINT32T)lower_lim_b);
643     lookup_b[i] = (tmp/65535)<<sh_b;
644     }
645    
646     /* apply table to input image (replacing colors by newly calculated ones) */
647     switch (srcImage->bits_per_pixel)
648     {
649     case 15:
650     {
651     unsigned short *p1, *pf, *p, *pl;
652     p1 = (unsigned short *) srcImage->data;
653     pf = (unsigned short *) (srcImage->data + srcImage->height * srcImage->bytes_per_line);
654     while (p1 < pf)
655     {
656     p = p1;
657     pl = p1 + srcImage->width;
658     for (; p < pl; p++)
659     {
660     *p = lookup_r[(*p & 0x7c00)>>10] |
661     lookup_g[(*p & 0x03e0)>> 5] |
662     lookup_b[(*p & 0x001f)];
663     }
664     p1 = (unsigned short *) ((char *) p1 + srcImage->bytes_per_line);
665     }
666     break;
667     }
668     case 16:
669     {
670     unsigned short *p1, *pf, *p, *pl;
671     p1 = (unsigned short *) srcImage->data;
672     pf = (unsigned short *) (srcImage->data + srcImage->height * srcImage->bytes_per_line);
673     while (p1 < pf)
674     {
675     p = p1;
676     pl = p1 + srcImage->width;
677     for (; p < pl; p++)
678     {
679     *p = lookup_r[(*p & 0xf800)>>11] |
680     lookup_g[(*p & 0x07e0)>> 5] |
681     lookup_b[(*p & 0x001f)];
682     }
683     p1 = (unsigned short *) ((char *) p1 + srcImage->bytes_per_line);
684     }
685     break;
686     }
687     case 24:
688     {
689     unsigned char *p1, *pf, *p, *pl;
690     p1 = (unsigned char *) srcImage->data;
691     pf = (unsigned char *) (srcImage->data + srcImage->height * srcImage->bytes_per_line);
692     while (p1 < pf)
693     {
694     p = p1;
695     pl = p1 + srcImage->width * 3;
696     for (; p < pl; p += 3)
697     {
698     p[0] = lookup_r[(p[0] & 0xff0000)>>16];
699     p[1] = lookup_r[(p[1] & 0x00ff00)>> 8];
700     p[2] = lookup_r[(p[2] & 0x0000ff)];
701     }
702     p1 = (unsigned char *) ((char *) p1 + srcImage->bytes_per_line);
703     }
704     break;
705     }
706     case 32:
707     {
708     RUINT32T *p1, *pf, *p, *pl;
709     p1 = (RUINT32T *) srcImage->data;
710     pf = (RUINT32T *) (srcImage->data + srcImage->height * srcImage->bytes_per_line);
711    
712     while (p1 < pf)
713     {
714     p = p1;
715     pl = p1 + srcImage->width;
716     for (; p < pl; p++)
717     {
718     *p = lookup_r[(*p & 0xff0000)>>16] |
719     lookup_g[(*p & 0x00ff00)>> 8] |
720     lookup_b[(*p & 0x0000ff)] |
721     (*p & ~0xffffff);
722     }
723     p1 = (RUINT32T *) ((char *) p1 + srcImage->bytes_per_line);
724     }
725     break;
726     }
727     }
728    
729     free (lookup);
730     }
731     #endif
732    
733     /*
734     * Check our parents are still who we think they are.
735     * Do transparency updates if required
736     */
737     int
738     rxvt_term::check_our_parents ()
739     {
740     check_our_parents_ev.stop ();
741     check_our_parents_ev.start (NOW + .1);
742     return 0;
743     }
744    
745     void
746     rxvt_term::check_our_parents_cb (time_watcher &w)
747     {
748 sasha 1.52 int i, pchanged, aformat, rootdepth;
749 ayin 1.39 unsigned long nitems, bytes_after;
750     Atom atype;
751     unsigned char *prop = NULL;
752     Window root, oldp, *list;
753     Pixmap rootpixmap = None;
754     XWindowAttributes wattr, wrootattr;
755     int sx, sy;
756     Window cr;
757 sasha 1.52 unsigned int rootpixmap_w = 0, rootpixmap_h = 0;
758 ayin 1.39
759     pchanged = 0;
760    
761     if (!option (Opt_transparent))
762     return /*pchanged*/; /* Don't try any more */
763    
764 sasha 1.52 #if 0
765     struct timeval stv;
766     gettimeofday (&stv,NULL);
767     #define PRINT_BACKGROUND_OP_TIME do{ struct timeval tv;gettimeofday (&tv,NULL); tv.tv_sec-= stv.tv_sec;\
768     fprintf (stderr,"%d: elapsed %ld usec\n",__LINE__,\
769     tv.tv_sec*1000000+tv.tv_usec-stv.tv_usec );}while(0)
770     #else
771     #define PRINT_BACKGROUND_OP_TIME do{}while(0)
772     #endif
773    
774    
775 ayin 1.39 XGetWindowAttributes (dpy, display->root, &wrootattr);
776     rootdepth = wrootattr.depth;
777    
778     XGetWindowAttributes (dpy, parent[0], &wattr);
779    
780     if (rootdepth != wattr.depth)
781     {
782     if (am_transparent)
783     {
784     pchanged = 1;
785     XSetWindowBackground (dpy, vt, pix_colors_focused[Color_bg]);
786     am_transparent = am_pixmap_trans = 0;
787     }
788    
789     return /*pchanged*/; /* Don't try any more */
790     }
791    
792     /* Get all X ops out of the queue so that our information is up-to-date. */
793     XSync (dpy, False);
794    
795     XTranslateCoordinates (dpy, parent[0], display->root,
796     0, 0, &sx, &sy, &cr);
797     /* check if we are outside of the visible part of the virtual screen : */
798 ayin 1.51 if( sx + (int)szHint.width <= 0 || sy + (int)szHint.height <= 0
799     || sx >= wrootattr.width || sy >= wrootattr.height )
800 ayin 1.39 return /* 0 */ ;
801     /*
802     * Make the frame window set by the window manager have
803     * the root background. Some window managers put multiple nested frame
804     * windows for each client, so we have to take care about that.
805     */
806     i = (xa[XA_XROOTPMAP_ID]
807     && XGetWindowProperty (dpy, display->root, xa[XA_XROOTPMAP_ID],
808     0L, 1L, False, XA_PIXMAP, &atype, &aformat,
809     &nitems, &bytes_after, &prop) == Success);
810    
811     if (!i || prop == NULL)
812     i = (xa[XA_ESETROOT_PMAP_ID]
813     && XGetWindowProperty (dpy, display->root, xa[XA_ESETROOT_PMAP_ID],
814     0L, 1L, False, XA_PIXMAP, &atype, &aformat,
815     &nitems, &bytes_after, &prop) == Success);
816    
817 sasha 1.52 /* TODO: the below logic needs to be cleaned up */
818 ayin 1.39 if (!i || prop == NULL
819     || (!ISSET_PIXCOLOR (Color_tint) && rs[Rs_shade] == NULL
820     #ifdef HAVE_AFTERIMAGE
821 sasha 1.55 && bgPixmap.original_asim == NULL && rs[Rs_blurradius] == NULL
822 ayin 1.39 #endif
823     )
824     )
825 sasha 1.52 rootpixmap = None;
826 ayin 1.39 else
827     {
828 sasha 1.52 int junk;
829     unsigned int ujunk;
830     /* root pixmap may be bad - allow a error */
831     allowedxerror = -1;
832     if ((rootpixmap = *(Pixmap *)prop) != None)
833     if (!XGetGeometry (dpy, rootpixmap, &root, &junk, &junk, &rootpixmap_w, &rootpixmap_h, &ujunk, &ujunk))
834     rootpixmap = None;
835     allowedxerror = 0;
836 ayin 1.39 }
837    
838 sasha 1.52 if (prop != NULL)
839     XFree (prop);
840    
841     if (rootpixmap != None)
842 ayin 1.39 {
843 sasha 1.49 Bool success = False;
844 ayin 1.40 GC gc = NULL;
845 ayin 1.39 XGCValues gcvalue;
846 sasha 1.52 int shade = 100;
847     rgba c (rgba::MAX_CC,rgba::MAX_CC,rgba::MAX_CC);
848     Bool whole_tint = False, no_tint = True;
849 ayin 1.51
850 sasha 1.52 while (sx < 0) sx += (int)wrootattr.width;
851     while (sy < 0) sy += (int)wrootattr.height;
852 ayin 1.39
853 sasha 1.52 if (rs[Rs_shade])
854     shade = atoi (rs[Rs_shade]);
855     if (ISSET_PIXCOLOR (Color_tint))
856     pix_colors_focused [Color_tint].get (c);
857 sasha 1.49 #define IS_COMPONENT_WHOLESOME(c) ((c) <=0x000700 || (c)>=0x00f700)
858 sasha 1.52 if (shade >= 100)
859     whole_tint = (IS_COMPONENT_WHOLESOME(c.r)
860     && IS_COMPONENT_WHOLESOME(c.g)
861     && IS_COMPONENT_WHOLESOME(c.b));
862     no_tint = (c.r >= 0x00f700 && c.g >= 0x00f700 && c.b >= 0x00f700);
863 sasha 1.49 #undef IS_COMPONENT_WHOLESOME
864 sasha 1.52 /* theer are no performance advantages to reusing same pixmap */
865 sasha 1.55 if (bgPixmap.pixmap != None)
866     XFreePixmap (dpy, bgPixmap.pixmap);
867     bgPixmap.pixmap = XCreatePixmap (dpy, vt, szHint.width, szHint.height, rootdepth);
868     bgPixmap.pmap_width = szHint.width;
869     bgPixmap.pmap_height = szHint.height;
870     bgPixmap.pmap_depth = rootdepth;
871 sasha 1.52
872     #if 0 /* TODO : identify cases where this will be detrimental to performance : */
873     /* we want to tile root pixmap into our own pixmap in this cases :
874     * 1) rootpixmap does not cover our window entirely
875     * 2) whole_tint - we can use server-side tinting or tinting disabled
876     */
877     if ( whole_tint || no_tint || pmap_w < sx + szHint.width || pmap_h < sy + szHint.height)
878     {
879     }
880     #endif
881     gcvalue.tile = rootpixmap;
882     gcvalue.fill_style = FillTiled;
883     gcvalue.ts_x_origin = -sx;
884     gcvalue.ts_y_origin = -sy;
885     gc = XCreateGC (dpy, rootpixmap, GCFillStyle | GCTile | GCTileStipXOrigin | GCTileStipYOrigin, &gcvalue);
886 sasha 1.55 XFillRectangle (dpy, bgPixmap.pixmap, gc, 0, 0, szHint.width, szHint.height);
887 sasha 1.49
888 sasha 1.52 if (whole_tint && !no_tint)
889     {
890     /* In this case we can tint image server-side getting significant
891     * performance improvements, as we eliminate XImage transfer
892     */
893     gcvalue.foreground = Pixel (pix_colors_focused [Color_tint]);
894     gcvalue.function = GXand;
895     gcvalue.fill_style = FillSolid;
896     XChangeGC (dpy, gc, GCFillStyle | GCForeground | GCFunction, &gcvalue);
897 sasha 1.55 XFillRectangle (dpy, bgPixmap.pixmap, gc, 0, 0, szHint.width, szHint.height);
898 sasha 1.52 }
899     success = True;
900     #ifdef HAVE_AFTERIMAGE
901 sasha 1.55 if (rs[Rs_blurradius] || bgPixmap.original_asim != NULL || (!whole_tint && (!no_tint || shade !=100)))
902 sasha 1.52 {
903     ARGB32 tint = TINT_LEAVE_SAME;
904     ASImage *back_im = NULL;
905    
906 sasha 1.55 back_im = pixmap2ximage (asv, bgPixmap.pixmap, 0, 0, szHint.width, szHint.height, AllPlanes, 100);
907 sasha 1.52 if (back_im != NULL)
908     {
909     if (!whole_tint && (!no_tint || shade !=100))
910     {
911     ShadingInfo as_shade;
912     as_shade.shading = shade;
913     as_shade.tintColor.red = c.r;
914     as_shade.tintColor.green = c.g;
915     as_shade.tintColor.blue = c.b;
916     tint = shading2tint32 (&as_shade);
917     }
918    
919     if (rs[Rs_blurradius] && back_im)
920     {
921 sasha 1.53 ASImage* tmp;
922     int junk;
923     unsigned int hr = 1, vr = 1;
924     int flags = XParseGeometry (rs[Rs_blurradius], &junk, &junk, &hr, &vr);
925     if (!(flags&WidthValue))
926     hr = 1;
927     if (!(flags&HeightValue))
928     vr = hr;
929     tmp = blur_asimage_gauss (asv, back_im, hr, vr, 0xFFFFFFFF,
930 sasha 1.55 (bgPixmap.original_asim == NULL || tint == TINT_LEAVE_SAME)?ASA_XImage:ASA_ASImage,
931 sasha 1.53 100, ASIMAGE_QUALITY_DEFAULT);
932 sasha 1.52 if (tmp)
933     {
934     destroy_asimage (&back_im);
935     back_im = tmp;
936     }
937     }
938    
939 sasha 1.55 if (bgPixmap.original_asim != NULL)
940 sasha 1.52 {
941     ASImageLayer *layers = create_image_layers (2);
942     ASImage *merged_im = NULL;
943     int fore_w, fore_h;
944    
945     layers[0].im = back_im;
946     layers[0].clip_width = szHint.width;
947     layers[0].clip_height = szHint.height;
948     layers[0].tint = tint;
949 sasha 1.55 layers[1].im = bgPixmap.original_asim;
950 sasha 1.56
951     fore_w = (bgPixmap.h_scale == 0) ? bgPixmap.original_asim->width : bgPixmap.h_scale*szHint.width/100;
952     fore_h = (bgPixmap.v_scale == 0) ? bgPixmap.original_asim->height : bgPixmap.v_scale*szHint.height/100;
953    
954 sasha 1.55 if (fore_w != bgPixmap.original_asim->width
955     || fore_h != bgPixmap.original_asim->height)
956 sasha 1.52 {
957     layers[1].im = scale_asimage (asv,
958 sasha 1.55 bgPixmap.original_asim,
959 sasha 1.52 fore_w, fore_h,
960     ASA_ASImage, 100,
961     ASIMAGE_QUALITY_DEFAULT);
962     }
963     layers[1].clip_width = szHint.width;
964     layers[1].clip_height = szHint.height;
965    
966     if (rs[Rs_blendtype])
967     {
968     layers[1].merge_scanlines = blend_scanlines_name2func (rs[Rs_blendtype]);
969     if (layers[1].merge_scanlines == NULL)
970     layers[1].merge_scanlines = alphablend_scanlines;
971     }
972     PRINT_BACKGROUND_OP_TIME;
973     merged_im = merge_layers (asv, layers, 2, szHint.width, szHint.height,
974     ASA_XImage, 0, ASIMAGE_QUALITY_DEFAULT);
975 sasha 1.55 if (layers[1].im != bgPixmap.original_asim)
976 sasha 1.52 destroy_asimage (&(layers[1].im));
977     free (layers);
978    
979     if (merged_im != NULL)
980     {
981     destroy_asimage (&back_im);
982     back_im = merged_im;
983     }
984     PRINT_BACKGROUND_OP_TIME;
985     }
986     else if (tint != TINT_LEAVE_SAME)
987     {
988     ASImage* tmp = tile_asimage (asv, back_im, 0, 0, szHint.width, szHint.height, tint, ASA_XImage, 100, ASIMAGE_QUALITY_DEFAULT);
989     if (tmp)
990     {
991     destroy_asimage (&back_im);
992     back_im = tmp;
993     }
994     PRINT_BACKGROUND_OP_TIME;
995     }
996 sasha 1.55 asimage2drawable (asv, bgPixmap.pixmap, back_im, gc, 0, 0, 0, 0, szHint.width, szHint.height, True);
997 sasha 1.52 destroy_asimage (&back_im);
998     } /* back_im != NULL */
999     else
1000     success = False;
1001     }
1002     #else /* HAVE_AFTERIMAGE */
1003     if (!whole_tint && (!no_tint || shade !=100))
1004     {
1005 sasha 1.55 XImage *image = XGetImage (dpy, bgPixmap.pixmap, 0, 0, szHint.width, szHint.height, AllPlanes, ZPixmap);
1006 sasha 1.52 success = False;
1007     if (image != NULL)
1008     {
1009     PRINT_BACKGROUND_OP_TIME;
1010     if (gc == NULL)
1011     gc = XCreateGC (dpy, vt, 0UL, &gcvalue);
1012     if (ISSET_PIXCOLOR (Color_tint) || shade != 100)
1013     ShadeXImage (this, image, shade, c.r, c.g, c.b);
1014 sasha 1.55 XPutImage (dpy, bgPixmap.pixmap, gc, image, 0, 0, 0, 0, image->width, image->height);
1015 sasha 1.52 XDestroyImage (image);
1016     success = True;
1017     }
1018     }
1019 ayin 1.39 #endif /* HAVE_AFTERIMAGE */
1020 sasha 1.52 PRINT_BACKGROUND_OP_TIME;
1021    
1022 ayin 1.51 if (gc != NULL)
1023 ayin 1.39 XFreeGC (dpy, gc);
1024    
1025     if (!success)
1026     {
1027     if (am_transparent && am_pixmap_trans)
1028     {
1029     pchanged = 1;
1030 sasha 1.55 if (bgPixmap.pixmap != None)
1031 ayin 1.39 {
1032 sasha 1.55 XFreePixmap (dpy, bgPixmap.pixmap);
1033     bgPixmap.pixmap = None;
1034 ayin 1.39 }
1035     }
1036    
1037     am_pixmap_trans = 0;
1038     }
1039     else
1040     {
1041 sasha 1.55 XSetWindowBackgroundPixmap (dpy, parent[0], bgPixmap.pixmap);
1042 ayin 1.39 XClearWindow (dpy, parent[0]);
1043    
1044     if (!am_transparent || !am_pixmap_trans)
1045     pchanged = 1;
1046    
1047     am_transparent = am_pixmap_trans = 1;
1048     }
1049 sasha 1.52 } /* rootpixmap != None */
1050 ayin 1.39
1051     if (am_pixmap_trans)
1052     XSetWindowBackgroundPixmap (dpy, vt, ParentRelative);
1053     else
1054     {
1055     unsigned int n;
1056     /*
1057     * InheritPixmap transparency
1058     */
1059     for (i = 1; i < (int) (sizeof (parent) / sizeof (Window)); i++)
1060     {
1061     oldp = parent[i];
1062     XQueryTree (dpy, parent[i - 1], &root, &parent[i], &list, &n);
1063     XFree (list);
1064    
1065     if (parent[i] == display->root)
1066     {
1067     if (oldp != None)
1068     pchanged = 1;
1069    
1070     break;
1071     }
1072    
1073     if (oldp != parent[i])
1074     pchanged = 1;
1075     }
1076    
1077     n = 0;
1078    
1079     if (pchanged)
1080     for (; n < (unsigned int)i; n++)
1081     {
1082     XGetWindowAttributes (dpy, parent[n], &wattr);
1083    
1084     if (wattr.depth != rootdepth || wattr.c_class == InputOnly)
1085     {
1086     n = (int) (sizeof (parent) / sizeof (Window)) + 1;
1087     break;
1088     }
1089     }
1090    
1091     if (n > (sizeof (parent) / sizeof (parent[0])))
1092     {
1093     XSetWindowBackground (dpy, parent[0], pix_colors_focused[Color_border]);
1094     XSetWindowBackground (dpy, vt, pix_colors_focused[Color_bg]);
1095     am_transparent = 0;
1096     /* XXX: also turn off Opt_transparent? */
1097     }
1098     else
1099     {
1100     for (n = 0; n < (unsigned int)i; n++)
1101     {
1102     XSetWindowBackgroundPixmap (dpy, parent[n], ParentRelative);
1103     XClearWindow (dpy, parent[n]);
1104     }
1105    
1106     XSetWindowBackgroundPixmap (dpy, vt, ParentRelative);
1107     am_transparent = 1;
1108     }
1109    
1110     for (; i < (int) (sizeof (parent) / sizeof (Window)); i++)
1111     parent[i] = None;
1112     }
1113    
1114     if (scrollBar.win)
1115     {
1116     XSetWindowBackgroundPixmap (dpy, scrollBar.win, ParentRelative);
1117     scrollBar.setIdle ();
1118     scrollbar_show (0);
1119     }
1120    
1121     if (am_transparent)
1122     {
1123     want_refresh = want_full_refresh = 1;
1124     if (am_pixmap_trans)
1125     flush ();
1126     }
1127    
1128     // return pchanged;
1129     }
1130     #endif