[gtk+] x11: Set the icon using Cairo



commit 64537102664da8c5b1a7c994bfe14ec2a8cf6144
Author: Benjamin Otte <otte redhat com>
Date:   Fri Aug 27 12:08:30 2010 +0200

    x11: Set the icon using Cairo
    
    No more GdkPixmap to store the icon and its mask, but instead use cairo
    surfaces. Also render the icon into the surfaces using Cairo instead of
    gdk_pixbuf_render_threshold_alpha().

 gdk/x11/gdkwindow-x11.c |  137 ++++++++++++++++++++++++++++++++++++++++++----
 gdk/x11/gdkwindow-x11.h |    4 +-
 2 files changed, 127 insertions(+), 14 deletions(-)
---
diff --git a/gdk/x11/gdkwindow-x11.c b/gdk/x11/gdkwindow-x11.c
index 39e62f5..84bec2d 100644
--- a/gdk/x11/gdkwindow-x11.c
+++ b/gdk/x11/gdkwindow-x11.c
@@ -221,6 +221,87 @@ gdk_window_impl_x11_finalize (GObject *object)
   G_OBJECT_CLASS (gdk_window_impl_x11_parent_class)->finalize (object);
 }
 
+typedef struct {
+  GdkDisplay *display;
+  Pixmap pixmap;
+} FreePixmapData;
+
+static void
+free_pixmap (gpointer datap)
+{
+  FreePixmapData *data = datap;
+
+  if (!gdk_display_is_closed (data->display))
+    {
+      XFreePixmap (GDK_DISPLAY_XDISPLAY (data->display),
+                   data->pixmap);
+    }
+
+  g_object_unref (data->display);
+  g_slice_free (FreePixmapData, data);
+}
+
+static void
+attach_free_pixmap_handler (cairo_surface_t *surface,
+                            GdkDisplay      *display,
+                            Pixmap           pixmap)
+{
+  static const cairo_user_data_key_t key;
+  FreePixmapData *data;
+  
+  data = g_slice_new (FreePixmapData);
+  data->display = g_object_ref (display);
+  data->pixmap = pixmap;
+
+  cairo_surface_set_user_data (surface, &key, data, free_pixmap);
+}
+
+/* Cairo does not guarantee we get an xlib surface if we call
+ * cairo_surface_create_similar(). In some cases however, we must use a
+ * pixmap or bitmap in the X11 API.
+ * These functions ensure an Xlib surface.
+ */
+static cairo_surface_t *
+gdk_x11_window_create_bitmap_surface (GdkWindow *window,
+                                      int        width,
+                                      int        height)
+{
+  cairo_surface_t *surface;
+  Pixmap pixmap;
+
+  pixmap = XCreatePixmap (GDK_WINDOW_XDISPLAY (window),
+                          GDK_WINDOW_XID (window),
+                          width, height, 1);
+  surface = cairo_xlib_surface_create_for_bitmap (GDK_WINDOW_XDISPLAY (window),
+                                                  pixmap,
+                                                  GDK_SCREEN_XSCREEN (GDK_WINDOW_SCREEN (window)),
+                                                  width, height);
+  attach_free_pixmap_handler (surface, GDK_WINDOW_DISPLAY (window), pixmap);
+
+  return surface;
+}
+
+static cairo_surface_t *
+gdk_x11_window_create_pixmap_surface (GdkWindow *window,
+                                      int        width,
+                                      int        height)
+{
+  cairo_surface_t *surface;
+  Pixmap pixmap;
+
+  pixmap = XCreatePixmap (GDK_WINDOW_XDISPLAY (window),
+                          GDK_WINDOW_XID (window),
+                          width, height,
+                          DefaultDepthOfScreen (GDK_SCREEN_XSCREEN (GDK_WINDOW_SCREEN (window))));
+  surface = cairo_xlib_surface_create (GDK_WINDOW_XDISPLAY (window),
+                                       pixmap,
+                                       GDK_VISUAL_XVISUAL (gdk_drawable_get_visual (window)),
+                                       width, height);
+  attach_free_pixmap_handler (surface, GDK_WINDOW_DISPLAY (window), pixmap);
+
+  return surface;
+}
+
 static void
 tmp_unset_bg (GdkWindow *window)
 {
@@ -992,12 +1073,12 @@ gdk_toplevel_x11_free_contents (GdkDisplay *display,
 {
   if (toplevel->icon_pixmap)
     {
-      g_object_unref (toplevel->icon_pixmap);
+      cairo_surface_destroy (toplevel->icon_pixmap);
       toplevel->icon_pixmap = NULL;
     }
   if (toplevel->icon_mask)
     {
-      g_object_unref (toplevel->icon_mask);
+      cairo_surface_destroy (toplevel->icon_mask);
       toplevel->icon_mask = NULL;
     }
   if (toplevel->group_leader)
@@ -1134,13 +1215,13 @@ update_wm_hints (GdkWindow *window,
   if (toplevel->icon_pixmap)
     {
       wm_hints.flags |= IconPixmapHint;
-      wm_hints.icon_pixmap = GDK_PIXMAP_XID (toplevel->icon_pixmap);
+      wm_hints.icon_pixmap = cairo_xlib_surface_get_drawable (toplevel->icon_pixmap);
     }
 
   if (toplevel->icon_mask)
     {
       wm_hints.flags |= IconMaskHint;
-      wm_hints.icon_mask = GDK_PIXMAP_XID (toplevel->icon_mask);
+      wm_hints.icon_mask = cairo_xlib_surface_get_drawable (toplevel->icon_mask);
     }
   
   wm_hints.flags |= WindowGroupHint;
@@ -3612,7 +3693,6 @@ static void
 gdk_window_update_icon (GdkWindow *window,
                         GList     *icon_list)
 {
-  GdkScreen *screen = gdk_drawable_get_screen (window);
   GdkToplevelX11 *toplevel;
   GdkPixbuf *best_icon;
   GList *tmp_list;
@@ -3622,13 +3702,13 @@ gdk_window_update_icon (GdkWindow *window,
 
   if (toplevel->icon_pixmap != NULL)
     {
-      g_object_unref (toplevel->icon_pixmap);
+      cairo_surface_destroy (toplevel->icon_pixmap);
       toplevel->icon_pixmap = NULL;
     }
   
   if (toplevel->icon_mask != NULL)
     {
-      g_object_unref (toplevel->icon_mask);
+      cairo_surface_destroy (toplevel->icon_mask);
       toplevel->icon_mask = NULL;
     }
   
@@ -3668,11 +3748,44 @@ gdk_window_update_icon (GdkWindow *window,
     }
 
   if (best_icon)
-    gdk_pixbuf_render_pixmap_and_mask_for_colormap (best_icon,
-                                                    gdk_screen_get_system_colormap (screen),
-                                                    &toplevel->icon_pixmap,
-                                                    &toplevel->icon_mask,
-                                                    128);
+    {
+      int width = gdk_pixbuf_get_width (best_icon);
+      int height = gdk_pixbuf_get_height (best_icon);
+      cairo_t *cr;
+
+      toplevel->icon_pixmap = gdk_x11_window_create_pixmap_surface (window,
+                                                                    width,
+                                                                    height);
+
+      cr = cairo_create (toplevel->icon_pixmap);
+      cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+      gdk_cairo_set_source_pixbuf (cr, best_icon, 0, 0);
+      if (gdk_pixbuf_get_has_alpha (best_icon))
+        {
+          /* Saturate the image, so it has bilevel alpha */
+          cairo_push_group_with_content (cr, CAIRO_CONTENT_COLOR_ALPHA);
+          cairo_paint (cr);
+          cairo_set_operator (cr, CAIRO_OPERATOR_SATURATE);
+          cairo_paint (cr);
+          cairo_pop_group_to_source (cr);
+        }
+      cairo_paint (cr);
+      cairo_destroy (cr);
+
+      if (gdk_pixbuf_get_has_alpha (best_icon))
+        {
+          toplevel->icon_mask = gdk_x11_window_create_bitmap_surface (window,
+                                                                      width,
+                                                                      height);
+
+          cr = cairo_create (toplevel->icon_mask);
+          gdk_cairo_set_source_pixbuf (cr, best_icon, 0, 0);
+          cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+          cairo_paint (cr);
+          cairo_destroy (cr);
+        }
+    }
+
   update_wm_hints (window, FALSE);
 }
 
diff --git a/gdk/x11/gdkwindow-x11.h b/gdk/x11/gdkwindow-x11.h
index 162d8b8..d9c617f 100644
--- a/gdk/x11/gdkwindow-x11.h
+++ b/gdk/x11/gdkwindow-x11.h
@@ -116,8 +116,8 @@ struct _GdkToplevelX11
   
   gulong map_serial;	/* Serial of last transition from unmapped */
   
-  GdkPixmap *icon_pixmap;
-  GdkPixmap *icon_mask;
+  cairo_surface_t *icon_pixmap;
+  cairo_surface_t *icon_mask;
   GdkWindow *group_leader;
 
   /* Time of most recent user interaction. */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]