libwnck3/libwnck_0002-icons-Use-cairo-surfaces-to-render-icons_43.patch
2022-09-19 17:56:43 +02:00

1325 lines
44 KiB
Diff

From 882fab71ee0260b1b70cb53edbc2bd2e9d35ebd3 Mon Sep 17 00:00:00 2001
From: Victor Kareh <vkareh@redhat.com>
Date: Fri, 27 Nov 2020 11:25:08 -0500
Subject: [PATCH 2/5] icons: Use cairo surfaces to render icons
This replaces GdkPixbuf manipulation with the cairo_surface equivalents.
As a result, icons can now render sharply in HiDPI displays.
---
libwnck/application.c | 151 ++++++++++++++++++---
libwnck/application.h | 3 +
libwnck/class-group.c | 172 +++++++++++++++++++-----
libwnck/class-group.h | 3 +
libwnck/pager.c | 20 +--
libwnck/selector.c | 103 +++++++--------
libwnck/tasklist.c | 173 ++++++++++++-------------
libwnck/window.c | 139 +++++++++++++++++---
libwnck/window.h | 3 +
libwnck/wnck-image-menu-item-private.h | 3 +
libwnck/wnck-image-menu-item.c | 8 ++
11 files changed, 556 insertions(+), 222 deletions(-)
diff --git a/libwnck/application.c b/libwnck/application.c
index 9ab7f48..d8283cc 100644
--- a/libwnck/application.c
+++ b/libwnck/application.c
@@ -62,8 +62,8 @@ struct _WnckApplicationPrivate
WnckWindow *name_window; /* window we are using name of */
- GdkPixbuf *icon;
- GdkPixbuf *mini_icon;
+ cairo_surface_t *icon;
+ cairo_surface_t *mini_icon;
WnckIconCache *icon_cache;
@@ -159,13 +159,8 @@ wnck_application_finalize (GObject *object)
g_free (application->priv->name);
application->priv->name = NULL;
- if (application->priv->icon)
- g_object_unref (G_OBJECT (application->priv->icon));
- application->priv->icon = NULL;
-
- if (application->priv->mini_icon)
- g_object_unref (G_OBJECT (application->priv->mini_icon));
- application->priv->mini_icon = NULL;
+ g_clear_pointer (&application->priv->icon, cairo_surface_destroy);
+ g_clear_pointer (&application->priv->mini_icon, cairo_surface_destroy);
_wnck_icon_cache_free (application->priv->icon_cache);
application->priv->icon_cache = NULL;
@@ -336,14 +331,20 @@ get_icons (WnckApplication *app)
{
app->priv->need_emit_icon_changed = TRUE;
- if (app->priv->icon)
- g_object_unref (G_OBJECT (app->priv->icon));
+ g_clear_pointer (&app->priv->icon, cairo_surface_destroy);
+ g_clear_pointer (&app->priv->mini_icon, cairo_surface_destroy);
- if (app->priv->mini_icon)
- g_object_unref (G_OBJECT (app->priv->mini_icon));
+ if (icon)
+ {
+ app->priv->icon = gdk_cairo_surface_create_from_pixbuf (icon, 0, NULL);
+ g_clear_object (&icon);
+ }
- app->priv->icon = icon;
- app->priv->mini_icon = mini_icon;
+ if (mini_icon)
+ {
+ app->priv->mini_icon = gdk_cairo_surface_create_from_pixbuf (mini_icon, 0, NULL);
+ g_clear_object (&mini_icon);
+ }
}
/* FIXME we should really fall back to using the icon
@@ -404,12 +405,39 @@ find_icon_window (WnckApplication *app)
GdkPixbuf*
wnck_application_get_icon (WnckApplication *app)
{
+ static const cairo_user_data_key_t app_icon_pixbuf_key;
+
g_return_val_if_fail (WNCK_IS_APPLICATION (app), NULL);
_wnck_application_load_icons (app);
if (app->priv->icon)
- return app->priv->icon;
+ {
+ GdkPixbuf *pixbuf;
+
+ pixbuf = cairo_surface_get_user_data (app->priv->icon, &app_icon_pixbuf_key);
+
+ if (pixbuf == NULL)
+ {
+ int scaling_factor;
+
+ pixbuf = gdk_pixbuf_get_from_surface (app->priv->icon,
+ 0,
+ 0,
+ cairo_image_surface_get_width (app->priv->icon),
+ cairo_image_surface_get_height (app->priv->icon));
+
+ scaling_factor = _wnck_get_window_scaling_factor ();
+ pixbuf = gdk_pixbuf_scale_simple (pixbuf,
+ gdk_pixbuf_get_width (pixbuf) / scaling_factor,
+ gdk_pixbuf_get_height (pixbuf) / scaling_factor,
+ GDK_INTERP_BILINEAR);
+
+ cairo_surface_set_user_data (app->priv->icon, &app_icon_pixbuf_key, pixbuf, g_object_unref);
+ }
+
+ return pixbuf;
+ }
else
{
WnckWindow *w = find_icon_window (app);
@@ -435,12 +463,39 @@ wnck_application_get_icon (WnckApplication *app)
GdkPixbuf*
wnck_application_get_mini_icon (WnckApplication *app)
{
+ static const cairo_user_data_key_t app_mini_icon_pixbuf_key;
+
g_return_val_if_fail (WNCK_IS_APPLICATION (app), NULL);
_wnck_application_load_icons (app);
if (app->priv->mini_icon)
- return app->priv->mini_icon;
+ {
+ GdkPixbuf *pixbuf;
+
+ pixbuf = cairo_surface_get_user_data (app->priv->mini_icon, &app_mini_icon_pixbuf_key);
+
+ if (pixbuf == NULL)
+ {
+ int scaling_factor;
+
+ pixbuf = gdk_pixbuf_get_from_surface (app->priv->mini_icon,
+ 0,
+ 0,
+ cairo_image_surface_get_width (app->priv->mini_icon),
+ cairo_image_surface_get_height (app->priv->mini_icon));
+
+ scaling_factor = _wnck_get_window_scaling_factor ();
+ pixbuf = gdk_pixbuf_scale_simple (pixbuf,
+ gdk_pixbuf_get_width (pixbuf) / scaling_factor,
+ gdk_pixbuf_get_height (pixbuf) / scaling_factor,
+ GDK_INTERP_BILINEAR);
+
+ cairo_surface_set_user_data (app->priv->mini_icon, &app_mini_icon_pixbuf_key, pixbuf, g_object_unref);
+ }
+
+ return pixbuf;
+ }
else
{
WnckWindow *w = find_icon_window (app);
@@ -451,6 +506,68 @@ wnck_application_get_mini_icon (WnckApplication *app)
}
}
+/**
+ * wnck_application_get_icon_surface:
+ * @app: a #WnckApplication.
+ *
+ * Gets the icon-surface to be used for @app. If no icon-surfaceis set for @app,
+ * a suboptimal heuristic is used to find an appropriate icon. If no icon-surface
+ * was found, a fallback icon-surface is used.
+ *
+ * Return value: (transfer full): a reference to the icon-surface for @app. The
+ * caller should unreference the <classname>cairo_surface_t</classname> once done
+ * with it.
+ **/
+cairo_surface_t*
+wnck_application_get_icon_surface (WnckApplication *app)
+{
+ g_return_val_if_fail (WNCK_IS_APPLICATION (app), NULL);
+
+ _wnck_application_load_icons (app);
+
+ if (app->priv->icon)
+ return cairo_surface_reference (app->priv->icon);
+ else
+ {
+ WnckWindow *w = find_icon_window (app);
+ if (w)
+ return wnck_window_get_icon_surface (w);
+ else
+ return NULL;
+ }
+}
+
+/**
+ * wnck_application_get_mini_icon_surface:
+ * @app: a #WnckApplication.
+ *
+ * Gets the mini-icon-surface to be used for @app. If no mini-icon-surfaceis set
+ * for @app, a suboptimal heuristic is used to find an appropriate icon. If no
+ * mini-icon-surface was found, a fallback mini-icon-surface is used.
+ *
+ * Return value: (transfer full): a reference to the mini-icon-surface for @app.
+ * The caller should unreference the <classname>cairo_surface_t</classname> once
+ * done with it.
+ **/
+cairo_surface_t*
+wnck_application_get_mini_icon_surface (WnckApplication *app)
+{
+ g_return_val_if_fail (WNCK_IS_APPLICATION (app), NULL);
+
+ _wnck_application_load_icons (app);
+
+ if (app->priv->mini_icon)
+ return cairo_surface_reference (app->priv->mini_icon);
+ else
+ {
+ WnckWindow *w = find_icon_window (app);
+ if (w)
+ return wnck_window_get_mini_icon_surface (w);
+ else
+ return NULL;
+ }
+}
+
/**
* wnck_application_get_icon_is_fallback:
* @app: a #WnckApplication
diff --git a/libwnck/application.h b/libwnck/application.h
index 40fe4c6..f3ea970 100644
--- a/libwnck/application.h
+++ b/libwnck/application.h
@@ -29,6 +29,7 @@
#include <glib-object.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <libwnck/screen.h>
+#include <cairo.h>
G_BEGIN_DECLS
@@ -92,6 +93,8 @@ const char* wnck_application_get_icon_name (WnckApplication *app);
int wnck_application_get_pid (WnckApplication *app);
GdkPixbuf* wnck_application_get_icon (WnckApplication *app);
GdkPixbuf* wnck_application_get_mini_icon (WnckApplication *app);
+cairo_surface_t* wnck_application_get_icon_surface (WnckApplication *app);
+cairo_surface_t* wnck_application_get_mini_icon_surface (WnckApplication *app);
gboolean wnck_application_get_icon_is_fallback (WnckApplication *app);
const char* wnck_application_get_startup_id (WnckApplication *app);
diff --git a/libwnck/class-group.c b/libwnck/class-group.c
index 46d1f24..e6c45d6 100644
--- a/libwnck/class-group.c
+++ b/libwnck/class-group.c
@@ -59,8 +59,8 @@ struct _WnckClassGroupPrivate {
GHashTable *window_icon_handlers;
GHashTable *window_name_handlers;
- GdkPixbuf *icon;
- GdkPixbuf *mini_icon;
+ cairo_surface_t *icon;
+ cairo_surface_t *mini_icon;
};
G_DEFINE_TYPE_WITH_PRIVATE (WnckClassGroup, wnck_class_group, G_TYPE_OBJECT);
@@ -171,17 +171,8 @@ wnck_class_group_finalize (GObject *object)
class_group->priv->window_name_handlers = NULL;
}
- if (class_group->priv->icon)
- {
- g_object_unref (class_group->priv->icon);
- class_group->priv->icon = NULL;
- }
-
- if (class_group->priv->mini_icon)
- {
- g_object_unref (class_group->priv->mini_icon);
- class_group->priv->mini_icon = NULL;
- }
+ g_clear_pointer (&class_group->priv->icon, cairo_surface_destroy);
+ g_clear_pointer (&class_group->priv->mini_icon, cairo_surface_destroy);
G_OBJECT_CLASS (wnck_class_group_parent_class)->finalize (object);
}
@@ -370,7 +361,8 @@ set_name (WnckClassGroup *class_group)
/* Walks the list of applications, trying to get an icon from them */
static void
-get_icons_from_applications (WnckClassGroup *class_group, GdkPixbuf **icon, GdkPixbuf **mini_icon)
+get_icons_from_applications (WnckClassGroup *class_group,
+ cairo_surface_t **icon, cairo_surface_t **mini_icon)
{
GList *l;
@@ -386,15 +378,15 @@ get_icons_from_applications (WnckClassGroup *class_group, GdkPixbuf **icon, GdkP
app = wnck_window_get_application (window);
if (app)
{
- *icon = wnck_application_get_icon (app);
- *mini_icon = wnck_application_get_mini_icon (app);
+ *icon = wnck_application_get_icon_surface (app);
+ *mini_icon = wnck_application_get_mini_icon_surface (app);
if (*icon && *mini_icon)
return;
else
{
- *icon = NULL;
- *mini_icon = NULL;
+ g_clear_pointer (icon, cairo_surface_destroy);
+ g_clear_pointer (mini_icon, cairo_surface_destroy);
}
}
}
@@ -402,7 +394,8 @@ get_icons_from_applications (WnckClassGroup *class_group, GdkPixbuf **icon, GdkP
/* Walks the list of windows, trying to get an icon from them */
static void
-get_icons_from_windows (WnckClassGroup *class_group, GdkPixbuf **icon, GdkPixbuf **mini_icon)
+get_icons_from_windows (WnckClassGroup *class_group,
+ cairo_surface_t **icon, cairo_surface_t **mini_icon)
{
GList *l;
@@ -415,15 +408,15 @@ get_icons_from_windows (WnckClassGroup *class_group, GdkPixbuf **icon, GdkPixbuf
window = WNCK_WINDOW (l->data);
- *icon = wnck_window_get_icon (window);
- *mini_icon = wnck_window_get_mini_icon (window);
+ *icon = wnck_window_get_icon_surface (window);
+ *mini_icon = wnck_window_get_mini_icon_surface (window);
if (*icon && *mini_icon)
return;
else
{
- *icon = NULL;
- *mini_icon = NULL;
+ g_clear_pointer (icon, cairo_surface_destroy);
+ g_clear_pointer (mini_icon, cairo_surface_destroy);
}
}
}
@@ -434,7 +427,7 @@ get_icons_from_windows (WnckClassGroup *class_group, GdkPixbuf **icon, GdkPixbuf
static void
set_icon (WnckClassGroup *class_group)
{
- GdkPixbuf *icon, *mini_icon;
+ cairo_surface_t *icon, *mini_icon;
gboolean icons_reffed = FALSE;
get_icons_from_applications (class_group, &icon, &mini_icon);
@@ -448,28 +441,39 @@ set_icon (WnckClassGroup *class_group)
handle = wnck_screen_get_handle (class_group->priv->screen);
- _wnck_get_fallback_icons (&icon,
+ GdkPixbuf *icon_pixbuf, *mini_icon_pixbuf;
+
+ _wnck_get_fallback_icons (&icon_pixbuf,
_wnck_handle_get_default_icon_size (handle),
- &mini_icon,
+ &mini_icon_pixbuf,
_wnck_handle_get_default_mini_icon_size (handle));
+ if (icon_pixbuf)
+ {
+ icon = gdk_cairo_surface_create_from_pixbuf (icon_pixbuf, 0, NULL);
+ g_clear_object (&icon_pixbuf);
+ }
+
+ if (mini_icon_pixbuf)
+ {
+ mini_icon = gdk_cairo_surface_create_from_pixbuf (mini_icon_pixbuf, 0, NULL);
+ g_clear_object (&mini_icon_pixbuf);
+ }
+
icons_reffed = TRUE;
}
g_assert (icon && mini_icon);
- if (class_group->priv->icon)
- g_object_unref (class_group->priv->icon);
-
- if (class_group->priv->mini_icon)
- g_object_unref (class_group->priv->mini_icon);
+ g_clear_pointer (&class_group->priv->icon, cairo_surface_destroy);
+ g_clear_pointer (&class_group->priv->mini_icon, cairo_surface_destroy);
class_group->priv->icon = icon;
class_group->priv->mini_icon = mini_icon;
if (!icons_reffed)
{
- g_object_ref (class_group->priv->icon);
- g_object_ref (class_group->priv->mini_icon);
+ cairo_surface_reference (class_group->priv->icon);
+ cairo_surface_reference (class_group->priv->mini_icon);
}
g_signal_emit (G_OBJECT (class_group), signals[ICON_CHANGED], 0);
@@ -702,9 +706,39 @@ wnck_class_group_get_name (WnckClassGroup *class_group)
GdkPixbuf *
wnck_class_group_get_icon (WnckClassGroup *class_group)
{
+ static const cairo_user_data_key_t class_group_icon_pixbuf_key;
+
g_return_val_if_fail (class_group != NULL, NULL);
- return class_group->priv->icon;
+ if (class_group->priv->icon)
+ {
+ GdkPixbuf *pixbuf;
+
+ pixbuf = cairo_surface_get_user_data (class_group->priv->icon, &class_group_icon_pixbuf_key);
+
+ if (pixbuf == NULL)
+ {
+ int scaling_factor;
+
+ pixbuf = gdk_pixbuf_get_from_surface (class_group->priv->icon,
+ 0,
+ 0,
+ cairo_image_surface_get_width (class_group->priv->icon),
+ cairo_image_surface_get_height (class_group->priv->icon));
+
+ scaling_factor = _wnck_get_window_scaling_factor ();
+ pixbuf = gdk_pixbuf_scale_simple (pixbuf,
+ gdk_pixbuf_get_width (pixbuf) / scaling_factor,
+ gdk_pixbuf_get_height (pixbuf) / scaling_factor,
+ GDK_INTERP_BILINEAR);
+
+ cairo_surface_set_user_data (class_group->priv->icon, &class_group_icon_pixbuf_key, pixbuf, g_object_unref);
+ }
+
+ return pixbuf;
+ }
+
+ return NULL;
}
/**
@@ -723,8 +757,76 @@ wnck_class_group_get_icon (WnckClassGroup *class_group)
**/
GdkPixbuf *
wnck_class_group_get_mini_icon (WnckClassGroup *class_group)
+{
+ static const cairo_user_data_key_t class_group_mini_icon_pixbuf_key;
+
+ g_return_val_if_fail (class_group != NULL, NULL);
+
+ if (class_group->priv->mini_icon)
+ {
+ GdkPixbuf *pixbuf;
+
+ pixbuf = cairo_surface_get_user_data (class_group->priv->mini_icon, &class_group_mini_icon_pixbuf_key);
+
+ if (pixbuf == NULL)
+ {
+ int scaling_factor;
+
+ pixbuf = gdk_pixbuf_get_from_surface (class_group->priv->mini_icon,
+ 0,
+ 0,
+ cairo_image_surface_get_width (class_group->priv->mini_icon),
+ cairo_image_surface_get_height (class_group->priv->mini_icon));
+
+ scaling_factor = _wnck_get_window_scaling_factor ();
+ pixbuf = gdk_pixbuf_scale_simple (pixbuf,
+ gdk_pixbuf_get_width (pixbuf) / scaling_factor,
+ gdk_pixbuf_get_height (pixbuf) / scaling_factor,
+ GDK_INTERP_BILINEAR);
+
+ cairo_surface_set_user_data (class_group->priv->mini_icon, &class_group_mini_icon_pixbuf_key, pixbuf, g_object_unref);
+ }
+
+ return pixbuf;
+ }
+
+ return NULL;
+}
+
+/**
+ * wnck_class_group_get_icon_surface:
+ * @class_group: a #WnckClassGroup.
+ *
+ * Gets the icon-surface to be used for @class_group. Since there is no way to
+ * properly find the icon-surface, the same suboptimal heuristic as the one for
+ * wnck_class_group_get_icon() is used to find it.
+ *
+ * Return value: (transfer full): the icon-surface for @class_group. The caller should
+ * unreference the returned <classname>cairo_surface_t</classname> once done with it.
+ **/
+cairo_surface_t *
+wnck_class_group_get_icon_surface (WnckClassGroup *class_group)
+{
+ g_return_val_if_fail (class_group != NULL, NULL);
+
+ return cairo_surface_reference (class_group->priv->icon);
+}
+
+/**
+ * wnck_class_group_get_mini_icon_surface:
+ * @class_group: a #WnckClassGroup.
+ *
+ * Gets the mini-icon-surface to be used for @class_group. Since there is no way to
+ * properly find the mini-icon-surface, the same suboptimal heuristic as the one for
+ * wnck_class_group_get_icon() is used to find it.
+ *
+ * Return value: (transfer full): the mini-icon-surface for @class_group. The caller should
+ * unreference the returned <classname>cairo_surface_t</classname> once done with it.
+ **/
+cairo_surface_t *
+wnck_class_group_get_mini_icon_surface (WnckClassGroup *class_group)
{
g_return_val_if_fail (class_group != NULL, NULL);
- return class_group->priv->mini_icon;
+ return cairo_surface_reference (class_group->priv->mini_icon);
}
diff --git a/libwnck/class-group.h b/libwnck/class-group.h
index 581cd22..122e0ed 100644
--- a/libwnck/class-group.h
+++ b/libwnck/class-group.h
@@ -30,6 +30,7 @@
#include <glib-object.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <libwnck/screen.h>
+#include <cairo.h>
G_BEGIN_DECLS
@@ -82,6 +83,8 @@ const char * wnck_class_group_get_name (WnckClassGroup *class_group);
GdkPixbuf *wnck_class_group_get_icon (WnckClassGroup *class_group);
GdkPixbuf *wnck_class_group_get_mini_icon (WnckClassGroup *class_group);
+cairo_surface_t *wnck_class_group_get_icon_surface (WnckClassGroup *class_group);
+cairo_surface_t *wnck_class_group_get_mini_icon_surface (WnckClassGroup *class_group);
#ifndef WNCK_DISABLE_DEPRECATED
G_DEPRECATED_FOR(wnck_class_group_get_id)
diff --git a/libwnck/pager.c b/libwnck/pager.c
index 4df766c..9b09928 100644
--- a/libwnck/pager.c
+++ b/libwnck/pager.c
@@ -984,8 +984,9 @@ draw_window (cairo_t *cr,
gboolean translucent)
{
GtkStyleContext *context;
- GdkPixbuf *icon;
+ cairo_surface_t *icon;
int icon_x, icon_y, icon_w, icon_h;
+ int scaling_factor;
gboolean is_active;
GdkRGBA fg;
gdouble translucency;
@@ -1015,14 +1016,15 @@ draw_window (cairo_t *cr,
cairo_pop_group_to_source (cr);
cairo_paint_with_alpha (cr, translucency);
- icon = wnck_window_get_icon (win);
+ icon = wnck_window_get_icon_surface (win);
icon_w = icon_h = 0;
+ scaling_factor = gtk_widget_get_scale_factor (widget);
if (icon)
{
- icon_w = gdk_pixbuf_get_width (icon);
- icon_h = gdk_pixbuf_get_height (icon);
+ icon_w = cairo_image_surface_get_width (icon) / scaling_factor;
+ icon_h = cairo_image_surface_get_height (icon) / scaling_factor;
/* If the icon is too big, fall back to mini icon.
* We don't arbitrarily scale the icon, because it's
@@ -1031,11 +1033,12 @@ draw_window (cairo_t *cr,
if (icon_w > (winrect->width - 2) ||
icon_h > (winrect->height - 2))
{
- icon = wnck_window_get_mini_icon (win);
+ cairo_surface_destroy (icon);
+ icon = wnck_window_get_mini_icon_surface (win);
if (icon)
{
- icon_w = gdk_pixbuf_get_width (icon);
- icon_h = gdk_pixbuf_get_height (icon);
+ icon_w = cairo_image_surface_get_width (icon) / scaling_factor;
+ icon_h = cairo_image_surface_get_height (icon) / scaling_factor;
/* Give up. */
if (icon_w > (winrect->width - 2) ||
@@ -1051,7 +1054,7 @@ draw_window (cairo_t *cr,
icon_y = winrect->y + (winrect->height - icon_h) / 2;
cairo_push_group (cr);
- gtk_render_icon (context, cr, icon, icon_x, icon_y);
+ gtk_render_icon_surface (context, cr, icon, icon_x, icon_y);
cairo_pop_group_to_source (cr);
cairo_paint_with_alpha (cr, translucency);
}
@@ -1072,6 +1075,7 @@ draw_window (cairo_t *cr,
cairo_stroke (cr);
gtk_style_context_restore (context);
+ cairo_surface_destroy (icon);
}
static WnckWindow *
diff --git a/libwnck/selector.c b/libwnck/selector.c
index 4cf6189..fcc3322 100644
--- a/libwnck/selector.c
+++ b/libwnck/selector.c
@@ -135,103 +135,96 @@ wnck_selector_get_screen (WnckSelector *selector)
gdk_x11_screen_get_screen_number (screen));
}
-static GdkPixbuf *
+static cairo_surface_t *
wnck_selector_get_default_window_icon (void)
{
- static GdkPixbuf *retval = NULL;
+ static cairo_surface_t *retval = NULL;
+ GdkPixbuf *pixbuf;
if (retval)
return retval;
- retval = gdk_pixbuf_new_from_resource ("/org/gnome/libwnck/default_icon.png", NULL);
+ pixbuf = gdk_pixbuf_new_from_resource ("/org/gnome/libwnck/default_icon.png", NULL);
- g_assert (retval);
+ g_assert (pixbuf);
+
+ retval = gdk_cairo_surface_create_from_pixbuf (pixbuf, 0, NULL);
+
+ g_object_unref (pixbuf);
return retval;
}
-static GdkPixbuf *
-wnck_selector_dimm_icon (GdkPixbuf *pixbuf)
+static void
+wnck_selector_dimm_icon (cairo_t *cr, cairo_surface_t *surface)
{
- int x, y, pixel_stride, row_stride;
- guchar *row, *pixels;
- int w, h;
- GdkPixbuf *dimmed;
+ cairo_surface_t *temp;
+ cairo_t *temp_cr;
- w = gdk_pixbuf_get_width (pixbuf);
- h = gdk_pixbuf_get_height (pixbuf);
+ g_assert (surface != NULL);
+ g_assert (cairo_surface_get_content (surface) != CAIRO_CONTENT_COLOR);
- if (gdk_pixbuf_get_has_alpha (pixbuf))
- dimmed = gdk_pixbuf_copy (pixbuf);
- else
- dimmed = gdk_pixbuf_add_alpha (pixbuf, FALSE, 0, 0, 0);
+ temp = cairo_surface_create_similar (surface,
+ cairo_surface_get_content (surface),
+ cairo_image_surface_get_width (surface),
+ cairo_image_surface_get_height (surface));
- pixel_stride = 4;
+ temp_cr = cairo_create (temp);
- row = gdk_pixbuf_get_pixels (dimmed);
- row_stride = gdk_pixbuf_get_rowstride (dimmed);
+ cairo_set_source_surface (temp_cr, surface, 0, 0);
+ cairo_paint_with_alpha (temp_cr, 0.5);
- for (y = 0; y < h; y++)
- {
- pixels = row;
- for (x = 0; x < w; x++)
- {
- pixels[3] /= 2;
- pixels += pixel_stride;
- }
- row += row_stride;
- }
+ cairo_set_operator (cr, CAIRO_OPERATOR_IN);
+ cairo_set_source_surface (cr, temp, 0, 0);
+ cairo_paint (cr);
- return dimmed;
+ cairo_destroy (temp_cr);
+ cairo_surface_destroy (temp);
}
void
_wnck_selector_set_window_icon (GtkWidget *image,
WnckWindow *window)
{
- GdkPixbuf *pixbuf, *freeme, *freeme2;
- int width, height;
+ cairo_surface_t *orig, *surface;
+ cairo_t *cr;
+ int scaling_factor;
int icon_size = -1;
- pixbuf = NULL;
- freeme = NULL;
- freeme2 = NULL;
+ orig = NULL;
+ surface = NULL;
if (window)
- pixbuf = wnck_window_get_mini_icon (window);
+ orig = wnck_window_get_mini_icon_surface (window);
- if (!pixbuf)
- pixbuf = wnck_selector_get_default_window_icon ();
+ if (!orig)
+ orig = wnck_selector_get_default_window_icon ();
if (icon_size == -1)
gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, NULL, &icon_size);
- width = gdk_pixbuf_get_width (pixbuf);
- height = gdk_pixbuf_get_height (pixbuf);
+ surface = cairo_surface_create_similar_image (orig,
+ cairo_image_surface_get_format (orig),
+ cairo_image_surface_get_width (orig),
+ cairo_image_surface_get_height (orig));
- if (icon_size != -1 && (width > icon_size || height > icon_size))
- {
- double scale;
+ scaling_factor = _wnck_get_window_scaling_factor ();
+ cairo_surface_set_device_scale (surface, (double)scaling_factor, (double)scaling_factor);
- scale = ((double) icon_size) / MAX (width, height);
+ cr = cairo_create (surface);
- pixbuf = gdk_pixbuf_scale_simple (pixbuf, width * scale,
- height * scale, GDK_INTERP_BILINEAR);
- freeme = pixbuf;
- }
+ cairo_set_source_surface (cr, orig, 0, 0);
+ cairo_paint (cr);
if (window && wnck_window_is_minimized (window))
{
- pixbuf = wnck_selector_dimm_icon (pixbuf);
- freeme2 = pixbuf;
+ wnck_selector_dimm_icon (cr, surface);
}
- gtk_image_set_from_pixbuf (GTK_IMAGE (image), pixbuf);
+ gtk_image_set_from_surface (GTK_IMAGE (image), surface);
- if (freeme)
- g_object_unref (freeme);
- if (freeme2)
- g_object_unref (freeme2);
+ cairo_destroy (cr);
+ cairo_surface_destroy (surface);
}
static void
diff --git a/libwnck/tasklist.c b/libwnck/tasklist.c
index b773247..10c6cc8 100644
--- a/libwnck/tasklist.c
+++ b/libwnck/tasklist.c
@@ -289,11 +289,11 @@ static WnckTask *wnck_task_new_from_startup_sequence (WnckTasklist *tasklis
#endif
static gboolean wnck_task_get_needs_attention (WnckTask *task);
+static cairo_surface_t *wnck_task_get_icon (WnckTask *task);
static char *wnck_task_get_text (WnckTask *task,
gboolean icon_text,
gboolean include_state);
-static GdkPixbuf *wnck_task_get_icon (WnckTask *task);
static gint wnck_task_compare_alphabetically (gconstpointer a,
gconstpointer b);
static gint wnck_task_compare (gconstpointer a,
@@ -637,10 +637,10 @@ wnck_button_set_handle (WnckButton *self,
}
static void
-wnck_button_set_image_from_pixbuf (WnckButton *self,
- GdkPixbuf *pixbuf)
+wnck_button_set_image_from_surface (WnckButton *self,
+ cairo_surface_t *surface)
{
- gtk_image_set_from_pixbuf (GTK_IMAGE (self->image), pixbuf);
+ gtk_image_set_from_surface (GTK_IMAGE (self->image), surface);
}
static void
@@ -3533,7 +3533,7 @@ wnck_task_popup_menu (WnckTask *task,
GtkWidget *menu;
WnckTask *win_task;
char *text;
- GdkPixbuf *pixbuf;
+ cairo_surface_t *surface;
GtkWidget *menu_item;
GList *l, *list;
@@ -3577,15 +3577,15 @@ wnck_task_popup_menu (WnckTask *task,
gtk_widget_set_tooltip_text (menu_item, text);
g_free (text);
- pixbuf = wnck_task_get_icon (win_task);
- if (pixbuf)
+ surface = wnck_task_get_icon (win_task);
+ if (surface)
{
WnckImageMenuItem *item;
item = WNCK_IMAGE_MENU_ITEM (menu_item);
- wnck_image_menu_item_set_image_from_icon_pixbuf (item, pixbuf);
- g_object_unref (pixbuf);
+ wnck_image_menu_item_set_image_from_icon_surface (item, surface);
+ cairo_surface_destroy (surface);
}
gtk_widget_show (menu_item);
@@ -3771,102 +3771,78 @@ wnck_task_get_text (WnckTask *task,
}
static void
-wnck_dimm_icon (GdkPixbuf *pixbuf)
+wnck_dimm_icon (cairo_t *cr, cairo_surface_t *surface)
{
- int x, y, pixel_stride, row_stride;
- guchar *row, *pixels;
- int w, h;
+ cairo_surface_t *temp;
+ cairo_t *temp_cr;
- g_assert (pixbuf != NULL);
+ g_assert (surface != NULL);
+ g_assert (cairo_surface_get_content (surface) != CAIRO_CONTENT_COLOR);
- w = gdk_pixbuf_get_width (pixbuf);
- h = gdk_pixbuf_get_height (pixbuf);
+ temp = cairo_surface_create_similar (surface,
+ cairo_surface_get_content (surface),
+ cairo_image_surface_get_width (surface),
+ cairo_image_surface_get_height (surface));
- g_assert (gdk_pixbuf_get_has_alpha (pixbuf));
+ temp_cr = cairo_create (temp);
- pixel_stride = 4;
+ cairo_set_source_surface (temp_cr, surface, 0, 0);
+ cairo_paint_with_alpha (temp_cr, 0.5);
- row = gdk_pixbuf_get_pixels (pixbuf);
- row_stride = gdk_pixbuf_get_rowstride (pixbuf);
+ cairo_set_operator (cr, CAIRO_OPERATOR_IN);
+ cairo_set_source_surface (cr, temp, 0, 0);
+ cairo_paint (cr);
- for (y = 0; y < h; y++)
- {
- pixels = row;
-
- for (x = 0; x < w; x++)
- {
- pixels[3] /= 2;
-
- pixels += pixel_stride;
- }
-
- row += row_stride;
- }
+ cairo_destroy (temp_cr);
+ cairo_surface_destroy (temp);
}
-static GdkPixbuf *
+static cairo_surface_t *
wnck_task_scale_icon (gsize mini_icon_size,
- GdkPixbuf *orig,
+ cairo_surface_t *orig,
gboolean minimized)
{
- int w, h;
- GdkPixbuf *pixbuf;
+ int scaling_factor;
+ cairo_surface_t *surface;
+ cairo_t *cr;
if (!orig)
return NULL;
- w = gdk_pixbuf_get_width (orig);
- h = gdk_pixbuf_get_height (orig);
+ surface = cairo_surface_create_similar_image (orig,
+ cairo_image_surface_get_format (orig),
+ cairo_image_surface_get_width (orig),
+ cairo_image_surface_get_height (orig));
- if (h != (int) mini_icon_size ||
- !gdk_pixbuf_get_has_alpha (orig))
- {
- double scale;
-
- pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
- TRUE,
- 8,
- mini_icon_size * w / (double) h,
- mini_icon_size);
-
- scale = mini_icon_size / (double) gdk_pixbuf_get_height (orig);
-
- gdk_pixbuf_scale (orig,
- pixbuf,
- 0, 0,
- gdk_pixbuf_get_width (pixbuf),
- gdk_pixbuf_get_height (pixbuf),
- 0, 0,
- scale, scale,
- GDK_INTERP_HYPER);
- }
- else
- pixbuf = orig;
+ scaling_factor = _wnck_get_window_scaling_factor ();
+ cairo_surface_set_device_scale (surface, (double)scaling_factor, (double)scaling_factor);
+
+ cr = cairo_create (surface);
+
+ cairo_set_source_surface (cr, orig, 0, 0);
+ cairo_paint (cr);
if (minimized)
{
- if (orig == pixbuf)
- pixbuf = gdk_pixbuf_copy (orig);
-
- wnck_dimm_icon (pixbuf);
+ wnck_dimm_icon (cr, surface);
}
- if (orig == pixbuf)
- g_object_ref (pixbuf);
+ cairo_destroy (cr);
- return pixbuf;
+ return surface;
}
-static GdkPixbuf *
+static cairo_surface_t *
wnck_task_get_icon (WnckTask *task)
{
WnckWindowState state;
- GdkPixbuf *pixbuf;
WnckHandle *handle;
gsize mini_icon_size;
+ cairo_surface_t *surface;
+ cairo_surface_t *mini_icon;
- pixbuf = NULL;
+ surface = NULL;
handle = task->tasklist->priv->handle;
mini_icon_size = _wnck_handle_get_default_mini_icon_size (handle);
@@ -3874,17 +3850,21 @@ wnck_task_get_icon (WnckTask *task)
switch (task->type)
{
case WNCK_TASK_CLASS_GROUP:
- pixbuf = wnck_task_scale_icon (mini_icon_size,
- wnck_class_group_get_mini_icon (task->class_group),
- FALSE);
+ mini_icon = wnck_class_group_get_mini_icon_surface (task->class_group);
+ surface = wnck_task_scale_icon (mini_icon_size, mini_icon, FALSE);
+
+ cairo_surface_destroy (mini_icon);
break;
case WNCK_TASK_WINDOW:
state = wnck_window_get_state (task->window);
- pixbuf = wnck_task_scale_icon (mini_icon_size,
- wnck_window_get_mini_icon (task->window),
- state & WNCK_WINDOW_STATE_MINIMIZED);
+ mini_icon = wnck_window_get_mini_icon_surface (task->window);
+ surface = wnck_task_scale_icon (mini_icon_size,
+ mini_icon,
+ state & WNCK_WINDOW_STATE_MINIMIZED);
+
+ cairo_surface_destroy (mini_icon);
break;
case WNCK_TASK_STARTUP_SEQUENCE:
@@ -3905,16 +3885,28 @@ wnck_task_get_icon (WnckTask *task)
if (loaded != NULL)
{
- pixbuf = wnck_task_scale_icon (mini_icon_size, loaded, FALSE);
+ cairo_surface_t *temp;
+
+ temp = gdk_cairo_surface_create_from_pixbuf (loaded, 0, NULL);
+ surface = wnck_task_scale_icon (mini_icon_size, temp, FALSE);
+
+ cairo_surface_destroy (temp);
g_object_unref (G_OBJECT (loaded));
}
}
}
- if (pixbuf == NULL)
+ if (surface == NULL)
{
+ GdkPixbuf *pixbuf;
_wnck_get_fallback_icons (NULL, 0,
&pixbuf, mini_icon_size);
+
+ if (pixbuf != NULL)
+ {
+ surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, 0, NULL);
+ g_object_unref (pixbuf);
+ }
}
#endif
break;
@@ -3923,7 +3915,7 @@ wnck_task_get_icon (WnckTask *task)
break;
}
- return pixbuf;
+ return surface;
}
static gboolean
@@ -3972,12 +3964,13 @@ wnck_task_get_needs_attention (WnckTask *task)
static void
wnck_task_update_visible_state (WnckTask *task)
{
- GdkPixbuf *pixbuf;
+ cairo_surface_t *surface;
char *text;
- pixbuf = wnck_task_get_icon (task);
- wnck_button_set_image_from_pixbuf (WNCK_BUTTON (task->button), pixbuf);
- g_clear_object (&pixbuf);
+ surface = wnck_task_get_icon (task);
+ wnck_button_set_image_from_surface (WNCK_BUTTON (task->button), surface);
+ if (surface)
+ cairo_surface_destroy (surface);
text = wnck_task_get_text (task, TRUE, TRUE);
if (text != NULL)
@@ -4448,7 +4441,7 @@ wnck_task_draw (GtkWidget *widget,
static void
wnck_task_create_widgets (WnckTask *task, GtkReliefStyle relief)
{
- GdkPixbuf *pixbuf;
+ cairo_surface_t *surface;
char *text;
static const GtkTargetEntry targets[] = {
{ (gchar *) "application/x-wnck-window-id", 0, 0 }
@@ -4477,9 +4470,9 @@ wnck_task_create_widgets (WnckTask *task, GtkReliefStyle relief)
gtk_drag_dest_set (GTK_WIDGET (task->button), 0,
NULL, 0, GDK_ACTION_DEFAULT);
- pixbuf = wnck_task_get_icon (task);
- wnck_button_set_image_from_pixbuf (WNCK_BUTTON (task->button), pixbuf);
- g_clear_object (&pixbuf);
+ surface = wnck_task_get_icon (task);
+ wnck_button_set_image_from_surface (WNCK_BUTTON (task->button), surface);
+ cairo_surface_destroy (surface);
text = wnck_task_get_text (task, TRUE, TRUE);
wnck_button_set_text (WNCK_BUTTON (task->button), text);
diff --git a/libwnck/window.c b/libwnck/window.c
index 35bb37c..f01b4c2 100644
--- a/libwnck/window.c
+++ b/libwnck/window.c
@@ -87,8 +87,8 @@ struct _WnckWindowPrivate
WnckWindowType wintype;
- GdkPixbuf *icon;
- GdkPixbuf *mini_icon;
+ cairo_surface_t *icon;
+ cairo_surface_t *mini_icon;
WnckIconCache *icon_cache;
@@ -411,13 +411,8 @@ wnck_window_finalize (GObject *object)
g_free (window->priv->session_id_utf8);
window->priv->session_id_utf8 = NULL;
- if (window->priv->icon)
- g_object_unref (G_OBJECT (window->priv->icon));
- window->priv->icon = NULL;
-
- if (window->priv->mini_icon)
- g_object_unref (G_OBJECT (window->priv->mini_icon));
- window->priv->mini_icon = NULL;
+ g_clear_pointer (&window->priv->icon, cairo_surface_destroy);
+ g_clear_pointer (&window->priv->mini_icon, cairo_surface_destroy);
_wnck_icon_cache_free (window->priv->icon_cache);
window->priv->icon_cache = NULL;
@@ -2132,14 +2127,20 @@ get_icons (WnckWindow *window)
{
window->priv->need_emit_icon_changed = TRUE;
- if (window->priv->icon)
- g_object_unref (G_OBJECT (window->priv->icon));
+ g_clear_pointer (&window->priv->icon, cairo_surface_destroy);
+ g_clear_pointer (&window->priv->mini_icon, cairo_surface_destroy);
- if (window->priv->mini_icon)
- g_object_unref (G_OBJECT (window->priv->mini_icon));
+ if (icon)
+ {
+ window->priv->icon = gdk_cairo_surface_create_from_pixbuf (icon, 0, NULL);
+ g_clear_object (&icon);
+ }
- window->priv->icon = icon;
- window->priv->mini_icon = mini_icon;
+ if (mini_icon)
+ {
+ window->priv->mini_icon = gdk_cairo_surface_create_from_pixbuf (mini_icon, 0, NULL);
+ g_clear_object (&mini_icon);
+ }
}
g_assert ((window->priv->icon && window->priv->mini_icon) ||
@@ -2173,11 +2174,41 @@ _wnck_window_load_icons (WnckWindow *window)
GdkPixbuf*
wnck_window_get_icon (WnckWindow *window)
{
+ static const cairo_user_data_key_t window_icon_pixbuf_key;
+
g_return_val_if_fail (WNCK_IS_WINDOW (window), NULL);
_wnck_window_load_icons (window);
- return window->priv->icon;
+ if (window->priv->icon)
+ {
+ GdkPixbuf *pixbuf;
+
+ pixbuf = cairo_surface_get_user_data (window->priv->icon, &window_icon_pixbuf_key);
+
+ if (pixbuf == NULL)
+ {
+ int scaling_factor;
+
+ pixbuf = gdk_pixbuf_get_from_surface (window->priv->icon,
+ 0,
+ 0,
+ cairo_image_surface_get_width (window->priv->icon),
+ cairo_image_surface_get_height (window->priv->icon));
+
+ scaling_factor = _wnck_get_window_scaling_factor ();
+ pixbuf = gdk_pixbuf_scale_simple (pixbuf,
+ gdk_pixbuf_get_width (pixbuf) / scaling_factor,
+ gdk_pixbuf_get_height (pixbuf) / scaling_factor,
+ GDK_INTERP_BILINEAR);
+
+ cairo_surface_set_user_data (window->priv->icon, &window_icon_pixbuf_key, pixbuf, g_object_unref);
+ }
+
+ return pixbuf;
+ }
+
+ return NULL;
}
/**
@@ -2194,12 +2225,86 @@ wnck_window_get_icon (WnckWindow *window)
**/
GdkPixbuf*
wnck_window_get_mini_icon (WnckWindow *window)
+{
+ static const cairo_user_data_key_t window_mini_icon_pixbuf_key;
+
+ g_return_val_if_fail (WNCK_IS_WINDOW (window), NULL);
+
+ _wnck_window_load_icons (window);
+
+ if (window->priv->mini_icon)
+ {
+ GdkPixbuf *pixbuf;
+
+ pixbuf = cairo_surface_get_user_data (window->priv->mini_icon, &window_mini_icon_pixbuf_key);
+
+ if (pixbuf == NULL)
+ {
+ int scaling_factor;
+
+ pixbuf = gdk_pixbuf_get_from_surface (window->priv->mini_icon,
+ 0,
+ 0,
+ cairo_image_surface_get_width (window->priv->mini_icon),
+ cairo_image_surface_get_height (window->priv->mini_icon));
+
+ scaling_factor = _wnck_get_window_scaling_factor ();
+ pixbuf = gdk_pixbuf_scale_simple (pixbuf,
+ gdk_pixbuf_get_width (pixbuf) / scaling_factor,
+ gdk_pixbuf_get_height (pixbuf) / scaling_factor,
+ GDK_INTERP_BILINEAR);
+
+ cairo_surface_set_user_data (window->priv->mini_icon, &window_mini_icon_pixbuf_key, pixbuf, g_object_unref);
+ }
+
+ return pixbuf;
+ }
+
+ return NULL;
+}
+
+/**
+ * wnck_window_get_icon_surface:
+ * @window: a #WnckWindow.
+ *
+ * Gets the icon-surface to be used for @window. If no icon-surface was found, a
+ * fallback icon-surface is used. wnck_window_get_icon_is_fallback() can be used
+ * to tell if the icon-surface is the fallback icon-surface.
+ *
+ * Return value: (transfer full): a reference to the icon-surface for @window.
+ * The caller should unreference the returned <classname>cairo_surface_t</classname>
+ * once done with it.
+ **/
+cairo_surface_t*
+wnck_window_get_icon_surface (WnckWindow *window)
+{
+ g_return_val_if_fail (WNCK_IS_WINDOW (window), NULL);
+
+ _wnck_window_load_icons (window);
+
+ return cairo_surface_reference (window->priv->icon);
+}
+
+/**
+ * wnck_window_get_mini_icon_surface:
+ * @window: a #WnckWindow.
+ *
+ * Gets the mini-icon-surface to be used for @window. If no mini-icon-surface
+ * was found, a fallback mini-icon-surface is used. wnck_window_get_icon_is_fallback()
+ * can be used to tell if the mini-icon-surface is the fallback mini-icon-surface.
+ *
+ * Return value: (transfer full): a reference to the mini-icon-surface for @window.
+ * The caller should unreference the returned <classname>cairo_surface_t</classname>
+ * once done with it.
+ **/
+cairo_surface_t*
+wnck_window_get_mini_icon_surface (WnckWindow *window)
{
g_return_val_if_fail (WNCK_IS_WINDOW (window), NULL);
_wnck_window_load_icons (window);
- return window->priv->mini_icon;
+ return cairo_surface_reference (window->priv->mini_icon);
}
/**
diff --git a/libwnck/window.h b/libwnck/window.h
index 47c6543..2bec086 100644
--- a/libwnck/window.h
+++ b/libwnck/window.h
@@ -33,6 +33,7 @@
#include <glib-object.h>
#include <libwnck/screen.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <cairo.h>
G_BEGIN_DECLS
@@ -382,6 +383,8 @@ gboolean wnck_window_transient_is_most_recently_activated (WnckWindow *window);
GdkPixbuf* wnck_window_get_icon (WnckWindow *window);
GdkPixbuf* wnck_window_get_mini_icon (WnckWindow *window);
+cairo_surface_t* wnck_window_get_icon_surface (WnckWindow *window);
+cairo_surface_t* wnck_window_get_mini_icon_surface (WnckWindow *window);
gboolean wnck_window_get_icon_is_fallback (WnckWindow *window);
diff --git a/libwnck/wnck-image-menu-item-private.h b/libwnck/wnck-image-menu-item-private.h
index 265289d..5c47517 100644
--- a/libwnck/wnck-image-menu-item-private.h
+++ b/libwnck/wnck-image-menu-item-private.h
@@ -34,6 +34,9 @@ GtkWidget *wnck_image_menu_item_new_with_label (const gchar *l
void wnck_image_menu_item_set_image_from_icon_pixbuf (WnckImageMenuItem *item,
GdkPixbuf *pixbuf);
+void wnck_image_menu_item_set_image_from_icon_surface (WnckImageMenuItem *item,
+ cairo_surface_t *surface);
+
void wnck_image_menu_item_set_image_from_window (WnckImageMenuItem *item,
WnckWindow *window);
diff --git a/libwnck/wnck-image-menu-item.c b/libwnck/wnck-image-menu-item.c
index e8e6d87..7f5efdc 100644
--- a/libwnck/wnck-image-menu-item.c
+++ b/libwnck/wnck-image-menu-item.c
@@ -219,6 +219,14 @@ wnck_image_menu_item_set_image_from_icon_pixbuf (WnckImageMenuItem *item,
gtk_widget_show (item->image);
}
+void
+wnck_image_menu_item_set_image_from_icon_surface (WnckImageMenuItem *item,
+ cairo_surface_t *surface)
+{
+ gtk_image_set_from_surface (GTK_IMAGE (item->image), surface);
+ gtk_widget_show (item->image);
+}
+
void
wnck_image_menu_item_set_image_from_window (WnckImageMenuItem *item,
WnckWindow *window)
--
2.37.2