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