]> Pileus Git - ~andy/gtk/blob - gtk/gtkimage.c
Document possible accelerator gotcha when using this function. (#139641,
[~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 "gtkcontainer.h"
30 #include "gtkimage.h"
31 #include "gtkiconfactory.h"
32 #include "gtkstock.h"
33 #include "gtkintl.h"
34 #include <string.h>
35
36 #define DEFAULT_ICON_SIZE GTK_ICON_SIZE_BUTTON
37
38 static void gtk_image_class_init   (GtkImageClass  *klass);
39 static void gtk_image_init         (GtkImage       *image);
40 static gint gtk_image_expose       (GtkWidget      *widget,
41                                     GdkEventExpose *event);
42 static void gtk_image_unmap        (GtkWidget      *widget);
43 static void gtk_image_unrealize    (GtkWidget      *widget);
44 static void gtk_image_size_request (GtkWidget      *widget,
45                                     GtkRequisition *requisition);
46 static void gtk_image_destroy      (GtkObject      *object);
47 static void gtk_image_clear        (GtkImage       *image);
48 static void gtk_image_reset        (GtkImage       *image);
49 static void gtk_image_calc_size    (GtkImage       *image);
50
51 static void gtk_image_update_size  (GtkImage       *image,
52                                     gint            image_width,
53                                     gint            image_height);
54
55 static void gtk_image_set_property      (GObject          *object,
56                                          guint             prop_id,
57                                          const GValue     *value,
58                                          GParamSpec       *pspec);
59 static void gtk_image_get_property      (GObject          *object,
60                                          guint             prop_id,
61                                          GValue           *value,
62                                          GParamSpec       *pspec);
63
64 static gpointer parent_class;
65
66 enum
67 {
68   PROP_0,
69   PROP_PIXBUF,
70   PROP_PIXMAP,
71   PROP_IMAGE,
72   PROP_MASK,
73   PROP_FILE,
74   PROP_STOCK,
75   PROP_ICON_SET,
76   PROP_ICON_SIZE,
77   PROP_PIXBUF_ANIMATION,
78   PROP_STORAGE_TYPE
79 };
80
81 GType
82 gtk_image_get_type (void)
83 {
84   static GType image_type = 0;
85
86   if (!image_type)
87     {
88       static const GTypeInfo image_info =
89       {
90         sizeof (GtkImageClass),
91         NULL,           /* base_init */
92         NULL,           /* base_finalize */
93         (GClassInitFunc) gtk_image_class_init,
94         NULL,           /* class_finalize */
95         NULL,           /* class_data */
96         sizeof (GtkImage),
97         0,              /* n_preallocs */
98         (GInstanceInitFunc) gtk_image_init,
99       };
100
101       image_type = g_type_register_static (GTK_TYPE_MISC, "GtkImage",
102                                            &image_info, 0);
103     }
104
105   return image_type;
106 }
107
108 static void
109 gtk_image_class_init (GtkImageClass *class)
110 {
111   GObjectClass *gobject_class;
112   GtkObjectClass *object_class;
113   GtkWidgetClass *widget_class;
114
115   parent_class = g_type_class_peek_parent (class);
116
117   gobject_class = G_OBJECT_CLASS (class);
118   
119   gobject_class->set_property = gtk_image_set_property;
120   gobject_class->get_property = gtk_image_get_property;
121   
122   object_class = GTK_OBJECT_CLASS (class);
123   
124   object_class->destroy = gtk_image_destroy;
125
126   widget_class = GTK_WIDGET_CLASS (class);
127   
128   widget_class->expose_event = gtk_image_expose;
129   widget_class->size_request = gtk_image_size_request;
130   widget_class->unmap = gtk_image_unmap;
131   widget_class->unrealize = gtk_image_unrealize;
132   
133   g_object_class_install_property (gobject_class,
134                                    PROP_PIXBUF,
135                                    g_param_spec_object ("pixbuf",
136                                                         P_("Pixbuf"),
137                                                         P_("A GdkPixbuf to display"),
138                                                         GDK_TYPE_PIXBUF,
139                                                         G_PARAM_READWRITE));
140
141   g_object_class_install_property (gobject_class,
142                                    PROP_PIXMAP,
143                                    g_param_spec_object ("pixmap",
144                                                         P_("Pixmap"),
145                                                         P_("A GdkPixmap to display"),
146                                                         GDK_TYPE_PIXMAP,
147                                                         G_PARAM_READWRITE));
148
149   g_object_class_install_property (gobject_class,
150                                    PROP_IMAGE,
151                                    g_param_spec_object ("image",
152                                                         P_("Image"),
153                                                         P_("A GdkImage to display"),
154                                                         GDK_TYPE_IMAGE,
155                                                         G_PARAM_READWRITE));
156
157   g_object_class_install_property (gobject_class,
158                                    PROP_MASK,
159                                    g_param_spec_object ("mask",
160                                                         P_("Mask"),
161                                                         P_("Mask bitmap to use with GdkImage or GdkPixmap"),
162                                                         GDK_TYPE_PIXMAP,
163                                                         G_PARAM_READWRITE));
164   
165   g_object_class_install_property (gobject_class,
166                                    PROP_FILE,
167                                    g_param_spec_string ("file",
168                                                         P_("Filename"),
169                                                         P_("Filename to load and display"),
170                                                         NULL,
171                                                         G_PARAM_WRITABLE));
172   
173
174   g_object_class_install_property (gobject_class,
175                                    PROP_STOCK,
176                                    g_param_spec_string ("stock",
177                                                         P_("Stock ID"),
178                                                         P_("Stock ID for a stock image to display"),
179                                                         NULL,
180                                                         G_PARAM_READWRITE));
181   
182   g_object_class_install_property (gobject_class,
183                                    PROP_ICON_SET,
184                                    g_param_spec_boxed ("icon_set",
185                                                        P_("Icon set"),
186                                                        P_("Icon set to display"),
187                                                        GTK_TYPE_ICON_SET,
188                                                        G_PARAM_READWRITE));
189   
190   g_object_class_install_property (gobject_class,
191                                    PROP_ICON_SIZE,
192                                    g_param_spec_int ("icon_size",
193                                                      P_("Icon size"),
194                                                      P_("Size to use for stock icon or icon set"),
195                                                      0, G_MAXINT,
196                                                      DEFAULT_ICON_SIZE,
197                                                      G_PARAM_READWRITE));
198
199   g_object_class_install_property (gobject_class,
200                                    PROP_PIXBUF_ANIMATION,
201                                    g_param_spec_object ("pixbuf_animation",
202                                                         P_("Animation"),
203                                                         P_("GdkPixbufAnimation to display"),
204                                                         GDK_TYPE_PIXBUF_ANIMATION,
205                                                         G_PARAM_READWRITE));
206   
207   g_object_class_install_property (gobject_class,
208                                    PROP_STORAGE_TYPE,
209                                    g_param_spec_enum ("storage_type",
210                                                       P_("Storage type"),
211                                                       P_("The representation being used for image data"),
212                                                       GTK_TYPE_IMAGE_TYPE,
213                                                       GTK_IMAGE_EMPTY,
214                                                       G_PARAM_READABLE));
215 }
216
217 static void
218 gtk_image_init (GtkImage *image)
219 {
220   GTK_WIDGET_SET_FLAGS (image, GTK_NO_WINDOW);
221
222   image->storage_type = GTK_IMAGE_EMPTY;
223   image->icon_size = DEFAULT_ICON_SIZE;
224   image->mask = NULL;
225 }
226
227 static void
228 gtk_image_destroy (GtkObject *object)
229 {
230   GtkImage *image = GTK_IMAGE (object);
231
232   gtk_image_clear (image);
233   
234   GTK_OBJECT_CLASS (parent_class)->destroy (object);
235 }
236
237 static void 
238 gtk_image_set_property (GObject      *object,
239                         guint         prop_id,
240                         const GValue *value,
241                         GParamSpec   *pspec)
242 {
243   GtkImage *image;
244
245   image = GTK_IMAGE (object);
246   
247   switch (prop_id)
248     {
249     case PROP_PIXBUF:
250       gtk_image_set_from_pixbuf (image,
251                                  g_value_get_object (value));
252       break;
253     case PROP_PIXMAP:
254       gtk_image_set_from_pixmap (image,
255                                  g_value_get_object (value),
256                                  image->mask);
257       break;
258     case PROP_IMAGE:
259       gtk_image_set_from_image (image,
260                                 g_value_get_object (value),
261                                 image->mask);
262       break;
263     case PROP_MASK:
264       if (image->storage_type == GTK_IMAGE_PIXMAP)
265         gtk_image_set_from_pixmap (image,
266                                    image->data.pixmap.pixmap,
267                                    g_value_get_object (value));
268       else if (image->storage_type == GTK_IMAGE_IMAGE)
269         gtk_image_set_from_image (image,
270                                   image->data.image.image,
271                                   g_value_get_object (value));
272       else
273         {
274           GdkBitmap *mask;
275
276           mask = g_value_get_object (value);
277
278           if (mask)
279             g_object_ref (mask);
280           
281           gtk_image_reset (image);
282
283           image->mask = mask;
284         }
285       break;
286     case PROP_FILE:
287       gtk_image_set_from_file (image,
288                                g_value_get_string (value));
289       break;
290     case PROP_STOCK:
291       gtk_image_set_from_stock (image, g_value_get_string (value),
292                                 image->icon_size);
293       break;
294     case PROP_ICON_SET:
295       gtk_image_set_from_icon_set (image, g_value_get_boxed (value),
296                                    image->icon_size);
297       break;
298     case PROP_ICON_SIZE:
299       if (image->storage_type == GTK_IMAGE_STOCK)
300         gtk_image_set_from_stock (image,
301                                   image->data.stock.stock_id,
302                                   g_value_get_int (value));
303       else if (image->storage_type == GTK_IMAGE_ICON_SET)
304         gtk_image_set_from_icon_set (image,
305                                      image->data.icon_set.icon_set,
306                                      g_value_get_int (value));
307       else
308         /* Save to be used when STOCK or ICON_SET property comes in */
309         image->icon_size = g_value_get_int (value);
310       break;
311     case PROP_PIXBUF_ANIMATION:
312       gtk_image_set_from_animation (image,
313                                     g_value_get_object (value));
314       break;
315       
316     default:
317       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
318       break;
319     }
320 }
321
322 static void 
323 gtk_image_get_property (GObject     *object,
324                         guint        prop_id,
325                         GValue      *value,
326                         GParamSpec  *pspec)
327 {
328   GtkImage *image;
329
330   image = GTK_IMAGE (object);
331
332   /* The "getter" functions whine if you try to get the wrong
333    * storage type. This function is instead robust against that,
334    * so that GUI builders don't have to jump through hoops
335    * to avoid g_warning
336    */
337   
338   switch (prop_id)
339     {
340     case PROP_PIXBUF:
341       if (image->storage_type != GTK_IMAGE_PIXBUF)
342         g_value_set_object (value, NULL);
343       else
344         g_value_set_object (value,
345                             gtk_image_get_pixbuf (image));
346       break;
347     case PROP_PIXMAP:
348       if (image->storage_type != GTK_IMAGE_PIXMAP)
349         g_value_set_object (value, NULL);
350       else
351         g_value_set_object (value,
352                             image->data.pixmap.pixmap);
353       break;
354     case PROP_MASK:
355       g_value_set_object (value, image->mask);
356       break;
357     case PROP_IMAGE:
358       if (image->storage_type != GTK_IMAGE_IMAGE)
359         g_value_set_object (value, NULL);
360       else
361         g_value_set_object (value,
362                             image->data.image.image);
363       break;
364     case PROP_STOCK:
365       if (image->storage_type != GTK_IMAGE_STOCK)
366         g_value_set_string (value, NULL);
367       else
368         g_value_set_string (value,
369                             image->data.stock.stock_id);
370       break;
371     case PROP_ICON_SET:
372       if (image->storage_type != GTK_IMAGE_ICON_SET)
373         g_value_set_boxed (value, NULL);
374       else
375         g_value_set_boxed (value,
376                            image->data.icon_set.icon_set);
377       break;      
378     case PROP_ICON_SIZE:
379       g_value_set_int (value, image->icon_size);
380       break;
381     case PROP_PIXBUF_ANIMATION:
382       if (image->storage_type != GTK_IMAGE_ANIMATION)
383         g_value_set_object (value, NULL);
384       else
385         g_value_set_object (value,
386                             image->data.anim.anim);
387       break;
388     case PROP_STORAGE_TYPE:
389       g_value_set_enum (value, image->storage_type);
390       break;
391       
392     default:
393       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
394       break;
395     }
396 }
397
398
399 /**
400  * gtk_image_new_from_pixmap:
401  * @pixmap: a #GdkPixmap, or %NULL
402  * @mask: a #GdkBitmap, or %NULL
403  * 
404  * Creates a #GtkImage widget displaying @pixmap with a @mask.
405  * A #GdkImage is a server-side image buffer in the pixel format of the
406  * current display. The #GtkImage does not assume a reference to the
407  * pixmap or mask; you still need to unref them if you own references.
408  * #GtkImage will add its own reference rather than adopting yours.
409  * 
410  * Return value: a new #GtkImage
411  **/
412 GtkWidget*
413 gtk_image_new_from_pixmap (GdkPixmap *pixmap,
414                            GdkBitmap *mask)
415 {
416   GtkImage *image;
417
418   image = g_object_new (GTK_TYPE_IMAGE, NULL);
419
420   gtk_image_set_from_pixmap (image, pixmap, mask);
421
422   return GTK_WIDGET (image);
423 }
424
425 /**
426  * gtk_image_new_from_image:
427  * @image: a #GdkImage, or %NULL
428  * @mask: a #GdkBitmap, or %NULL 
429  * 
430  * Creates a #GtkImage widget displaying a @image with a @mask.
431  * A #GdkImage is a client-side image buffer in the pixel format of the
432  * current display.
433  * The #GtkImage does not assume a reference to the
434  * image or mask; you still need to unref them if you own references.
435  * #GtkImage will add its own reference rather than adopting yours.
436  * 
437  * Return value: a new #GtkImage
438  **/
439 GtkWidget*
440 gtk_image_new_from_image  (GdkImage  *gdk_image,
441                            GdkBitmap *mask)
442 {
443   GtkImage *image;
444
445   image = g_object_new (GTK_TYPE_IMAGE, NULL);
446
447   gtk_image_set_from_image (image, gdk_image, mask);
448
449   return GTK_WIDGET (image);
450 }
451
452 /**
453  * gtk_image_new_from_file:
454  * @filename: a filename
455  * 
456  * Creates a new #GtkImage displaying the file @filename. If the file
457  * isn't found or can't be loaded, the resulting #GtkImage will
458  * display a "broken image" icon. This function never returns %NULL,
459  * it always returns a valid #GtkImage widget.
460  *
461  * If the file contains an animation, the image will contain an
462  * animation.
463  *
464  * If you need to detect failures to load the file, use
465  * gdk_pixbuf_new_from_file() to load the file yourself, then create
466  * the #GtkImage from the pixbuf. (Or for animations, use
467  * gdk_pixbuf_animation_new_from_file()).
468  *
469  * The storage type (gtk_image_get_storage_type()) of the returned
470  * image is not defined, it will be whatever is appropriate for
471  * displaying the file.
472  * 
473  * Return value: a new #GtkImage
474  **/
475 GtkWidget*
476 gtk_image_new_from_file   (const gchar *filename)
477 {
478   GtkImage *image;
479
480   image = g_object_new (GTK_TYPE_IMAGE, NULL);
481
482   gtk_image_set_from_file (image, filename);
483
484   return GTK_WIDGET (image);
485 }
486
487 /**
488  * gtk_image_new_from_pixbuf:
489  * @pixbuf: a #GdkPixbuf, or %NULL
490  * 
491  * Creates a new #GtkImage displaying @pixbuf.
492  * The #GtkImage does not assume a reference to the
493  * pixbuf; you still need to unref it if you own references.
494  * #GtkImage will add its own reference rather than adopting yours.
495  * 
496  * Note that this function just creates an #GtkImage from the pixbuf.  The
497  * #GtkImage created will not react to state changes.  Should you want that, you
498  * should use gtk_image_new_from_icon_set().
499  * 
500  * Return value: a new #GtkImage
501  **/
502 GtkWidget*
503 gtk_image_new_from_pixbuf (GdkPixbuf *pixbuf)
504 {
505   GtkImage *image;
506
507   image = g_object_new (GTK_TYPE_IMAGE, NULL);
508
509   gtk_image_set_from_pixbuf (image, pixbuf);
510
511   return GTK_WIDGET (image);  
512 }
513
514 /**
515  * gtk_image_new_from_stock:
516  * @stock_id: a stock icon name
517  * @size: a stock icon size
518  * 
519  * Creates a #GtkImage displaying a stock icon. Sample stock icon
520  * names are #GTK_STOCK_OPEN, #GTK_STOCK_EXIT. Sample stock sizes
521  * are #GTK_ICON_SIZE_MENU, #GTK_ICON_SIZE_SMALL_TOOLBAR. If the stock
522  * icon name isn't known, a "broken image" icon will be displayed instead.
523  * You can register your own stock icon names, see
524  * gtk_icon_factory_add_default() and gtk_icon_factory_add().
525  * 
526  * Return value: a new #GtkImage displaying the stock icon
527  **/
528 GtkWidget*
529 gtk_image_new_from_stock (const gchar    *stock_id,
530                           GtkIconSize     size)
531 {
532   GtkImage *image;
533
534   image = g_object_new (GTK_TYPE_IMAGE, NULL);
535
536   gtk_image_set_from_stock (image, stock_id, size);
537
538   return GTK_WIDGET (image);
539 }
540
541 /**
542  * gtk_image_new_from_icon_set:
543  * @icon_set: a #GtkIconSet
544  * @size: a stock icon size
545  *
546  * Creates a #GtkImage displaying an icon set. Sample stock sizes are
547  * #GTK_ICON_SIZE_MENU, #GTK_ICON_SIZE_SMALL_TOOLBAR. Instead of using
548  * this function, usually it's better to create a #GtkIconFactory, put
549  * your icon sets in the icon factory, add the icon factory to the
550  * list of default factories with gtk_icon_factory_add_default(), and
551  * then use gtk_image_new_from_stock(). This will allow themes to
552  * override the icon you ship with your application.
553  *
554  * The #GtkImage does not assume a reference to the
555  * icon set; you still need to unref it if you own references.
556  * #GtkImage will add its own reference rather than adopting yours.
557  * 
558  * 
559  * Return value: a new #GtkImage
560  **/
561 GtkWidget*
562 gtk_image_new_from_icon_set (GtkIconSet     *icon_set,
563                              GtkIconSize     size)
564 {
565   GtkImage *image;
566
567   image = g_object_new (GTK_TYPE_IMAGE, NULL);
568
569   gtk_image_set_from_icon_set (image, icon_set, size);
570
571   return GTK_WIDGET (image);
572 }
573
574 /**
575  * gtk_image_new_from_animation:
576  * @animation: an animation
577  * 
578  * Creates a #GtkImage displaying the given animation.
579  * The #GtkImage does not assume a reference to the
580  * animation; you still need to unref it if you own references.
581  * #GtkImage will add its own reference rather than adopting yours.
582  * 
583  * Return value: a new #GtkImage widget
584  **/
585 GtkWidget*
586 gtk_image_new_from_animation (GdkPixbufAnimation *animation)
587 {
588   GtkImage *image;
589
590   g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), NULL);
591   
592   image = g_object_new (GTK_TYPE_IMAGE, NULL);
593
594   gtk_image_set_from_animation (image, animation);
595
596   return GTK_WIDGET (image);
597 }
598
599 /**
600  * gtk_image_set_from_pixmap:
601  * @image: a #GtkImage
602  * @pixmap: a #GdkPixmap or %NULL
603  * @mask: a #GdkBitmap or %NULL
604  *
605  * See gtk_image_new_from_pixmap() for details.
606  * 
607  **/
608 void
609 gtk_image_set_from_pixmap (GtkImage  *image,
610                            GdkPixmap *pixmap,
611                            GdkBitmap *mask)
612 {
613   g_return_if_fail (GTK_IS_IMAGE (image));
614   g_return_if_fail (pixmap == NULL ||
615                     GDK_IS_PIXMAP (pixmap));
616   g_return_if_fail (mask == NULL ||
617                     GDK_IS_PIXMAP (mask));
618
619   g_object_freeze_notify (G_OBJECT (image));
620   
621   if (pixmap)
622     g_object_ref (pixmap);
623
624   if (mask)
625     g_object_ref (mask);
626
627   gtk_image_reset (image);
628
629   image->mask = mask;
630   
631   if (pixmap)
632     {
633       int width;
634       int height;
635       
636       image->storage_type = GTK_IMAGE_PIXMAP;
637
638       image->data.pixmap.pixmap = pixmap;
639
640       gdk_drawable_get_size (GDK_DRAWABLE (pixmap), &width, &height);
641
642       gtk_image_update_size (image, width, height);
643     }
644
645   g_object_notify (G_OBJECT (image), "pixmap");
646   g_object_notify (G_OBJECT (image), "mask");
647   
648   g_object_thaw_notify (G_OBJECT (image));
649 }
650
651 /**
652  * gtk_image_set_from_image:
653  * @image: a #GtkImage
654  * @gdk_image: a #GdkImage or %NULL
655  * @mask: a #GdkBitmap or %NULL
656  *
657  * See gtk_image_new_from_image() for details.
658  * 
659  **/
660 void
661 gtk_image_set_from_image  (GtkImage  *image,
662                            GdkImage  *gdk_image,
663                            GdkBitmap *mask)
664 {
665   g_return_if_fail (GTK_IS_IMAGE (image));
666   g_return_if_fail (gdk_image == NULL ||
667                     GDK_IS_IMAGE (gdk_image));
668   g_return_if_fail (mask == NULL ||
669                     GDK_IS_PIXMAP (mask));
670
671   g_object_freeze_notify (G_OBJECT (image));
672   
673   if (gdk_image)
674     g_object_ref (gdk_image);
675
676   if (mask)
677     g_object_ref (mask);
678
679   gtk_image_reset (image);
680
681   if (gdk_image)
682     {
683       image->storage_type = GTK_IMAGE_IMAGE;
684
685       image->data.image.image = gdk_image;
686       image->mask = mask;
687
688       gtk_image_update_size (image, gdk_image->width, gdk_image->height);
689     }
690   else
691     {
692       /* Clean up the mask if gdk_image was NULL */
693       if (mask)
694         g_object_unref (mask);
695     }
696
697   g_object_notify (G_OBJECT (image), "image");
698   g_object_notify (G_OBJECT (image), "mask");
699   
700   g_object_thaw_notify (G_OBJECT (image));
701 }
702
703 /**
704  * gtk_image_set_from_file:
705  * @image: a #GtkImage
706  * @filename: a filename or %NULL
707  *
708  * See gtk_image_new_from_file() for details.
709  * 
710  **/
711 void
712 gtk_image_set_from_file   (GtkImage    *image,
713                            const gchar *filename)
714 {
715   GdkPixbufAnimation *anim;
716   
717   g_return_if_fail (GTK_IS_IMAGE (image));
718
719   g_object_freeze_notify (G_OBJECT (image));
720   
721   gtk_image_reset (image);
722
723   if (filename == NULL)
724     {
725       g_object_thaw_notify (G_OBJECT (image));
726       return;
727     }
728   
729   anim = gdk_pixbuf_animation_new_from_file (filename, NULL);
730
731   if (anim == NULL)
732     {
733       gtk_image_set_from_stock (image,
734                                 GTK_STOCK_MISSING_IMAGE,
735                                 GTK_ICON_SIZE_BUTTON);
736       g_object_thaw_notify (G_OBJECT (image));
737       return;
738     }
739
740   /* We could just unconditionally set_from_animation,
741    * but it's nicer for memory if we toss the animation
742    * if it's just a single pixbuf
743    */
744
745   if (gdk_pixbuf_animation_is_static_image (anim))
746     {
747       gtk_image_set_from_pixbuf (image,
748                                  gdk_pixbuf_animation_get_static_image (anim));
749     }
750   else
751     {
752       gtk_image_set_from_animation (image, anim);
753     }
754
755   g_object_unref (anim);
756
757   g_object_thaw_notify (G_OBJECT (image));
758 }
759
760 /**
761  * gtk_image_set_from_pixbuf:
762  * @image: a #GtkImage
763  * @pixbuf: a #GdkPixbuf or %NULL
764  *
765  * See gtk_image_new_from_pixbuf() for details. 
766  * 
767  **/
768 void
769 gtk_image_set_from_pixbuf (GtkImage  *image,
770                            GdkPixbuf *pixbuf)
771 {
772   g_return_if_fail (GTK_IS_IMAGE (image));
773   g_return_if_fail (pixbuf == NULL ||
774                     GDK_IS_PIXBUF (pixbuf));
775
776   g_object_freeze_notify (G_OBJECT (image));
777   
778   if (pixbuf)
779     g_object_ref (pixbuf);
780
781   gtk_image_reset (image);
782
783   if (pixbuf != NULL)
784     {
785       image->storage_type = GTK_IMAGE_PIXBUF;
786
787       image->data.pixbuf.pixbuf = pixbuf;
788
789       gtk_image_update_size (image,
790                              gdk_pixbuf_get_width (pixbuf),
791                              gdk_pixbuf_get_height (pixbuf));
792     }
793
794   g_object_notify (G_OBJECT (image), "pixbuf");
795   
796   g_object_thaw_notify (G_OBJECT (image));
797 }
798
799 /**
800  * gtk_image_set_from_stock:
801  * @image: a #GtkImage
802  * @stock_id: a stock icon name
803  * @size: a stock icon size
804  *
805  * See gtk_image_new_from_stock() for details.
806  * 
807  **/
808 void
809 gtk_image_set_from_stock  (GtkImage       *image,
810                            const gchar    *stock_id,
811                            GtkIconSize     size)
812 {
813   gchar *new_id;
814   
815   g_return_if_fail (GTK_IS_IMAGE (image));
816
817   g_object_freeze_notify (G_OBJECT (image));
818
819   /* in case stock_id == image->data.stock.stock_id */
820   new_id = g_strdup (stock_id);
821   
822   gtk_image_reset (image);
823
824   if (new_id)
825     {
826       image->storage_type = GTK_IMAGE_STOCK;
827       
828       image->data.stock.stock_id = new_id;
829       image->icon_size = size;
830
831       /* Size is demand-computed in size request method
832        * if we're a stock image, since changing the
833        * style impacts the size request
834        */
835     }
836
837   g_object_notify (G_OBJECT (image), "stock");
838   g_object_notify (G_OBJECT (image), "icon_size");
839   
840   g_object_thaw_notify (G_OBJECT (image));
841 }
842
843 /**
844  * gtk_image_set_from_icon_set:
845  * @image: a #GtkImage
846  * @icon_set: a #GtkIconSet
847  * @size: a stock icon size
848  *
849  * See gtk_image_new_from_icon_set() for details.
850  * 
851  **/
852 void
853 gtk_image_set_from_icon_set  (GtkImage       *image,
854                               GtkIconSet     *icon_set,
855                               GtkIconSize     size)
856 {
857   g_return_if_fail (GTK_IS_IMAGE (image));
858
859   g_object_freeze_notify (G_OBJECT (image));
860   
861   if (icon_set)
862     gtk_icon_set_ref (icon_set);
863   
864   gtk_image_reset (image);
865
866   if (icon_set)
867     {      
868       image->storage_type = GTK_IMAGE_ICON_SET;
869       
870       image->data.icon_set.icon_set = icon_set;
871       image->icon_size = size;
872
873       /* Size is demand-computed in size request method
874        * if we're an icon set
875        */
876     }
877   
878   g_object_notify (G_OBJECT (image), "icon_set");
879   g_object_notify (G_OBJECT (image), "icon_size");
880   
881   g_object_thaw_notify (G_OBJECT (image));
882 }
883
884 /**
885  * gtk_image_set_from_animation:
886  * @image: a #GtkImage
887  * @animation: the #GdkPixbufAnimation
888  * 
889  * Causes the #GtkImage to display the given animation (or display
890  * nothing, if you set the animation to %NULL).
891  **/
892 void
893 gtk_image_set_from_animation (GtkImage           *image,
894                               GdkPixbufAnimation *animation)
895 {
896   g_return_if_fail (GTK_IS_IMAGE (image));
897   g_return_if_fail (animation == NULL ||
898                     GDK_IS_PIXBUF_ANIMATION (animation));
899
900   g_object_freeze_notify (G_OBJECT (image));
901   
902   if (animation)
903     g_object_ref (animation);
904
905   gtk_image_reset (image);
906
907   if (animation != NULL)
908     {
909       image->storage_type = GTK_IMAGE_ANIMATION;
910
911       image->data.anim.anim = animation;
912       image->data.anim.frame_timeout = 0;
913       image->data.anim.iter = NULL;
914       
915       gtk_image_update_size (image,
916                              gdk_pixbuf_animation_get_width (animation),
917                              gdk_pixbuf_animation_get_height (animation));
918     }
919
920   g_object_notify (G_OBJECT (image), "pixbuf_animation");
921   
922   g_object_thaw_notify (G_OBJECT (image));
923 }
924
925 /**
926  * gtk_image_get_storage_type:
927  * @image: a #GtkImage
928  * 
929  * Gets the type of representation being used by the #GtkImage
930  * to store image data. If the #GtkImage has no image data,
931  * the return value will be %GTK_IMAGE_EMPTY.
932  * 
933  * Return value: image representation being used
934  **/
935 GtkImageType
936 gtk_image_get_storage_type (GtkImage *image)
937 {
938   g_return_val_if_fail (GTK_IS_IMAGE (image), GTK_IMAGE_EMPTY);
939
940   return image->storage_type;
941 }
942
943 /**
944  * gtk_image_get_pixmap:
945  * @image: a #GtkImage
946  * @pixmap: location to store the pixmap, or %NULL
947  * @mask: location to store the mask, or %NULL
948  *
949  * Gets the pixmap and mask being displayed by the #GtkImage.
950  * The storage type of the image must be %GTK_IMAGE_EMPTY or
951  * %GTK_IMAGE_PIXMAP (see gtk_image_get_storage_type()).
952  * The caller of this function does not own a reference to the
953  * returned pixmap and mask.
954  * 
955  **/
956 void
957 gtk_image_get_pixmap (GtkImage   *image,
958                       GdkPixmap **pixmap,
959                       GdkBitmap **mask)
960 {
961   g_return_if_fail (GTK_IS_IMAGE (image)); 
962   g_return_if_fail (image->storage_type == GTK_IMAGE_PIXMAP ||
963                     image->storage_type == GTK_IMAGE_EMPTY);
964   
965   if (pixmap)
966     *pixmap = image->data.pixmap.pixmap;
967   
968   if (mask)
969     *mask = image->mask;
970 }
971
972 /**
973  * gtk_image_get_image:
974  * @image: a #GtkImage
975  * @gdk_image: return location for a #GtkImage
976  * @mask: return location for a #GdkBitmap
977  * 
978  * Gets the #GdkImage and mask being displayed by the #GtkImage.
979  * The storage type of the image must be %GTK_IMAGE_EMPTY or
980  * %GTK_IMAGE_IMAGE (see gtk_image_get_storage_type()).
981  * The caller of this function does not own a reference to the
982  * returned image and mask.
983  **/
984 void
985 gtk_image_get_image  (GtkImage   *image,
986                       GdkImage  **gdk_image,
987                       GdkBitmap **mask)
988 {
989   g_return_if_fail (GTK_IS_IMAGE (image));
990   g_return_if_fail (image->storage_type == GTK_IMAGE_IMAGE ||
991                     image->storage_type == GTK_IMAGE_EMPTY);
992
993   if (gdk_image)
994     *gdk_image = image->data.image.image;
995   
996   if (mask)
997     *mask = image->mask;
998 }
999
1000 /**
1001  * gtk_image_get_pixbuf:
1002  * @image: a #GtkImage
1003  *
1004  *
1005  * Gets the #GdkPixbuf being displayed by the #GtkImage.
1006  * The storage type of the image must be %GTK_IMAGE_EMPTY or
1007  * %GTK_IMAGE_PIXBUF (see gtk_image_get_storage_type()).
1008  * The caller of this function does not own a reference to the
1009  * returned pixbuf.
1010  * 
1011  * Return value: the displayed pixbuf, or %NULL if the image is empty
1012  **/
1013 GdkPixbuf*
1014 gtk_image_get_pixbuf (GtkImage *image)
1015 {
1016   g_return_val_if_fail (GTK_IS_IMAGE (image), NULL);
1017   g_return_val_if_fail (image->storage_type == GTK_IMAGE_PIXBUF ||
1018                         image->storage_type == GTK_IMAGE_EMPTY, NULL);
1019
1020   if (image->storage_type == GTK_IMAGE_EMPTY)
1021     image->data.pixbuf.pixbuf = NULL;
1022   
1023   return image->data.pixbuf.pixbuf;
1024 }
1025
1026 /**
1027  * gtk_image_get_stock:
1028  * @image: a #GtkImage
1029  * @stock_id: place to store a stock icon name
1030  * @size: place to store a stock icon size
1031  *
1032  * Gets the stock icon name and size being displayed by the #GtkImage.
1033  * The storage type of the image must be %GTK_IMAGE_EMPTY or
1034  * %GTK_IMAGE_STOCK (see gtk_image_get_storage_type()).
1035  * The returned string is owned by the #GtkImage and should not
1036  * be freed.
1037  * 
1038  **/
1039 void
1040 gtk_image_get_stock  (GtkImage        *image,
1041                       gchar          **stock_id,
1042                       GtkIconSize     *size)
1043 {
1044   g_return_if_fail (GTK_IS_IMAGE (image));
1045   g_return_if_fail (image->storage_type == GTK_IMAGE_STOCK ||
1046                     image->storage_type == GTK_IMAGE_EMPTY);
1047
1048   if (image->storage_type == GTK_IMAGE_EMPTY)
1049     image->data.stock.stock_id = NULL;
1050   
1051   if (stock_id)
1052     *stock_id = image->data.stock.stock_id;
1053
1054   if (size)
1055     *size = image->icon_size;
1056 }
1057
1058 /**
1059  * gtk_image_get_icon_set:
1060  * @image: a #GtkImage
1061  * @icon_set: location to store a #GtkIconSet
1062  * @size: location to store a stock icon size
1063  *
1064  * Gets the icon set and size being displayed by the #GtkImage.
1065  * The storage type of the image must be %GTK_IMAGE_EMPTY or
1066  * %GTK_IMAGE_ICON_SET (see gtk_image_get_storage_type()).
1067  * 
1068  **/
1069 void
1070 gtk_image_get_icon_set  (GtkImage        *image,
1071                          GtkIconSet     **icon_set,
1072                          GtkIconSize     *size)
1073 {
1074   g_return_if_fail (GTK_IS_IMAGE (image));
1075   g_return_if_fail (image->storage_type == GTK_IMAGE_ICON_SET ||
1076                     image->storage_type == GTK_IMAGE_EMPTY);
1077       
1078   if (icon_set)    
1079     *icon_set = image->data.icon_set.icon_set;
1080
1081   if (size)
1082     *size = image->icon_size;
1083 }
1084
1085 /**
1086  * gtk_image_get_animation:
1087  * @image: a #GtkImage
1088  *
1089  *
1090  * Gets the #GdkPixbufAnimation being displayed by the #GtkImage.
1091  * The storage type of the image must be %GTK_IMAGE_EMPTY or
1092  * %GTK_IMAGE_ANIMATION (see gtk_image_get_storage_type()).
1093  * The caller of this function does not own a reference to the
1094  * returned animation.
1095  * 
1096  * Return value: the displayed animation, or %NULL if the image is empty
1097  **/
1098 GdkPixbufAnimation*
1099 gtk_image_get_animation (GtkImage *image)
1100 {
1101   g_return_val_if_fail (GTK_IS_IMAGE (image), NULL);
1102   g_return_val_if_fail (image->storage_type == GTK_IMAGE_ANIMATION ||
1103                         image->storage_type == GTK_IMAGE_EMPTY,
1104                         NULL);
1105
1106   if (image->storage_type == GTK_IMAGE_EMPTY)
1107     image->data.anim.anim = NULL;
1108   
1109   return image->data.anim.anim;
1110 }
1111
1112 /**
1113  * gtk_image_new:
1114  * 
1115  * Creates a new empty #GtkImage widget.
1116  * 
1117  * Return value: a newly created #GtkImage widget. 
1118  **/
1119 GtkWidget*
1120 gtk_image_new (void)
1121 {
1122   return g_object_new (GTK_TYPE_IMAGE, NULL);
1123 }
1124
1125 void
1126 gtk_image_set (GtkImage  *image,
1127                GdkImage  *val,
1128                GdkBitmap *mask)
1129 {
1130   g_return_if_fail (GTK_IS_IMAGE (image));
1131
1132   gtk_image_set_from_image (image, val, mask);
1133 }
1134
1135 void
1136 gtk_image_get (GtkImage   *image,
1137                GdkImage  **val,
1138                GdkBitmap **mask)
1139 {
1140   g_return_if_fail (GTK_IS_IMAGE (image));
1141
1142   gtk_image_get_image (image, val, mask);
1143 }
1144
1145 static void
1146 gtk_image_reset_anim_iter (GtkImage *image)
1147 {
1148   if (image->storage_type == GTK_IMAGE_ANIMATION)
1149     {
1150       /* Reset the animation */
1151       
1152       if (image->data.anim.frame_timeout)
1153         {
1154           g_source_remove (image->data.anim.frame_timeout);
1155           image->data.anim.frame_timeout = 0;
1156         }
1157
1158       if (image->data.anim.iter)
1159         {
1160           g_object_unref (image->data.anim.iter);
1161           image->data.anim.iter = NULL;
1162         }
1163     }
1164 }
1165
1166 static void
1167 gtk_image_unmap (GtkWidget *widget)
1168 {
1169   gtk_image_reset_anim_iter (GTK_IMAGE (widget));
1170
1171   if (GTK_WIDGET_CLASS (parent_class)->unmap)
1172     GTK_WIDGET_CLASS (parent_class)->unmap (widget);
1173 }
1174
1175 static void
1176 gtk_image_unrealize (GtkWidget *widget)
1177 {
1178   gtk_image_reset_anim_iter (GTK_IMAGE (widget));
1179
1180   if (GTK_WIDGET_CLASS (parent_class)->unrealize)
1181     GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
1182 }
1183
1184 static gint
1185 animation_timeout (gpointer data)
1186 {
1187   GtkImage *image;
1188
1189   GDK_THREADS_ENTER ();
1190
1191   image = GTK_IMAGE (data);
1192   
1193   image->data.anim.frame_timeout = 0;
1194
1195   gdk_pixbuf_animation_iter_advance (image->data.anim.iter, NULL);
1196
1197   if (gdk_pixbuf_animation_iter_get_delay_time (image->data.anim.iter) >= 0)
1198     image->data.anim.frame_timeout =
1199       g_timeout_add (gdk_pixbuf_animation_iter_get_delay_time (image->data.anim.iter),
1200                      animation_timeout,
1201                      image);
1202   
1203   gtk_widget_queue_draw (GTK_WIDGET (image));
1204
1205   GDK_THREADS_LEAVE ();
1206
1207   return FALSE;
1208 }
1209
1210 static gint
1211 gtk_image_expose (GtkWidget      *widget,
1212                   GdkEventExpose *event)
1213 {
1214   g_return_val_if_fail (GTK_IS_IMAGE (widget), FALSE);
1215   g_return_val_if_fail (event != NULL, FALSE);
1216   
1217   if (GTK_WIDGET_MAPPED (widget) &&
1218       GTK_IMAGE (widget)->storage_type != GTK_IMAGE_EMPTY)
1219     {
1220       GtkImage *image;
1221       GtkMisc *misc;
1222       GdkRectangle area, image_bound;
1223       gfloat xalign;
1224       gint x, y;
1225       GdkBitmap *mask;
1226       GdkPixbuf *pixbuf;
1227       gboolean needs_state_transform;
1228       
1229       image = GTK_IMAGE (widget);
1230       misc = GTK_MISC (widget);
1231
1232       area = event->area;
1233
1234       /* For stock items and icon sets, we lazily calculate
1235        * the size; we might get here between a queue_resize()
1236        * and size_request() if something explicitely forces
1237        * a redraw.
1238        */
1239       if (widget->requisition.width == 0 && widget->requisition.height == 0)
1240         gtk_image_calc_size (image);
1241       
1242       if (!gdk_rectangle_intersect (&area, &widget->allocation, &area))
1243         return FALSE;
1244
1245       if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
1246         xalign = misc->xalign;
1247       else
1248         xalign = 1.0 - misc->xalign;
1249   
1250       x = floor (widget->allocation.x + misc->xpad
1251                  + ((widget->allocation.width - widget->requisition.width) * xalign)
1252                  + 0.5);
1253       y = floor (widget->allocation.y + misc->ypad 
1254                  + ((widget->allocation.height - widget->requisition.height) * misc->yalign)
1255                  + 0.5);
1256       
1257       image_bound.x = x;
1258       image_bound.y = y;      
1259       image_bound.width = 0;
1260       image_bound.height = 0;      
1261
1262       mask = NULL;
1263       pixbuf = NULL;
1264       needs_state_transform = GTK_WIDGET_STATE (widget) != GTK_STATE_NORMAL;
1265       
1266       switch (image->storage_type)
1267         {
1268         case GTK_IMAGE_PIXMAP:
1269           mask = image->mask;
1270           gdk_drawable_get_size (image->data.pixmap.pixmap,
1271                                  &image_bound.width,
1272                                  &image_bound.height);
1273
1274           if (gdk_rectangle_intersect (&image_bound, &area, &image_bound) &&
1275               needs_state_transform)
1276             {
1277               pixbuf = gdk_pixbuf_get_from_drawable (NULL,
1278                                                      image->data.pixmap.pixmap,
1279                                                      gtk_widget_get_colormap (widget),
1280                                                      image_bound.x - x, image_bound.y - y,
1281                                                      0, 0,
1282                                                      image_bound.width,
1283                                                      image_bound.height);
1284
1285               x = image_bound.x;
1286               y = image_bound.y;
1287             }
1288           
1289           break;
1290
1291         case GTK_IMAGE_IMAGE:
1292           mask = image->mask;
1293           image_bound.width = image->data.image.image->width;
1294           image_bound.height = image->data.image.image->height;
1295
1296           if (gdk_rectangle_intersect (&image_bound, &area, &image_bound) &&
1297               needs_state_transform)
1298             {
1299               pixbuf = gdk_pixbuf_get_from_image (NULL,
1300                                                   image->data.image.image,
1301                                                   gtk_widget_get_colormap (widget),
1302                                                   image_bound.x - x, image_bound.y - y,
1303                                                   0, 0,
1304                                                   image_bound.width,
1305                                                   image_bound.height);
1306
1307               x = image_bound.x;
1308               y = image_bound.y;
1309             }
1310           break;
1311
1312         case GTK_IMAGE_PIXBUF:
1313           image_bound.width = gdk_pixbuf_get_width (image->data.pixbuf.pixbuf);
1314           image_bound.height = gdk_pixbuf_get_height (image->data.pixbuf.pixbuf);          
1315
1316           if (gdk_rectangle_intersect (&image_bound, &area, &image_bound) &&
1317               needs_state_transform)
1318             {
1319               pixbuf = gdk_pixbuf_new_subpixbuf (image->data.pixbuf.pixbuf,
1320                                                  image_bound.x - x, image_bound.y - y,
1321                                                  image_bound.width, image_bound.height);
1322
1323               x = image_bound.x;
1324               y = image_bound.y;
1325             }
1326           else
1327             {
1328               pixbuf = image->data.pixbuf.pixbuf;
1329               g_object_ref (pixbuf);
1330             }
1331           break;
1332
1333         case GTK_IMAGE_STOCK:
1334           pixbuf = gtk_widget_render_icon (widget,
1335                                            image->data.stock.stock_id,
1336                                            image->icon_size,
1337                                            NULL);
1338           if (pixbuf)
1339             {              
1340               image_bound.width = gdk_pixbuf_get_width (pixbuf);
1341               image_bound.height = gdk_pixbuf_get_height (pixbuf);
1342             }
1343
1344           /* already done */
1345           needs_state_transform = FALSE;
1346           break;
1347
1348         case GTK_IMAGE_ICON_SET:
1349           pixbuf =
1350             gtk_icon_set_render_icon (image->data.icon_set.icon_set,
1351                                       widget->style,
1352                                       gtk_widget_get_direction (widget),
1353                                       GTK_WIDGET_STATE (widget),
1354                                       image->icon_size,
1355                                       widget,
1356                                       NULL);
1357
1358           if (pixbuf)
1359             {
1360               image_bound.width = gdk_pixbuf_get_width (pixbuf);
1361               image_bound.height = gdk_pixbuf_get_height (pixbuf);
1362             }
1363
1364           /* already done */
1365           needs_state_transform = FALSE;
1366           break;
1367
1368         case GTK_IMAGE_ANIMATION:
1369           {
1370             if (image->data.anim.iter == NULL)
1371               {
1372                 image->data.anim.iter = gdk_pixbuf_animation_get_iter (image->data.anim.anim, NULL);
1373                 
1374                 if (gdk_pixbuf_animation_iter_get_delay_time (image->data.anim.iter) >= 0)
1375                   image->data.anim.frame_timeout =
1376                     g_timeout_add (gdk_pixbuf_animation_iter_get_delay_time (image->data.anim.iter),
1377                                    animation_timeout,
1378                                    image);
1379               }
1380
1381             image_bound.width = gdk_pixbuf_animation_get_width (image->data.anim.anim);
1382             image_bound.height = gdk_pixbuf_animation_get_height (image->data.anim.anim);
1383                   
1384             /* don't advance the anim iter here, or we could get frame changes between two
1385              * exposes of different areas.
1386              */
1387             
1388             pixbuf = gdk_pixbuf_animation_iter_get_pixbuf (image->data.anim.iter);
1389             g_object_ref (pixbuf);
1390           }
1391           break;
1392
1393         case GTK_IMAGE_EMPTY:
1394           g_assert_not_reached ();
1395           break;
1396         }
1397
1398       if (mask)
1399         {
1400           gdk_gc_set_clip_mask (widget->style->black_gc, mask);
1401           gdk_gc_set_clip_origin (widget->style->black_gc, x, y);
1402         }
1403
1404       if (gdk_rectangle_intersect (&image_bound, &area, &image_bound))
1405         {
1406           if (pixbuf)
1407             {
1408               if (needs_state_transform)
1409                 {
1410                   GtkIconSource *source;
1411                   GdkPixbuf *rendered;
1412
1413                   source = gtk_icon_source_new ();
1414                   gtk_icon_source_set_pixbuf (source, pixbuf);
1415                   /* The size here is arbitrary; since size isn't
1416                    * wildcarded in the souce, it isn't supposed to be
1417                    * scaled by the engine function
1418                    */
1419                   gtk_icon_source_set_size (source,
1420                                             GTK_ICON_SIZE_SMALL_TOOLBAR);
1421                   gtk_icon_source_set_size_wildcarded (source, FALSE);
1422                   
1423                   rendered = gtk_style_render_icon (widget->style,
1424                                                     source,
1425                                                     gtk_widget_get_direction (widget),
1426                                                     GTK_WIDGET_STATE (widget),
1427                                                     /* arbitrary */
1428                                                     (GtkIconSize)-1,
1429                                                     widget,
1430                                                     "gtk-image");
1431
1432                   gtk_icon_source_free (source);
1433
1434                   g_object_unref (pixbuf);
1435                   pixbuf = rendered;
1436                 }
1437
1438               if (pixbuf)
1439                 {
1440                   gdk_draw_pixbuf (widget->window,
1441                                    widget->style->black_gc,
1442                                    pixbuf,
1443                                    image_bound.x - x,
1444                                    image_bound.y - y,
1445                                    image_bound.x,
1446                                    image_bound.y,
1447                                    image_bound.width,
1448                                    image_bound.height,
1449                                    GDK_RGB_DITHER_NORMAL,
1450                                    0, 0);
1451
1452                   g_object_unref (pixbuf);
1453                   pixbuf = NULL;
1454                 }
1455             }
1456           else
1457             {
1458               switch (image->storage_type)
1459                 {
1460                 case GTK_IMAGE_PIXMAP:
1461                   gdk_draw_drawable (widget->window,
1462                                      widget->style->black_gc,
1463                                      image->data.pixmap.pixmap,
1464                                      image_bound.x - x, image_bound.y - y,
1465                                      image_bound.x, image_bound.y,
1466                                      image_bound.width, image_bound.height);
1467                   break;
1468               
1469                 case GTK_IMAGE_IMAGE:
1470                   gdk_draw_image (widget->window,
1471                                   widget->style->black_gc,
1472                                   image->data.image.image,
1473                                   image_bound.x - x, image_bound.y - y,
1474                                   image_bound.x, image_bound.y,
1475                                   image_bound.width, image_bound.height);
1476                   break;
1477
1478                 case GTK_IMAGE_PIXBUF:
1479                 case GTK_IMAGE_STOCK:
1480                 case GTK_IMAGE_ICON_SET:
1481                 case GTK_IMAGE_ANIMATION:
1482                 case GTK_IMAGE_EMPTY:
1483                   g_assert_not_reached ();
1484                   break;
1485                 }
1486             }
1487         } /* if rectangle intersects */      
1488
1489       if (mask)
1490         {
1491           gdk_gc_set_clip_mask (widget->style->black_gc, NULL);
1492           gdk_gc_set_clip_origin (widget->style->black_gc, 0, 0);
1493         }
1494       
1495     } /* if widget is drawable */
1496
1497   return FALSE;
1498 }
1499
1500 static void
1501 gtk_image_clear (GtkImage *image)
1502 {
1503   g_object_freeze_notify (G_OBJECT (image));
1504   
1505   if (image->storage_type != GTK_IMAGE_EMPTY)
1506     g_object_notify (G_OBJECT (image), "storage_type");
1507
1508   if (image->mask)
1509     {
1510       g_object_unref (image->mask);
1511       image->mask = NULL;
1512       g_object_notify (G_OBJECT (image), "mask");
1513     }
1514
1515   if (image->icon_size != DEFAULT_ICON_SIZE)
1516     {
1517       image->icon_size = DEFAULT_ICON_SIZE;
1518       g_object_notify (G_OBJECT (image), "icon_size");
1519     }
1520   
1521   switch (image->storage_type)
1522     {
1523     case GTK_IMAGE_PIXMAP:
1524
1525       if (image->data.pixmap.pixmap)
1526         g_object_unref (image->data.pixmap.pixmap);
1527       image->data.pixmap.pixmap = NULL;
1528       
1529       g_object_notify (G_OBJECT (image), "pixmap");
1530       
1531       break;
1532
1533     case GTK_IMAGE_IMAGE:
1534
1535       if (image->data.image.image)
1536         g_object_unref (image->data.image.image);
1537       image->data.image.image = NULL;
1538       
1539       g_object_notify (G_OBJECT (image), "image");
1540       
1541       break;
1542
1543     case GTK_IMAGE_PIXBUF:
1544
1545       if (image->data.pixbuf.pixbuf)
1546         g_object_unref (image->data.pixbuf.pixbuf);
1547
1548       g_object_notify (G_OBJECT (image), "pixbuf");
1549       
1550       break;
1551
1552     case GTK_IMAGE_STOCK:
1553
1554       g_free (image->data.stock.stock_id);
1555
1556       image->data.stock.stock_id = NULL;
1557       
1558       g_object_notify (G_OBJECT (image), "stock");      
1559       break;
1560
1561     case GTK_IMAGE_ICON_SET:
1562       if (image->data.icon_set.icon_set)
1563         gtk_icon_set_unref (image->data.icon_set.icon_set);
1564       image->data.icon_set.icon_set = NULL;
1565       
1566       g_object_notify (G_OBJECT (image), "icon_set");      
1567       break;
1568
1569     case GTK_IMAGE_ANIMATION:
1570       if (image->data.anim.frame_timeout)
1571         g_source_remove (image->data.anim.frame_timeout);
1572       
1573       if (image->data.anim.anim)
1574         g_object_unref (image->data.anim.anim);
1575
1576       image->data.anim.frame_timeout = 0;
1577       image->data.anim.anim = NULL;
1578       
1579       g_object_notify (G_OBJECT (image), "pixbuf_animation");
1580       
1581       break;
1582       
1583     case GTK_IMAGE_EMPTY:
1584     default:
1585       break;
1586       
1587     }
1588
1589   image->storage_type = GTK_IMAGE_EMPTY;
1590
1591   memset (&image->data, '\0', sizeof (image->data));
1592
1593   g_object_thaw_notify (G_OBJECT (image));
1594 }
1595
1596 static void
1597 gtk_image_reset (GtkImage *image)
1598 {
1599   gtk_image_clear (image);
1600
1601   gtk_image_update_size (image, 0, 0);
1602 }
1603
1604 static void
1605 gtk_image_calc_size (GtkImage *image)
1606 {
1607   GtkWidget *widget = GTK_WIDGET (image);
1608   GdkPixbuf *pixbuf = NULL;
1609   
1610   /* We update stock/icon set on every size request, because
1611    * the theme could have affected the size; for other kinds of
1612    * image, we just update the requisition when the image data
1613    * is set.
1614    */
1615   switch (image->storage_type)
1616     {
1617     case GTK_IMAGE_STOCK:
1618       pixbuf = gtk_widget_render_icon (widget,
1619                                        image->data.stock.stock_id,
1620                                        image->icon_size,
1621                                        NULL);
1622       break;
1623       
1624     case GTK_IMAGE_ICON_SET:
1625       pixbuf = gtk_icon_set_render_icon (image->data.icon_set.icon_set,
1626                                          widget->style,
1627                                          gtk_widget_get_direction (widget),
1628                                          GTK_WIDGET_STATE (widget),
1629                                          image->icon_size,
1630                                          widget,
1631                                          NULL);
1632       break;
1633       
1634     default:
1635       break;
1636     }
1637
1638   if (pixbuf)
1639     {
1640       widget->requisition.width = gdk_pixbuf_get_width (pixbuf) + GTK_MISC (image)->xpad * 2;
1641       widget->requisition.height = gdk_pixbuf_get_height (pixbuf) + GTK_MISC (image)->ypad * 2;
1642
1643       g_object_unref (pixbuf);
1644     }
1645 }
1646
1647 static void
1648 gtk_image_size_request (GtkWidget      *widget,
1649                         GtkRequisition *requisition)
1650 {
1651   GtkImage *image;
1652   
1653   image = GTK_IMAGE (widget);
1654
1655   gtk_image_calc_size (image);
1656
1657   /* Chain up to default that simply reads current requisition */
1658   GTK_WIDGET_CLASS (parent_class)->size_request (widget, requisition);
1659 }
1660
1661 static void
1662 gtk_image_update_size (GtkImage *image,
1663                        gint      image_width,
1664                        gint      image_height)
1665 {
1666   GTK_WIDGET (image)->requisition.width = image_width + GTK_MISC (image)->xpad * 2;
1667   GTK_WIDGET (image)->requisition.height = image_height + GTK_MISC (image)->ypad * 2;
1668
1669   if (GTK_WIDGET_VISIBLE (image))
1670     gtk_widget_queue_resize (GTK_WIDGET (image));
1671 }