Index: gtk/gtkimage.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkimage.h,v
retrieving revision 1.15
diff -u -p -r1.15 gtkimage.h
--- gtk/gtkimage.h	5 Oct 2002 23:15:37 -0000	1.15
+++ gtk/gtkimage.h	18 Oct 2004 05:13:24 -0000
@@ -53,6 +53,7 @@ typedef struct _GtkImagePixbufData  GtkI
 typedef struct _GtkImageStockData   GtkImageStockData;
 typedef struct _GtkImageIconSetData GtkImageIconSetData;
 typedef struct _GtkImageAnimationData GtkImageAnimationData;
+typedef struct _GtkImageIconNameData  GtkImageIconNameData;
 
 struct _GtkImagePixmapData
 {
@@ -86,6 +87,13 @@ struct _GtkImageAnimationData
   guint frame_timeout;
 };
 
+struct _GtkImageIconNameData
+{
+  gchar *icon_name;
+  GdkPixbuf *pixbuf;
+  guint theme_change_id;
+};
+
 typedef enum
 {
   GTK_IMAGE_EMPTY,
@@ -94,7 +102,8 @@ typedef enum
   GTK_IMAGE_PIXBUF,
   GTK_IMAGE_STOCK,
   GTK_IMAGE_ICON_SET,
-  GTK_IMAGE_ANIMATION
+  GTK_IMAGE_ANIMATION,
+  GTK_IMAGE_ICON_NAME
 } GtkImageType;
 
 struct _GtkImage
@@ -111,12 +120,13 @@ struct _GtkImage
     GtkImageStockData stock;
     GtkImageIconSetData icon_set;
     GtkImageAnimationData anim;
+    GtkImageIconNameData name;
   } data;
 
   /* Only used with GTK_IMAGE_PIXMAP, GTK_IMAGE_IMAGE */
   GdkBitmap *mask;
 
-  /* Only used with GTK_IMAGE_STOCK, GTK_IMAGE_ICON_SET */
+  /* Only used with GTK_IMAGE_STOCK, GTK_IMAGE_ICON_SET, GTK_IMAGE_ICON_NAME */
   GtkIconSize icon_size;
 };
 
@@ -145,6 +155,8 @@ GtkWidget* gtk_image_new_from_stock     
 GtkWidget* gtk_image_new_from_icon_set  (GtkIconSet      *icon_set,
                                          GtkIconSize      size);
 GtkWidget* gtk_image_new_from_animation (GdkPixbufAnimation *animation);
+GtkWidget* gtk_image_new_from_icon_name (const gchar     *icon_name,
+					 GtkIconSize      size);
 
 void gtk_image_set_from_pixmap    (GtkImage        *image,
                                    GdkPixmap       *pixmap,
@@ -164,6 +176,9 @@ void gtk_image_set_from_icon_set  (GtkIm
                                    GtkIconSize      size);
 void gtk_image_set_from_animation (GtkImage           *image,
                                    GdkPixbufAnimation *animation);
+void gtk_image_set_from_icon_name (GtkImage        *image,
+				   const gchar     *icon_name,
+				   GtkIconSize      size);
 
 GtkImageType gtk_image_get_storage_type (GtkImage   *image);
 
@@ -181,6 +196,9 @@ void       gtk_image_get_icon_set (GtkIm
                                    GtkIconSet      **icon_set,
                                    GtkIconSize      *size);
 GdkPixbufAnimation* gtk_image_get_animation (GtkImage *image);
+void       gtk_image_get_icon_name (GtkImage        *image,
+				    gchar          **icon_name,
+				    GtkIconSize     *size);
 
 
 #ifndef GTK_DISABLE_DEPRECATED
Index: gtk/gtkimage.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkimage.c,v
retrieving revision 1.50
diff -u -p -r1.50 gtkimage.c
--- gtk/gtkimage.c	1 Sep 2004 04:57:02 -0000	1.50
+++ gtk/gtkimage.c	18 Oct 2004 05:13:26 -0000
@@ -31,6 +31,7 @@
 #include "gtkimage.h"
 #include "gtkiconfactory.h"
 #include "gtkstock.h"
+#include "gtkicontheme.h"
 #include "gtkintl.h"
 #include <string.h>
 
@@ -78,6 +79,7 @@ enum
   PROP_ICON_SET,
   PROP_ICON_SIZE,
   PROP_PIXBUF_ANIMATION,
+  PROP_ICON_NAME,
   PROP_STORAGE_TYPE
 };
 
