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