]> Pileus Git - ~andy/gtk/blob - gtk/gtkimage.c
GtkImagePrivate: Improve struct packing
[~andy/gtk] / gtk / gtkimage.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include "config.h"
28
29 #include <math.h>
30 #include <string.h>
31
32 #include "gtkcontainer.h"
33 #include "gtkimageprivate.h"
34 #include "gtkiconfactory.h"
35 #include "gtkstock.h"
36 #include "gtkicontheme.h"
37 #include "gtksizerequest.h"
38 #include "gtkintl.h"
39 #include "gtkprivate.h"
40 #include "gtktypebuiltins.h"
41
42 /**
43  * SECTION:gtkimage
44  * @Short_description: A widget displaying an image
45  * @Title: GtkImage
46  * @See_also:#GdkPixbuf
47  *
48  * The #GtkImage widget displays an image. Various kinds of object
49  * can be displayed as an image; most typically, you would load a
50  * #GdkPixbuf ("pixel buffer") from a file, and then display that.
51  * There's a convenience function to do this, gtk_image_new_from_file(),
52  * used as follows:
53  * <informalexample><programlisting>
54  *   GtkWidget *image;
55  *   image = gtk_image_new_from_file ("myfile.png");
56  * </programlisting></informalexample>
57  * If the file isn't loaded successfully, the image will contain a
58  * "broken image" icon similar to that used in many web browsers.
59  * If you want to handle errors in loading the file yourself,
60  * for example by displaying an error message, then load the image with
61  * gdk_pixbuf_new_from_file(), then create the #GtkImage with
62  * gtk_image_new_from_pixbuf().
63  *
64  * The image file may contain an animation, if so the #GtkImage will
65  * display an animation (#GdkPixbufAnimation) instead of a static image.
66  *
67  * #GtkImage is a subclass of #GtkMisc, which implies that you can
68  * align it (center, left, right) and add padding to it, using
69  * #GtkMisc methods.
70  *
71  * #GtkImage is a "no window" widget (has no #GdkWindow of its own),
72  * so by default does not receive events. If you want to receive events
73  * on the image, such as button clicks, place the image inside a
74  * #GtkEventBox, then connect to the event signals on the event box.
75  * <example>
76  * <title>Handling button press events on a
77  * <structname>GtkImage</structname>.</title>
78  * <programlisting>
79  *   static gboolean
80  *   button_press_callback (GtkWidget      *event_box,
81  *                          GdkEventButton *event,
82  *                          gpointer        data)
83  *   {
84  *     g_print ("Event box clicked at coordinates &percnt;f,&percnt;f\n",
85  *              event->x, event->y);
86  *
87  *     /<!---->* Returning TRUE means we handled the event, so the signal
88  *      * emission should be stopped (don't call any further
89  *      * callbacks that may be connected). Return FALSE
90  *      * to continue invoking callbacks.
91  *      *<!---->/
92  *     return TRUE;
93  *   }
94  *
95  *   static GtkWidget*
96  *   create_image (void)
97  *   {
98  *     GtkWidget *image;
99  *     GtkWidget *event_box;
100  *
101  *     image = gtk_image_new_from_file ("myfile.png");
102  *
103  *     event_box = gtk_event_box_new (<!-- -->);
104  *
105  *     gtk_container_add (GTK_CONTAINER (event_box), image);
106  *
107  *     g_signal_connect (G_OBJECT (event_box),
108  *                       "button_press_event",
109  *                       G_CALLBACK (button_press_callback),
110  *                       image);
111  *
112  *     return image;
113  *   }
114  * </programlisting>
115  * </example>
116  *
117  * When handling events on the event box, keep in mind that coordinates
118  * in the image may be different from event box coordinates due to
119  * the alignment and padding settings on the image (see #GtkMisc).
120  * The simplest way to solve this is to set the alignment to 0.0
121  * (left/top), and set the padding to zero. Then the origin of
122  * the image will be the same as the origin of the event box.
123  *
124  * Sometimes an application will want to avoid depending on external data
125  * files, such as image files. GTK+ comes with a program to avoid this,
126  * called <application>gdk-pixbuf-csource</application>. This program
127  * allows you to convert an image into a C variable declaration, which
128  * can then be loaded into a #GdkPixbuf using
129  * gdk_pixbuf_new_from_inline().
130  */
131
132
133 struct _GtkImagePrivate
134 {
135   GtkIconSize           icon_size;      /* Only used with GTK_IMAGE_STOCK, GTK_IMAGE_ICON_SET, GTK_IMAGE_ICON_NAME */
136   GtkImageType          storage_type;
137
138   union
139   {
140     GtkImagePixbufData     pixbuf;
141     GtkImageStockData      stock;
142     GtkImageIconSetData    icon_set;
143     GtkImageAnimationData  anim;
144     GtkImageIconNameData   name;
145     GtkImageGIconData      gicon;
146   } data;
147
148   gchar                *filename;       /* Only used with GTK_IMAGE_ANIMATION, GTK_IMAGE_PIXBUF */
149   gint                  last_rendered_state;  /* a GtkStateFlags, with -1 meaning an invalid state,
150                                                * only used with GTK_IMAGE_GICON, GTK_IMAGE_ICON_NAME */
151   gint                  pixel_size;
152   gint                  required_width;
153   gint                  required_height;
154   guint                 need_calc_size : 1;
155   guint                 use_fallback   : 1;
156   guint                 was_symbolic   : 1;
157 };
158
159
160 #define DEFAULT_ICON_SIZE GTK_ICON_SIZE_BUTTON
161 static gint gtk_image_draw                 (GtkWidget    *widget,
162                                             cairo_t      *cr);
163 static void gtk_image_unmap                (GtkWidget    *widget);
164 static void gtk_image_unrealize            (GtkWidget    *widget);
165 static void gtk_image_get_preferred_width  (GtkWidget    *widget,
166                                             gint         *minimum,
167                                             gint         *natural);
168 static void gtk_image_get_preferred_height (GtkWidget    *widget,
169                                             gint         *minimum,
170                                             gint         *natural);
171
172 static void gtk_image_style_updated        (GtkWidget    *widget);
173 static void gtk_image_screen_changed       (GtkWidget    *widget,
174                                             GdkScreen    *prev_screen);
175 static void gtk_image_destroy              (GtkWidget    *widget);
176 static void gtk_image_reset                (GtkImage     *image);
177 static void gtk_image_calc_size            (GtkImage     *image);
178
179 static void gtk_image_update_size          (GtkImage     *image,
180                                             gint          image_width,
181                                             gint          image_height);
182
183 static void gtk_image_set_property         (GObject      *object,
184                                             guint         prop_id,
185                                             const GValue *value,
186                                             GParamSpec   *pspec);
187 static void gtk_image_get_property         (GObject      *object,
188                                             guint         prop_id,
189                                             GValue       *value,
190                                             GParamSpec   *pspec);
191
192 static void icon_theme_changed             (GtkImage     *image);
193
194 enum
195 {
196   PROP_0,
197   PROP_PIXBUF,
198   PROP_FILE,
199   PROP_STOCK,
200   PROP_ICON_SET,
201   PROP_ICON_SIZE,
202   PROP_PIXEL_SIZE,
203   PROP_PIXBUF_ANIMATION,
204   PROP_ICON_NAME,
205   PROP_STORAGE_TYPE,
206   PROP_GICON,
207   PROP_USE_FALLBACK
208 };
209
210 G_DEFINE_TYPE (GtkImage, gtk_image, GTK_TYPE_MISC)
211
212 static void
213 gtk_image_class_init (GtkImageClass *class)
214 {
215   GObjectClass *gobject_class;
216   GtkWidgetClass *widget_class;
217
218   gobject_class = G_OBJECT_CLASS (class);
219   
220   gobject_class->set_property = gtk_image_set_property;
221   gobject_class->get_property = gtk_image_get_property;
222
223   widget_class = GTK_WIDGET_CLASS (class);
224   widget_class->draw = gtk_image_draw;
225   widget_class->destroy = gtk_image_destroy;
226   widget_class->get_preferred_width = gtk_image_get_preferred_width;
227   widget_class->get_preferred_height = gtk_image_get_preferred_height;
228   widget_class->unmap = gtk_image_unmap;
229   widget_class->unrealize = gtk_image_unrealize;
230   widget_class->style_updated = gtk_image_style_updated;
231   widget_class->screen_changed = gtk_image_screen_changed;
232   
233   g_object_class_install_property (gobject_class,
234                                    PROP_PIXBUF,
235                                    g_param_spec_object ("pixbuf",
236                                                         P_("Pixbuf"),
237                                                         P_("A GdkPixbuf to display"),
238                                                         GDK_TYPE_PIXBUF,
239                                                         GTK_PARAM_READWRITE));
240
241   g_object_class_install_property (gobject_class,
242                                    PROP_FILE,
243                                    g_param_spec_string ("file",
244                                                         P_("Filename"),
245                                                         P_("Filename to load and display"),
246                                                         NULL,
247                                                         GTK_PARAM_READWRITE));
248   
249
250   g_object_class_install_property (gobject_class,
251                                    PROP_STOCK,
252                                    g_param_spec_string ("stock",
253                                                         P_("Stock ID"),
254                                                         P_("Stock ID for a stock image to display"),
255                                                         NULL,
256                                                         GTK_PARAM_READWRITE));
257   
258   g_object_class_install_property (gobject_class,
259                                    PROP_ICON_SET,
260                                    g_param_spec_boxed ("icon-set",
261                                                        P_("Icon set"),
262                                                        P_("Icon set to display"),
263                                                        GTK_TYPE_ICON_SET,
264                                                        GTK_PARAM_READWRITE));
265   
266   g_object_class_install_property (gobject_class,
267                                    PROP_ICON_SIZE,
268                                    g_param_spec_int ("icon-size",
269                                                      P_("Icon size"),
270                                                      P_("Symbolic size to use for stock icon, icon set or named icon"),
271                                                      0, G_MAXINT,
272                                                      DEFAULT_ICON_SIZE,
273                                                      GTK_PARAM_READWRITE));
274   /**
275    * GtkImage:pixel-size:
276    *
277    * The "pixel-size" property can be used to specify a fixed size
278    * overriding the #GtkImage:icon-size property for images of type 
279    * %GTK_IMAGE_ICON_NAME. 
280    *
281    * Since: 2.6
282    */
283   g_object_class_install_property (gobject_class,
284                                    PROP_PIXEL_SIZE,
285                                    g_param_spec_int ("pixel-size",
286                                                      P_("Pixel size"),
287                                                      P_("Pixel size to use for named icon"),
288                                                      -1, G_MAXINT,
289                                                      -1,
290                                                      GTK_PARAM_READWRITE));
291   
292   g_object_class_install_property (gobject_class,
293                                    PROP_PIXBUF_ANIMATION,
294                                    g_param_spec_object ("pixbuf-animation",
295                                                         P_("Animation"),
296                                                         P_("GdkPixbufAnimation to display"),
297                                                         GDK_TYPE_PIXBUF_ANIMATION,
298                                                         GTK_PARAM_READWRITE));
299
300   /**
301    * GtkImage:icon-name:
302    *
303    * The name of the icon in the icon theme. If the icon theme is
304    * changed, the image will be updated automatically.
305    *
306    * Since: 2.6
307    */
308   g_object_class_install_property (gobject_class,
309                                    PROP_ICON_NAME,
310                                    g_param_spec_string ("icon-name",
311                                                         P_("Icon Name"),
312                                                         P_("The name of the icon from the icon theme"),
313                                                         NULL,
314                                                         GTK_PARAM_READWRITE));
315   
316   /**
317    * GtkImage:gicon:
318    *
319    * The GIcon displayed in the GtkImage. For themed icons,
320    * If the icon theme is changed, the image will be updated
321    * automatically.
322    *
323    * Since: 2.14
324    */
325   g_object_class_install_property (gobject_class,
326                                    PROP_GICON,
327                                    g_param_spec_object ("gicon",
328                                                         P_("Icon"),
329                                                         P_("The GIcon being displayed"),
330                                                         G_TYPE_ICON,
331                                                         GTK_PARAM_READWRITE));
332   
333   g_object_class_install_property (gobject_class,
334                                    PROP_STORAGE_TYPE,
335                                    g_param_spec_enum ("storage-type",
336                                                       P_("Storage type"),
337                                                       P_("The representation being used for image data"),
338                                                       GTK_TYPE_IMAGE_TYPE,
339                                                       GTK_IMAGE_EMPTY,
340                                                       GTK_PARAM_READABLE));
341
342   /**
343    * GtkImage:use-fallback:
344    *
345    * Whether the icon displayed in the GtkImage will use
346    * standard icon names fallback. The value of this property
347    * is only relevant for images of type %GTK_IMAGE_ICON_NAME
348    * and %GTK_IMAGE_GICON.
349    *
350    * Since: 3.0
351    */
352   g_object_class_install_property (gobject_class,
353                                    PROP_USE_FALLBACK,
354                                    g_param_spec_boolean ("use-fallback",
355                                                          P_("Use Fallback"),
356                                                          P_("Whether to use icon names fallback"),
357                                                          FALSE,
358                                                          GTK_PARAM_READWRITE));
359
360   g_type_class_add_private (class, sizeof (GtkImagePrivate));
361 }
362
363 static void
364 gtk_image_init (GtkImage *image)
365 {
366   GtkImagePrivate *priv;
367
368   image->priv = G_TYPE_INSTANCE_GET_PRIVATE (image,
369                                              GTK_TYPE_IMAGE,
370                                              GtkImagePrivate);
371   priv = image->priv;
372
373   gtk_widget_set_has_window (GTK_WIDGET (image), FALSE);
374
375   priv->storage_type = GTK_IMAGE_EMPTY;
376   priv->icon_size = DEFAULT_ICON_SIZE;
377
378   priv->pixel_size = -1;
379
380   priv->filename = NULL;
381 }
382
383 static void
384 gtk_image_destroy (GtkWidget *widget)
385 {
386   GtkImage *image = GTK_IMAGE (widget);
387
388   gtk_image_reset (image);
389
390   GTK_WIDGET_CLASS (gtk_image_parent_class)->destroy (widget);
391 }
392
393 static void 
394 gtk_image_set_property (GObject      *object,
395                         guint         prop_id,
396                         const GValue *value,
397                         GParamSpec   *pspec)
398 {
399   GtkImage *image = GTK_IMAGE (object);
400   GtkImagePrivate *priv = image->priv;
401
402   switch (prop_id)
403     {
404     case PROP_PIXBUF:
405       gtk_image_set_from_pixbuf (image,
406                                  g_value_get_object (value));
407       break;
408     case PROP_FILE:
409       gtk_image_set_from_file (image, g_value_get_string (value));
410       break;
411     case PROP_STOCK:
412       gtk_image_set_from_stock (image, g_value_get_string (value),
413                                 priv->icon_size);
414       break;
415     case PROP_ICON_SET:
416       gtk_image_set_from_icon_set (image, g_value_get_boxed (value),
417                                    priv->icon_size);
418       break;
419     case PROP_ICON_SIZE:
420       if (priv->storage_type == GTK_IMAGE_STOCK)
421         gtk_image_set_from_stock (image,
422                                   priv->data.stock.stock_id,
423                                   g_value_get_int (value));
424       else if (priv->storage_type == GTK_IMAGE_ICON_SET)
425         gtk_image_set_from_icon_set (image,
426                                      priv->data.icon_set.icon_set,
427                                      g_value_get_int (value));
428       else if (priv->storage_type == GTK_IMAGE_ICON_NAME)
429         gtk_image_set_from_icon_name (image,
430                                       priv->data.name.icon_name,
431                                       g_value_get_int (value));
432       else if (priv->storage_type == GTK_IMAGE_GICON)
433         gtk_image_set_from_gicon (image,
434                                   priv->data.gicon.icon,
435                                   g_value_get_int (value));
436       else
437         /* Save to be used when STOCK, ICON_SET, ICON_NAME or GICON property comes in */
438         priv->icon_size = g_value_get_int (value);
439       break;
440     case PROP_PIXEL_SIZE:
441       gtk_image_set_pixel_size (image, g_value_get_int (value));
442       break;
443     case PROP_PIXBUF_ANIMATION:
444       gtk_image_set_from_animation (image,
445                                     g_value_get_object (value));
446       break;
447     case PROP_ICON_NAME:
448       gtk_image_set_from_icon_name (image, g_value_get_string (value),
449                                     priv->icon_size);
450       break;
451     case PROP_GICON:
452       gtk_image_set_from_gicon (image, g_value_get_object (value),
453                                 priv->icon_size);
454       break;
455
456     case PROP_USE_FALLBACK:
457       priv->use_fallback = g_value_get_boolean (value);
458       if (priv->storage_type == GTK_IMAGE_ICON_NAME)
459         gtk_image_set_from_icon_name (image,
460                                       priv->data.name.icon_name,
461                                       priv->icon_size);
462       else if (priv->storage_type == GTK_IMAGE_GICON)
463         gtk_image_set_from_gicon (image,
464                                   priv->data.gicon.icon,
465                                   priv->icon_size);
466       break;
467
468     default:
469       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
470       break;
471     }
472 }
473
474 static void 
475 gtk_image_get_property (GObject     *object,
476                         guint        prop_id,
477                         GValue      *value,
478                         GParamSpec  *pspec)
479 {
480   GtkImage *image = GTK_IMAGE (object);
481   GtkImagePrivate *priv = image->priv;
482
483   /* The "getter" functions whine if you try to get the wrong
484    * storage type. This function is instead robust against that,
485    * so that GUI builders don't have to jump through hoops
486    * to avoid g_warning
487    */
488   
489   switch (prop_id)
490     {
491     case PROP_PIXBUF:
492       if (priv->storage_type != GTK_IMAGE_PIXBUF)
493         g_value_set_object (value, NULL);
494       else
495         g_value_set_object (value,
496                             gtk_image_get_pixbuf (image));
497       break;
498     case PROP_FILE:
499       g_value_set_string (value, priv->filename);
500       break;
501     case PROP_STOCK:
502       if (priv->storage_type != GTK_IMAGE_STOCK)
503         g_value_set_string (value, NULL);
504       else
505         g_value_set_string (value,
506                             priv->data.stock.stock_id);
507       break;
508     case PROP_ICON_SET:
509       if (priv->storage_type != GTK_IMAGE_ICON_SET)
510         g_value_set_boxed (value, NULL);
511       else
512         g_value_set_boxed (value,
513                            priv->data.icon_set.icon_set);
514       break;      
515     case PROP_ICON_SIZE:
516       g_value_set_int (value, priv->icon_size);
517       break;
518     case PROP_PIXEL_SIZE:
519       g_value_set_int (value, priv->pixel_size);
520       break;
521     case PROP_PIXBUF_ANIMATION:
522       if (priv->storage_type != GTK_IMAGE_ANIMATION)
523         g_value_set_object (value, NULL);
524       else
525         g_value_set_object (value,
526                             priv->data.anim.anim);
527       break;
528     case PROP_ICON_NAME:
529       if (priv->storage_type != GTK_IMAGE_ICON_NAME)
530         g_value_set_string (value, NULL);
531       else
532         g_value_set_string (value,
533                             priv->data.name.icon_name);
534       break;
535     case PROP_GICON:
536       if (priv->storage_type != GTK_IMAGE_GICON)
537         g_value_set_object (value, NULL);
538       else
539         g_value_set_object (value,
540                             priv->data.gicon.icon);
541       break;
542     case PROP_STORAGE_TYPE:
543       g_value_set_enum (value, priv->storage_type);
544       break;
545
546     case PROP_USE_FALLBACK:
547       g_value_set_boolean (value, priv->use_fallback);
548       break;
549       
550     default:
551       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
552       break;
553     }
554 }
555
556
557 /**
558  * gtk_image_new_from_file:
559  * @filename: (type filename): a filename
560  * 
561  * Creates a new #GtkImage displaying the file @filename. If the file
562  * isn't found or can't be loaded, the resulting #GtkImage will
563  * display a "broken image" icon. This function never returns %NULL,
564  * it always returns a valid #GtkImage widget.
565  *
566  * If the file contains an animation, the image will contain an
567  * animation.
568  *
569  * If you need to detect failures to load the file, use
570  * gdk_pixbuf_new_from_file() to load the file yourself, then create
571  * the #GtkImage from the pixbuf. (Or for animations, use
572  * gdk_pixbuf_animation_new_from_file()).
573  *
574  * The storage type (gtk_image_get_storage_type()) of the returned
575  * image is not defined, it will be whatever is appropriate for
576  * displaying the file.
577  * 
578  * Return value: a new #GtkImage
579  **/
580 GtkWidget*
581 gtk_image_new_from_file   (const gchar *filename)
582 {
583   GtkImage *image;
584
585   image = g_object_new (GTK_TYPE_IMAGE, NULL);
586
587   gtk_image_set_from_file (image, filename);
588
589   return GTK_WIDGET (image);
590 }
591
592 /**
593  * gtk_image_new_from_pixbuf:
594  * @pixbuf: (allow-none): a #GdkPixbuf, or %NULL
595  *
596  * Creates a new #GtkImage displaying @pixbuf.
597  * The #GtkImage does not assume a reference to the
598  * pixbuf; you still need to unref it if you own references.
599  * #GtkImage will add its own reference rather than adopting yours.
600  * 
601  * Note that this function just creates an #GtkImage from the pixbuf. The
602  * #GtkImage created will not react to state changes. Should you want that, 
603  * you should use gtk_image_new_from_icon_set().
604  * 
605  * Return value: a new #GtkImage
606  **/
607 GtkWidget*
608 gtk_image_new_from_pixbuf (GdkPixbuf *pixbuf)
609 {
610   GtkImage *image;
611
612   image = g_object_new (GTK_TYPE_IMAGE, NULL);
613
614   gtk_image_set_from_pixbuf (image, pixbuf);
615
616   return GTK_WIDGET (image);  
617 }
618
619 /**
620  * gtk_image_new_from_stock:
621  * @stock_id: a stock icon name
622  * @size: (type int): a stock icon size
623  * 
624  * Creates a #GtkImage displaying a stock icon. Sample stock icon
625  * names are #GTK_STOCK_OPEN, #GTK_STOCK_QUIT. Sample stock sizes
626  * are #GTK_ICON_SIZE_MENU, #GTK_ICON_SIZE_SMALL_TOOLBAR. If the stock
627  * icon name isn't known, the image will be empty.
628  * You can register your own stock icon names, see
629  * gtk_icon_factory_add_default() and gtk_icon_factory_add().
630  * 
631  * Return value: a new #GtkImage displaying the stock icon
632  **/
633 GtkWidget*
634 gtk_image_new_from_stock (const gchar    *stock_id,
635                           GtkIconSize     size)
636 {
637   GtkImage *image;
638
639   image = g_object_new (GTK_TYPE_IMAGE, NULL);
640
641   gtk_image_set_from_stock (image, stock_id, size);
642
643   return GTK_WIDGET (image);
644 }
645
646 /**
647  * gtk_image_new_from_icon_set:
648  * @icon_set: a #GtkIconSet
649  * @size: (type int): a stock icon size
650  *
651  * Creates a #GtkImage displaying an icon set. Sample stock sizes are
652  * #GTK_ICON_SIZE_MENU, #GTK_ICON_SIZE_SMALL_TOOLBAR. Instead of using
653  * this function, usually it's better to create a #GtkIconFactory, put
654  * your icon sets in the icon factory, add the icon factory to the
655  * list of default factories with gtk_icon_factory_add_default(), and
656  * then use gtk_image_new_from_stock(). This will allow themes to
657  * override the icon you ship with your application.
658  *
659  * The #GtkImage does not assume a reference to the
660  * icon set; you still need to unref it if you own references.
661  * #GtkImage will add its own reference rather than adopting yours.
662  * 
663  * Return value: a new #GtkImage
664  **/
665 GtkWidget*
666 gtk_image_new_from_icon_set (GtkIconSet     *icon_set,
667                              GtkIconSize     size)
668 {
669   GtkImage *image;
670
671   image = g_object_new (GTK_TYPE_IMAGE, NULL);
672
673   gtk_image_set_from_icon_set (image, icon_set, size);
674
675   return GTK_WIDGET (image);
676 }
677
678 /**
679  * gtk_image_new_from_animation:
680  * @animation: an animation
681  * 
682  * Creates a #GtkImage displaying the given animation.
683  * The #GtkImage does not assume a reference to the
684  * animation; you still need to unref it if you own references.
685  * #GtkImage will add its own reference rather than adopting yours.
686  *
687  * Note that the animation frames are shown using a timeout with
688  * #G_PRIORITY_DEFAULT. When using animations to indicate busyness,
689  * keep in mind that the animation will only be shown if the main loop
690  * is not busy with something that has a higher priority.
691  *
692  * Return value: a new #GtkImage widget
693  **/
694 GtkWidget*
695 gtk_image_new_from_animation (GdkPixbufAnimation *animation)
696 {
697   GtkImage *image;
698
699   g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), NULL);
700   
701   image = g_object_new (GTK_TYPE_IMAGE, NULL);
702
703   gtk_image_set_from_animation (image, animation);
704
705   return GTK_WIDGET (image);
706 }
707
708 /**
709  * gtk_image_new_from_icon_name:
710  * @icon_name: an icon name
711  * @size: (type int): a stock icon size
712  * 
713  * Creates a #GtkImage displaying an icon from the current icon theme.
714  * If the icon name isn't known, a "broken image" icon will be
715  * displayed instead.  If the current icon theme is changed, the icon
716  * will be updated appropriately.
717  * 
718  * Return value: a new #GtkImage displaying the themed icon
719  *
720  * Since: 2.6
721  **/
722 GtkWidget*
723 gtk_image_new_from_icon_name (const gchar    *icon_name,
724                               GtkIconSize     size)
725 {
726   GtkImage *image;
727
728   image = g_object_new (GTK_TYPE_IMAGE, NULL);
729
730   gtk_image_set_from_icon_name (image, icon_name, size);
731
732   return GTK_WIDGET (image);
733 }
734
735 /**
736  * gtk_image_new_from_gicon:
737  * @icon: an icon
738  * @size: (type int): a stock icon size
739  * 
740  * Creates a #GtkImage displaying an icon from the current icon theme.
741  * If the icon name isn't known, a "broken image" icon will be
742  * displayed instead.  If the current icon theme is changed, the icon
743  * will be updated appropriately.
744  * 
745  * Return value: a new #GtkImage displaying the themed icon
746  *
747  * Since: 2.14
748  **/
749 GtkWidget*
750 gtk_image_new_from_gicon (GIcon *icon,
751                           GtkIconSize     size)
752 {
753   GtkImage *image;
754
755   image = g_object_new (GTK_TYPE_IMAGE, NULL);
756
757   gtk_image_set_from_gicon (image, icon, size);
758
759   return GTK_WIDGET (image);
760 }
761
762 /**
763  * gtk_image_set_from_file:
764  * @image: a #GtkImage
765  * @filename: (type filename) (allow-none): a filename or %NULL
766  *
767  * See gtk_image_new_from_file() for details.
768  **/
769 void
770 gtk_image_set_from_file   (GtkImage    *image,
771                            const gchar *filename)
772 {
773   GtkImagePrivate *priv;
774   GdkPixbufAnimation *anim;
775   
776   g_return_if_fail (GTK_IS_IMAGE (image));
777
778   priv = image->priv;
779
780   g_object_freeze_notify (G_OBJECT (image));
781   
782   gtk_image_clear (image);
783
784   if (filename == NULL)
785     {
786       priv->filename = NULL;
787       g_object_thaw_notify (G_OBJECT (image));
788       return;
789     }
790
791   anim = gdk_pixbuf_animation_new_from_file (filename, NULL);
792
793   if (anim == NULL)
794     {
795       gtk_image_set_from_stock (image,
796                                 GTK_STOCK_MISSING_IMAGE,
797                                 GTK_ICON_SIZE_BUTTON);
798       g_object_thaw_notify (G_OBJECT (image));
799       return;
800     }
801
802   /* We could just unconditionally set_from_animation,
803    * but it's nicer for memory if we toss the animation
804    * if it's just a single pixbuf
805    */
806
807   if (gdk_pixbuf_animation_is_static_image (anim))
808     gtk_image_set_from_pixbuf (image,
809                                gdk_pixbuf_animation_get_static_image (anim));
810   else
811     gtk_image_set_from_animation (image, anim);
812
813   g_object_unref (anim);
814
815   priv->filename = g_strdup (filename);
816   
817   g_object_thaw_notify (G_OBJECT (image));
818 }
819
820 /**
821  * gtk_image_set_from_pixbuf:
822  * @image: a #GtkImage
823  * @pixbuf: (allow-none): a #GdkPixbuf or %NULL
824  *
825  * See gtk_image_new_from_pixbuf() for details.
826  **/
827 void
828 gtk_image_set_from_pixbuf (GtkImage  *image,
829                            GdkPixbuf *pixbuf)
830 {
831   GtkImagePrivate *priv;
832
833   g_return_if_fail (GTK_IS_IMAGE (image));
834   g_return_if_fail (pixbuf == NULL ||
835                     GDK_IS_PIXBUF (pixbuf));
836
837   priv = image->priv;
838
839   g_object_freeze_notify (G_OBJECT (image));
840   
841   if (pixbuf)
842     g_object_ref (pixbuf);
843
844   gtk_image_clear (image);
845
846   if (pixbuf != NULL)
847     {
848       priv->storage_type = GTK_IMAGE_PIXBUF;
849
850       priv->data.pixbuf.pixbuf = pixbuf;
851
852       gtk_image_update_size (image,
853                              gdk_pixbuf_get_width (pixbuf),
854                              gdk_pixbuf_get_height (pixbuf));
855     }
856
857   g_object_notify (G_OBJECT (image), "pixbuf");
858   
859   g_object_thaw_notify (G_OBJECT (image));
860 }
861
862 /**
863  * gtk_image_set_from_stock:
864  * @image: a #GtkImage
865  * @stock_id: a stock icon name
866  * @size: (type int): a stock icon size
867  *
868  * See gtk_image_new_from_stock() for details.
869  **/
870 void
871 gtk_image_set_from_stock  (GtkImage       *image,
872                            const gchar    *stock_id,
873                            GtkIconSize     size)
874 {
875   GtkImagePrivate *priv;
876   gchar *new_id;
877
878   g_return_if_fail (GTK_IS_IMAGE (image));
879
880   priv = image->priv;
881
882   g_object_freeze_notify (G_OBJECT (image));
883
884   /* in case stock_id == priv->data.stock.stock_id */
885   new_id = g_strdup (stock_id);
886   
887   gtk_image_clear (image);
888
889   if (new_id)
890     {
891       priv->storage_type = GTK_IMAGE_STOCK;
892       
893       priv->data.stock.stock_id = new_id;
894       priv->icon_size = size;
895
896       /* Size is demand-computed in size request method
897        * if we're a stock image, since changing the
898        * style impacts the size request
899        */
900     }
901
902   g_object_notify (G_OBJECT (image), "stock");
903   g_object_notify (G_OBJECT (image), "icon-size");
904   
905   g_object_thaw_notify (G_OBJECT (image));
906 }
907
908 /**
909  * gtk_image_set_from_icon_set:
910  * @image: a #GtkImage
911  * @icon_set: a #GtkIconSet
912  * @size: (type int): a stock icon size
913  *
914  * See gtk_image_new_from_icon_set() for details.
915  **/
916 void
917 gtk_image_set_from_icon_set  (GtkImage       *image,
918                               GtkIconSet     *icon_set,
919                               GtkIconSize     size)
920 {
921   GtkImagePrivate *priv;
922
923   g_return_if_fail (GTK_IS_IMAGE (image));
924
925   priv = image->priv;
926
927   g_object_freeze_notify (G_OBJECT (image));
928   
929   if (icon_set)
930     gtk_icon_set_ref (icon_set);
931   
932   gtk_image_clear (image);
933
934   if (icon_set)
935     {      
936       priv->storage_type = GTK_IMAGE_ICON_SET;
937       
938       priv->data.icon_set.icon_set = icon_set;
939       priv->icon_size = size;
940
941       /* Size is demand-computed in size request method
942        * if we're an icon set
943        */
944     }
945   
946   g_object_notify (G_OBJECT (image), "icon-set");
947   g_object_notify (G_OBJECT (image), "icon-size");
948   
949   g_object_thaw_notify (G_OBJECT (image));
950 }
951
952 /**
953  * gtk_image_set_from_animation:
954  * @image: a #GtkImage
955  * @animation: the #GdkPixbufAnimation
956  * 
957  * Causes the #GtkImage to display the given animation (or display
958  * nothing, if you set the animation to %NULL).
959  **/
960 void
961 gtk_image_set_from_animation (GtkImage           *image,
962                               GdkPixbufAnimation *animation)
963 {
964   GtkImagePrivate *priv;
965
966   g_return_if_fail (GTK_IS_IMAGE (image));
967   g_return_if_fail (animation == NULL ||
968                     GDK_IS_PIXBUF_ANIMATION (animation));
969
970   priv = image->priv;
971
972   g_object_freeze_notify (G_OBJECT (image));
973   
974   if (animation)
975     g_object_ref (animation);
976
977   gtk_image_clear (image);
978
979   if (animation != NULL)
980     {
981       priv->storage_type = GTK_IMAGE_ANIMATION;
982
983       priv->data.anim.anim = animation;
984       priv->data.anim.frame_timeout = 0;
985       priv->data.anim.iter = NULL;
986       
987       gtk_image_update_size (image,
988                              gdk_pixbuf_animation_get_width (animation),
989                              gdk_pixbuf_animation_get_height (animation));
990     }
991
992   g_object_notify (G_OBJECT (image), "pixbuf-animation");
993   
994   g_object_thaw_notify (G_OBJECT (image));
995 }
996
997 /**
998  * gtk_image_set_from_icon_name:
999  * @image: a #GtkImage
1000  * @icon_name: an icon name
1001  * @size: (type int): an icon size
1002  *
1003  * See gtk_image_new_from_icon_name() for details.
1004  * 
1005  * Since: 2.6
1006  **/
1007 void
1008 gtk_image_set_from_icon_name  (GtkImage       *image,
1009                                const gchar    *icon_name,
1010                                GtkIconSize     size)
1011 {
1012   gchar *new_name;
1013   GtkImagePrivate *priv;
1014
1015   g_return_if_fail (GTK_IS_IMAGE (image));
1016
1017   priv = image->priv;
1018
1019   g_object_freeze_notify (G_OBJECT (image));
1020
1021   /* in case icon_name == priv->data.name.icon_name */
1022   new_name = g_strdup (icon_name);
1023   
1024   gtk_image_clear (image);
1025
1026   if (new_name)
1027     {
1028       priv->storage_type = GTK_IMAGE_ICON_NAME;
1029       
1030       priv->data.name.icon_name = new_name;
1031       priv->icon_size = size;
1032
1033       /* Size is demand-computed in size request method
1034        * if we're a icon theme image, since changing the
1035        * style impacts the size request
1036        */
1037     }
1038
1039   g_object_notify (G_OBJECT (image), "icon-name");
1040   g_object_notify (G_OBJECT (image), "icon-size");
1041   
1042   g_object_thaw_notify (G_OBJECT (image));
1043 }
1044
1045 /**
1046  * gtk_image_set_from_gicon:
1047  * @image: a #GtkImage
1048  * @icon: an icon
1049  * @size: (type int): an icon size
1050  *
1051  * See gtk_image_new_from_gicon() for details.
1052  * 
1053  * Since: 2.14
1054  **/
1055 void
1056 gtk_image_set_from_gicon  (GtkImage       *image,
1057                            GIcon          *icon,
1058                            GtkIconSize     size)
1059 {
1060   GtkImagePrivate *priv;
1061
1062   g_return_if_fail (GTK_IS_IMAGE (image));
1063
1064   priv = image->priv;
1065
1066   g_object_freeze_notify (G_OBJECT (image));
1067
1068   /* in case icon == priv->data.gicon.icon */
1069   if (icon)
1070     g_object_ref (icon);
1071   
1072   gtk_image_clear (image);
1073
1074   if (icon)
1075     {
1076       priv->storage_type = GTK_IMAGE_GICON;
1077
1078       priv->data.gicon.icon = icon;
1079       priv->icon_size = size;
1080
1081       /* Size is demand-computed in size request method
1082        * if we're a icon theme image, since changing the
1083        * style impacts the size request
1084        */
1085     }
1086
1087   g_object_notify (G_OBJECT (image), "gicon");
1088   g_object_notify (G_OBJECT (image), "icon-size");
1089   
1090   g_object_thaw_notify (G_OBJECT (image));
1091 }
1092
1093 /**
1094  * gtk_image_get_storage_type:
1095  * @image: a #GtkImage
1096  * 
1097  * Gets the type of representation being used by the #GtkImage
1098  * to store image data. If the #GtkImage has no image data,
1099  * the return value will be %GTK_IMAGE_EMPTY.
1100  * 
1101  * Return value: image representation being used
1102  **/
1103 GtkImageType
1104 gtk_image_get_storage_type (GtkImage *image)
1105 {
1106   g_return_val_if_fail (GTK_IS_IMAGE (image), GTK_IMAGE_EMPTY);
1107
1108   return image->priv->storage_type;
1109 }
1110
1111 /**
1112  * gtk_image_get_pixbuf:
1113  * @image: a #GtkImage
1114  *
1115  * Gets the #GdkPixbuf being displayed by the #GtkImage.
1116  * The storage type of the image must be %GTK_IMAGE_EMPTY or
1117  * %GTK_IMAGE_PIXBUF (see gtk_image_get_storage_type()).
1118  * The caller of this function does not own a reference to the
1119  * returned pixbuf.
1120  * 
1121  * Return value: (transfer none): the displayed pixbuf, or %NULL if
1122  * the image is empty
1123  **/
1124 GdkPixbuf*
1125 gtk_image_get_pixbuf (GtkImage *image)
1126 {
1127   GtkImagePrivate *priv;
1128
1129   g_return_val_if_fail (GTK_IS_IMAGE (image), NULL);
1130
1131   priv = image->priv;
1132
1133   g_return_val_if_fail (priv->storage_type == GTK_IMAGE_PIXBUF ||
1134                         priv->storage_type == GTK_IMAGE_EMPTY, NULL);
1135
1136   if (priv->storage_type == GTK_IMAGE_EMPTY)
1137     priv->data.pixbuf.pixbuf = NULL;
1138
1139   return priv->data.pixbuf.pixbuf;
1140 }
1141
1142 /**
1143  * gtk_image_get_stock:
1144  * @image: a #GtkImage
1145  * @stock_id: (out) (transfer none) (allow-none): place to store a
1146  *     stock icon name, or %NULL
1147  * @size: (out) (allow-none) (type int): place to store a stock icon
1148  *     size, or %NULL
1149  *
1150  * Gets the stock icon name and size being displayed by the #GtkImage.
1151  * The storage type of the image must be %GTK_IMAGE_EMPTY or
1152  * %GTK_IMAGE_STOCK (see gtk_image_get_storage_type()).
1153  * The returned string is owned by the #GtkImage and should not
1154  * be freed.
1155  **/
1156 void
1157 gtk_image_get_stock  (GtkImage        *image,
1158                       gchar          **stock_id,
1159                       GtkIconSize     *size)
1160 {
1161   GtkImagePrivate *priv;
1162
1163   g_return_if_fail (GTK_IS_IMAGE (image));
1164
1165   priv = image->priv;
1166
1167   g_return_if_fail (priv->storage_type == GTK_IMAGE_STOCK ||
1168                     priv->storage_type == GTK_IMAGE_EMPTY);
1169
1170   if (priv->storage_type == GTK_IMAGE_EMPTY)
1171     priv->data.stock.stock_id = NULL;
1172
1173   if (stock_id)
1174     *stock_id = priv->data.stock.stock_id;
1175
1176   if (size)
1177     *size = priv->icon_size;
1178 }
1179
1180 /**
1181  * gtk_image_get_icon_set:
1182  * @image: a #GtkImage
1183  * @icon_set: (out) (transfer none) (allow-none): location to store a
1184  *     #GtkIconSet, or %NULL
1185  * @size: (out) (allow-none) (type int): location to store a stock
1186  *     icon size, or %NULL
1187  *
1188  * Gets the icon set and size being displayed by the #GtkImage.
1189  * The storage type of the image must be %GTK_IMAGE_EMPTY or
1190  * %GTK_IMAGE_ICON_SET (see gtk_image_get_storage_type()).
1191  **/
1192 void
1193 gtk_image_get_icon_set  (GtkImage        *image,
1194                          GtkIconSet     **icon_set,
1195                          GtkIconSize     *size)
1196 {
1197   GtkImagePrivate *priv;
1198
1199   g_return_if_fail (GTK_IS_IMAGE (image));
1200
1201   priv = image->priv;
1202
1203   g_return_if_fail (priv->storage_type == GTK_IMAGE_ICON_SET ||
1204                     priv->storage_type == GTK_IMAGE_EMPTY);
1205
1206   if (icon_set)
1207     *icon_set = priv->data.icon_set.icon_set;
1208
1209   if (size)
1210     *size = priv->icon_size;
1211 }
1212
1213 /**
1214  * gtk_image_get_animation:
1215  * @image: a #GtkImage
1216  *
1217  * Gets the #GdkPixbufAnimation being displayed by the #GtkImage.
1218  * The storage type of the image must be %GTK_IMAGE_EMPTY or
1219  * %GTK_IMAGE_ANIMATION (see gtk_image_get_storage_type()).
1220  * The caller of this function does not own a reference to the
1221  * returned animation.
1222  * 
1223  * Return value: (transfer none): the displayed animation, or %NULL if
1224  * the image is empty
1225  **/
1226 GdkPixbufAnimation*
1227 gtk_image_get_animation (GtkImage *image)
1228 {
1229   GtkImagePrivate *priv;
1230
1231   g_return_val_if_fail (GTK_IS_IMAGE (image), NULL);
1232
1233   priv = image->priv;
1234
1235   g_return_val_if_fail (priv->storage_type == GTK_IMAGE_ANIMATION ||
1236                         priv->storage_type == GTK_IMAGE_EMPTY,
1237                         NULL);
1238
1239   if (priv->storage_type == GTK_IMAGE_EMPTY)
1240     priv->data.anim.anim = NULL;
1241
1242   return priv->data.anim.anim;
1243 }
1244
1245 /**
1246  * gtk_image_get_icon_name:
1247  * @image: a #GtkImage
1248  * @icon_name: (out) (transfer none) (allow-none): place to store an
1249  *     icon name, or %NULL
1250  * @size: (out) (allow-none) (type int): place to store an icon size,
1251  *     or %NULL
1252  *
1253  * Gets the icon name and size being displayed by the #GtkImage.
1254  * The storage type of the image must be %GTK_IMAGE_EMPTY or
1255  * %GTK_IMAGE_ICON_NAME (see gtk_image_get_storage_type()).
1256  * The returned string is owned by the #GtkImage and should not
1257  * be freed.
1258  * 
1259  * Since: 2.6
1260  **/
1261 void
1262 gtk_image_get_icon_name  (GtkImage              *image,
1263                           G_CONST_RETURN gchar **icon_name,
1264                           GtkIconSize           *size)
1265 {
1266   GtkImagePrivate *priv;
1267
1268   g_return_if_fail (GTK_IS_IMAGE (image));
1269
1270   priv = image->priv;
1271
1272   g_return_if_fail (priv->storage_type == GTK_IMAGE_ICON_NAME ||
1273                     priv->storage_type == GTK_IMAGE_EMPTY);
1274
1275   if (priv->storage_type == GTK_IMAGE_EMPTY)
1276     priv->data.name.icon_name = NULL;
1277
1278   if (icon_name)
1279     *icon_name = priv->data.name.icon_name;
1280
1281   if (size)
1282     *size = priv->icon_size;
1283 }
1284
1285 /**
1286  * gtk_image_get_gicon:
1287  * @image: a #GtkImage
1288  * @gicon: (out) (transfer none) (allow-none): place to store a
1289  *     #GIcon, or %NULL
1290  * @size: (out) (allow-none) (type int): place to store an icon size,
1291  *     or %NULL
1292  *
1293  * Gets the #GIcon and size being displayed by the #GtkImage.
1294  * The storage type of the image must be %GTK_IMAGE_EMPTY or
1295  * %GTK_IMAGE_GICON (see gtk_image_get_storage_type()).
1296  * The caller of this function does not own a reference to the
1297  * returned #GIcon.
1298  * 
1299  * Since: 2.14
1300  **/
1301 void
1302 gtk_image_get_gicon (GtkImage     *image,
1303                      GIcon       **gicon,
1304                      GtkIconSize  *size)
1305 {
1306   GtkImagePrivate *priv;
1307
1308   g_return_if_fail (GTK_IS_IMAGE (image));
1309
1310   priv = image->priv;
1311
1312   g_return_if_fail (priv->storage_type == GTK_IMAGE_GICON ||
1313                     priv->storage_type == GTK_IMAGE_EMPTY);
1314
1315   if (priv->storage_type == GTK_IMAGE_EMPTY)
1316     priv->data.gicon.icon = NULL;
1317
1318   if (gicon)
1319     *gicon = priv->data.gicon.icon;
1320
1321   if (size)
1322     *size = priv->icon_size;
1323 }
1324
1325 /**
1326  * gtk_image_new:
1327  * 
1328  * Creates a new empty #GtkImage widget.
1329  * 
1330  * Return value: a newly created #GtkImage widget. 
1331  **/
1332 GtkWidget*
1333 gtk_image_new (void)
1334 {
1335   return g_object_new (GTK_TYPE_IMAGE, NULL);
1336 }
1337
1338 static void
1339 gtk_image_reset_anim_iter (GtkImage *image)
1340 {
1341   GtkImagePrivate *priv = image->priv;
1342
1343   if (priv->storage_type == GTK_IMAGE_ANIMATION)
1344     {
1345       /* Reset the animation */
1346       
1347       if (priv->data.anim.frame_timeout)
1348         {
1349           g_source_remove (priv->data.anim.frame_timeout);
1350           priv->data.anim.frame_timeout = 0;
1351         }
1352
1353       if (priv->data.anim.iter)
1354         {
1355           g_object_unref (priv->data.anim.iter);
1356           priv->data.anim.iter = NULL;
1357         }
1358     }
1359 }
1360
1361 static void
1362 gtk_image_unmap (GtkWidget *widget)
1363 {
1364   gtk_image_reset_anim_iter (GTK_IMAGE (widget));
1365
1366   GTK_WIDGET_CLASS (gtk_image_parent_class)->unmap (widget);
1367 }
1368
1369 static void
1370 gtk_image_unrealize (GtkWidget *widget)
1371 {
1372   gtk_image_reset_anim_iter (GTK_IMAGE (widget));
1373
1374   GTK_WIDGET_CLASS (gtk_image_parent_class)->unrealize (widget);
1375 }
1376
1377 static gint
1378 animation_timeout (gpointer data)
1379 {
1380   GtkImage *image = GTK_IMAGE (data);
1381   GtkImagePrivate *priv = image->priv;
1382   int delay;
1383
1384   priv->data.anim.frame_timeout = 0;
1385
1386   gdk_pixbuf_animation_iter_advance (priv->data.anim.iter, NULL);
1387
1388   delay = gdk_pixbuf_animation_iter_get_delay_time (priv->data.anim.iter);
1389   if (delay >= 0)
1390     {
1391       GtkWidget *widget = GTK_WIDGET (image);
1392
1393       priv->data.anim.frame_timeout =
1394         gdk_threads_add_timeout (delay, animation_timeout, image);
1395
1396       gtk_widget_queue_draw (widget);
1397
1398       if (gtk_widget_is_drawable (widget))
1399         gdk_window_process_updates (gtk_widget_get_window (widget), TRUE);
1400     }
1401
1402   return FALSE;
1403 }
1404
1405 static void
1406 icon_theme_changed (GtkImage *image)
1407 {
1408   GtkImagePrivate *priv = image->priv;
1409
1410   if (priv->storage_type == GTK_IMAGE_ICON_NAME)
1411     {
1412       if (priv->data.name.pixbuf)
1413         g_object_unref (priv->data.name.pixbuf);
1414       priv->data.name.pixbuf = NULL;
1415
1416       gtk_widget_queue_draw (GTK_WIDGET (image));
1417     }
1418   if (priv->storage_type == GTK_IMAGE_GICON)
1419     {
1420       if (priv->data.gicon.pixbuf)
1421         g_object_unref (priv->data.gicon.pixbuf);
1422       priv->data.gicon.pixbuf = NULL;
1423
1424       gtk_widget_queue_draw (GTK_WIDGET (image));
1425     }
1426 }
1427
1428 static void
1429 ensure_pixbuf_for_icon_name (GtkImage      *image,
1430                              GtkStateFlags  state)
1431 {
1432   GtkImagePrivate *priv = image->priv;
1433   GdkScreen *screen;
1434   GtkIconTheme *icon_theme;
1435   GtkSettings *settings;
1436   gint width, height;
1437   gint *sizes, *s, dist;
1438   GtkIconInfo *info;
1439   GtkIconLookupFlags flags;
1440
1441   g_return_if_fail (priv->storage_type == GTK_IMAGE_ICON_NAME);
1442
1443   screen = gtk_widget_get_screen (GTK_WIDGET (image));
1444   icon_theme = gtk_icon_theme_get_for_screen (screen);
1445   settings = gtk_settings_get_for_screen (screen);
1446   flags = GTK_ICON_LOOKUP_USE_BUILTIN;
1447   if (priv->use_fallback)
1448     flags |= GTK_ICON_LOOKUP_GENERIC_FALLBACK;
1449   if (priv->data.name.pixbuf == NULL ||
1450       (priv->was_symbolic && priv->last_rendered_state != state))
1451     {
1452       priv->last_rendered_state = state;
1453       if (priv->data.name.pixbuf)
1454         {
1455           g_object_unref (priv->data.name.pixbuf);
1456           priv->data.name.pixbuf = NULL;
1457         }
1458       if (priv->pixel_size != -1)
1459         {
1460           width = height = priv->pixel_size;
1461           flags |= GTK_ICON_LOOKUP_FORCE_SIZE;
1462         }
1463       else if (!gtk_icon_size_lookup_for_settings (settings,
1464                                                    priv->icon_size,
1465                                                    &width, &height))
1466         {
1467           if (priv->icon_size == -1)
1468             {
1469               /* Find an available size close to 48 */
1470               sizes = gtk_icon_theme_get_icon_sizes (icon_theme, priv->data.name.icon_name);
1471               dist = 100;
1472               width = height = 48;
1473               for (s = sizes; *s; s++)
1474                 {
1475                   if (*s == -1)
1476                     {
1477                       width = height = 48;
1478                       break;
1479                     }
1480                   if (*s < 48)
1481                     {
1482                       if (48 - *s < dist)
1483                         {
1484                           width = height = *s;
1485                           dist = 48 - *s;
1486                         }
1487                     }
1488                   else
1489                     {
1490                       if (*s - 48 < dist)
1491                         {
1492                           width = height = *s;
1493                           dist = *s - 48;
1494                         }
1495                     }
1496                 }
1497               g_free (sizes);
1498             }
1499           else
1500             {
1501               g_warning ("Invalid icon size %d\n", priv->icon_size);
1502               width = height = 24;
1503             }
1504         }
1505
1506       info = gtk_icon_theme_lookup_icon (icon_theme,
1507                                          priv->data.name.icon_name,
1508                                          MIN (width, height), flags);
1509       if (info)
1510         {
1511           GtkStyleContext *context;
1512           gboolean was_symbolic;
1513
1514           context = gtk_widget_get_style_context (GTK_WIDGET (image));
1515           priv->data.name.pixbuf =
1516             gtk_icon_info_load_symbolic_for_context (info,
1517                                                      context,
1518                                                      &was_symbolic,
1519                                                      NULL);
1520           priv->was_symbolic = was_symbolic;
1521           gtk_icon_info_free (info);
1522         }
1523
1524       if (priv->data.name.pixbuf == NULL)
1525         {
1526           priv->data.name.pixbuf =
1527             gtk_widget_render_icon_pixbuf (GTK_WIDGET (image),
1528                                            GTK_STOCK_MISSING_IMAGE,
1529                                            priv->icon_size);
1530           priv->was_symbolic = FALSE;
1531         }
1532     }
1533 }
1534
1535 static void
1536 ensure_pixbuf_for_gicon (GtkImage      *image,
1537                          GtkStateFlags  state)
1538 {
1539   GtkImagePrivate *priv = image->priv;
1540   GdkScreen *screen;
1541   GtkIconTheme *icon_theme;
1542   GtkSettings *settings;
1543   gint width, height;
1544   GtkIconInfo *info;
1545   GtkIconLookupFlags flags;
1546
1547   g_return_if_fail (priv->storage_type == GTK_IMAGE_GICON);
1548
1549   screen = gtk_widget_get_screen (GTK_WIDGET (image));
1550   icon_theme = gtk_icon_theme_get_for_screen (screen);
1551   settings = gtk_settings_get_for_screen (screen);
1552   flags = GTK_ICON_LOOKUP_USE_BUILTIN;
1553   if (priv->use_fallback)
1554     flags |= GTK_ICON_LOOKUP_GENERIC_FALLBACK;
1555   if (priv->data.gicon.pixbuf == NULL ||
1556       (priv->was_symbolic && priv->last_rendered_state != state))
1557     {
1558       priv->last_rendered_state = state;
1559       if (priv->data.gicon.pixbuf)
1560         {
1561           g_object_unref (priv->data.gicon.pixbuf);
1562           priv->data.gicon.pixbuf = NULL;
1563         }
1564       if (priv->pixel_size != -1)
1565         {
1566           width = height = priv->pixel_size;
1567           flags |= GTK_ICON_LOOKUP_FORCE_SIZE;
1568         }
1569       else if (!gtk_icon_size_lookup_for_settings (settings,
1570                                                    priv->icon_size,
1571                                                    &width, &height))
1572         {
1573           if (priv->icon_size == -1)
1574             width = height = 48;
1575           else
1576             {
1577               g_warning ("Invalid icon size %d\n", priv->icon_size);
1578               width = height = 24;
1579             }
1580         }
1581
1582       info = gtk_icon_theme_lookup_by_gicon (icon_theme,
1583                                              priv->data.gicon.icon,
1584                                              MIN (width, height), flags);
1585       if (info)
1586         {
1587           GtkStyleContext *context;
1588           gboolean was_symbolic;
1589
1590           context = gtk_widget_get_style_context (GTK_WIDGET (image));
1591           priv->data.gicon.pixbuf =
1592             gtk_icon_info_load_symbolic_for_context (info,
1593                                                      context,
1594                                                      &was_symbolic,
1595                                                      NULL);
1596           priv->was_symbolic = was_symbolic;
1597           gtk_icon_info_free (info);
1598         }
1599
1600       if (priv->data.gicon.pixbuf == NULL)
1601         {
1602           priv->data.gicon.pixbuf =
1603             gtk_widget_render_icon_pixbuf (GTK_WIDGET (image),
1604                                            GTK_STOCK_MISSING_IMAGE,
1605                                            priv->icon_size);
1606           priv->was_symbolic = FALSE;
1607         }
1608     }
1609 }
1610
1611 static gint
1612 gtk_image_draw (GtkWidget *widget,
1613                 cairo_t   *cr)
1614 {
1615   GtkImage *image;
1616   GtkImagePrivate *priv;
1617
1618   g_return_val_if_fail (GTK_IS_IMAGE (widget), FALSE);
1619
1620   image = GTK_IMAGE (widget);
1621   priv = image->priv;
1622   
1623   if (priv->storage_type != GTK_IMAGE_EMPTY)
1624     {
1625       GtkMisc *misc;
1626       gint x, y;
1627       gint xpad, ypad;
1628       gfloat xalign, yalign;
1629       GdkPixbuf *pixbuf;
1630       GtkStateFlags state;
1631       gboolean needs_state_transform;
1632       GtkStyleContext *context;
1633
1634       misc = GTK_MISC (widget);
1635       context = gtk_widget_get_style_context (widget);
1636       state = gtk_widget_get_state_flags (widget);
1637
1638       gtk_style_context_save (context);
1639       gtk_style_context_set_state (context, state);
1640
1641       /* For stock items and icon sets, we lazily calculate
1642        * the size; we might get here between a queue_resize()
1643        * and size_request() if something explicitely forces
1644        * a redraw.
1645        */
1646       if (priv->need_calc_size)
1647         gtk_image_calc_size (image);
1648
1649       gtk_misc_get_alignment (misc, &xalign, &yalign);
1650       gtk_misc_get_padding (misc, &xpad, &ypad);
1651
1652       if (gtk_widget_get_direction (widget) != GTK_TEXT_DIR_LTR)
1653         xalign = 1.0 - xalign;
1654
1655       x = floor (xpad + ((gtk_widget_get_allocated_width (widget) - priv->required_width) * xalign));
1656       y = floor (ypad + ((gtk_widget_get_allocated_height (widget) - priv->required_height) * yalign));
1657
1658       needs_state_transform = state != 0;
1659
1660       switch (priv->storage_type)
1661         {
1662
1663         case GTK_IMAGE_PIXBUF:
1664           pixbuf = priv->data.pixbuf.pixbuf;
1665           g_object_ref (pixbuf);
1666           break;
1667
1668         case GTK_IMAGE_STOCK:
1669           pixbuf = gtk_widget_render_icon_pixbuf (widget,
1670                                                   priv->data.stock.stock_id,
1671                                                   priv->icon_size);
1672
1673           /* already done */
1674           needs_state_transform = FALSE;
1675           break;
1676
1677         case GTK_IMAGE_ICON_SET:
1678           pixbuf =
1679             gtk_icon_set_render_icon_pixbuf (priv->data.icon_set.icon_set,
1680                                              context, priv->icon_size);
1681
1682           /* already done */
1683           needs_state_transform = FALSE;
1684           break;
1685
1686         case GTK_IMAGE_ANIMATION:
1687           {
1688             if (priv->data.anim.iter == NULL)
1689               {
1690                 priv->data.anim.iter = gdk_pixbuf_animation_get_iter (priv->data.anim.anim, NULL);
1691                 
1692                 if (gdk_pixbuf_animation_iter_get_delay_time (priv->data.anim.iter) >= 0)
1693                   priv->data.anim.frame_timeout =
1694                     gdk_threads_add_timeout (gdk_pixbuf_animation_iter_get_delay_time (priv->data.anim.iter),
1695                                    animation_timeout,
1696                                    image);
1697               }
1698
1699             /* don't advance the anim iter here, or we could get frame changes between two
1700              * exposes of different areas.
1701              */
1702             
1703             pixbuf = gdk_pixbuf_animation_iter_get_pixbuf (priv->data.anim.iter);
1704             g_object_ref (pixbuf);
1705           }
1706           break;
1707
1708         case GTK_IMAGE_ICON_NAME:
1709           if (state & GTK_STATE_FLAG_INSENSITIVE)
1710             {
1711               ensure_pixbuf_for_icon_name (image, 0);
1712             }
1713           else
1714             {
1715               ensure_pixbuf_for_icon_name (image, state);
1716               /* Already done by the loading function? */
1717               if (priv->was_symbolic)
1718                 needs_state_transform = FALSE;
1719             }
1720           pixbuf = priv->data.name.pixbuf;
1721           if (pixbuf)
1722             {
1723               g_object_ref (pixbuf);
1724             }
1725           break;
1726
1727         case GTK_IMAGE_GICON:
1728           if (state & GTK_STATE_FLAG_INSENSITIVE)
1729             {
1730               ensure_pixbuf_for_gicon (image, 0);
1731             }
1732           else
1733             {
1734               ensure_pixbuf_for_gicon (image, state);
1735               /* Already done by the loading function? */
1736               if (priv->was_symbolic)
1737                 needs_state_transform = FALSE;
1738             }
1739           pixbuf = priv->data.gicon.pixbuf;
1740           if (pixbuf)
1741             {
1742               g_object_ref (pixbuf);
1743             }
1744           break;
1745           
1746         case GTK_IMAGE_EMPTY:
1747         default:
1748           g_assert_not_reached ();
1749           pixbuf = NULL;
1750           break;
1751         }
1752
1753       if (pixbuf)
1754         {
1755           if (needs_state_transform)
1756             {
1757               GtkIconSource *source;
1758               GdkPixbuf *rendered;
1759
1760               source = gtk_icon_source_new ();
1761               gtk_icon_source_set_pixbuf (source, pixbuf);
1762               /* The size here is arbitrary; since size isn't
1763                * wildcarded in the souce, it isn't supposed to be
1764                * scaled by the engine function
1765                */
1766               gtk_icon_source_set_size (source,
1767                                         GTK_ICON_SIZE_SMALL_TOOLBAR);
1768               gtk_icon_source_set_size_wildcarded (source, FALSE);
1769
1770               rendered = gtk_render_icon_pixbuf (context, source, (GtkIconSize) -1);
1771               gtk_icon_source_free (source);
1772
1773               g_object_unref (pixbuf);
1774               pixbuf = rendered;
1775             }
1776
1777           gdk_cairo_set_source_pixbuf (cr, pixbuf, x, y);
1778           cairo_paint (cr);
1779
1780           g_object_unref (pixbuf);
1781         }
1782
1783       gtk_style_context_restore (context);
1784     }
1785
1786   return FALSE;
1787 }
1788
1789 static void
1790 gtk_image_reset (GtkImage *image)
1791 {
1792   GtkImagePrivate *priv = image->priv;
1793
1794   g_object_freeze_notify (G_OBJECT (image));
1795   
1796   if (priv->storage_type != GTK_IMAGE_EMPTY)
1797     g_object_notify (G_OBJECT (image), "storage-type");
1798
1799   if (priv->icon_size != DEFAULT_ICON_SIZE)
1800     {
1801       priv->icon_size = DEFAULT_ICON_SIZE;
1802       g_object_notify (G_OBJECT (image), "icon-size");
1803     }
1804   
1805   switch (priv->storage_type)
1806     {
1807
1808     case GTK_IMAGE_PIXBUF:
1809
1810       if (priv->data.pixbuf.pixbuf)
1811         g_object_unref (priv->data.pixbuf.pixbuf);
1812
1813       g_object_notify (G_OBJECT (image), "pixbuf");
1814       
1815       break;
1816
1817     case GTK_IMAGE_STOCK:
1818
1819       g_free (priv->data.stock.stock_id);
1820
1821       priv->data.stock.stock_id = NULL;
1822       
1823       g_object_notify (G_OBJECT (image), "stock");      
1824       break;
1825
1826     case GTK_IMAGE_ICON_SET:
1827       if (priv->data.icon_set.icon_set)
1828         gtk_icon_set_unref (priv->data.icon_set.icon_set);
1829       priv->data.icon_set.icon_set = NULL;
1830       
1831       g_object_notify (G_OBJECT (image), "icon-set");      
1832       break;
1833
1834     case GTK_IMAGE_ANIMATION:
1835       gtk_image_reset_anim_iter (image);
1836       
1837       if (priv->data.anim.anim)
1838         g_object_unref (priv->data.anim.anim);
1839       priv->data.anim.anim = NULL;
1840       
1841       g_object_notify (G_OBJECT (image), "pixbuf-animation");
1842       
1843       break;
1844
1845     case GTK_IMAGE_ICON_NAME:
1846       g_free (priv->data.name.icon_name);
1847       priv->data.name.icon_name = NULL;
1848       if (priv->data.name.pixbuf)
1849         g_object_unref (priv->data.name.pixbuf);
1850       priv->data.name.pixbuf = NULL;
1851
1852       g_object_notify (G_OBJECT (image), "icon-name");
1853
1854       break;
1855       
1856     case GTK_IMAGE_GICON:
1857       if (priv->data.gicon.icon)
1858         g_object_unref (priv->data.gicon.icon);
1859       priv->data.gicon.icon = NULL;
1860       if (priv->data.gicon.pixbuf)
1861         g_object_unref (priv->data.gicon.pixbuf);
1862       priv->data.gicon.pixbuf = NULL;
1863
1864       g_object_notify (G_OBJECT (image), "gicon");
1865
1866       break;
1867       
1868     case GTK_IMAGE_EMPTY:
1869     default:
1870       break;
1871       
1872     }
1873
1874   if (priv->filename)
1875     {
1876       g_free (priv->filename);
1877       priv->filename = NULL;
1878       g_object_notify (G_OBJECT (image), "file");
1879     }
1880
1881   priv->storage_type = GTK_IMAGE_EMPTY;
1882
1883   memset (&priv->data, '\0', sizeof (priv->data));
1884
1885   g_object_thaw_notify (G_OBJECT (image));
1886 }
1887
1888 /**
1889  * gtk_image_clear:
1890  * @image: a #GtkImage
1891  *
1892  * Resets the image to be empty.
1893  *
1894  * Since: 2.8
1895  */
1896 void
1897 gtk_image_clear (GtkImage *image)
1898 {
1899   GtkImagePrivate *priv = image->priv;
1900
1901   priv->need_calc_size = 1;
1902
1903   gtk_image_reset (image);
1904   gtk_image_update_size (image, 0, 0);
1905 }
1906
1907 static void
1908 gtk_image_calc_size (GtkImage *image)
1909 {
1910   GtkWidget *widget = GTK_WIDGET (image);
1911   GtkImagePrivate *priv = image->priv;
1912   GdkPixbuf *pixbuf = NULL;
1913   GtkStyleContext *context;
1914   GtkStateFlags state;
1915
1916   priv->need_calc_size = 0;
1917   context = gtk_widget_get_style_context (widget);
1918   state = gtk_widget_get_state_flags (widget);
1919
1920   gtk_style_context_save (context);
1921   gtk_style_context_set_state (context, state);
1922
1923   /* We update stock/icon set on every size request, because
1924    * the theme could have affected the size; for other kinds of
1925    * image, we just update the required width/height when the image data
1926    * is set.
1927    */
1928   switch (priv->storage_type)
1929     {
1930     case GTK_IMAGE_STOCK:
1931       pixbuf = gtk_widget_render_icon_pixbuf (widget,
1932                                               priv->data.stock.stock_id,
1933                                               priv->icon_size);
1934       break;
1935       
1936     case GTK_IMAGE_ICON_SET:
1937       pixbuf = gtk_icon_set_render_icon_pixbuf (priv->data.icon_set.icon_set,
1938                                                 context, priv->icon_size);
1939       break;
1940     case GTK_IMAGE_ICON_NAME:
1941       ensure_pixbuf_for_icon_name (image, 0);
1942       pixbuf = priv->data.name.pixbuf;
1943       if (pixbuf) g_object_ref (pixbuf);
1944       break;
1945     case GTK_IMAGE_GICON:
1946       ensure_pixbuf_for_gicon (image, 0);
1947       pixbuf = priv->data.gicon.pixbuf;
1948       if (pixbuf)
1949         g_object_ref (pixbuf);
1950       break;
1951     default:
1952       break;
1953     }
1954
1955   if (pixbuf)
1956     {
1957       gint xpad, ypad;
1958
1959       gtk_misc_get_padding (GTK_MISC (image), &xpad, &ypad);
1960
1961       priv->required_width = gdk_pixbuf_get_width (pixbuf) + xpad * 2;
1962       priv->required_height = gdk_pixbuf_get_height (pixbuf) + ypad * 2;
1963
1964       g_object_unref (pixbuf);
1965     }
1966
1967   gtk_style_context_restore (context);
1968 }
1969
1970 static void
1971 gtk_image_get_preferred_width (GtkWidget *widget,
1972                                gint      *minimum,
1973                                gint      *natural)
1974 {
1975   GtkImage *image;
1976   GtkImagePrivate *priv;
1977
1978   image = GTK_IMAGE (widget);
1979   priv  = image->priv;
1980
1981   gtk_image_calc_size (image);
1982
1983   *minimum = *natural = priv->required_width;
1984 }
1985
1986 static void
1987 gtk_image_get_preferred_height (GtkWidget *widget,
1988                                 gint      *minimum,
1989                                 gint      *natural)
1990 {
1991   GtkImage *image;
1992   GtkImagePrivate *priv;
1993
1994   image = GTK_IMAGE (widget);
1995   priv  = image->priv;
1996
1997   gtk_image_calc_size (image);
1998
1999   *minimum = *natural = priv->required_height;
2000 }
2001
2002 static void
2003 gtk_image_style_updated (GtkWidget *widget)
2004 {
2005   GTK_WIDGET_CLASS (gtk_image_parent_class)->style_updated (widget);
2006
2007   icon_theme_changed (GTK_IMAGE (widget));
2008 }
2009
2010 static void
2011 gtk_image_screen_changed (GtkWidget *widget,
2012                           GdkScreen *prev_screen)
2013 {
2014   GtkImage *image;
2015
2016   image = GTK_IMAGE (widget);
2017
2018   if (GTK_WIDGET_CLASS (gtk_image_parent_class)->screen_changed)
2019     GTK_WIDGET_CLASS (gtk_image_parent_class)->screen_changed (widget, prev_screen);
2020
2021   icon_theme_changed (image);
2022 }
2023
2024
2025 static void
2026 gtk_image_update_size (GtkImage *image,
2027                        gint      image_width,
2028                        gint      image_height)
2029 {
2030   GtkWidget       *widget = GTK_WIDGET (image);
2031   GtkImagePrivate *priv = image->priv;
2032   gint             xpad, ypad;
2033
2034   gtk_misc_get_padding (GTK_MISC (image), &xpad, &ypad);
2035
2036   priv->required_width  = image_width + xpad * 2;
2037   priv->required_height = image_height + ypad * 2;
2038
2039   if (gtk_widget_get_visible (widget))
2040     gtk_widget_queue_resize (widget);
2041 }
2042
2043
2044 /**
2045  * gtk_image_set_pixel_size:
2046  * @image: a #GtkImage
2047  * @pixel_size: the new pixel size
2048  * 
2049  * Sets the pixel size to use for named icons. If the pixel size is set
2050  * to a value != -1, it is used instead of the icon size set by
2051  * gtk_image_set_from_icon_name().
2052  *
2053  * Since: 2.6
2054  */
2055 void 
2056 gtk_image_set_pixel_size (GtkImage *image,
2057                           gint      pixel_size)
2058 {
2059   GtkImagePrivate *priv;
2060
2061   g_return_if_fail (GTK_IS_IMAGE (image));
2062
2063   priv = image->priv;
2064
2065   if (priv->pixel_size != pixel_size)
2066     {
2067       priv->pixel_size = pixel_size;
2068       
2069       if (priv->storage_type == GTK_IMAGE_ICON_NAME)
2070         {
2071           if (priv->data.name.pixbuf)
2072             {
2073               g_object_unref (priv->data.name.pixbuf);
2074               priv->data.name.pixbuf = NULL;
2075             }
2076           
2077           gtk_image_update_size (image, pixel_size, pixel_size);
2078         }
2079       
2080       if (priv->storage_type == GTK_IMAGE_GICON)
2081         {
2082           if (priv->data.gicon.pixbuf)
2083             {
2084               g_object_unref (priv->data.gicon.pixbuf);
2085               priv->data.gicon.pixbuf = NULL;
2086             }
2087           
2088           gtk_image_update_size (image, pixel_size, pixel_size);
2089         }
2090       
2091       g_object_notify (G_OBJECT (image), "pixel-size");
2092     }
2093 }
2094
2095 /**
2096  * gtk_image_get_pixel_size:
2097  * @image: a #GtkImage
2098  * 
2099  * Gets the pixel size used for named icons.
2100  *
2101  * Returns: the pixel size used for named icons.
2102  *
2103  * Since: 2.6
2104  */
2105 gint
2106 gtk_image_get_pixel_size (GtkImage *image)
2107 {
2108   g_return_val_if_fail (GTK_IS_IMAGE (image), -1);
2109
2110   return image->priv->pixel_size;
2111 }