summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOlivier Fourdan <fourdan@xfce.org>2015-02-05 21:24:49 +0100
committerOlivier Fourdan <fourdan@xfce.org>2015-02-05 21:59:10 +0100
commit6a7aff593d752da525aba0098572a2d9d20d0e86 (patch)
treeb2e01e7e95a07cd48c07b422987a1b589cbb7e17
parent21486cab4e78f70949319bf911648e9554708b0f (diff)
downloadxfwm4-6a7aff593d752da525aba0098572a2d9d20d0e86.tar.gz
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 <fourdan@xfce.org>
-rw-r--r--src/compositor.c111
-rw-r--r--src/compositor.h6
-rw-r--r--src/icons.c46
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);
}