[gtk+] Support 'symbolic' themed icons



commit 6b939d57c762f58a9f8d529024b7171ff70b6986
Author: Matthias Clasen <mclasen redhat com>
Date:   Mon Apr 26 11:55:34 2010 +0100

    Support 'symbolic' themed icons
    
    Add gtk_icon_info_load_symbolic() to load symbolic icons, and
    theme their background/foreground colours to match the
    colours used in the theme.
    
    Adds the gtk_icon_info_load_symbolic() function, explicit
    support in GtkImage and GtkCellRendererPixbuf, and test cases
    for those 2 widgets.
    
    With help from Bastien Nocera <hadess hadess net>
    
    https://bugzilla.gnome.org/show_bug.cgi?id=614711

 demos/gtk-demo/images.c             |   21 +++++
 demos/gtk-demo/list_store.c         |   30 +++++++
 docs/reference/gtk/gtk-sections.txt |    1 +
 gtk/gtk.symbols                     |    1 +
 gtk/gtkcellrendererpixbuf.c         |  157 +++++++++++++++++++++++++++++++----
 gtk/gtkicontheme.c                  |  136 ++++++++++++++++++++++++++++++
 gtk/gtkicontheme.h                  |    7 ++
 gtk/gtkimage.c                      |  137 +++++++++++++++++++++++++++----
 8 files changed, 457 insertions(+), 33 deletions(-)
---
diff --git a/demos/gtk-demo/images.c b/demos/gtk-demo/images.c
index 9eaac39..eb3f1d9 100644
--- a/demos/gtk-demo/images.c
+++ b/demos/gtk-demo/images.c
@@ -317,6 +317,7 @@ do_images (GtkWidget *do_widget)
   GtkWidget *align;
   GtkWidget *button;
   GdkPixbuf *pixbuf;
+  GIcon     *gicon;
   GError *error = NULL;
   char *filename;
 
@@ -415,6 +416,26 @@ do_images (GtkWidget *do_widget)
 
       gtk_container_add (GTK_CONTAINER (frame), image);
 
+      /* Symbolic icon */
+
+      label = gtk_label_new (NULL);
+      gtk_label_set_markup (GTK_LABEL (label),
+			    "<u>Symbolic themed icon</u>");
+      gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+
+      frame = gtk_frame_new (NULL);
+      gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
+      /* The alignment keeps the frame from growing when users resize
+       * the window
+       */
+      align = gtk_alignment_new (0.5, 0.5, 0, 0);
+      gtk_container_add (GTK_CONTAINER (align), frame);
+      gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 0);
+
+      gicon = g_themed_icon_new_with_default_fallbacks ("battery-critical-charging-symbolic");
+      image = gtk_image_new_from_gicon (gicon, GTK_ICON_SIZE_DIALOG);
+
+      gtk_container_add (GTK_CONTAINER (frame), image);
 
       /* Progressive */
 
diff --git a/demos/gtk-demo/list_store.c b/demos/gtk-demo/list_store.c
index 009cd97..e5c72ba 100644
--- a/demos/gtk-demo/list_store.c
+++ b/demos/gtk-demo/list_store.c
@@ -29,7 +29,9 @@ enum
   COLUMN_SEVERITY,
   COLUMN_DESCRIPTION,
   COLUMN_PULSE,
+  COLUMN_ICON,
   COLUMN_ACTIVE,
+  COLUMN_SENSITIVE,
   NUM_COLUMNS
 };
 
@@ -92,11 +94,24 @@ create_model (void)
                               G_TYPE_STRING,
                               G_TYPE_STRING,
                               G_TYPE_UINT,
