[gtk+] GtkWindow: Use cairo_surface_t for icons



commit aa873e77090f788e6f231237f729552e42a6edc8
Author: Alexander Larsson <alexl redhat com>
Date:   Sun Oct 22 22:57:21 2017 +0200

    GtkWindow: Use cairo_surface_t for icons

 gtk/gtkheaderbar.c     |   13 +---
 gtk/gtkwindow.c        |  179 ++++++++++++++++++++++++++++++++----------------
 gtk/gtkwindow.h        |    6 +-
 gtk/gtkwindowprivate.h |    5 +-
 4 files changed, 130 insertions(+), 73 deletions(-)
---
diff --git a/gtk/gtkheaderbar.c b/gtk/gtkheaderbar.c
index de25017..ba8786d 100644
--- a/gtk/gtkheaderbar.c
+++ b/gtk/gtkheaderbar.c
@@ -200,7 +200,7 @@ _gtk_header_bar_update_window_icon (GtkHeaderBar *bar,
                                     GtkWindow    *window)
 {
   GtkHeaderBarPrivate *priv = gtk_header_bar_get_instance_private (bar);
-  GdkPixbuf *pixbuf;
+  cairo_surface_t *surface;
   gint scale;
 
   if (priv->titlebar_icon == NULL)
@@ -208,19 +208,14 @@ _gtk_header_bar_update_window_icon (GtkHeaderBar *bar,
 
   scale = gtk_widget_get_scale_factor (priv->titlebar_icon);
   if (GTK_IS_BUTTON (gtk_widget_get_parent (priv->titlebar_icon)))
-    pixbuf = gtk_window_get_icon_for_size (window, scale * 16);
+    surface = gtk_window_get_icon_for_size (window, 16, scale);
   else
-    pixbuf = gtk_window_get_icon_for_size (window, scale * 20);
+    surface = gtk_window_get_icon_for_size (window, 20, scale);
 
-  if (pixbuf)
+  if (surface)
     {
-      cairo_surface_t *surface;
-
-      surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, scale, gtk_widget_get_window 
(priv->titlebar_icon));
-
       gtk_image_set_from_surface (GTK_IMAGE (priv->titlebar_icon), surface);
       cairo_surface_destroy (surface);
-      g_object_unref (pixbuf);
       gtk_widget_show (priv->titlebar_icon);
 
       return TRUE;
diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c
index c5d9c17..57cec5d 100644
--- a/gtk/gtkwindow.c
+++ b/gtk/gtkwindow.c
@@ -24,6 +24,8 @@
 
 #include "config.h"
 
+#include <cairo-gobject.h>
+
 #include "gtkwindow.h"
 
 #include <string.h>
@@ -927,7 +929,7 @@ gtk_window_class_init (GtkWindowClass *klass)
       g_param_spec_object ("icon",
                            P_("Icon"),
                            P_("Icon for this window"),
-                           GDK_TYPE_PIXBUF,
+                          CAIRO_GOBJECT_TYPE_SURFACE,
                            GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
 
   /**
@@ -4415,10 +4417,11 @@ static GList *
 icon_list_from_theme (GtkWindow   *window,
                      const gchar *name)
 {
+  GtkWindowPrivate *priv = window->priv;
   GList *list;
 
   GtkIconTheme *icon_theme;
-  GdkPixbuf *icon;
+  cairo_surface_t *icon;
   gint *sizes;
   gint i;
 
@@ -4437,11 +4440,15 @@ icon_list_from_theme (GtkWindow   *window,
        * fixed size of 48.
        */ 
       if (sizes[i] == -1)
-       icon = gtk_icon_theme_load_icon (icon_theme, name,
-                                        48, 0, NULL);
+       icon = gtk_icon_theme_load_surface (icon_theme, name,
+                                           48, priv->scale,
+                                           _gtk_widget_get_window (GTK_WIDGET (window)),
+                                           0, NULL);
       else
-       icon = gtk_icon_theme_load_icon (icon_theme, name,
-                                        sizes[i], 0, NULL);
+       icon = gtk_icon_theme_load_surface (icon_theme, name,
+                                           sizes[i], priv->scale,
+                                           _gtk_widget_get_window (GTK_WIDGET (window)),
+                                           0, NULL);
       if (icon)
        list = g_list_append (list, icon);
     }
@@ -4526,43 +4533,90 @@ gtk_window_realize_icon (GtkWindow *window)
     }
 }
 
