--- rxvt-unicode/src/background.C 2012/05/20 16:34:42 1.217 +++ rxvt-unicode/src/background.C 2012/05/26 08:10:25 1.222 @@ -60,6 +60,11 @@ void rxvt_term::bg_destroy () { +# ifdef BG_IMAGE_FROM_FILE + for (vector::iterator bg_image = image_vec.begin (); bg_image < image_vec.end (); bg_image++) + bg_image->destroy (); +# endif + if (bg_pixmap) XFreePixmap (dpy, bg_pixmap); } @@ -87,11 +92,11 @@ # endif # ifdef BG_IMAGE_FROM_FILE - if (bg_image.flags & IM_IS_SET) + for (vector::iterator bg_image = image_vec.begin (); bg_image < image_vec.end (); bg_image++) { - if ((bg_image.flags & IM_IS_SIZE_SENSITIVE) - || bg_image.width () > szHint.width - || bg_image.height () > szHint.height) + if ((bg_image->flags & IM_IS_SIZE_SENSITIVE) + || bg_image->width () > szHint.width + || bg_image->height () > szHint.height) return true; } # endif @@ -108,9 +113,9 @@ # endif # ifdef BG_IMAGE_FROM_FILE - if (bg_image.flags & IM_IS_SET) + for (vector::iterator bg_image = image_vec.begin (); bg_image < image_vec.end (); bg_image++) { - if (bg_image.flags & IM_ROOT_ALIGN) + if (bg_image->flags & IM_ROOT_ALIGN) return true; } # endif @@ -147,6 +152,41 @@ return src_pos; } +static void +parse_style (const char *style, int &x, int &y, unsigned int &w, unsigned int &h, uint8_t &flags) +{ + if (!strcasecmp (style, "tiled")) + { + flags = IM_TILE; + w = h = noScale; + x = y = 0; + } + else if (!strcasecmp (style, "aspect-stretched")) + { + flags = IM_KEEP_ASPECT; + w = h = windowScale; + x = y = centerAlign; + } + else if (!strcasecmp (style, "stretched")) + { + flags = 0; + w = h = windowScale; + x = y = centerAlign; + } + else if (!strcasecmp (style, "centered")) + { + flags = 0; + w = h = noScale; + x = y = centerAlign; + } + else if (!strcasecmp (style, "root-tiled")) + { + flags = IM_TILE|IM_ROOT_ALIGN; + w = h = noScale; + x = y = 0; + } +} + bool rxvt_image::set_geometry (const char *geom, bool update) { @@ -156,7 +196,7 @@ int y = v_align; unsigned int w = h_scale; unsigned int h = v_scale; - unsigned long new_flags = 0; + uint8_t new_flags = 0; if (geom == NULL) return false; @@ -167,39 +207,11 @@ for (int i = 0; arr[i]; i++) { - if (!strcasecmp (arr[i], "style=tiled")) - { - new_flags = IM_TILE; - w = h = noScale; - x = y = 0; - geom_flags = WidthValue|HeightValue|XValue|YValue; - } - else if (!strcasecmp (arr[i], "style=aspect-stretched")) - { - new_flags = IM_KEEP_ASPECT; - w = h = windowScale; - x = y = centerAlign; - geom_flags = WidthValue|HeightValue|XValue|YValue; - } - else if (!strcasecmp (arr[i], "style=stretched")) - { - new_flags = 0; - w = h = windowScale; - geom_flags = WidthValue|HeightValue; - } - else if (!strcasecmp (arr[i], "style=centered")) + if (!strncasecmp (arr[i], "style=", 6)) { - new_flags = 0; - w = h = noScale; - x = y = centerAlign; + parse_style (arr[i] + 6, x, y, w, h, new_flags); geom_flags = WidthValue|HeightValue|XValue|YValue; } - else if (!strcasecmp (arr[i], "style=root-tiled")) - { - new_flags = IM_TILE|IM_ROOT_ALIGN; - w = h = noScale; - geom_flags = WidthValue|HeightValue; - } else if (!strcasecmp (arr[i], "op=tile")) new_flags |= IM_TILE; else if (!strcasecmp (arr[i], "op=keep-aspect")) @@ -343,13 +355,13 @@ bool rxvt_term::pixbuf_to_pixmap (GdkPixbuf *pixbuf, Pixmap pixmap, GC gc, int src_x, int src_y, int dst_x, int dst_y, - unsigned int width, unsigned int height) + unsigned int width, unsigned int height, bool argb) { XImage *ximage; char *line; int width_r, width_g, width_b, width_a; int sh_r, sh_g, sh_b, sh_a; - uint32_t alpha_mask; + uint32_t red_mask, green_mask, blue_mask, alpha_mask; int rowstride; int channels; unsigned char *row; @@ -357,31 +369,44 @@ if (visual->c_class != TrueColor) return false; -#if XRENDER - XRenderPictFormat *format = XRenderFindVisualFormat (dpy, visual); - if (format) - alpha_mask = (uint32_t)format->direct.alphaMask << format->direct.alpha; + if (argb) + { + red_mask = 0xff << 16; + green_mask = 0xff << 8; + blue_mask = 0xff; + alpha_mask = 0xff << 24; + } else + { + red_mask = visual->red_mask; + green_mask = visual->green_mask; + blue_mask = visual->blue_mask; +#if XRENDER + XRenderPictFormat *format = XRenderFindVisualFormat (dpy, visual); + if (format) + alpha_mask = (uint32_t)format->direct.alphaMask << format->direct.alpha; + else #endif - alpha_mask = 0; + alpha_mask = 0; + } - width_r = ecb_popcount32 (visual->red_mask); - width_g = ecb_popcount32 (visual->green_mask); - width_b = ecb_popcount32 (visual->blue_mask); + width_r = ecb_popcount32 (red_mask); + width_g = ecb_popcount32 (green_mask); + width_b = ecb_popcount32 (blue_mask); width_a = ecb_popcount32 (alpha_mask); if (width_r > 8 || width_g > 8 || width_b > 8 || width_a > 8) return false; - sh_r = ecb_ctz32 (visual->red_mask); - sh_g = ecb_ctz32 (visual->green_mask); - sh_b = ecb_ctz32 (visual->blue_mask); + sh_r = ecb_ctz32 (red_mask); + sh_g = ecb_ctz32 (green_mask); + sh_b = ecb_ctz32 (blue_mask); sh_a = ecb_ctz32 (alpha_mask); if (width > 32767 || height > 32767) return false; - ximage = XCreateImage (dpy, visual, depth, ZPixmap, 0, 0, + ximage = XCreateImage (dpy, visual, argb ? 32 : depth, ZPixmap, 0, 0, width, height, 32, 0); if (!ximage) return false; @@ -513,42 +538,45 @@ image_height = gdk_pixbuf_get_height (result); if (need_blend) - { - tmp_pixmap = bg_pixmap; - bg_pixmap = None; - } + tmp_pixmap = XCreatePixmap (dpy, vt, new_pmap_width, new_pmap_height, 32); else { - if (image.flags & IM_TILE) + // optimise bg pixmap size when tiling, but only if there are no + // other pixbufs to render. Otherwise, the bg pixmap size must + // be equal to the window size. + if ((image.flags & IM_TILE) + && image_vec.size () == 1) { new_pmap_width = min (image_width, target_width); new_pmap_height = min (image_height, target_height); } - } - if (bg_pixmap == None - || bg_pmap_width != new_pmap_width - || bg_pmap_height != new_pmap_height) - { - if (bg_pixmap) - XFreePixmap (dpy, bg_pixmap); - bg_pixmap = XCreatePixmap (dpy, vt, new_pmap_width, new_pmap_height, depth); - bg_pmap_width = new_pmap_width; - bg_pmap_height = new_pmap_height; + if (bg_pixmap == None + || bg_pmap_width != new_pmap_width + || bg_pmap_height != new_pmap_height) + { + if (bg_pixmap) + XFreePixmap (dpy, bg_pixmap); + bg_pixmap = XCreatePixmap (dpy, vt, new_pmap_width, new_pmap_height, depth); + bg_pmap_width = new_pmap_width; + bg_pmap_height = new_pmap_height; + } + + tmp_pixmap = bg_pixmap; } gcv.foreground = pix_colors[Color_bg]; - gc = XCreateGC (dpy, vt, GCForeground, &gcv); + gc = XCreateGC (dpy, tmp_pixmap, GCForeground, &gcv); if (gc) { if (image.flags & IM_TILE) { - Pixmap tile = XCreatePixmap (dpy, vt, image_width, image_height, depth); + Pixmap tile = XCreatePixmap (dpy, vt, image_width, image_height, need_blend ? 32 : depth); pixbuf_to_pixmap (result, tile, gc, 0, 0, 0, 0, - image_width, image_height); + image_width, image_height, need_blend); gcv.tile = tile; gcv.fill_style = FillTiled; @@ -556,7 +584,7 @@ gcv.ts_y_origin = y; XChangeGC (dpy, gc, GCFillStyle | GCTile | GCTileStipXOrigin | GCTileStipYOrigin, &gcv); - XFillRectangle (dpy, bg_pixmap, gc, 0, 0, new_pmap_width, new_pmap_height); + XFillRectangle (dpy, tmp_pixmap, gc, 0, 0, new_pmap_width, new_pmap_height); XFreePixmap (dpy, tile); } else @@ -570,21 +598,22 @@ if (dst_x > 0 || dst_y > 0 || dst_x + dst_width < new_pmap_width || dst_y + dst_height < new_pmap_height) - XFillRectangle (dpy, bg_pixmap, gc, 0, 0, new_pmap_width, new_pmap_height); + XFillRectangle (dpy, tmp_pixmap, gc, 0, 0, new_pmap_width, new_pmap_height); if (dst_x < new_pmap_width && dst_y < new_pmap_height) - pixbuf_to_pixmap (result, bg_pixmap, gc, + pixbuf_to_pixmap (result, tmp_pixmap, gc, src_x, src_y, dst_x, dst_y, - dst_width, dst_height); + dst_width, dst_height, need_blend); } #if XRENDER if (need_blend) { + XRenderPictFormat *argb_format = XRenderFindStandardFormat (dpy, PictStandardARGB32); XRenderPictFormat *format = XRenderFindVisualFormat (dpy, visual); - Picture src = XRenderCreatePicture (dpy, tmp_pixmap, format, 0, 0); + Picture src = XRenderCreatePicture (dpy, tmp_pixmap, argb_format, 0, 0); Picture dst = XRenderCreatePicture (dpy, bg_pixmap, format, 0, 0); @@ -592,7 +621,7 @@ XRenderColor mask_c; - mask_c.alpha = 0x8000; + mask_c.alpha = gdk_pixbuf_get_has_alpha (image.pixbuf) ? 0xffff : image.alpha; mask_c.red = mask_c.green = mask_c.blue = 0; @@ -621,13 +650,59 @@ } # endif /* HAVE_PIXBUF */ +# ifndef NO_RESOURCES +static int +rxvt_define_image (XrmDatabase *database ecb_unused, + XrmBindingList bindings ecb_unused, + XrmQuarkList quarks, + XrmRepresentation *type ecb_unused, + XrmValue *value, + XPointer closure ecb_unused) +{ + int size; + + for (size = 0; quarks[size] != NULLQUARK; size++) + ; + + if (size >= 2) + { + int id = strtol (XrmQuarkToString (quarks[size-2]), 0, 0); + if (id >= 1) + GET_R->parse_image (id, XrmQuarkToString (quarks[size-1]), (char *)value->addr); + } + return False; +} + +void +rxvt_term::parse_image (int id, const char *type, const char *arg) +{ + if (image_vec.size () < id + 1) + image_vec.resize (id + 1); + + rxvt_image *image = &image_vec[id]; +} +# endif + +rxvt_image::rxvt_image () +{ + alpha = + flags = + h_scale = + v_scale = + h_align = + v_align = 0; + +# ifdef HAVE_PIXBUF + pixbuf = 0; +# endif +} + bool -rxvt_image::set_file (const char *file) +rxvt_image::set_file_geometry (const char *file) { if (!file || !*file) return false; - bool ret = false; const char *p = strchr (file, ';'); if (p) @@ -639,6 +714,18 @@ file = f; } + bool ret = set_file (file); + alpha = 0x8000; + if (ret && p) + set_geometry (p + 1); + return ret; +} + +bool +rxvt_image::set_file (const char *file) +{ + bool ret = false; + # ifdef HAVE_PIXBUF GdkPixbuf *image = gdk_pixbuf_new_from_file (file, NULL); if (image) @@ -652,12 +739,10 @@ if (ret) { + alpha = 0xffff; flags = IM_IS_SET | IM_IS_SIZE_SENSITIVE; h_scale = v_scale = defaultScale; h_align = v_align = defaultAlign; - - if (p) - set_geometry (p + 1); } return ret; @@ -1080,9 +1165,9 @@ # endif # ifdef BG_IMAGE_FROM_FILE - if (bg_image.flags & IM_IS_SET) + for (vector::iterator bg_image = image_vec.begin (); bg_image < image_vec.end (); bg_image++) { - if (render_image (bg_image)) + if (render_image (*bg_image)) bg_flags |= BG_IS_VALID; } # endif @@ -1126,6 +1211,31 @@ XFree (filters); } #endif + +#ifdef BG_IMAGE_FROM_FILE + if (rs[Rs_backgroundPixmap]) + { + rxvt_image *image = new_image (); + if (!image->set_file_geometry (rs[Rs_backgroundPixmap])) + image_vec.pop_back (); + } + +# ifndef NO_RESOURCES + find_resources ("image", "Image", XrmEnumAllLevels, rxvt_define_image); + vector::iterator bg_image = image_vec.begin (); + while (bg_image != image_vec.end ()) + { + if (!(bg_image->flags & IM_IS_SET)) + bg_image = image_vec.erase (bg_image); + else + bg_image++; + } +# endif + + if (image_vec.size () > 0 + && !bg_window_position_sensitive ()) + update_background (); +#endif } #endif /* HAVE_BG_PIXMAP */