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