]> Pileus Git - ~andy/gtk/blob - gtk/gtkimage.c
Add functions to allow threadsafe handling of idles and timeouts wrt. to
[~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->storage_type == GTK_IMAGE_ICON_NAME) 
1387     {
1388       if (image->data.name.pixbuf)
1389         g_object_unref (image->data.name.pixbuf);
1390       image->data.name.pixbuf = NULL;
1391
1392       gtk_widget_queue_draw (GTK_WIDGET (image));
1393     }
1394 }
1395
1396 static void
1397 ensure_pixbuf_for_icon_name (GtkImage *image)
1398 {
1399   GtkImagePrivate *priv;
1400   GdkScreen *screen;
1401   GtkIconTheme *icon_theme;
1402   GtkSettings *settings;
1403   gint width, height;
1404   gint *sizes, *s, dist;
1405   GError *error = NULL;
1406
1407   g_return_if_fail (image->storage_type == GTK_IMAGE_ICON_NAME);
1408
1409   priv = GTK_IMAGE_GET_PRIVATE (image);
1410   screen = gtk_widget_get_screen (GTK_WIDGET (image));
1411   icon_theme = gtk_icon_theme_get_for_screen (screen);
1412   settings = gtk_settings_get_for_screen (screen);
1413   if (image->data.name.pixbuf == NULL)
1414     {
1415       if (priv->pixel_size != -1)
1416         {
1417           width = height = priv->pixel_size;
1418         }
1419       else if (!gtk_icon_size_lookup_for_settings (settings,
1420                                                    image->icon_size,
1421                                                    &width, &height))
1422         {
1423           if (image->icon_size == -1)
1424             {
1425               /* Find an available size close to 48 */
1426               sizes = gtk_icon_theme_get_icon_sizes (icon_theme, image->data.name.icon_name);
1427               dist = 100;
1428               width = height = 48;
1429               for (s = sizes; *s; s++)
1430                 {
1431                   if (*s == -1)
1432                     {
1433                       width = height = 48;
1434                       break;
1435                     }
1436                   if (*s < 48)
1437                     {
1438                       if (48 - *s < dist)
1439                         {
1440                           width = height = *s;
1441                           dist = 48 - *s;
1442                         }
1443                     }
1444                   else
1445                     {
1446                       if (*s - 48 < dist)
1447                         {
1448                           width = height = *s;
1449                           dist = *s - 48;
1450                         }
1451                     }
1452                 }
1453               g_free (sizes);
1454             }
1455           else
1456             {
1457               g_warning ("Invalid icon size %d\n", image->icon_size);
1458               width = height = 24;
1459             }
1460         }
1461       image->data.name.pixbuf =
1462         gtk_icon_theme_load_icon (icon_theme,
1463                                   image->data.name.icon_name,
1464                                   MIN (width, height), 0, &error);
1465       if (image->data.name.pixbuf == NULL)
1466         {
1467           g_error_free (error);
1468           image->data.name.pixbuf =
1469             gtk_widget_render_icon (GTK_WIDGET (image),
1470                                     GTK_STOCK_MISSING_IMAGE,
1471                                     image->icon_size,
1472                                     NULL);
1473         }
1474     }
1475 }
1476
1477 /*
1478  * Like gdk_rectangle_intersect (dest, src, dest), but make 
1479  * sure that the origin of dest is moved by an "even" offset. 
1480  * If necessary grow the intersection by one row or column 
1481  * to achieve this.
1482  *
1483  * This is necessary since we can't pass alignment information
1484  * for the pixelation pattern down to gdk_pixbuf_saturate_and_pixelate(), 
1485  * thus we have to makesure that the subimages are properly aligned.
1486  */
1487 static gboolean
1488 rectangle_intersect_even (GdkRectangle *src, 
1489                           GdkRectangle *dest)
1490 {
1491   gboolean isect;
1492   gint x, y;
1493
1494   x = dest->x;
1495   y = dest->y;
1496   isect = gdk_rectangle_intersect (dest, src, dest);
1497
1498   if ((dest->x - x + dest->y - y) % 2 != 0)
1499     {
1500       if (dest->x > x)
1501         {
1502           dest->x--;
1503           dest->width++;
1504         }
1505       else
1506         {
1507           dest->y--;
1508           dest->height++;
1509         }
1510     }
1511   
1512   return isect;
1513 }
1514
1515 static gint
1516 gtk_image_expose (GtkWidget      *widget,
1517                   GdkEventExpose *event)
1518 {
1519   g_return_val_if_fail (GTK_IS_IMAGE (widget), FALSE);
1520   g_return_val_if_fail (event != NULL, FALSE);
1521   
1522   if (GTK_WIDGET_MAPPED (widget) &&
1523       GTK_IMAGE (widget)->storage_type != GTK_IMAGE_EMPTY)
1524     {
1525       GtkImage *image;
1526       GtkMisc *misc;
1527       GdkRectangle area, image_bound;
1528       gfloat xalign;
1529       gint x, y, mask_x, mask_y;
1530       GdkBitmap *mask;
1531       GdkPixbuf *pixbuf;
1532       gboolean needs_state_transform;
1533
1534       image = GTK_IMAGE (widget);
1535       misc = GTK_MISC (widget);
1536
1537       area = event->area;
1538
1539       /* For stock items and icon sets, we lazily calculate
1540        * the size; we might get here between a queue_resize()
1541        * and size_request() if something explicitely forces
1542        * a redraw.
1543        */
1544       if (widget->requisition.width == 0 && widget->requisition.height == 0)
1545         gtk_image_calc_size (image);
1546       
1547       if (!gdk_rectangle_intersect (&area, &widget->allocation, &area))
1548         return FALSE;
1549
1550       if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
1551         xalign = misc->xalign;
1552       else
1553         xalign = 1.0 - misc->xalign;
1554   
1555       x = floor (widget->allocation.x + misc->xpad
1556                  + ((widget->allocation.width - widget->requisition.width) * xalign));
1557       y = floor (widget->allocation.y + misc->ypad 
1558                  + ((widget->allocation.height - widget->requisition.height) * misc->yalign));
1559       mask_x = x;
1560       mask_y = y;
1561       
1562       image_bound.x = x;
1563       image_bound.y = y;      
1564       image_bound.width = 0;
1565       image_bound.height = 0;      
1566
1567       mask = NULL;
1568       pixbuf = NULL;
1569       needs_state_transform = GTK_WIDGET_STATE (widget) != GTK_STATE_NORMAL;
1570       
1571       switch (image->storage_type)
1572         {
1573         case GTK_IMAGE_PIXMAP:
1574           mask = image->mask;
1575           gdk_drawable_get_size (image->data.pixmap.pixmap,
1576                                  &image_bound.width,
1577                                  &image_bound.height);
1578           if (rectangle_intersect_even (&area, &image_bound) &&
1579               needs_state_transform)
1580             {
1581               pixbuf = gdk_pixbuf_get_from_drawable (NULL,
1582                                                      image->data.pixmap.pixmap,
1583                                                      gtk_widget_get_colormap (widget),
1584                                                      image_bound.x - x, image_bound.y - y,
1585                                                      0, 0,
1586                                                      image_bound.width,
1587                                                      image_bound.height);
1588
1589               x = image_bound.x;
1590               y = image_bound.y;
1591             }
1592           
1593           break;
1594
1595         case GTK_IMAGE_IMAGE:
1596           mask = image->mask;
1597           image_bound.width = image->data.image.image->width;
1598           image_bound.height = image->data.image.image->height;
1599
1600           if (rectangle_intersect_even (&area, &image_bound) &&
1601               needs_state_transform)
1602             {
1603               pixbuf = gdk_pixbuf_get_from_image (NULL,
1604                                                   image->data.image.image,
1605                                                   gtk_widget_get_colormap (widget),
1606                                                   image_bound.x - x, image_bound.y - y,
1607                                                   0, 0,
1608                                                   image_bound.width,
1609                                                   image_bound.height);
1610
1611               x = image_bound.x;
1612               y = image_bound.y;
1613             }
1614           break;
1615
1616         case GTK_IMAGE_PIXBUF:
1617           image_bound.width = gdk_pixbuf_get_width (image->data.pixbuf.pixbuf);
1618           image_bound.height = gdk_pixbuf_get_height (image->data.pixbuf.pixbuf);            
1619
1620           if (rectangle_intersect_even (&area, &image_bound) &&
1621               needs_state_transform)
1622             {
1623               pixbuf = gdk_pixbuf_new_subpixbuf (image->data.pixbuf.pixbuf,
1624                                                  image_bound.x - x, image_bound.y - y,
1625                                                  image_bound.width, image_bound.height);
1626
1627               x = image_bound.x;
1628               y = image_bound.y;
1629             }
1630           else
1631             {
1632               pixbuf = image->data.pixbuf.pixbuf;
1633               g_object_ref (pixbuf);
1634             }
1635           break;
1636
1637         case GTK_IMAGE_STOCK:
1638           pixbuf = gtk_widget_render_icon (widget,
1639                                            image->data.stock.stock_id,
1640                                            image->icon_size,
1641                                            NULL);
1642           if (pixbuf)
1643             {              
1644               image_bound.width = gdk_pixbuf_get_width (pixbuf);
1645               image_bound.height = gdk_pixbuf_get_height (pixbuf);
1646             }
1647
1648           /* already done */
1649           needs_state_transform = FALSE;
1650           break;
1651
1652         case GTK_IMAGE_ICON_SET:
1653           pixbuf =
1654             gtk_icon_set_render_icon (image->data.icon_set.icon_set,
1655                                       widget->style,
1656                                       gtk_widget_get_direction (widget),
1657                                       GTK_WIDGET_STATE (widget),
1658                                       image->icon_size,
1659                                       widget,
1660                                       NULL);
1661
1662           if (pixbuf)
1663             {
1664               image_bound.width = gdk_pixbuf_get_width (pixbuf);
1665               image_bound.height = gdk_pixbuf_get_height (pixbuf);
1666             }
1667
1668           /* already done */
1669           needs_state_transform = FALSE;
1670           break;
1671
1672         case GTK_IMAGE_ANIMATION:
1673           {
1674             if (image->data.anim.iter == NULL)
1675               {
1676                 image->data.anim.iter = gdk_pixbuf_animation_get_iter (image->data.anim.anim, NULL);
1677                 
1678                 if (gdk_pixbuf_animation_iter_get_delay_time (image->data.anim.iter) >= 0)
1679                   image->data.anim.frame_timeout =
1680                     g_timeout_add (gdk_pixbuf_animation_iter_get_delay_time (image->data.anim.iter),
1681                                    animation_timeout,
1682                                    image);
1683               }
1684
1685             image_bound.width = gdk_pixbuf_animation_get_width (image->data.anim.anim);
1686             image_bound.height = gdk_pixbuf_animation_get_height (image->data.anim.anim);
1687                   
1688             /* don't advance the anim iter here, or we could get frame changes between two
1689              * exposes of different areas.
1690              */
1691             
1692             pixbuf = gdk_pixbuf_animation_iter_get_pixbuf (image->data.anim.iter);
1693             g_object_ref (pixbuf);
1694           }
1695           break;
1696
1697         case GTK_IMAGE_ICON_NAME:
1698           ensure_pixbuf_for_icon_name (image);
1699           pixbuf = image->data.name.pixbuf;
1700           if (pixbuf)
1701             {
1702               g_object_ref (pixbuf);
1703               image_bound.width = gdk_pixbuf_get_width (pixbuf);
1704               image_bound.height = gdk_pixbuf_get_height (pixbuf);
1705             }
1706           break;
1707
1708         case GTK_IMAGE_EMPTY:
1709           g_assert_not_reached ();
1710           break;
1711         }
1712
1713       if (mask)
1714         {
1715           gdk_gc_set_clip_mask (widget->style->black_gc, mask);
1716           gdk_gc_set_clip_origin (widget->style->black_gc, mask_x, mask_y);
1717         }
1718
1719       if (rectangle_intersect_even (&area, &image_bound))
1720         {
1721           if (pixbuf)
1722             {
1723               if (needs_state_transform)
1724                 {
1725                   GtkIconSource *source;
1726                   GdkPixbuf *rendered;
1727
1728                   source = gtk_icon_source_new ();
1729                   gtk_icon_source_set_pixbuf (source, pixbuf);
1730                   /* The size here is arbitrary; since size isn't
1731                    * wildcarded in the souce, it isn't supposed to be
1732                    * scaled by the engine function
1733                    */
1734                   gtk_icon_source_set_size (source,
1735                                             GTK_ICON_SIZE_SMALL_TOOLBAR);
1736                   gtk_icon_source_set_size_wildcarded (source, FALSE);
1737                   
1738                   rendered = gtk_style_render_icon (widget->style,
1739                                                     source,
1740                                                     gtk_widget_get_direction (widget),
1741                                                     GTK_WIDGET_STATE (widget),
1742                                                     /* arbitrary */
1743                                                     (GtkIconSize)-1,
1744                                                     widget,
1745                                                     "gtk-image");
1746
1747                   gtk_icon_source_free (source);
1748
1749                   g_object_unref (pixbuf);
1750                   pixbuf = rendered;
1751                 }
1752
1753               if (pixbuf)
1754                 {
1755                   gdk_draw_pixbuf (widget->window,
1756                                    widget->style->black_gc,
1757                                    pixbuf,
1758                                    image_bound.x - x,
1759                                    image_bound.y - y,
1760                                    image_bound.x,
1761                                    image_bound.y,
1762                                    image_bound.width,
1763                                    image_bound.height,
1764                                    GDK_RGB_DITHER_NORMAL,
1765                                    0, 0);
1766                 }
1767             }
1768           else
1769             {
1770               switch (image->storage_type)
1771                 {
1772                 case GTK_IMAGE_PIXMAP:
1773                   gdk_draw_drawable (widget->window,
1774                                      widget->style->black_gc,
1775                                      image->data.pixmap.pixmap,
1776                                      image_bound.x - x, image_bound.y - y,
1777                                      image_bound.x, image_bound.y,
1778                                      image_bound.width, image_bound.height);
1779                   break;
1780               
1781                 case GTK_IMAGE_IMAGE:
1782                   gdk_draw_image (widget->window,
1783                                   widget->style->black_gc,
1784                                   image->data.image.image,
1785                                   image_bound.x - x, image_bound.y - y,
1786                                   image_bound.x, image_bound.y,
1787                                   image_bound.width, image_bound.height);
1788                   break;
1789
1790                 case GTK_IMAGE_PIXBUF:
1791                 case GTK_IMAGE_STOCK:
1792                 case GTK_IMAGE_ICON_SET:
1793                 case GTK_IMAGE_ANIMATION:
1794                 case GTK_IMAGE_ICON_NAME:
1795                 case GTK_IMAGE_EMPTY:
1796                   g_assert_not_reached ();
1797                   break;
1798                 }
1799             }
1800         } /* if rectangle intersects */      
1801
1802       if (mask)
1803         {
1804           gdk_gc_set_clip_mask (widget->style->black_gc, NULL);
1805           gdk_gc_set_clip_origin (widget->style->black_gc, 0, 0);
1806         }
1807       
1808       if (pixbuf)
1809         g_object_unref (pixbuf);
1810
1811     } /* if widget is drawable */
1812
1813   return FALSE;
1814 }
1815
1816 static void
1817 gtk_image_reset (GtkImage *image)
1818 {
1819   GtkImagePrivate *priv;
1820
1821   priv = GTK_IMAGE_GET_PRIVATE (image);
1822
1823   g_object_freeze_notify (G_OBJECT (image));
1824   
1825   if (image->storage_type != GTK_IMAGE_EMPTY)
1826     g_object_notify (G_OBJECT (image), "storage-type");
1827
1828   if (image->mask)
1829     {
1830       g_object_unref (image->mask);
1831       image->mask = NULL;
1832       g_object_notify (G_OBJECT (image), "mask");
1833     }
1834
1835   if (image->icon_size != DEFAULT_ICON_SIZE)
1836     {
1837       image->icon_size = DEFAULT_ICON_SIZE;
1838       g_object_notify (G_OBJECT (image), "icon-size");
1839     }
1840   
1841   switch (image->storage_type)
1842     {
1843     case GTK_IMAGE_PIXMAP:
1844
1845       if (image->data.pixmap.pixmap)
1846         g_object_unref (image->data.pixmap.pixmap);
1847       image->data.pixmap.pixmap = NULL;
1848       
1849       g_object_notify (G_OBJECT (image), "pixmap");
1850       
1851       break;
1852
1853     case GTK_IMAGE_IMAGE:
1854
1855       if (image->data.image.image)
1856         g_object_unref (image->data.image.image);
1857       image->data.image.image = NULL;
1858       
1859       g_object_notify (G_OBJECT (image), "image");
1860       
1861       break;
1862
1863     case GTK_IMAGE_PIXBUF:
1864
1865       if (image->data.pixbuf.pixbuf)
1866         g_object_unref (image->data.pixbuf.pixbuf);
1867
1868       g_object_notify (G_OBJECT (image), "pixbuf");
1869       
1870       break;
1871
1872     case GTK_IMAGE_STOCK:
1873
1874       g_free (image->data.stock.stock_id);
1875
1876       image->data.stock.stock_id = NULL;
1877       
1878       g_object_notify (G_OBJECT (image), "stock");      
1879       break;
1880
1881     case GTK_IMAGE_ICON_SET:
1882       if (image->data.icon_set.icon_set)
1883         gtk_icon_set_unref (image->data.icon_set.icon_set);
1884       image->data.icon_set.icon_set = NULL;
1885       
1886       g_object_notify (G_OBJECT (image), "icon-set");      
1887       break;
1888
1889     case GTK_IMAGE_ANIMATION:
1890       gtk_image_reset_anim_iter (image);
1891       
1892       if (image->data.anim.anim)
1893         g_object_unref (image->data.anim.anim);
1894       image->data.anim.anim = NULL;
1895       
1896       g_object_notify (G_OBJECT (image), "pixbuf-animation");
1897       
1898       break;
1899
1900     case GTK_IMAGE_ICON_NAME:
1901       if (image->data.name.icon_name)
1902         g_free (image->data.name.icon_name);
1903       image->data.name.icon_name = NULL;
1904       if (image->data.name.pixbuf)
1905         g_object_unref (image->data.name.pixbuf);
1906       image->data.name.pixbuf = NULL;
1907
1908       g_object_notify (G_OBJECT (image), "icon-name");
1909
1910       break;
1911       
1912     case GTK_IMAGE_EMPTY:
1913     default:
1914       break;
1915       
1916     }
1917
1918   if (priv->filename)
1919     {
1920       g_free (priv->filename);
1921       priv->filename = NULL;
1922       g_object_notify (G_OBJECT (image), "file");
1923     }
1924
1925   image->storage_type = GTK_IMAGE_EMPTY;
1926
1927   memset (&image->data, '\0', sizeof (image->data));
1928
1929   g_object_thaw_notify (G_OBJECT (image));
1930 }
1931
1932 /**
1933  * gtk_image_clear:
1934  * @image: a #GtkImage
1935  *
1936  * Resets the image to be empty.
1937  *
1938  * Since: 2.8
1939  */
1940 void
1941 gtk_image_clear (GtkImage *image)
1942 {
1943   gtk_image_reset (image);
1944
1945   gtk_image_update_size (image, 0, 0);
1946 }
1947
1948 static void
1949 gtk_image_calc_size (GtkImage *image)
1950 {
1951   GtkWidget *widget = GTK_WIDGET (image);
1952   GdkPixbuf *pixbuf = NULL;
1953   
1954   /* We update stock/icon set on every size request, because
1955    * the theme could have affected the size; for other kinds of
1956    * image, we just update the requisition when the image data
1957    * is set.
1958    */
1959   switch (image->storage_type)
1960     {
1961     case GTK_IMAGE_STOCK:
1962       pixbuf = gtk_widget_render_icon (widget,
1963                                        image->data.stock.stock_id,
1964                                        image->icon_size,
1965                                        NULL);
1966       break;
1967       
1968     case GTK_IMAGE_ICON_SET:
1969       pixbuf = gtk_icon_set_render_icon (image->data.icon_set.icon_set,
1970                                          widget->style,
1971                                          gtk_widget_get_direction (widget),
1972                                          GTK_WIDGET_STATE (widget),
1973                                          image->icon_size,
1974                                          widget,
1975                                          NULL);
1976       break;
1977     case GTK_IMAGE_ICON_NAME:
1978       ensure_pixbuf_for_icon_name (image);
1979       pixbuf = image->data.name.pixbuf;
1980       if (pixbuf) g_object_ref (pixbuf);
1981       break;
1982     default:
1983       break;
1984     }
1985
1986   if (pixbuf)
1987     {
1988       widget->requisition.width = gdk_pixbuf_get_width (pixbuf) + GTK_MISC (image)->xpad * 2;
1989       widget->requisition.height = gdk_pixbuf_get_height (pixbuf) + GTK_MISC (image)->ypad * 2;
1990
1991       g_object_unref (pixbuf);
1992     }
1993 }
1994
1995 static void
1996 gtk_image_size_request (GtkWidget      *widget,
1997                         GtkRequisition *requisition)
1998 {
1999   GtkImage *image;
2000   
2001   image = GTK_IMAGE (widget);
2002
2003   gtk_image_calc_size (image);
2004
2005   /* Chain up to default that simply reads current requisition */
2006   GTK_WIDGET_CLASS (gtk_image_parent_class)->size_request (widget, requisition);
2007 }
2008
2009 static void
2010 gtk_image_style_set (GtkWidget      *widget,
2011                      GtkStyle       *prev_style)
2012 {
2013   GtkImage *image;
2014
2015   image = GTK_IMAGE (widget);
2016
2017   if (GTK_WIDGET_CLASS (gtk_image_parent_class)->style_set)
2018     GTK_WIDGET_CLASS (gtk_image_parent_class)->style_set (widget, prev_style);
2019   
2020   icon_theme_changed (image);
2021 }
2022
2023 static void
2024 gtk_image_screen_changed (GtkWidget *widget,
2025                           GdkScreen *prev_screen)
2026 {
2027   GtkImage *image;
2028
2029   image = GTK_IMAGE (widget);
2030
2031   if (GTK_WIDGET_CLASS (gtk_image_parent_class)->screen_changed)
2032     GTK_WIDGET_CLASS (gtk_image_parent_class)->screen_changed (widget, prev_screen);
2033
2034   icon_theme_changed (image);
2035 }
2036
2037
2038 static void
2039 gtk_image_update_size (GtkImage *image,
2040                        gint      image_width,
2041                        gint      image_height)
2042 {
2043   GTK_WIDGET (image)->requisition.width = image_width + GTK_MISC (image)->xpad * 2;
2044   GTK_WIDGET (image)->requisition.height = image_height + GTK_MISC (image)->ypad * 2;
2045
2046   if (GTK_WIDGET_VISIBLE (image))
2047     gtk_widget_queue_resize (GTK_WIDGET (image));
2048 }
2049
2050
2051 /**
2052  * gtk_image_set_pixel_size:
2053  * @image: a #GtkImage
2054  * @pixel_size: the new pixel size
2055  * 
2056  * Sets the pixel size to use for named icons. If the pixel size is set
2057  * to a value != -1, it is used instead of the icon size set by
2058  * gtk_image_set_from_icon_name().
2059  *
2060  * Since: 2.6
2061  */
2062 void 
2063 gtk_image_set_pixel_size (GtkImage *image,
2064                           gint      pixel_size)
2065 {
2066   GtkImagePrivate *priv;
2067
2068   g_return_if_fail (GTK_IS_IMAGE (image));
2069   
2070   priv = GTK_IMAGE_GET_PRIVATE (image);
2071
2072   if (priv->pixel_size != pixel_size)
2073     {
2074       priv->pixel_size = pixel_size;
2075       
2076       if (image->storage_type == GTK_IMAGE_ICON_NAME)
2077         {
2078           if (image->data.name.pixbuf)
2079             {
2080               g_object_unref (image->data.name.pixbuf);
2081               image->data.name.pixbuf = NULL;
2082             }
2083           
2084           gtk_image_update_size (image, pixel_size, pixel_size);
2085         }
2086       
2087       g_object_notify (G_OBJECT (image), "pixel-size");
2088     }
2089 }
2090
2091 /**
2092  * gtk_image_get_pixel_size:
2093  * @image: a #GtkImage
2094  * 
2095  * Gets the pixel size used for named icons.
2096  *
2097  * Returns: the pixel size used for named icons.
2098  *
2099  * Since: 2.6
2100  */
2101 gint
2102 gtk_image_get_pixel_size (GtkImage *image)
2103 {
2104   GtkImagePrivate *priv;
2105
2106   g_return_val_if_fail (GTK_IS_IMAGE (image), -1);
2107   
2108   priv = GTK_IMAGE_GET_PRIVATE (image);
2109
2110   return priv->pixel_size;
2111 }
2112
2113 #ifdef G_OS_WIN32
2114
2115 #undef gtk_image_new_from_file
2116
2117 GtkWidget*
2118 gtk_image_new_from_file   (const gchar *filename)
2119 {
2120   gchar *utf8_filename = g_locale_to_utf8 (filename, -1, NULL, NULL, NULL);
2121   GtkWidget *retval;
2122
2123   retval = gtk_image_new_from_file_utf8 (utf8_filename);
2124
2125   g_free (utf8_filename);
2126
2127   return retval;
2128 }
2129
2130 #undef gtk_image_set_from_file
2131
2132 void
2133 gtk_image_set_from_file   (GtkImage    *image,
2134                            const gchar *filename)
2135 {
2136   gchar *utf8_filename = g_locale_to_utf8 (filename, -1, NULL, NULL, NULL);
2137
2138   gtk_image_set_from_file_utf8 (image, utf8_filename);
2139
2140   g_free (utf8_filename);
2141 }
2142
2143 #endif
2144
2145 #define __GTK_IMAGE_C__
2146 #include "gtkaliasdef.c"