@@ -206,6 +208,14 @@ gtk_image_class_init (GtkImageClass *cla
                                                         P_("GdkPixbufAnimation to display"),
                                                         GDK_TYPE_PIXBUF_ANIMATION,
                                                         G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_ICON_NAME,
+                                   g_param_spec_string ("icon_name",
+                                                        P_("Icon Name"),
+                                                        P_("The name of the icon from the current icon theme"),
+                                                        NULL,
+                                                        G_PARAM_READWRITE));
   
   g_object_class_install_property (gobject_class,
                                    PROP_STORAGE_TYPE,
@@ -307,6 +317,10 @@ gtk_image_set_property (GObject      *ob
         gtk_image_set_from_icon_set (image,
                                      image->data.icon_set.icon_set,
                                      g_value_get_int (value));
+      else if (image->storage_type == GTK_IMAGE_ICON_NAME)
+        gtk_image_set_from_icon_name (image,
+				      image->data.name.icon_name,
+				      g_value_get_int (value));
       else
         /* Save to be used when STOCK or ICON_SET property comes in */
         image->icon_size = g_value_get_int (value);
@@ -315,7 +329,9 @@ gtk_image_set_property (GObject      *ob
       gtk_image_set_from_animation (image,
                                     g_value_get_object (value));
       break;
-      
+    case PROP_ICON_NAME:
+      gtk_image_set_from_icon_name (image, g_value_get_string (value),
+				    image->icon_size);
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -388,6 +404,13 @@ gtk_image_get_property (GObject     *obj
         g_value_set_object (value,
                             image->data.anim.anim);
       break;
+    case PROP_ICON_NAME:
+      if (image->storage_type != GTK_IMAGE_ICON_NAME)
+	g_value_set_object (value, NULL);
+      else
+	g_value_set_string (value,
+			    image->data.name.icon_name);
+      break;
     case PROP_STORAGE_TYPE:
       g_value_set_enum (value, image->storage_type);
       break;
@@ -600,6 +623,31 @@ gtk_image_new_from_animation (GdkPixbufA
 }
 
 /**
+ * gtk_image_new_from_icon_name:
+ * @icon_name: an icon name
+ * @size: a stock icon size
+ * 
+ * Creates a #GtkImage displaying an icon from the current icon theme.
+ * If the icon name isn't known, a "broken image" icon will be
+ * displayed instead.  If the current icon theme is changed, the icon
+ * will be updated appropriately.
+ * 
+ * Return value: a new #GtkImage displaying the stock icon
+ **/
+GtkWidget*
+gtk_image_new_from_icon_name (const gchar    *icon_name,
+			      GtkIconSize     size)
+{
+  GtkImage *image;
+
+  image = g_object_new (GTK_TYPE_IMAGE, NULL);
+
+  gtk_image_set_from_icon_name (image, icon_name, size);
+
+  return GTK_WIDGET (image);
+}
+
+/**
  * gtk_image_set_from_pixmap:
  * @image: a #GtkImage
  * @pixmap: a #GdkPixmap or %NULL
@@ -926,6 +974,50 @@ gtk_image_set_from_animation (GtkImage  
 }
 
 /**
+ * gtk_image_set_from_icon_name:
+ * @image: a #GtkImage
+ * @icon_name: an icon name
+ * @size: an icon size
+ *
+ * See gtk_image_new_from_icon_name() for details.
+ * 
+ **/
+void
+gtk_image_set_from_icon_name  (GtkImage       *image,
+			       const gchar    *icon_name,
+			       GtkIconSize     size)
+{
+  gchar *new_name;
+  
+  g_return_if_fail (GTK_IS_IMAGE (image));
+
+  g_object_freeze_notify (G_OBJECT (image));
+
+  /* in case stock_id == image->data.stock.stock_id */
+  new_name = g_strdup (icon_name);
+  
+  gtk_image_reset (image);
+
+  if (new_name)
+    {
+      image->storage_type = GTK_IMAGE_ICON_NAME;
+      
+      image->data.name.icon_name = new_name;
+      image->icon_size = size;
+
+      /* Size is demand-computed in size request method
+       * if we're a icon theme image, since changing the
+       * style impacts the size request
+       */
+    }
+
+  g_object_notify (G_OBJECT (image), "icon_name");
+  g_object_notify (G_OBJECT (image), "icon_size");
+  
+  g_object_thaw_notify (G_OBJECT (image));
+}
+
+/**
  * gtk_image_get_storage_type:
  * @image: a #GtkImage
  * 
@@ -1113,6 +1205,38 @@ gtk_image_get_animation (GtkImage *image
 }
 
 /**
+ * gtk_image_get_icon_name:
+ * @image: a #GtkImage
+ * @icon_name: place to store an icon name
+ * @size: place to store an icon size
+ *
+ * Gets the icon name and size being displayed by the #GtkImage.
+ * The storage type of the image must be %GTK_IMAGE_EMPTY or
+ * %GTK_IMAGE_ICON_NAME (see gtk_image_get_storage_type()).
+ * The returned string is owned by the #GtkImage and should not
+ * be freed.
+ * 
+ **/
+void
+gtk_image_get_icon_name  (GtkImage        *image,
+			  gchar          **icon_name,
+			  GtkIconSize     *size)
+{
+  g_return_if_fail (GTK_IS_IMAGE (image));
+  g_return_if_fail (image->storage_type == GTK_IMAGE_ICON_NAME ||
+                    image->storage_type == GTK_IMAGE_EMPTY);
+
+  if (image->storage_type == GTK_IMAGE_EMPTY)
+    image->data.name.icon_name = NULL;
+  
+  if (icon_name)
+    *icon_name = image->data.name.icon_name;
+
+  if (size)
+    *size = image->icon_size;
+}
+
+/**
  * gtk_image_new:
  * 
  * Creates a new empty #GtkImage widget.
@@ -1167,9 +1291,29 @@ gtk_image_reset_anim_iter (GtkImage *ima
 }
 
 static void
+gtk_image_reset_icon_theme_change_cb (GtkImage *image)
+{
+  GdkScreen *screen;
+  GtkIconTheme *icon_theme;
+
+  if (image->storage_type == GTK_IMAGE_ICON_NAME)
+    {
+      if (image->data.name.theme_change_id)
+	{
+	  screen = gtk_widget_get_screen (GTK_WIDGET (image));
+	  icon_theme = gtk_icon_theme_get_for_screen (screen);
+	  g_signal_handler_disconnect (icon_theme,
+				       image->data.name.theme_change_id);
+	}
+      image->data.name.theme_change_id = 0;
+    }
+}
+
+static void
 gtk_image_unmap (GtkWidget *widget)
 {
   gtk_image_reset_anim_iter (GTK_IMAGE (widget));
+  gtk_image_reset_icon_theme_change_cb (GTK_IMAGE (widget));
 
   if (GTK_WIDGET_CLASS (parent_class)->unmap)
     GTK_WIDGET_CLASS (parent_class)->unmap (widget);
@@ -1179,6 +1323,7 @@ static void
 gtk_image_unrealize (GtkWidget *widget)
 {
   gtk_image_reset_anim_iter (GTK_IMAGE (widget));
+  gtk_image_reset_icon_theme_change_cb (GTK_IMAGE (widget));
 
   if (GTK_WIDGET_CLASS (parent_class)->unrealize)
     GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
@@ -1210,6 +1355,56 @@ animation_timeout (gpointer data)
   return FALSE;
 }
 
+static void
+icon_theme_changed (GtkIconTheme *icon_theme,
+		    GtkImage     *image)
+{
+  if (image->data.name.pixbuf)
+    g_object_unref (image->data.name.pixbuf);
+  image->data.name.pixbuf = NULL;
+
+  gtk_widget_queue_draw (GTK_WIDGET (image));
+}
+
+static void
+ensure_pixbuf_for_icon_name (GtkImage *image)
+{
+  GdkScreen *screen;
+  GtkIconTheme *icon_theme;
+  GtkSettings *settings;
+  gint width, height;
+  GError *error = NULL;
+
+  g_return_if_fail (image->storage_type == GTK_IMAGE_ICON_NAME);
+
+  screen = gtk_widget_get_screen (GTK_WIDGET (image));
+  icon_theme = gtk_icon_theme_get_for_screen (screen);
+  settings = gtk_settings_get_for_screen (screen);
+  if (image->data.name.pixbuf == NULL)
+    {
+      if (!gtk_icon_size_lookup_for_settings (settings,
+					      image->icon_size,
+					      &width, &height))
+	{
+	  g_warning ("Invalid icon size %d\n", image->icon_size);
+	  width = height = 24;
+	}
+      image->data.name.pixbuf =
+	gtk_icon_theme_load_icon (icon_theme,
+				  image->data.name.icon_name,
+				  MIN (width, height), 0, &error);
+      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);
+	}
+    }
+}
+
 /*
  * Like gdk_rectangle_intersect (dest, src, dest), but make 
  * sure that the origin of dest is moved by an "even" offset. 
@@ -1266,6 +1461,8 @@ gtk_image_expose (GtkWidget      *widget
       GdkBitmap *mask;
       GdkPixbuf *pixbuf;
       gboolean needs_state_transform;
+      GdkScreen *screen;
+      GtkIconTheme *icon_theme;
       
       image = GTK_IMAGE (widget);
       misc = GTK_MISC (widget);
@@ -1433,6 +1630,26 @@ gtk_image_expose (GtkWidget      *widget
           }
           break;
 
+	case GTK_IMAGE_ICON_NAME:
+	  if (image->data.name.theme_change_id == 0)
+	    {
+	      screen = gtk_widget_get_screen (widget);
+	      icon_theme = gtk_icon_theme_get_for_screen (screen);
+	      image->data.name.theme_change_id =
+		g_signal_connect_object (icon_theme, "changed",
+					 G_CALLBACK (icon_theme_changed),
+					 image, 0);
+	    }
+	  ensure_pixbuf_for_icon_name (image);
+	  pixbuf = image->data.name.pixbuf;
+	  if (pixbuf)
+	    {
+	      g_object_ref (pixbuf);
+	      image_bound.width = gdk_pixbuf_get_width (pixbuf);
+	      image_bound.height = gdk_pixbuf_get_height (pixbuf);
+	    }
+	  break;
+
         case GTK_IMAGE_EMPTY:
           g_assert_not_reached ();
           break;
@@ -1522,6 +1739,7 @@ gtk_image_expose (GtkWidget      *widget
                 case GTK_IMAGE_STOCK:
                 case GTK_IMAGE_ICON_SET:
                 case GTK_IMAGE_ANIMATION:
+		case GTK_IMAGE_ICON_NAME:
                 case GTK_IMAGE_EMPTY:
                   g_assert_not_reached ();
                   break;
@@ -1619,6 +1837,20 @@ gtk_image_clear (GtkImage *image)
       g_object_notify (G_OBJECT (image), "pixbuf_animation");
       
       break;
+
+    case GTK_IMAGE_ICON_NAME:
+      gtk_image_reset_icon_theme_change_cb (image);
+
+      if (image->data.name.icon_name)
+	g_free (image->data.name.icon_name);
+      image->data.name.icon_name = NULL;
+      if (image->data.name.pixbuf)
+	g_object_unref (image->data.name.pixbuf);
+      image->data.name.pixbuf = NULL;
+
+      g_object_notify (G_OBJECT (image), "icon_name");
+
+      break;
       
     case GTK_IMAGE_EMPTY:
     default:
@@ -1670,7 +1902,11 @@ gtk_image_calc_size (GtkImage *image)
                                          widget,
                                          NULL);
       break;
-      
+    case GTK_IMAGE_ICON_NAME:
+      ensure_pixbuf_for_icon_name (image);
+      pixbuf = image->data.name.pixbuf;
+      if (pixbuf) g_object_ref (pixbuf);
+      break;
     default:
       break;
     }
