From 6a7aff593d752da525aba0098572a2d9d20d0e86 Mon Sep 17 00:00:00 2001 From: Olivier Fourdan Date: Thu, 5 Feb 2015 21:24:49 +0100 Subject: Use XRender for scaling down window pixmaps Instead of GdkPixbuf routines, although GdkPixbuf gives much better results that XRender, using XRender is much faster on some hardware. Also add the application icon to the preview compensate the lower quality. Signed-off-by: Olivier Fourdan --- src/compositor.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++---- src/compositor.h | 6 ++- src/icons.c | 46 ++++++++++++++++++++--- 3 files changed, 147 insertions(+), 16 deletions(-) diff --git a/src/compositor.c b/src/compositor.c index 5af29ce5f..bf3fee9ca 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -2476,9 +2476,9 @@ recenter_zoomed_area (ScreenInfo *screen_info, int x_root, int y_root) } if (zf > (1 << 14) && zf < (1 << 16)) - XRenderSetPictureFilter (dpy, screen_info->rootBuffer, "bilinear", NULL, 0); + XRenderSetPictureFilter (dpy, screen_info->rootBuffer, FilterBilinear, NULL, 0); else - XRenderSetPictureFilter (dpy, screen_info->rootBuffer, "nearest", NULL, 0); + XRenderSetPictureFilter (dpy, screen_info->rootBuffer, FilterNearest, NULL, 0); XRenderSetPictureTransform (dpy, screen_info->rootBuffer, &screen_info->transform); @@ -3038,6 +3038,104 @@ compositorWindowPixmapAvailable (ScreenInfo *screen_info) return FALSE; } +static Pixmap +compositorScaleWindowPixmap (CWindow *cw, guint *width, guint *height) +{ + Display *dpy; + ScreenInfo *screen_info; + Picture srcPicture, destPicture; + Pixmap source, pixmap; + XTransform transform; + XRenderPictFormat *render_format; + double scale; + int x, y, src_size, dest_size; + unsigned int source_w, source_h; + unsigned int dest_w, dest_h; + XRenderColor c = { 0, 0, 0, 0 }; + + screen_info = cw->screen_info; + dpy = myScreenGetXDisplay (screen_info); + + source = None; + if (cw->name_window_pixmap != None) + { + source = cw->name_window_pixmap; + } + else + { + source = cw->saved_window_pixmap; + } + if (!source) + { + return None; + } + + /* Get the source pixmap size to compute the scale */ + source_w = cw->attr.width; + source_h = cw->attr.height; + src_size = MAX (source_w, source_h); + + /*/ + * Caller may pass either NULL or 0. + * If 0, we return the actual unscalled size. + */ + dest_w = (width != NULL && *width > 0) ? *width : source_w; + dest_h = (height != NULL && *height > 0) ? *height : source_h; + dest_size = MIN (dest_w, dest_h); + + scale = (double) dest_size / (double) src_size; + dest_w = source_w * scale; + dest_h = source_h * scale; + + transform.matrix[0][0] = XDoubleToFixed(1.0); + transform.matrix[0][1] = XDoubleToFixed(0.0); + transform.matrix[0][2] = XDoubleToFixed(0.0); + transform.matrix[1][0] = XDoubleToFixed(0.0); + transform.matrix[1][1] = XDoubleToFixed(1.0); + transform.matrix[1][2] = XDoubleToFixed(0.0); + transform.matrix[2][0] = XDoubleToFixed(0.0); + transform.matrix[2][1] = XDoubleToFixed(0.0); + transform.matrix[2][2] = XDoubleToFixed(scale); + + pixmap = XCreatePixmap (dpy, screen_info->output, dest_w, dest_h, 32); + if (!pixmap) + { + return None; + } + + render_format = get_window_format (cw); + if (!render_format) + { + return None; + } + + srcPicture = XRenderCreatePicture (dpy, source, render_format, 0, NULL); + XRenderSetPictureFilter (dpy, srcPicture, FilterBilinear, 0, 0); + XRenderSetPictureTransform (dpy, srcPicture, &transform); + + render_format = XRenderFindStandardFormat (dpy, PictStandardARGB32); + destPicture = XRenderCreatePicture (dpy, pixmap, render_format, 0, NULL); + + XRenderFillRectangle (dpy, PictOpSrc, destPicture, &c, 0, 0, dest_w, dest_h); + XRenderComposite (dpy, PictOpSrc, srcPicture, None, destPicture, + 0, 0, 0, 0, 0, 0, dest_w, dest_h); + + XRenderFreePicture (dpy, srcPicture); + XRenderFreePicture (dpy, destPicture); + + /* Update given size if requested */ + if (width != NULL) + { + *width = dest_w; + } + if (height != NULL) + { + *height = dest_h; + } + + return pixmap; +} + /* May return None if: * - The xserver does not support name window pixmaps * - The compositor is disabled at run time @@ -3046,13 +3144,14 @@ compositorWindowPixmapAvailable (ScreenInfo *screen_info) * if the window is unmapped. */ Pixmap -compositorGetWindowPixmap (ScreenInfo *screen_info, Window id) +compositorGetWindowPixmapAtSize (ScreenInfo *screen_info, Window id, guint *width, guint *height) { #ifdef HAVE_NAME_WINDOW_PIXMAP #ifdef HAVE_COMPOSITOR CWindow *cw; g_return_val_if_fail (id != None, None); + TRACE ("entering compositorGetPixmap: 0x%lx", id); if (!compositorWindowPixmapAvailable (screen_info)) @@ -3063,11 +3162,7 @@ compositorGetWindowPixmap (ScreenInfo *screen_info, Window id) cw = find_cwindow_in_screen (screen_info, id); if (cw) { - if (cw->name_window_pixmap != None) - { - return cw->name_window_pixmap; - } - return cw->saved_window_pixmap; + return compositorScaleWindowPixmap (cw, width, height); } #endif /* HAVE_COMPOSITOR */ #endif /* HAVE_NAME_WINDOW_PIXMAP */ diff --git a/src/compositor.h b/src/compositor.h index 6629f3e95..dc34c486b 100644 --- a/src/compositor.h +++ b/src/compositor.h @@ -53,8 +53,10 @@ void compositorResizeWindow (DisplayInfo *, int, int); gboolean compositorWindowPixmapAvailable (ScreenInfo *); -Pixmap compositorGetWindowPixmap (ScreenInfo *, - Window); +Pixmap compositorGetWindowPixmapAtSize (ScreenInfo *, + Window, + guint *, + guint *); void compositorHandleEvent (DisplayInfo *, XEvent *); void compositorZoomIn (ScreenInfo *, diff --git a/src/icons.c b/src/icons.c index 1105107e9..40ebd418a 100644 --- a/src/icons.c +++ b/src/icons.c @@ -423,9 +423,9 @@ get_pixbuf_from_pixmap (GdkScreen *gscreen, Pixmap xpixmap, guint src_x, guint s } cmap = get_cmap (drawable, gscreen); - - retval = gdk_pixbuf_get_from_drawable (NULL, drawable, cmap, src_x, src_y, - dest_x, dest_y, width, height); + retval = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, width, height); + gdk_pixbuf_get_from_drawable (retval, drawable, cmap, src_x, src_y, + dest_x, dest_y, width, height); if (G_LIKELY(cmap)) { @@ -583,18 +583,52 @@ getClientIcon (Client *c, guint width, guint height) ScreenInfo *screen_info; GdkPixbuf *icon_pixbuf; GdkPixbuf *icon_pixbuf_stated; + guint app_icon_width, app_icon_height; Pixmap pixmap; g_return_val_if_fail (c != NULL, NULL); screen_info = c->screen_info; icon_pixbuf = NULL; - pixmap = compositorGetWindowPixmap (screen_info, c->frame); + app_icon_width = width; /* Set to 0 to use gdk pixbuf scaling */ + app_icon_height = height; /* Set to 0 to use gdk pixbuf scaling */ + + pixmap = compositorGetWindowPixmapAtSize (screen_info, c->frame, &app_icon_width, &app_icon_height); if (pixmap != None) { - icon_pixbuf = try_pixmap_and_mask (screen_info, pixmap, None, width, height); + GdkPixbuf *app_content; + GdkPixbuf *small_icon; + guint small_icon_size; + + icon_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, width, height); + gdk_pixbuf_fill (icon_pixbuf, 0x00); + + app_content = try_pixmap_and_mask (screen_info, pixmap, None, width, height); + XFreePixmap (myScreenGetXDisplay (screen_info), pixmap); + + app_icon_width = (guint) gdk_pixbuf_get_width (app_content); + app_icon_height = (guint) gdk_pixbuf_get_height (app_content); + + gdk_pixbuf_copy_area (app_content, 0, 0, app_icon_width, app_icon_height, icon_pixbuf, + (width - app_icon_width) / 2, (height - app_icon_height) / 2); + g_object_unref (app_content); + + small_icon_size = MIN (width / 4, height / 4); + small_icon_size = MIN (small_icon_size, 48); + + small_icon = getAppIcon (screen_info, c->window, small_icon_size, small_icon_size); + + gdk_pixbuf_composite (small_icon, icon_pixbuf, + (width - small_icon_size) / 2, height - small_icon_size, + small_icon_size, small_icon_size, + (width - small_icon_size) / 2, height - small_icon_size, + 1.0, 1.0, + GDK_INTERP_BILINEAR, + 0xff); + + g_object_unref (small_icon); } - if (!icon_pixbuf) + else { icon_pixbuf = getAppIcon (screen_info, c->window, width, height); } -- cgit v1.2.1