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