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