-static GdkPixbuf *
-icon_from_list (GList *list,
-                gint   size)
+static cairo_surface_t *
+icon_from_list (GtkWindow *window,
+               GList *list,
+                gint   size,
+               gint   scale)
 {
-  GdkPixbuf *best;
-  GdkPixbuf *pixbuf;
+  cairo_surface_t *best;
+  cairo_surface_t *surface;
   GList *l;
 
   best = NULL;
+  /* Look for exact match */
   for (l = list; l; l = l->next)
     {
-      pixbuf = list->data;
-      if (gdk_pixbuf_get_width (pixbuf) <= size)
-        {
-          best = g_object_ref (pixbuf);
+      surface = list->data;
+      double x_scale;
+
+      cairo_surface_get_device_scale (surface, &x_scale, NULL);
+      
+      if (cairo_image_surface_get_width (surface) == size &&
+         x_scale == scale)
+       {
+          best = cairo_surface_reference (surface);
           break;
-        }
+       }
     }
 
-  if (best == NULL)
-    best = gdk_pixbuf_scale_simple (GDK_PIXBUF (list->data), size, size, GDK_INTERP_BILINEAR);
+  if (best != NULL)
+    return best;
+    
+  /* Ignore scale */
+  for (l = list; l; l = l->next)
+    {
+      surface = list->data;
+      double x_scale;
+
+      cairo_surface_get_device_scale (surface, &x_scale, NULL);
+      
+      if (cairo_image_surface_get_width (surface) * x_scale <= size)
+       {
+         best = cairo_surface_reference (surface);
+         break;
+       }
+    }
+
+  if (best == NULL && list != NULL)
+    best = (cairo_surface_t *)list->data;
+
+  
+  if (best)
+    {
+      cairo_t *cr;
+      surface =
+       gdk_window_create_similar_image_surface (_gtk_widget_get_window (GTK_WIDGET(window)),
+                                                CAIRO_FORMAT_ARGB32,
+                                                size, size, scale);
+      cr = cairo_create (surface);
+      cairo_set_source_surface (cr, best, 0, 0);
+      cairo_scale (cr,
+                  size / cairo_image_surface_get_width (best),
+                  size / cairo_image_surface_get_height (best));
+      cairo_paint (cr);
+      cairo_destroy (cr);
+    }
 
   return best;
 }
 
-static GdkPixbuf *
-icon_from_name (const gchar *name,
-                gint         size)
+static cairo_surface_t *
+icon_from_name (GtkWindow *window,
+               const gchar *name,
+                gint         size,
+               gint         scale)
 {
-  return gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
-                                   name, size,
-                                   GTK_ICON_LOOKUP_FORCE_SIZE, NULL);
+  return gtk_icon_theme_load_surface (gtk_icon_theme_get_default (),
+                                     name, size, scale,
+                                     _gtk_widget_get_window (GTK_WIDGET(window)),
+                                     GTK_ICON_LOOKUP_FORCE_SIZE, NULL);
 }
 
