summaryrefslogtreecommitdiff
path: root/applets/wncklet/window-list.c
diff options
context:
space:
mode:
authorVictor Kareh <[email protected]>2020-12-03 17:26:33 -0500
committerRobert Antoni Buj Gelonch <[email protected]>2020-12-08 11:08:07 +0100
commit0b455a79b90f84b1fa26926b77ef3c41d592fb21 (patch)
treee7e140068f50356a03d202a4c932ca6e0172f376 /applets/wncklet/window-list.c
parente285d049120f48284b6e71cdb34a6fe477db043d (diff)
downloadmate-panel-0b455a79b90f84b1fa26926b77ef3c41d592fb21.tar.bz2
mate-panel-0b455a79b90f84b1fa26926b77ef3c41d592fb21.tar.xz
window-list: Render thumbnails as cairo surfaces
This allows thumbnail previews to be properly rendered on HiDPI displays and ensures that the window surface is flushed before painting it.
Diffstat (limited to 'applets/wncklet/window-list.c')
-rw-r--r--applets/wncklet/window-list.c81
1 files changed, 51 insertions, 30 deletions
diff --git a/applets/wncklet/window-list.c b/applets/wncklet/window-list.c
index 6038400e..4708d56c 100644
--- a/applets/wncklet/window-list.c
+++ b/applets/wncklet/window-list.c
@@ -237,14 +237,14 @@ static void applet_change_background(MatePanelApplet* applet, MatePanelAppletBac
#ifdef HAVE_X11
#ifdef HAVE_WINDOW_PREVIEWS
-static GdkPixbuf *preview_window_thumbnail (WnckWindow *wnck_window, TasklistData *tasklist)
+static cairo_surface_t *preview_window_thumbnail (WnckWindow *wnck_window, TasklistData *tasklist)
{
GdkWindow *window;
- GdkPixbuf *screenshot;
- GdkPixbuf *thumbnail;
+ cairo_surface_t *screenshot;
+ cairo_surface_t *thumbnail;
+ cairo_t *cr;
double ratio;
- int width, height;
- int scale;
+ int width, height, scale;
window = gdk_x11_window_foreign_new_for_display (gdk_display_get_default (), wnck_window_get_xid (wnck_window));
@@ -255,50 +255,71 @@ static GdkPixbuf *preview_window_thumbnail (WnckWindow *wnck_window, TasklistDat
width = gdk_window_get_width (window) * scale;
height = gdk_window_get_height (window) * scale;
- /* Generate window screenshot for preview */
- screenshot = gdk_pixbuf_get_from_window (window, 0, 0, width / scale, height / scale);
+ /* Get reference to GdkWindow surface */
+ cairo_t *win_cr = gdk_cairo_create (window);
+ cairo_surface_t *win_surface = cairo_get_target (win_cr);
+ /* Flush to ensure all writing to the image was done */
+ cairo_surface_flush (win_surface);
+ cairo_destroy (win_cr);
+
+ /* Create screenshot surface with the GdkWindow as its source */
+ screenshot = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
+ cairo_surface_set_device_scale (screenshot, scale, scale);
+ cr = cairo_create (screenshot);
+ cairo_set_source_surface (cr, win_surface, 0, 0);
+ cairo_paint (cr);
+
+ /* Mark the image dirty so Cairo clears its caches */
+ cairo_surface_mark_dirty (win_surface);
+
+ cairo_destroy (cr);
g_object_unref (window);
if (screenshot == NULL)
return NULL;
- /* Determine whether the contents of the screenshot are empty */
- if (gdk_pixbuf_get_byte_length (screenshot) == 0)
- {
- g_object_unref (screenshot);
- return NULL;
- }
-
/* Scale to configured size while maintaining aspect ratio */
if (width > height)
{
- ratio = (double) height / (double) width;
- width = MIN(width, tasklist->thumbnail_size);
- height = width * ratio;
+ int max_size = MIN (width, tasklist->thumbnail_size);
+ ratio = (double) max_size / (double) width;
+ width = max_size;
+ height = (int) ((double) height * ratio);
}
else
{
- ratio = (double) width / (double) height;
- height = MIN(height, tasklist->thumbnail_size);
- width = height * ratio;
+ int max_size = MIN (height, tasklist->thumbnail_size);
+ ratio = (double) max_size / (double) height;
+ height = max_size;
+ width = (int) ((double) width * ratio);
}
- thumbnail = gdk_pixbuf_scale_simple (screenshot, width, height, GDK_INTERP_BILINEAR);
- g_object_unref (screenshot);
+ thumbnail = cairo_surface_create_similar (screenshot,
+ cairo_surface_get_content (screenshot),
+ width, height);
+
+ cr = cairo_create (thumbnail);
+ cairo_scale (cr, scale * ratio, scale * ratio);
+ cairo_set_source_surface (cr, screenshot, 0, 0);
+ cairo_paint (cr);
+
+ cairo_destroy (cr);
+ cairo_surface_destroy (screenshot);
return thumbnail;
}
#define PREVIEW_PADDING 5
-static void preview_window_reposition (TasklistData *tasklist, GdkPixbuf *thumbnail)
+static void preview_window_reposition (TasklistData *tasklist, cairo_surface_t *thumbnail)
{
GdkMonitor *monitor;
GdkRectangle monitor_geom;
int x_pos, y_pos;
- int width, height;
+ int width, height, scale;
- width = gdk_pixbuf_get_width (thumbnail);
- height = gdk_pixbuf_get_height (thumbnail);
+ scale = gtk_widget_get_scale_factor (tasklist->preview);
+ width = cairo_image_surface_get_width (thumbnail) / scale;
+ height = cairo_image_surface_get_height (thumbnail) / scale;
/* Resize window to fit thumbnail */
gtk_window_resize (GTK_WINDOW (tasklist->preview), width, height);
@@ -332,19 +353,19 @@ static void preview_window_reposition (TasklistData *tasklist, GdkPixbuf *thumbn
gtk_window_move (GTK_WINDOW (tasklist->preview), x_pos, y_pos);
}
-static gboolean preview_window_draw (GtkWidget *widget, cairo_t *cr, GdkPixbuf *thumbnail)
+static gboolean preview_window_draw (GtkWidget *widget, cairo_t *cr, cairo_surface_t *thumbnail)
{
GtkStyleContext *context;
context = gtk_widget_get_style_context (widget);
- gtk_render_icon (context, cr, thumbnail, 0, 0);
+ gtk_render_icon_surface (context, cr, thumbnail, 0, 0);
return FALSE;
}
static gboolean applet_enter_notify_event (WnckTasklist *tl, GList *wnck_windows, TasklistData *tasklist)
{
- GdkPixbuf *thumbnail;
+ cairo_surface_t *thumbnail;
WnckWindow *wnck_window = NULL;
int n_windows;
@@ -389,7 +410,7 @@ static gboolean applet_enter_notify_event (WnckTasklist *tl, GList *wnck_windows
gtk_widget_show (tasklist->preview);
- g_signal_connect_data (G_OBJECT (tasklist->preview), "draw", G_CALLBACK (preview_window_draw), thumbnail, (GClosureNotify) G_CALLBACK (g_object_unref), 0);
+ g_signal_connect_data (G_OBJECT (tasklist->preview), "draw", G_CALLBACK (preview_window_draw), thumbnail, (GClosureNotify) G_CALLBACK (cairo_surface_destroy), 0);
return FALSE;
}