]> Pileus Git - ~andy/gtk/blob - gtk/gtkicontheme.c
Merge branch 'notebooks-without-mouse-scrolling'
[~andy/gtk] / gtk / gtkicontheme.c
1 /* GtkIconTheme - a loader for icon themes
2  * gtk-icon-theme.c Copyright (C) 2002, 2003 Red Hat, Inc.
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 #include "config.h"
21
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #ifdef HAVE_UNISTD_H
25 #include <unistd.h>
26 #endif
27 #include <string.h>
28 #include <stdlib.h>
29 #include <glib.h>
30 #include <glib/gstdio.h>
31
32 #ifdef G_OS_WIN32
33 #ifndef S_ISDIR
34 #define S_ISDIR(mode) ((mode)&_S_IFDIR)
35 #endif
36 #define WIN32_MEAN_AND_LEAN
37 #include <windows.h>
38 #include "win32/gdkwin32.h"
39 #endif /* G_OS_WIN32 */
40
41 #include "gtkicontheme.h"
42 #include "gtkiconfactory.h"
43 #include "gtkiconcache.h"
44 #include "gtkbuiltincache.h"
45 #include "gtkintl.h"
46 #include "gtkmain.h"
47 #include "gtksettings.h"
48 #include "gtkprivate.h"
49
50 #define DEFAULT_THEME_NAME "hicolor"
51
52 typedef enum
53 {
54   ICON_THEME_DIR_FIXED,  
55   ICON_THEME_DIR_SCALABLE,  
56   ICON_THEME_DIR_THRESHOLD,
57   ICON_THEME_DIR_UNTHEMED
58 } IconThemeDirType;
59
60 /* In reverse search order: */
61 typedef enum
62 {
63   ICON_SUFFIX_NONE = 0,
64   ICON_SUFFIX_XPM = 1 << 0,
65   ICON_SUFFIX_SVG = 1 << 1,
66   ICON_SUFFIX_PNG = 1 << 2,
67   HAS_ICON_FILE = 1 << 3
68 } IconSuffix;
69
70
71 struct _GtkIconThemePrivate
72 {
73   guint custom_theme        : 1;
74   guint is_screen_singleton : 1;
75   guint pixbuf_supports_svg : 1;
76   guint themes_valid        : 1;
77   guint check_reload        : 1;
78   guint loading_themes      : 1;
79   
80   char *current_theme;
81   char *fallback_theme;
82   char **search_path;
83   int search_path_len;
84
85   /* A list of all the themes needed to look up icons.
86    * In search order, without duplicates
87    */
88   GList *themes;
89   GHashTable *unthemed_icons;
90   
91   /* Note: The keys of this hashtable are owned by the
92    * themedir and unthemed hashtables.
93    */
94   GHashTable *all_icons;
95
96   /* GdkScreen for the icon theme (may be NULL)
97    */
98   GdkScreen *screen;
99   
100   /* time when we last stat:ed for theme changes */
101   long last_stat_time;
102   GList *dir_mtimes;
103
104   gulong reset_styles_idle;
105 };
106
107 struct _GtkIconInfo
108 {
109   /* Information about the source
110    */
111   gchar *filename;
112   GLoadableIcon *loadable;
113   GSList *emblem_infos;
114
115   /* Cache pixbuf (if there is any) */
116   GdkPixbuf *cache_pixbuf;
117
118   GtkIconData *data;
119   
120   /* Information about the directory where
121    * the source was found
122    */
123   IconThemeDirType dir_type;
124   gint dir_size;
125   gint threshold;
126
127   /* Parameters influencing the scaled icon
128    */
129   gint desired_size;
130   guint raw_coordinates : 1;
131   guint forced_size     : 1;
132
133   /* Cached information if we go ahead and try to load
134    * the icon.
135    */
136   GdkPixbuf *pixbuf;
137   GError *load_error;
138   gdouble scale;
139
140   guint ref_count;
141 };
142
143 typedef struct
144 {
145   char *name;
146   char *display_name;
147   char *comment;
148   char *example;
149
150   /* In search order */
151   GList *dirs;
152 } IconTheme;
153
154 typedef struct
155 {
156   IconThemeDirType type;
157   GQuark context;
158
159   int size;
160   int min_size;
161   int max_size;
162   int threshold;
163
164   char *dir;
165   char *subdir;
166   int subdir_index;
167   
168   GtkIconCache *cache;
169   
170   GHashTable *icons;
171   GHashTable *icon_data;
172 } IconThemeDir;
173
174 typedef struct
175 {
176   char *svg_filename;
177   char *no_svg_filename;
178 } UnthemedIcon;
179
180 typedef struct
181 {
182   gint size;
183   GdkPixbuf *pixbuf;
184 } BuiltinIcon;
185
186 typedef struct 
187 {
188   char *dir;
189   time_t mtime; /* 0 == not existing or not a dir */
190
191   GtkIconCache *cache;
192 } IconThemeDirMtime;
193
194 static void  gtk_icon_theme_finalize   (GObject              *object);
195 static void  theme_dir_destroy         (IconThemeDir         *dir);
196
197 static void         theme_destroy     (IconTheme        *theme);
198 static GtkIconInfo *theme_lookup_icon (IconTheme        *theme,
199                                        const char       *icon_name,
200                                        int               size,
201                                        gboolean          allow_svg,
202                                        gboolean          use_default_icons);
203 static void         theme_list_icons  (IconTheme        *theme,
204                                        GHashTable       *icons,
205                                        GQuark            context);
206 static void         theme_list_contexts  (IconTheme        *theme,
207                                           GHashTable       *contexts);
208 static void         theme_subdir_load (GtkIconTheme     *icon_theme,
209                                        IconTheme        *theme,
210                                        GKeyFile         *theme_file,
211                                        char             *subdir);
212 static void         do_theme_change   (GtkIconTheme     *icon_theme);
213
214 static void     blow_themes               (GtkIconTheme    *icon_themes);
215 static gboolean rescan_themes             (GtkIconTheme    *icon_themes);
216
217 static void  icon_data_free            (GtkIconData     *icon_data);
218 static void load_icon_data             (IconThemeDir    *dir,
219                                         const char      *path,
220                                         const char      *name);
221
222 static IconSuffix theme_dir_get_icon_suffix (IconThemeDir *dir,
223                                              const gchar  *icon_name,
224                                              gboolean     *has_icon_file);
225
226
227 static GtkIconInfo *icon_info_new             (void);
228 static GtkIconInfo *icon_info_new_builtin     (BuiltinIcon *icon);
229
230 static IconSuffix suffix_from_name (const char *name);
231
232 static BuiltinIcon *find_builtin_icon (const gchar *icon_name,
233                                        gint        size,
234                                        gint        *min_difference_p,
235                                        gboolean    *has_larger_p);
236
237 static guint signal_changed = 0;
238
239 static GHashTable *icon_theme_builtin_icons;
240
241 /* also used in gtkiconfactory.c */
242 GtkIconCache *_builtin_cache = NULL;
243 static GList *builtin_dirs = NULL;
244
245 G_DEFINE_TYPE (GtkIconTheme, gtk_icon_theme, G_TYPE_OBJECT)
246
247 /**
248  * gtk_icon_theme_new:
249  * 
250  * Creates a new icon theme object. Icon theme objects are used
251  * to lookup up an icon by name in a particular icon theme.
252  * Usually, you'll want to use gtk_icon_theme_get_default()
253  * or gtk_icon_theme_get_for_screen() rather than creating
254  * a new icon theme object for scratch.
255  * 
256  * Return value: the newly created #GtkIconTheme object.
257  *
258  * Since: 2.4
259  **/
260 GtkIconTheme *
261 gtk_icon_theme_new (void)
262 {
263   return g_object_new (GTK_TYPE_ICON_THEME, NULL);
264 }
265
266 /**
267  * gtk_icon_theme_get_default:
268  * 
269  * Gets the icon theme for the default screen. See
270  * gtk_icon_theme_get_for_screen().
271  *
272  * Return value: (transfer none): A unique #GtkIconTheme associated with
273  *  the default screen. This icon theme is associated with
274  *  the screen and can be used as long as the screen
275  *  is open. Do not ref or unref it.
276  *
277  * Since: 2.4
278  **/
279 GtkIconTheme *
280 gtk_icon_theme_get_default (void)
281 {
282   return gtk_icon_theme_get_for_screen (gdk_screen_get_default ());
283 }
284
285 /**
286  * gtk_icon_theme_get_for_screen:
287  * @screen: a #GdkScreen
288  * 
289  * Gets the icon theme object associated with @screen; if this
290  * function has not previously been called for the given
291  * screen, a new icon theme object will be created and
292  * associated with the screen. Icon theme objects are
293  * fairly expensive to create, so using this function
294  * is usually a better choice than calling than gtk_icon_theme_new()
295  * and setting the screen yourself; by using this function
296  * a single icon theme object will be shared between users.
297  *
298  * Return value: (transfer none): A unique #GtkIconTheme associated with
299  *  the given screen. This icon theme is associated with
300  *  the screen and can be used as long as the screen
301  *  is open. Do not ref or unref it.
302  *
303  * Since: 2.4
304  **/
305 GtkIconTheme *
306 gtk_icon_theme_get_for_screen (GdkScreen *screen)
307 {
308   GtkIconTheme *icon_theme;
309
310   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
311   g_return_val_if_fail (!screen->closed, NULL);
312
313   icon_theme = g_object_get_data (G_OBJECT (screen), "gtk-icon-theme");
314   if (!icon_theme)
315     {
316       GtkIconThemePrivate *priv;
317
318       icon_theme = gtk_icon_theme_new ();
319       gtk_icon_theme_set_screen (icon_theme, screen);
320
321       priv = icon_theme->priv;
322       priv->is_screen_singleton = TRUE;
323
324       g_object_set_data (G_OBJECT (screen), I_("gtk-icon-theme"), icon_theme);
325     }
326
327   return icon_theme;
328 }
329
330 static void
331 gtk_icon_theme_class_init (GtkIconThemeClass *klass)
332 {
333   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
334
335   gobject_class->finalize = gtk_icon_theme_finalize;
336
337 /**
338  * GtkIconTheme::changed
339  * @icon_theme: the icon theme
340  * 
341  * Emitted when the current icon theme is switched or GTK+ detects
342  * that a change has occurred in the contents of the current
343  * icon theme.
344  **/
345   signal_changed = g_signal_new (I_("changed"),
346                                  G_TYPE_FROM_CLASS (klass),
347                                  G_SIGNAL_RUN_LAST,
348                                  G_STRUCT_OFFSET (GtkIconThemeClass, changed),
349                                  NULL, NULL,
350                                  g_cclosure_marshal_VOID__VOID,
351                                  G_TYPE_NONE, 0);
352
353   g_type_class_add_private (klass, sizeof (GtkIconThemePrivate));
354 }
355
356
357 /* Callback when the display that the icon theme is attached to
358  * is closed; unset the screen, and if it's the unique theme
359  * for the screen, drop the reference
360  */
361 static void
362 display_closed (GdkDisplay   *display,
363                 gboolean      is_error,
364                 GtkIconTheme *icon_theme)
365 {
366   GtkIconThemePrivate *priv = icon_theme->priv;
367   GdkScreen *screen = priv->screen;
368   gboolean was_screen_singleton = priv->is_screen_singleton;
369
370   if (was_screen_singleton)
371     {
372       g_object_set_data (G_OBJECT (screen), I_("gtk-icon-theme"), NULL);
373       priv->is_screen_singleton = FALSE;
374     }
375
376   gtk_icon_theme_set_screen (icon_theme, NULL);
377
378   if (was_screen_singleton)
379     {
380       g_object_unref (icon_theme);
381     }
382 }
383
384 static void
385 update_current_theme (GtkIconTheme *icon_theme)
386 {
387 #define theme_changed(_old, _new) \
388   ((_old && !_new) || (!_old && _new) || \
389    (_old && _new && strcmp (_old, _new) != 0))
390   GtkIconThemePrivate *priv = icon_theme->priv;
391
392   if (!priv->custom_theme)
393     {
394       gchar *theme = NULL;
395       gchar *fallback_theme = NULL;
396       gboolean changed = FALSE;
397
398       if (priv->screen)
399         {
400           GtkSettings *settings = gtk_settings_get_for_screen (priv->screen);
401           g_object_get (settings, 
402                         "gtk-icon-theme-name", &theme, 
403                         "gtk-fallback-icon-theme", &fallback_theme, NULL);
404         }
405
406       /* ensure that the current theme (even when just the default)
407        * is searched before any fallback theme
408        */
409       if (!theme && fallback_theme)
410         theme = g_strdup (DEFAULT_THEME_NAME);
411
412       if (theme_changed (priv->current_theme, theme))
413         {
414           g_free (priv->current_theme);
415           priv->current_theme = theme;
416           changed = TRUE;
417         }
418       else
419         g_free (theme);
420
421       if (theme_changed (priv->fallback_theme, fallback_theme))
422         {
423           g_free (priv->fallback_theme);
424           priv->fallback_theme = fallback_theme;
425           changed = TRUE;
426         }
427       else
428         g_free (fallback_theme);
429
430       if (changed)
431         do_theme_change (icon_theme);
432     }
433 #undef theme_changed
434 }
435
436 /* Callback when the icon theme GtkSetting changes
437  */
438 static void
439 theme_changed (GtkSettings  *settings,
440                GParamSpec   *pspec,
441                GtkIconTheme *icon_theme)
442 {
443   update_current_theme (icon_theme);
444 }
445
446 static void
447 unset_screen (GtkIconTheme *icon_theme)
448 {
449   GtkIconThemePrivate *priv = icon_theme->priv;
450   GtkSettings *settings;
451   GdkDisplay *display;
452   
453   if (priv->screen)
454     {
455       settings = gtk_settings_get_for_screen (priv->screen);
456       display = gdk_screen_get_display (priv->screen);
457       
458       g_signal_handlers_disconnect_by_func (display,
459                                             (gpointer) display_closed,
460                                             icon_theme);
461       g_signal_handlers_disconnect_by_func (settings,
462                                             (gpointer) theme_changed,
463                                             icon_theme);
464
465       priv->screen = NULL;
466     }
467 }
468
469 /**
470  * gtk_icon_theme_set_screen:
471  * @icon_theme: a #GtkIconTheme
472  * @screen: a #GdkScreen
473  * 
474  * Sets the screen for an icon theme; the screen is used
475  * to track the user's currently configured icon theme,
476  * which might be different for different screens.
477  *
478  * Since: 2.4
479  **/
480 void
481 gtk_icon_theme_set_screen (GtkIconTheme *icon_theme,
482                            GdkScreen    *screen)
483 {
484   GtkIconThemePrivate *priv;
485   GtkSettings *settings;
486   GdkDisplay *display;
487
488   g_return_if_fail (GTK_ICON_THEME (icon_theme));
489   g_return_if_fail (screen == NULL || GDK_IS_SCREEN (screen));
490
491   priv = icon_theme->priv;
492
493   unset_screen (icon_theme);
494   
495   if (screen)
496     {
497       display = gdk_screen_get_display (screen);
498       settings = gtk_settings_get_for_screen (screen);
499       
500       priv->screen = screen;
501       
502       g_signal_connect (display, "closed",
503                         G_CALLBACK (display_closed), icon_theme);
504       g_signal_connect (settings, "notify::gtk-icon-theme-name",
505                         G_CALLBACK (theme_changed), icon_theme);
506       g_signal_connect (settings, "notify::gtk-fallback-icon-theme-name",
507                         G_CALLBACK (theme_changed), icon_theme);
508     }
509
510   update_current_theme (icon_theme);
511 }
512
513 /* Checks whether a loader for SVG files has been registered
514  * with GdkPixbuf.
515  */
516 static gboolean
517 pixbuf_supports_svg (void)
518 {
519   GSList *formats;
520   GSList *tmp_list;
521   static gint found_svg = -1;
522
523   if (found_svg != -1)
524     return found_svg;
525
526   formats = gdk_pixbuf_get_formats ();
527
528   found_svg = FALSE; 
529   for (tmp_list = formats; tmp_list && !found_svg; tmp_list = tmp_list->next)
530     {
531       gchar **mime_types = gdk_pixbuf_format_get_mime_types (tmp_list->data);
532       gchar **mime_type;
533       
534       for (mime_type = mime_types; *mime_type && !found_svg; mime_type++)
535         {
536           if (strcmp (*mime_type, "image/svg") == 0)
537             found_svg = TRUE;
538         }
539
540       g_strfreev (mime_types);
541     }
542
543   g_slist_free (formats);
544   
545   return found_svg;
546 }
547
548 static void
549 gtk_icon_theme_init (GtkIconTheme *icon_theme)
550 {
551   GtkIconThemePrivate *priv;
552   const gchar * const *xdg_data_dirs;
553   int i, j;
554
555   priv = G_TYPE_INSTANCE_GET_PRIVATE (icon_theme,
556                                       GTK_TYPE_ICON_THEME,
557                                       GtkIconThemePrivate);
558   icon_theme->priv = priv;
559
560   priv->custom_theme = FALSE;
561
562   xdg_data_dirs = g_get_system_data_dirs ();
563   for (i = 0; xdg_data_dirs[i]; i++) ;
564
565   priv->search_path_len = 2 * i + 2;
566   
567   priv->search_path = g_new (char *, priv->search_path_len);
568   
569   i = 0;
570   priv->search_path[i++] = g_build_filename (g_get_home_dir (), ".icons", NULL);
571   priv->search_path[i++] = g_build_filename (g_get_user_data_dir (), "icons", NULL);
572   
573   for (j = 0; xdg_data_dirs[j]; j++) 
574     priv->search_path[i++] = g_build_filename (xdg_data_dirs[j], "icons", NULL);
575
576   for (j = 0; xdg_data_dirs[j]; j++) 
577     priv->search_path[i++] = g_build_filename (xdg_data_dirs[j], "pixmaps", NULL);
578
579   priv->themes_valid = FALSE;
580   priv->themes = NULL;
581   priv->unthemed_icons = NULL;
582   
583   priv->pixbuf_supports_svg = pixbuf_supports_svg ();
584 }
585
586 static void
587 free_dir_mtime (IconThemeDirMtime *dir_mtime)
588 {
589   if (dir_mtime->cache)
590     _gtk_icon_cache_unref (dir_mtime->cache);
591
592   g_free (dir_mtime->dir);
593   g_slice_free (IconThemeDirMtime, dir_mtime);
594
595 }
596
597 static gboolean
598 reset_styles_idle (gpointer user_data)
599 {
600   GtkIconTheme *icon_theme;
601   GtkIconThemePrivate *priv;
602
603   icon_theme = GTK_ICON_THEME (user_data);
604   priv = icon_theme->priv;
605
606   if (priv->screen && priv->is_screen_singleton)
607     {
608       GtkSettings *settings = gtk_settings_get_for_screen (priv->screen);
609       gtk_rc_reset_styles (settings);
610     }
611
612   priv->reset_styles_idle = 0;
613
614   return FALSE;
615 }
616
617 static void
618 do_theme_change (GtkIconTheme *icon_theme)
619 {
620   GtkIconThemePrivate *priv = icon_theme->priv;
621
622   if (!priv->themes_valid)
623     return;
624   
625   GTK_NOTE (ICONTHEME, 
626             g_print ("change to icon theme \"%s\"\n", priv->current_theme));
627   blow_themes (icon_theme);
628   g_signal_emit (icon_theme, signal_changed, 0);
629
630   if (!priv->reset_styles_idle)
631     priv->reset_styles_idle = 
632       gdk_threads_add_idle_full (GTK_PRIORITY_RESIZE - 2, 
633                        reset_styles_idle, icon_theme, NULL);
634 }
635
636 static void
637 blow_themes (GtkIconTheme *icon_theme)
638 {
639   GtkIconThemePrivate *priv = icon_theme->priv;
640   
641   if (priv->themes_valid)
642     {
643       g_hash_table_destroy (priv->all_icons);
644       g_list_foreach (priv->themes, (GFunc)theme_destroy, NULL);
645       g_list_free (priv->themes);
646       g_list_foreach (priv->dir_mtimes, (GFunc)free_dir_mtime, NULL);
647       g_list_free (priv->dir_mtimes);
648       g_hash_table_destroy (priv->unthemed_icons);
649     }
650   priv->themes = NULL;
651   priv->unthemed_icons = NULL;
652   priv->dir_mtimes = NULL;
653   priv->all_icons = NULL;
654   priv->themes_valid = FALSE;
655 }
656
657 static void
658 gtk_icon_theme_finalize (GObject *object)
659 {
660   GtkIconTheme *icon_theme;
661   GtkIconThemePrivate *priv;
662   int i;
663
664   icon_theme = GTK_ICON_THEME (object);
665   priv = icon_theme->priv;
666
667   if (priv->reset_styles_idle)
668     {
669       g_source_remove (priv->reset_styles_idle);
670       priv->reset_styles_idle = 0;
671     }
672
673   unset_screen (icon_theme);
674
675   g_free (priv->current_theme);
676   priv->current_theme = NULL;
677
678   for (i = 0; i < priv->search_path_len; i++)
679     g_free (priv->search_path[i]);
680
681   g_free (priv->search_path);
682   priv->search_path = NULL;
683
684   blow_themes (icon_theme);
685
686   G_OBJECT_CLASS (gtk_icon_theme_parent_class)->finalize (object);  
687 }
688
689 /**
690  * gtk_icon_theme_set_search_path:
691  * @icon_theme: a #GtkIconTheme
692  * @path: array of directories that are searched for icon themes
693  * @n_elements: number of elements in @path.
694  * 
695  * Sets the search path for the icon theme object. When looking
696  * for an icon theme, GTK+ will search for a subdirectory of
697  * one or more of the directories in @path with the same name
698  * as the icon theme. (Themes from multiple of the path elements
699  * are combined to allow themes to be extended by adding icons
700  * in the user's home directory.)
701  *
702  * In addition if an icon found isn't found either in the current
703  * icon theme or the default icon theme, and an image file with
704  * the right name is found directly in one of the elements of
705  * @path, then that image will be used for the icon name.
706  * (This is legacy feature, and new icons should be put
707  * into the default icon theme, which is called DEFAULT_THEME_NAME,
708  * rather than directly on the icon path.)
709  *
710  * Since: 2.4
711  **/
712 void
713 gtk_icon_theme_set_search_path (GtkIconTheme *icon_theme,
714                                 const gchar  *path[],
715                                 gint          n_elements)
716 {
717   GtkIconThemePrivate *priv;
718   gint i;
719
720   g_return_if_fail (GTK_IS_ICON_THEME (icon_theme));
721
722   priv = icon_theme->priv;
723   for (i = 0; i < priv->search_path_len; i++)
724     g_free (priv->search_path[i]);
725
726   g_free (priv->search_path);
727
728   priv->search_path = g_new (gchar *, n_elements);
729   priv->search_path_len = n_elements;
730
731   for (i = 0; i < priv->search_path_len; i++)
732     priv->search_path[i] = g_strdup (path[i]);
733
734   do_theme_change (icon_theme);
735 }
736
737
738 /**
739  * gtk_icon_theme_get_search_path:
740  * @icon_theme: a #GtkIconTheme
741  * @path: (allow-none): (array length=n_elements) (out): location to store a list of icon theme path directories or %NULL
742  *        The stored value should be freed with g_strfreev().
743  * @n_elements: location to store number of elements
744  *              in @path, or %NULL
745  * 
746  * Gets the current search path. See gtk_icon_theme_set_search_path().
747  *
748  * Since: 2.4
749  **/
750 void
751 gtk_icon_theme_get_search_path (GtkIconTheme      *icon_theme,
752                                 gchar            **path[],
753                                 gint              *n_elements)
754 {
755   GtkIconThemePrivate *priv;
756   int i;
757
758   g_return_if_fail (GTK_IS_ICON_THEME (icon_theme));
759
760   priv = icon_theme->priv;
761
762   if (n_elements)
763     *n_elements = priv->search_path_len;
764   
765   if (path)
766     {
767       *path = g_new (gchar *, priv->search_path_len + 1);
768       for (i = 0; i < priv->search_path_len; i++)
769         (*path)[i] = g_strdup (priv->search_path[i]);
770       (*path)[i] = NULL;
771     }
772 }
773
774 /**
775  * gtk_icon_theme_append_search_path:
776  * @icon_theme: a #GtkIconTheme
777  * @path: directory name to append to the icon path
778  * 
779  * Appends a directory to the search path. 
780  * See gtk_icon_theme_set_search_path(). 
781  *
782  * Since: 2.4
783  **/
784 void
785 gtk_icon_theme_append_search_path (GtkIconTheme *icon_theme,
786                                    const gchar  *path)
787 {
788   GtkIconThemePrivate *priv;
789
790   g_return_if_fail (GTK_IS_ICON_THEME (icon_theme));
791   g_return_if_fail (path != NULL);
792
793   priv = icon_theme->priv;
794   
795   priv->search_path_len++;
796
797   priv->search_path = g_renew (gchar *, priv->search_path, priv->search_path_len);
798   priv->search_path[priv->search_path_len-1] = g_strdup (path);
799
800   do_theme_change (icon_theme);
801 }
802
803 /**
804  * gtk_icon_theme_prepend_search_path:
805  * @icon_theme: a #GtkIconTheme
806  * @path: directory name to prepend to the icon path
807  * 
808  * Prepends a directory to the search path. 
809  * See gtk_icon_theme_set_search_path().
810  *
811  * Since: 2.4
812  **/
813 void
814 gtk_icon_theme_prepend_search_path (GtkIconTheme *icon_theme,
815                                     const gchar  *path)
816 {
817   GtkIconThemePrivate *priv;
818   int i;
819
820   g_return_if_fail (GTK_IS_ICON_THEME (icon_theme));
821   g_return_if_fail (path != NULL);
822
823   priv = icon_theme->priv;
824   
825   priv->search_path_len++;
826   priv->search_path = g_renew (gchar *, priv->search_path, priv->search_path_len);
827
828   for (i = priv->search_path_len - 1; i > 0; i--)
829     priv->search_path[i] = priv->search_path[i - 1];
830   
831   priv->search_path[0] = g_strdup (path);
832
833   do_theme_change (icon_theme);
834 }
835
836 /**
837  * gtk_icon_theme_set_custom_theme:
838  * @icon_theme: a #GtkIconTheme
839  * @theme_name: name of icon theme to use instead of configured theme,
840  *   or %NULL to unset a previously set custom theme
841  * 
842  * Sets the name of the icon theme that the #GtkIconTheme object uses
843  * overriding system configuration. This function cannot be called
844  * on the icon theme objects returned from gtk_icon_theme_get_default()
845  * and gtk_icon_theme_get_for_screen().
846  *
847  * Since: 2.4
848  **/
849 void
850 gtk_icon_theme_set_custom_theme (GtkIconTheme *icon_theme,
851                                  const gchar  *theme_name)
852 {
853   GtkIconThemePrivate *priv;
854
855   g_return_if_fail (GTK_IS_ICON_THEME (icon_theme));
856
857   priv = icon_theme->priv;
858
859   g_return_if_fail (!priv->is_screen_singleton);
860   
861   if (theme_name != NULL)
862     {
863       priv->custom_theme = TRUE;
864       if (!priv->current_theme || strcmp (theme_name, priv->current_theme) != 0)
865         {
866           g_free (priv->current_theme);
867           priv->current_theme = g_strdup (theme_name);
868
869           do_theme_change (icon_theme);
870         }
871     }
872   else
873     {
874       if (priv->custom_theme)
875         {
876           priv->custom_theme = FALSE;
877
878           update_current_theme (icon_theme);
879         }
880     }
881 }
882
883 static void
884 insert_theme (GtkIconTheme *icon_theme, const char *theme_name)
885 {
886   int i;
887   GList *l;
888   char **dirs;
889   char **themes;
890   GtkIconThemePrivate *priv;
891   IconTheme *theme = NULL;
892   char *path;
893   GKeyFile *theme_file;
894   GError *error = NULL;
895   IconThemeDirMtime *dir_mtime;
896   struct stat stat_buf;
897   
898   priv = icon_theme->priv;
899
900   for (l = priv->themes; l != NULL; l = l->next)
901     {
902       theme = l->data;
903       if (strcmp (theme->name, theme_name) == 0)
904         return;
905     }
906   
907   for (i = 0; i < priv->search_path_len; i++)
908     {
909       path = g_build_filename (priv->search_path[i],
910                                theme_name,
911                                NULL);
912       dir_mtime = g_slice_new (IconThemeDirMtime);
913       dir_mtime->cache = NULL;
914       dir_mtime->dir = path;
915       if (g_stat (path, &stat_buf) == 0 && S_ISDIR (stat_buf.st_mode))
916         dir_mtime->mtime = stat_buf.st_mtime;
917       else
918         dir_mtime->mtime = 0;
919
920       priv->dir_mtimes = g_list_prepend (priv->dir_mtimes, dir_mtime);
921     }
922   priv->dir_mtimes = g_list_reverse (priv->dir_mtimes);
923
924   theme_file = NULL;
925   for (i = 0; i < priv->search_path_len && !theme_file; i++)
926     {
927       path = g_build_filename (priv->search_path[i],
928                                theme_name,
929                                "index.theme",
930                                NULL);
931       if (g_file_test (path, G_FILE_TEST_IS_REGULAR)) 
932         {
933           theme_file = g_key_file_new ();
934           g_key_file_set_list_separator (theme_file, ',');
935           g_key_file_load_from_file (theme_file, path, 0, &error);
936           if (error)
937             {
938               g_key_file_free (theme_file);
939               theme_file = NULL;
940               g_error_free (error);
941               error = NULL;
942             }
943         }
944       g_free (path);
945     }
946
947   if (theme_file || strcmp (theme_name, DEFAULT_THEME_NAME) == 0)
948     {
949       theme = g_new0 (IconTheme, 1);
950       theme->name = g_strdup (theme_name);
951       priv->themes = g_list_prepend (priv->themes, theme);
952     }
953
954   if (theme_file == NULL)
955     return;
956
957   theme->display_name = 
958     g_key_file_get_locale_string (theme_file, "Icon Theme", "Name", NULL, NULL);
959   if (!theme->display_name)
960     g_warning ("Theme file for %s has no name\n", theme_name);
961
962   dirs = g_key_file_get_string_list (theme_file, "Icon Theme", "Directories", NULL, NULL);
963   if (!dirs)
964     {
965       g_warning ("Theme file for %s has no directories\n", theme_name);
966       priv->themes = g_list_remove (priv->themes, theme);
967       g_free (theme->name);
968       g_free (theme->display_name);
969       g_free (theme);
970       g_key_file_free (theme_file);
971       return;
972     }
973   
974   theme->comment = 
975     g_key_file_get_locale_string (theme_file, 
976                                   "Icon Theme", "Comment",
977                                   NULL, NULL);
978   theme->example = 
979     g_key_file_get_string (theme_file, 
980                            "Icon Theme", "Example",
981                            NULL);
982
983   theme->dirs = NULL;
984   for (i = 0; dirs[i] != NULL; i++)
985     theme_subdir_load (icon_theme, theme, theme_file, dirs[i]);
986
987   g_strfreev (dirs);
988
989   theme->dirs = g_list_reverse (theme->dirs);
990
991   themes = g_key_file_get_string_list (theme_file,
992                                        "Icon Theme",
993                                        "Inherits",
994                                        NULL,
995                                        NULL);
996   if (themes)
997     {
998       for (i = 0; themes[i] != NULL; i++)
999         insert_theme (icon_theme, themes[i]);
1000       
1001       g_strfreev (themes);
1002     }
1003
1004   g_key_file_free (theme_file);
1005 }
1006
1007 static void
1008 free_unthemed_icon (UnthemedIcon *unthemed_icon)
1009 {
1010   g_free (unthemed_icon->svg_filename);
1011   g_free (unthemed_icon->no_svg_filename);
1012   g_slice_free (UnthemedIcon, unthemed_icon);
1013 }
1014
1015 static char *
1016 strip_suffix (const char *filename)
1017 {
1018   const char *dot;
1019
1020   dot = strrchr (filename, '.');
1021
1022   if (dot == NULL)
1023     return g_strdup (filename);
1024
1025   return g_strndup (filename, dot - filename);
1026 }
1027
1028 static void
1029 load_themes (GtkIconTheme *icon_theme)
1030 {
1031   GtkIconThemePrivate *priv;
1032   GDir *gdir;
1033   int base;
1034   char *dir;
1035   const char *file;
1036   UnthemedIcon *unthemed_icon;
1037   IconSuffix old_suffix, new_suffix;
1038   GTimeVal tv;
1039   IconThemeDirMtime *dir_mtime;
1040   struct stat stat_buf;
1041   
1042   priv = icon_theme->priv;
1043
1044   priv->all_icons = g_hash_table_new (g_str_hash, g_str_equal);
1045   
1046   if (priv->current_theme)
1047     insert_theme (icon_theme, priv->current_theme);
1048
1049   /* Always look in the "default" icon theme, and in a fallback theme */
1050   if (priv->fallback_theme)
1051     insert_theme (icon_theme, priv->fallback_theme);
1052   insert_theme (icon_theme, DEFAULT_THEME_NAME);
1053   priv->themes = g_list_reverse (priv->themes);
1054
1055
1056   priv->unthemed_icons = g_hash_table_new_full (g_str_hash, g_str_equal,
1057                                                 g_free, (GDestroyNotify)free_unthemed_icon);
1058
1059   for (base = 0; base < icon_theme->priv->search_path_len; base++)
1060     {
1061       dir = icon_theme->priv->search_path[base];
1062
1063       dir_mtime = g_slice_new (IconThemeDirMtime);
1064       priv->dir_mtimes = g_list_append (priv->dir_mtimes, dir_mtime);
1065       
1066       dir_mtime->dir = g_strdup (dir);
1067       dir_mtime->mtime = 0;
1068       dir_mtime->cache = NULL;
1069
1070       if (g_stat (dir, &stat_buf) != 0 || !S_ISDIR (stat_buf.st_mode))
1071         continue;
1072       dir_mtime->mtime = stat_buf.st_mtime;
1073
1074       dir_mtime->cache = _gtk_icon_cache_new_for_path (dir);
1075       if (dir_mtime->cache != NULL)
1076         continue;
1077
1078       gdir = g_dir_open (dir, 0, NULL);
1079       if (gdir == NULL)
1080         continue;
1081
1082       while ((file = g_dir_read_name (gdir)))
1083         {
1084           new_suffix = suffix_from_name (file);
1085           
1086           if (new_suffix != ICON_SUFFIX_NONE)
1087             {
1088               char *abs_file;
1089               char *base_name;
1090
1091               abs_file = g_build_filename (dir, file, NULL);
1092               base_name = strip_suffix (file);
1093
1094               if ((unthemed_icon = g_hash_table_lookup (priv->unthemed_icons,
1095                                                         base_name)))
1096                 {
1097                   if (new_suffix == ICON_SUFFIX_SVG)
1098                     {
1099                       if (unthemed_icon->svg_filename)
1100                         g_free (abs_file);
1101                       else
1102                         unthemed_icon->svg_filename = abs_file;
1103                     }
1104                   else
1105                     {
1106                       if (unthemed_icon->no_svg_filename)
1107                         {
1108                           old_suffix = suffix_from_name (unthemed_icon->no_svg_filename);
1109                           if (new_suffix > old_suffix)
1110                             {
1111                               g_free (unthemed_icon->no_svg_filename);
1112                               unthemed_icon->no_svg_filename = abs_file;                              
1113                             }
1114                           else
1115                             g_free (abs_file);
1116                         }
1117                       else
1118                         unthemed_icon->no_svg_filename = abs_file;                            
1119                     }
1120
1121                   g_free (base_name);
1122                 }
1123               else
1124                 {
1125                   unthemed_icon = g_slice_new0 (UnthemedIcon);
1126                   
1127                   if (new_suffix == ICON_SUFFIX_SVG)
1128                     unthemed_icon->svg_filename = abs_file;
1129                   else
1130                     unthemed_icon->no_svg_filename = abs_file;
1131
1132                   g_hash_table_insert (priv->unthemed_icons,
1133                                        base_name,
1134                                        unthemed_icon);
1135                   g_hash_table_insert (priv->all_icons,
1136                                        base_name, NULL);
1137                 }
1138             }
1139         }
1140       g_dir_close (gdir);
1141     }
1142
1143   priv->themes_valid = TRUE;
1144   
1145   g_get_current_time(&tv);
1146   priv->last_stat_time = tv.tv_sec;
1147 }
1148
1149 void
1150 _gtk_icon_theme_ensure_builtin_cache (void)
1151 {
1152   static gboolean initialized = FALSE;
1153   IconThemeDir *dir;
1154   static IconThemeDir dirs[5] = 
1155     {
1156       { ICON_THEME_DIR_THRESHOLD, 0, 16, 16, 16, 2, NULL, "16", -1, NULL, NULL, NULL },
1157       { ICON_THEME_DIR_THRESHOLD, 0, 20, 20, 20, 2, NULL, "20", -1,  NULL, NULL, NULL },
1158       { ICON_THEME_DIR_THRESHOLD, 0, 24, 24, 24, 2, NULL, "24", -1, NULL, NULL, NULL },
1159       { ICON_THEME_DIR_THRESHOLD, 0, 32, 32, 32, 2, NULL, "32", -1, NULL, NULL, NULL },
1160       { ICON_THEME_DIR_THRESHOLD, 0, 48, 48, 48, 2, NULL, "48", -1, NULL, NULL, NULL }
1161     };
1162   gint i;
1163
1164   if (!initialized)
1165     {
1166       initialized = TRUE;
1167
1168       _builtin_cache = _gtk_icon_cache_new ((gchar *)builtin_icons);
1169
1170       for (i = 0; i < G_N_ELEMENTS (dirs); i++)
1171         {
1172           dir = &(dirs[i]);
1173           dir->cache = _gtk_icon_cache_ref (_builtin_cache);
1174           dir->subdir_index = _gtk_icon_cache_get_directory_index (dir->cache, dir->subdir);
1175
1176           builtin_dirs = g_list_append (builtin_dirs, dir);
1177         }
1178     }
1179 }
1180
1181 static void
1182 ensure_valid_themes (GtkIconTheme *icon_theme)
1183 {
1184   GtkIconThemePrivate *priv = icon_theme->priv;
1185   GTimeVal tv;
1186   gboolean was_valid = priv->themes_valid;
1187
1188   if (priv->loading_themes)
1189     return;
1190   priv->loading_themes = TRUE;
1191
1192   _gtk_icon_theme_ensure_builtin_cache ();
1193
1194   if (priv->themes_valid)
1195     {
1196       g_get_current_time (&tv);
1197
1198       if (ABS (tv.tv_sec - priv->last_stat_time) > 5 &&
1199           rescan_themes (icon_theme))
1200         blow_themes (icon_theme);
1201     }
1202   
1203   if (!priv->themes_valid)
1204     {
1205       load_themes (icon_theme);
1206
1207       if (was_valid)
1208         {
1209           g_signal_emit (icon_theme, signal_changed, 0);
1210
1211           if (!priv->check_reload && priv->screen)
1212             {     
1213               static GdkAtom atom_iconthemes = GDK_NONE;
1214               GdkEvent *event = gdk_event_new (GDK_CLIENT_EVENT);
1215               int i;
1216
1217               if (!atom_iconthemes)
1218                 atom_iconthemes = gdk_atom_intern_static_string ("_GTK_LOAD_ICONTHEMES");
1219
1220               for (i = 0; i < 5; i++)
1221                 event->client.data.l[i] = 0;
1222               event->client.data_format = 32;
1223               event->client.message_type = atom_iconthemes;
1224
1225               gdk_screen_broadcast_client_message (priv->screen, event);
1226             }
1227         }
1228     }
1229
1230   priv->loading_themes = FALSE;
1231 }
1232
1233 static GtkIconInfo *
1234 choose_icon (GtkIconTheme       *icon_theme,
1235              const gchar        *icon_names[],
1236              gint                size,
1237              GtkIconLookupFlags  flags)
1238 {
1239   GtkIconThemePrivate *priv;
1240   GList *l;
1241   GtkIconInfo *icon_info = NULL;
1242   UnthemedIcon *unthemed_icon = NULL;
1243   gboolean allow_svg;
1244   gboolean use_builtin;
1245   gint i;
1246
1247   priv = icon_theme->priv;
1248
1249   if (flags & GTK_ICON_LOOKUP_NO_SVG)
1250     allow_svg = FALSE;
1251   else if (flags & GTK_ICON_LOOKUP_FORCE_SVG)
1252     allow_svg = TRUE;
1253   else
1254     allow_svg = priv->pixbuf_supports_svg;
1255
1256   use_builtin = flags & GTK_ICON_LOOKUP_USE_BUILTIN;
1257   
1258   ensure_valid_themes (icon_theme);
1259
1260   for (l = priv->themes; l; l = l->next)
1261     {
1262       IconTheme *theme = l->data;
1263       
1264       for (i = 0; icon_names[i]; i++)
1265         {
1266           icon_info = theme_lookup_icon (theme, icon_names[i], size, allow_svg, use_builtin);
1267           if (icon_info)
1268             goto out;
1269         }
1270     }
1271
1272   for (i = 0; icon_names[i]; i++)
1273     {
1274       unthemed_icon = g_hash_table_lookup (priv->unthemed_icons, icon_names[i]);
1275       if (unthemed_icon)
1276         break;
1277     }
1278 #ifdef G_OS_WIN32
1279   /* Still not found an icon, check if reference to a Win32 resource */
1280   if (!unthemed_icon)
1281     {
1282       gchar **resources;
1283       HICON hIcon = NULL;
1284       
1285       resources = g_strsplit (icon_names[0], ",", 0);
1286       if (resources[0])
1287         {
1288           wchar_t *wfile = g_utf8_to_utf16 (resources[0], -1, NULL, NULL, NULL);
1289           ExtractIconExW (wfile, resources[1] ? atoi (resources[1]) : 0, &hIcon, NULL, 1);
1290           g_free (wfile);
1291         }
1292       
1293       if (hIcon)
1294         {
1295           icon_info = icon_info_new ();
1296           icon_info->cache_pixbuf = gdk_win32_icon_to_pixbuf_libgtk_only (hIcon);
1297           DestroyIcon (hIcon);
1298           icon_info->dir_type = ICON_THEME_DIR_UNTHEMED;
1299           icon_info->dir_size = size;
1300         }
1301       g_strfreev (resources);
1302     }
1303 #endif
1304
1305   if (unthemed_icon)
1306     {
1307       icon_info = icon_info_new ();
1308
1309       /* A SVG icon, when allowed, beats out a XPM icon, but not
1310        * a PNG icon
1311        */
1312       if (allow_svg &&
1313           unthemed_icon->svg_filename &&
1314           (!unthemed_icon->no_svg_filename ||
1315            suffix_from_name (unthemed_icon->no_svg_filename) != ICON_SUFFIX_PNG))
1316         icon_info->filename = g_strdup (unthemed_icon->svg_filename);
1317       else if (unthemed_icon->no_svg_filename)
1318         icon_info->filename = g_strdup (unthemed_icon->no_svg_filename);
1319
1320       icon_info->dir_type = ICON_THEME_DIR_UNTHEMED;
1321       icon_info->dir_size = size;
1322     }
1323
1324  out:
1325   if (icon_info) 
1326     {
1327       icon_info->desired_size = size;
1328       icon_info->forced_size = (flags & GTK_ICON_LOOKUP_FORCE_SIZE) != 0;
1329     }
1330   else
1331     {
1332       static gboolean check_for_default_theme = TRUE;
1333       char *default_theme_path;
1334       gboolean found = FALSE;
1335       unsigned i;
1336
1337       if (check_for_default_theme)
1338         {
1339           check_for_default_theme = FALSE;
1340
1341           for (i = 0; !found && i < priv->search_path_len; i++)
1342             {
1343               default_theme_path = g_build_filename (priv->search_path[i],
1344                                                      DEFAULT_THEME_NAME,
1345                                                      "index.theme",
1346                                                      NULL);
1347               found = g_file_test (default_theme_path, G_FILE_TEST_IS_REGULAR);
1348               g_free (default_theme_path);
1349             }
1350
1351           if (!found)
1352             {
1353               g_warning (_("Could not find the icon '%s'. The '%s' theme\n"
1354                            "was not found either, perhaps you need to install it.\n"
1355                            "You can get a copy from:\n"
1356                            "\t%s"),
1357                          icon_names[0], DEFAULT_THEME_NAME, "http://icon-theme.freedesktop.org/releases");
1358             }
1359         }
1360     }
1361
1362   return icon_info;
1363 }
1364
1365
1366 /**
1367  * gtk_icon_theme_lookup_icon:
1368  * @icon_theme: a #GtkIconTheme
1369  * @icon_name: the name of the icon to lookup
1370  * @size: desired icon size
1371  * @flags: flags modifying the behavior of the icon lookup
1372  * 
1373  * Looks up a named icon and returns a structure containing
1374  * information such as the filename of the icon. The icon
1375  * can then be rendered into a pixbuf using
1376  * gtk_icon_info_load_icon(). (gtk_icon_theme_load_icon()
1377  * combines these two steps if all you need is the pixbuf.)
1378  * 
1379  * Return value: a #GtkIconInfo structure containing information
1380  * about the icon, or %NULL if the icon wasn't found. Free with
1381  * gtk_icon_info_free()
1382  *
1383  * Since: 2.4
1384  */
1385 GtkIconInfo *
1386 gtk_icon_theme_lookup_icon (GtkIconTheme       *icon_theme,
1387                             const gchar        *icon_name,
1388                             gint                size,
1389                             GtkIconLookupFlags  flags)
1390 {
1391   GtkIconInfo *info;
1392
1393   g_return_val_if_fail (GTK_IS_ICON_THEME (icon_theme), NULL);
1394   g_return_val_if_fail (icon_name != NULL, NULL);
1395   g_return_val_if_fail ((flags & GTK_ICON_LOOKUP_NO_SVG) == 0 ||
1396                         (flags & GTK_ICON_LOOKUP_FORCE_SVG) == 0, NULL);
1397
1398   GTK_NOTE (ICONTHEME, 
1399             g_print ("gtk_icon_theme_lookup_icon %s\n", icon_name));
1400
1401   if (flags & GTK_ICON_LOOKUP_GENERIC_FALLBACK)
1402     {
1403       gchar **names;
1404       gint dashes, i;
1405       gchar *p;
1406  
1407       dashes = 0;
1408       for (p = (gchar *) icon_name; *p; p++)
1409         if (*p == '-')
1410           dashes++;
1411
1412       names = g_new (gchar *, dashes + 2);
1413       names[0] = g_strdup (icon_name);
1414       for (i = 1; i <= dashes; i++)
1415         {
1416           names[i] = g_strdup (names[i - 1]);
1417           p = strrchr (names[i], '-');
1418           *p = '\0';
1419         }
1420       names[dashes + 1] = NULL;
1421    
1422       info = choose_icon (icon_theme, (const gchar **) names, size, flags);
1423       
1424       g_strfreev (names);
1425     }
1426   else 
1427     {
1428       const gchar *names[2];
1429       
1430       names[0] = icon_name;
1431       names[1] = NULL;
1432
1433       info = choose_icon (icon_theme, names, size, flags);
1434     }
1435
1436   return info;
1437 }
1438
1439 /**
1440  * gtk_icon_theme_choose_icon:
1441  * @icon_theme: a #GtkIconTheme
1442  * @icon_names: %NULL-terminated array of icon names to lookup
1443  * @size: desired icon size
1444  * @flags: flags modifying the behavior of the icon lookup
1445  * 
1446  * Looks up a named icon and returns a structure containing
1447  * information such as the filename of the icon. The icon
1448  * can then be rendered into a pixbuf using
1449  * gtk_icon_info_load_icon(). (gtk_icon_theme_load_icon()
1450  * combines these two steps if all you need is the pixbuf.)
1451  *
1452  * If @icon_names contains more than one name, this function 
1453  * tries them all in the given order before falling back to 
1454  * inherited icon themes.
1455  * 
1456  * Return value: a #GtkIconInfo structure containing information
1457  * about the icon, or %NULL if the icon wasn't found. Free with
1458  * gtk_icon_info_free()
1459  *
1460  * Since: 2.12
1461  */
1462 GtkIconInfo *
1463 gtk_icon_theme_choose_icon (GtkIconTheme       *icon_theme,
1464                             const gchar        *icon_names[],
1465                             gint                size,
1466                             GtkIconLookupFlags  flags)
1467 {
1468   g_return_val_if_fail (GTK_IS_ICON_THEME (icon_theme), NULL);
1469   g_return_val_if_fail (icon_names != NULL, NULL);
1470   g_return_val_if_fail ((flags & GTK_ICON_LOOKUP_NO_SVG) == 0 ||
1471                         (flags & GTK_ICON_LOOKUP_FORCE_SVG) == 0, NULL);
1472
1473   return choose_icon (icon_theme, icon_names, size, flags);
1474 }
1475
1476 /* Error quark */
1477 GQuark
1478 gtk_icon_theme_error_quark (void)
1479 {
1480   return g_quark_from_static_string ("gtk-icon-theme-error-quark");
1481 }
1482
1483 /**
1484  * gtk_icon_theme_load_icon:
1485  * @icon_theme: a #GtkIconTheme
1486  * @icon_name: the name of the icon to lookup
1487  * @size: the desired icon size. The resulting icon may not be
1488  *     exactly this size; see gtk_icon_info_load_icon().
1489  * @flags: flags modifying the behavior of the icon lookup
1490  * @error: (allow-none): Location to store error information on failure,
1491  *     or %NULL.
1492  *
1493  * Looks up an icon in an icon theme, scales it to the given size
1494  * and renders it into a pixbuf. This is a convenience function;
1495  * if more details about the icon are needed, use
1496  * gtk_icon_theme_lookup_icon() followed by gtk_icon_info_load_icon().
1497  *
1498  * Note that you probably want to listen for icon theme changes and
1499  * update the icon. This is usually done by connecting to the
1500  * GtkWidget::style-set signal. If for some reason you do not want to
1501  * update the icon when the icon theme changes, you should consider
1502  * using gdk_pixbuf_copy() to make a private copy of the pixbuf
1503  * returned by this function. Otherwise GTK+ may need to keep the old
1504  * icon theme loaded, which would be a waste of memory.
1505  *
1506  * Return value: (transfer full): the rendered icon; this may be a
1507  *     newly created icon or a new reference to an internal icon, so
1508  *     you must not modify the icon. Use g_object_unref() to release
1509  *     your reference to the icon. %NULL if the icon isn't found.
1510  *
1511  * Since: 2.4
1512  **/
1513 GdkPixbuf *
1514 gtk_icon_theme_load_icon (GtkIconTheme         *icon_theme,
1515                           const gchar          *icon_name,
1516                           gint                  size,
1517                           GtkIconLookupFlags    flags,
1518                           GError              **error)
1519 {
1520   GtkIconInfo *icon_info;
1521   GdkPixbuf *pixbuf = NULL;
1522   
1523   g_return_val_if_fail (GTK_IS_ICON_THEME (icon_theme), NULL);
1524   g_return_val_if_fail (icon_name != NULL, NULL);
1525   g_return_val_if_fail ((flags & GTK_ICON_LOOKUP_NO_SVG) == 0 ||
1526                         (flags & GTK_ICON_LOOKUP_FORCE_SVG) == 0, NULL);
1527   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1528   
1529   icon_info = gtk_icon_theme_lookup_icon (icon_theme, icon_name, size,
1530                                           flags | GTK_ICON_LOOKUP_USE_BUILTIN);
1531   if (!icon_info)
1532     {
1533       g_set_error (error, GTK_ICON_THEME_ERROR,  GTK_ICON_THEME_NOT_FOUND,
1534                    _("Icon '%s' not present in theme"), icon_name);
1535       return NULL;
1536     }
1537
1538   pixbuf = gtk_icon_info_load_icon (icon_info, error);
1539   gtk_icon_info_free (icon_info);
1540
1541   return pixbuf;
1542 }
1543
1544 /**
1545  * gtk_icon_theme_has_icon:
1546  * @icon_theme: a #GtkIconTheme
1547  * @icon_name: the name of an icon
1548  * 
1549  * Checks whether an icon theme includes an icon
1550  * for a particular name.
1551  * 
1552  * Return value: %TRUE if @icon_theme includes an
1553  *  icon for @icon_name.
1554  *
1555  * Since: 2.4
1556  **/
1557 gboolean 
1558 gtk_icon_theme_has_icon (GtkIconTheme *icon_theme,
1559                          const char   *icon_name)
1560 {
1561   GtkIconThemePrivate *priv;
1562   GList *l;
1563
1564   g_return_val_if_fail (GTK_IS_ICON_THEME (icon_theme), FALSE);
1565   g_return_val_if_fail (icon_name != NULL, FALSE);
1566
1567   priv = icon_theme->priv;
1568   
1569   ensure_valid_themes (icon_theme);
1570
1571   for (l = priv->dir_mtimes; l; l = l->next)
1572     {
1573       IconThemeDirMtime *dir_mtime = l->data;
1574       GtkIconCache *cache = dir_mtime->cache;
1575       
1576       if (cache && _gtk_icon_cache_has_icon (cache, icon_name))
1577         return TRUE;
1578     }
1579
1580   if (g_hash_table_lookup_extended (priv->all_icons,
1581                                     icon_name, NULL, NULL))
1582     return TRUE;
1583
1584   if (_builtin_cache &&
1585       _gtk_icon_cache_has_icon (_builtin_cache, icon_name))
1586     return TRUE;
1587
1588   if (icon_theme_builtin_icons &&
1589       g_hash_table_lookup_extended (icon_theme_builtin_icons,
1590                                     icon_name, NULL, NULL))
1591     return TRUE;
1592
1593   return FALSE;
1594 }
1595
1596 static void
1597 add_size (gpointer  key,
1598           gpointer  value,
1599           gpointer  user_data)
1600 {
1601   gint **res_p = user_data;
1602
1603   **res_p = GPOINTER_TO_INT (key);
1604
1605   (*res_p)++;
1606 }
1607
1608 /**
1609  * gtk_icon_theme_get_icon_sizes:
1610  * @icon_theme: a #GtkIconTheme
1611  * @icon_name: the name of an icon
1612  * 
1613  * Returns an array of integers describing the sizes at which
1614  * the icon is available without scaling. A size of -1 means 
1615  * that the icon is available in a scalable format. The array 
1616  * is zero-terminated.
1617  * 
1618  * Return value: An newly allocated array describing the sizes at
1619  * which the icon is available. The array should be freed with g_free()
1620  * when it is no longer needed.
1621  *
1622  * Since: 2.6
1623  **/
1624 gint *
1625 gtk_icon_theme_get_icon_sizes (GtkIconTheme *icon_theme,
1626                                const char   *icon_name)
1627 {
1628   GList *l, *d, *icons;
1629   GHashTable *sizes;
1630   gint *result, *r;
1631   guint suffix;  
1632   GtkIconThemePrivate *priv;
1633
1634   g_return_val_if_fail (GTK_IS_ICON_THEME (icon_theme), NULL);
1635   
1636   priv = icon_theme->priv;
1637
1638   ensure_valid_themes (icon_theme);
1639
1640   sizes = g_hash_table_new (g_direct_hash, g_direct_equal);
1641
1642   for (l = priv->themes; l; l = l->next)
1643     {
1644       IconTheme *theme = l->data;
1645       for (d = theme->dirs; d; d = d->next)
1646         {
1647           IconThemeDir *dir = d->data;
1648
1649           if (dir->type != ICON_THEME_DIR_SCALABLE && g_hash_table_lookup_extended (sizes, GINT_TO_POINTER (dir->size), NULL, NULL))
1650             continue;
1651
1652           suffix = theme_dir_get_icon_suffix (dir, icon_name, NULL);      
1653           if (suffix != ICON_SUFFIX_NONE)
1654             {
1655               if (suffix == ICON_SUFFIX_SVG)
1656                 g_hash_table_insert (sizes, GINT_TO_POINTER (-1), NULL);
1657               else
1658                 g_hash_table_insert (sizes, GINT_TO_POINTER (dir->size), NULL);
1659             }
1660         }
1661     }
1662
1663   for (d = builtin_dirs; d; d = d->next)
1664     {
1665       IconThemeDir *dir = d->data;
1666       
1667       if (dir->type != ICON_THEME_DIR_SCALABLE && g_hash_table_lookup_extended (sizes, GINT_TO_POINTER (dir->size), NULL, NULL))
1668         continue;
1669
1670       suffix = theme_dir_get_icon_suffix (dir, icon_name, NULL);          
1671       if (suffix != ICON_SUFFIX_NONE)
1672         {
1673           if (suffix == ICON_SUFFIX_SVG)
1674             g_hash_table_insert (sizes, GINT_TO_POINTER (-1), NULL);
1675           else
1676             g_hash_table_insert (sizes, GINT_TO_POINTER (dir->size), NULL);
1677         }
1678     }
1679
1680   if (icon_theme_builtin_icons)
1681     {
1682       icons = g_hash_table_lookup (icon_theme_builtin_icons, icon_name);
1683       
1684       while (icons)
1685         {
1686           BuiltinIcon *icon = icons->data;
1687         
1688           g_hash_table_insert (sizes, GINT_TO_POINTER (icon->size), NULL);
1689           icons = icons->next;
1690         }      
1691     }
1692
1693   r = result = g_new0 (gint, g_hash_table_size (sizes) + 1);
1694
1695   g_hash_table_foreach (sizes, add_size, &r);
1696   g_hash_table_destroy (sizes);
1697   
1698   return result;
1699 }
1700
1701 static void
1702 add_key_to_hash (gpointer  key,
1703                  gpointer  value,
1704                  gpointer  user_data)
1705 {
1706   GHashTable *hash = user_data;
1707
1708   g_hash_table_insert (hash, key, NULL);
1709 }
1710
1711 static void
1712 add_key_to_list (gpointer  key,
1713                  gpointer  value,
1714                  gpointer  user_data)
1715 {
1716   GList **list = user_data;
1717
1718   *list = g_list_prepend (*list, g_strdup (key));
1719 }
1720
1721 /**
1722  * gtk_icon_theme_list_icons:
1723  * @icon_theme: a #GtkIconTheme
1724  * @context: a string identifying a particular type of icon,
1725  *           or %NULL to list all icons.
1726  * 
1727  * Lists the icons in the current icon theme. Only a subset
1728  * of the icons can be listed by providing a context string.
1729  * The set of values for the context string is system dependent,
1730  * but will typically include such values as "Applications" and
1731  * "MimeTypes".
1732  *
1733  * Return value: (element-type utf8) (transfer none): a #GList list holding the names of all the
1734  *  icons in the theme. You must first free each element
1735  *  in the list with g_free(), then free the list itself
1736  *  with g_list_free().
1737  *
1738  * Since: 2.4
1739  **/
1740 GList *
1741 gtk_icon_theme_list_icons (GtkIconTheme *icon_theme,
1742                            const char   *context)
1743 {
1744   GtkIconThemePrivate *priv;
1745   GHashTable *icons;
1746   GList *list, *l;
1747   GQuark context_quark;
1748   
1749   priv = icon_theme->priv;
1750   
1751   ensure_valid_themes (icon_theme);
1752
1753   if (context)
1754     {
1755       context_quark = g_quark_try_string (context);
1756
1757       if (!context_quark)
1758         return NULL;
1759     }
1760   else
1761     context_quark = 0;
1762
1763   icons = g_hash_table_new (g_str_hash, g_str_equal);
1764   
1765   l = priv->themes;
1766   while (l != NULL)
1767     {
1768       theme_list_icons (l->data, icons, context_quark);
1769       l = l->next;
1770     }
1771
1772   if (context_quark == 0)
1773     g_hash_table_foreach (priv->unthemed_icons,
1774                           add_key_to_hash,
1775                           icons);
1776
1777   list = NULL;
1778   
1779   g_hash_table_foreach (icons,
1780                         add_key_to_list,
1781                         &list);
1782
1783   g_hash_table_destroy (icons);
1784   
1785   return list;
1786 }
1787
1788 /**
1789  * gtk_icon_theme_list_contexts:
1790  * @icon_theme: a #GtkIconTheme
1791  *
1792  * Gets the list of contexts available within the current
1793  * hierarchy of icon themes
1794  *
1795  * Return value: (element-type utf8) (transfer full): a #GList list holding the names of all the
1796  *  contexts in the theme. You must first free each element
1797  *  in the list with g_free(), then free the list itself
1798  *  with g_list_free().
1799  *
1800  * Since: 2.12
1801  **/
1802 GList *
1803 gtk_icon_theme_list_contexts (GtkIconTheme *icon_theme)
1804 {
1805   GtkIconThemePrivate *priv;
1806   GHashTable *contexts;
1807   GList *list, *l;
1808
1809   priv = icon_theme->priv;
1810   
1811   ensure_valid_themes (icon_theme);
1812
1813   contexts = g_hash_table_new (g_str_hash, g_str_equal);
1814
1815   l = priv->themes;
1816   while (l != NULL)
1817     {
1818       theme_list_contexts (l->data, contexts);
1819       l = l->next;
1820     }
1821
1822   list = NULL;
1823
1824   g_hash_table_foreach (contexts,
1825                         add_key_to_list,
1826                         &list);
1827
1828   g_hash_table_destroy (contexts);
1829
1830   return list;
1831 }
1832
1833 /**
1834  * gtk_icon_theme_get_example_icon_name:
1835  * @icon_theme: a #GtkIconTheme
1836  * 
1837  * Gets the name of an icon that is representative of the
1838  * current theme (for instance, to use when presenting
1839  * a list of themes to the user.)
1840  * 
1841  * Return value: the name of an example icon or %NULL.
1842  *  Free with g_free().
1843  *
1844  * Since: 2.4
1845  **/
1846 char *
1847 gtk_icon_theme_get_example_icon_name (GtkIconTheme *icon_theme)
1848 {
1849   GtkIconThemePrivate *priv;
1850   GList *l;
1851   IconTheme *theme;
1852
1853   g_return_val_if_fail (GTK_IS_ICON_THEME (icon_theme), NULL);
1854   
1855   priv = icon_theme->priv;
1856   
1857   ensure_valid_themes (icon_theme);
1858
1859   l = priv->themes;
1860   while (l != NULL)
1861     {
1862       theme = l->data;
1863       if (theme->example)
1864         return g_strdup (theme->example);
1865       
1866       l = l->next;
1867     }
1868   
1869   return NULL;
1870 }
1871
1872
1873 static gboolean
1874 rescan_themes (GtkIconTheme *icon_theme)
1875 {
1876   GtkIconThemePrivate *priv;
1877   IconThemeDirMtime *dir_mtime;
1878   GList *d;
1879   int stat_res;
1880   struct stat stat_buf;
1881   GTimeVal tv;
1882
1883   priv = icon_theme->priv;
1884
1885   for (d = priv->dir_mtimes; d != NULL; d = d->next)
1886     {
1887       dir_mtime = d->data;
1888
1889       stat_res = g_stat (dir_mtime->dir, &stat_buf);
1890
1891       /* dir mtime didn't change */
1892       if (stat_res == 0 &&
1893           S_ISDIR (stat_buf.st_mode) &&
1894           dir_mtime->mtime == stat_buf.st_mtime)
1895         continue;
1896       /* didn't exist before, and still doesn't */
1897       if (dir_mtime->mtime == 0 &&
1898           (stat_res != 0 || !S_ISDIR (stat_buf.st_mode)))
1899         continue;
1900
1901       return TRUE;
1902     }
1903
1904   g_get_current_time (&tv);
1905   priv->last_stat_time = tv.tv_sec;
1906
1907   return FALSE;
1908 }
1909
1910 /**
1911  * gtk_icon_theme_rescan_if_needed:
1912  * @icon_theme: a #GtkIconTheme
1913  * 
1914  * Checks to see if the icon theme has changed; if it has, any
1915  * currently cached information is discarded and will be reloaded
1916  * next time @icon_theme is accessed.
1917  * 
1918  * Return value: %TRUE if the icon theme has changed and needed
1919  *   to be reloaded.
1920  *
1921  * Since: 2.4
1922  **/
1923 gboolean
1924 gtk_icon_theme_rescan_if_needed (GtkIconTheme *icon_theme)
1925 {
1926   gboolean retval;
1927
1928   g_return_val_if_fail (GTK_IS_ICON_THEME (icon_theme), FALSE);
1929
1930   retval = rescan_themes (icon_theme);
1931   if (retval)
1932       do_theme_change (icon_theme);
1933
1934   return retval;
1935 }
1936
1937 static void
1938 theme_destroy (IconTheme *theme)
1939 {
1940   g_free (theme->display_name);
1941   g_free (theme->comment);
1942   g_free (theme->name);
1943   g_free (theme->example);
1944
1945   g_list_foreach (theme->dirs, (GFunc)theme_dir_destroy, NULL);
1946   g_list_free (theme->dirs);
1947   
1948   g_free (theme);
1949 }
1950
1951 static void
1952 theme_dir_destroy (IconThemeDir *dir)
1953 {
1954   if (dir->cache)
1955       _gtk_icon_cache_unref (dir->cache);
1956   else
1957     g_hash_table_destroy (dir->icons);
1958   
1959   if (dir->icon_data)
1960     g_hash_table_destroy (dir->icon_data);
1961   g_free (dir->dir);
1962   g_free (dir->subdir);
1963   g_free (dir);
1964 }
1965
1966 static int
1967 theme_dir_size_difference (IconThemeDir *dir, int size, gboolean *smaller)
1968 {
1969   int min, max;
1970   switch (dir->type)
1971     {
1972     case ICON_THEME_DIR_FIXED:
1973       *smaller = size < dir->size;
1974       return abs (size - dir->size);
1975       break;
1976     case ICON_THEME_DIR_SCALABLE:
1977       *smaller = size < dir->min_size;
1978       if (size < dir->min_size)
1979         return dir->min_size - size;
1980       if (size > dir->max_size)
1981         return size - dir->max_size;
1982       return 0;
1983       break;
1984     case ICON_THEME_DIR_THRESHOLD:
1985       min = dir->size - dir->threshold;
1986       max = dir->size + dir->threshold;
1987       *smaller = size < min;
1988       if (size < min)
1989         return min - size;
1990       if (size > max)
1991         return size - max;
1992       return 0;
1993       break;
1994     case ICON_THEME_DIR_UNTHEMED:
1995       g_assert_not_reached ();
1996       break;
1997     }
1998   g_assert_not_reached ();
1999   return 1000;
2000 }
2001
2002 static const char *
2003 string_from_suffix (IconSuffix suffix)
2004 {
2005   switch (suffix)
2006     {
2007     case ICON_SUFFIX_XPM:
2008       return ".xpm";
2009     case ICON_SUFFIX_SVG:
2010       return ".svg";
2011     case ICON_SUFFIX_PNG:
2012       return ".png";
2013     default:
2014       g_assert_not_reached();
2015     }
2016   return NULL;
2017 }
2018
2019 static IconSuffix
2020 suffix_from_name (const char *name)
2021 {
2022   IconSuffix retval;
2023
2024   if (g_str_has_suffix (name, ".png"))
2025     retval = ICON_SUFFIX_PNG;
2026   else if (g_str_has_suffix (name, ".svg"))
2027     retval = ICON_SUFFIX_SVG;
2028   else if (g_str_has_suffix (name, ".xpm"))
2029     retval = ICON_SUFFIX_XPM;
2030   else
2031     retval = ICON_SUFFIX_NONE;
2032
2033   return retval;
2034 }
2035
2036 static IconSuffix
2037 best_suffix (IconSuffix suffix,
2038              gboolean   allow_svg)
2039 {
2040   if ((suffix & ICON_SUFFIX_PNG) != 0)
2041     return ICON_SUFFIX_PNG;
2042   else if (allow_svg && ((suffix & ICON_SUFFIX_SVG) != 0))
2043     return ICON_SUFFIX_SVG;
2044   else if ((suffix & ICON_SUFFIX_XPM) != 0)
2045     return ICON_SUFFIX_XPM;
2046   else
2047     return ICON_SUFFIX_NONE;
2048 }
2049
2050
2051 static IconSuffix
2052 theme_dir_get_icon_suffix (IconThemeDir *dir,
2053                            const gchar  *icon_name,
2054                            gboolean     *has_icon_file)
2055 {
2056   IconSuffix suffix;
2057
2058   if (dir->cache)
2059     {
2060       suffix = (IconSuffix)_gtk_icon_cache_get_icon_flags (dir->cache,
2061                                                            icon_name,
2062                                                            dir->subdir_index);
2063
2064       if (has_icon_file)
2065         *has_icon_file = suffix & HAS_ICON_FILE;
2066
2067       suffix = suffix & ~HAS_ICON_FILE;
2068     }
2069   else
2070     suffix = GPOINTER_TO_UINT (g_hash_table_lookup (dir->icons, icon_name));
2071
2072   GTK_NOTE (ICONTHEME, 
2073             g_print ("get_icon_suffix%s %u\n", dir->cache ? " (cached)" : "", suffix));
2074
2075   return suffix;
2076 }
2077
2078 static GtkIconInfo *
2079 theme_lookup_icon (IconTheme          *theme,
2080                    const char         *icon_name,
2081                    int                 size,
2082                    gboolean            allow_svg,
2083                    gboolean            use_builtin)
2084 {
2085   GList *dirs, *l;
2086   IconThemeDir *dir, *min_dir;
2087   char *file;
2088   int min_difference, difference;
2089   BuiltinIcon *closest_builtin = NULL;
2090   gboolean smaller, has_larger, match;
2091   IconSuffix suffix;
2092
2093   min_difference = G_MAXINT;
2094   min_dir = NULL;
2095   has_larger = FALSE;
2096   match = FALSE;
2097
2098   /* Builtin icons are logically part of the default theme and
2099    * are searched before other subdirectories of the default theme.
2100    */
2101   if (use_builtin && strcmp (theme->name, DEFAULT_THEME_NAME) == 0)
2102     {
2103       closest_builtin = find_builtin_icon (icon_name, 
2104                                            size,
2105                                            &min_difference,
2106                                            &has_larger);
2107
2108       if (min_difference == 0)
2109         return icon_info_new_builtin (closest_builtin);
2110
2111       dirs = builtin_dirs;
2112     }
2113   else
2114     dirs = theme->dirs;
2115
2116   l = dirs;
2117   while (l != NULL)
2118     {
2119       dir = l->data;
2120
2121       GTK_NOTE (ICONTHEME,
2122                 g_print ("theme_lookup_icon dir %s\n", dir->dir));
2123       suffix = theme_dir_get_icon_suffix (dir, icon_name, NULL);
2124       if (best_suffix (suffix, allow_svg) != ICON_SUFFIX_NONE)
2125         {
2126           difference = theme_dir_size_difference (dir, size, &smaller);
2127
2128           if (difference == 0)
2129             {
2130               if (dir->type == ICON_THEME_DIR_SCALABLE)
2131                 {
2132                   /* don't pick scalable if we already found
2133                    * a matching non-scalable dir
2134                    */
2135                   if (!match)
2136                     {
2137                       min_dir = dir;
2138                       break;
2139                     }
2140                 }
2141               else
2142                 {
2143                   /* for a matching non-scalable dir keep
2144                    * going and look for a closer match
2145                    */             
2146                   difference = abs (size - dir->size);
2147                   if (!match || difference < min_difference)
2148                     {
2149                       match = TRUE;
2150                       min_difference = difference;
2151                       min_dir = dir;
2152                     }
2153                   if (difference == 0)
2154                     break;
2155                 }
2156             } 
2157   
2158           if (!match)
2159             {
2160               if (!has_larger)
2161                 {
2162                   if (difference < min_difference || smaller)
2163                     {
2164                       min_difference = difference;
2165                       min_dir = dir;
2166                       has_larger = smaller;
2167                     }
2168                 }
2169               else
2170                 {
2171                   if (difference < min_difference && smaller)
2172                     {
2173                       min_difference = difference;
2174                       min_dir = dir;
2175                     }
2176                 }
2177             }
2178         }
2179
2180       l = l->next;
2181
2182       if (l == NULL && dirs == builtin_dirs)
2183         {
2184           dirs = theme->dirs;
2185           l = dirs;
2186         }
2187     }
2188
2189   if (min_dir)
2190     {
2191       GtkIconInfo *icon_info = icon_info_new ();
2192       gboolean has_icon_file = FALSE;
2193       
2194       suffix = theme_dir_get_icon_suffix (min_dir, icon_name, &has_icon_file);
2195       suffix = best_suffix (suffix, allow_svg);
2196       g_assert (suffix != ICON_SUFFIX_NONE);
2197       
2198       if (min_dir->dir)
2199         {
2200           file = g_strconcat (icon_name, string_from_suffix (suffix), NULL);
2201           icon_info->filename = g_build_filename (min_dir->dir, file, NULL);
2202           g_free (file);
2203         }
2204       else
2205         {
2206           icon_info->filename = NULL;
2207         }
2208       
2209       if (min_dir->icon_data != NULL)
2210         icon_info->data = g_hash_table_lookup (min_dir->icon_data, icon_name);
2211
2212       if (icon_info->data == NULL && min_dir->cache != NULL)
2213         {
2214           icon_info->data = _gtk_icon_cache_get_icon_data (min_dir->cache, icon_name, min_dir->subdir_index);
2215           if (icon_info->data)
2216             {
2217               if (min_dir->icon_data == NULL)
2218                 min_dir->icon_data = g_hash_table_new_full (g_str_hash, g_str_equal,
2219                                                             g_free, (GDestroyNotify)icon_data_free);
2220
2221               g_hash_table_replace (min_dir->icon_data, g_strdup (icon_name), icon_info->data);
2222             }
2223         }
2224
2225       if (icon_info->data == NULL && has_icon_file)
2226         {
2227           gchar *icon_file_name, *icon_file_path;
2228
2229           icon_file_name = g_strconcat (icon_name, ".icon", NULL);
2230           icon_file_path = g_build_filename (min_dir->dir, icon_file_name, NULL);
2231
2232           if (g_file_test (icon_file_path, G_FILE_TEST_IS_REGULAR))
2233             {
2234               if (min_dir->icon_data == NULL)   
2235                 min_dir->icon_data = g_hash_table_new_full (g_str_hash, g_str_equal,
2236                                                             g_free, (GDestroyNotify)icon_data_free);
2237               load_icon_data (min_dir, icon_file_path, icon_file_name);
2238               
2239               icon_info->data = g_hash_table_lookup (min_dir->icon_data, icon_name);
2240             }
2241           g_free (icon_file_name);
2242           g_free (icon_file_path);
2243         }
2244
2245       if (min_dir->cache)
2246         {
2247           icon_info->cache_pixbuf = _gtk_icon_cache_get_icon (min_dir->cache, icon_name,
2248                                                               min_dir->subdir_index);
2249         }
2250
2251       icon_info->dir_type = min_dir->type;
2252       icon_info->dir_size = min_dir->size;
2253       icon_info->threshold = min_dir->threshold;
2254       
2255       return icon_info;
2256     }
2257
2258   if (closest_builtin)
2259     return icon_info_new_builtin (closest_builtin);
2260   
2261   return NULL;
2262 }
2263
2264 static void
2265 theme_list_icons (IconTheme  *theme, 
2266                   GHashTable *icons,
2267                   GQuark      context)
2268 {
2269   GList *l = theme->dirs;
2270   IconThemeDir *dir;
2271   
2272   while (l != NULL)
2273     {
2274       dir = l->data;
2275
2276       if (context == dir->context ||
2277           context == 0)
2278         {
2279           if (dir->cache)
2280             {
2281               _gtk_icon_cache_add_icons (dir->cache,
2282                                          dir->subdir,
2283                                          icons);
2284                                          
2285             }
2286           else
2287             {
2288               g_hash_table_foreach (dir->icons,
2289                                     add_key_to_hash,
2290                                     icons);
2291             }
2292         }
2293       l = l->next;
2294     }
2295 }
2296
2297 static void
2298 theme_list_contexts (IconTheme  *theme, 
2299                      GHashTable *contexts)
2300 {
2301   GList *l = theme->dirs;
2302   IconThemeDir *dir;
2303   const char *context;
2304
2305   while (l != NULL)
2306     {
2307       dir = l->data;
2308
2309       context = g_quark_to_string (dir->context);
2310       g_hash_table_replace (contexts, (gpointer) context, NULL);
2311
2312       l = l->next;
2313     }
2314 }
2315
2316 static void
2317 load_icon_data (IconThemeDir *dir, const char *path, const char *name)
2318 {
2319   GKeyFile *icon_file;
2320   char *base_name;
2321   char **split;
2322   gsize length;
2323   char *str;
2324   char *split_point;
2325   int i;
2326   gint *ivalues;
2327   GError *error = NULL;
2328   
2329   GtkIconData *data;
2330
2331   icon_file = g_key_file_new ();
2332   g_key_file_set_list_separator (icon_file, ',');
2333   g_key_file_load_from_file (icon_file, path, 0, &error);
2334   if (error)
2335     {
2336       g_error_free (error);
2337       g_key_file_free (icon_file);      
2338       return;
2339     }
2340   else
2341     {
2342       base_name = strip_suffix (name);
2343       
2344       data = g_slice_new0 (GtkIconData);
2345       g_hash_table_replace (dir->icon_data, base_name, data);
2346       
2347       ivalues = g_key_file_get_integer_list (icon_file, 
2348                                              "Icon Data", "EmbeddedTextRectangle",
2349                                               &length, NULL);
2350       if (ivalues)
2351         {
2352           if (length == 4)
2353             {
2354               data->has_embedded_rect = TRUE;
2355               data->x0 = ivalues[0];
2356               data->y0 = ivalues[1];
2357               data->x1 = ivalues[2];
2358               data->y1 = ivalues[3];
2359             }
2360           
2361           g_free (ivalues);
2362         }
2363       
2364       str = g_key_file_get_string (icon_file, "Icon Data", "AttachPoints", NULL);
2365       if (str)
2366         {
2367           split = g_strsplit (str, "|", -1);
2368           
2369           data->n_attach_points = g_strv_length (split);
2370           data->attach_points = g_new (GdkPoint, data->n_attach_points);
2371
2372           i = 0;
2373           while (split[i] != NULL && i < data->n_attach_points)
2374             {
2375               split_point = strchr (split[i], ',');
2376               if (split_point)
2377                 {
2378                   *split_point = 0;
2379                   split_point++;
2380                   data->attach_points[i].x = atoi (split[i]);
2381                   data->attach_points[i].y = atoi (split_point);
2382                 }
2383               i++;
2384             }
2385           
2386           g_strfreev (split);
2387           g_free (str);
2388         }
2389       
2390       data->display_name = g_key_file_get_locale_string (icon_file, 
2391                                                          "Icon Data", "DisplayName",
2392                                                          NULL, NULL);
2393       g_key_file_free (icon_file);
2394     }
2395 }
2396
2397 static void
2398 scan_directory (GtkIconThemePrivate *icon_theme,
2399                 IconThemeDir *dir, char *full_dir)
2400 {
2401   GDir *gdir;
2402   const char *name;
2403
2404   GTK_NOTE (ICONTHEME, 
2405             g_print ("scanning directory %s\n", full_dir));
2406   dir->icons = g_hash_table_new_full (g_str_hash, g_str_equal,
2407                                       g_free, NULL);
2408   
2409   gdir = g_dir_open (full_dir, 0, NULL);
2410
2411   if (gdir == NULL)
2412     return;
2413
2414   while ((name = g_dir_read_name (gdir)))
2415     {
2416       char *path;
2417       char *base_name;
2418       IconSuffix suffix, hash_suffix;
2419
2420       if (g_str_has_suffix (name, ".icon"))
2421         {
2422           if (dir->icon_data == NULL)
2423             dir->icon_data = g_hash_table_new_full (g_str_hash, g_str_equal,
2424                                                     g_free, (GDestroyNotify)icon_data_free);
2425           
2426           path = g_build_filename (full_dir, name, NULL);
2427           if (g_file_test (path, G_FILE_TEST_IS_REGULAR))
2428             load_icon_data (dir, path, name);
2429           
2430           g_free (path);
2431           
2432           continue;
2433         }
2434
2435       suffix = suffix_from_name (name);
2436       if (suffix == ICON_SUFFIX_NONE)
2437         continue;
2438
2439       base_name = strip_suffix (name);
2440
2441       hash_suffix = GPOINTER_TO_INT (g_hash_table_lookup (dir->icons, base_name));
2442       g_hash_table_replace (icon_theme->all_icons, base_name, NULL);
2443       g_hash_table_replace (dir->icons, base_name, GUINT_TO_POINTER (hash_suffix| suffix));
2444     }
2445   
2446   g_dir_close (gdir);
2447 }
2448
2449 static void
2450 theme_subdir_load (GtkIconTheme *icon_theme,
2451                    IconTheme    *theme,
2452                    GKeyFile     *theme_file,
2453                    char         *subdir)
2454 {
2455   GList *d;
2456   char *type_string;
2457   IconThemeDir *dir;
2458   IconThemeDirType type;
2459   char *context_string;
2460   GQuark context;
2461   int size;
2462   int min_size;
2463   int max_size;
2464   int threshold;
2465   char *full_dir;
2466   GError *error = NULL;
2467   IconThemeDirMtime *dir_mtime;
2468
2469   size = g_key_file_get_integer (theme_file, subdir, "Size", &error);
2470   if (error)
2471     {
2472       g_error_free (error);
2473       g_warning ("Theme directory %s of theme %s has no size field\n", 
2474                  subdir, theme->name);
2475       return;
2476     }
2477   
2478   type = ICON_THEME_DIR_THRESHOLD;
2479   type_string = g_key_file_get_string (theme_file, subdir, "Type", NULL);
2480   if (type_string)
2481     {
2482       if (strcmp (type_string, "Fixed") == 0)
2483         type = ICON_THEME_DIR_FIXED;
2484       else if (strcmp (type_string, "Scalable") == 0)
2485         type = ICON_THEME_DIR_SCALABLE;
2486       else if (strcmp (type_string, "Threshold") == 0)
2487         type = ICON_THEME_DIR_THRESHOLD;
2488
2489       g_free (type_string);
2490     }
2491   
2492   context = 0;
2493   context_string = g_key_file_get_string (theme_file, subdir, "Context", NULL);
2494   if (context_string)
2495     {
2496       context = g_quark_from_string (context_string);
2497       g_free (context_string);
2498     }
2499
2500   max_size = g_key_file_get_integer (theme_file, subdir, "MaxSize", &error);
2501   if (error)
2502     {
2503       max_size = size;
2504
2505       g_error_free (error);
2506       error = NULL;
2507     }
2508
2509   min_size = g_key_file_get_integer (theme_file, subdir, "MinSize", &error);
2510   if (error)
2511     {
2512       min_size = size;
2513
2514       g_error_free (error);
2515       error = NULL;
2516     }
2517   
2518   threshold = g_key_file_get_integer (theme_file, subdir, "Threshold", &error);
2519   if (error)
2520     {
2521       threshold = 2;
2522
2523       g_error_free (error);
2524       error = NULL;
2525     }
2526
2527   for (d = icon_theme->priv->dir_mtimes; d; d = d->next)
2528     {
2529       dir_mtime = (IconThemeDirMtime *)d->data;
2530
2531       if (dir_mtime->mtime == 0)
2532         continue; /* directory doesn't exist */
2533
2534        full_dir = g_build_filename (dir_mtime->dir, subdir, NULL);
2535
2536       /* First, see if we have a cache for the directory */
2537       if (dir_mtime->cache != NULL || g_file_test (full_dir, G_FILE_TEST_IS_DIR))
2538         {
2539           if (dir_mtime->cache == NULL)
2540             {
2541               /* This will return NULL if the cache doesn't exist or is outdated */
2542               dir_mtime->cache = _gtk_icon_cache_new_for_path (dir_mtime->dir);
2543             }
2544           
2545           dir = g_new (IconThemeDir, 1);
2546           dir->type = type;
2547           dir->context = context;
2548           dir->size = size;
2549           dir->min_size = min_size;
2550           dir->max_size = max_size;
2551           dir->threshold = threshold;
2552           dir->dir = full_dir;
2553           dir->icon_data = NULL;
2554           dir->subdir = g_strdup (subdir);
2555           if (dir_mtime->cache != NULL)
2556             {
2557               dir->cache = _gtk_icon_cache_ref (dir_mtime->cache);
2558               dir->subdir_index = _gtk_icon_cache_get_directory_index (dir->cache, dir->subdir);
2559             }
2560           else
2561             {
2562               dir->cache = NULL;
2563               dir->subdir_index = -1;
2564               scan_directory (icon_theme->priv, dir, full_dir);
2565             }
2566
2567           theme->dirs = g_list_prepend (theme->dirs, dir);
2568         }
2569       else
2570         g_free (full_dir);
2571     }
2572 }
2573
2574 static void
2575 icon_data_free (GtkIconData *icon_data)
2576 {
2577   g_free (icon_data->attach_points);
2578   g_free (icon_data->display_name);
2579   g_slice_free (GtkIconData, icon_data);
2580 }
2581
2582 /*
2583  * GtkIconInfo
2584  */
2585
2586 G_DEFINE_BOXED_TYPE (GtkIconInfo, gtk_icon_info,
2587                      gtk_icon_info_copy,
2588                      gtk_icon_info_free)
2589
2590 static GtkIconInfo *
2591 icon_info_new (void)
2592 {
2593   GtkIconInfo *icon_info = g_slice_new0 (GtkIconInfo);
2594
2595   icon_info->scale = -1.;
2596   icon_info->ref_count = 1;
2597
2598   return icon_info;
2599 }
2600
2601 static GtkIconInfo *
2602 icon_info_new_builtin (BuiltinIcon *icon)
2603 {
2604   GtkIconInfo *icon_info = icon_info_new ();
2605
2606   icon_info->cache_pixbuf = g_object_ref (icon->pixbuf);
2607   icon_info->dir_type = ICON_THEME_DIR_THRESHOLD;
2608   icon_info->dir_size = icon->size;
2609   icon_info->threshold = 2;
2610
2611   return icon_info;
2612 }
2613
2614 /**
2615  * gtk_icon_info_copy:
2616  * @icon_info: a #GtkIconInfo
2617  * 
2618  * Make a copy of a #GtkIconInfo.
2619  * 
2620  * Return value: the new GtkIconInfo
2621  *
2622  * Since: 2.4
2623  **/
2624 GtkIconInfo *
2625 gtk_icon_info_copy (GtkIconInfo *icon_info)
2626 {
2627   
2628   g_return_val_if_fail (icon_info != NULL, NULL);
2629
2630   icon_info->ref_count++;
2631
2632   return icon_info;
2633 }
2634
2635 /**
2636  * gtk_icon_info_free:
2637  * @icon_info: a #GtkIconInfo
2638  * 
2639  * Free a #GtkIconInfo and associated information
2640  *
2641  * Since: 2.4
2642  **/
2643 void
2644 gtk_icon_info_free (GtkIconInfo *icon_info)
2645 {
2646   g_return_if_fail (icon_info != NULL);
2647
2648   icon_info->ref_count--;
2649   if (icon_info->ref_count > 0)
2650     return;
2651  
2652   g_free (icon_info->filename);
2653   if (icon_info->loadable)
2654     g_object_unref (icon_info->loadable);
2655   g_slist_foreach (icon_info->emblem_infos, (GFunc)gtk_icon_info_free, NULL);
2656   g_slist_free (icon_info->emblem_infos);
2657   if (icon_info->pixbuf)
2658     g_object_unref (icon_info->pixbuf);
2659   if (icon_info->cache_pixbuf)
2660     g_object_unref (icon_info->cache_pixbuf);
2661
2662   g_slice_free (GtkIconInfo, icon_info);
2663 }
2664
2665 /**
2666  * gtk_icon_info_get_base_size:
2667  * @icon_info: a #GtkIconInfo
2668  * 
2669  * Gets the base size for the icon. The base size
2670  * is a size for the icon that was specified by
2671  * the icon theme creator. This may be different
2672  * than the actual size of image; an example of
2673  * this is small emblem icons that can be attached
2674  * to a larger icon. These icons will be given
2675  * the same base size as the larger icons to which
2676  * they are attached.
2677  * 
2678  * Return value: the base size, or 0, if no base
2679  *  size is known for the icon.
2680  *
2681  * Since: 2.4
2682  **/
2683 gint
2684 gtk_icon_info_get_base_size (GtkIconInfo *icon_info)
2685 {
2686   g_return_val_if_fail (icon_info != NULL, 0);
2687
2688   return icon_info->dir_size;
2689 }
2690
2691 /**
2692  * gtk_icon_info_get_filename:
2693  * @icon_info: a #GtkIconInfo
2694  * 
2695  * Gets the filename for the icon. If the
2696  * %GTK_ICON_LOOKUP_USE_BUILTIN flag was passed
2697  * to gtk_icon_theme_lookup_icon(), there may be
2698  * no filename if a builtin icon is returned; in this
2699  * case, you should use gtk_icon_info_get_builtin_pixbuf().
2700  * 
2701  * Return value: the filename for the icon, or %NULL
2702  *  if gtk_icon_info_get_builtin_pixbuf() should
2703  *  be used instead. The return value is owned by
2704  *  GTK+ and should not be modified or freed.
2705  *
2706  * Since: 2.4
2707  **/
2708 G_CONST_RETURN gchar *
2709 gtk_icon_info_get_filename (GtkIconInfo *icon_info)
2710 {
2711   g_return_val_if_fail (icon_info != NULL, NULL);
2712
2713   return icon_info->filename;
2714 }
2715
2716 /**
2717  * gtk_icon_info_get_builtin_pixbuf:
2718  * @icon_info: a #GtkIconInfo structure
2719  * 
2720  * Gets the built-in image for this icon, if any. To allow
2721  * GTK+ to use built in icon images, you must pass the
2722  * %GTK_ICON_LOOKUP_USE_BUILTIN to
2723  * gtk_icon_theme_lookup_icon().
2724  *
2725  * Return value: (transfer none): the built-in image pixbuf, or %NULL. No
2726  *  extra reference is added to the returned pixbuf, so if
2727  *  you want to keep it around, you must use g_object_ref().
2728  *  The returned image must not be modified.
2729  *
2730  * Since: 2.4
2731  **/
2732 GdkPixbuf *
2733 gtk_icon_info_get_builtin_pixbuf (GtkIconInfo *icon_info)
2734 {
2735   g_return_val_if_fail (icon_info != NULL, NULL);
2736
2737   if (icon_info->filename)
2738     return NULL;
2739   
2740   return icon_info->cache_pixbuf;
2741 }
2742
2743 static gboolean icon_info_ensure_scale_and_pixbuf (GtkIconInfo*, gboolean);
2744
2745 /* Combine the icon with all emblems, the first emblem is placed 
2746  * in the southeast corner. Scale emblems to be at most 3/4 of the
2747  * size of the icon itself.
2748  */
2749 static void 
2750 apply_emblems (GtkIconInfo *info)
2751 {
2752   GdkPixbuf *icon = NULL;
2753   gint w, h, pos;
2754   GSList *l;
2755
2756   if (info->emblem_infos == NULL)
2757     return;
2758
2759   w = gdk_pixbuf_get_width (info->pixbuf);
2760   h = gdk_pixbuf_get_height (info->pixbuf);
2761
2762   for (l = info->emblem_infos, pos = 0; l; l = l->next, pos++)
2763     {
2764       GtkIconInfo *emblem_info = l->data;
2765
2766       if (icon_info_ensure_scale_and_pixbuf (emblem_info, FALSE))
2767         {
2768           GdkPixbuf *emblem = emblem_info->pixbuf;
2769           gint ew, eh;
2770           gint x = 0, y = 0; /* silence compiler */
2771           gdouble scale;
2772
2773           ew = gdk_pixbuf_get_width (emblem);
2774           eh = gdk_pixbuf_get_height (emblem);
2775           if (ew >= w)
2776             {
2777               scale = 0.75;
2778               ew = ew * 0.75;
2779               eh = eh * 0.75;
2780             }
2781           else
2782             scale = 1.0;
2783
2784           switch (pos % 4)
2785             {
2786             case 0:
2787               x = w - ew;
2788               y = h - eh;
2789               break;
2790             case 1:
2791               x = w - ew;
2792               y = 0;
2793               break;
2794             case 2:
2795               x = 0;
2796               y = h - eh;
2797               break;
2798             case 3:
2799               x = 0;
2800               y = 0;
2801               break;
2802             }
2803
2804           if (icon == NULL)
2805             {
2806               icon = gdk_pixbuf_copy (info->pixbuf);
2807               if (icon == NULL)
2808                 break;
2809             }
2810
2811           gdk_pixbuf_composite (emblem, icon, x, y, ew, eh, x, y,
2812                                 scale, scale, GDK_INTERP_BILINEAR, 255);
2813        }
2814    }
2815
2816   if (icon)
2817     {
2818       g_object_unref (info->pixbuf);
2819       info->pixbuf = icon;
2820     }
2821 }
2822
2823 /* This function contains the complicated logic for deciding
2824  * on the size at which to load the icon and loading it at
2825  * that size.
2826  */
2827 static gboolean
2828 icon_info_ensure_scale_and_pixbuf (GtkIconInfo  *icon_info,
2829                                    gboolean      scale_only)
2830 {
2831   int image_width, image_height;
2832   GdkPixbuf *source_pixbuf;
2833   gboolean is_svg;
2834
2835   /* First check if we already succeeded have the necessary
2836    * information (or failed earlier)
2837    */
2838   if (scale_only && icon_info->scale >= 0)
2839     return TRUE;
2840
2841   if (icon_info->pixbuf)
2842     return TRUE;
2843
2844   if (icon_info->load_error)
2845     return FALSE;
2846
2847   /* SVG icons are a special case - we just immediately scale them
2848    * to the desired size
2849    */
2850   if (icon_info->filename && !icon_info->loadable) 
2851     {
2852       GFile *file;
2853
2854       file = g_file_new_for_path (icon_info->filename);
2855       icon_info->loadable = G_LOADABLE_ICON (g_file_icon_new (file));
2856       g_object_unref (file);
2857     }
2858
2859   is_svg = FALSE;
2860   if (G_IS_FILE_ICON (icon_info->loadable))
2861     {
2862       GFile *file;
2863       GFileInfo *file_info;
2864       const gchar *content_type;
2865
2866       file = g_file_icon_get_file (G_FILE_ICON (icon_info->loadable));
2867       file_info = g_file_query_info (file, 
2868                                      G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
2869                                      G_FILE_QUERY_INFO_NONE,
2870                                      NULL, NULL);
2871       if (file_info) 
2872         {
2873           content_type = g_file_info_get_content_type (file_info);
2874
2875           if (content_type && strcmp (content_type, "image/svg+xml") == 0)
2876             is_svg = TRUE;
2877
2878           g_object_unref (file_info);
2879        }
2880     }
2881
2882   if (is_svg)
2883     {
2884       GInputStream *stream;
2885
2886       icon_info->scale = icon_info->desired_size / 1000.;
2887
2888       if (scale_only)
2889         return TRUE;
2890       
2891       stream = g_loadable_icon_load (icon_info->loadable,
2892                                      icon_info->desired_size,
2893                                      NULL, NULL,
2894                                      &icon_info->load_error);
2895       if (stream)
2896         {
2897           icon_info->pixbuf = gdk_pixbuf_new_from_stream_at_scale (stream,
2898                                                                    icon_info->desired_size,
2899                                                                    icon_info->desired_size,
2900                                                                    TRUE,
2901                                                                    NULL,
2902                                                                    &icon_info->load_error);
2903           g_object_unref (stream);
2904         }
2905
2906       if (!icon_info->pixbuf)
2907         return FALSE;
2908
2909       apply_emblems (icon_info);
2910         
2911       return TRUE;
2912     }
2913
2914   /* In many cases, the scale can be determined without actual access
2915    * to the icon file. This is generally true when we have a size
2916    * for the directory where the icon is; the image size doesn't
2917    * matter in that case.
2918    */
2919   if (icon_info->forced_size)
2920     icon_info->scale = -1;
2921   else if (icon_info->dir_type == ICON_THEME_DIR_FIXED)
2922     icon_info->scale = 1.0;
2923   else if (icon_info->dir_type == ICON_THEME_DIR_THRESHOLD)
2924     {
2925       if (icon_info->desired_size >= icon_info->dir_size - icon_info->threshold &&
2926           icon_info->desired_size <= icon_info->dir_size + icon_info->threshold)
2927         icon_info->scale = 1.0;
2928       else if (icon_info->dir_size > 0)
2929         icon_info->scale =(gdouble) icon_info->desired_size / icon_info->dir_size;
2930     }
2931   else if (icon_info->dir_type == ICON_THEME_DIR_SCALABLE)
2932     {
2933       if (icon_info->dir_size > 0)
2934         icon_info->scale = (gdouble) icon_info->desired_size / icon_info->dir_size;
2935     }
2936
2937   if (icon_info->scale >= 0. && scale_only)
2938     return TRUE;
2939
2940   /* At this point, we need to actually get the icon; either from the
2941    * builtin image or by loading the file
2942    */
2943   source_pixbuf = NULL;
2944   if (icon_info->cache_pixbuf)
2945     source_pixbuf = g_object_ref (icon_info->cache_pixbuf);
2946   else
2947     {
2948       GInputStream *stream;
2949
2950       stream = g_loadable_icon_load (icon_info->loadable,
2951                                      icon_info->desired_size,
2952                                      NULL, NULL,
2953                                      &icon_info->load_error);
2954       if (stream)
2955         {
2956           source_pixbuf = gdk_pixbuf_new_from_stream (stream,
2957                                                       NULL,
2958                                                       &icon_info->load_error);
2959           g_object_unref (stream);
2960         }
2961     }
2962
2963   if (!source_pixbuf)
2964     return FALSE;
2965
2966   /* Do scale calculations that depend on the image size
2967    */
2968   image_width = gdk_pixbuf_get_width (source_pixbuf);
2969   image_height = gdk_pixbuf_get_height (source_pixbuf);
2970
2971   if (icon_info->scale < 0.0)
2972     {
2973       gint image_size = MAX (image_width, image_height);
2974       if (image_size > 0)
2975         icon_info->scale = (gdouble)icon_info->desired_size / (gdouble)image_size;
2976       else
2977         icon_info->scale = 1.0;
2978       
2979       if (icon_info->dir_type == ICON_THEME_DIR_UNTHEMED && 
2980           !icon_info->forced_size)
2981         icon_info->scale = MIN (icon_info->scale, 1.0);
2982     }
2983
2984   /* We don't short-circuit out here for scale_only, since, now
2985    * we've loaded the icon, we might as well go ahead and finish
2986    * the job. This is a bit of a waste when we scale here
2987    * and never get the final pixbuf; at the cost of a bit of
2988    * extra complexity, we could keep the source pixbuf around
2989    * but not actually scale it until needed.
2990    */
2991   if (icon_info->scale == 1.0)
2992     icon_info->pixbuf = source_pixbuf;
2993   else
2994     {
2995       icon_info->pixbuf = gdk_pixbuf_scale_simple (source_pixbuf,
2996                                                    0.5 + image_width * icon_info->scale,
2997                                                    0.5 + image_height * icon_info->scale,
2998                                                    GDK_INTERP_BILINEAR);
2999       g_object_unref (source_pixbuf);
3000     }
3001
3002   apply_emblems (icon_info);
3003
3004   return TRUE;
3005 }
3006
3007 /**
3008  * gtk_icon_info_load_icon:
3009  * @icon_info: a #GtkIconInfo structure from gtk_icon_theme_lookup_icon()
3010  * @error: (allow-none): location to store error information on failure,
3011  *     or %NULL.
3012  *
3013  * Renders an icon previously looked up in an icon theme using
3014  * gtk_icon_theme_lookup_icon(); the size will be based on the size
3015  * passed to gtk_icon_theme_lookup_icon(). Note that the resulting
3016  * pixbuf may not be exactly this size; an icon theme may have icons
3017  * that differ slightly from their nominal sizes, and in addition GTK+
3018  * will avoid scaling icons that it considers sufficiently close to the
3019  * requested size or for which the source image would have to be scaled
3020  * up too far. (This maintains sharpness.). This behaviour can be changed
3021  * by passing the %GTK_ICON_LOOKUP_FORCE_SIZE flag when obtaining
3022  * the #GtkIconInfo. If this flag has been specified, the pixbuf
3023  * returned by this function will be scaled to the exact size.
3024  *
3025  * Return value: (transfer full): the rendered icon; this may be a newly
3026  *     created icon or a new reference to an internal icon, so you must
3027  *     not modify the icon. Use g_object_unref() to release your reference
3028  *     to the icon.
3029  *
3030  * Since: 2.4
3031  **/
3032 GdkPixbuf *
3033 gtk_icon_info_load_icon (GtkIconInfo *icon_info,
3034                          GError     **error)
3035 {
3036   g_return_val_if_fail (icon_info != NULL, NULL);
3037   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
3038
3039   if (!icon_info_ensure_scale_and_pixbuf (icon_info, FALSE))
3040     {
3041       if (icon_info->load_error)
3042         g_propagate_error (error, icon_info->load_error);
3043       else
3044         g_set_error_literal (error,  
3045                              GTK_ICON_THEME_ERROR,  
3046                              GTK_ICON_THEME_NOT_FOUND,
3047                              _("Failed to load icon"));
3048  
3049       return NULL;
3050     }
3051
3052   return g_object_ref (icon_info->pixbuf);
3053 }
3054
3055 static gchar *
3056 gdk_color_to_css (GdkColor *color)
3057 {
3058   return g_strdup_printf ("rgb(%d,%d,%d)",
3059                           color->red >> 8,
3060                           color->green >> 8,
3061                           color->blue >> 8);
3062 }
3063
3064 /**
3065  * gtk_icon_info_load_symbolic:
3066  * @icon_info: a #GtkIconInfo
3067  * @fg: a #GdkColor representing the foreground color of the icon
3068  * @success_color: (allow-none): a #GdkColor representing the warning color
3069  *     of the icon or %NULL to use the default color
3070  * @warning_color: (allow-none): a #GdkColor representing the warning color
3071  *     of the icon or %NULL to use the default color
3072  * @error_color: (allow-none): a #GdkColor representing the error color
3073  *     of the icon or %NULL to use the default color (allow-none)
3074  * @was_symbolic: (allow-none): a #gboolean, returns whether the loaded icon
3075  *     was a symbolic one and whether the @fg color was applied to it.
3076  * @error: (allow-none): location to store error information on failure,
3077  *     or %NULL.
3078  *
3079  * Loads an icon, modifying it to match the system colours for the foreground,
3080  * success, warning and error colors provided. If the icon is not a symbolic
3081  * one, the function will return the result from gtk_icon_info_load_icon().
3082  *
3083  * This allows loading symbolic icons that will match the system theme.
3084  *
3085  * Unless you are implementing a widget, you will want to use
3086  * g_themed_icon_new_with_default_fallbacks() to load the icon.
3087  *
3088  * As implementation details, the icon loaded needs to be of SVG type,
3089  * contain the "symbolic" term as the last component of the icon name,
3090  * and use the 'fg', 'success', 'warning' and 'error' CSS styles in the
3091  * SVG file itself.
3092  *
3093  * See the <ulink url="http://www.freedesktop.org/wiki/SymbolicIcons">Symbolic Icons spec</ulink>
3094  * for more information about symbolic icons.
3095  *
3096  * Return value: (transfer full): a #GdkPixbuf representing the loaded icon
3097  *
3098  * Since: 3.0
3099  **/
3100 GdkPixbuf *
3101 gtk_icon_info_load_symbolic (GtkIconInfo  *icon_info,
3102                              GdkColor     *fg,
3103                              GdkColor     *success_color,
3104                              GdkColor     *warning_color,
3105                              GdkColor     *error_color,
3106                              gboolean     *was_symbolic,
3107                              GError      **error)
3108 {
3109   GdkPixbuf *pixbuf;
3110   GInputStream *stream;
3111   gchar *data;
3112   gchar *css_fg;
3113   gchar *css_success;
3114   gchar *css_warning;
3115   gchar *css_error;
3116
3117   g_return_val_if_fail (fg != NULL, NULL);
3118
3119   if (!icon_info->filename ||
3120       !g_str_has_suffix (icon_info->filename, "-symbolic.svg"))
3121     {
3122       if (was_symbolic)
3123         *was_symbolic = FALSE;
3124       return gtk_icon_info_load_icon (icon_info, error);
3125     }
3126
3127   if (was_symbolic)
3128     *was_symbolic = TRUE;
3129
3130   css_fg = gdk_color_to_css (fg);
3131   if (!warning_color)
3132     {
3133       GdkColor warning_default_color = { 0, 0xf500, 0x7900, 0x3e00 };
3134       css_warning = gdk_color_to_css (&warning_default_color);
3135     }
3136   else
3137       css_warning = gdk_color_to_css (warning_color);
3138   if (!error_color)
3139     {
3140       GdkColor error_default_color = { 0, 0xcc00, 0x0000, 0x0000 };
3141       css_error = gdk_color_to_css (&error_default_color);
3142     }
3143   else
3144       css_error = gdk_color_to_css (error_color);
3145   if (!success_color)
3146     {
3147       GdkColor success_default_color = { 0, 0x4e00, 0x9a00, 0x0600 };
3148       css_success = gdk_color_to_css (&success_default_color);
3149     }
3150   else
3151       css_success = gdk_color_to_css (success_color);
3152
3153   data = g_strconcat (
3154 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
3155 "<svg version=\"1.1\"\n"
3156 "     xmlns=\"http://www.w3.org/2000/svg\"\n"
3157 "     xmlns:xi=\"http://www.w3.org/2001/XInclude\"\n"
3158 "     width=\"16\"\n"
3159 "     height=\"16\">\n"
3160 "  <style type=\"text/css\">\n"
3161 "    rect,path {\n"
3162 "      fill: ", css_fg," !important;\n"
3163 "    }\n"
3164 "    .warning {\n"
3165 "      fill: ", css_warning," !important;\n"
3166 "    }\n"
3167 "    .error {\n"
3168 "      fill: ", css_error," !important;\n"
3169 "    }\n"
3170 "    .success {\n"
3171 "      fill: ", css_success," !important;\n"
3172 "    }\n"
3173 "  </style>\n"
3174 "  <xi:include href=\"", icon_info->filename, "\"/>\n"
3175 "</svg>",
3176          NULL);
3177   g_free (css_fg);
3178   g_free (css_warning);
3179   g_free (css_success);
3180   g_free (css_error);
3181
3182   stream = g_memory_input_stream_new_from_data (data, -1, g_free);
3183
3184   pixbuf = gdk_pixbuf_new_from_stream_at_scale (stream,
3185                                                 icon_info->desired_size,
3186                                                 icon_info->desired_size,
3187                                                 TRUE,
3188                                                 NULL,
3189                                                 error);
3190   g_object_unref (stream);
3191
3192   return pixbuf;
3193 }
3194
3195 /**
3196  * gtk_icon_info_load_symbolic_for_style:
3197  * @icon_info: a #GtkIconInfo
3198  * @style: a #GtkStyle to take the colors from
3199  * @state: the widget state to use for colors
3200  * @was_symbolic: (allow-none): a #gboolean, returns whether the loaded icon
3201  *     was a symbolic one and whether the @fg color was applied to it.
3202  * @error: (allow-none): location to store error information on failure,
3203  *     or %NULL.
3204  *
3205  * Loads an icon, modifying it to match the system colours for the foreground,
3206  * success, warning and error colors provided. If the icon is not a symbolic
3207  * one, the function will return the result from gtk_icon_info_load_icon().
3208  *
3209  * This allows loading symbolic icons that will match the system theme.
3210  *
3211  * See gtk_icon_info_load_symbolic() for more details.
3212  *
3213  * Return value: (transfer full): a #GdkPixbuf representing the loaded icon
3214  *
3215  * Since: 3.0
3216  **/
3217 GdkPixbuf *
3218 gtk_icon_info_load_symbolic_for_style (GtkIconInfo   *icon_info,
3219                                        GtkStyle      *style,
3220                                        GtkStateType   state,
3221                                        gboolean      *was_symbolic,
3222                                        GError       **error)
3223 {
3224   GdkColor success_color;
3225   GdkColor warning_color;
3226   GdkColor error_color;
3227   GdkColor *fg;
3228   GdkColor *success = NULL;
3229   GdkColor *warning = NULL;
3230   GdkColor *err = NULL;
3231
3232   fg = &style->fg[state];
3233   if (gtk_style_lookup_color (style, "success_color", &success_color))
3234     success = &success_color;
3235   if (gtk_style_lookup_color (style, "warning_color", &warning_color))
3236     warning = &warning_color;
3237   if (gtk_style_lookup_color (style, "error_color", &error_color))
3238     err = &error_color;
3239
3240   return gtk_icon_info_load_symbolic (icon_info, fg, success, warning, err,
3241                                       was_symbolic, error);
3242 }
3243
3244 /**
3245  * gtk_icon_info_set_raw_coordinates:
3246  * @icon_info: a #GtkIconInfo
3247  * @raw_coordinates: whether the coordinates of embedded rectangles
3248  *   and attached points should be returned in their original
3249  *   (unscaled) form.
3250  * 
3251  * Sets whether the coordinates returned by gtk_icon_info_get_embedded_rect()
3252  * and gtk_icon_info_get_attach_points() should be returned in their
3253  * original form as specified in the icon theme, instead of scaled
3254  * appropriately for the pixbuf returned by gtk_icon_info_load_icon().
3255  *
3256  * Raw coordinates are somewhat strange; they are specified to be with
3257  * respect to the unscaled pixmap for PNG and XPM icons, but for SVG
3258  * icons, they are in a 1000x1000 coordinate space that is scaled
3259  * to the final size of the icon.  You can determine if the icon is an SVG
3260  * icon by using gtk_icon_info_get_filename(), and seeing if it is non-%NULL
3261  * and ends in '.svg'.
3262  *
3263  * This function is provided primarily to allow compatibility wrappers
3264  * for older API's, and is not expected to be useful for applications.
3265  *
3266  * Since: 2.4
3267  **/
3268 void
3269 gtk_icon_info_set_raw_coordinates (GtkIconInfo *icon_info,
3270                                    gboolean     raw_coordinates)
3271 {
3272   g_return_if_fail (icon_info != NULL);
3273   
3274   icon_info->raw_coordinates = raw_coordinates != FALSE;
3275 }
3276
3277 /* Scale coordinates from the icon data prior to returning
3278  * them to the user.
3279  */
3280 static gboolean
3281 icon_info_scale_point (GtkIconInfo  *icon_info,
3282                        gint          x,
3283                        gint          y,
3284                        gint         *x_out,
3285                        gint         *y_out)
3286 {
3287   if (icon_info->raw_coordinates)
3288     {
3289       *x_out = x;
3290       *y_out = y;
3291     }
3292   else
3293     {
3294       if (!icon_info_ensure_scale_and_pixbuf (icon_info, TRUE))
3295         return FALSE;
3296
3297       *x_out = 0.5 + x * icon_info->scale;
3298       *y_out = 0.5 + y * icon_info->scale;
3299     }
3300
3301   return TRUE;
3302 }
3303
3304 /**
3305  * gtk_icon_info_get_embedded_rect:
3306  * @icon_info: a #GtkIconInfo
3307  * @rectangle: #GdkRectangle in which to store embedded
3308  *   rectangle coordinates; coordinates are only stored
3309  *   when this function returns %TRUE.
3310  *
3311  * Gets the coordinates of a rectangle within the icon
3312  * that can be used for display of information such
3313  * as a preview of the contents of a text file.
3314  * See gtk_icon_info_set_raw_coordinates() for further
3315  * information about the coordinate system.
3316  * 
3317  * Return value: %TRUE if the icon has an embedded rectangle
3318  *
3319  * Since: 2.4
3320  **/
3321 gboolean
3322 gtk_icon_info_get_embedded_rect (GtkIconInfo  *icon_info,
3323                                  GdkRectangle *rectangle)
3324 {
3325   g_return_val_if_fail (icon_info != NULL, FALSE);
3326
3327   if (icon_info->data && icon_info->data->has_embedded_rect &&
3328       icon_info_ensure_scale_and_pixbuf (icon_info, TRUE))
3329     {
3330       gint scaled_x0, scaled_y0;
3331       gint scaled_x1, scaled_y1;
3332       
3333       if (rectangle)
3334         {
3335           icon_info_scale_point (icon_info,
3336                                  icon_info->data->x0, icon_info->data->y0,
3337                                  &scaled_x0, &scaled_y0);
3338           icon_info_scale_point (icon_info,
3339                                  icon_info->data->x1, icon_info->data->y1,
3340                                  &scaled_x1, &scaled_y1);
3341           
3342           rectangle->x = scaled_x0;
3343           rectangle->y = scaled_y0;
3344           rectangle->width = scaled_x1 - rectangle->x;
3345           rectangle->height = scaled_y1 - rectangle->y;
3346         }
3347
3348       return TRUE;
3349     }
3350   else
3351     return FALSE;
3352 }
3353
3354 /**
3355  * gtk_icon_info_get_attach_points:
3356  * @icon_info: a #GtkIconInfo
3357  * @points: (allow-none): (array length=n_points) (out): location to store pointer to an array of points, or %NULL
3358  *          free the array of points with g_free().
3359  * @n_points: (allow-none): location to store the number of points in @points, or %NULL
3360  * 
3361  * Fetches the set of attach points for an icon. An attach point
3362  * is a location in the icon that can be used as anchor points for attaching
3363  * emblems or overlays to the icon.
3364  * 
3365  * Return value: %TRUE if there are any attach points for the icon.
3366  *
3367  * Since: 2.4
3368  **/
3369 gboolean
3370 gtk_icon_info_get_attach_points (GtkIconInfo *icon_info,
3371                                  GdkPoint   **points,
3372                                  gint        *n_points)
3373 {
3374   g_return_val_if_fail (icon_info != NULL, FALSE);
3375   
3376   if (icon_info->data && icon_info->data->n_attach_points &&
3377       icon_info_ensure_scale_and_pixbuf (icon_info, TRUE))
3378     {
3379       if (points)
3380         {
3381           gint i;
3382           
3383           *points = g_new (GdkPoint, icon_info->data->n_attach_points);
3384           for (i = 0; i < icon_info->data->n_attach_points; i++)
3385             icon_info_scale_point (icon_info,
3386                                    icon_info->data->attach_points[i].x,
3387                                    icon_info->data->attach_points[i].y,
3388                                    &(*points)[i].x,
3389                                    &(*points)[i].y);
3390         }
3391           
3392       if (n_points)
3393         *n_points = icon_info->data->n_attach_points;
3394
3395       return TRUE;
3396     }
3397   else
3398     {
3399       if (points)
3400         *points = NULL;
3401       if (n_points)
3402         *n_points = 0;
3403       
3404       return FALSE;
3405     }
3406 }
3407
3408 /**
3409  * gtk_icon_info_get_display_name:
3410  * @icon_info: a #GtkIconInfo
3411  * 
3412  * Gets the display name for an icon. A display name is a
3413  * string to be used in place of the icon name in a user
3414  * visible context like a list of icons.
3415  * 
3416  * Return value: the display name for the icon or %NULL, if
3417  *  the icon doesn't have a specified display name. This value
3418  *  is owned @icon_info and must not be modified or free.
3419  *
3420  * Since: 2.4
3421  **/
3422 G_CONST_RETURN gchar *
3423 gtk_icon_info_get_display_name (GtkIconInfo *icon_info)
3424 {
3425   g_return_val_if_fail (icon_info != NULL, NULL);
3426
3427   if (icon_info->data)
3428     return icon_info->data->display_name;
3429   else
3430     return NULL;
3431 }
3432
3433 /*
3434  * Builtin icons
3435  */
3436
3437
3438 /**
3439  * gtk_icon_theme_add_builtin_icon:
3440  * @icon_name: the name of the icon to register
3441  * @size: the size at which to register the icon (different
3442  *        images can be registered for the same icon name
3443  *        at different sizes.)
3444  * @pixbuf: #GdkPixbuf that contains the image to use
3445  *          for @icon_name.
3446  * 
3447  * Registers a built-in icon for icon theme lookups. The idea
3448  * of built-in icons is to allow an application or library
3449  * that uses themed icons to function requiring files to
3450  * be present in the file system. For instance, the default
3451  * images for all of GTK+'s stock icons are registered
3452  * as built-icons.
3453  *
3454  * In general, if you use gtk_icon_theme_add_builtin_icon()
3455  * you should also install the icon in the icon theme, so
3456  * that the icon is generally available.
3457  *
3458  * This function will generally be used with pixbufs loaded
3459  * via gdk_pixbuf_new_from_inline().
3460  *
3461  * Since: 2.4
3462  **/
3463 void
3464 gtk_icon_theme_add_builtin_icon (const gchar *icon_name,
3465                                  gint         size,
3466                                  GdkPixbuf   *pixbuf)
3467 {
3468   BuiltinIcon *default_icon;
3469   GSList *icons;
3470   gpointer key;
3471
3472   g_return_if_fail (icon_name != NULL);
3473   g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
3474   
3475   if (!icon_theme_builtin_icons)
3476     icon_theme_builtin_icons = g_hash_table_new (g_str_hash, g_str_equal);
3477
3478   icons = g_hash_table_lookup (icon_theme_builtin_icons, icon_name);
3479   if (!icons)
3480     key = g_strdup (icon_name);
3481   else
3482     key = (gpointer)icon_name;  /* Won't get stored */
3483
3484   default_icon = g_new (BuiltinIcon, 1);
3485   default_icon->size = size;
3486   default_icon->pixbuf = g_object_ref (pixbuf);
3487   icons = g_slist_prepend (icons, default_icon);
3488
3489   /* Replaces value, leaves key untouched
3490    */
3491   g_hash_table_insert (icon_theme_builtin_icons, key, icons);
3492 }
3493
3494 /* Look up a builtin icon; the min_difference_p and
3495  * has_larger_p out parameters allow us to combine
3496  * this lookup with searching through the actual directories
3497  * of the "hicolor" icon theme. See theme_lookup_icon()
3498  * for how they are used.
3499  */
3500 static BuiltinIcon *
3501 find_builtin_icon (const gchar *icon_name,
3502                    gint         size,
3503                    gint        *min_difference_p,
3504                    gboolean    *has_larger_p)
3505 {
3506   GSList *icons = NULL;
3507   gint min_difference = G_MAXINT;
3508   gboolean has_larger = FALSE;
3509   BuiltinIcon *min_icon = NULL;
3510   
3511   if (!icon_theme_builtin_icons)
3512     return NULL;
3513
3514   icons = g_hash_table_lookup (icon_theme_builtin_icons, icon_name);
3515
3516   while (icons)
3517     {
3518       BuiltinIcon *default_icon = icons->data;
3519       int min, max, difference;
3520       gboolean smaller;
3521       
3522       min = default_icon->size - 2;
3523       max = default_icon->size + 2;
3524       smaller = size < min;
3525       if (size < min)
3526         difference = min - size;
3527       else if (size > max)
3528         difference = size - max;
3529       else
3530         difference = 0;
3531       
3532       if (difference == 0)
3533         {
3534           min_icon = default_icon;
3535           break;
3536         }
3537       
3538       if (!has_larger)
3539         {
3540           if (difference < min_difference || smaller)
3541             {
3542               min_difference = difference;
3543               min_icon = default_icon;
3544               has_larger = smaller;
3545             }
3546         }
3547       else
3548         {
3549           if (difference < min_difference && smaller)
3550             {
3551               min_difference = difference;
3552               min_icon = default_icon;
3553             }
3554         }
3555       
3556       icons = icons->next;
3557     }
3558
3559   if (min_difference_p)
3560     *min_difference_p = min_difference;
3561   if (has_larger_p)
3562     *has_larger_p = has_larger;
3563
3564   return min_icon;
3565 }
3566
3567 void
3568 _gtk_icon_theme_check_reload (GdkDisplay *display)
3569 {
3570   gint n_screens, i;
3571   GdkScreen *screen;
3572   GtkIconTheme *icon_theme;
3573
3574   n_screens = gdk_display_get_n_screens (display);
3575   
3576   for (i = 0; i < n_screens; i++)
3577     {
3578       screen = gdk_display_get_screen (display, i);
3579
3580       icon_theme = g_object_get_data (G_OBJECT (screen), "gtk-icon-theme");
3581       if (icon_theme)
3582         {
3583           icon_theme->priv->check_reload = TRUE;
3584           ensure_valid_themes (icon_theme);
3585           icon_theme->priv->check_reload = FALSE;
3586         }
3587     }
3588 }
3589
3590
3591 /**
3592  * gtk_icon_theme_lookup_by_gicon:
3593  * @icon_theme: a #GtkIconTheme
3594  * @icon: the #GIcon to look up
3595  * @size: desired icon size
3596  * @flags: flags modifying the behavior of the icon lookup
3597  * 
3598  * Looks up an icon and returns a structure containing
3599  * information such as the filename of the icon. 
3600  * The icon can then be rendered into a pixbuf using
3601  * gtk_icon_info_load_icon().
3602  *
3603  * Return value: a #GtkIconInfo structure containing 
3604  *     information about the icon, or %NULL if the icon 
3605  *     wasn't found. Free with gtk_icon_info_free()
3606  *
3607  * Since: 2.14
3608  */
3609 GtkIconInfo *
3610 gtk_icon_theme_lookup_by_gicon (GtkIconTheme       *icon_theme,
3611                                 GIcon              *icon,
3612                                 gint                size,
3613                                 GtkIconLookupFlags  flags)
3614 {
3615   GtkIconInfo *info;
3616
3617   g_return_val_if_fail (GTK_IS_ICON_THEME (icon_theme), NULL);
3618   g_return_val_if_fail (G_IS_ICON (icon), NULL);
3619
3620   if (G_IS_LOADABLE_ICON (icon))
3621     {
3622       info = icon_info_new ();
3623       info->loadable = G_LOADABLE_ICON (g_object_ref (icon));
3624
3625       info->dir_type = ICON_THEME_DIR_UNTHEMED;
3626       info->dir_size = size;
3627       info->desired_size = size;
3628       info->threshold = 2;
3629       info->forced_size = (flags & GTK_ICON_LOOKUP_FORCE_SIZE) != 0;
3630
3631       return info;
3632     }
3633   else if (G_IS_THEMED_ICON (icon))
3634     {
3635       const gchar **names;
3636
3637       names = (const gchar **)g_themed_icon_get_names (G_THEMED_ICON (icon));
3638       info = gtk_icon_theme_choose_icon (icon_theme, names, size, flags);
3639
3640       return info;
3641     }
3642   else if (G_IS_EMBLEMED_ICON (icon))
3643     {
3644       GIcon *base, *emblem;
3645       GList *list, *l;
3646       GtkIconInfo *emblem_info;
3647
3648       base = g_emblemed_icon_get_icon (G_EMBLEMED_ICON (icon));
3649       info = gtk_icon_theme_lookup_by_gicon (icon_theme, base, size, flags);
3650       if (info)
3651         {
3652           list = g_emblemed_icon_get_emblems (G_EMBLEMED_ICON (icon));
3653           for (l = list; l; l = l->next)
3654             {
3655               emblem = g_emblem_get_icon (G_EMBLEM (l->data));
3656               emblem_info = gtk_icon_theme_lookup_by_gicon (icon_theme, emblem, size / 2, flags);
3657               if (emblem_info)
3658                 info->emblem_infos = g_slist_prepend (info->emblem_infos, emblem_info);
3659             }
3660         }
3661
3662       return info;
3663     }
3664
3665   return NULL;
3666 }
3667
3668 /**
3669  * gtk_icon_info_new_for_pixbuf:
3670  * @icon_theme: a #GtkIconTheme
3671  * @pixbuf: the pixbuf to wrap in a #GtkIconInfo
3672  *
3673  * Creates a #GtkIconInfo for a #GdkPixbuf.
3674  *
3675  * Returns: a #GtkIconInfo
3676  *
3677  * Since: 2.14
3678  */
3679 GtkIconInfo *
3680 gtk_icon_info_new_for_pixbuf (GtkIconTheme *icon_theme,
3681                               GdkPixbuf    *pixbuf)
3682 {
3683   GtkIconInfo *info;
3684
3685   g_return_val_if_fail (GTK_IS_ICON_THEME (icon_theme), NULL);
3686   g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
3687
3688   info = icon_info_new ();
3689   info->pixbuf = g_object_ref (pixbuf);
3690   info->scale = 1.0;
3691   info->dir_type = ICON_THEME_DIR_UNTHEMED;
3692
3693   return info;
3694 }