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