summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVictor Kareh <[email protected]>2019-10-14 10:49:07 -0400
committerVictor Kareh <[email protected]>2019-10-27 13:42:15 -0400
commita74cd3d8406e54a68868bc69f4117c3c25cf1f40 (patch)
tree1a1e3178233387056535d001cab7003ae7c5af12
parent621223f9180936e946b8a89b37d4b106187a6d41 (diff)
downloadmarco-a74cd3d8406e54a68868bc69f4117c3c25cf1f40.tar.bz2
marco-a74cd3d8406e54a68868bc69f4117c3c25cf1f40.tar.xz
tabpopup: Render window thumbnail as cairo surface
Instead of converting from surface to a GdkPixbuf and then back to a surface, we keep it as a surface for the entire manipulation flow. This improves rendering speed a bit and sets the ground for a higher resolution thumbnail in the future.
-rw-r--r--src/core/screen.c178
-rw-r--r--src/include/tabpopup.h1
-rw-r--r--src/ui/tabpopup.c30
3 files changed, 118 insertions, 91 deletions
diff --git a/src/core/screen.c b/src/core/screen.c
index 49e50506..78a41d83 100644
--- a/src/core/screen.c
+++ b/src/core/screen.c
@@ -48,6 +48,7 @@
#endif
#include <X11/Xatom.h>
+#include <cairo/cairo-xlib.h>
#include <locale.h>
#include <string.h>
#include <stdio.h>
@@ -1212,60 +1213,60 @@ meta_screen_update_cursor (MetaScreen *screen)
XFreeCursor (screen->display->xdisplay, xcursor);
}
-#define MAX_PREVIEW_SCALE 10.0
+#define MAX_PREVIEW_SCREEN_FRACTION 0.33
+#define MAX_PREVIEW_SIZE 300
-static GdkPixbuf *
-get_window_pixbuf (MetaWindow *window,
- int *width,
- int *height)
+static cairo_surface_t *
+get_window_surface (MetaWindow *window)
{
- MetaDisplay *display;
- cairo_surface_t *surface;
- GdkPixbuf *pixbuf, *scaled;
+ cairo_surface_t *surface, *scaled;
+ cairo_t *cr;
const MetaXineramaScreenInfo *current;
+ int width, height, max_columns, max_size;
double ratio;
- display = window->display;
- surface = meta_compositor_get_window_surface (window->display->compositor,
- window);
- if (surface == None)
- return NULL;
-
- meta_error_trap_push (display);
-
- pixbuf = meta_ui_get_pixbuf_from_surface (surface);
- cairo_surface_destroy (surface);
-
- if (meta_error_trap_pop_with_return (display, FALSE) != Success)
- g_clear_object (&pixbuf);
+ surface = meta_compositor_get_window_surface (window->display->compositor, window);
- if (pixbuf == NULL)
+ if (surface == NULL)
return NULL;
- *width = gdk_pixbuf_get_width (pixbuf);
- *height = gdk_pixbuf_get_height (pixbuf);
+ width = cairo_xlib_surface_get_width (surface);
+ height = cairo_xlib_surface_get_height (surface);
current = meta_screen_get_current_xinerama (window->screen);
+ max_columns = meta_prefs_get_alt_tab_max_columns ();
- /* Scale pixbuf to max dimension based on monitor size */
- if (*width > *height)
+ /* Scale surface to fit current screen */
+ if (width > height)
{
- int max_preview_width = current->rect.width / MAX_PREVIEW_SCALE;
- ratio = ((double) *width) / max_preview_width;
- *width = (int) max_preview_width;
- *height = (int) (((double) *height) / ratio);
+ max_size = MIN (MAX_PREVIEW_SIZE, current->rect.width / max_columns * MAX_PREVIEW_SCREEN_FRACTION);
+ ratio = ((double) width) / max_size;
+ width = (int) max_size;
+ height = (int) (((double) height) / ratio);
}
else
{
- int max_preview_height = current->rect.height / MAX_PREVIEW_SCALE;
- ratio = ((double) *height) / max_preview_height;
- *height = (int) max_preview_height;
- *width = (int) (((double) *width) / ratio);
+ max_size = MIN (MAX_PREVIEW_SIZE, current->rect.height / max_columns * MAX_PREVIEW_SCREEN_FRACTION);
+ ratio = ((double) height) / max_size;
+ height = (int) max_size;
+ width = (int) (((double) width) / ratio);
}
- scaled = gdk_pixbuf_scale_simple (pixbuf, *width, *height,
- GDK_INTERP_BILINEAR);
- g_object_unref (pixbuf);
+ meta_error_trap_push (window->display);
+ scaled = cairo_surface_create_similar (surface,
+ cairo_surface_get_content (surface),
+ width, height);
+ if (meta_error_trap_pop_with_return (window->display, FALSE) != Success)
+ return NULL;
+
+ cr = cairo_create (scaled);
+ cairo_scale (cr, 1/ratio, 1/ratio);
+ cairo_set_source_surface (cr, surface, 0, 0);
+ cairo_paint (cr);
+
+ cairo_destroy (cr);
+ cairo_surface_destroy (surface);
+
return scaled;
}
@@ -1280,6 +1281,7 @@ meta_screen_ensure_tab_popup (MetaScreen *screen,
int len;
int i;
gint border;
+ int scale;
if (screen->tab_popup)
return;
@@ -1290,11 +1292,13 @@ meta_screen_ensure_tab_popup (MetaScreen *screen,
screen->active_workspace);
len = g_list_length (tab_list);
+ scale = gdk_window_get_scale_factor (gdk_get_default_root_window ());
entries = g_new (MetaTabEntry, len + 1);
entries[len].key = NULL;
entries[len].title = NULL;
entries[len].icon = NULL;
+ entries[len].win_surface = NULL;
border = meta_prefs_show_tab_border() ? BORDER_OUTLINE_TAB |
BORDER_OUTLINE_WINDOW : BORDER_OUTLINE_TAB;
@@ -1304,59 +1308,64 @@ meta_screen_ensure_tab_popup (MetaScreen *screen,
{
MetaWindow *window;
MetaRectangle r;
- GdkPixbuf *win_pixbuf = NULL;
- int width = 0, height = 0;
window = tmp->data;
entries[i].key = (MetaTabEntryKey) window->xwindow;
entries[i].title = window->title;
+ entries[i].win_surface = NULL;
- /* Only get the pixbuf if the user does NOT have
- compositing-fast-alt-tab-set to true
- in GSettings. There is an obvious lag when the pixbuf is
- retrieved. */
- if (!meta_prefs_get_compositing_fast_alt_tab())
- win_pixbuf = get_window_pixbuf (window, &width, &height);
+ entries[i].icon = g_object_ref (window->icon);
- if (win_pixbuf == NULL)
- entries[i].icon = g_object_ref (window->icon);
- else
+ /* Only get the window thumbnail surface if the user has a compositor
+ * enabled and does NOT have compositing-fast-alt-tab-set to true in
+ * GSettings. There is an obvious lag when the surface is retrieved. */
+ if (meta_prefs_get_compositing_manager() && !meta_prefs_get_compositing_fast_alt_tab())
{
- int icon_width, icon_height, t_width, t_height;
+ cairo_surface_t *win_surface;
+
+ /* Get window thumbnail */
+ win_surface = get_window_surface (window);
+
+ if (win_surface != NULL)
+ {
+ cairo_surface_t *surface, *icon;
+ cairo_t *cr;
+ int width, height, icon_width, icon_height;
+
#define ICON_OFFSET 6
- icon_width = gdk_pixbuf_get_width (window->icon);
- icon_height = gdk_pixbuf_get_height (window->icon);
-
- t_width = width + ICON_OFFSET;
- t_height = height + ICON_OFFSET;
-
- entries[i].icon = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
- t_width, t_height);
- gdk_pixbuf_fill (entries[i].icon, 0x00000000);
- gdk_pixbuf_copy_area (win_pixbuf, 0, 0, width, height,
- entries[i].icon, 0, 0);
- g_object_unref (win_pixbuf);
-
- double icon_scale = 1.0;
- double max_coverage = 0.9;
-
- if (icon_width > t_width * max_coverage)
- icon_scale = (t_width * max_coverage) / icon_width;
-
- if (icon_height * icon_scale > t_height * max_coverage)
- icon_scale = (t_height * max_coverage) / icon_height;
-
- int t_icon_width = (int)(icon_width * icon_scale);
- int t_icon_height = (int)(icon_height * icon_scale);
-
- gdk_pixbuf_composite (window->icon, entries[i].icon,
- t_width - t_icon_width,
- t_height - t_icon_height,
- t_icon_width, t_icon_height,
- t_width - t_icon_width, t_height - t_icon_height,
- icon_scale, icon_scale, GDK_INTERP_BILINEAR, 255);
+ width = cairo_xlib_surface_get_width (win_surface);
+ height = cairo_xlib_surface_get_height (win_surface);
+
+ /* Create a new surface to overlap the window icon into */
+ surface = cairo_surface_create_similar (win_surface,
+ cairo_surface_get_content (win_surface),
+ width, height);
+
+ cr = cairo_create (surface);
+ cairo_set_source_surface (cr, win_surface, 0, 0);
+ cairo_paint (cr);
+
+ /* Get the window icon as a surface */
+ icon = gdk_cairo_surface_create_from_pixbuf (window->icon, scale, NULL);
+
+ icon_width = cairo_image_surface_get_width (icon) / scale;
+ icon_height = cairo_image_surface_get_height (icon) / scale;
+
+ /* Overlap the window icon surface over the window thumbnail */
+ cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
+ cairo_set_source_surface (cr, icon,
+ width - icon_width - ICON_OFFSET,
+ height - icon_height - ICON_OFFSET);
+ cairo_paint (cr);
+
+ entries[i].win_surface = surface;
+
+ cairo_destroy (cr);
+ cairo_surface_destroy (icon);
+ cairo_surface_destroy (win_surface);
+ }
}
entries[i].blank = FALSE;
@@ -1403,7 +1412,11 @@ meta_screen_ensure_tab_popup (MetaScreen *screen,
border);
for (i = 0; i < len; i++)
- g_object_unref (entries[i].icon);
+ {
+ g_object_unref (entries[i].icon);
+ if (entries[i].win_surface)
+ cairo_surface_destroy (entries[i].win_surface);
+ }
g_free (entries);
@@ -1437,6 +1450,7 @@ meta_screen_ensure_workspace_popup (MetaScreen *screen)
entries[len].key = NULL;
entries[len].title = NULL;
entries[len].icon = NULL;
+ entries[len].win_surface = NULL;
i = 0;
while (i < len)
@@ -1451,6 +1465,7 @@ meta_screen_ensure_workspace_popup (MetaScreen *screen)
entries[i].key = (MetaTabEntryKey) workspace;
entries[i].title = meta_workspace_get_name (workspace);
entries[i].icon = NULL;
+ entries[i].win_surface = NULL;
entries[i].blank = FALSE;
g_assert (entries[i].title != NULL);
@@ -1460,6 +1475,7 @@ meta_screen_ensure_workspace_popup (MetaScreen *screen)
entries[i].key = NULL;
entries[i].title = NULL;
entries[i].icon = NULL;
+ entries[i].win_surface = NULL;
entries[i].blank = TRUE;
}
entries[i].hidden = FALSE;
diff --git a/src/include/tabpopup.h b/src/include/tabpopup.h
index 447264e1..19e8621b 100644
--- a/src/include/tabpopup.h
+++ b/src/include/tabpopup.h
@@ -49,6 +49,7 @@ struct _MetaTabEntry
MetaTabEntryKey key;
const char *title;
GdkPixbuf *icon;
+ cairo_surface_t *win_surface;
MetaRectangle rect;
MetaRectangle inner_rect;
guint blank : 1;
diff --git a/src/ui/tabpopup.c b/src/ui/tabpopup.c
index 013700ed..06ee84e9 100644
--- a/src/ui/tabpopup.c
+++ b/src/ui/tabpopup.c
@@ -50,6 +50,7 @@ struct _TabEntry
gint grid_left;
gint grid_top;
GdkPixbuf *icon, *dimmed_icon;
+ cairo_surface_t *win_surface;
GtkWidget *widget;
GdkRectangle rect;
GdkRectangle inner_rect;
@@ -68,7 +69,7 @@ struct _MetaTabPopup
gint border;
};
-static GtkWidget* selectable_image_new (GdkPixbuf *pixbuf);
+static GtkWidget* selectable_image_new (GdkPixbuf *pixbuf, cairo_surface_t *win_surface);
static void select_image (GtkWidget *widget);
static void unselect_image (GtkWidget *widget);
@@ -203,6 +204,7 @@ tab_entry_new (const MetaTabEntry *entry,
}
te->widget = NULL;
te->icon = entry->icon;
+ te->win_surface = entry->win_surface;
te->blank = entry->blank;
te->dimmed_icon = NULL;
if (te->icon)
@@ -373,11 +375,11 @@ meta_ui_tab_popup_new (const MetaTabEntry *entries,
{
if (te->dimmed_icon)
{
- image = selectable_image_new (te->dimmed_icon);
+ image = selectable_image_new (te->dimmed_icon, NULL);
}
else
{
- image = selectable_image_new (te->icon);
+ image = selectable_image_new (te->icon, te->win_surface);
}
gtk_misc_set_padding (GTK_MISC (image),
@@ -751,19 +753,27 @@ struct _MetaSelectImageClass
static GType meta_select_image_get_type (void) G_GNUC_CONST;
static GtkWidget*
-selectable_image_new (GdkPixbuf *pixbuf)
+selectable_image_new (GdkPixbuf *pixbuf, cairo_surface_t *win_surface)
{
GtkWidget *widget;
- int scale;
- cairo_surface_t *surface;
widget = g_object_new (meta_select_image_get_type (), NULL);
- scale = gtk_widget_get_scale_factor (widget);
- surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, scale, NULL);
- gtk_image_set_from_surface (GTK_IMAGE (widget), surface);
+ if (win_surface == NULL)
+ {
+ int scale;
+ cairo_surface_t *surface;
+
+ scale = gtk_widget_get_scale_factor (widget);
+ surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, scale, NULL);
+
+ gtk_image_set_from_surface (GTK_IMAGE (widget), surface);
+
+ cairo_surface_destroy (surface);
+ }
+ else
+ gtk_image_set_from_surface (GTK_IMAGE (widget), win_surface);
- cairo_surface_destroy (surface);
return widget;
}