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