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