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