+                              G_TYPE_STRING,
+                              G_TYPE_BOOLEAN,
                               G_TYPE_BOOLEAN);
 
   /* add data to the list store */
   for (i = 0; i < G_N_ELEMENTS (data); i++)
     {
+      gchar *icon_name;
+      gboolean sensitive;
+
+      if (i == 1 || i == 3)
+        icon_name = "battery-critical-charging-symbolic";
+      else
+        icon_name = NULL;
+      if (i == 3)
+        sensitive = FALSE;
+      else
+        sensitive = TRUE;
       gtk_list_store_append (store, &iter);
       gtk_list_store_set (store, &iter,
                           COLUMN_FIXED, data[i].fixed,
@@ -104,7 +119,9 @@ create_model (void)
                           COLUMN_SEVERITY, data[i].severity,
                           COLUMN_DESCRIPTION, data[i].description,
                           COLUMN_PULSE, 0,
+                          COLUMN_ICON, icon_name,
                           COLUMN_ACTIVE, FALSE,
+                          COLUMN_SENSITIVE, sensitive,
                           -1);
     }
 
@@ -199,6 +216,19 @@ add_columns (GtkTreeView *treeview)
                                                      NULL);
   gtk_tree_view_column_set_sort_column_id (column, COLUMN_PULSE);
   gtk_tree_view_append_column (treeview, column);
+
+  /* column for symbolic icon */
+  renderer = gtk_cell_renderer_pixbuf_new ();
+  g_object_set (G_OBJECT (renderer), "follow-state", TRUE, NULL);
+  column = gtk_tree_view_column_new_with_attributes ("Symbolic icon",
+                                                     renderer,
+                                                     "icon-name",
+                                                     COLUMN_ICON,
+                                                     "sensitive",
+                                                     COLUMN_SENSITIVE,
+                                                     NULL);
+  gtk_tree_view_column_set_sort_column_id (column, COLUMN_ICON);
+  gtk_tree_view_append_column (treeview, column);
 }
 
 static gboolean
diff --git a/docs/reference/gtk/gtk-sections.txt b/docs/reference/gtk/gtk-sections.txt
index 1961891..bf9c664 100644
--- a/docs/reference/gtk/gtk-sections.txt
+++ b/docs/reference/gtk/gtk-sections.txt
@@ -6684,6 +6684,7 @@ gtk_icon_info_get_base_size
 gtk_icon_info_get_filename
 gtk_icon_info_get_builtin_pixbuf
 gtk_icon_info_load_icon
+gtk_icon_info_load_symbolic
 gtk_icon_info_set_raw_coordinates
 gtk_icon_info_get_embedded_rect
 gtk_icon_info_get_attach_points
diff --git a/gtk/gtk.symbols b/gtk/gtk.symbols
index af6ada4..ff85c8c 100644
--- a/gtk/gtk.symbols
+++ b/gtk/gtk.symbols
@@ -1965,6 +1965,7 @@ gtk_icon_info_get_filename_utf8
 #endif
 gtk_icon_info_get_type G_GNUC_CONST
 gtk_icon_info_load_icon
+gtk_icon_info_load_symbolic
 gtk_icon_info_set_raw_coordinates
 gtk_icon_theme_add_builtin_icon
 #ifndef _WIN64