-GdkPixbuf *
+cairo_surface_t *
 gtk_window_get_icon_for_size (GtkWindow *window,
-                              gint       size)
+                              int        size,
+                             int        scale)
 {
   GtkWindowPrivate *priv = window->priv;
   GtkWindowIconInfo *info;
@@ -4571,24 +4625,24 @@ gtk_window_get_icon_for_size (GtkWindow *window,
   info = ensure_icon_info (window);
 
   if (info->icon_list != NULL)
-    return icon_from_list (info->icon_list, size);
+    return icon_from_list (window, info->icon_list, size, scale);
 
   name = gtk_window_get_icon_name (window);
   if (name != NULL)
-    return icon_from_name (name, size);
+    return icon_from_name (window, name, size, scale);
 
   if (priv->transient_parent != NULL)
     {
       info = ensure_icon_info (priv->transient_parent);
       if (info->icon_list)
-        return icon_from_list (info->icon_list, size);
+        return icon_from_list (window, info->icon_list, size, scale);
     }
 
   if (default_icon_list != NULL)
-    return icon_from_list (default_icon_list, size);
+    return icon_from_list (window, default_icon_list, size, scale);
 
   if (default_icon_name != NULL)
-    return icon_from_name (default_icon_name, size);
+    return icon_from_name (window, default_icon_name, size, scale);
 
   return NULL;
 }
@@ -4614,7 +4668,7 @@ gtk_window_unrealize_icon (GtkWindow *window)
 /**
  * gtk_window_set_icon_list:
  * @window: a #GtkWindow
- * @list: (element-type GdkPixbuf): list of #GdkPixbuf
+ * @list: (element-type cairo_surface_t): list of image surfaces
  *
  * Sets up the icon representing a #GtkWindow. The icon is used when
  * the window is minimized (also known as iconified).  Some window
@@ -4683,7 +4737,7 @@ gtk_window_set_icon_list (GtkWindow  *window,
  * The list is copied, but the reference count on each
  * member won’t be incremented.
  *
- * Returns: (element-type GdkPixbuf) (transfer container): copy of window’s icon list
+ * Returns: (element-type cairo_surface_t) (transfer container): copy of window’s icon list
  **/
 GList*
 gtk_window_get_icon_list (GtkWindow  *window)
@@ -4727,12 +4781,12 @@ gtk_window_get_icon_list (GtkWindow  *window)
  **/
 void
 gtk_window_set_icon (GtkWindow  *window,
-                     GdkPixbuf  *icon)
+                     cairo_surface_t *icon)
 {
   GList *list;
   
   g_return_if_fail (GTK_IS_WINDOW (window));
-  g_return_if_fail (icon == NULL || GDK_IS_PIXBUF (icon));
+  g_return_if_fail (icon == NULL);
 
   list = NULL;
 
@@ -4829,7 +4883,7 @@ gtk_window_get_icon_name (GtkWindow *window)
  *
  * Returns: (transfer none): icon for window
  **/
-GdkPixbuf*
+cairo_surface_t *
 gtk_window_get_icon (GtkWindow  *window)
 {
   GtkWindowIconInfo *info;
@@ -4838,19 +4892,21 @@ gtk_window_get_icon (GtkWindow  *window)
 
   info = get_icon_info (window);
   if (info && info->icon_list)
-    return GDK_PIXBUF (info->icon_list->data);
+    return (cairo_surface_t *) (info->icon_list->data);
   else
     return NULL;
 }
 
-/* Load pixbuf, printing warning on failure if error == NULL
+/* Load surface, printing warning on failure if error == NULL
  */
-static GdkPixbuf *
-load_pixbuf_verbosely (const char *filename,
-                      GError    **err)
+static cairo_surface_t *
+load_surface_verbosely (GdkWindow *window,
+                       const char *filename,
+                       GError    **err)
 {
   GError *local_err = NULL;
   GdkPixbuf *pixbuf;
+  cairo_surface_t *surface = NULL;
 
   pixbuf = gdk_pixbuf_new_from_file (filename, &local_err);
 
@@ -4865,8 +4921,13 @@ load_pixbuf_verbosely (const char *filename,
          g_error_free (local_err);
        }
     }
+  else
+    {
+      surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, 1, window);
+      g_object_unref (pixbuf);
+    }
 
-  return pixbuf;
+  return surface;
 }
 
 /**
@@ -4879,7 +4940,7 @@ load_pixbuf_verbosely (const char *filename,
  * Warns on failure if @err is %NULL.
  *
  * This function is equivalent to calling gtk_window_set_icon()
- * with a pixbuf created by loading the image from @filename.
+ * with a surface created by loading the image from @filename.
  *
  * Returns: %TRUE if setting the icon succeeded.
  *
@@ -4890,12 +4951,12 @@ gtk_window_set_icon_from_file (GtkWindow   *window,
                               const gchar *filename,
                               GError     **err)
 {
-  GdkPixbuf *pixbuf = load_pixbuf_verbosely (filename, err);
+  cairo_surface_t *surface = load_surface_verbosely (_gtk_widget_get_window (GTK_WIDGET (window)), filename, 
err);
 
-  if (pixbuf)
+  if (surface)
     {
-      gtk_window_set_icon (window, pixbuf);
-      g_object_unref (pixbuf);
+      gtk_window_set_icon (window, surface);
+      cairo_surface_destroy (surface);
       
       return TRUE;
     }
@@ -4905,7 +4966,7 @@ gtk_window_set_icon_from_file (GtkWindow   *window,
 
 /**
  * gtk_window_set_default_icon_list:
- * @list: (element-type GdkPixbuf) (transfer container): a list of #GdkPixbuf
+ * @list: (element-type cairo_surface_t) (transfer container): a list of #cairo_surface_t image surfaces
  *
  * Sets an icon list to be used as fallback for windows that haven't
  * had gtk_window_set_icon_list() called on them to set up a
@@ -4928,9 +4989,9 @@ gtk_window_set_default_icon_list (GList *list)
   default_icon_serial++;
   
   g_list_foreach (list,
-                  (GFunc) g_object_ref, NULL);
+                  (GFunc) cairo_surface_reference, NULL);
 
-  g_list_free_full (default_icon_list, g_object_unref);
+  g_list_free_full (default_icon_list, (GDestroyNotify)cairo_surface_destroy);
 
   default_icon_list = g_list_copy (list);
   
@@ -4960,16 +5021,16 @@ gtk_window_set_default_icon_list (GList *list)
  * @icon: the icon
  *
  * Sets an icon to be used as fallback for windows that haven't
- * had gtk_window_set_icon() called on them from a pixbuf.
+ * had gtk_window_set_icon() called on them from a surface.
  *
  * Since: 2.4
  **/
 void
