--- rxvt-unicode/src/background.C 2010/10/04 14:31:00 1.64 +++ rxvt-unicode/src/background.C 2010/10/13 23:04:57 1.80 @@ -21,6 +21,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *---------------------------------------------------------------------*/ +#include #include "../config.h" /* NECESSARY */ #include "rxvt.h" /* NECESSARY */ @@ -106,6 +107,9 @@ h_scale = v_scale = 0; h_align = v_align = 0; #endif +#ifdef ENABLE_TRANSPARENCY + shade = 100; +#endif flags = 0; pixmap = None; valid_since = invalid_since = 0; @@ -176,7 +180,7 @@ # ifdef ENABLE_TRANSPARENCY if (flags & isTransparent) { -# ifdef HAVE_AFTERIMAGE // can't blur without libAI anyways +# ifdef HAVE_AFTERIMAGE if ((flags & blurNeeded) && !(flags & blurServerSide)) return true; # endif @@ -228,13 +232,11 @@ int diff = window_size - image_size; int smaller = min (image_size, window_size); - if (align >= 0 && align <= 50) + if (align >= 0 && align <= 100) return diff * align / 100; - else if (align > 50 && align <= 100) - return window_size - image_size - diff * (100 - align) / 100; else if (align > 100 && align <= 200 ) return ((align - 100) * smaller / 100) + window_size - smaller; - else if (align > -100 && align < 0) + else if (align >= -100 && align < 0) return ((align + 100) * smaller / 100) - image_size; return 0; } @@ -243,15 +245,14 @@ make_clip_rectangle (int pos, int size, int target_size, int &dst_pos, int &dst_size) { int src_pos = 0; - dst_pos = 0; + dst_pos = pos; dst_size = size; if (pos < 0) { src_pos = -pos; + dst_pos = 0; dst_size += pos; } - else if (pos > 0) - dst_pos = pos; if (dst_pos + dst_size > target_size) dst_size = target_size - dst_pos; @@ -463,6 +464,9 @@ h = v_scale * target_height / 100; } + if (!w) w = image_width; + if (!h) h = image_height; + if (flags & rootAlign) { target->get_window_origin (x, y); @@ -471,14 +475,14 @@ } else { - x = make_align_position (h_align, target_width, w > 0 ? w : image_width); - y = make_align_position (v_align, target_height, h > 0 ? h : image_height); + x = make_align_position (h_align, target_width, w); + y = make_align_position (v_align, target_height, h); } flags &= ~sizeSensitive; if (h_scale != 0 || v_scale != 0 || h_align != 0 || v_align != 0 - || image_width > target_width || image_height > target_height) + || w > target_width || h > target_height) flags |= sizeSensitive; } @@ -501,7 +505,7 @@ if (!(background_flags & transpPmapTinted) && (flags & tintNeeded)) { ShadingInfo as_shade; - as_shade.shading = (shade == 0) ? 100 : shade; + as_shade.shading = shade; rgba c (rgba::MAX_CC,rgba::MAX_CC,rgba::MAX_CC); if (flags & tintSet) @@ -513,7 +517,7 @@ background_tint = shading2tint32 (&as_shade); } - if (!(background_flags & transpPmapBlured) && (flags & blurNeeded) && background != NULL) + if (!(background_flags & transpPmapBlurred) && (flags & blurNeeded) && background != NULL) { ASImage *tmp = blur_asimage_gauss (target->asv, background, h_blurRadius, v_blurRadius, 0xFFFFFFFF, (original_asim == NULL || tint == TINT_LEAVE_SAME) ? ASA_XImage : ASA_ASImage, @@ -544,10 +548,11 @@ get_image_geometry (original_asim->width, original_asim->height, w, h, x, y); if (!original_asim - || x >= target_width - || y >= target_height - || (w > 0 && x + w <= 0) - || (h > 0 && y + h <= 0)) + || (!(flags & rootAlign) + && (x >= target_width + || y >= target_height + || (x + w <= 0) + || (y + h <= 0)))) { if (background) { @@ -571,12 +576,11 @@ { result = original_asim; - if ((w > 0 && w != original_asim->width) - || (h > 0 && h != original_asim->height)) + if ((w != original_asim->width) + || (h != original_asim->height)) { result = scale_asimage (target->asv, original_asim, - w > 0 ? w : original_asim->width, - h > 0 ? h : original_asim->height, + w, h, background ? ASA_ASImage : ASA_XImage, 100, ASIMAGE_QUALITY_DEFAULT); } @@ -618,7 +622,7 @@ layers[0].tint = background_tint; layers[1].im = result; - if (w <= 0) + if (h_scale == 0 || v_scale == 0) { /* tile horizontally */ while (x > 0) x -= (int)result->width; @@ -632,7 +636,7 @@ layers[1].clip_width = result->width; } - if (h <= 0) + if (h_scale == 0 || v_scale == 0) { while (y > 0) y -= (int)result->height; layers[1].dst_y = y; @@ -743,9 +747,10 @@ if (!pixbuf) return false; - // TODO: add alpha blending +#if !XFT if (background_flags) return false; +#endif GdkPixbuf *result; @@ -764,20 +769,20 @@ get_image_geometry (image_width, image_height, w, h, x, y); - if (x >= target_width - || y >= target_height - || (w > 0 && x + w <= 0) - || (h > 0 && y + h <= 0)) + if (!(flags & rootAlign) + && (x >= target_width + || y >= target_height + || (x + w <= 0) + || (y + h <= 0))) return false; result = pixbuf; - if ((w > 0 && w != image_width) - || (h > 0 && h != image_height)) + if ((w != image_width) + || (h != image_height)) { result = gdk_pixbuf_scale_simple (pixbuf, - w > 0 ? w : image_width, - h > 0 ? h : image_height, + w, h, GDK_INTERP_BILINEAR); } @@ -787,14 +792,23 @@ { XGCValues gcv; GC gc; + Pixmap root_pmap; image_width = gdk_pixbuf_get_width (result); image_height = gdk_pixbuf_get_height (result); - if (h_scale == 0 || v_scale == 0) + if (background_flags) + { + root_pmap = pixmap; + pixmap = None; + } + else { - new_pmap_width = min (image_width, target_width); - new_pmap_height = min (image_height, target_height); + if (h_scale == 0 || v_scale == 0) + { + new_pmap_width = min (image_width, target_width); + new_pmap_height = min (image_height, target_height); + } } if (pixmap) @@ -860,6 +874,44 @@ 0, 0); } +#if XFT + if (background_flags) + { + Display *dpy = target->dpy; + XRenderPictureAttributes pa; + + XRenderPictFormat *src_format = XRenderFindVisualFormat (dpy, DefaultVisual (dpy, target->display->screen)); + Picture src = XRenderCreatePicture (dpy, root_pmap, src_format, 0, &pa); + + XRenderPictFormat *dst_format = XRenderFindVisualFormat (dpy, target->visual); + Picture dst = XRenderCreatePicture (dpy, pixmap, dst_format, 0, &pa); + + pa.repeat = True; + Pixmap mask_pmap = XCreatePixmap (dpy, target->vt, 1, 1, 8); + XRenderPictFormat *mask_format = XRenderFindStandardFormat (dpy, PictStandardA8); + Picture mask = XRenderCreatePicture (dpy, mask_pmap, mask_format, CPRepeat, &pa); + XFreePixmap (dpy, mask_pmap); + + if (src && dst && mask) + { + XRenderColor mask_c; + + mask_c.alpha = 0x8000; + mask_c.red = 0; + mask_c.green = 0; + mask_c.blue = 0; + XRenderFillRectangle (dpy, PictOpSrc, mask, &mask_c, 0, 0, 1, 1); + XRenderComposite (dpy, PictOpOver, src, mask, dst, 0, 0, 0, 0, 0, 0, target_width, target_height); + } + + XRenderFreePicture (dpy, src); + XRenderFreePicture (dpy, dst); + XRenderFreePicture (dpy, mask); + + XFreePixmap (dpy, root_pmap); + } +#endif + if (result != pixbuf) g_object_unref (result); @@ -936,6 +988,9 @@ if (!(geom_flags & HeightValue)) vr = hr; + min_it (hr, 128); + min_it (vr, 128); + if (h_blurRadius != hr) { ++changed; @@ -953,6 +1008,18 @@ else flags |= blurNeeded; +#if XFT + XFilters *filters = XRenderQueryFilters (target->dpy, target->display->root); + if (filters) + { + for (int i = 0; i < filters->nfilter; i++) + if (!strcmp (filters->filter[i], FilterConvolution)) + flags |= bgPixmap_t::blurServerSide; + + XFree (filters); + } +#endif + return (changed > 0); } @@ -961,7 +1028,7 @@ { unsigned long flags = 0; rgba c (rgba::MAX_CC,rgba::MAX_CC,rgba::MAX_CC); - bool has_shade = (shade > 0 && shade < 100) || (shade > 100 && shade < 200); + bool has_shade = shade != 100; if (tint) { @@ -1003,7 +1070,7 @@ bool bgPixmap_t::set_tint (rxvt_color &new_tint) { - if (tint != new_tint) + if (!(flags & tintSet) || tint != new_tint) { unsigned long new_flags = compute_tint_shade_flags (&new_tint, shade); tint = new_tint; @@ -1031,12 +1098,11 @@ bool bgPixmap_t::set_shade (const char *shade_str) { - int new_shade = (shade_str) ? atoi (shade_str) : 0; + int new_shade = (shade_str) ? atoi (shade_str) : 100; - if (new_shade < 0 && new_shade > -100) + clamp_it (new_shade, -100, 200); + if (new_shade < 0) new_shade = 200 - (100 + new_shade); - else if (new_shade == 100) - new_shade = 0; if (new_shade != shade) { @@ -1049,13 +1115,95 @@ return false; } +static void +get_gaussian_kernel (int radius, int width, double *kernel, XFixed *params) +{ + double sigma = radius / 2.0; + double scale = sqrt (2.0 * M_PI) * sigma; + double sum = 0.0; + + for (int i = 0; i < width; i++) + { + double x = i - width / 2; + kernel[i] = exp (-(x * x) / (2.0 * sigma * sigma)) / scale; + sum += kernel[i]; + } + + params[0] = XDoubleToFixed (width); + params[1] = XDoubleToFixed (1); + + for (int i = 0; i < width; i++) + params[i+2] = XDoubleToFixed (kernel[i] / sum); +} + bool -bgPixmap_t::tint_pixmap (Pixmap pixmap) +bgPixmap_t::blur_pixmap (Pixmap pixmap, Visual *visual, int width, int height) +{ + bool ret = false; +#if XFT + int size = max (h_blurRadius, v_blurRadius) * 2 + 1; + double *kernel = (double *)malloc (size * sizeof (double)); + XFixed *params = (XFixed *)malloc ((size + 2) * sizeof (XFixed)); + + Display *dpy = target->dpy; + XRenderPictureAttributes pa; + XRenderPictFormat *format = XRenderFindVisualFormat (dpy, target->visual); + + Picture src = XRenderCreatePicture (dpy, pixmap, format, 0, &pa); + Picture dst = XRenderCreatePicture (dpy, pixmap, format, 0, &pa); + + if (kernel && params && src && dst) + { + if (h_blurRadius) + { + size = h_blurRadius * 2 + 1; + get_gaussian_kernel (h_blurRadius, size, kernel, params); + + XRenderSetPictureFilter (dpy, src, FilterConvolution, params, size+2); + XRenderComposite (dpy, + PictOpSrc, + src, + None, + dst, + 0, 0, + 0, 0, + 0, 0, + width, height); + } + + if (v_blurRadius) + { + size = v_blurRadius * 2 + 1; + get_gaussian_kernel (v_blurRadius, size, kernel, params); + swap (params[0], params[1]); + + XRenderSetPictureFilter (dpy, src, FilterConvolution, params, size+2); + XRenderComposite (dpy, + PictOpSrc, + src, + None, + dst, + 0, 0, + 0, 0, + 0, 0, + width, height); + } + + ret = true; + } + + free (kernel); + free (params); + XRenderFreePicture (dpy, src); + XRenderFreePicture (dpy, dst); +#endif + return ret; +} + +bool +bgPixmap_t::tint_pixmap (Pixmap pixmap, Visual *visual, int width, int height) { - Window root = target->display->root; Display *dpy = target->dpy; - int window_width = target->szHint.width; - int window_height = target->szHint.height; bool ret = false; if (flags & tintWholesome) @@ -1069,10 +1217,10 @@ gcv.foreground = Pixel (tint); gcv.function = GXand; gcv.fill_style = FillSolid; - gc = XCreateGC (dpy, root, GCFillStyle | GCForeground | GCFunction, &gcv); + gc = XCreateGC (dpy, pixmap, GCFillStyle | GCForeground | GCFunction, &gcv); if (gc) { - XFillRectangle (dpy, pixmap, gc, 0, 0, window_width, window_height); + XFillRectangle (dpy, pixmap, gc, 0, 0, width, height); ret = true; XFreeGC (dpy, gc); } @@ -1085,49 +1233,33 @@ if (flags & tintSet) tint.get (c); - if (shade > 0 && shade < 100) + if (shade <= 100) { c.r = (c.r * shade) / 100; c.g = (c.g * shade) / 100; c.b = (c.b * shade) / 100; } - else if (shade > 100 && shade < 200) + else { - c.r = (c.r * (200 - shade)) / 100; - c.g = (c.g * (200 - shade)) / 100; - c.b = (c.b * (200 - shade)) / 100; - } - - XRenderPictFormat pf; - pf.type = PictTypeDirect; - pf.depth = 32; - pf.direct.redMask = 0xff; - pf.direct.greenMask = 0xff; - pf.direct.blueMask = 0xff; - pf.direct.alphaMask = 0xff; - - XRenderPictFormat *solid_format = XRenderFindFormat (dpy, - (PictFormatType| - PictFormatDepth| - PictFormatRedMask| - PictFormatGreenMask| - PictFormatBlueMask| - PictFormatAlphaMask), - &pf, - 0); - XRenderPictFormat *root_format = XRenderFindVisualFormat (dpy, DefaultVisualOfScreen (ScreenOfDisplay (dpy, target->display->screen))); + c.r = ((0xffff - c.r) * (200 - shade)) / 100; + c.g = ((0xffff - c.g) * (200 - shade)) / 100; + c.b = ((0xffff - c.b) * (200 - shade)) / 100; + } + + XRenderPictFormat *solid_format = XRenderFindStandardFormat (dpy, PictStandardARGB32); + XRenderPictFormat *format = XRenderFindVisualFormat (dpy, visual); XRenderPictureAttributes pa; - Picture back_pic = XRenderCreatePicture (dpy, pixmap, root_format, 0, &pa); + Picture back_pic = XRenderCreatePicture (dpy, pixmap, format, 0, &pa); pa.repeat = True; - Pixmap overlay_pmap = XCreatePixmap (dpy, root, 1, 1, 32); + Pixmap overlay_pmap = XCreatePixmap (dpy, pixmap, 1, 1, 32); Picture overlay_pic = XRenderCreatePicture (dpy, overlay_pmap, solid_format, CPRepeat, &pa); XFreePixmap (dpy, overlay_pmap); pa.component_alpha = True; - Pixmap mask_pmap = XCreatePixmap (dpy, root, 1, 1, 32); + Pixmap mask_pmap = XCreatePixmap (dpy, pixmap, 1, 1, 32); Picture mask_pic = XRenderCreatePicture (dpy, mask_pmap, solid_format, CPRepeat|CPComponentAlpha, &pa); XFreePixmap (dpy, mask_pmap); @@ -1144,7 +1276,7 @@ mask_c.green = 0xffff - c.g; mask_c.blue = 0xffff - c.b; XRenderFillRectangle (dpy, PictOpSrc, mask_pic, &mask_c, 0, 0, 1, 1); - XRenderComposite (dpy, PictOpOver, overlay_pic, mask_pic, back_pic, 0, 0, 0, 0, 0, 0, window_width, window_height); + XRenderComposite (dpy, PictOpOver, overlay_pic, mask_pic, back_pic, 0, 0, 0, 0, 0, 0, width, height); ret = true; } @@ -1197,7 +1329,7 @@ if (root_pixmap != None) { - /* we want to validate the pixmap and get it's size at the same time : */ + /* we want to validate the pixmap and get its size at the same time : */ int junk; unsigned int ujunk; /* root pixmap may be bad - allow a error */ @@ -1295,9 +1427,14 @@ { if (!need_client_side_rendering ()) { + if ((flags & blurNeeded)) + { + if (blur_pixmap (tiled_root_pmap, DefaultVisual (dpy, target->display->screen), window_width, window_height)) + result |= transpPmapBlurred; + } if ((flags & tintNeeded)) { - if (tint_pixmap (tiled_root_pmap)) + if (tint_pixmap (tiled_root_pmap, DefaultVisual (dpy, target->display->screen), window_width, window_height)) result |= transpPmapTinted; } } /* server side rendering completed */ @@ -1549,9 +1686,6 @@ if (visual->c_class != TrueColor || srcImage->format != ZPixmap) return ; - if (shade == 0) - shade = 100; - /* for convenience */ mask_r = visual->red_mask; mask_g = visual->green_mask; @@ -1616,10 +1750,8 @@ } /* prepare limits for color transformation (each channel is handled separately) */ - if (shade < 0) { - shade = -shade; - if (shade < 0) shade = 0; - if (shade > 100) shade = 100; + if (shade > 100) { + shade = 200 - shade; lower_lim_r = 65535-rm; lower_lim_g = 65535-gm; @@ -1631,8 +1763,6 @@ upper_lim_r = upper_lim_g = upper_lim_b = 65535; } else { - if (shade < 0) shade = 0; - if (shade > 100) shade = 100; lower_lim_r = lower_lim_g = lower_lim_b = 0;