diff --git a/gtk/gtkcellrendererpixbuf.c b/gtk/gtkcellrendererpixbuf.c
index f689784..bde1d80 100644
--- a/gtk/gtkcellrendererpixbuf.c
+++ b/gtk/gtkcellrendererpixbuf.c
@@ -497,6 +497,7 @@ gtk_cell_renderer_pixbuf_create_themed_pixbuf (GtkCellRendererPixbuf *cellpixbuf
   GtkIconTheme *icon_theme;
   GtkSettings *settings;
   gint width, height;
+  GtkIconInfo *info;
 
   priv = GTK_CELL_RENDERER_PIXBUF_GET_PRIVATE (cellpixbuf);
 
@@ -519,30 +520,141 @@ gtk_cell_renderer_pixbuf_create_themed_pixbuf (GtkCellRendererPixbuf *cellpixbuf
     }
 
   if (priv->icon_name)
-    cellpixbuf->pixbuf = gtk_icon_theme_load_icon (icon_theme,
-			                           priv->icon_name,
-			                           MIN (width, height), 
-                                                   GTK_ICON_LOOKUP_USE_BUILTIN,
-                                                   NULL);
+    info = gtk_icon_theme_lookup_icon (icon_theme,
+                                       priv->icon_name,
+                                       MIN (width, height),
+                                       GTK_ICON_LOOKUP_USE_BUILTIN);
   else if (priv->gicon)
+    info = gtk_icon_theme_lookup_by_gicon (icon_theme,
+                                           priv->gicon,
+                                           MIN (width, height),
+                                           GTK_ICON_LOOKUP_USE_BUILTIN);
+  else
+    info = NULL;
+
+  if (info)
     {
-      GtkIconInfo *info;
+      GdkColor error_color, warning_color, success_color;
+      GdkColor *error_ptr, *warning_ptr, *success_ptr;
+      GtkStyle *style;
 
-      info = gtk_icon_theme_lookup_by_gicon (icon_theme,
-                                             priv->gicon,
-			                     MIN (width, height), 
-                                             GTK_ICON_LOOKUP_USE_BUILTIN);
-      if (info)
-        {
-          cellpixbuf->pixbuf = gtk_icon_info_load_icon (info, NULL);
-          gtk_icon_info_free (info);
-        }
+      style = gtk_widget_get_style (GTK_WIDGET (widget));
+      if (!gtk_style_lookup_color (style, "error_color", &error_color))
+        error_ptr = NULL;
+      else
+        error_ptr = &error_color;
+      if (!gtk_style_lookup_color (style, "warning_color", &warning_color))
+        warning_ptr = NULL;
+      else
+        warning_ptr = &warning_color;
+      if (!gtk_style_lookup_color (style, "success_color", &success_color))
+        success_ptr = NULL;
+      else
+        success_ptr = &success_color;
+
+      cellpixbuf->pixbuf = gtk_icon_info_load_symbolic (info,
+                                                        &style->fg[GTK_STATE_NORMAL],
+                                                        success_ptr,
+                                                        warning_ptr,
+                                                        error_ptr,
+                                                        NULL,
+                                                        NULL);
+      gtk_icon_info_free (info);
     }
 
   g_object_notify (G_OBJECT (cellpixbuf), "pixbuf");
 }
 
 static GdkPixbuf *
