diff options
author | Victor Kareh <[email protected]> | 2020-12-03 17:26:33 -0500 |
---|---|---|
committer | Robert Antoni Buj Gelonch <[email protected]> | 2020-12-08 11:08:07 +0100 |
commit | 0b455a79b90f84b1fa26926b77ef3c41d592fb21 (patch) | |
tree | e7e140068f50356a03d202a4c932ca6e0172f376 /applets/wncklet/window-list.c | |
parent | e285d049120f48284b6e71cdb34a6fe477db043d (diff) | |
download | mate-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.c | 81 |
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; } |