]> Pileus Git - ~andy/gtk/blob - gtk/gtkimage.c
image: Fix up draw function
[~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       GtkMisc *misc;
1586       gint x, y;
1587       gint xpad, ypad;
1588       gfloat xalign, yalign;
1589       GdkPixbuf *pixbuf;
1590       GtkStateType state;
1591       gboolean needs_state_transform;
1592
1593       misc = GTK_MISC (widget);
1594
1595       /* For stock items and icon sets, we lazily calculate
1596        * the size; we might get here between a queue_resize()
1597        * and size_request() if something explicitely forces
1598        * a redraw.
1599        */
1600       if (priv->need_calc_size)
1601         gtk_image_calc_size (image);
1602
1603       gtk_misc_get_alignment (misc, &xalign, &yalign);
1604       gtk_misc_get_padding (misc, &xpad, &ypad);
1605
1606       if (gtk_widget_get_direction (widget) != GTK_TEXT_DIR_LTR)
1607         xalign = 1.0 - xalign;
1608
1609       x = floor (xpad + ((gtk_widget_get_allocated_width (widget) - priv->required_width) * xalign));
1610       y = floor (ypad + ((gtk_widget_get_allocated_height (widget) - priv->required_height) * yalign));
1611       
1612       needs_state_transform = gtk_widget_get_state (widget) != GTK_STATE_NORMAL;
1613       
1614       switch (priv->storage_type)
1615         {
1616
1617         case GTK_IMAGE_PIXBUF:
1618           pixbuf = priv->data.pixbuf.pixbuf;
1619           g_object_ref (pixbuf);
1620           break;
1621
1622         case GTK_IMAGE_STOCK:
1623           pixbuf = gtk_widget_render_icon (widget,
1624                                            priv->data.stock.stock_id,
1625                                            priv->icon_size,
1626                                            NULL);
1627
1628           /* already done */
1629           needs_state_transform = FALSE;
1630           break;
1631
1632         case GTK_IMAGE_ICON_SET:
1633           pixbuf =
1634             gtk_icon_set_render_icon (priv->data.icon_set.icon_set,
1635                                       gtk_widget_get_style (widget),
1636                                       gtk_widget_get_direction (widget),
1637                                       gtk_widget_get_state (widget),
1638                                       priv->icon_size,
1639                                       widget,
1640                                       NULL);
1641
1642           /* already done */
1643           needs_state_transform = FALSE;
1644           break;
1645
1646         case GTK_IMAGE_ANIMATION:
1647           {
1648             if (priv->data.anim.iter == NULL)
1649               {
1650                 priv->data.anim.iter = gdk_pixbuf_animation_get_iter (priv->data.anim.anim, NULL);
1651                 
1652                 if (gdk_pixbuf_animation_iter_get_delay_time (priv->data.anim.iter) >= 0)
1653                   priv->data.anim.frame_timeout =
1654                     gdk_threads_add_timeout (gdk_pixbuf_animation_iter_get_delay_time (priv->data.anim.iter),
1655                                    animation_timeout,
1656                                    image);
1657               }
1658
1659             /* don't advance the anim iter here, or we could get frame changes between two
1660              * exposes of different areas.
1661              */
1662             
1663             pixbuf = gdk_pixbuf_animation_iter_get_pixbuf (priv->data.anim.iter);
1664             g_object_ref (pixbuf);
1665           }
1666           break;
1667
1668         case GTK_IMAGE_ICON_NAME:
1669           state = gtk_widget_get_state (widget);
1670           if (state == GTK_STATE_INSENSITIVE)
1671             {
1672               ensure_pixbuf_for_icon_name (image, GTK_STATE_NORMAL);
1673             }
1674           else
1675             {
1676               ensure_pixbuf_for_icon_name (image, state);
1677               /* Already done by the loading function? */
1678               if (priv->was_symbolic)
1679                 needs_state_transform = FALSE;
1680             }
1681           pixbuf = priv->data.name.pixbuf;
1682           if (pixbuf)
1683             {
1684               g_object_ref (pixbuf);
1685             }
1686           break;
1687
1688         case GTK_IMAGE_GICON:
1689           state = gtk_widget_get_state (widget);
1690           if (state == GTK_STATE_INSENSITIVE)
1691             {
1692               ensure_pixbuf_for_gicon (image, GTK_STATE_NORMAL);
1693             }
1694           else
1695             {
1696               ensure_pixbuf_for_gicon (image, state);
1697               /* Already done by the loading function? */
1698               if (priv->was_symbolic)
1699                 needs_state_transform = FALSE;
1700             }
1701           pixbuf = priv->data.gicon.pixbuf;
1702           if (pixbuf)
1703             {
1704               g_object_ref (pixbuf);
1705             }
1706           break;
1707           
1708         case GTK_IMAGE_EMPTY:
1709         default:
1710           g_assert_not_reached ();
1711           pixbuf = NULL;
1712           break;
1713         }
1714
1715       if (pixbuf)
1716         {
1717           if (needs_state_transform)
1718             {
1719               GtkIconSource *source;
1720               GdkPixbuf *rendered;
1721
1722               source = gtk_icon_source_new ();
1723               gtk_icon_source_set_pixbuf (source, pixbuf);
1724               /* The size here is arbitrary; since size isn't
1725                * wildcarded in the souce, it isn't supposed to be
1726                * scaled by the engine function
1727                */
1728               gtk_icon_source_set_size (source,
1729                                         GTK_ICON_SIZE_SMALL_TOOLBAR);
1730               gtk_icon_source_set_size_wildcarded (source, FALSE);
1731               
1732               rendered = gtk_style_render_icon (gtk_widget_get_style (widget),
1733                                                 source,
1734                                                 gtk_widget_get_direction (widget),
1735                                                 gtk_widget_get_state (widget),
1736                                                 /* arbitrary */
1737                                                 (GtkIconSize)-1,
1738                                                 widget,
1739                                                 "gtk-image");
1740
1741               gtk_icon_source_free (source);
1742
1743               g_object_unref (pixbuf);
1744               pixbuf = rendered;
1745             }
1746
1747           gdk_cairo_set_source_pixbuf (cr, pixbuf, x, y);
1748           cairo_paint (cr);
1749
1750           g_object_unref (pixbuf);
1751         }
1752     }
1753
1754   return FALSE;
1755 }
1756
1757 static void
1758 gtk_image_reset (GtkImage *image)
1759 {
1760   GtkImagePrivate *priv = image->priv;
1761
1762   g_object_freeze_notify (G_OBJECT (image));
1763   
1764   if (priv->storage_type != GTK_IMAGE_EMPTY)
1765     g_object_notify (G_OBJECT (image), "storage-type");
1766
1767   if (priv->icon_size != DEFAULT_ICON_SIZE)
1768     {
1769       priv->icon_size = DEFAULT_ICON_SIZE;
1770       g_object_notify (G_OBJECT (image), "icon-size");
1771     }
1772   
1773   switch (priv->storage_type)
1774     {
1775
1776     case GTK_IMAGE_PIXBUF:
1777
1778       if (priv->data.pixbuf.pixbuf)
1779         g_object_unref (priv->data.pixbuf.pixbuf);
1780
1781       g_object_notify (G_OBJECT (image), "pixbuf");
1782       
1783       break;
1784
1785     case GTK_IMAGE_STOCK:
1786
1787       g_free (priv->data.stock.stock_id);
1788
1789       priv->data.stock.stock_id = NULL;
1790       
1791       g_object_notify (G_OBJECT (image), "stock");      
1792       break;
1793
1794     case GTK_IMAGE_ICON_SET:
1795       if (priv->data.icon_set.icon_set)
1796         gtk_icon_set_unref (priv->data.icon_set.icon_set);
1797       priv->data.icon_set.icon_set = NULL;
1798       
1799       g_object_notify (G_OBJECT (image), "icon-set");      
1800       break;
1801
1802     case GTK_IMAGE_ANIMATION:
1803       gtk_image_reset_anim_iter (image);
1804       
1805       if (priv->data.anim.anim)
1806         g_object_unref (priv->data.anim.anim);
1807       priv->data.anim.anim = NULL;
1808       
1809       g_object_notify (G_OBJECT (image), "pixbuf-animation");
1810       
1811       break;
1812
1813     case GTK_IMAGE_ICON_NAME:
1814       g_free (priv->data.name.icon_name);
1815       priv->data.name.icon_name = NULL;
1816       if (priv->data.name.pixbuf)
1817         g_object_unref (priv->data.name.pixbuf);
1818       priv->data.name.pixbuf = NULL;
1819
1820       g_object_notify (G_OBJECT (image), "icon-name");
1821
1822       break;
1823       
1824     case GTK_IMAGE_GICON:
1825       if (priv->data.gicon.icon)
1826         g_object_unref (priv->data.gicon.icon);
1827       priv->data.gicon.icon = NULL;
1828       if (priv->data.gicon.pixbuf)
1829         g_object_unref (priv->data.gicon.pixbuf);
1830       priv->data.gicon.pixbuf = NULL;
1831
1832       g_object_notify (G_OBJECT (image), "gicon");
1833
1834       break;
1835       
1836     case GTK_IMAGE_EMPTY:
1837     default:
1838       break;
1839       
1840     }
1841
1842   if (priv->filename)
1843     {
1844       g_free (priv->filename);
1845       priv->filename = NULL;
1846       g_object_notify (G_OBJECT (image), "file");
1847     }
1848
1849   priv->storage_type = GTK_IMAGE_EMPTY;
1850
1851   memset (&priv->data, '\0', sizeof (priv->data));
1852
1853   g_object_thaw_notify (G_OBJECT (image));
1854 }
1855
1856 /**
1857  * gtk_image_clear:
1858  * @image: a #GtkImage
1859  *
1860  * Resets the image to be empty.
1861  *
1862  * Since: 2.8
1863  */
1864 void
1865 gtk_image_clear (GtkImage *image)
1866 {
1867   GtkImagePrivate *priv = image->priv;
1868
1869   priv->need_calc_size = 1;
1870
1871   gtk_image_reset (image);
1872   gtk_image_update_size (image, 0, 0);
1873 }
1874
1875 static void
1876 gtk_image_calc_size (GtkImage *image)
1877 {
1878   GtkWidget *widget = GTK_WIDGET (image);
1879   GtkImagePrivate *priv = image->priv;
1880   GdkPixbuf *pixbuf = NULL;
1881
1882   priv->need_calc_size = 0;
1883
1884   /* We update stock/icon set on every size request, because
1885    * the theme could have affected the size; for other kinds of
1886    * image, we just update the required width/height when the image data
1887    * is set.
1888    */
1889   switch (priv->storage_type)
1890     {
1891     case GTK_IMAGE_STOCK:
1892       pixbuf = gtk_widget_render_icon (widget,
1893                                        priv->data.stock.stock_id,
1894                                        priv->icon_size,
1895                                        NULL);
1896       break;
1897       
1898     case GTK_IMAGE_ICON_SET:
1899       pixbuf = gtk_icon_set_render_icon (priv->data.icon_set.icon_set,
1900                                          gtk_widget_get_style (widget),
1901                                          gtk_widget_get_direction (widget),
1902                                          gtk_widget_get_state (widget),
1903                                          priv->icon_size,
1904                                          widget,
1905                                          NULL);
1906       break;
1907     case GTK_IMAGE_ICON_NAME:
1908       ensure_pixbuf_for_icon_name (image, GTK_STATE_NORMAL);
1909       pixbuf = priv->data.name.pixbuf;
1910       if (pixbuf) g_object_ref (pixbuf);
1911       break;
1912     case GTK_IMAGE_GICON:
1913       ensure_pixbuf_for_gicon (image, GTK_STATE_NORMAL);
1914       pixbuf = priv->data.gicon.pixbuf;
1915       if (pixbuf)
1916         g_object_ref (pixbuf);
1917       break;
1918     default:
1919       break;
1920     }
1921
1922   if (pixbuf)
1923     {
1924       gint xpad, ypad;
1925
1926       gtk_misc_get_padding (GTK_MISC (image), &xpad, &ypad);
1927
1928       priv->required_width = gdk_pixbuf_get_width (pixbuf) + xpad * 2;
1929       priv->required_height = gdk_pixbuf_get_height (pixbuf) + ypad * 2;
1930
1931       g_object_unref (pixbuf);
1932     }
1933 }
1934
1935 static void
1936 gtk_image_size_request (GtkWidget      *widget,
1937                         GtkRequisition *requisition)
1938 {
1939   GtkImage *image;
1940   GtkImagePrivate *priv;
1941   
1942   image = GTK_IMAGE (widget);
1943   priv  = image->priv;
1944
1945   gtk_image_calc_size (image);
1946
1947   requisition->width  = priv->required_width;
1948   requisition->height = priv->required_height;
1949 }
1950
1951 static void
1952 gtk_image_style_set (GtkWidget      *widget,
1953                      GtkStyle       *prev_style)
1954 {
1955   GtkImage *image;
1956
1957   image = GTK_IMAGE (widget);
1958
1959   GTK_WIDGET_CLASS (gtk_image_parent_class)->style_set (widget, prev_style);
1960
1961   icon_theme_changed (image);
1962 }
1963
1964 static void
1965 gtk_image_screen_changed (GtkWidget *widget,
1966                           GdkScreen *prev_screen)
1967 {
1968   GtkImage *image;
1969
1970   image = GTK_IMAGE (widget);
1971
1972   if (GTK_WIDGET_CLASS (gtk_image_parent_class)->screen_changed)
1973     GTK_WIDGET_CLASS (gtk_image_parent_class)->screen_changed (widget, prev_screen);
1974
1975   icon_theme_changed (image);
1976 }
1977
1978
1979 static void
1980 gtk_image_update_size (GtkImage *image,
1981                        gint      image_width,
1982                        gint      image_height)
1983 {
1984   GtkWidget       *widget = GTK_WIDGET (image);
1985   GtkImagePrivate *priv = image->priv;
1986   gint             xpad, ypad;
1987
1988   gtk_misc_get_padding (GTK_MISC (image), &xpad, &ypad);
1989
1990   priv->required_width  = image_width + xpad * 2;
1991   priv->required_height = image_height + ypad * 2;
1992
1993   if (gtk_widget_get_visible (widget))
1994     gtk_widget_queue_resize (widget);
1995 }
1996
1997
1998 /**
1999  * gtk_image_set_pixel_size:
2000  * @image: a #GtkImage
2001  * @pixel_size: the new pixel size
2002  * 
2003  * Sets the pixel size to use for named icons. If the pixel size is set
2004  * to a value != -1, it is used instead of the icon size set by
2005  * gtk_image_set_from_icon_name().
2006  *
2007  * Since: 2.6
2008  */
2009 void 
2010 gtk_image_set_pixel_size (GtkImage *image,
2011                           gint      pixel_size)
2012 {
2013   GtkImagePrivate *priv;
2014
2015   g_return_if_fail (GTK_IS_IMAGE (image));
2016
2017   priv = image->priv;
2018
2019   if (priv->pixel_size != pixel_size)
2020     {
2021       priv->pixel_size = pixel_size;
2022       
2023       if (priv->storage_type == GTK_IMAGE_ICON_NAME)
2024         {
2025           if (priv->data.name.pixbuf)
2026             {
2027               g_object_unref (priv->data.name.pixbuf);
2028               priv->data.name.pixbuf = NULL;
2029             }
2030           
2031           gtk_image_update_size (image, pixel_size, pixel_size);
2032         }
2033       
2034       if (priv->storage_type == GTK_IMAGE_GICON)
2035         {
2036           if (priv->data.gicon.pixbuf)
2037             {
2038               g_object_unref (priv->data.gicon.pixbuf);
2039               priv->data.gicon.pixbuf = NULL;
2040             }
2041           
2042           gtk_image_update_size (image, pixel_size, pixel_size);
2043         }
2044       
2045       g_object_notify (G_OBJECT (image), "pixel-size");
2046     }
2047 }
2048
2049 /**
2050  * gtk_image_get_pixel_size:
2051  * @image: a #GtkImage
2052  * 
2053  * Gets the pixel size used for named icons.
2054  *
2055  * Returns: the pixel size used for named icons.
2056  *
2057  * Since: 2.6
2058  */
2059 gint
2060 gtk_image_get_pixel_size (GtkImage *image)
2061 {
2062   g_return_val_if_fail (GTK_IS_IMAGE (image), -1);
2063
2064   return image->priv->pixel_size;
2065 }