+create_symbolic_pixbuf (GtkCellRendererPixbuf *cellpixbuf,
+			GtkWidget             *widget,
+			GdkColor              *fg)
+{
+  GtkCellRendererPixbufPrivate *priv;
+  GdkScreen *screen;
+  GtkIconTheme *icon_theme;
+  GtkSettings *settings;
+  gint width, height;
+  GtkIconInfo *info;
+  GdkPixbuf *pixbuf;
+
+  priv = GTK_CELL_RENDERER_PIXBUF_GET_PRIVATE (cellpixbuf);
+
+  /* Not a named symbolic icon? */
+  if (priv->icon_name) {
+    if (!g_str_has_suffix (priv->icon_name, "-symbolic"))
+      return NULL;
+  } else if (priv->gicon) {
+    const gchar * const *names;
+    if (!G_IS_THEMED_ICON (priv->gicon))
+      return NULL;
+    names = g_themed_icon_get_names (G_THEMED_ICON (priv->gicon));
+    if (names == NULL || !g_str_has_suffix (names[0], "-symbolic"))
+      return NULL;
+  } else {
+    return NULL;
+  }
+
+  screen = gtk_widget_get_screen (GTK_WIDGET (widget));
+  icon_theme = gtk_icon_theme_get_for_screen (screen);
+  settings = gtk_settings_get_for_screen (screen);
+
+  if (!gtk_icon_size_lookup_for_settings (settings,
+					  priv->stock_size,
+					  &width, &height))
+    {
+      g_warning ("Invalid icon size %u\n", priv->stock_size);
+      width = height = 24;
+    }
+
+
+  if (priv->icon_name)
+    info = gtk_icon_theme_lookup_icon (icon_theme,
+                                       priv->icon_name,
+                                       MIN (width, height),
+                                       GTK_ICON_LOOKUP_USE_BUILTIN);
+  else if (priv->gicon)
+    info = gtk_icon_theme_lookup_by_gicon (icon_theme,
+                                           priv->gicon,
+                                           MIN (width, height),
+                                           GTK_ICON_LOOKUP_USE_BUILTIN);
+  else
+    return NULL;
+
+  if (info)
+    {
+      GdkColor error_color, warning_color, success_color;
+      GdkColor *error_ptr, *warning_ptr, *success_ptr;
+      GtkStyle *style;
+
+      style = gtk_widget_get_style (GTK_WIDGET (widget));
+      if (!gtk_style_lookup_color (style, "error_color", &error_color))
+        error_ptr = NULL;
+      else
+        error_ptr = &error_color;
+      if (!gtk_style_lookup_color (style, "warning_color", &warning_color))
+        warning_ptr = NULL;
+      else
+        warning_ptr = &warning_color;
+      if (!gtk_style_lookup_color (style, "success_color", &success_color))
+        success_ptr = NULL;
+      else
+        success_ptr = &success_color;
+
+      pixbuf = gtk_icon_info_load_symbolic (info,
+                                            fg,
+                                            success_ptr,
+                                            warning_ptr,
+                                            error_ptr,
+                                            NULL,
+                                            NULL);
+      gtk_icon_info_free (info);
+      return pixbuf;
+    }
+  return NULL;
+}
+
+static GdkPixbuf *
 create_colorized_pixbuf (GdkPixbuf *src, 
 			 GdkColor  *new_color)
 {
@@ -678,6 +790,7 @@ gtk_cell_renderer_pixbuf_render (GtkCellRenderer      *cell,
   GdkPixbuf *pixbuf;
   GdkPixbuf *invisible = NULL;
   GdkPixbuf *colorized = NULL;
+  GdkPixbuf *symbolic = NULL;
   GdkRectangle pix_rect;
   GdkRectangle draw_rect;
   cairo_t *cr;
@@ -755,10 +868,15 @@ gtk_cell_renderer_pixbuf_render (GtkCellRenderer      *cell,
       else
 	state = GTK_STATE_PRELIGHT;
 
-      colorized = create_colorized_pixbuf (pixbuf,
-					   &widget->style->base[state]);
+      symbolic = create_symbolic_pixbuf (cellpixbuf, widget, &widget->style->fg[state]);
+      if (!symbolic) {
+        colorized = create_colorized_pixbuf (pixbuf,
+					     &widget->style->base[state]);
 
-      pixbuf = colorized;
+	pixbuf = colorized;
+      } else {
+        pixbuf = symbolic;
+      }
     }
 
   cr = gdk_cairo_create (window);
@@ -774,6 +892,9 @@ gtk_cell_renderer_pixbuf_render (GtkCellRenderer      *cell,
 
   if (colorized)
     g_object_unref (colorized);
+
+  if (symbolic)
+    g_object_unref (symbolic);
 }
 
 #define __GTK_CELL_RENDERER_PIXBUF_C__
diff --git a/gtk/gtkicontheme.c b/gtk/gtkicontheme.c
index 67ed420..0084343 100644
--- a/gtk/gtkicontheme.c
+++ b/gtk/gtkicontheme.c
@@ -3079,6 +3079,142 @@ gtk_icon_info_load_icon (GtkIconInfo *icon_info,
   return g_object_ref (icon_info->pixbuf);
 }
 
+static gchar *
+gdk_color_to_css (GdkColor *color)
+{
+  return g_strdup_printf ("rgb(%d,%d,%d)",
+                          color->red >> 8,
+                          color->green >> 8,
+                          color->blue >> 8);
+}
+
+/**
+ * gtk_icon_info_load_symbolic:
+ * @info: a #GtkIconInfo
+ * @fg: a #GdkColor representing the foreground color of the icon
+ * @success_color: (allow-none): a #GdkColor representing the warning color of the icon
+ * or %NULL to use the default color
+ * @warning_color: (allow-none): a #GdkColor representing the warning color of the icon
+ * or %NULL to use the default color
+ * @error_color: (allow-none): a #GdkColor representing the error color of the icon
+ * or %NULL to use the default color (allow-none)
+ * @was_symbolic: (allow-none): a #gboolean, returns whether the loaded icon was a symbolic
+ * one and whether the @fg color was applied to it.
+ * @error: (allow-none): location to store error information on failure, or %NULL.
+ *
+ * Loads an icon, modifying it to match the system colours for the foreground,
+ * success, warning and error colors provided. If the icon is not a symbolic one,
+ * the function will return the result from gtk_icon_info_load_icon().
+ *
+ * This allows loading symbolic icons that will match the system theme.
+ *
+ * Unless you are implementing a widget, you will want to use
+ * g_themed_icon_new_with_default_fallbacks() to load the icon.
+ *
+ * As implementation details, the icon loaded needs to be of SVG type,
+ * contain the "symbolic" term as the last chunk of the icon name,
+ * and use the fg, success, warning and error styles in the SVG file itself.
+ * See the <a ulink url="http://www.freedesktop.org/wiki/SymbolicIcons";>Symbolic Icons spec</ulink>
+ * for more information about symbolic icons.
+ *
+ * Return value: a #GdkPixbuf representing the loaded icon
+ *
+ * Since: 2.22
+ **/
+GdkPixbuf *
+gtk_icon_info_load_symbolic (GtkIconInfo  *info,
+                             GdkColor     *fg,
+                             GdkColor     *success_color,
+                             GdkColor     *warning_color,
+                             GdkColor     *error_color,
+                             gboolean     *was_symbolic,
+                             GError      **error)
+{
+  GdkPixbuf *pixbuf;
+  GInputStream *stream;
+  gchar *data;
+  gchar *css_fg;
+  gchar *css_success;
+  gchar *css_warning;
+  gchar *css_error;
+
+  g_return_val_if_fail (fg != NULL, NULL);
+
+  if (!info->filename || !g_str_has_suffix (info->filename, "-symbolic.svg"))
+    {
+      if (was_symbolic)
+        *was_symbolic = FALSE;
+      return gtk_icon_info_load_icon (info, error);
+    }
+
+  if (was_symbolic)
+    *was_symbolic = TRUE;
+
+  css_fg = gdk_color_to_css (fg);
+  if (!warning_color)
+    {
+      GdkColor warning_default_color = { 0, 0xf500, 0x7900, 0x3e00 };
+      css_warning = gdk_color_to_css (&warning_default_color);
+    }
+  else
+      css_warning = gdk_color_to_css (warning_color);
+  if (!error_color)
+    {
+      GdkColor error_default_color = { 0, 0xcc00, 0x0000, 0x0000 };
+      css_error = gdk_color_to_css (&error_default_color);
+    }
+  else
+      css_error = gdk_color_to_css (error_color);
+  if (!success_color)
+    {
+      GdkColor success_default_color = { 0, 0x4e00, 0x9a00, 0x0600 };
+      css_success = gdk_color_to_css (&success_default_color);
+    }
+  else
+      css_success = gdk_color_to_css (success_color);
+
+  data = g_strconcat (
+"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
+"<svg version=\"1.1\"\n"
+"     xmlns=\"http://www.w3.org/2000/svg\"\n";
+"     xmlns:xi=\"http://www.w3.org/2001/XInclude\"\n";
+"     width=\"16\"\n"
+"     height=\"16\">\n"
+"  <style type=\"text/css\">\n"
+"    rect,path {\n"
+"      fill: ", css_fg," !important;\n"
+"    }\n"
+"    .warning {\n"
+"      fill: ", css_warning," !important;\n"
+"    }\n"
+"    .error {\n"
+"      fill: ", css_error," !important;\n"
+"    }\n"
+"    .success {\n"
+"      fill: ", css_success," !important;\n"
+"    }\n"
+"  </style>\n"
+"  <xi:include href=\"", info->filename, "\"/>\n"
+"</svg>",
+         NULL);
+  g_free (css_fg);
+  g_free (css_warning);
+  g_free (css_success);
+  g_free (css_error);
+
+  stream = g_memory_input_stream_new_from_data (data, -1, g_free);
+
+  pixbuf = gdk_pixbuf_new_from_stream_at_scale (stream,
+                                                info->desired_size,
+                                                info->desired_size,
+                                                TRUE,
+                                                NULL,
+                                                error);
+  g_object_unref (stream);
+
+  return pixbuf;
+}
+
 /**
  * gtk_icon_info_set_raw_coordinates:
  * @icon_info: a #GtkIconInfo
diff --git a/gtk/gtkicontheme.h b/gtk/gtkicontheme.h
index b6d7d31..f8609cb 100644
--- a/gtk/gtkicontheme.h
+++ b/gtk/gtkicontheme.h
@@ -179,6 +179,13 @@ G_CONST_RETURN gchar *gtk_icon_info_get_filename       (GtkIconInfo   *icon_info
 GdkPixbuf *           gtk_icon_info_get_builtin_pixbuf (GtkIconInfo   *icon_info);
 GdkPixbuf *           gtk_icon_info_load_icon          (GtkIconInfo   *icon_info,
 							GError       **error);
+GdkPixbuf *           gtk_icon_info_load_symbolic      (GtkIconInfo   *icon_info,
+                                                        GdkColor      *fg,
+                                                        GdkColor      *success_color,
+							GdkColor      *warning_color,
+							GdkColor      *error_color,
+							gboolean      *was_symbolic,
+                                                        GError       **error);
 void                  gtk_icon_info_set_raw_coordinates (GtkIconInfo  *icon_info,
 							 gboolean      raw_coordinates);
 
diff --git a/gtk/gtkimage.c b/gtk/gtkimage.c
index 6654f0d..87e0b08 100644
--- a/gtk/gtkimage.c
+++ b/gtk/gtkimage.c
@@ -134,6 +134,11 @@ struct _GtkImagePrivate
   /* Only used with GTK_IMAGE_ANIMATION, GTK_IMAGE_PIXBUF */
   gchar *filename;
 
+  /* a GtkStateType, with -1 meaning an invalid state,
+   * only used with GTK_IMAGE_GICON, GTK_IMAGE_ICON_NAME */
+  gint last_rendered_state;
+  gboolean was_symbolic;
+
   gint pixel_size;
   guint need_calc_size : 1;
 };
@@ -1628,6 +1633,10 @@ animation_timeout (gpointer data)
 static void
 icon_theme_changed (GtkImage *image)
 {
+  GtkImagePrivate *priv;
+
+  priv = GTK_IMAGE_GET_PRIVATE (image);
+
   if (image->storage_type == GTK_IMAGE_ICON_NAME) 
     {
       if (image->data.name.pixbuf)
@@ -1647,7 +1656,8 @@ icon_theme_changed (GtkImage *image)
 }
 
 static void
-ensure_pixbuf_for_icon_name (GtkImage *image)
+ensure_pixbuf_for_icon_name (GtkImage     *image,
+			     GtkStateType  state)
 {
   GtkImagePrivate *priv;
   GdkScreen *screen;
@@ -1655,8 +1665,8 @@ ensure_pixbuf_for_icon_name (GtkImage *image)
   GtkSettings *settings;
   gint width, height;
   gint *sizes, *s, dist;
+  GtkIconInfo *info;
   GtkIconLookupFlags flags;
-  GError *error = NULL;
 
   g_return_if_fail (image->storage_type == GTK_IMAGE_ICON_NAME);
 
@@ -1665,8 +1675,15 @@ ensure_pixbuf_for_icon_name (GtkImage *image)
   icon_theme = gtk_icon_theme_get_for_screen (screen);
   settings = gtk_settings_get_for_screen (screen);
   flags = GTK_ICON_LOOKUP_USE_BUILTIN;
-  if (image->data.name.pixbuf == NULL)
+  if (image->data.name.pixbuf == NULL ||
+      (priv->was_symbolic && priv->last_rendered_state != state))
     {
+      priv->last_rendered_state = state;
+      if (image->data.name.pixbuf)
+        {
+          g_object_unref (image->data.name.pixbuf);
+          image->data.name.pixbuf = NULL;
+	}
       if (priv->pixel_size != -1)
 	{
 	  width = height = priv->pixel_size;
@@ -1714,24 +1731,57 @@ ensure_pixbuf_for_icon_name (GtkImage *image)
 	      width = height = 24;
 	    }
 	}
-      image->data.name.pixbuf =
-	gtk_icon_theme_load_icon (icon_theme,
-				  image->data.name.icon_name,
-				  MIN (width, height), flags, &error);
+
+      info = gtk_icon_theme_lookup_icon (icon_theme,
+                                         image->data.name.icon_name,
+                                         MIN (width, height), flags);
+      if (info)
+        {
+          GdkColor error_color, warning_color, success_color;
+          GdkColor *error_ptr, *warning_ptr, *success_ptr;
+          GtkStyle *style;
+          gboolean was_symbolic;
+
+          style = gtk_widget_get_style (GTK_WIDGET (image));
+          if (!gtk_style_lookup_color (style, "error_color", &error_color))
+            error_ptr = NULL;
+          else
+            error_ptr = &error_color;
+          if (!gtk_style_lookup_color (style, "warning_color", &warning_color))
+            warning_ptr = NULL;
+          else
+            warning_ptr = &warning_color;
+          if (!gtk_style_lookup_color (style, "success_color", &success_color))
+            success_ptr = NULL;
+          else
+            success_ptr = &success_color;
+
+          image->data.name.pixbuf = gtk_icon_info_load_symbolic (info,
+                                                                 &style->fg[state],
+                                                                 success_ptr,
+                                                                 warning_ptr,
+                                                                 error_ptr,
+                                                                 &was_symbolic,
+                                                                 NULL);
+          priv->was_symbolic = was_symbolic;
+          gtk_icon_info_free (info);
+        }
+
       if (image->data.name.pixbuf == NULL)
 	{
-	  g_error_free (error);
 	  image->data.name.pixbuf =
 	    gtk_widget_render_icon (GTK_WIDGET (image),
 				    GTK_STOCK_MISSING_IMAGE,
 				    image->icon_size,
 				    NULL);
+	  priv->was_symbolic = FALSE;
 	}
     }
 }
 
 static void
-ensure_pixbuf_for_gicon (GtkImage *image)
+ensure_pixbuf_for_gicon (GtkImage     *image,
+			 GtkStateType  state)
 {
   GtkImagePrivate *priv;
   GdkScreen *screen;
@@ -1748,8 +1798,15 @@ ensure_pixbuf_for_gicon (GtkImage *image)
   icon_theme = gtk_icon_theme_get_for_screen (screen);
   settings = gtk_settings_get_for_screen (screen);
   flags = GTK_ICON_LOOKUP_USE_BUILTIN;
-  if (image->data.gicon.pixbuf == NULL)
+  if (image->data.gicon.pixbuf == NULL ||
+      (priv->was_symbolic && priv->last_rendered_state != state))
     {
+      priv->last_rendered_state = state;
+      if (image->data.gicon.pixbuf)
+        {
+          g_object_unref (image->data.gicon.pixbuf);
+          image->data.gicon.pixbuf = NULL;
+	}
       if (priv->pixel_size != -1)
 	{
 	  width = height = priv->pixel_size;
@@ -1773,7 +1830,33 @@ ensure_pixbuf_for_gicon (GtkImage *image)
 					     MIN (width, height), flags);
       if (info)
         {
-          image->data.gicon.pixbuf = gtk_icon_info_load_icon (info, NULL);
+          GdkColor error_color, warning_color, success_color;
+          GdkColor *error_ptr, *warning_ptr, *success_ptr;
+          GtkStyle *style;
+          gboolean was_symbolic;
+
+          style = gtk_widget_get_style (GTK_WIDGET (image));
+          if (!gtk_style_lookup_color (style, "error_color", &error_color))
+            error_ptr = NULL;
+          else
+            error_ptr = &error_color;
+          if (!gtk_style_lookup_color (style, "warning_color", &warning_color))
+            warning_ptr = NULL;
+          else
+            warning_ptr = &warning_color;
+          if (!gtk_style_lookup_color (style, "success_color", &success_color))
+            success_ptr = NULL;
+          else
+            success_ptr = &success_color;
+
+          image->data.gicon.pixbuf = gtk_icon_info_load_symbolic (info,
+                                                                  &style->fg[state],
+                                                                  success_ptr,
+                                                                  warning_ptr,
+                                                                  error_ptr,
+                                                                  &was_symbolic,
+                                                                  NULL);
+          priv->was_symbolic = was_symbolic;
           gtk_icon_info_free (info);
         }
 
@@ -1784,6 +1867,7 @@ ensure_pixbuf_for_gicon (GtkImage *image)
 				    GTK_STOCK_MISSING_IMAGE,
 				    image->icon_size,
 				    NULL);
+	  priv->was_symbolic = FALSE;
 	}
     }
 }
