Blob Blame History Raw
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