]> Pileus Git - ~andy/gtk/blob - gtk/gtkimage.c
Various cleanups. (#315360, Kjartan Maraas)
[~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 <string.h>
30
31 #include "gtkcontainer.h"
32 #include "gtkimage.h"
33 #include "gtkiconfactory.h"
34 #include "gtkstock.h"
35 #include "gtkicontheme.h"
36 #include "gtkintl.h"
37 #include "gtkprivate.h"
38 #include "gtkalias.h"
39
40 typedef struct _GtkImagePrivate GtkImagePrivate;
41
42 struct _GtkImagePrivate
43 {
44   /* Only used with GTK_IMAGE_ANIMATION, GTK_IMAGE_PIXBUF */
45   gchar *filename;
46
47   gint pixel_size;
48 };
49
50 #define GTK_IMAGE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_IMAGE, GtkImagePrivate))
51
52
53 #define DEFAULT_ICON_SIZE GTK_ICON_SIZE_BUTTON
54
55 static void gtk_image_class_init   (GtkImageClass  *klass);
56 static void gtk_image_init         (GtkImage       *image);
57 static gint gtk_image_expose       (GtkWidget      *widget,
58                                     GdkEventExpose *event);
59 static void gtk_image_unmap        (GtkWidget      *widget);
60 static void gtk_image_unrealize    (GtkWidget      *widget);
61 static void gtk_image_size_request (GtkWidget      *widget,
62                                     GtkRequisition *requisition);
63 static void gtk_image_style_set    (GtkWidget      *widget,
64                                     GtkStyle       *prev_style);
65 static void gtk_image_screen_changed (GtkWidget    *widget,
66                                       GdkScreen    *prev_screen);
67 static void gtk_image_destroy      (GtkObject      *object);
68 static void gtk_image_reset        (GtkImage       *image);
69 static void gtk_image_calc_size    (GtkImage       *image);
70
71 static void gtk_image_update_size  (GtkImage       *image,
72                                     gint            image_width,
73                                     gint            image_height);
74
75 static void gtk_image_set_property      (GObject          *object,
76                                          guint             prop_id,
77                                          const GValue     *value,
78                                          GParamSpec       *pspec);
79 static void gtk_image_get_property      (GObject          *object,
80                                          guint             prop_id,
81                                          GValue           *value,
82                                          GParamSpec       *pspec);
83
84 static void icon_theme_changed          (GtkImage         *image);
85
86 static gpointer parent_class;
87
88 enum
89 {
90   PROP_0,
91   PROP_PIXBUF,
92   PROP_PIXMAP,
93   PROP_IMAGE,
94   PROP_MASK,
95   PROP_FILE,
96   PROP_STOCK,
97   PROP_ICON_SET,
98   PROP_ICON_SIZE,
99   PROP_PIXEL_SIZE,
100   PROP_PIXBUF_ANIMATION,
101   PROP_ICON_NAME,
102   PROP_STORAGE_TYPE
103 };
104
105 GType
106 gtk_image_get_type (void)
107 {
108   static GType image_type = 0;
109
110   if (!image_type)
111     {
112       static const GTypeInfo image_info =
113       {
114         sizeof (GtkImageClass),
115         NULL,           /* base_init */
116         NULL,           /* base_finalize */
117         (GClassInitFunc) gtk_image_class_init,
118         NULL,           /* class_finalize */
119         NULL,           /* class_data */
120         sizeof (GtkImage),
121         0,              /* n_preallocs */
122         (GInstanceInitFunc) gtk_image_init,
123       };
124
125       image_type = g_type_register_static (GTK_TYPE_MISC, I_("GtkImage"),
126                                            &image_info, 0);
127     }
128
129   return image_type;
130 }
131
132 static void
133 gtk_image_class_init (GtkImageClass *class)
134 {
135   GObjectClass *gobject_class;
136   GtkObjectClass *object_class;
137   GtkWidgetClass *widget_class;
138
139   parent_class = g_type_class_peek_parent (class);
140
141   gobject_class = G_OBJECT_CLASS (class);
142   
143   gobject_class->set_property = gtk_image_set_property;
144   gobject_class->get_property = gtk_image_get_property;
145   
146   object_class = GTK_OBJECT_CLASS (class);
147   
148   object_class->destroy = gtk_image_destroy;
149
150   widget_class = GTK_WIDGET_CLASS (class);
151   
152   widget_class->expose_event = gtk_image_expose;
153   widget_class->size_request = gtk_image_size_request;
154   widget_class->unmap = gtk_image_unmap;
155   widget_class->unrealize = gtk_image_unrealize;
156   widget_class->style_set = gtk_image_style_set;
157   widget_class->screen_changed = gtk_image_screen_changed;
158   
159   g_object_class_install_property (gobject_class,
160                                    PROP_PIXBUF,
161                                    g_param_spec_object ("pixbuf",
162                                                         P_("Pixbuf"),
163                                                         P_("A GdkPixbuf to display"),
164                                                         GDK_TYPE_PIXBUF,
165                                                         GTK_PARAM_READWRITE));
166
167   g_object_class_install_property (gobject_class,
168                                    PROP_PIXMAP,
169                                    g_param_spec_object ("pixmap",
170                                                         P_("Pixmap"),
171                                                         P_("A GdkPixmap to display"),
172                                                         GDK_TYPE_PIXMAP,
173                                                         GTK_PARAM_READWRITE));
174
175   g_object_class_install_property (gobject_class,
176                                    PROP_IMAGE,
177                                    g_param_spec_object ("image",
178                                                         P_("Image"),
179                                                         P_("A GdkImage to display"),
180                                                         GDK_TYPE_IMAGE,
181                                                         GTK_PARAM_READWRITE));
182
183   g_object_class_install_property (gobject_class,
184                                    PROP_MASK,
185                                    g_param_spec_object ("mask",
186                                                         P_("Mask"),
187                                                         P_("Mask bitmap to use with GdkImage or GdkPixmap"),
188                                                         GDK_TYPE_PIXMAP,
189                                                         GTK_PARAM_READWRITE));
190   
191   g_object_class_install_property (gobject_class,
192                                    PROP_FILE,
193                                    g_param_spec_string ("file",
194                                                         P_("Filename"),
195                                                         P_("Filename to load and display"),
196                                                         NULL,
197                                                         GTK_PARAM_READWRITE));
198   
199
200   g_object_class_install_property (gobject_class,
201                                    PROP_STOCK,
202                                    g_param_spec_string ("stock",
203                                                         P_("Stock ID"),
204                                                         P_("Stock ID for a stock image to display"),
205                                                         NULL,
206                                                         GTK_PARAM_READWRITE));
207   
208   g_object_class_install_property (gobject_class,
209                                    PROP_ICON_SET,
210                                    g_param_spec_boxed ("icon-set",
211                                                        P_("Icon set"),
212                                                        P_("Icon set to display"),
213                                                        GTK_TYPE_ICON_SET,
214                                                        GTK_PARAM_READWRITE));
215   
216   g_object_class_install_property (gobject_class,
217                                    PROP_ICON_SIZE,
218                                    g_param_spec_int ("icon-size",
219                                                      P_("Icon size"),
220                                                      P_("Symbolic size to use for stock icon, icon set or named icon"),
221                                                      0, G_MAXINT,
222                                                      DEFAULT_ICON_SIZE,
223                                                      GTK_PARAM_READWRITE));
224   /**
225    * GtkImage:pixel-size:
226    *
227    * The :pixel-size property can be used to specify a fixed size
228    * overriding the :icon-size property for images of type 
229    * %GTK_IMAGE_ICON_NAME. 
230    *
231    * Since: 2.6
232    */
233   g_object_class_install_property (gobject_class,
234                                    PROP_PIXEL_SIZE,
235                                    g_param_spec_int ("pixel-size",
236                                                      P_("Pixel size"),
237                                                      P_("Pixel size to use for named icon"),
238                                                      -1, G_MAXINT,
239                                                      -1,
240                                                      GTK_PARAM_READWRITE));
241   
242   g_object_class_install_property (gobject_class,
243                                    PROP_PIXBUF_ANIMATION,
244                                    g_param_spec_object ("pixbuf-animation",
245                                                         P_("Animation"),
246                                                         P_("GdkPixbufAnimation to display"),
247                                                         GDK_TYPE_PIXBUF_ANIMATION,
248                                                         GTK_PARAM_READWRITE));
249
250   /**
251    * GtkImage:icon-name:
252    *
253    * The name of the icon in the icon theme.  If the icon theme is
254    * changed, the image will be updated automatically.
255    *
256    * Since: 2.6
257    */
258   g_object_class_install_property (gobject_class,
259                                    PROP_ICON_NAME,
260                                    g_param_spec_string ("icon-name",
261                                                         P_("Icon Name"),
262                                                         P_("The name of the icon from the icon theme"),
263                                                         NULL,
264                                                         GTK_PARAM_READWRITE));
265   
266   g_object_class_install_property (gobject_class,
267                                    PROP_STORAGE_TYPE,
268                                    g_param_spec_enum ("storage-type",
269                                                       P_("Storage type"),
270                                                       P_("The representation being used for image data"),
271                                                       GTK_TYPE_IMAGE_TYPE,
272                                                       GTK_IMAGE_EMPTY,
273                                                       GTK_PARAM_READABLE));
274
275   g_type_class_add_private (object_class, sizeof (GtkImagePrivate));
276 }
277
278 static void
279 gtk_image_init (GtkImage *image)
280 {
281   GtkImagePrivate *priv = GTK_IMAGE_GET_PRIVATE (image);
282
283   GTK_WIDGET_SET_FLAGS (image, GTK_NO_WINDOW);
284
285   image->storage_type = GTK_IMAGE_EMPTY;
286   image->icon_size = DEFAULT_ICON_SIZE;
287   image->mask = NULL;
288
289   priv->pixel_size = -1;
290
291   priv->filename = NULL;
292 }
293
294 static void
295 gtk_image_destroy (GtkObject *object)
296 {
297   GtkImage *image = GTK_IMAGE (object);
298
299   gtk_image_clear (image);
300   
301   GTK_OBJECT_CLASS (parent_class)->destroy (object);
302 }
303
304 static void 
305 gtk_image_set_property (GObject      *object,
306                         guint         prop_id,
307                         const GValue *value,
308                         GParamSpec   *pspec)
309 {
310   GtkImage *image;
311
312   image = GTK_IMAGE (object);
313   
314   switch (prop_id)
315     {
316     case PROP_PIXBUF:
317       gtk_image_set_from_pixbuf (image,
318                                  g_value_get_object (value));
319       break;
320     case PROP_PIXMAP:
321       gtk_image_set_from_pixmap (image,
322                                  g_value_get_object (value),
323                                  image->mask);
324       break;
325     case PROP_IMAGE:
326       gtk_image_set_from_image (image,
327                                 g_value_get_object (value),
328                                 image->mask);
329       break;
330     case PROP_MASK:
331       if (image->storage_type == GTK_IMAGE_PIXMAP)
332         gtk_image_set_from_pixmap (image,
333                                    image->data.pixmap.pixmap,
334                                    g_value_get_object (value));
335       else if (image->storage_type == GTK_IMAGE_IMAGE)
336         gtk_image_set_from_image (image,
337                                   image->data.image.image,
338                                   g_value_get_object (value));
339       else
340         {
341           GdkBitmap *mask;
342
343           mask = g_value_get_object (value);
344
345           if (mask)
346             g_object_ref (mask);
347           
348           gtk_image_reset (image);
349
350           image->mask = mask;
351         }
352       break;
353     case PROP_FILE:
354       gtk_image_set_from_file (image, g_value_get_string (value));
355       break;
356     case PROP_STOCK:
357       gtk_image_set_from_stock (image, g_value_get_string (value),
358                                 image->icon_size);
359       break;
360     case PROP_ICON_SET:
361       gtk_image_set_from_icon_set (image, g_value_get_boxed (value),
362                                    image->icon_size);
363       break;
364     case PROP_ICON_SIZE:
365       if (image->storage_type == GTK_IMAGE_STOCK)
366         gtk_image_set_from_stock (image,
367                                   image->data.stock.stock_id,
368                                   g_value_get_int (value));
369       else if (image->storage_type == GTK_IMAGE_ICON_SET)
370         gtk_image_set_from_icon_set (image,
371                                      image->data.icon_set.icon_set,
372                                      g_value_get_int (value));
373       else if (image->storage_type == GTK_IMAGE_ICON_NAME)
374         gtk_image_set_from_icon_name (image,
375                                       image->data.name.icon_name,
376                                       g_value_get_int (value));
377       else
378         /* Save to be used when STOCK or ICON_SET property comes in */
379         image->icon_size = g_value_get_int (value);
380       break;
381     case PROP_PIXEL_SIZE:
382       gtk_image_set_pixel_size (image, g_value_get_int (value));
383       break;
384     case PROP_PIXBUF_ANIMATION:
385       gtk_image_set_from_animation (image,
386                                     g_value_get_object (value));
387       break;
388     case PROP_ICON_NAME:
389       gtk_image_set_from_icon_name (image, g_value_get_string (value),
390                                     image->icon_size);
391       break;
392
393     default:
394       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
395       break;
396     }
397 }
398
399 static void 
400 gtk_image_get_property (GObject     *object,
401                         guint        prop_id,
402                         GValue      *value,
403                         GParamSpec  *pspec)
404 {
405   GtkImage *image;
406   GtkImagePrivate *priv;
407
408   image = GTK_IMAGE (object);
409   priv = GTK_IMAGE_GET_PRIVATE (image);
410
411   /* The "getter" functions whine if you try to get the wrong
412    * storage type. This function is instead robust against that,
413    * so that GUI builders don't have to jump through hoops
414    * to avoid g_warning
415    */
416   
417   switch (prop_id)
418     {
419     case PROP_PIXBUF:
420       if (image->storage_type != GTK_IMAGE_PIXBUF)
421         g_value_set_object (value, NULL);
422       else
423         g_value_set_object (value,
424                             gtk_image_get_pixbuf (image));
425       break;
426     case PROP_PIXMAP:
427       if (image->storage_type != GTK_IMAGE_PIXMAP)
428         g_value_set_object (value, NULL);
429       else
430         g_value_set_object (value,
431                             image->data.pixmap.pixmap);
432       break;
433     case PROP_MASK:
434       g_value_set_object (value, image->mask);
435       break;
436     case PROP_IMAGE:
437       if (image->storage_type != GTK_IMAGE_IMAGE)
438         g_value_set_object (value, NULL);
439       else
440         g_value_set_object (value,
441                             image->data.image.image);
442       break;
443     case PROP_FILE:
444       g_value_set_string (value, priv->filename);
445       break;
446     case PROP_STOCK:
447       if (image->storage_type != GTK_IMAGE_STOCK)
448         g_value_set_string (value, NULL);
449       else
450         g_value_set_string (value,
451                             image->data.stock.stock_id);
452       break;
453     case PROP_ICON_SET:
454       if (image->storage_type != GTK_IMAGE_ICON_SET)
455         g_value_set_boxed (value, NULL);
456       else
457         g_value_set_boxed (value,
458                            image->data.icon_set.icon_set);
459       break;      
460     case PROP_ICON_SIZE:
461       g_value_set_int (value, image->icon_size);
462       break;
463     case PROP_PIXEL_SIZE:
464       g_value_set_int (value, priv->pixel_size);
465       break;
466     case PROP_PIXBUF_ANIMATION:
467       if (image->storage_type != GTK_IMAGE_ANIMATION)
468         g_value_set_object (value, NULL);
469       else
470         g_value_set_object (value,
471                             image->data.anim.anim);
472       break;
473     case PROP_ICON_NAME:
474       if (image->storage_type != GTK_IMAGE_ICON_NAME)
475         g_value_set_string (value, NULL);
476       else
477         g_value_set_string (value,
478                             image->data.name.icon_name);
479       break;
480     case PROP_STORAGE_TYPE:
481       g_value_set_enum (value, image->storage_type);
482       break;
483       
484     default:
485       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
486       break;
487     }
488 }
489
490
491 /**
492  * gtk_image_new_from_pixmap:
493  * @pixmap: a #GdkPixmap, or %NULL
494  * @mask: a #GdkBitmap, or %NULL
495  * 
496  * Creates a #GtkImage widget displaying @pixmap with a @mask.
497  * A #GdkPixmap is a server-side image buffer in the pixel format of the
498  * current display. The #GtkImage does not assume a reference to the
499  * pixmap or mask; you still need to unref them if you own references.
500  * #GtkImage will add its own reference rather than adopting yours.
501  * 
502  * Return value: a new #GtkImage
503  **/
504 GtkWidget*
505 gtk_image_new_from_pixmap (GdkPixmap *pixmap,
506                            GdkBitmap *mask)
507 {
508   GtkImage *image;
509
510   image = g_object_new (GTK_TYPE_IMAGE, NULL);
511
512   gtk_image_set_from_pixmap (image, pixmap, mask);
513
514   return GTK_WIDGET (image);
515 }
516
517 /**
518  * gtk_image_new_from_image:
519  * @image: a #GdkImage, or %NULL
520  * @mask: a #GdkBitmap, or %NULL 
521  * 
522  * Creates a #GtkImage widget displaying a @image with a @mask.
523  * A #GdkImage is a client-side image buffer in the pixel format of the
524  * current display.
525  * The #GtkImage does not assume a reference to the
526  * image or mask; you still need to unref them if you own references.
527  * #GtkImage will add its own reference rather than adopting yours.
528  * 
529  * Return value: a new #GtkImage
530  **/
531 GtkWidget*
532 gtk_image_new_from_image  (GdkImage  *gdk_image,
533                            GdkBitmap *mask)
534 {
535   GtkImage *image;
536
537   image = g_object_new (GTK_TYPE_IMAGE, NULL);
538
539   gtk_image_set_from_image (image, gdk_image, mask);
540
541   return GTK_WIDGET (image);
542 }
543
544 /**
545  * gtk_image_new_from_file:
546  * @filename: a filename
547  * 
548  * Creates a new #GtkImage displaying the file @filename. If the file
549  * isn't found or can't be loaded, the resulting #GtkImage will
550  * display a "broken image" icon. This function never returns %NULL,
551  * it always returns a valid #GtkImage widget.
552  *
553  * If the file contains an animation, the image will contain an
554  * animation.
555  *
556  * If you need to detect failures to load the file, use
557  * gdk_pixbuf_new_from_file() to load the file yourself, then create
558  * the #GtkImage from the pixbuf. (Or for animations, use
559  * gdk_pixbuf_animation_new_from_file()).
560  *
561  * The storage type (gtk_image_get_storage_type()) of the returned
562  * image is not defined, it will be whatever is appropriate for
563  * displaying the file.
564  * 
565  * Return value: a new #GtkImage
566  **/
567 GtkWidget*
568 gtk_image_new_from_file   (const gchar *filename)
569 {
570   GtkImage *image;
571
572   image = g_object_new (GTK_TYPE_IMAGE, NULL);
573
574   gtk_image_set_from_file (image, filename);
575
576   return GTK_WIDGET (image);
577 }
578
579 /**
580  * gtk_image_new_from_pixbuf:
581  * @pixbuf: a #GdkPixbuf, or %NULL
582  * 
583  * Creates a new #GtkImage displaying @pixbuf.
584  * The #GtkImage does not assume a reference to the
585  * pixbuf; you still need to unref it if you own references.
586  * #GtkImage will add its own reference rather than adopting yours.
587  * 
588  * Note that this function just creates an #GtkImage from the pixbuf.  The
589  * #GtkImage created will not react to state changes.  Should you want that, you
590  * should use gtk_image_new_from_icon_set().
591  * 
592  * Return value: a new #GtkImage
593  **/
594 GtkWidget*
595 gtk_image_new_from_pixbuf (GdkPixbuf *pixbuf)
596 {
597   GtkImage *image;
598
599   image = g_object_new (GTK_TYPE_IMAGE, NULL);
600
601   gtk_image_set_from_pixbuf (image, pixbuf);
602
603   return GTK_WIDGET (image);  
604 }
605
606 /**
607  * gtk_image_new_from_stock:
608  * @stock_id: a stock icon name
609  * @size: a stock icon size
610  * 
611  * Creates a #GtkImage displaying a stock icon. Sample stock icon
612  * names are #GTK_STOCK_OPEN, #GTK_STOCK_QUIT. Sample stock sizes
613  * are #GTK_ICON_SIZE_MENU, #GTK_ICON_SIZE_SMALL_TOOLBAR. If the stock
614  * icon name isn't known, the image will be empty.
615  * You can register your own stock icon names, see
616  * gtk_icon_factory_add_default() and gtk_icon_factory_add().
617  * 
618  * Return value: a new #GtkImage displaying the stock icon
619  **/
620 GtkWidget*
621 gtk_image_new_from_stock (const gchar    *stock_id,
622                           GtkIconSize     size)
623 {
624   GtkImage *image;
625
626   image = g_object_new (GTK_TYPE_IMAGE, NULL);
627
628   gtk_image_set_from_stock (image, stock_id, size);
629
630   return GTK_WIDGET (image);
631 }
632
633 /**
634  * gtk_image_new_from_icon_set:
635  * @icon_set: a #GtkIconSet
636  * @size: a stock icon size
637  *
638  * Creates a #GtkImage displaying an icon set. Sample stock sizes are
639  * #GTK_ICON_SIZE_MENU, #GTK_ICON_SIZE_SMALL_TOOLBAR. Instead of using
640  * this function, usually it's better to create a #GtkIconFactory, put
641  * your icon sets in the icon factory, add the icon factory to the
642  * list of default factories with gtk_icon_factory_add_default(), and
643  * then use gtk_image_new_from_stock(). This will allow themes to
644  * override the icon you ship with your application.
645  *
646  * The #GtkImage does not assume a reference to the
647  * icon set; you still need to unref it if you own references.
648  * #GtkImage will add its own reference rather than adopting yours.
649  * 
650  * 
651  * Return value: a new #GtkImage
652  **/
653 GtkWidget*
654 gtk_image_new_from_icon_set (GtkIconSet     *icon_set,
655                              GtkIconSize     size)
656 {
657   GtkImage *image;
658
659   image = g_object_new (GTK_TYPE_IMAGE, NULL);
660
661   gtk_image_set_from_icon_set (image, icon_set, size);
662
663   return GTK_WIDGET (image);
664 }
665
666 /**
667  * gtk_image_new_from_animation:
668  * @animation: an animation
669  * 
670  * Creates a #GtkImage displaying the given animation.
671  * The #GtkImage does not assume a reference to the
672  * animation; you still need to unref it if you own references.
673  * #GtkImage will add its own reference rather than adopting yours.
674  * 
675  * Return value: a new #GtkImage widget
676  **/
677 GtkWidget*
678 gtk_image_new_from_animation (GdkPixbufAnimation *animation)
679 {
680   GtkImage *image;
681
682   g_return_val_if_fail (GDK_IS_PIXBUF_ANIMATION (animation), NULL);
683   
684   image = g_object_new (GTK_TYPE_IMAGE, NULL);
685
686   gtk_image_set_from_animation (image, animation);
687
688   return GTK_WIDGET (image);
689 }
690
691 /**
692  * gtk_image_new_from_icon_name:
693  * @icon_name: an icon name
694  * @size: a stock icon size
695  * 
696  * Creates a #GtkImage displaying an icon from the current icon theme.
697  * If the icon name isn't known, a "broken image" icon will be
698  * displayed instead.  If the current icon theme is changed, the icon
699  * will be updated appropriately.
700  * 
701  * Return value: a new #GtkImage displaying the themed icon
702  *
703  * Since: 2.6
704  **/
705 GtkWidget*
706 gtk_image_new_from_icon_name (const gchar    *icon_name,
707                               GtkIconSize     size)
708 {
709   GtkImage *image;
710
711   image = g_object_new (GTK_TYPE_IMAGE, NULL);
712
713   gtk_image_set_from_icon_name (image, icon_name, size);
714
715   return GTK_WIDGET (image);
716 }
717
718 /**
719  * gtk_image_set_from_pixmap:
720  * @image: a #GtkImage
721  * @pixmap: a #GdkPixmap or %NULL
722  * @mask: a #GdkBitmap or %NULL
723  *
724  * See gtk_image_new_from_pixmap() for details.
725  * 
726  **/
727 void
728 gtk_image_set_from_pixmap (GtkImage  *image,
729                            GdkPixmap *pixmap,
730                            GdkBitmap *mask)
731 {
732   g_return_if_fail (GTK_IS_IMAGE (image));
733   g_return_if_fail (pixmap == NULL ||
734                     GDK_IS_PIXMAP (pixmap));
735   g_return_if_fail (mask == NULL ||
736                     GDK_IS_PIXMAP (mask));
737
738   g_object_freeze_notify (G_OBJECT (image));
739   
740   if (pixmap)
741     g_object_ref (pixmap);
742
743   if (mask)
744     g_object_ref (mask);
745
746   gtk_image_reset (image);
747
748   image->mask = mask;
749   
750   if (pixmap)
751     {
752       int width;
753       int height;
754       
755       image->storage_type = GTK_IMAGE_PIXMAP;
756
757       image->data.pixmap.pixmap = pixmap;
758
759       gdk_drawable_get_size (GDK_DRAWABLE (pixmap), &width, &height);
760
761       gtk_image_update_size (image, width, height);
762     }
763
764   g_object_notify (G_OBJECT (image), "pixmap");
765   g_object_notify (G_OBJECT (image), "mask");
766   
767   g_object_thaw_notify (G_OBJECT (image));
768 }
769
770 /**
771  * gtk_image_set_from_image:
772  * @image: a #GtkImage
773  * @gdk_image: a #GdkImage or %NULL
774  * @mask: a #GdkBitmap or %NULL
775  *
776  * See gtk_image_new_from_image() for details.
777  * 
778  **/
779 void
780 gtk_image_set_from_image  (GtkImage  *image,
781                            GdkImage  *gdk_image,
782                            GdkBitmap *mask)
783 {
784   g_return_if_fail (GTK_IS_IMAGE (image));
785   g_return_if_fail (gdk_image == NULL ||
786                     GDK_IS_IMAGE (gdk_image));
787   g_return_if_fail (mask == NULL ||
788                     GDK_IS_PIXMAP (mask));
789
790   g_object_freeze_notify (G_OBJECT (image));
791   
792   if (gdk_image)
793     g_object_ref (gdk_image);
794
795   if (mask)
796     g_object_ref (mask);
797
798   gtk_image_reset (image);
799
800   if (gdk_image)
801     {
802       image->storage_type = GTK_IMAGE_IMAGE;
803
804       image->data.image.image = gdk_image;
805       image->mask = mask;
806
807       gtk_image_update_size (image, gdk_image->width, gdk_image->height);
808     }
809   else
810     {
811       /* Clean up the mask if gdk_image was NULL */
812       if (mask)
813         g_object_unref (mask);
814     }
815
816   g_object_notify (G_OBJECT (image), "image");
817   g_object_notify (G_OBJECT (image), "mask");
818   
819   g_object_thaw_notify (G_OBJECT (image));
820 }
821
822 /**
823  * gtk_image_set_from_file:
824  * @image: a #GtkImage
825  * @filename: a filename or %NULL
826  *
827  * See gtk_image_new_from_file() for details.
828  * 
829  **/
830 void
831 gtk_image_set_from_file   (GtkImage    *image,
832                            const gchar *filename)
833 {
834   GtkImagePrivate *priv = GTK_IMAGE_GET_PRIVATE (image);
835   GdkPixbufAnimation *anim;
836   
837   g_return_if_fail (GTK_IS_IMAGE (image));
838
839   g_object_freeze_notify (G_OBJECT (image));
840   
841   gtk_image_reset (image);
842
843   if (filename == NULL)
844     {
845       priv->filename = NULL;
846       g_object_thaw_notify (G_OBJECT (image));
847       return;
848     }
849
850   anim = gdk_pixbuf_animation_new_from_file (filename, NULL);
851
852   if (anim == NULL)
853     {
854       gtk_image_set_from_stock (image,
855                                 GTK_STOCK_MISSING_IMAGE,
856                                 GTK_ICON_SIZE_BUTTON);
857       g_object_thaw_notify (G_OBJECT (image));
858       return;
859     }
860
861   /* We could just unconditionally set_from_animation,
862    * but it's nicer for memory if we toss the animation
863    * if it's just a single pixbuf
864    */
865
866   if (gdk_pixbuf_animation_is_static_image (anim))
867     gtk_image_set_from_pixbuf (image,
868                                gdk_pixbuf_animation_get_static_image (anim));
869   else
870     gtk_image_set_from_animation (image, anim);
871
872   g_object_unref (anim);
873
874   priv->filename = g_strdup (filename);
875   
876   g_object_thaw_notify (G_OBJECT (image));
877 }
878
879 /**
880  * gtk_image_set_from_pixbuf:
881  * @image: a #GtkImage
882  * @pixbuf: a #GdkPixbuf or %NULL
883  *
884  * See gtk_image_new_from_pixbuf() for details. 
885  * 
886  **/
887 void
888 gtk_image_set_from_pixbuf (GtkImage  *image,
889                            GdkPixbuf *pixbuf)
890 {
891   g_return_if_fail (GTK_IS_IMAGE (image));
892   g_return_if_fail (pixbuf == NULL ||
893                     GDK_IS_PIXBUF (pixbuf));
894
895   g_object_freeze_notify (G_OBJECT (image));
896   
897   if (pixbuf)
898     g_object_ref (pixbuf);
899
900   gtk_image_reset (image);
901
902   if (pixbuf != NULL)
903     {
904       image->storage_type = GTK_IMAGE_PIXBUF;
905
906       image->data.pixbuf.pixbuf = pixbuf;
907
908       gtk_image_update_size (image,
909                              gdk_pixbuf_get_width (pixbuf),
910                              gdk_pixbuf_get_height (pixbuf));
911     }
912
913   g_object_notify (G_OBJECT (image), "pixbuf");
914   
915   g_object_thaw_notify (G_OBJECT (image));
916 }
917
918 /**
919  * gtk_image_set_from_stock:
920  * @image: a #GtkImage
921  * @stock_id: a stock icon name
922  * @size: a stock icon size
923  *
924  * See gtk_image_new_from_stock() for details.
925  * 
926  **/
927 void
928 gtk_image_set_from_stock  (GtkImage       *image,
929                            const gchar    *stock_id,
930                            GtkIconSize     size)
931 {
932   gchar *new_id;
933   
934   g_return_if_fail (GTK_IS_IMAGE (image));
935
936   g_object_freeze_notify (G_OBJECT (image));
937
938   /* in case stock_id == image->data.stock.stock_id */
939   new_id = g_strdup (stock_id);
940   
941   gtk_image_reset (image);
942
943   if (new_id)
944     {
945       image->storage_type = GTK_IMAGE_STOCK;
946       
947       image->data.stock.stock_id = new_id;
948       image->icon_size = size;
949
950       /* Size is demand-computed in size request method
951        * if we're a stock image, since changing the
952        * style impacts the size request
953        */
954     }
955
956   g_object_notify (G_OBJECT (image), "stock");
957   g_object_notify (G_OBJECT (image), "icon-size");
958   
959   g_object_thaw_notify (G_OBJECT (image));
960 }
961
962 /**
963  * gtk_image_set_from_icon_set:
964  * @image: a #GtkImage
965  * @icon_set: a #GtkIconSet
966  * @size: a stock icon size
967  *
968  * See gtk_image_new_from_icon_set() for details.
969  * 
970  **/
971 void
972 gtk_image_set_from_icon_set  (GtkImage       *image,
973                               GtkIconSet     *icon_set,
974                               GtkIconSize     size)
975 {
976   g_return_if_fail (GTK_IS_IMAGE (image));
977
978   g_object_freeze_notify (G_OBJECT (image));
979   
980   if (icon_set)
981     gtk_icon_set_ref (icon_set);
982   
983   gtk_image_reset (image);
984
985   if (icon_set)
986     {      
987       image->storage_type = GTK_IMAGE_ICON_SET;
988       
989       image->data.icon_set.icon_set = icon_set;
990       image->icon_size = size;
991
992       /* Size is demand-computed in size request method
993        * if we're an icon set
994        */
995     }
996   
997   g_object_notify (G_OBJECT (image), "icon-set");
998   g_object_notify (G_OBJECT (image), "icon-size");
999   
1000   g_object_thaw_notify (G_OBJECT (image));
1001 }
1002
1003 /**
1004  * gtk_image_set_from_animation:
1005  * @image: a #GtkImage
1006  * @animation: the #GdkPixbufAnimation
1007  * 
1008  * Causes the #GtkImage to display the given animation (or display
1009  * nothing, if you set the animation to %NULL).
1010  **/
1011 void
1012 gtk_image_set_from_animation (GtkImage           *image,
1013                               GdkPixbufAnimation *animation)
1014 {
1015   g_return_if_fail (GTK_IS_IMAGE (image));
1016   g_return_if_fail (animation == NULL ||
1017                     GDK_IS_PIXBUF_ANIMATION (animation));
1018
1019   g_object_freeze_notify (G_OBJECT (image));
1020   
1021   if (animation)
1022     g_object_ref (animation);
1023
1024   gtk_image_reset (image);
1025
1026   if (animation != NULL)
1027     {
1028       image->storage_type = GTK_IMAGE_ANIMATION;
1029
1030       image->data.anim.anim = animation;
1031       image->data.anim.frame_timeout = 0;
1032       image->data.anim.iter = NULL;
1033       
1034       gtk_image_update_size (image,
1035                              gdk_pixbuf_animation_get_width (animation),
1036                              gdk_pixbuf_animation_get_height (animation));
1037     }
1038
1039   g_object_notify (G_OBJECT (image), "pixbuf-animation");
1040   
1041   g_object_thaw_notify (G_OBJECT (image));
1042 }
1043
1044 /**
1045  * gtk_image_set_from_icon_name:
1046  * @image: a #GtkImage
1047  * @icon_name: an icon name
1048  * @size: an icon size
1049  *
1050  * See gtk_image_new_from_icon_name() for details.
1051  * 
1052  * Since: 2.6
1053  **/
1054 void
1055 gtk_image_set_from_icon_name  (GtkImage       *image,
1056                                const gchar    *icon_name,
1057                                GtkIconSize     size)
1058 {
1059   gchar *new_name;
1060   
1061   g_return_if_fail (GTK_IS_IMAGE (image));
1062
1063   g_object_freeze_notify (G_OBJECT (image));
1064
1065   /* in case icon_name == image->data.name.icon_name */
1066   new_name = g_strdup (icon_name);
1067   
1068   gtk_image_reset (image);
1069
1070   if (new_name)
1071     {
1072       image->storage_type = GTK_IMAGE_ICON_NAME;
1073       
1074       image->data.name.icon_name = new_name;
1075       image->icon_size = size;
1076
1077       /* Size is demand-computed in size request method
1078        * if we're a icon theme image, since changing the
1079        * style impacts the size request
1080        */
1081     }
1082
1083   g_object_notify (G_OBJECT (image), "icon-name");
1084   g_object_notify (G_OBJECT (image), "icon-size");
1085   
1086   g_object_thaw_notify (G_OBJECT (image));
1087 }
1088
1089 /**
1090  * gtk_image_get_storage_type:
1091  * @image: a #GtkImage
1092  * 
1093  * Gets the type of representation being used by the #GtkImage
1094  * to store image data. If the #GtkImage has no image data,
1095  * the return value will be %GTK_IMAGE_EMPTY.
1096  * 
1097  * Return value: image representation being used
1098  **/
1099 GtkImageType
1100 gtk_image_get_storage_type (GtkImage *image)
1101 {
1102   g_return_val_if_fail (GTK_IS_IMAGE (image), GTK_IMAGE_EMPTY);
1103
1104   return image->storage_type;
1105 }
1106
1107 /**
1108  * gtk_image_get_pixmap:
1109  * @image: a #GtkImage
1110  * @pixmap: location to store the pixmap, or %NULL
1111  * @mask: location to store the mask, or %NULL
1112  *
1113  * Gets the pixmap and mask being displayed by the #GtkImage.
1114  * The storage type of the image must be %GTK_IMAGE_EMPTY or
1115  * %GTK_IMAGE_PIXMAP (see gtk_image_get_storage_type()).
1116  * The caller of this function does not own a reference to the
1117  * returned pixmap and mask.
1118  * 
1119  **/
1120 void
1121 gtk_image_get_pixmap (GtkImage   *image,
1122                       GdkPixmap **pixmap,
1123                       GdkBitmap **mask)
1124 {
1125   g_return_if_fail (GTK_IS_IMAGE (image)); 
1126   g_return_if_fail (image->storage_type == GTK_IMAGE_PIXMAP ||
1127                     image->storage_type == GTK_IMAGE_EMPTY);
1128   
1129   if (pixmap)
1130     *pixmap = image->data.pixmap.pixmap;
1131   
1132   if (mask)
1133     *mask = image->mask;
1134 }
1135
1136 /**
1137  * gtk_image_get_image:
1138  * @image: a #GtkImage
1139  * @gdk_image: return location for a #GtkImage
1140  * @mask: return location for a #GdkBitmap
1141  * 
1142  * Gets the #GdkImage and mask being displayed by the #GtkImage.
1143  * The storage type of the image must be %GTK_IMAGE_EMPTY or
1144  * %GTK_IMAGE_IMAGE (see gtk_image_get_storage_type()).
1145  * The caller of this function does not own a reference to the
1146  * returned image and mask.
1147  **/
1148 void
1149 gtk_image_get_image  (GtkImage   *image,
1150                       GdkImage  **gdk_image,
1151                       GdkBitmap **mask)
1152 {
1153   g_return_if_fail (GTK_IS_IMAGE (image));
1154   g_return_if_fail (image->storage_type == GTK_IMAGE_IMAGE ||
1155                     image->storage_type == GTK_IMAGE_EMPTY);
1156
1157   if (gdk_image)
1158     *gdk_image = image->data.image.image;
1159   
1160   if (mask)
1161     *mask = image->mask;
1162 }
1163
1164 /**
1165  * gtk_image_get_pixbuf:
1166  * @image: a #GtkImage
1167  *
1168  *
1169  * Gets the #GdkPixbuf being displayed by the #GtkImage.
1170  * The storage type of the image must be %GTK_IMAGE_EMPTY or
1171  * %GTK_IMAGE_PIXBUF (see gtk_image_get_storage_type()).
1172  * The caller of this function does not own a reference to the
1173  * returned pixbuf.
1174  * 
1175  * Return value: the displayed pixbuf, or %NULL if the image is empty
1176  **/
1177 GdkPixbuf*
1178 gtk_image_get_pixbuf (GtkImage *image)
1179 {
1180   g_return_val_if_fail (GTK_IS_IMAGE (image), NULL);
1181   g_return_val_if_fail (image->storage_type == GTK_IMAGE_PIXBUF ||
1182                         image->storage_type == GTK_IMAGE_EMPTY, NULL);
1183
1184   if (image->storage_type == GTK_IMAGE_EMPTY)
1185     image->data.pixbuf.pixbuf = NULL;
1186   
1187   return image->data.pixbuf.pixbuf;
1188 }
1189
1190 /**
1191  * gtk_image_get_stock:
1192  * @image: a #GtkImage
1193  * @stock_id: place to store a stock icon name
1194  * @size: place to store a stock icon size
1195  *
1196  * Gets the stock icon name and size being displayed by the #GtkImage.
1197  * The storage type of the image must be %GTK_IMAGE_EMPTY or
1198  * %GTK_IMAGE_STOCK (see gtk_image_get_storage_type()).
1199  * The returned string is owned by the #GtkImage and should not
1200  * be freed.
1201  * 
1202  **/
1203 void
1204 gtk_image_get_stock  (GtkImage        *image,
1205                       gchar          **stock_id,
1206                       GtkIconSize     *size)
1207 {
1208   g_return_if_fail (GTK_IS_IMAGE (image));
1209   g_return_if_fail (image->storage_type == GTK_IMAGE_STOCK ||
1210                     image->storage_type == GTK_IMAGE_EMPTY);
1211
1212   if (image->storage_type == GTK_IMAGE_EMPTY)
1213     image->data.stock.stock_id = NULL;
1214   
1215   if (stock_id)
1216     *stock_id = image->data.stock.stock_id;
1217
1218   if (size)
1219     *size = image->icon_size;
1220 }
1221
1222 /**
1223  * gtk_image_get_icon_set:
1224  * @image: a #GtkImage
1225  * @icon_set: location to store a #GtkIconSet
1226  * @size: location to store a stock icon size
1227  *
1228  * Gets the icon set and size being displayed by the #GtkImage.
1229  * The storage type of the image must be %GTK_IMAGE_EMPTY or
1230  * %GTK_IMAGE_ICON_SET (see gtk_image_get_storage_type()).
1231  * 
1232  **/
1233 void
1234 gtk_image_get_icon_set  (GtkImage        *image,
1235                          GtkIconSet     **icon_set,
1236                          GtkIconSize     *size)
1237 {
1238   g_return_if_fail (GTK_IS_IMAGE (image));
1239   g_return_if_fail (image->storage_type == GTK_IMAGE_ICON_SET ||
1240                     image->storage_type == GTK_IMAGE_EMPTY);
1241       
1242   if (icon_set)    
1243     *icon_set = image->data.icon_set.icon_set;
1244
1245   if (size)
1246     *size = image->icon_size;
1247 }
1248
1249 /**
1250  * gtk_image_get_animation:
1251  * @image: a #GtkImage
1252  *
1253  *
1254  * Gets the #GdkPixbufAnimation being displayed by the #GtkImage.
1255  * The storage type of the image must be %GTK_IMAGE_EMPTY or
1256  * %GTK_IMAGE_ANIMATION (see gtk_image_get_storage_type()).
1257  * The caller of this function does not own a reference to the
1258  * returned animation.
1259  * 
1260  * Return value: the displayed animation, or %NULL if the image is empty
1261  **/
1262 GdkPixbufAnimation*
1263 gtk_image_get_animation (GtkImage *image)
1264 {
1265   g_return_val_if_fail (GTK_IS_IMAGE (image), NULL);
1266   g_return_val_if_fail (image->storage_type == GTK_IMAGE_ANIMATION ||
1267                         image->storage_type == GTK_IMAGE_EMPTY,
1268                         NULL);
1269
1270   if (image->storage_type == GTK_IMAGE_EMPTY)
1271     image->data.anim.anim = NULL;
1272   
1273   return image->data.anim.anim;
1274 }
1275
1276 /**
1277  * gtk_image_get_icon_name:
1278  * @image: a #GtkImage
1279  * @icon_name: place to store an icon name
1280  * @size: place to store an icon size
1281  *
1282  * Gets the icon name and size being displayed by the #GtkImage.
1283  * The storage type of the image must be %GTK_IMAGE_EMPTY or
1284  * %GTK_IMAGE_ICON_NAME (see gtk_image_get_storage_type()).
1285  * The returned string is owned by the #GtkImage and should not
1286  * be freed.
1287  * 
1288  * Since: 2.6
1289  **/
1290 void
1291 gtk_image_get_icon_name  (GtkImage              *image,
1292                           G_CONST_RETURN gchar **icon_name,
1293                           GtkIconSize           *size)
1294 {
1295   g_return_if_fail (GTK_IS_IMAGE (image));
1296   g_return_if_fail (image->storage_type == GTK_IMAGE_ICON_NAME ||
1297                     image->storage_type == GTK_IMAGE_EMPTY);
1298
1299   if (image->storage_type == GTK_IMAGE_EMPTY)
1300     image->data.name.icon_name = NULL;
1301   
1302   if (icon_name)
1303     *icon_name = image->data.name.icon_name;
1304
1305   if (size)
1306     *size = image->icon_size;
1307 }
1308
1309 /**
1310  * gtk_image_new:
1311  * 
1312  * Creates a new empty #GtkImage widget.
1313  * 
1314  * Return value: a newly created #GtkImage widget. 
1315  **/
1316 GtkWidget*
1317 gtk_image_new (void)
1318 {
1319   return g_object_new (GTK_TYPE_IMAGE, NULL);
1320 }
1321
1322 void
1323 gtk_image_set (GtkImage  *image,
1324                GdkImage  *val,
1325                GdkBitmap *mask)
1326 {
1327   g_return_if_fail (GTK_IS_IMAGE (image));
1328
1329   gtk_image_set_from_image (image, val, mask);
1330 }
1331
1332 void
1333 gtk_image_get (GtkImage   *image,
1334                GdkImage  **val,
1335                GdkBitmap **mask)
1336 {
1337   g_return_if_fail (GTK_IS_IMAGE (image));
1338
1339   gtk_image_get_image (image, val, mask);
1340 }
1341
1342 static void
1343 gtk_image_reset_anim_iter (GtkImage *image)
1344 {
1345   if (image->storage_type == GTK_IMAGE_ANIMATION)
1346     {
1347       /* Reset the animation */
1348       
1349       if (image->data.anim.frame_timeout)
1350         {
1351           g_source_remove (image->data.anim.frame_timeout);
1352           image->data.anim.frame_timeout = 0;
1353         }
1354
1355       if (image->data.anim.iter)
1356         {
1357           g_object_unref (image->data.anim.iter);
1358           image->data.anim.iter = NULL;
1359         }
1360     }
1361 }
1362
1363 static void
1364 gtk_image_unmap (GtkWidget *widget)
1365 {
1366   gtk_image_reset_anim_iter (GTK_IMAGE (widget));
1367
1368   if (GTK_WIDGET_CLASS (parent_class)->unmap)
1369     GTK_WIDGET_CLASS (parent_class)->unmap (widget);
1370 }
1371
1372 static void
1373 gtk_image_unrealize (GtkWidget *widget)
1374 {
1375   gtk_image_reset_anim_iter (GTK_IMAGE (widget));
1376
1377   if (GTK_WIDGET_CLASS (parent_class)->unrealize)
1378     GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
1379 }
1380
1381 static gint
1382 animation_timeout (gpointer data)
1383 {
1384   GtkImage *image;
1385
1386   GDK_THREADS_ENTER ();
1387
1388   image = GTK_IMAGE (data);
1389   
1390   image->data.anim.frame_timeout = 0;
1391
1392   gdk_pixbuf_animation_iter_advance (image->data.anim.iter, NULL);
1393
1394   if (gdk_pixbuf_animation_iter_get_delay_time (image->data.anim.iter) >= 0)
1395     image->data.anim.frame_timeout =
1396       g_timeout_add (gdk_pixbuf_animation_iter_get_delay_time (image->data.anim.iter),
1397                      animation_timeout,
1398                      image);
1399   
1400   gtk_widget_queue_draw (GTK_WIDGET (image));
1401
1402   GDK_THREADS_LEAVE ();
1403
1404   return FALSE;
1405 }
1406
1407 static void
1408 icon_theme_changed (GtkImage *image)
1409 {
1410   if (image->data.name.pixbuf)
1411     g_object_unref (image->data.name.pixbuf);
1412   image->data.name.pixbuf = NULL;
1413
1414   gtk_widget_queue_draw (GTK_WIDGET (image));
1415 }
1416
1417 static void
1418 ensure_pixbuf_for_icon_name (GtkImage *image)
1419 {
1420   GtkImagePrivate *priv;
1421   GdkScreen *screen;
1422   GtkIconTheme *icon_theme;
1423   GtkSettings *settings;
1424   gint width, height;
1425   gint *sizes, *s, dist;
1426   GError *error = NULL;
1427
1428   g_return_if_fail (image->storage_type == GTK_IMAGE_ICON_NAME);
1429
1430   priv = GTK_IMAGE_GET_PRIVATE (image);
1431   screen = gtk_widget_get_screen (GTK_WIDGET (image));
1432   icon_theme = gtk_icon_theme_get_for_screen (screen);
1433   settings = gtk_settings_get_for_screen (screen);
1434   if (image->data.name.pixbuf == NULL)
1435     {
1436       if (priv->pixel_size != -1)
1437         {
1438           width = height = priv->pixel_size;
1439         }
1440       else if (!gtk_icon_size_lookup_for_settings (settings,
1441                                                    image->icon_size,
1442                                                    &width, &height))
1443         {
1444           if (image->icon_size == -1)
1445             {
1446               /* Find an available size close to 48 */
1447               sizes = gtk_icon_theme_get_icon_sizes (icon_theme, image->data.name.icon_name);
1448               dist = 100;
1449               width = height = 48;
1450               for (s = sizes; *s; s++)
1451                 {
1452                   if (*s == -1)
1453                     {
1454                       width = height = 48;
1455                       break;
1456                     }
1457                   if (*s < 48)
1458                     {
1459                       if (48 - *s < dist)
1460                         {
1461                           width = height = *s;
1462                           dist = 48 - *s;
1463                         }
1464                     }
1465                   else
1466                     {
1467                       if (*s - 48 < dist)
1468                         {
1469                           width = height = *s;
1470                           dist = *s - 48;
1471                         }
1472                     }
1473                 }
1474               g_free (sizes);
1475             }
1476           else
1477             {
1478               g_warning ("Invalid icon size %d\n", image->icon_size);
1479               width = height = 24;
1480             }
1481         }
1482       image->data.name.pixbuf =
1483         gtk_icon_theme_load_icon (icon_theme,
1484                                   image->data.name.icon_name,
1485                                   MIN (width, height), 0, &error);
1486       if (image->data.name.pixbuf == NULL)
1487         {
1488           g_error_free (error);
1489           image->data.name.pixbuf =
1490             gtk_widget_render_icon (GTK_WIDGET (image),
1491                                     GTK_STOCK_MISSING_IMAGE,
1492                                     image->icon_size,
1493                                     NULL);
1494         }
1495     }
1496 }
1497
1498 /*
1499  * Like gdk_rectangle_intersect (dest, src, dest), but make 
1500  * sure that the origin of dest is moved by an "even" offset. 
1501  * If necessary grow the intersection by one row or column 
1502  * to achieve this.
1503  *
1504  * This is necessary since we can't pass alignment information
1505  * for the pixelation pattern down to gdk_pixbuf_saturate_and_pixelate(), 
1506  * thus we have to makesure that the subimages are properly aligned.
1507  */
1508 static gboolean
1509 rectangle_intersect_even (GdkRectangle *src, 
1510                           GdkRectangle *dest)
1511 {
1512   gboolean isect;
1513   gint x, y;
1514
1515   x = dest->x;
1516   y = dest->y;
1517   isect = gdk_rectangle_intersect (dest, src, dest);
1518
1519   if ((dest->x - x + dest->y - y) % 2 != 0)
1520     {
1521       if (dest->x > x)
1522         {
1523           dest->x--;
1524           dest->width++;
1525         }
1526       else
1527         {
1528           dest->y--;
1529           dest->height++;
1530         }
1531     }
1532   
1533   return isect;
1534 }
1535
1536 static gint
1537 gtk_image_expose (GtkWidget      *widget,
1538                   GdkEventExpose *event)
1539 {
1540   g_return_val_if_fail (GTK_IS_IMAGE (widget), FALSE);
1541   g_return_val_if_fail (event != NULL, FALSE);
1542   
1543   if (GTK_WIDGET_MAPPED (widget) &&
1544       GTK_IMAGE (widget)->storage_type != GTK_IMAGE_EMPTY)
1545     {
1546       GtkImage *image;
1547       GtkMisc *misc;
1548       GdkRectangle area, image_bound;
1549       gfloat xalign;
1550       gint x, y, mask_x, mask_y;
1551       GdkBitmap *mask;
1552       GdkPixbuf *pixbuf;
1553       gboolean needs_state_transform;
1554
1555       image = GTK_IMAGE (widget);
1556       misc = GTK_MISC (widget);
1557
1558       area = event->area;
1559
1560       /* For stock items and icon sets, we lazily calculate
1561        * the size; we might get here between a queue_resize()
1562        * and size_request() if something explicitely forces
1563        * a redraw.
1564        */
1565       if (widget->requisition.width == 0 && widget->requisition.height == 0)
1566         gtk_image_calc_size (image);
1567       
1568       if (!gdk_rectangle_intersect (&area, &widget->allocation, &area))
1569         return FALSE;
1570
1571       if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
1572         xalign = misc->xalign;
1573       else
1574         xalign = 1.0 - misc->xalign;
1575   
1576       x = floor (widget->allocation.x + misc->xpad
1577                  + ((widget->allocation.width - widget->requisition.width) * xalign));
1578       y = floor (widget->allocation.y + misc->ypad 
1579                  + ((widget->allocation.height - widget->requisition.height) * misc->yalign));
1580       mask_x = x;
1581       mask_y = y;
1582       
1583       image_bound.x = x;
1584       image_bound.y = y;      
1585       image_bound.width = 0;
1586       image_bound.height = 0;      
1587
1588       mask = NULL;
1589       pixbuf = NULL;
1590       needs_state_transform = GTK_WIDGET_STATE (widget) != GTK_STATE_NORMAL;
1591       
1592       switch (image->storage_type)
1593         {
1594         case GTK_IMAGE_PIXMAP:
1595           mask = image->mask;
1596           gdk_drawable_get_size (image->data.pixmap.pixmap,
1597                                  &image_bound.width,
1598                                  &image_bound.height);
1599           if (rectangle_intersect_even (&area, &image_bound) &&
1600               needs_state_transform)
1601             {
1602               pixbuf = gdk_pixbuf_get_from_drawable (NULL,
1603                                                      image->data.pixmap.pixmap,
1604                                                      gtk_widget_get_colormap (widget),
1605                                                      image_bound.x - x, image_bound.y - y,
1606                                                      0, 0,
1607                                                      image_bound.width,
1608                                                      image_bound.height);
1609
1610               x = image_bound.x;
1611               y = image_bound.y;
1612             }
1613           
1614           break;
1615
1616         case GTK_IMAGE_IMAGE:
1617           mask = image->mask;
1618           image_bound.width = image->data.image.image->width;
1619           image_bound.height = image->data.image.image->height;
1620
1621           if (rectangle_intersect_even (&area, &image_bound) &&
1622               needs_state_transform)
1623             {
1624               pixbuf = gdk_pixbuf_get_from_image (NULL,
1625                                                   image->data.image.image,
1626                                                   gtk_widget_get_colormap (widget),
1627                                                   image_bound.x - x, image_bound.y - y,
1628                                                   0, 0,
1629                                                   image_bound.width,
1630                                                   image_bound.height);
1631
1632               x = image_bound.x;
1633               y = image_bound.y;
1634             }
1635           break;
1636
1637         case GTK_IMAGE_PIXBUF:
1638           image_bound.width = gdk_pixbuf_get_width (image->data.pixbuf.pixbuf);
1639           image_bound.height = gdk_pixbuf_get_height (image->data.pixbuf.pixbuf);            
1640
1641           if (rectangle_intersect_even (&area, &image_bound) &&
1642               needs_state_transform)
1643             {
1644               pixbuf = gdk_pixbuf_new_subpixbuf (image->data.pixbuf.pixbuf,
1645                                                  image_bound.x - x, image_bound.y - y,
1646                                                  image_bound.width, image_bound.height);
1647
1648               x = image_bound.x;
1649               y = image_bound.y;
1650             }
1651           else
1652             {
1653               pixbuf = image->data.pixbuf.pixbuf;
1654               g_object_ref (pixbuf);
1655             }
1656           break;
1657
1658         case GTK_IMAGE_STOCK:
1659           pixbuf = gtk_widget_render_icon (widget,
1660                                            image->data.stock.stock_id,
1661                                            image->icon_size,
1662                                            NULL);
1663           if (pixbuf)
1664             {              
1665               image_bound.width = gdk_pixbuf_get_width (pixbuf);
1666               image_bound.height = gdk_pixbuf_get_height (pixbuf);
1667             }
1668
1669           /* already done */
1670           needs_state_transform = FALSE;
1671           break;
1672
1673         case GTK_IMAGE_ICON_SET:
1674           pixbuf =
1675             gtk_icon_set_render_icon (image->data.icon_set.icon_set,
1676                                       widget->style,
1677                                       gtk_widget_get_direction (widget),
1678                                       GTK_WIDGET_STATE (widget),
1679                                       image->icon_size,
1680                                       widget,
1681                                       NULL);
1682
1683           if (pixbuf)
1684             {
1685               image_bound.width = gdk_pixbuf_get_width (pixbuf);
1686               image_bound.height = gdk_pixbuf_get_height (pixbuf);
1687             }
1688
1689           /* already done */
1690           needs_state_transform = FALSE;
1691           break;
1692
1693         case GTK_IMAGE_ANIMATION:
1694           {
1695             if (image->data.anim.iter == NULL)
1696               {
1697                 image->data.anim.iter = gdk_pixbuf_animation_get_iter (image->data.anim.anim, NULL);
1698                 
1699                 if (gdk_pixbuf_animation_iter_get_delay_time (image->data.anim.iter) >= 0)
1700                   image->data.anim.frame_timeout =
1701                     g_timeout_add (gdk_pixbuf_animation_iter_get_delay_time (image->data.anim.iter),
1702                                    animation_timeout,
1703                                    image);
1704               }
1705
1706             image_bound.width = gdk_pixbuf_animation_get_width (image->data.anim.anim);
1707             image_bound.height = gdk_pixbuf_animation_get_height (image->data.anim.anim);
1708                   
1709             /* don't advance the anim iter here, or we could get frame changes between two
1710              * exposes of different areas.
1711              */
1712             
1713             pixbuf = gdk_pixbuf_animation_iter_get_pixbuf (image->data.anim.iter);
1714             g_object_ref (pixbuf);
1715           }
1716           break;
1717
1718         case GTK_IMAGE_ICON_NAME:
1719           ensure_pixbuf_for_icon_name (image);
1720           pixbuf = image->data.name.pixbuf;
1721           if (pixbuf)
1722             {
1723               g_object_ref (pixbuf);
1724               image_bound.width = gdk_pixbuf_get_width (pixbuf);
1725               image_bound.height = gdk_pixbuf_get_height (pixbuf);
1726             }
1727           break;
1728
1729         case GTK_IMAGE_EMPTY:
1730           g_assert_not_reached ();
1731           break;
1732         }
1733
1734       if (mask)
1735         {
1736           gdk_gc_set_clip_mask (widget->style->black_gc, mask);
1737           gdk_gc_set_clip_origin (widget->style->black_gc, mask_x, mask_y);
1738         }
1739
1740       if (rectangle_intersect_even (&area, &image_bound))
1741         {
1742           if (pixbuf)
1743             {
1744               if (needs_state_transform)
1745                 {
1746                   GtkIconSource *source;
1747                   GdkPixbuf *rendered;
1748
1749                   source = gtk_icon_source_new ();
1750                   gtk_icon_source_set_pixbuf (source, pixbuf);
1751                   /* The size here is arbitrary; since size isn't
1752                    * wildcarded in the souce, it isn't supposed to be
1753                    * scaled by the engine function
1754                    */
1755                   gtk_icon_source_set_size (source,
1756                                             GTK_ICON_SIZE_SMALL_TOOLBAR);
1757                   gtk_icon_source_set_size_wildcarded (source, FALSE);
1758                   
1759                   rendered = gtk_style_render_icon (widget->style,
1760                                                     source,
1761                                                     gtk_widget_get_direction (widget),
1762                                                     GTK_WIDGET_STATE (widget),
1763                                                     /* arbitrary */
1764                                                     (GtkIconSize)-1,
1765                                                     widget,
1766                                                     "gtk-image");
1767
1768                   gtk_icon_source_free (source);
1769
1770                   g_object_unref (pixbuf);
1771                   pixbuf = rendered;
1772                 }
1773
1774               if (pixbuf)
1775                 {
1776                   gdk_draw_pixbuf (widget->window,
1777                                    widget->style->black_gc,
1778                                    pixbuf,
1779                                    image_bound.x - x,
1780                                    image_bound.y - y,
1781                                    image_bound.x,
1782                                    image_bound.y,
1783                                    image_bound.width,
1784                                    image_bound.height,
1785                                    GDK_RGB_DITHER_NORMAL,
1786                                    0, 0);
1787
1788                   g_object_unref (pixbuf);
1789                   pixbuf = NULL;
1790                 }
1791             }
1792           else
1793             {
1794               switch (image->storage_type)
1795                 {
1796                 case GTK_IMAGE_PIXMAP:
1797                   gdk_draw_drawable (widget->window,
1798                                      widget->style->black_gc,
1799                                      image->data.pixmap.pixmap,
1800                                      image_bound.x - x, image_bound.y - y,
1801                                      image_bound.x, image_bound.y,
1802                                      image_bound.width, image_bound.height);
1803                   break;
1804               
1805                 case GTK_IMAGE_IMAGE:
1806                   gdk_draw_image (widget->window,
1807                                   widget->style->black_gc,
1808                                   image->data.image.image,
1809                                   image_bound.x - x, image_bound.y - y,
1810                                   image_bound.x, image_bound.y,
1811                                   image_bound.width, image_bound.height);
1812                   break;
1813
1814                 case GTK_IMAGE_PIXBUF:
1815                 case GTK_IMAGE_STOCK:
1816                 case GTK_IMAGE_ICON_SET:
1817                 case GTK_IMAGE_ANIMATION:
1818                 case GTK_IMAGE_ICON_NAME:
1819                 case GTK_IMAGE_EMPTY:
1820                   g_assert_not_reached ();
1821                   break;
1822                 }
1823             }
1824         } /* if rectangle intersects */      
1825
1826       if (mask)
1827         {
1828           gdk_gc_set_clip_mask (widget->style->black_gc, NULL);
1829           gdk_gc_set_clip_origin (widget->style->black_gc, 0, 0);
1830         }
1831       
1832     } /* if widget is drawable */
1833
1834   return FALSE;
1835 }
1836
1837 /**
1838  * gtk_image_clear:
1839  * @image: a #GtkImage
1840  *
1841  * Resets the image to be empty.
1842  *
1843  * Since: 2.8
1844  */
1845 void
1846 gtk_image_clear (GtkImage *image)
1847 {
1848   GtkImagePrivate *priv;
1849
1850   g_return_if_fail (GTK_IS_IMAGE (image));
1851
1852   priv = GTK_IMAGE_GET_PRIVATE (image);
1853
1854   g_object_freeze_notify (G_OBJECT (image));
1855   
1856   if (image->storage_type != GTK_IMAGE_EMPTY)
1857     g_object_notify (G_OBJECT (image), "storage-type");
1858
1859   if (image->mask)
1860     {
1861       g_object_unref (image->mask);
1862       image->mask = NULL;
1863       g_object_notify (G_OBJECT (image), "mask");
1864     }
1865
1866   if (image->icon_size != DEFAULT_ICON_SIZE)
1867     {
1868       image->icon_size = DEFAULT_ICON_SIZE;
1869       g_object_notify (G_OBJECT (image), "icon-size");
1870     }
1871   
1872   switch (image->storage_type)
1873     {
1874     case GTK_IMAGE_PIXMAP:
1875
1876       if (image->data.pixmap.pixmap)
1877         g_object_unref (image->data.pixmap.pixmap);
1878       image->data.pixmap.pixmap = NULL;
1879       
1880       g_object_notify (G_OBJECT (image), "pixmap");
1881       
1882       break;
1883
1884     case GTK_IMAGE_IMAGE:
1885
1886       if (image->data.image.image)
1887         g_object_unref (image->data.image.image);
1888       image->data.image.image = NULL;
1889       
1890       g_object_notify (G_OBJECT (image), "image");
1891       
1892       break;
1893
1894     case GTK_IMAGE_PIXBUF:
1895
1896       if (image->data.pixbuf.pixbuf)
1897         g_object_unref (image->data.pixbuf.pixbuf);
1898
1899       g_object_notify (G_OBJECT (image), "pixbuf");
1900       
1901       break;
1902
1903     case GTK_IMAGE_STOCK:
1904
1905       g_free (image->data.stock.stock_id);
1906
1907       image->data.stock.stock_id = NULL;
1908       
1909       g_object_notify (G_OBJECT (image), "stock");      
1910       break;
1911
1912     case GTK_IMAGE_ICON_SET:
1913       if (image->data.icon_set.icon_set)
1914         gtk_icon_set_unref (image->data.icon_set.icon_set);
1915       image->data.icon_set.icon_set = NULL;
1916       
1917       g_object_notify (G_OBJECT (image), "icon-set");      
1918       break;
1919
1920     case GTK_IMAGE_ANIMATION:
1921       gtk_image_reset_anim_iter (image);
1922       
1923       if (image->data.anim.anim)
1924         g_object_unref (image->data.anim.anim);
1925       image->data.anim.anim = NULL;
1926       
1927       g_object_notify (G_OBJECT (image), "pixbuf-animation");
1928       
1929       break;
1930
1931     case GTK_IMAGE_ICON_NAME:
1932       if (image->data.name.icon_name)
1933         g_free (image->data.name.icon_name);
1934       image->data.name.icon_name = NULL;
1935       if (image->data.name.pixbuf)
1936         g_object_unref (image->data.name.pixbuf);
1937       image->data.name.pixbuf = NULL;
1938
1939       g_object_notify (G_OBJECT (image), "icon-name");
1940
1941       break;
1942       
1943     case GTK_IMAGE_EMPTY:
1944     default:
1945       break;
1946       
1947     }
1948
1949   if (priv->filename)
1950     {
1951       g_free (priv->filename);
1952       priv->filename = NULL;
1953       g_object_notify (G_OBJECT (image), "file");
1954     }
1955
1956   image->storage_type = GTK_IMAGE_EMPTY;
1957
1958   memset (&image->data, '\0', sizeof (image->data));
1959
1960   g_object_thaw_notify (G_OBJECT (image));
1961 }
1962
1963 static void
1964 gtk_image_reset (GtkImage *image)
1965 {
1966   gtk_image_clear (image);
1967
1968   gtk_image_update_size (image, 0, 0);
1969 }
1970
1971 static void
1972 gtk_image_calc_size (GtkImage *image)
1973 {
1974   GtkWidget *widget = GTK_WIDGET (image);
1975   GdkPixbuf *pixbuf = NULL;
1976   
1977   /* We update stock/icon set on every size request, because
1978    * the theme could have affected the size; for other kinds of
1979    * image, we just update the requisition when the image data
1980    * is set.
1981    */
1982   switch (image->storage_type)
1983     {
1984     case GTK_IMAGE_STOCK:
1985       pixbuf = gtk_widget_render_icon (widget,
1986                                        image->data.stock.stock_id,
1987                                        image->icon_size,
1988                                        NULL);
1989       break;
1990       
1991     case GTK_IMAGE_ICON_SET:
1992       pixbuf = gtk_icon_set_render_icon (image->data.icon_set.icon_set,
1993                                          widget->style,
1994                                          gtk_widget_get_direction (widget),
1995                                          GTK_WIDGET_STATE (widget),
1996                                          image->icon_size,
1997                                          widget,
1998                                          NULL);
1999       break;
2000     case GTK_IMAGE_ICON_NAME:
2001       ensure_pixbuf_for_icon_name (image);
2002       pixbuf = image->data.name.pixbuf;
2003       if (pixbuf) g_object_ref (pixbuf);
2004       break;
2005     default:
2006       break;
2007     }
2008
2009   if (pixbuf)
2010     {
2011       widget->requisition.width = gdk_pixbuf_get_width (pixbuf) + GTK_MISC (image)->xpad * 2;
2012       widget->requisition.height = gdk_pixbuf_get_height (pixbuf) + GTK_MISC (image)->ypad * 2;
2013
2014       g_object_unref (pixbuf);
2015     }
2016 }
2017
2018 static void
2019 gtk_image_size_request (GtkWidget      *widget,
2020                         GtkRequisition *requisition)
2021 {
2022   GtkImage *image;
2023   
2024   image = GTK_IMAGE (widget);
2025
2026   gtk_image_calc_size (image);
2027
2028   /* Chain up to default that simply reads current requisition */
2029   GTK_WIDGET_CLASS (parent_class)->size_request (widget, requisition);
2030 }
2031
2032 static void
2033 gtk_image_style_set (GtkWidget      *widget,
2034                      GtkStyle       *prev_style)
2035 {
2036   GtkImage *image;
2037
2038   image = GTK_IMAGE (widget);
2039
2040   if (GTK_WIDGET_CLASS (parent_class)->style_set)
2041     GTK_WIDGET_CLASS (parent_class)->style_set (widget, prev_style);
2042   
2043   icon_theme_changed (image);
2044 }
2045
2046 static void
2047 gtk_image_screen_changed (GtkWidget *widget,
2048                           GdkScreen *prev_screen)
2049 {
2050   GtkImage *image;
2051
2052   image = GTK_IMAGE (widget);
2053
2054   if (GTK_WIDGET_CLASS (parent_class)->screen_changed)
2055     GTK_WIDGET_CLASS (parent_class)->screen_changed (widget, prev_screen);
2056
2057   icon_theme_changed (image);
2058 }
2059
2060
2061 static void
2062 gtk_image_update_size (GtkImage *image,
2063                        gint      image_width,
2064                        gint      image_height)
2065 {
2066   GTK_WIDGET (image)->requisition.width = image_width + GTK_MISC (image)->xpad * 2;
2067   GTK_WIDGET (image)->requisition.height = image_height + GTK_MISC (image)->ypad * 2;
2068
2069   if (GTK_WIDGET_VISIBLE (image))
2070     gtk_widget_queue_resize (GTK_WIDGET (image));
2071 }
2072
2073
2074 /**
2075  * gtk_image_set_pixel_size:
2076  * @image: a #GtkImage
2077  * @pixel_size: the new pixel size
2078  * 
2079  * Sets the pixel size to use for named icons. If the pixel size is set
2080  * to a value != -1, it is used instead of the icon size set by
2081  * gtk_image_set_from_icon_name().
2082  *
2083  * Since: 2.6
2084  */
2085 void 
2086 gtk_image_set_pixel_size (GtkImage *image,
2087                           gint      pixel_size)
2088 {
2089   GtkImagePrivate *priv;
2090
2091   g_return_if_fail (GTK_IS_IMAGE (image));
2092   
2093   priv = GTK_IMAGE_GET_PRIVATE (image);
2094
2095   if (priv->pixel_size != pixel_size)
2096     {
2097       priv->pixel_size = pixel_size;
2098       
2099       if (image->storage_type == GTK_IMAGE_ICON_NAME)
2100         {
2101           if (image->data.name.pixbuf)
2102             {
2103               g_object_unref (image->data.name.pixbuf);
2104               image->data.name.pixbuf = NULL;
2105             }
2106           
2107           gtk_image_update_size (image, pixel_size, pixel_size);
2108         }
2109       
2110       g_object_notify (G_OBJECT (image), "pixel-size");
2111     }
2112 }
2113
2114 /**
2115  * gtk_image_get_pixel_size:
2116  * @image: a #GtkImage
2117  * 
2118  * Gets the pixel size used for named icons.
2119  *
2120  * Returns: the pixel size used for named icons.
2121  *
2122  * Since: 2.6
2123  */
2124 gint
2125 gtk_image_get_pixel_size (GtkImage *image)
2126 {
2127   GtkImagePrivate *priv;
2128
2129   g_return_val_if_fail (GTK_IS_IMAGE (image), -1);
2130   
2131   priv = GTK_IMAGE_GET_PRIVATE (image);
2132
2133   return priv->pixel_size;
2134 }
2135
2136 #ifdef G_OS_WIN32
2137
2138 #undef gtk_image_new_from_file
2139
2140 GtkWidget*
2141 gtk_image_new_from_file   (const gchar *filename)
2142 {
2143   gchar *utf8_filename = g_locale_to_utf8 (filename, -1, NULL, NULL, NULL);
2144   GtkWidget *retval;
2145
2146   retval = gtk_image_new_from_file_utf8 (utf8_filename);
2147
2148   g_free (utf8_filename);
2149
2150   return retval;
2151 }
2152
2153 #undef gtk_image_set_from_file
2154
2155 void
2156 gtk_image_set_from_file   (GtkImage    *image,
2157                            const gchar *filename)
2158 {
2159   gchar *utf8_filename = g_locale_to_utf8 (filename, -1, NULL, NULL, NULL);
2160
2161   gtk_image_set_from_file_utf8 (image, utf8_filename);
2162
2163   g_free (utf8_filename);
2164 }
2165
2166 #endif
2167
2168 #define __GTK_IMAGE_C__
2169 #include "gtkaliasdef.c"