@@ -1845,6 +1929,7 @@ gtk_image_expose (GtkWidget      *widget,
       gint x, y, mask_x, mask_y;
       GdkBitmap *mask;
       GdkPixbuf *pixbuf;
+      GtkStateType state;
       gboolean needs_state_transform;
 
       image = GTK_IMAGE (widget);
@@ -2012,7 +2097,18 @@ gtk_image_expose (GtkWidget      *widget,
           break;
 
 	case GTK_IMAGE_ICON_NAME:
-	  ensure_pixbuf_for_icon_name (image);
+	  state = gtk_widget_get_state (widget);
+	  if (state == GTK_STATE_INSENSITIVE)
+	    {
+	      ensure_pixbuf_for_icon_name (image, GTK_STATE_NORMAL);
+	    }
+	  else
+	    {
+	      ensure_pixbuf_for_icon_name (image, state);
+	      /* Already done by the loading function? */
+	      if (priv->was_symbolic)
+	        needs_state_transform = FALSE;
+	    }
 	  pixbuf = image->data.name.pixbuf;
 	  if (pixbuf)
 	    {
@@ -2023,7 +2119,18 @@ gtk_image_expose (GtkWidget      *widget,
 	  break;
 
 	case GTK_IMAGE_GICON:
-	  ensure_pixbuf_for_gicon (image);
+	  state = gtk_widget_get_state (widget);
+	  if (state == GTK_STATE_INSENSITIVE)
+	    {
+	      ensure_pixbuf_for_gicon (image, GTK_STATE_NORMAL);
+	    }
+	  else
+	    {
+	      ensure_pixbuf_for_gicon (image, state);
+	      /* Already done by the loading function? */
+	      if (priv->was_symbolic)
+	        needs_state_transform = FALSE;
+	    }
 	  pixbuf = image->data.gicon.pixbuf;
 	  if (pixbuf)
 	    {
@@ -2325,12 +2432,12 @@ gtk_image_calc_size (GtkImage *image)
                                          NULL);
       break;
     case GTK_IMAGE_ICON_NAME:
-      ensure_pixbuf_for_icon_name (image);
+      ensure_pixbuf_for_icon_name (image, GTK_STATE_NORMAL);
       pixbuf = image->data.name.pixbuf;
       if (pixbuf) g_object_ref (pixbuf);
       break;
     case GTK_IMAGE_GICON:
-      ensure_pixbuf_for_gicon (image);
+      ensure_pixbuf_for_gicon (image, GTK_STATE_NORMAL);
       pixbuf = image->data.gicon.pixbuf;
       if (pixbuf)
 	g_object_ref (pixbuf);



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