]> Pileus Git - ~andy/gtk/blob - gtk/gtkimage.c
Allow NULL filenames.
[~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 <math.h>
28 #include "gtkcontainer.h"
29 #include "gtkimage.h"
30 #include "gtkiconfactory.h"
31 #include "gtkstock.h"
32 #include "gtkintl.h"
33 #include <string.h>
34
35 #define DEFAULT_ICON_SIZE GTK_ICON_SIZE_BUTTON
36
37 static void gtk_image_class_init   (GtkImageClass  *klass);
38 static void gtk_image_init         (GtkImage       *image);
39 static gint gtk_image_expose       (GtkWidget      *widget,
40                                     GdkEventExpose *event);
41 static void gtk_image_unmap        (GtkWidget      *widget);
42 static void gtk_image_size_request (GtkWidget      *widget,
43                                     GtkRequisition *requisition);
44 static void gtk_image_destroy      (GtkObject      *object);
45 static void gtk_image_clear        (GtkImage       *image);
46 static void gtk_image_reset        (GtkImage       *image);
47 static void gtk_image_update_size  (GtkImage       *image,
48                                     gint            image_width,
49                                     gint            image_height);
50
51 static void gtk_image_set_property      (GObject          *object,
52                                          guint             prop_id,
53                                          const GValue     *value,
54                                          GParamSpec       *pspec);
55 static void gtk_image_get_property      (GObject          *object,
56                                          guint             prop_id,
57                                          GValue           *value,
58                                          GParamSpec       *pspec);
59
60 static gpointer parent_class;
61
62 enum
63 {
64   PROP_0,
65   PROP_PIXBUF,
66   PROP_PIXMAP,
67   PROP_IMAGE,
68   PROP_MASK,
69   PROP_FILE,
70   PROP_STOCK,
71   PROP_ICON_SET,
72   PROP_ICON_SIZE,
73   PROP_PIXBUF_ANIMATION,
74   PROP_STORAGE_TYPE
75 };
76
77 GtkType
78 gtk_image_get_type (void)
79 {
80   static GtkType image_type = 0;
81
82   if (!image_type)
83     {
84       static const GtkTypeInfo image_info =
85       {
86         "GtkImage",
87         sizeof (GtkImage),
88         sizeof (GtkImageClass),
89         (GtkClassInitFunc) gtk_image_class_init,
90         (GtkObjectInitFunc) gtk_image_init,
91         /* reserved_1 */ NULL,
92         /* reserved_2 */ NULL,
93         (GtkClassInitFunc) NULL,
94       };
95
96       image_type = gtk_type_unique (GTK_TYPE_MISC, &image_info);
97     }
98
99   return image_type;
100 }
101
102 static void
103 gtk_image_class_init (GtkImageClass *class)
104 {
105   GObjectClass *gobject_class;
106   GtkObjectClass *object_class;
107   GtkWidgetClass *widget_class;
108
109   parent_class = g_type_class_peek_parent (class);
110
111   gobject_class = G_OBJECT_CLASS (class);
112   
113   gobject_class->set_property = gtk_image_set_property;
114   gobject_class->get_property = gtk_image_get_property;
115   
116   object_class = GTK_OBJECT_CLASS (class);
117   
118   object_class->destroy = gtk_image_destroy;
119
120   widget_class = GTK_WIDGET_CLASS (class);
121   
122   widget_class->expose_event = gtk_image_expose;
123   widget_class->size_request = gtk_image_size_request;
124   widget_class->unmap = gtk_image_unmap;
125   
126   g_object_class_install_property (gobject_class,
127                                    PROP_PIXBUF,
128                                    g_param_spec_object ("pixbuf",
129                                                         _("Pixbuf"),
130                                                         _("A GdkPixbuf to display."),
131                                                         GDK_TYPE_PIXBUF,
132                                                         G_PARAM_READWRITE));
133
134   g_object_class_install_property (gobject_class,
135                                    PROP_PIXMAP,
136                                    g_param_spec_object ("pixmap",
137                                                         _("Pixmap"),
138                                                         _("A GdkPixmap to display."),
139                                                         GDK_TYPE_PIXMAP,
140                                                         G_PARAM_READWRITE));
141
142   g_object_class_install_property (gobject_class,
143                                    PROP_IMAGE,
144                                    g_param_spec_object ("image",
145                                                         _("Image"),
146                                                         _("A GdkImage to display."),
147                                                         GDK_TYPE_IMAGE,
148                                                         G_PARAM_READWRITE));
149
150   g_object_class_install_property (gobject_class,
151                                    PROP_MASK,
152                                    g_param_spec_object ("mask",
153                                                         _("Mask"),
154                                                         _("Mask bitmap to use with GdkImage or GdkPixmap"),
155                                                         GDK_TYPE_PIXMAP,
156                                                         G_PARAM_READWRITE));
157   
158   g_object_class_install_property (gobject_class,
159                                    PROP_FILE,
160                                    g_param_spec_string ("file",
161                                                         _("Filename"),
162                                                         _("Filename to load and display."),
163                                                         NULL,
164                                                         G_PARAM_WRITABLE));
165   
166
167   g_object_class_install_property (gobject_class,
168                                    PROP_STOCK,
169                                    g_param_spec_string ("stock",
170                                                         _("Stock ID"),
171                                                         _("Stock ID for a stock image to display."),
172                                                         NULL,
173                                                         G_PARAM_READWRITE));
174   
175   g_object_class_install_property (gobject_class,
176                                    PROP_ICON_SET,
177                                    g_param_spec_boxed ("icon_set",
178                                                        _("Icon set"),
179                                                        _("Icon set to display."),
180                                                        GTK_TYPE_ICON_SET,
181                                                        G_PARAM_READWRITE));
182   
183   g_object_class_install_property (gobject_class,
184                                    PROP_ICON_SIZE,
185                                    g_param_spec_int ("icon_size",
186                                                      _("Icon size"),
187                                                      _("Size to use for stock icon or icon set."),
188                                                      0, G_MAXINT,
189                                                      DEFAULT_ICON_SIZE,
190                                                      G_PARAM_READWRITE));
191
192   g_object_class_install_property (gobject_class,
193                                    PROP_PIXBUF_ANIMATION,
194                                    g_param_spec_object ("pixbuf_animation",
195                                                         _("Animation"),
196                                                         _("GdkPixbufAnimation to display."),
197                                                         GDK_TYPE_PIXBUF_ANIMATION,
198                                                         G_PARAM_READWRITE));
199   
200   g_object_class_install_property (gobject_class,
201                                    PROP_STORAGE_TYPE,
202                                    g_param_spec_enum ("storage_type",
203                                                       _("Storage type"),
204                                                       _("The representation being used for image data."),
205                                                       GTK_TYPE_IMAGE_TYPE,
206                                                       GTK_IMAGE_EMPTY,
207                                                       G_PARAM_READABLE));
208 }
209
210 static void
211 gtk_image_init (GtkImage *image)
212 {
213   GTK_WIDGET_SET_FLAGS (image, GTK_NO_WINDOW);
214
215   image->storage_type = GTK_IMAGE_EMPTY;
216   image->icon_size = DEFAULT_ICON_SIZE;
217   image->mask = NULL;
218 }
219
220 static void
221 gtk_image_destroy (GtkObject *object)
222 {
223   GtkImage *image = GTK_IMAGE (object);
224
225   gtk_image_clear (image);
226   
227   GTK_OBJECT_CLASS (parent_class)->destroy (object);
228 }
229
230 static void 
231 gtk_image_set_property (GObject      *object,
232                         guint         prop_id,
233                         const GValue *value,
234                         GParamSpec   *pspec)
235 {
236   GtkImage *image;
237
238   image = GTK_IMAGE (object);
239   
240   switch (prop_id)
241     {
242     case PROP_PIXBUF:
243       gtk_image_set_from_pixbuf (image,
244                                  g_value_get_object (value));
245       break;
246     case PROP_PIXMAP:
247       gtk_image_set_from_pixmap (image,
248                                  g_value_get_object (value),
249                                  image->mask);
250       break;
251     case PROP_IMAGE:
252       gtk_image_set_from_image (image,
253                                 g_value_get_object (value),
254                                 image->mask);
255       break;
256     case PROP_MASK:
257       if (image->storage_type == GTK_IMAGE_PIXMAP)
258         gtk_image_set_from_pixmap (image,
259                                    image->data.pixmap.pixmap,
260                                    g_value_get_object (value));
261       else if (image->storage_type == GTK_IMAGE_IMAGE)
262         gtk_image_set_from_image (image,
263                                   image->data.image.image,
264                                   g_value_get_object (value));
265       else
266         {
267           GdkBitmap *mask;
268
269           mask = g_value_get_object (value);
270
271           if (mask)
272             g_object_ref (G_OBJECT (mask));
273           
274           gtk_image_reset (image);
275
276           image->mask = mask;
277         }
278       break;
279     case PROP_FILE:
280       gtk_image_set_from_file (image,
281                                g_value_get_string (value));
282       break;
283     case PROP_STOCK:
284       gtk_image_set_from_stock (image, g_value_get_string (value),
285                                 image->icon_size);
286       break;
287     case PROP_ICON_SET:
288       gtk_image_set_from_icon_set (image, g_value_get_boxed (value),
289                                    image->icon_size);
290       break;
291     case PROP_ICON_SIZE:
292       if (image->storage_type == GTK_IMAGE_STOCK)
293         gtk_image_set_from_stock (image,
294                                   image->data.stock.stock_id,
295                                   g_value_get_int (value));
296       else if (image->storage_type == GTK_IMAGE_ICON_SET)
297         gtk_image_set_from_icon_set (image,
298                                      image->data.icon_set.icon_set,
299                                      g_value_get_int (value));
300       else
301         /* Save to be used when STOCK or ICON_SET property comes in */
302         image->icon_size = g_value_get_int (value);
303       break;
304     case PROP_PIXBUF_ANIMATION:
305       gtk_image_set_from_animation (image,
306                                     g_value_get_object (value));
307       break;
308       
309     default:
310       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
311       break;
312     }
313 }
314
315 static void 
316 gtk_image_get_property (GObject     *object,
317                         guint        prop_id,
318                         GValue      *value,
319                         GParamSpec  *pspec)
320 {
321   GtkImage *image;
322
323   image = GTK_IMAGE (object);
324
325   /* The "getter" functions whine if you try to get the wrong
326    * storage type. This function is instead robust against that,
327    * so that GUI builders don't have to jump through hoops
328    * to avoid g_warning
329    */
330   
331   switch (prop_id)
332     {
333     case PROP_PIXBUF:
334       if (image->storage_type != GTK_IMAGE_PIXBUF)
335         g_value_set_object (value, NULL);
336       else
337         g_value_set_object (value,
338                             gtk_image_get_pixbuf (image));
339       break;
340     case PROP_PIXMAP:
341       if (image->storage_type != GTK_IMAGE_PIXMAP)
342         g_value_set_object (value, NULL);
343       else
344         g_value_set_object (value,
345                             image->data.pixmap.pixmap);
346       break;
347     case PROP_MASK:
348       g_value_set_object (value, image->mask);
349       break;
350     case PROP_IMAGE:
351       if (image->storage_type != GTK_IMAGE_IMAGE)
352         g_value_set_object (value, NULL);
353       else
354         g_value_set_object (value,
355                             image->data.image.image);
356       break;
357     case PROP_STOCK:
358       if (image->storage_type != GTK_IMAGE_STOCK)
359         g_value_set_string (value, NULL);
360       else
361         g_value_set_string (value,
362                             image->data.stock.stock_id);
363       break;
364     case PROP_ICON_SET:
365       if (image->storage_type != GTK_IMAGE_ICON_SET)
366         g_value_set_boxed (value, NULL);
367       else
368         g_value_set_boxed (value,
369                            image->data.icon_set.icon_set);
370       break;      
371     case PROP_ICON_SIZE:
372       g_value_set_int (value, image->icon_size);
373       break;
374     case PROP_PIXBUF_ANIMATION:
375       if (image->storage_type != GTK_IMAGE_ANIMATION)
376         g_value_set_object (value, NULL);
377       else
378         g_value_set_object (value,
379                             image->data.anim.anim);
380       break;
381     case PROP_STORAGE_TYPE:
382       g_value_set_enum (value, image->storage_type);
383       break;
384       
385     default:
386       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
387       break;
388     }
389 }
390
391
392 /**
393  * gtk_image_new_from_pixmap:
394  * @pixmap: a #GdkPixmap, or %NULL
395  * @mask: a #GdkBitmap, or %NULL
396  * 
397  * Creates a #GtkImage widget displaying @pixmap with a @mask.
398  * A #GdkImage is a server-side image buffer in the pixel format of the
399  * current display. The #GtkImage does not assume a reference to the
400  * pixmap or mask; you still need to unref them if you own references.
401  * #GtkImage will add its own reference rather than adopting yours.
402  * 
403  * Return value: a new #GtkImage
404  **/
405 GtkWidget*
406 gtk_image_new_from_pixmap (GdkPixmap *pixmap,
407                            GdkBitmap *mask)
408 {
409   GtkImage *image;
410
411   image = gtk_type_new (GTK_TYPE_IMAGE);
412
413   gtk_image_set_from_pixmap (image, pixmap, mask);
414
415   return GTK_WIDGET (image);
416 }
417
418 /**
419  * gtk_image_new_from_image:
420  * @image: a #GdkImage, or %NULL
421  * @mask: a #GdkBitmap, or %NULL 
422  * 
423  * Creates a #GtkImage widget displaying a @image with a @mask.
424  * A #GdkImage is a client-side image buffer in the pixel format of the
425  * current display.
426  * The #GtkImage does not assume a reference to the
427  * image or mask; you still need to unref them if you own references.
428  * #GtkImage will add its own reference rather than adopting yours.
429  * 
430  * Return value: a new #GtkImage
431  **/
432 GtkWidget*
433 gtk_image_new_from_image  (GdkImage  *gdk_image,
434                            GdkBitmap *mask)
435 {
436   GtkImage *image;
437
438   image = gtk_type_new (GTK_TYPE_IMAGE);
439
440   gtk_image_set_from_image (image, gdk_image, mask);
441
442   return GTK_WIDGET (image);
443 }
444
445 /**
446  * gtk_image_new_from_file:
447  * @filename: a filename
448  * 
449  * Creates a new #GtkImage displaying the file @filename. If the file
450  * isn't found or can't be loaded, the resulting #GtkImage will
451  * display a "broken image" icon. This function never returns %NULL,
452  * it always returns a valid #GtkImage widget.
453  *
454  * If the file contains an animation, the image will contain an
455  * animation.
456  *
457  * If you need to detect failures to load the file, use
458  * gdk_pixbuf_new_from_file() to load the file yourself, then create
459  * the #GtkImage from the pixbuf. (Or for animations, use
460  * gdk_pixbuf_animation_new_from_file()).
461  *
462  * The storage type (gtk_image_get_storage_type()) of the returned
463  * image is not defined, it will be whatever is appropriate for
464  * displaying the file.
465  * 
466  * Return value: a new #GtkImage
467  **/
468 GtkWidget*
469 gtk_image_new_from_file   (const gchar *filename)
470 {
471   GtkImage *image;
472
473   image = gtk_type_new (GTK_TYPE_IMAGE);
474
475   gtk_image_set_from_file (image, filename);
476
477   return GTK_WIDGET (image);
478 }
479
480 /**
481  * gtk_image_new_from_pixbuf:
482  * @pixbuf: a #GdkPixbuf, or %NULL
483  * 
484  * Creates a new #GtkImage displaying @pixbuf.
485  * The #GtkImage does not assume a reference to the
486  * pixbuf; you still need to unref it if you own references.
487  * #GtkImage will add its own reference rather than adopting yours.
488  * 
489  * Note that this function just creates an #GtkImage from the pixbuf.  The
490  * #GtkImage created will not react to state changes.  Should you want that, you
491  * should use gtk_image_new_from_icon_set().
492  * 
493  * Return value: a new #GtkImage
494  **/
495 GtkWidget*
496 gtk_image_new_from_pixbuf (GdkPixbuf *pixbuf)
497 {
498   GtkImage *image;
499
500   image = gtk_type_new (GTK_TYPE_IMAGE);
501
502   gtk_image_set_from_pixbuf (image, pixbuf);
503
504   return GTK_WIDGET (image);  
505 }
506
507 /**
508  * gtk_image_new_from_stock:
509  * @stock_id: a stock icon name
510  * @size: a stock icon size
511  * 
512  * Creates a #GtkImage displaying a stock icon. Sample stock icon
513  * names are #GTK_STOCK_OPEN, #GTK_STOCK_EXIT. Sample stock sizes
514  * are #GTK_ICON_SIZE_MENU, #GTK_ICON_SIZE_SMALL_TOOLBAR. If the stock
515  * icon name isn't known, a "broken image" icon will be displayed instead.
516  * You can register your own stock icon names, see
517  * gtk_icon_factory_add_default() and gtk_icon_factory_add().
518  * 
519  * Return value: a new #GtkImage displaying the stock icon
520  **/
521 GtkWidget*
522 gtk_image_new_from_stock (const gchar    *stock_id,
523                           GtkIconSize     size)
524 {
525   GtkImage *image;
526
527   image = gtk_type_new (GTK_TYPE_IMAGE);
528
529   gtk_image_set_from_stock (image, stock_id, size);
530
531   return GTK_WIDGET (image);
532 }
533
534 /**
535  * gtk_image_new_from_icon_set:
536  * @icon_set: a #GtkIconSet
537  * @size: a stock icon size
538  *
539  * Creates a #GtkImage displaying an icon set. Sample stock sizes are
540  * #GTK_ICON_SIZE_MENU, #GTK_ICON_SIZE_SMALL_TOOLBAR. Instead of using
541  * this function, usually it's better to create a #GtkIconFactory, put
542  * your icon sets in the icon factory, add the icon factory to the
543  * list of default factories with gtk_icon_factory_add_default(), and
544  * then use gtk_image_new_from_stock(). This will allow themes to
545  * override the icon you ship with your application.
546  *
547  * The #GtkImage does not assume a reference to the
548  * icon set; you still need to unref it if you own references.
549  * #GtkImage will add its own reference rather than adopting yours.
550  * 
551  * 
552  * Return value: a new #GtkImage
553  **/
554 GtkWidget*
555 gtk_image_new_from_icon_set (GtkIconSet     *icon_set,
556                              GtkIconSize     size)
557 {
558   GtkImage *image;
559
560   image = gtk_type_new (GTK_TYPE_IMAGE);
561
562   gtk_image_set_from_icon_set (image, icon_set, size);
563
564   return GTK_WIDGET (image);
565 }
566
567 /**
568  * gtk_image_new_from_animation:
569  * @animation: an animation
570  * 
571  * Creates a #GtkImage displaying the given animation.
572  * The #GtkImage does not assume a reference to the
573  * animation; you still need to unref it if you own references.
574  * #GtkImage will add its own reference rather than adopting yours.
575  * 
576  * Return value: a new #GtkImage widget
577  **/
578 GtkWidget*
579 gtk_image_new_from_animation (GdkPixbufAnimation *animation)
580 {
581   GtkImage *image;
582
583   g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), NULL);
584   
585   image = gtk_type_new (GTK_TYPE_IMAGE);
586
587   gtk_image_set_from_animation (image, animation);
588
589   return GTK_WIDGET (image);
590 }
591
592 /**
593  * gtk_image_set_from_pixmap:
594  * @image: a #GtkImage
595  * @pixmap: a #GdkPixmap or %NULL
596  * @mask: a #GdkBitmap or %NULL
597  *
598  * See gtk_image_new_from_pixmap() for details.
599  * 
600  **/
601 void
602 gtk_image_set_from_pixmap (GtkImage  *image,
603                            GdkPixmap *pixmap,
604                            GdkBitmap *mask)
605 {
606   g_return_if_fail (GTK_IS_IMAGE (image));
607   g_return_if_fail (pixmap == NULL ||
608                     GDK_IS_PIXMAP (pixmap));
609   g_return_if_fail (mask == NULL ||
610                     GDK_IS_PIXMAP (mask));
611
612   g_object_freeze_notify (G_OBJECT (image));
613   
614   if (pixmap)
615     g_object_ref (G_OBJECT (pixmap));
616
617   if (mask)
618     g_object_ref (G_OBJECT (mask));
619
620   gtk_image_reset (image);
621
622   image->mask = mask;
623   
624   if (pixmap)
625     {
626       int width;
627       int height;
628       
629       image->storage_type = GTK_IMAGE_PIXMAP;
630
631       image->data.pixmap.pixmap = pixmap;
632
633       gdk_drawable_get_size (GDK_DRAWABLE (pixmap), &width, &height);
634
635       gtk_image_update_size (image, width, height);
636     }
637
638   g_object_notify (G_OBJECT (image), "pixmap");
639   g_object_notify (G_OBJECT (image), "mask");
640   
641   g_object_thaw_notify (G_OBJECT (image));
642 }
643
644 /**
645  * gtk_image_set_from_image:
646  * @image: a #GtkImage
647  * @gdk_image: a #GdkImage or %NULL
648  * @mask: a #GdkBitmap or %NULL
649  *
650  * See gtk_image_new_from_image() for details.
651  * 
652  **/
653 void
654 gtk_image_set_from_image  (GtkImage  *image,
655                            GdkImage  *gdk_image,
656                            GdkBitmap *mask)
657 {
658   g_return_if_fail (GTK_IS_IMAGE (image));
659   g_return_if_fail (gdk_image == NULL ||
660                     GDK_IS_IMAGE (gdk_image));
661   g_return_if_fail (mask == NULL ||
662                     GDK_IS_PIXMAP (mask));
663
664   g_object_freeze_notify (G_OBJECT (image));
665   
666   if (gdk_image)
667     g_object_ref (G_OBJECT (gdk_image));
668
669   if (mask)
670     g_object_ref (G_OBJECT (mask));
671
672   gtk_image_reset (image);
673
674   if (gdk_image)
675     {
676       image->storage_type = GTK_IMAGE_IMAGE;
677
678       image->data.image.image = gdk_image;
679       image->mask = mask;
680
681       gtk_image_update_size (image, gdk_image->width, gdk_image->height);
682     }
683   else
684     {
685       /* Clean up the mask if gdk_image was NULL */
686       if (mask)
687         g_object_unref (G_OBJECT (mask));
688     }
689
690   g_object_notify (G_OBJECT (image), "image");
691   g_object_notify (G_OBJECT (image), "mask");
692   
693   g_object_thaw_notify (G_OBJECT (image));
694 }
695
696 /**
697  * gtk_image_set_from_file:
698  * @image: a #GtkImage
699  * @filename: a filename or %NULL
700  *
701  * See gtk_image_new_from_file() for details.
702  * 
703  **/
704 void
705 gtk_image_set_from_file   (GtkImage    *image,
706                            const gchar *filename)
707 {
708   GdkPixbufAnimation *anim;
709   
710   g_return_if_fail (GTK_IS_IMAGE (image));
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 static 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_MAPPED (widget) &&
1200       GTK_IMAGE (widget)->storage_type != GTK_IMAGE_EMPTY)
1201     {
1202       GtkImage *image;
1203       GtkMisc *misc;
1204       GdkRectangle area, image_bound;
1205       gfloat xalign;
1206       gint x, y;
1207       GdkBitmap *mask;
1208       GdkPixbuf *pixbuf;
1209       gboolean needs_state_transform;
1210       
1211       image = GTK_IMAGE (widget);
1212       misc = GTK_MISC (widget);
1213
1214       area = event->area;
1215       
1216       if (!gdk_rectangle_intersect (&area, &widget->allocation, &area))
1217         return FALSE;
1218
1219       if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
1220         xalign = misc->xalign;
1221       else
1222         xalign = 1.0 - misc->xalign;
1223   
1224       x = floor (widget->allocation.x + misc->xpad
1225                  + ((widget->allocation.width - widget->requisition.width) * xalign)
1226                  + 0.5);
1227       y = floor (widget->allocation.y + misc->ypad 
1228                  + ((widget->allocation.height - widget->requisition.height) * misc->yalign)
1229                  + 0.5);
1230       
1231       image_bound.x = x;
1232       image_bound.y = y;      
1233       image_bound.width = 0;
1234       image_bound.height = 0;      
1235
1236       mask = NULL;
1237       pixbuf = NULL;
1238       needs_state_transform = GTK_WIDGET_STATE (widget) != GTK_STATE_NORMAL;
1239       
1240       switch (image->storage_type)
1241         {
1242         case GTK_IMAGE_PIXMAP:
1243           mask = image->mask;
1244           gdk_drawable_get_size (image->data.pixmap.pixmap,
1245                                  &image_bound.width,
1246                                  &image_bound.height);
1247
1248           if (gdk_rectangle_intersect (&image_bound, &area, &image_bound) &&
1249               needs_state_transform)
1250             {
1251               pixbuf = gdk_pixbuf_get_from_drawable (NULL,
1252                                                      image->data.pixmap.pixmap,
1253                                                      gtk_widget_get_colormap (widget),
1254                                                      image_bound.x - x, image_bound.y - y,
1255                                                      0, 0,
1256                                                      image_bound.width,
1257                                                      image_bound.height);
1258
1259               x = image_bound.x;
1260               y = image_bound.y;
1261             }
1262           
1263           break;
1264
1265         case GTK_IMAGE_IMAGE:
1266           mask = image->mask;
1267           image_bound.width = image->data.image.image->width;
1268           image_bound.height = image->data.image.image->height;
1269
1270           if (gdk_rectangle_intersect (&image_bound, &area, &image_bound) &&
1271               needs_state_transform)
1272             {
1273               pixbuf = gdk_pixbuf_get_from_image (NULL,
1274                                                   image->data.image.image,
1275                                                   gtk_widget_get_colormap (widget),
1276                                                   image_bound.x - x, image_bound.y - y,
1277                                                   0, 0,
1278                                                   image_bound.width,
1279                                                   image_bound.height);
1280
1281               x = image_bound.x;
1282               y = image_bound.y;
1283             }
1284           break;
1285
1286         case GTK_IMAGE_PIXBUF:
1287           image_bound.width = gdk_pixbuf_get_width (image->data.pixbuf.pixbuf);
1288           image_bound.height = gdk_pixbuf_get_height (image->data.pixbuf.pixbuf);          
1289
1290           if (gdk_rectangle_intersect (&image_bound, &area, &image_bound) &&
1291               needs_state_transform)
1292             {
1293               pixbuf = gdk_pixbuf_new_subpixbuf (image->data.pixbuf.pixbuf,
1294                                                  image_bound.x - x, image_bound.y - y,
1295                                                  image_bound.width, image_bound.height);
1296
1297               x = image_bound.x;
1298               y = image_bound.y;
1299             }
1300           else
1301             {
1302               pixbuf = image->data.pixbuf.pixbuf;
1303               g_object_ref (G_OBJECT (pixbuf));
1304             }
1305           break;
1306
1307         case GTK_IMAGE_STOCK:
1308           pixbuf = gtk_widget_render_icon (widget,
1309                                            image->data.stock.stock_id,
1310                                            image->icon_size,
1311                                            NULL);
1312           if (pixbuf)
1313             {              
1314               image_bound.width = gdk_pixbuf_get_width (pixbuf);
1315               image_bound.height = gdk_pixbuf_get_height (pixbuf);
1316             }
1317
1318           /* already done */
1319           needs_state_transform = FALSE;
1320           break;
1321
1322         case GTK_IMAGE_ICON_SET:
1323           pixbuf =
1324             gtk_icon_set_render_icon (image->data.icon_set.icon_set,
1325                                       widget->style,
1326                                       gtk_widget_get_direction (widget),
1327                                       GTK_WIDGET_STATE (widget),
1328                                       image->icon_size,
1329                                       widget,
1330                                       NULL);
1331
1332           if (pixbuf)
1333             {
1334               image_bound.width = gdk_pixbuf_get_width (pixbuf);
1335               image_bound.height = gdk_pixbuf_get_height (pixbuf);
1336             }
1337
1338           /* already done */
1339           needs_state_transform = FALSE;
1340           break;
1341
1342         case GTK_IMAGE_ANIMATION:
1343           {
1344             if (image->data.anim.iter == NULL)
1345               {
1346                 image->data.anim.iter = gdk_pixbuf_animation_get_iter (image->data.anim.anim, NULL);
1347                 
1348                 if (gdk_pixbuf_animation_iter_get_delay_time (image->data.anim.iter) >= 0)
1349                   image->data.anim.frame_timeout =
1350                     g_timeout_add (gdk_pixbuf_animation_iter_get_delay_time (image->data.anim.iter),
1351                                    animation_timeout,
1352                                    image);
1353               }
1354
1355             image_bound.width = gdk_pixbuf_animation_get_width (image->data.anim.anim);
1356             image_bound.height = gdk_pixbuf_animation_get_height (image->data.anim.anim);
1357                   
1358             /* don't advance the anim iter here, or we could get frame changes between two
1359              * exposes of different areas.
1360              */
1361             
1362             pixbuf = gdk_pixbuf_animation_iter_get_pixbuf (image->data.anim.iter);
1363             g_object_ref (G_OBJECT (pixbuf));
1364           }
1365           break;
1366
1367         case GTK_IMAGE_EMPTY:
1368           g_assert_not_reached ();
1369           break;
1370         }
1371
1372       if (mask)
1373         {
1374           gdk_gc_set_clip_mask (widget->style->black_gc, mask);
1375           gdk_gc_set_clip_origin (widget->style->black_gc, x, y);
1376         }
1377
1378       if (gdk_rectangle_intersect (&image_bound, &area, &image_bound))
1379         {
1380           if (pixbuf)
1381             {
1382               if (needs_state_transform)
1383                 {
1384                   GtkIconSource *source;
1385                   GdkPixbuf *rendered;
1386
1387                   source = gtk_icon_source_new ();
1388                   gtk_icon_source_set_pixbuf (source, pixbuf);
1389                   /* The size here is arbitrary; since size isn't
1390                    * wildcarded in the souce, it isn't supposed to be
1391                    * scaled by the engine function
1392                    */
1393                   gtk_icon_source_set_size (source,
1394                                             GTK_ICON_SIZE_SMALL_TOOLBAR);
1395                   gtk_icon_source_set_size_wildcarded (source, FALSE);
1396                   
1397                   rendered = gtk_style_render_icon (widget->style,
1398                                                     source,
1399                                                     gtk_widget_get_direction (widget),
1400                                                     GTK_WIDGET_STATE (widget),
1401                                                     /* arbitrary */
1402                                                     (GtkIconSize)-1,
1403                                                     widget,
1404                                                     "gtk-image");
1405
1406                   gtk_icon_source_free (source);
1407
1408                   g_object_unref (G_OBJECT (pixbuf));
1409                   pixbuf = rendered;
1410                 }
1411
1412               if (pixbuf)
1413                 {
1414                   gdk_pixbuf_render_to_drawable (pixbuf,
1415                                                  widget->window,
1416                                                  widget->style->black_gc,                                                
1417                                                  image_bound.x - x,
1418                                                  image_bound.y - y,
1419                                                  image_bound.x,
1420                                                  image_bound.y,
1421                                                  image_bound.width,
1422                                                  image_bound.height,
1423                                                  GDK_RGB_DITHER_NORMAL,
1424                                                  0, 0);
1425
1426                   g_object_unref (G_OBJECT (pixbuf));
1427                   pixbuf = NULL;
1428                 }
1429             }
1430           else
1431             {
1432               switch (image->storage_type)
1433                 {
1434                 case GTK_IMAGE_PIXMAP:
1435                   gdk_draw_drawable (widget->window,
1436                                      widget->style->black_gc,
1437                                      image->data.pixmap.pixmap,
1438                                      image_bound.x - x, image_bound.y - y,
1439                                      image_bound.x, image_bound.y,
1440                                      image_bound.width, image_bound.height);
1441                   break;
1442               
1443                 case GTK_IMAGE_IMAGE:
1444                   gdk_draw_image (widget->window,
1445                                   widget->style->black_gc,
1446                                   image->data.image.image,
1447                                   image_bound.x - x, image_bound.y - y,
1448                                   image_bound.x, image_bound.y,
1449                                   image_bound.width, image_bound.height);
1450                   break;
1451
1452                 case GTK_IMAGE_PIXBUF:
1453                 case GTK_IMAGE_STOCK:
1454                 case GTK_IMAGE_ICON_SET:
1455                 case GTK_IMAGE_ANIMATION:
1456                 case GTK_IMAGE_EMPTY:
1457                   g_assert_not_reached ();
1458                   break;
1459                 }
1460             }
1461         } /* if rectangle intersects */      
1462
1463       if (mask)
1464         {
1465           gdk_gc_set_clip_mask (widget->style->black_gc, NULL);
1466           gdk_gc_set_clip_origin (widget->style->black_gc, 0, 0);
1467         }
1468       
1469     } /* if widget is drawable */
1470
1471   return FALSE;
1472 }
1473
1474 static void
1475 gtk_image_clear (GtkImage *image)
1476 {
1477   g_object_freeze_notify (G_OBJECT (image));
1478   
1479   if (image->storage_type != GTK_IMAGE_EMPTY)
1480     g_object_notify (G_OBJECT (image), "storage_type");
1481
1482   if (image->mask)
1483     {
1484       g_object_unref (G_OBJECT (image->mask));
1485       image->mask = NULL;
1486       g_object_notify (G_OBJECT (image), "mask");
1487     }
1488
1489   if (image->icon_size != DEFAULT_ICON_SIZE)
1490     {
1491       image->icon_size = DEFAULT_ICON_SIZE;
1492       g_object_notify (G_OBJECT (image), "icon_size");
1493     }
1494   
1495   switch (image->storage_type)
1496     {
1497     case GTK_IMAGE_PIXMAP:
1498
1499       if (image->data.pixmap.pixmap)
1500         g_object_unref (G_OBJECT (image->data.pixmap.pixmap));
1501       image->data.pixmap.pixmap = NULL;
1502       
1503       g_object_notify (G_OBJECT (image), "pixmap");
1504       
1505       break;
1506
1507     case GTK_IMAGE_IMAGE:
1508
1509       if (image->data.image.image)
1510         g_object_unref (G_OBJECT (image->data.image.image));
1511       image->data.image.image = NULL;
1512       
1513       g_object_notify (G_OBJECT (image), "image");
1514       
1515       break;
1516
1517     case GTK_IMAGE_PIXBUF:
1518
1519       if (image->data.pixbuf.pixbuf)
1520         g_object_unref (G_OBJECT (image->data.pixbuf.pixbuf));
1521
1522       g_object_notify (G_OBJECT (image), "pixbuf");
1523       
1524       break;
1525
1526     case GTK_IMAGE_STOCK:
1527
1528       g_free (image->data.stock.stock_id);
1529
1530       image->data.stock.stock_id = NULL;
1531       
1532       g_object_notify (G_OBJECT (image), "stock");      
1533       break;
1534
1535     case GTK_IMAGE_ICON_SET:
1536       if (image->data.icon_set.icon_set)
1537         gtk_icon_set_unref (image->data.icon_set.icon_set);
1538       image->data.icon_set.icon_set = NULL;
1539       
1540       g_object_notify (G_OBJECT (image), "icon_set");      
1541       break;
1542
1543     case GTK_IMAGE_ANIMATION:
1544       if (image->data.anim.frame_timeout)
1545         g_source_remove (image->data.anim.frame_timeout);
1546       
1547       if (image->data.anim.anim)
1548         g_object_unref (G_OBJECT (image->data.anim.anim));
1549
1550       image->data.anim.frame_timeout = 0;
1551       image->data.anim.anim = NULL;
1552       
1553       g_object_notify (G_OBJECT (image), "pixbuf_animation");
1554       
1555       break;
1556       
1557     case GTK_IMAGE_EMPTY:
1558     default:
1559       break;
1560       
1561     }
1562
1563   image->storage_type = GTK_IMAGE_EMPTY;
1564
1565   memset (&image->data, '\0', sizeof (image->data));
1566
1567   g_object_thaw_notify (G_OBJECT (image));
1568 }
1569
1570 static void
1571 gtk_image_reset (GtkImage *image)
1572 {
1573   gtk_image_clear (image);
1574
1575   gtk_image_update_size (image, 0, 0);
1576 }
1577
1578 static void
1579 gtk_image_size_request (GtkWidget      *widget,
1580                         GtkRequisition *requisition)
1581 {
1582   GtkImage *image;
1583   GdkPixbuf *pixbuf = NULL;
1584   
1585   image = GTK_IMAGE (widget);
1586
1587   /* We update stock/icon set on every size request, because
1588    * the theme could have affected the size; for other kinds of
1589    * image, we just update the requisition when the image data
1590    * is set.
1591    */
1592   
1593   switch (image->storage_type)
1594     {
1595     case GTK_IMAGE_STOCK:
1596       pixbuf = gtk_widget_render_icon (GTK_WIDGET (image),
1597                                        image->data.stock.stock_id,
1598                                        image->icon_size,
1599                                        NULL);
1600       break;
1601
1602     case GTK_IMAGE_ICON_SET:
1603       pixbuf = gtk_icon_set_render_icon (image->data.icon_set.icon_set,
1604                                          widget->style,
1605                                          gtk_widget_get_direction (widget),
1606                                          GTK_WIDGET_STATE (widget),
1607                                          image->icon_size,
1608                                          widget,
1609                                          NULL);
1610       break;
1611       
1612     default:
1613       break;
1614     }
1615
1616   if (pixbuf)
1617     {
1618       GTK_WIDGET (image)->requisition.width = gdk_pixbuf_get_width (pixbuf) + GTK_MISC (image)->xpad * 2;
1619       GTK_WIDGET (image)->requisition.height = gdk_pixbuf_get_height (pixbuf) + GTK_MISC (image)->ypad * 2;
1620
1621       g_object_unref (G_OBJECT (pixbuf));
1622     }
1623
1624   /* Chain up to default that simply reads current requisition */
1625   GTK_WIDGET_CLASS (parent_class)->size_request (widget, requisition);
1626 }
1627
1628 static void
1629 gtk_image_update_size (GtkImage *image,
1630                        gint      image_width,
1631                        gint      image_height)
1632 {
1633   GTK_WIDGET (image)->requisition.width = image_width + GTK_MISC (image)->xpad * 2;
1634   GTK_WIDGET (image)->requisition.height = image_height + GTK_MISC (image)->ypad * 2;
1635
1636   if (GTK_WIDGET_VISIBLE (image))
1637     gtk_widget_queue_resize (GTK_WIDGET (image));
1638 }
1639
1640