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