]> Pileus Git - ~andy/gtk/blob - gtk/gtkimage.c
gdk/gdkdraw.c #include gdkcairo.h for gdk_cairo_create() declaration.
[~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, the image will be empty.
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           if (rectangle_intersect_even (&area, &image_bound) &&
1640               needs_state_transform)
1641             {
1642               pixbuf = gdk_pixbuf_new_subpixbuf (image->data.pixbuf.pixbuf,
1643                                                  image_bound.x - x, image_bound.y - y,
1644                                                  image_bound.width, image_bound.height);
1645
1646               x = image_bound.x;
1647               y = image_bound.y;
1648             }
1649           else
1650             {
1651               pixbuf = image->data.pixbuf.pixbuf;
1652               g_object_ref (pixbuf);
1653             }
1654           break;
1655
1656         case GTK_IMAGE_STOCK:
1657           pixbuf = gtk_widget_render_icon (widget,
1658                                            image->data.stock.stock_id,
1659                                            image->icon_size,
1660                                            NULL);
1661           if (pixbuf)
1662             {              
1663               image_bound.width = gdk_pixbuf_get_width (pixbuf);
1664               image_bound.height = gdk_pixbuf_get_height (pixbuf);
1665             }
1666
1667           /* already done */
1668           needs_state_transform = FALSE;
1669           break;
1670
1671         case GTK_IMAGE_ICON_SET:
1672           pixbuf =
1673             gtk_icon_set_render_icon (image->data.icon_set.icon_set,
1674                                       widget->style,
1675                                       gtk_widget_get_direction (widget),
1676                                       GTK_WIDGET_STATE (widget),
1677                                       image->icon_size,
1678                                       widget,
1679                                       NULL);
1680
1681           if (pixbuf)
1682             {
1683               image_bound.width = gdk_pixbuf_get_width (pixbuf);
1684               image_bound.height = gdk_pixbuf_get_height (pixbuf);
1685             }
1686
1687           /* already done */
1688           needs_state_transform = FALSE;
1689           break;
1690
1691         case GTK_IMAGE_ANIMATION:
1692           {
1693             if (image->data.anim.iter == NULL)
1694               {
1695                 image->data.anim.iter = gdk_pixbuf_animation_get_iter (image->data.anim.anim, NULL);
1696                 
1697                 if (gdk_pixbuf_animation_iter_get_delay_time (image->data.anim.iter) >= 0)
1698                   image->data.anim.frame_timeout =
1699                     g_timeout_add (gdk_pixbuf_animation_iter_get_delay_time (image->data.anim.iter),
1700                                    animation_timeout,
1701                                    image);
1702               }
1703
1704             image_bound.width = gdk_pixbuf_animation_get_width (image->data.anim.anim);
1705             image_bound.height = gdk_pixbuf_animation_get_height (image->data.anim.anim);
1706                   
1707             /* don't advance the anim iter here, or we could get frame changes between two
1708              * exposes of different areas.
1709              */
1710             
1711             pixbuf = gdk_pixbuf_animation_iter_get_pixbuf (image->data.anim.iter);
1712             g_object_ref (pixbuf);
1713           }
1714           break;
1715
1716         case GTK_IMAGE_ICON_NAME:
1717           ensure_pixbuf_for_icon_name (image);
1718           pixbuf = image->data.name.pixbuf;
1719           if (pixbuf)
1720             {
1721               g_object_ref (pixbuf);
1722               image_bound.width = gdk_pixbuf_get_width (pixbuf);
1723               image_bound.height = gdk_pixbuf_get_height (pixbuf);
1724             }
1725           break;
1726
1727         case GTK_IMAGE_EMPTY:
1728           g_assert_not_reached ();
1729           break;
1730         }
1731
1732       if (mask)
1733         {
1734           gdk_gc_set_clip_mask (widget->style->black_gc, mask);
1735           gdk_gc_set_clip_origin (widget->style->black_gc, mask_x, mask_y);
1736         }
1737
1738       if (rectangle_intersect_even (&area, &image_bound))
1739         {
1740           if (pixbuf)
1741             {
1742               if (needs_state_transform)
1743                 {
1744                   GtkIconSource *source;
1745                   GdkPixbuf *rendered;
1746
1747                   source = gtk_icon_source_new ();
1748                   gtk_icon_source_set_pixbuf (source, pixbuf);
1749                   /* The size here is arbitrary; since size isn't
1750                    * wildcarded in the souce, it isn't supposed to be
1751                    * scaled by the engine function
1752                    */
1753                   gtk_icon_source_set_size (source,
1754                                             GTK_ICON_SIZE_SMALL_TOOLBAR);
1755                   gtk_icon_source_set_size_wildcarded (source, FALSE);
1756                   
1757                   rendered = gtk_style_render_icon (widget->style,
1758                                                     source,
1759                                                     gtk_widget_get_direction (widget),
1760                                                     GTK_WIDGET_STATE (widget),
1761                                                     /* arbitrary */
1762                                                     (GtkIconSize)-1,
1763                                                     widget,
1764                                                     "gtk-image");
1765
1766                   gtk_icon_source_free (source);
1767
1768                   g_object_unref (pixbuf);
1769                   pixbuf = rendered;
1770                 }
1771
1772               if (pixbuf)
1773                 {
1774                   gdk_draw_pixbuf (widget->window,
1775                                    widget->style->black_gc,
1776                                    pixbuf,
1777                                    image_bound.x - x,
1778                                    image_bound.y - y,
1779                                    image_bound.x,
1780                                    image_bound.y,
1781                                    image_bound.width,
1782                                    image_bound.height,
1783                                    GDK_RGB_DITHER_NORMAL,
1784                                    0, 0);
1785
1786                   g_object_unref (pixbuf);
1787                   pixbuf = NULL;
1788                 }
1789             }
1790           else
1791             {
1792               switch (image->storage_type)
1793                 {
1794                 case GTK_IMAGE_PIXMAP:
1795                   gdk_draw_drawable (widget->window,
1796                                      widget->style->black_gc,
1797                                      image->data.pixmap.pixmap,
1798                                      image_bound.x - x, image_bound.y - y,
1799                                      image_bound.x, image_bound.y,
1800                                      image_bound.width, image_bound.height);
1801                   break;
1802               
1803                 case GTK_IMAGE_IMAGE:
1804                   gdk_draw_image (widget->window,
1805                                   widget->style->black_gc,
1806                                   image->data.image.image,
1807                                   image_bound.x - x, image_bound.y - y,
1808                                   image_bound.x, image_bound.y,
1809                                   image_bound.width, image_bound.height);
1810                   break;
1811
1812                 case GTK_IMAGE_PIXBUF:
1813                 case GTK_IMAGE_STOCK:
1814                 case GTK_IMAGE_ICON_SET:
1815                 case GTK_IMAGE_ANIMATION:
1816                 case GTK_IMAGE_ICON_NAME:
1817                 case GTK_IMAGE_EMPTY:
1818                   g_assert_not_reached ();
1819                   break;
1820                 }
1821             }
1822         } /* if rectangle intersects */      
1823
1824       if (mask)
1825         {
1826           gdk_gc_set_clip_mask (widget->style->black_gc, NULL);
1827           gdk_gc_set_clip_origin (widget->style->black_gc, 0, 0);
1828         }
1829       
1830     } /* if widget is drawable */
1831
1832   return FALSE;
1833 }
1834
1835 static void
1836 gtk_image_clear (GtkImage *image)
1837 {
1838   g_object_freeze_notify (G_OBJECT (image));
1839   
1840   if (image->storage_type != GTK_IMAGE_EMPTY)
1841     g_object_notify (G_OBJECT (image), "storage-type");
1842
1843   if (image->mask)
1844     {
1845       g_object_unref (image->mask);
1846       image->mask = NULL;
1847       g_object_notify (G_OBJECT (image), "mask");
1848     }
1849
1850   if (image->icon_size != DEFAULT_ICON_SIZE)
1851     {
1852       image->icon_size = DEFAULT_ICON_SIZE;
1853       g_object_notify (G_OBJECT (image), "icon-size");
1854     }
1855   
1856   switch (image->storage_type)
1857     {
1858     case GTK_IMAGE_PIXMAP:
1859
1860       if (image->data.pixmap.pixmap)
1861         g_object_unref (image->data.pixmap.pixmap);
1862       image->data.pixmap.pixmap = NULL;
1863       
1864       g_object_notify (G_OBJECT (image), "pixmap");
1865       
1866       break;
1867
1868     case GTK_IMAGE_IMAGE:
1869
1870       if (image->data.image.image)
1871         g_object_unref (image->data.image.image);
1872       image->data.image.image = NULL;
1873       
1874       g_object_notify (G_OBJECT (image), "image");
1875       
1876       break;
1877
1878     case GTK_IMAGE_PIXBUF:
1879
1880       if (image->data.pixbuf.pixbuf)
1881         g_object_unref (image->data.pixbuf.pixbuf);
1882
1883       g_object_notify (G_OBJECT (image), "pixbuf");
1884       
1885       break;
1886
1887     case GTK_IMAGE_STOCK:
1888
1889       g_free (image->data.stock.stock_id);
1890
1891       image->data.stock.stock_id = NULL;
1892       
1893       g_object_notify (G_OBJECT (image), "stock");      
1894       break;
1895
1896     case GTK_IMAGE_ICON_SET:
1897       if (image->data.icon_set.icon_set)
1898         gtk_icon_set_unref (image->data.icon_set.icon_set);
1899       image->data.icon_set.icon_set = NULL;
1900       
1901       g_object_notify (G_OBJECT (image), "icon-set");      
1902       break;
1903
1904     case GTK_IMAGE_ANIMATION:
1905       gtk_image_reset_anim_iter (image);
1906       
1907       if (image->data.anim.anim)
1908         g_object_unref (image->data.anim.anim);
1909       image->data.anim.anim = NULL;
1910       
1911       g_object_notify (G_OBJECT (image), "pixbuf-animation");
1912       
1913       break;
1914
1915     case GTK_IMAGE_ICON_NAME:
1916       if (image->data.name.icon_name)
1917         g_free (image->data.name.icon_name);
1918       image->data.name.icon_name = NULL;
1919       if (image->data.name.pixbuf)
1920         g_object_unref (image->data.name.pixbuf);
1921       image->data.name.pixbuf = NULL;
1922
1923       g_object_notify (G_OBJECT (image), "icon-name");
1924
1925       break;
1926       
1927     case GTK_IMAGE_EMPTY:
1928     default:
1929       break;
1930       
1931     }
1932
1933   image->storage_type = GTK_IMAGE_EMPTY;
1934
1935   memset (&image->data, '\0', sizeof (image->data));
1936
1937   g_object_thaw_notify (G_OBJECT (image));
1938 }
1939
1940 static void
1941 gtk_image_reset (GtkImage *image)
1942 {
1943   gtk_image_clear (image);
1944
1945   gtk_image_update_size (image, 0, 0);
1946 }
1947
1948 static void
1949 gtk_image_calc_size (GtkImage *image)
1950 {
1951   GtkWidget *widget = GTK_WIDGET (image);
1952   GdkPixbuf *pixbuf = NULL;
1953   
1954   /* We update stock/icon set on every size request, because
1955    * the theme could have affected the size; for other kinds of
1956    * image, we just update the requisition when the image data
1957    * is set.
1958    */
1959   switch (image->storage_type)
1960     {
1961     case GTK_IMAGE_STOCK:
1962       pixbuf = gtk_widget_render_icon (widget,
1963                                        image->data.stock.stock_id,
1964                                        image->icon_size,
1965                                        NULL);
1966       break;
1967       
1968     case GTK_IMAGE_ICON_SET:
1969       pixbuf = gtk_icon_set_render_icon (image->data.icon_set.icon_set,
1970                                          widget->style,
1971                                          gtk_widget_get_direction (widget),
1972                                          GTK_WIDGET_STATE (widget),
1973                                          image->icon_size,
1974                                          widget,
1975                                          NULL);
1976       break;
1977     case GTK_IMAGE_ICON_NAME:
1978       ensure_pixbuf_for_icon_name (image);
1979       pixbuf = image->data.name.pixbuf;
1980       if (pixbuf) g_object_ref (pixbuf);
1981       break;
1982     default:
1983       break;
1984     }
1985
1986   if (pixbuf)
1987     {
1988       widget->requisition.width = gdk_pixbuf_get_width (pixbuf) + GTK_MISC (image)->xpad * 2;
1989       widget->requisition.height = gdk_pixbuf_get_height (pixbuf) + GTK_MISC (image)->ypad * 2;
1990
1991       g_object_unref (pixbuf);
1992     }
1993 }
1994
1995 static void
1996 gtk_image_size_request (GtkWidget      *widget,
1997                         GtkRequisition *requisition)
1998 {
1999   GtkImage *image;
2000   
2001   image = GTK_IMAGE (widget);
2002
2003   gtk_image_calc_size (image);
2004
2005   /* Chain up to default that simply reads current requisition */
2006   GTK_WIDGET_CLASS (parent_class)->size_request (widget, requisition);
2007 }
2008
2009 static void
2010 gtk_image_style_set (GtkWidget      *widget,
2011                      GtkStyle       *prev_style)
2012 {
2013   GtkImage *image;
2014
2015   image = GTK_IMAGE (widget);
2016
2017   if (GTK_WIDGET_CLASS (parent_class)->style_set)
2018     GTK_WIDGET_CLASS (parent_class)->style_set (widget, prev_style);
2019   
2020   icon_theme_changed (image);
2021 }
2022
2023 static void
2024 gtk_image_screen_changed (GtkWidget *widget,
2025                           GdkScreen *prev_screen)
2026 {
2027   GtkImage *image;
2028
2029   image = GTK_IMAGE (widget);
2030
2031   if (GTK_WIDGET_CLASS (parent_class)->screen_changed)
2032     GTK_WIDGET_CLASS (parent_class)->screen_changed (widget, prev_screen);
2033
2034   icon_theme_changed (image);
2035 }
2036
2037
2038 static void
2039 gtk_image_update_size (GtkImage *image,
2040                        gint      image_width,
2041                        gint      image_height)
2042 {
2043   GTK_WIDGET (image)->requisition.width = image_width + GTK_MISC (image)->xpad * 2;
2044   GTK_WIDGET (image)->requisition.height = image_height + GTK_MISC (image)->ypad * 2;
2045
2046   if (GTK_WIDGET_VISIBLE (image))
2047     gtk_widget_queue_resize (GTK_WIDGET (image));
2048 }
2049
2050
2051 /**
2052  * gtk_image_set_pixel_size:
2053  * @image: a #GtkImage
2054  * @pixel_size: the new pixel size
2055  * 
2056  * Sets the pixel size to use for named icons. If the pixel size is set
2057  * to a value != -1, it is used instead of the icon size set by
2058  * gtk_image_set_from_icon_name().
2059  *
2060  * Since: 2.6
2061  */
2062 void 
2063 gtk_image_set_pixel_size (GtkImage *image,
2064                           gint      pixel_size)
2065 {
2066   GtkImagePrivate *priv;
2067
2068   g_return_if_fail (GTK_IS_IMAGE (image));
2069   
2070   priv = GTK_IMAGE_GET_PRIVATE (image);
2071
2072   if (priv->pixel_size != pixel_size)
2073     {
2074       priv->pixel_size = pixel_size;
2075       
2076       if (image->storage_type == GTK_IMAGE_ICON_NAME)
2077         {
2078           if (image->data.name.pixbuf)
2079             {
2080               g_object_unref (image->data.name.pixbuf);
2081               image->data.name.pixbuf = NULL;
2082             }
2083           
2084           gtk_image_update_size (image, pixel_size, pixel_size);
2085         }
2086       
2087       g_object_notify (G_OBJECT (image), "pixel-size");
2088     }
2089 }
2090
2091 /**
2092  * gtk_image_get_pixel_size:
2093  * @image: a #GtkImage
2094  * 
2095  * Gets the pixel size used for named icons.
2096  *
2097  * Returns: the pixel size used for named icons.
2098  *
2099  * Since: 2.6
2100  */
2101 gint
2102 gtk_image_get_pixel_size (GtkImage *image)
2103 {
2104   GtkImagePrivate *priv;
2105
2106   g_return_val_if_fail (GTK_IS_IMAGE (image), -1);
2107   
2108   priv = GTK_IMAGE_GET_PRIVATE (image);
2109
2110   return priv->pixel_size;
2111 }
2112
2113 #ifdef G_OS_WIN32
2114
2115 #undef gtk_image_new_from_file
2116
2117 GtkWidget*
2118 gtk_image_new_from_file   (const gchar *filename)
2119 {
2120   gchar *utf8_filename = g_locale_to_utf8 (filename, -1, NULL, NULL, NULL);
2121   GtkWidget *retval;
2122
2123   retval = gtk_image_new_from_file_utf8 (utf8_filename);
2124
2125   g_free (utf8_filename);
2126
2127   return retval;
2128 }
2129
2130 #undef gtk_image_set_from_file
2131
2132 void
2133 gtk_image_set_from_file   (GtkImage    *image,
2134                            const gchar *filename)
2135 {
2136   gchar *utf8_filename = g_locale_to_utf8 (filename, -1, NULL, NULL, NULL);
2137
2138   gtk_image_set_from_file_utf8 (image, utf8_filename);
2139
2140   g_free (utf8_filename);
2141 }
2142
2143 #endif
2144
2145 #define __GTK_IMAGE_C__
2146 #include "gtkaliasdef.c"