]> Pileus Git - ~andy/gtk/blob - gtk/gtkimage.c
4b2517e4b18ecff29c1e800c7cc080f3b0720d84
[~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   g_return_if_fail (filename != NULL);
712
713   g_object_freeze_notify (G_OBJECT (image));
714   
715   gtk_image_reset (image);
716
717   if (filename == NULL)
718     {
719       g_object_thaw_notify (G_OBJECT (image));
720       return;
721     }
722   
723   anim = gdk_pixbuf_animation_new_from_file (filename, NULL);
724
725   if (anim == NULL)
726     {
727       gtk_image_set_from_stock (image,
728                                 GTK_STOCK_MISSING_IMAGE,
729                                 GTK_ICON_SIZE_BUTTON);
730       g_object_thaw_notify (G_OBJECT (image));
731       return;
732     }
733
734   /* We could just unconditionally set_from_animation,
735    * but it's nicer for memory if we toss the animation
736    * if it's just a single pixbuf
737    */
738
739   if (gdk_pixbuf_animation_is_static_image (anim))
740     {
741       gtk_image_set_from_pixbuf (image,
742                                  gdk_pixbuf_animation_get_static_image (anim));
743     }
744   else
745     {
746       gtk_image_set_from_animation (image, anim);
747     }
748
749   g_object_unref (G_OBJECT (anim));
750
751   g_object_thaw_notify (G_OBJECT (image));
752 }
753
754 /**
755  * gtk_image_set_from_pixbuf:
756  * @image: a #GtkImage
757  * @pixbuf: a #GdkPixbuf or %NULL
758  *
759  * See gtk_image_new_from_pixbuf() for details. 
760  * 
761  **/
762 void
763 gtk_image_set_from_pixbuf (GtkImage  *image,
764                            GdkPixbuf *pixbuf)
765 {
766   g_return_if_fail (GTK_IS_IMAGE (image));
767   g_return_if_fail (pixbuf == NULL ||
768                     GDK_IS_PIXBUF (pixbuf));
769
770   g_object_freeze_notify (G_OBJECT (image));
771   
772   if (pixbuf)
773     g_object_ref (G_OBJECT (pixbuf));
774
775   gtk_image_reset (image);
776
777   if (pixbuf != NULL)
778     {
779       image->storage_type = GTK_IMAGE_PIXBUF;
780
781       image->data.pixbuf.pixbuf = pixbuf;
782
783       gtk_image_update_size (image,
784                              gdk_pixbuf_get_width (pixbuf),
785                              gdk_pixbuf_get_height (pixbuf));
786     }
787
788   g_object_notify (G_OBJECT (image), "pixbuf");
789   
790   g_object_thaw_notify (G_OBJECT (image));
791 }
792
793 /**
794  * gtk_image_set_from_stock:
795  * @image: a #GtkImage
796  * @stock_id: a stock icon name
797  * @size: a stock icon size
798  *
799  * See gtk_image_new_from_stock() for details.
800  * 
801  **/
802 void
803 gtk_image_set_from_stock  (GtkImage       *image,
804                            const gchar    *stock_id,
805                            GtkIconSize     size)
806 {
807   gchar *new_id;
808   
809   g_return_if_fail (GTK_IS_IMAGE (image));
810
811   g_object_freeze_notify (G_OBJECT (image));
812
813   /* in case stock_id == image->data.stock.stock_id */
814   new_id = g_strdup (stock_id);
815   
816   gtk_image_reset (image);
817
818   if (new_id)
819     {
820       image->storage_type = GTK_IMAGE_STOCK;
821       
822       image->data.stock.stock_id = new_id;
823       image->icon_size = size;
824
825       /* Size is demand-computed in size request method
826        * if we're a stock image, since changing the
827        * style impacts the size request
828        */
829     }
830
831   g_object_notify (G_OBJECT (image), "stock");
832   g_object_notify (G_OBJECT (image), "icon_size");
833   
834   g_object_thaw_notify (G_OBJECT (image));
835 }
836
837 /**
838  * gtk_image_set_from_icon_set:
839  * @image: a #GtkImage
840  * @icon_set: a #GtkIconSet
841  * @size: a stock icon size
842  *
843  * See gtk_image_new_from_icon_set() for details.
844  * 
845  **/
846 void
847 gtk_image_set_from_icon_set  (GtkImage       *image,
848                               GtkIconSet     *icon_set,
849                               GtkIconSize     size)
850 {
851   g_return_if_fail (GTK_IS_IMAGE (image));
852
853   g_object_freeze_notify (G_OBJECT (image));
854   
855   if (icon_set)
856     gtk_icon_set_ref (icon_set);
857   
858   gtk_image_reset (image);
859
860   if (icon_set)
861     {      
862       image->storage_type = GTK_IMAGE_ICON_SET;
863       
864       image->data.icon_set.icon_set = icon_set;
865       image->icon_size = size;
866
867       /* Size is demand-computed in size request method
868        * if we're an icon set
869        */
870     }
871   
872   g_object_notify (G_OBJECT (image), "icon_set");
873   g_object_notify (G_OBJECT (image), "icon_size");
874   
875   g_object_thaw_notify (G_OBJECT (image));
876 }
877
878 /**
879  * gtk_image_set_from_animation:
880  * @image: a #GtkImage
881  * @animation: the #GdkPixbufAnimation
882  * 
883  * Causes the #GtkImage to display the given animation (or display
884  * nothing, if you set the animation to %NULL).
885  **/
886 void
887 gtk_image_set_from_animation (GtkImage           *image,
888                               GdkPixbufAnimation *animation)
889 {
890   g_return_if_fail (GTK_IS_IMAGE (image));
891   g_return_if_fail (animation == NULL ||
892                     GDK_IS_PIXBUF_ANIMATION (animation));
893
894   g_object_freeze_notify (G_OBJECT (image));
895   
896   if (animation)
897     g_object_ref (G_OBJECT (animation));
898
899   gtk_image_reset (image);
900
901   if (animation != NULL)
902     {
903       image->storage_type = GTK_IMAGE_ANIMATION;
904
905       image->data.anim.anim = animation;
906       image->data.anim.frame_timeout = 0;
907       image->data.anim.iter = NULL;
908       
909       gtk_image_update_size (image,
910                              gdk_pixbuf_animation_get_width (animation),
911                              gdk_pixbuf_animation_get_height (animation));
912     }
913
914   g_object_notify (G_OBJECT (image), "pixbuf_animation");
915   
916   g_object_thaw_notify (G_OBJECT (image));
917 }
918
919 /**
920  * gtk_image_get_storage_type:
921  * @image: a #GtkImage
922  * 
923  * Gets the type of representation being used by the #GtkImage
924  * to store image data. If the #GtkImage has no image data,
925  * the return value will be %GTK_IMAGE_EMPTY.
926  * 
927  * Return value: image representation being used
928  **/
929 GtkImageType
930 gtk_image_get_storage_type (GtkImage *image)
931 {
932   g_return_val_if_fail (GTK_IS_IMAGE (image), GTK_IMAGE_EMPTY);
933
934   return image->storage_type;
935 }
936
937 /**
938  * gtk_image_get_pixmap:
939  * @image: a #GtkImage
940  * @pixmap: location to store the pixmap, or %NULL
941  * @mask: location to store the mask, or %NULL
942  *
943  * Gets the pixmap and mask being displayed by the #GtkImage.
944  * The storage type of the image must be %GTK_IMAGE_EMPTY or
945  * %GTK_IMAGE_PIXMAP (see gtk_image_get_storage_type()).
946  * The caller of this function does not own a reference to the
947  * returned pixmap and mask.
948  * 
949  **/
950 void
951 gtk_image_get_pixmap (GtkImage   *image,
952                       GdkPixmap **pixmap,
953                       GdkBitmap **mask)
954 {
955   g_return_if_fail (GTK_IS_IMAGE (image)); 
956   g_return_if_fail (image->storage_type == GTK_IMAGE_PIXMAP ||
957                     image->storage_type == GTK_IMAGE_EMPTY);
958   
959   if (pixmap)
960     *pixmap = image->data.pixmap.pixmap;
961   
962   if (mask)
963     *mask = image->mask;
964 }
965
966 /**
967  * gtk_image_get_image:
968  * @image: a #GtkImage
969  * @gdk_image: return location for a #GtkImage
970  * @mask: return location for a #GdkBitmap
971  * 
972  * Gets the #GdkImage and mask being displayed by the #GtkImage.
973  * The storage type of the image must be %GTK_IMAGE_EMPTY or
974  * %GTK_IMAGE_IMAGE (see gtk_image_get_storage_type()).
975  * The caller of this function does not own a reference to the
976  * returned image and mask.
977  **/
978 void
979 gtk_image_get_image  (GtkImage   *image,
980                       GdkImage  **gdk_image,
981                       GdkBitmap **mask)
982 {
983   g_return_if_fail (GTK_IS_IMAGE (image));
984   g_return_if_fail (image->storage_type == GTK_IMAGE_IMAGE ||
985                     image->storage_type == GTK_IMAGE_EMPTY);
986
987   if (gdk_image)
988     *gdk_image = image->data.image.image;
989   
990   if (mask)
991     *mask = image->mask;
992 }
993
994 /**
995  * gtk_image_get_pixbuf:
996  * @image: a #GtkImage
997  *
998  *
999  * Gets the #GdkPixbuf being displayed by the #GtkImage.
1000  * The storage type of the image must be %GTK_IMAGE_EMPTY or
1001  * %GTK_IMAGE_PIXBUF (see gtk_image_get_storage_type()).
1002  * The caller of this function does not own a reference to the
1003  * returned pixbuf.
1004  * 
1005  * Return value: the displayed pixbuf, or %NULL if the image is empty
1006  **/
1007 GdkPixbuf*
1008 gtk_image_get_pixbuf (GtkImage *image)
1009 {
1010   g_return_val_if_fail (GTK_IS_IMAGE (image), NULL);
1011   g_return_val_if_fail (image->storage_type == GTK_IMAGE_PIXBUF ||
1012                         image->storage_type == GTK_IMAGE_EMPTY, NULL);
1013
1014   if (image->storage_type == GTK_IMAGE_EMPTY)
1015     image->data.pixbuf.pixbuf = NULL;
1016   
1017   return image->data.pixbuf.pixbuf;
1018 }
1019
1020 /**
1021  * gtk_image_get_stock:
1022  * @image: a #GtkImage
1023  * @stock_id: place to store a stock icon name
1024  * @size: place to store a stock icon size
1025  *
1026  * Gets the stock icon name and size being displayed by the #GtkImage.
1027  * The storage type of the image must be %GTK_IMAGE_EMPTY or
1028  * %GTK_IMAGE_STOCK (see gtk_image_get_storage_type()).
1029  * The returned string is owned by the #GtkImage and should not
1030  * be freed.
1031  * 
1032  **/
1033 void
1034 gtk_image_get_stock  (GtkImage        *image,
1035                       gchar          **stock_id,
1036                       GtkIconSize     *size)
1037 {
1038   g_return_if_fail (GTK_IS_IMAGE (image));
1039   g_return_if_fail (image->storage_type == GTK_IMAGE_STOCK ||
1040                     image->storage_type == GTK_IMAGE_EMPTY);
1041
1042   if (image->storage_type == GTK_IMAGE_EMPTY)
1043     image->data.stock.stock_id = NULL;
1044   
1045   if (stock_id)
1046     *stock_id = image->data.stock.stock_id;
1047
1048   if (size)
1049     *size = image->icon_size;
1050 }
1051
1052 /**
1053  * gtk_image_get_icon_set:
1054  * @image: a #GtkImage
1055  * @icon_set: location to store a #GtkIconSet
1056  * @size: location to store a stock icon size
1057  *
1058  * Gets the icon set and size being displayed by the #GtkImage.
1059  * The storage type of the image must be %GTK_IMAGE_EMPTY or
1060  * %GTK_IMAGE_ICON_SET (see gtk_image_get_storage_type()).
1061  * 
1062  **/
1063 void
1064 gtk_image_get_icon_set  (GtkImage        *image,
1065                          GtkIconSet     **icon_set,
1066                          GtkIconSize     *size)
1067 {
1068   g_return_if_fail (GTK_IS_IMAGE (image));
1069   g_return_if_fail (image->storage_type == GTK_IMAGE_ICON_SET ||
1070                     image->storage_type == GTK_IMAGE_EMPTY);
1071       
1072   if (icon_set)    
1073     *icon_set = image->data.icon_set.icon_set;
1074
1075   if (size)
1076     *size = image->icon_size;
1077 }
1078
1079 /**
1080  * gtk_image_get_animation:
1081  * @image: a #GtkImage
1082  *
1083  *
1084  * Gets the #GdkPixbufAnimation being displayed by the #GtkImage.
1085  * The storage type of the image must be %GTK_IMAGE_EMPTY or
1086  * %GTK_IMAGE_ANIMATION (see gtk_image_get_storage_type()).
1087  * The caller of this function does not own a reference to the
1088  * returned animation.
1089  * 
1090  * Return value: the displayed animation, or %NULL if the image is empty
1091  **/
1092 GdkPixbufAnimation*
1093 gtk_image_get_animation (GtkImage *image)
1094 {
1095   g_return_val_if_fail (GTK_IS_IMAGE (image), NULL);
1096   g_return_val_if_fail (image->storage_type == GTK_IMAGE_ANIMATION ||
1097                         image->storage_type == GTK_IMAGE_EMPTY,
1098                         NULL);
1099
1100   if (image->storage_type == GTK_IMAGE_EMPTY)
1101     image->data.anim.anim = NULL;
1102   
1103   return image->data.anim.anim;
1104 }
1105
1106 /**
1107  * gtk_image_new:
1108  * 
1109  * Creates a new empty #GtkImage widget.
1110  * 
1111  * Return value: a newly created #GtkImage widget. 
1112  **/
1113 GtkWidget*
1114 gtk_image_new (void)
1115 {
1116   return g_object_new (GTK_TYPE_IMAGE, NULL);
1117 }
1118
1119 void
1120 gtk_image_set (GtkImage  *image,
1121                GdkImage  *val,
1122                GdkBitmap *mask)
1123 {
1124   g_return_if_fail (GTK_IS_IMAGE (image));
1125
1126   gtk_image_set_from_image (image, val, mask);
1127 }
1128
1129 void
1130 gtk_image_get (GtkImage   *image,
1131                GdkImage  **val,
1132                GdkBitmap **mask)
1133 {
1134   g_return_if_fail (GTK_IS_IMAGE (image));
1135
1136   gtk_image_get_image (image, val, mask);
1137 }
1138
1139 static void
1140 gtk_image_unmap (GtkWidget *widget)
1141 {
1142   GtkImage *image;
1143
1144   image = GTK_IMAGE (widget);
1145
1146   if (image->storage_type == GTK_IMAGE_ANIMATION)
1147     {
1148       /* Reset the animation */
1149       
1150       if (image->data.anim.frame_timeout)
1151         {
1152           g_source_remove (image->data.anim.frame_timeout);
1153           image->data.anim.frame_timeout = 0;
1154         }
1155
1156       if (image->data.anim.iter)
1157         {
1158           g_object_unref (G_OBJECT (image->data.anim.iter));
1159           image->data.anim.iter = NULL;
1160         }
1161     }
1162
1163   if (GTK_WIDGET_CLASS (parent_class)->unmap)
1164     GTK_WIDGET_CLASS (parent_class)->unmap (widget);
1165 }
1166
1167 static gint
1168 animation_timeout (gpointer data)
1169 {
1170   GtkImage *image;
1171
1172   GDK_THREADS_ENTER ();
1173
1174   image = GTK_IMAGE (data);
1175   
1176   image->data.anim.frame_timeout = 0;
1177
1178   gdk_pixbuf_animation_iter_advance (image->data.anim.iter, NULL);
1179
1180   if (gdk_pixbuf_animation_iter_get_delay_time (image->data.anim.iter) >= 0)
1181     image->data.anim.frame_timeout =
1182       g_timeout_add (gdk_pixbuf_animation_iter_get_delay_time (image->data.anim.iter),
1183                      animation_timeout,
1184                      image);
1185   
1186   gtk_widget_queue_draw (GTK_WIDGET (image));
1187
1188   GDK_THREADS_LEAVE ();
1189
1190   return FALSE;
1191 }
1192
1193 static gint
1194 gtk_image_expose (GtkWidget      *widget,
1195                   GdkEventExpose *event)
1196 {
1197   g_return_val_if_fail (GTK_IS_IMAGE (widget), FALSE);
1198   g_return_val_if_fail (event != NULL, FALSE);
1199   
1200   if (GTK_WIDGET_MAPPED (widget) &&
1201       GTK_IMAGE (widget)->storage_type != GTK_IMAGE_EMPTY)
1202     {
1203       GtkImage *image;
1204       GtkMisc *misc;
1205       GdkRectangle area, image_bound;
1206       gfloat xalign;
1207       gint x, y;
1208       GdkBitmap *mask;
1209       GdkPixbuf *pixbuf;
1210       gboolean needs_state_transform;
1211       
1212       image = GTK_IMAGE (widget);
1213       misc = GTK_MISC (widget);
1214
1215       area = event->area;
1216       
1217       if (!gdk_rectangle_intersect (&area, &widget->allocation, &area))
1218         return FALSE;
1219
1220       if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
1221         xalign = misc->xalign;
1222       else
1223         xalign = 1.0 - misc->xalign;
1224   
1225       x = floor (widget->allocation.x + misc->xpad
1226                  + ((widget->allocation.width - widget->requisition.width) * xalign)
1227                  + 0.5);
1228       y = floor (widget->allocation.y + misc->ypad 
1229                  + ((widget->allocation.height - widget->requisition.height) * misc->yalign)
1230                  + 0.5);
1231       
1232       image_bound.x = x;
1233       image_bound.y = y;      
1234       image_bound.width = 0;
1235       image_bound.height = 0;      
1236
1237       mask = NULL;
1238       pixbuf = NULL;
1239       needs_state_transform = GTK_WIDGET_STATE (widget) != GTK_STATE_NORMAL;
1240       
1241       switch (image->storage_type)
1242         {
1243         case GTK_IMAGE_PIXMAP:
1244           mask = image->mask;
1245           gdk_drawable_get_size (image->data.pixmap.pixmap,
1246                                  &image_bound.width,
1247                                  &image_bound.height);
1248
1249           if (gdk_rectangle_intersect (&image_bound, &area, &image_bound) &&
1250               needs_state_transform)
1251             {
1252               pixbuf = gdk_pixbuf_get_from_drawable (NULL,
1253                                                      image->data.pixmap.pixmap,
1254                                                      gtk_widget_get_colormap (widget),
1255                                                      image_bound.x - x, image_bound.y - y,
1256                                                      0, 0,
1257                                                      image_bound.width,
1258                                                      image_bound.height);
1259
1260               x = image_bound.x;
1261               y = image_bound.y;
1262             }
1263           
1264           break;
1265
1266         case GTK_IMAGE_IMAGE:
1267           mask = image->mask;
1268           image_bound.width = image->data.image.image->width;
1269           image_bound.height = image->data.image.image->height;
1270
1271           if (gdk_rectangle_intersect (&image_bound, &area, &image_bound) &&
1272               needs_state_transform)
1273             {
1274               pixbuf = gdk_pixbuf_get_from_image (NULL,
1275                                                   image->data.image.image,
1276                                                   gtk_widget_get_colormap (widget),
1277                                                   image_bound.x - x, image_bound.y - y,
1278                                                   0, 0,
1279                                                   image_bound.width,
1280                                                   image_bound.height);
1281
1282               x = image_bound.x;
1283               y = image_bound.y;
1284             }
1285           break;
1286
1287         case GTK_IMAGE_PIXBUF:
1288           image_bound.width = gdk_pixbuf_get_width (image->data.pixbuf.pixbuf);
1289           image_bound.height = gdk_pixbuf_get_height (image->data.pixbuf.pixbuf);          
1290
1291           if (gdk_rectangle_intersect (&image_bound, &area, &image_bound) &&
1292               needs_state_transform)
1293             {
1294               pixbuf = gdk_pixbuf_new_subpixbuf (image->data.pixbuf.pixbuf,
1295                                                  image_bound.x - x, image_bound.y - y,
1296                                                  image_bound.width, image_bound.height);
1297
1298               x = image_bound.x;
1299               y = image_bound.y;
1300             }
1301           else
1302             {
1303               pixbuf = image->data.pixbuf.pixbuf;
1304               g_object_ref (G_OBJECT (pixbuf));
1305             }
1306           break;
1307
1308         case GTK_IMAGE_STOCK:
1309           pixbuf = gtk_widget_render_icon (widget,
1310                                            image->data.stock.stock_id,
1311                                            image->icon_size,
1312                                            NULL);
1313           if (pixbuf)
1314             {              
1315               image_bound.width = gdk_pixbuf_get_width (pixbuf);
1316               image_bound.height = gdk_pixbuf_get_height (pixbuf);
1317             }
1318
1319           /* already done */
1320           needs_state_transform = FALSE;
1321           break;
1322
1323         case GTK_IMAGE_ICON_SET:
1324           pixbuf =
1325             gtk_icon_set_render_icon (image->data.icon_set.icon_set,
1326                                       widget->style,
1327                                       gtk_widget_get_direction (widget),
1328                                       GTK_WIDGET_STATE (widget),
1329                                       image->icon_size,
1330                                       widget,
1331                                       NULL);
1332
1333           if (pixbuf)
1334             {
1335               image_bound.width = gdk_pixbuf_get_width (pixbuf);
1336               image_bound.height = gdk_pixbuf_get_height (pixbuf);
1337             }
1338
1339           /* already done */
1340           needs_state_transform = FALSE;
1341           break;
1342
1343         case GTK_IMAGE_ANIMATION:
1344           {
1345             if (image->data.anim.iter == NULL)
1346               {
1347                 image->data.anim.iter = gdk_pixbuf_animation_get_iter (image->data.anim.anim, NULL);
1348                 
1349                 if (gdk_pixbuf_animation_iter_get_delay_time (image->data.anim.iter) >= 0)
1350                   image->data.anim.frame_timeout =
1351                     g_timeout_add (gdk_pixbuf_animation_iter_get_delay_time (image->data.anim.iter),
1352                                    animation_timeout,
1353                                    image);
1354               }
1355
1356             image_bound.width = gdk_pixbuf_animation_get_width (image->data.anim.anim);
1357             image_bound.height = gdk_pixbuf_animation_get_height (image->data.anim.anim);
1358                   
1359             /* don't advance the anim iter here, or we could get frame changes between two
1360              * exposes of different areas.
1361              */
1362             
1363             pixbuf = gdk_pixbuf_animation_iter_get_pixbuf (image->data.anim.iter);
1364             g_object_ref (G_OBJECT (pixbuf));
1365           }
1366           break;
1367
1368         case GTK_IMAGE_EMPTY:
1369           g_assert_not_reached ();
1370           break;
1371         }
1372
1373       if (mask)
1374         {
1375           gdk_gc_set_clip_mask (widget->style->black_gc, mask);
1376           gdk_gc_set_clip_origin (widget->style->black_gc, x, y);
1377         }
1378
1379       if (gdk_rectangle_intersect (&image_bound, &area, &image_bound))
1380         {
1381           if (pixbuf)
1382             {
1383               if (needs_state_transform)
1384                 {
1385                   GtkIconSource *source;
1386                   GdkPixbuf *rendered;
1387
1388                   source = gtk_icon_source_new ();
1389                   gtk_icon_source_set_pixbuf (source, pixbuf);
1390                   /* The size here is arbitrary; since size isn't
1391                    * wildcarded in the souce, it isn't supposed to be
1392                    * scaled by the engine function
1393                    */
1394                   gtk_icon_source_set_size (source,
1395                                             GTK_ICON_SIZE_SMALL_TOOLBAR);
1396                   gtk_icon_source_set_size_wildcarded (source, FALSE);
1397                   
1398                   rendered = gtk_style_render_icon (widget->style,
1399                                                     source,
1400                                                     gtk_widget_get_direction (widget),
1401                                                     GTK_WIDGET_STATE (widget),
1402                                                     /* arbitrary */
1403                                                     (GtkIconSize)-1,
1404                                                     widget,
1405                                                     "gtk-image");
1406
1407                   gtk_icon_source_free (source);
1408
1409                   g_object_unref (G_OBJECT (pixbuf));
1410                   pixbuf = rendered;
1411                 }
1412
1413               if (pixbuf)
1414                 {
1415                   gdk_pixbuf_render_to_drawable (pixbuf,
1416                                                  widget->window,
1417                                                  widget->style->black_gc,                                                
1418                                                  image_bound.x - x,
1419                                                  image_bound.y - y,
1420                                                  image_bound.x,
1421                                                  image_bound.y,
1422                                                  image_bound.width,
1423                                                  image_bound.height,
1424                                                  GDK_RGB_DITHER_NORMAL,
1425                                                  0, 0);
1426
1427                   g_object_unref (G_OBJECT (pixbuf));
1428                   pixbuf = NULL;
1429                 }
1430             }
1431           else
1432             {
1433               switch (image->storage_type)
1434                 {
1435                 case GTK_IMAGE_PIXMAP:
1436                   gdk_draw_drawable (widget->window,
1437                                      widget->style->black_gc,
1438                                      image->data.pixmap.pixmap,
1439                                      image_bound.x - x, image_bound.y - y,
1440                                      image_bound.x, image_bound.y,
1441                                      image_bound.width, image_bound.height);
1442                   break;
1443               
1444                 case GTK_IMAGE_IMAGE:
1445                   gdk_draw_image (widget->window,
1446                                   widget->style->black_gc,
1447                                   image->data.image.image,
1448                                   image_bound.x - x, image_bound.y - y,
1449                                   image_bound.x, image_bound.y,
1450                                   image_bound.width, image_bound.height);
1451                   break;
1452
1453                 case GTK_IMAGE_PIXBUF:
1454                 case GTK_IMAGE_STOCK:
1455                 case GTK_IMAGE_ICON_SET:
1456                 case GTK_IMAGE_ANIMATION:
1457                 case GTK_IMAGE_EMPTY:
1458                   g_assert_not_reached ();
1459                   break;
1460                 }
1461             }
1462         } /* if rectangle intersects */      
1463
1464       if (mask)
1465         {
1466           gdk_gc_set_clip_mask (widget->style->black_gc, NULL);
1467           gdk_gc_set_clip_origin (widget->style->black_gc, 0, 0);
1468         }
1469       
1470     } /* if widget is drawable */
1471
1472   return FALSE;
1473 }
1474
1475 static void
1476 gtk_image_clear (GtkImage *image)
1477 {
1478   g_object_freeze_notify (G_OBJECT (image));
1479   
1480   if (image->storage_type != GTK_IMAGE_EMPTY)
1481     g_object_notify (G_OBJECT (image), "storage_type");
1482
1483   if (image->mask)
1484     {
1485       g_object_unref (G_OBJECT (image->mask));
1486       image->mask = NULL;
1487       g_object_notify (G_OBJECT (image), "mask");
1488     }
1489
1490   if (image->icon_size != DEFAULT_ICON_SIZE)
1491     {
1492       image->icon_size = DEFAULT_ICON_SIZE;
1493       g_object_notify (G_OBJECT (image), "icon_size");
1494     }
1495   
1496   switch (image->storage_type)
1497     {
1498     case GTK_IMAGE_PIXMAP:
1499
1500       if (image->data.pixmap.pixmap)
1501         g_object_unref (G_OBJECT (image->data.pixmap.pixmap));
1502       image->data.pixmap.pixmap = NULL;
1503       
1504       g_object_notify (G_OBJECT (image), "pixmap");
1505       
1506       break;
1507
1508     case GTK_IMAGE_IMAGE:
1509
1510       if (image->data.image.image)
1511         g_object_unref (G_OBJECT (image->data.image.image));
1512       image->data.image.image = NULL;
1513       
1514       g_object_notify (G_OBJECT (image), "image");
1515       
1516       break;
1517
1518     case GTK_IMAGE_PIXBUF:
1519
1520       if (image->data.pixbuf.pixbuf)
1521         g_object_unref (G_OBJECT (image->data.pixbuf.pixbuf));
1522
1523       g_object_notify (G_OBJECT (image), "pixbuf");
1524       
1525       break;
1526
1527     case GTK_IMAGE_STOCK:
1528
1529       g_free (image->data.stock.stock_id);
1530
1531       image->data.stock.stock_id = NULL;
1532       
1533       g_object_notify (G_OBJECT (image), "stock");      
1534       break;
1535
1536     case GTK_IMAGE_ICON_SET:
1537       if (image->data.icon_set.icon_set)
1538         gtk_icon_set_unref (image->data.icon_set.icon_set);
1539       image->data.icon_set.icon_set = NULL;
1540       
1541       g_object_notify (G_OBJECT (image), "icon_set");      
1542       break;
1543
1544     case GTK_IMAGE_ANIMATION:
1545       if (image->data.anim.frame_timeout)
1546         g_source_remove (image->data.anim.frame_timeout);
1547       
1548       if (image->data.anim.anim)
1549         g_object_unref (G_OBJECT (image->data.anim.anim));
1550
1551       image->data.anim.frame_timeout = 0;
1552       image->data.anim.anim = NULL;
1553       
1554       g_object_notify (G_OBJECT (image), "pixbuf_animation");
1555       
1556       break;
1557       
1558     case GTK_IMAGE_EMPTY:
1559     default:
1560       break;
1561       
1562     }
1563
1564   image->storage_type = GTK_IMAGE_EMPTY;
1565
1566   memset (&image->data, '\0', sizeof (image->data));
1567
1568   g_object_thaw_notify (G_OBJECT (image));
1569 }
1570
1571 static void
1572 gtk_image_reset (GtkImage *image)
1573 {
1574   gtk_image_clear (image);
1575
1576   gtk_image_update_size (image, 0, 0);
1577 }
1578
1579 static void
1580 gtk_image_size_request (GtkWidget      *widget,
1581                         GtkRequisition *requisition)
1582 {
1583   GtkImage *image;
1584   GdkPixbuf *pixbuf = NULL;
1585   
1586   image = GTK_IMAGE (widget);
1587
1588   /* We update stock/icon set on every size request, because
1589    * the theme could have affected the size; for other kinds of
1590    * image, we just update the requisition when the image data
1591    * is set.
1592    */
1593   
1594   switch (image->storage_type)
1595     {
1596     case GTK_IMAGE_STOCK:
1597       pixbuf = gtk_widget_render_icon (GTK_WIDGET (image),
1598                                        image->data.stock.stock_id,
1599                                        image->icon_size,
1600                                        NULL);
1601       break;
1602
1603     case GTK_IMAGE_ICON_SET:
1604       pixbuf = gtk_icon_set_render_icon (image->data.icon_set.icon_set,
1605                                          widget->style,
1606                                          gtk_widget_get_direction (widget),
1607                                          GTK_WIDGET_STATE (widget),
1608                                          image->icon_size,
1609                                          widget,
1610                                          NULL);
1611       break;
1612       
1613     default:
1614       break;
1615     }
1616
1617   if (pixbuf)
1618     {
1619       GTK_WIDGET (image)->requisition.width = gdk_pixbuf_get_width (pixbuf) + GTK_MISC (image)->xpad * 2;
1620       GTK_WIDGET (image)->requisition.height = gdk_pixbuf_get_height (pixbuf) + GTK_MISC (image)->ypad * 2;
1621
1622       g_object_unref (G_OBJECT (pixbuf));
1623     }
1624
1625   /* Chain up to default that simply reads current requisition */
1626   GTK_WIDGET_CLASS (parent_class)->size_request (widget, requisition);
1627 }
1628
1629 static void
1630 gtk_image_update_size (GtkImage *image,
1631                        gint      image_width,
1632                        gint      image_height)
1633 {
1634   GTK_WIDGET (image)->requisition.width = image_width + GTK_MISC (image)->xpad * 2;
1635   GTK_WIDGET (image)->requisition.height = image_height + GTK_MISC (image)->ypad * 2;
1636
1637   if (GTK_WIDGET_VISIBLE (image))
1638     gtk_widget_queue_resize (GTK_WIDGET (image));
1639 }
1640
1641