-gtk_window_set_default_icon (GdkPixbuf *icon)
+gtk_window_set_default_icon (cairo_surface_t *icon)
 {
   GList *list;
   
-  g_return_if_fail (GDK_IS_PIXBUF (icon));
+  g_return_if_fail (cairo_surface_get_type (icon) == CAIRO_SURFACE_TYPE_IMAGE);
 
   list = g_list_prepend (NULL, icon);
   gtk_window_set_default_icon_list (list);
@@ -5059,12 +5120,12 @@ gboolean
 gtk_window_set_default_icon_from_file (const gchar *filename,
                                       GError     **err)
 {
-  GdkPixbuf *pixbuf = load_pixbuf_verbosely (filename, err);
+  cairo_surface_t *surface = load_surface_verbosely (NULL, filename, err);
 
-  if (pixbuf)
+  if (surface)
     {
-      gtk_window_set_default_icon (pixbuf);
-      g_object_unref (pixbuf);
+      gtk_window_set_default_icon (surface);
+      cairo_surface_destroy (surface);
       
       return TRUE;
     }
@@ -5077,10 +5138,10 @@ gtk_window_set_default_icon_from_file (const gchar *filename,
  * 
  * Gets the value set by gtk_window_set_default_icon_list().
  * The list is a copy and should be freed with g_list_free(),
- * but the pixbufs in the list have not had their reference count
+ * but the surfaces in the list have not had their reference count
  * incremented.
  * 
- * Returns: (element-type GdkPixbuf) (transfer container): copy of default icon list 
+ * Returns: (element-type cairo_surface_t) (transfer container): copy of default icon list 
  **/
 GList*
 gtk_window_get_default_icon_list (void)
diff --git a/gtk/gtkwindow.h b/gtk/gtkwindow.h
index 0f247e0..05e86d2 100644
--- a/gtk/gtkwindow.h
+++ b/gtk/gtkwindow.h
@@ -277,7 +277,7 @@ GDK_AVAILABLE_IN_ALL
 GList*     gtk_window_get_icon_list                (GtkWindow  *window);
 GDK_AVAILABLE_IN_ALL
 void       gtk_window_set_icon                     (GtkWindow  *window,
-                                                    GdkPixbuf  *icon);
+                                                    cairo_surface_t  *icon);
 GDK_AVAILABLE_IN_ALL
 void       gtk_window_set_icon_name                (GtkWindow   *window,
                                                    const gchar *name);
@@ -286,7 +286,7 @@ gboolean   gtk_window_set_icon_from_file           (GtkWindow   *window,
                                                    const gchar *filename,
                                                    GError     **err);
 GDK_AVAILABLE_IN_ALL
-GdkPixbuf* gtk_window_get_icon                     (GtkWindow  *window);
+cairo_surface_t * gtk_window_get_icon              (GtkWindow  *window);
 GDK_AVAILABLE_IN_ALL
 const gchar * gtk_window_get_icon_name             (GtkWindow  *window);
 GDK_AVAILABLE_IN_ALL
@@ -294,7 +294,7 @@ void       gtk_window_set_default_icon_list        (GList      *list);
 GDK_AVAILABLE_IN_ALL
 GList*     gtk_window_get_default_icon_list        (void);
 GDK_AVAILABLE_IN_ALL
-void       gtk_window_set_default_icon             (GdkPixbuf  *icon);
+void       gtk_window_set_default_icon             (cairo_surface_t  *icon);
 GDK_AVAILABLE_IN_ALL
 void       gtk_window_set_default_icon_name        (const gchar *name);
 GDK_AVAILABLE_IN_ALL
diff --git a/gtk/gtkwindowprivate.h b/gtk/gtkwindowprivate.h
index 7c37ff3..fc6bde7 100644
--- a/gtk/gtkwindowprivate.h
+++ b/gtk/gtkwindowprivate.h
@@ -110,8 +110,9 @@ GtkWidget * _gtk_window_get_popover_parent (GtkWindow *window,
 gboolean    _gtk_window_is_popover_widget  (GtkWindow *window,
                                             GtkWidget *popover);
 
-GdkPixbuf *gtk_window_get_icon_for_size (GtkWindow *window,
-                                         gint       size);
+cairo_surface_t *gtk_window_get_icon_for_size (GtkWindow *window,
+                                              int        size,
+                                              int        scale);
 
 void       gtk_window_set_use_subsurface (GtkWindow *window,
                                           gboolean   use_subsurface);


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