]> Pileus Git - ~andy/gtk/blob - gtk/gtkiconfactory.c
register the GTK_STOCK_PAGE_SETUP icon.
[~andy/gtk] / gtk / gtkiconfactory.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 2000 Red Hat, Inc.
3  *               2008 Johan Dahlin
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include <config.h>
28 #include <stdlib.h>
29 #include <errno.h>
30 #include <string.h>
31 #include <pango/pango-utils.h>  /* For pango_scan_* */
32 #include "gtkiconfactory.h"
33 #include "gtkiconcache.h"
34 #include "gtkdebug.h"
35 #include "gtkicontheme.h"
36 #include "gtksettings.h"
37 #include "gtkstock.h"
38 #include "gtkwidget.h"
39 #include "gtkintl.h"
40 #include "gtkbuildable.h"
41 #include "gtkbuilderprivate.h"
42 #include "gtkalias.h"
43
44
45 static GSList *all_icon_factories = NULL;
46
47 typedef enum {
48   GTK_ICON_SOURCE_EMPTY,
49   GTK_ICON_SOURCE_ICON_NAME,
50   GTK_ICON_SOURCE_STATIC_ICON_NAME,
51   GTK_ICON_SOURCE_FILENAME,
52   GTK_ICON_SOURCE_PIXBUF
53 } GtkIconSourceType;
54
55 struct _GtkIconSource
56 {
57   GtkIconSourceType type;
58   
59   union {
60     gchar *icon_name;
61     gchar *filename;
62     GdkPixbuf *pixbuf;
63   } source;
64
65   GdkPixbuf *filename_pixbuf;
66
67   GtkTextDirection direction;
68   GtkStateType state;
69   GtkIconSize size;
70
71   /* If TRUE, then the parameter is wildcarded, and the above
72    * fields should be ignored. If FALSE, the parameter is
73    * specified, and the above fields should be valid.
74    */
75   guint any_direction : 1;
76   guint any_state : 1;
77   guint any_size : 1;
78
79 #ifdef G_OS_WIN32
80   /* System codepage version of filename, for DLL ABI backward
81    * compatibility functions.
82    */
83   gchar *cp_filename;
84 #endif
85 };
86
87
88 static void
89 gtk_icon_factory_buildable_init  (GtkBuildableIface      *iface);
90
91 static gboolean gtk_icon_factory_buildable_custom_tag_start (GtkBuildable     *buildable,
92                                                              GtkBuilder       *builder,
93                                                              GObject          *child,
94                                                              const gchar      *tagname,
95                                                              GMarkupParser    *parser,
96                                                              gpointer         *data);
97 static void gtk_icon_factory_buildable_custom_tag_end (GtkBuildable *buildable,
98                                                        GtkBuilder   *builder,
99                                                        GObject      *child,
100                                                        const gchar  *tagname,
101                                                        gpointer     *user_data);
102 static void gtk_icon_factory_finalize   (GObject             *object);
103 static void get_default_icons           (GtkIconFactory      *icon_factory);
104 static void icon_source_clear           (GtkIconSource       *source);
105
106 static GtkIconSize icon_size_register_intern (const gchar *name,
107                                               gint         width,
108                                               gint         height);
109
110 #define GTK_ICON_SOURCE_INIT(any_direction, any_state, any_size)        \
111   { GTK_ICON_SOURCE_EMPTY, { NULL }, NULL,                              \
112    0, 0, 0,                                                             \
113    any_direction, any_state, any_size }
114
115 G_DEFINE_TYPE_WITH_CODE (GtkIconFactory, gtk_icon_factory, G_TYPE_OBJECT,
116                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
117                                                 gtk_icon_factory_buildable_init))
118
119 static void
120 gtk_icon_factory_init (GtkIconFactory *factory)
121 {
122   factory->icons = g_hash_table_new (g_str_hash, g_str_equal);
123   all_icon_factories = g_slist_prepend (all_icon_factories, factory);
124 }
125
126 static void
127 gtk_icon_factory_class_init (GtkIconFactoryClass *klass)
128 {
129   GObjectClass *object_class = G_OBJECT_CLASS (klass);
130   
131   object_class->finalize = gtk_icon_factory_finalize;
132 }
133
134 static void
135 gtk_icon_factory_buildable_init (GtkBuildableIface *iface)
136 {
137   iface->custom_tag_start = gtk_icon_factory_buildable_custom_tag_start;
138   iface->custom_tag_end = gtk_icon_factory_buildable_custom_tag_end;
139 }
140
141 static void
142 free_icon_set (gpointer key, gpointer value, gpointer data)
143 {
144   g_free (key);
145   gtk_icon_set_unref (value);
146 }
147
148 static void
149 gtk_icon_factory_finalize (GObject *object)
150 {
151   GtkIconFactory *factory = GTK_ICON_FACTORY (object);
152
153   all_icon_factories = g_slist_remove (all_icon_factories, factory);
154   
155   g_hash_table_foreach (factory->icons, free_icon_set, NULL);
156   
157   g_hash_table_destroy (factory->icons);
158   
159   G_OBJECT_CLASS (gtk_icon_factory_parent_class)->finalize (object);
160 }
161
162 /**
163  * gtk_icon_factory_new:
164  *
165  * Creates a new #GtkIconFactory. An icon factory manages a collection
166  * of #GtkIconSet<!-- -->s; a #GtkIconSet manages a set of variants of a
167  * particular icon (i.e. a #GtkIconSet contains variants for different
168  * sizes and widget states). Icons in an icon factory are named by a
169  * stock ID, which is a simple string identifying the icon. Each
170  * #GtkStyle has a list of #GtkIconFactory<!-- -->s derived from the current
171  * theme; those icon factories are consulted first when searching for
172  * an icon. If the theme doesn't set a particular icon, GTK+ looks for
173  * the icon in a list of default icon factories, maintained by
174  * gtk_icon_factory_add_default() and
175  * gtk_icon_factory_remove_default(). Applications with icons should
176  * add a default icon factory with their icons, which will allow
177  * themes to override the icons for the application.
178  * 
179  * Return value: a new #GtkIconFactory
180  **/
181 GtkIconFactory*
182 gtk_icon_factory_new (void)
183 {
184   return g_object_new (GTK_TYPE_ICON_FACTORY, NULL);
185 }
186
187 /**
188  * gtk_icon_factory_add:
189  * @factory: a #GtkIconFactory
190  * @stock_id: icon name
191  * @icon_set: icon set
192  *
193  * Adds the given @icon_set to the icon factory, under the name
194  * @stock_id.  @stock_id should be namespaced for your application,
195  * e.g. "myapp-whatever-icon".  Normally applications create a
196  * #GtkIconFactory, then add it to the list of default factories with
197  * gtk_icon_factory_add_default(). Then they pass the @stock_id to
198  * widgets such as #GtkImage to display the icon. Themes can provide
199  * an icon with the same name (such as "myapp-whatever-icon") to
200  * override your application's default icons. If an icon already
201  * existed in @factory for @stock_id, it is unreferenced and replaced
202  * with the new @icon_set.
203  * 
204  **/
205 void
206 gtk_icon_factory_add (GtkIconFactory *factory,
207                       const gchar    *stock_id,
208                       GtkIconSet     *icon_set)
209 {
210   gpointer old_key = NULL;
211   gpointer old_value = NULL;
212
213   g_return_if_fail (GTK_IS_ICON_FACTORY (factory));
214   g_return_if_fail (stock_id != NULL);
215   g_return_if_fail (icon_set != NULL);  
216
217   g_hash_table_lookup_extended (factory->icons, stock_id,
218                                 &old_key, &old_value);
219
220   if (old_value == icon_set)
221     return;
222   
223   gtk_icon_set_ref (icon_set);
224
225   /* GHashTable key memory management is so fantastically broken. */
226   if (old_key)
227     g_hash_table_insert (factory->icons, old_key, icon_set);
228   else
229     g_hash_table_insert (factory->icons, g_strdup (stock_id), icon_set);
230
231   if (old_value)
232     gtk_icon_set_unref (old_value);
233 }
234
235 /**
236  * gtk_icon_factory_lookup:
237  * @factory: a #GtkIconFactory
238  * @stock_id: an icon name
239  * 
240  * Looks up @stock_id in the icon factory, returning an icon set
241  * if found, otherwise %NULL. For display to the user, you should
242  * use gtk_style_lookup_icon_set() on the #GtkStyle for the
243  * widget that will display the icon, instead of using this
244  * function directly, so that themes are taken into account.
245  * 
246  * Return value: icon set of @stock_id.
247  **/
248 GtkIconSet *
249 gtk_icon_factory_lookup (GtkIconFactory *factory,
250                          const gchar    *stock_id)
251 {
252   g_return_val_if_fail (GTK_IS_ICON_FACTORY (factory), NULL);
253   g_return_val_if_fail (stock_id != NULL, NULL);
254   
255   return g_hash_table_lookup (factory->icons, stock_id);
256 }
257
258 static GtkIconFactory *gtk_default_icons = NULL;
259 static GSList *default_factories = NULL;
260
261 /**
262  * gtk_icon_factory_add_default:
263  * @factory: a #GtkIconFactory
264  * 
265  * Adds an icon factory to the list of icon factories searched by
266  * gtk_style_lookup_icon_set(). This means that, for example,
267  * gtk_image_new_from_stock() will be able to find icons in @factory.
268  * There will normally be an icon factory added for each library or
269  * application that comes with icons. The default icon factories
270  * can be overridden by themes.
271  * 
272  **/
273 void
274 gtk_icon_factory_add_default (GtkIconFactory *factory)
275 {
276   g_return_if_fail (GTK_IS_ICON_FACTORY (factory));
277
278   g_object_ref (factory);
279   
280   default_factories = g_slist_prepend (default_factories, factory);
281 }
282
283 /**
284  * gtk_icon_factory_remove_default:
285  * @factory: a #GtkIconFactory previously added with gtk_icon_factory_add_default()
286  *
287  * Removes an icon factory from the list of default icon
288  * factories. Not normally used; you might use it for a library that
289  * can be unloaded or shut down.
290  * 
291  **/
292 void
293 gtk_icon_factory_remove_default (GtkIconFactory  *factory)
294 {
295   g_return_if_fail (GTK_IS_ICON_FACTORY (factory));
296
297   default_factories = g_slist_remove (default_factories, factory);
298
299   g_object_unref (factory);
300 }
301
302 void
303 _gtk_icon_factory_ensure_default_icons (void)
304 {
305   if (gtk_default_icons == NULL)
306     {
307       gtk_default_icons = gtk_icon_factory_new ();
308
309       get_default_icons (gtk_default_icons);
310     }
311 }
312
313 /**
314  * gtk_icon_factory_lookup_default:
315  * @stock_id: an icon name
316  *
317  * Looks for an icon in the list of default icon factories.  For
318  * display to the user, you should use gtk_style_lookup_icon_set() on
319  * the #GtkStyle for the widget that will display the icon, instead of
320  * using this function directly, so that themes are taken into
321  * account.
322  * 
323  * 
324  * Return value: a #GtkIconSet, or %NULL
325  **/
326 GtkIconSet *
327 gtk_icon_factory_lookup_default (const gchar *stock_id)
328 {
329   GSList *tmp_list;
330
331   g_return_val_if_fail (stock_id != NULL, NULL);
332   
333   tmp_list = default_factories;
334   while (tmp_list != NULL)
335     {
336       GtkIconSet *icon_set =
337         gtk_icon_factory_lookup (GTK_ICON_FACTORY (tmp_list->data),
338                                  stock_id);
339
340       if (icon_set)
341         return icon_set;
342       
343       tmp_list = g_slist_next (tmp_list);
344     }
345
346   _gtk_icon_factory_ensure_default_icons ();
347   
348   return gtk_icon_factory_lookup (gtk_default_icons, stock_id);
349 }
350
351 static void
352 register_stock_icon (GtkIconFactory *factory,
353                      const gchar    *stock_id)
354 {
355   GtkIconSet *set = gtk_icon_set_new ();
356   GtkIconSource source = GTK_ICON_SOURCE_INIT (TRUE, TRUE, TRUE);
357
358   source.type = GTK_ICON_SOURCE_STATIC_ICON_NAME;
359   source.source.icon_name = (gchar *)stock_id;
360   gtk_icon_set_add_source (set, &source);
361   
362   gtk_icon_factory_add (factory, stock_id, set);
363   gtk_icon_set_unref (set);
364 }
365
366 static void
367 register_bidi_stock_icon (GtkIconFactory *factory,
368                           const gchar    *stock_id,
369                           const gchar    *stock_id_ltr,
370                           const gchar    *stock_id_rtl)
371 {
372   GtkIconSet *set = gtk_icon_set_new ();
373   GtkIconSource source = GTK_ICON_SOURCE_INIT (FALSE, TRUE, TRUE);
374
375   source.type = GTK_ICON_SOURCE_STATIC_ICON_NAME;
376   source.source.icon_name = (gchar *)stock_id_ltr;
377   source.direction = GTK_TEXT_DIR_LTR;
378   gtk_icon_set_add_source (set, &source);
379   
380   source.type = GTK_ICON_SOURCE_STATIC_ICON_NAME;
381   source.source.icon_name = (gchar *)stock_id_rtl;
382   source.direction = GTK_TEXT_DIR_RTL;
383   gtk_icon_set_add_source (set, &source);
384   
385   gtk_icon_factory_add (factory, stock_id, set);
386   gtk_icon_set_unref (set);
387 }
388
389 static void
390 get_default_icons (GtkIconFactory *factory)
391 {
392   /* KEEP IN SYNC with gtkstock.c */
393
394   register_stock_icon (factory, GTK_STOCK_DIALOG_AUTHENTICATION);
395   register_stock_icon (factory, GTK_STOCK_DIALOG_ERROR);
396   register_stock_icon (factory, GTK_STOCK_DIALOG_INFO);
397   register_stock_icon (factory, GTK_STOCK_DIALOG_QUESTION);
398   register_stock_icon (factory, GTK_STOCK_DIALOG_WARNING);
399   register_stock_icon (factory, GTK_STOCK_DND);
400   register_stock_icon (factory, GTK_STOCK_DND_MULTIPLE);
401   register_stock_icon (factory, GTK_STOCK_APPLY);
402   register_stock_icon (factory, GTK_STOCK_CANCEL);
403   register_stock_icon (factory, GTK_STOCK_NO);
404   register_stock_icon (factory, GTK_STOCK_OK);
405   register_stock_icon (factory, GTK_STOCK_YES);
406   register_stock_icon (factory, GTK_STOCK_CLOSE);
407   register_stock_icon (factory, GTK_STOCK_ADD);
408   register_stock_icon (factory, GTK_STOCK_JUSTIFY_CENTER);
409   register_stock_icon (factory, GTK_STOCK_JUSTIFY_FILL);
410   register_stock_icon (factory, GTK_STOCK_JUSTIFY_LEFT);
411   register_stock_icon (factory, GTK_STOCK_JUSTIFY_RIGHT);
412   register_stock_icon (factory, GTK_STOCK_GOTO_BOTTOM);
413   register_stock_icon (factory, GTK_STOCK_CDROM);
414   register_stock_icon (factory, GTK_STOCK_CONVERT);
415   register_stock_icon (factory, GTK_STOCK_COPY);
416   register_stock_icon (factory, GTK_STOCK_CUT);
417   register_stock_icon (factory, GTK_STOCK_GO_DOWN);
418   register_stock_icon (factory, GTK_STOCK_EXECUTE);
419   register_stock_icon (factory, GTK_STOCK_QUIT);
420   register_bidi_stock_icon (factory,  
421                             GTK_STOCK_GOTO_FIRST, 
422                             GTK_STOCK_GOTO_FIRST "-ltr", 
423                             GTK_STOCK_GOTO_FIRST "-rtl");
424   register_stock_icon (factory, GTK_STOCK_SELECT_FONT);
425   register_stock_icon (factory, GTK_STOCK_FULLSCREEN);
426   register_stock_icon (factory, GTK_STOCK_LEAVE_FULLSCREEN);
427   register_stock_icon (factory, GTK_STOCK_HARDDISK);
428   register_stock_icon (factory, GTK_STOCK_HELP);
429   register_stock_icon (factory, GTK_STOCK_HOME);
430   register_stock_icon (factory, GTK_STOCK_INFO);
431   register_bidi_stock_icon (factory, 
432                             GTK_STOCK_JUMP_TO,
433                             GTK_STOCK_JUMP_TO "-ltr",
434                             GTK_STOCK_JUMP_TO "-rtl");
435   register_bidi_stock_icon (factory, 
436                             GTK_STOCK_GOTO_LAST,
437                             GTK_STOCK_GOTO_LAST "-ltr",
438                             GTK_STOCK_GOTO_LAST "-rtl");
439   register_bidi_stock_icon (factory, 
440                             GTK_STOCK_GO_BACK,
441                             GTK_STOCK_GO_BACK "-ltr",
442                             GTK_STOCK_GO_BACK "-rtl");
443   register_stock_icon (factory, GTK_STOCK_MISSING_IMAGE);
444   register_stock_icon (factory, GTK_STOCK_NETWORK);
445   register_stock_icon (factory, GTK_STOCK_NEW);
446   register_stock_icon (factory, GTK_STOCK_OPEN);
447   register_stock_icon (factory, GTK_STOCK_ORIENTATION_PORTRAIT);
448   register_stock_icon (factory, GTK_STOCK_ORIENTATION_LANDSCAPE);
449   register_stock_icon (factory, GTK_STOCK_ORIENTATION_REVERSE_PORTRAIT);
450   register_stock_icon (factory, GTK_STOCK_ORIENTATION_REVERSE_LANDSCAPE);
451   register_stock_icon (factory, GTK_STOCK_PAGE_SETUP);
452   register_stock_icon (factory, GTK_STOCK_PASTE);
453   register_stock_icon (factory, GTK_STOCK_PREFERENCES);
454   register_stock_icon (factory, GTK_STOCK_PRINT);
455   register_stock_icon (factory, GTK_STOCK_PRINT_PREVIEW);
456   register_stock_icon (factory, GTK_STOCK_PROPERTIES);
457   register_bidi_stock_icon (factory, 
458                             GTK_STOCK_REDO,
459                             GTK_STOCK_REDO "-ltr",
460                             GTK_STOCK_REDO "-rtl");
461   register_stock_icon (factory, GTK_STOCK_REMOVE);
462   register_stock_icon (factory, GTK_STOCK_REFRESH);
463   register_bidi_stock_icon (factory, 
464                             GTK_STOCK_REVERT_TO_SAVED,
465                             GTK_STOCK_REVERT_TO_SAVED "-ltr",
466                             GTK_STOCK_REVERT_TO_SAVED "-rtl");
467   register_bidi_stock_icon (factory, 
468                             GTK_STOCK_GO_FORWARD,
469                             GTK_STOCK_GO_FORWARD "-ltr",
470                             GTK_STOCK_GO_FORWARD "-rtl");
471   register_stock_icon (factory, GTK_STOCK_SAVE);
472   register_stock_icon (factory, GTK_STOCK_FLOPPY);
473   register_stock_icon (factory, GTK_STOCK_SAVE_AS);
474   register_stock_icon (factory, GTK_STOCK_FIND);
475   register_stock_icon (factory, GTK_STOCK_FIND_AND_REPLACE);
476   register_stock_icon (factory, GTK_STOCK_SORT_DESCENDING);
477   register_stock_icon (factory, GTK_STOCK_SORT_ASCENDING);
478   register_stock_icon (factory, GTK_STOCK_SPELL_CHECK);
479   register_stock_icon (factory, GTK_STOCK_STOP);
480   register_stock_icon (factory, GTK_STOCK_BOLD);
481   register_stock_icon (factory, GTK_STOCK_ITALIC);
482   register_stock_icon (factory, GTK_STOCK_STRIKETHROUGH);
483   register_stock_icon (factory, GTK_STOCK_UNDERLINE);
484   register_bidi_stock_icon (factory, 
485                             GTK_STOCK_INDENT,
486                             GTK_STOCK_INDENT "-ltr",
487                             GTK_STOCK_INDENT "-rtl");
488   register_bidi_stock_icon (factory, 
489                             GTK_STOCK_UNINDENT,
490                             GTK_STOCK_UNINDENT "-ltr",
491                             GTK_STOCK_UNINDENT "-rtl");
492   register_stock_icon (factory, GTK_STOCK_GOTO_TOP);
493   register_stock_icon (factory, GTK_STOCK_DELETE);
494   register_bidi_stock_icon (factory, 
495                             GTK_STOCK_UNDELETE,
496                             GTK_STOCK_UNDELETE "-ltr",
497                             GTK_STOCK_UNDELETE "-rtl");
498   register_bidi_stock_icon (factory, 
499                             GTK_STOCK_UNDO,
500                             GTK_STOCK_UNDO "-ltr",
501                             GTK_STOCK_UNDO "-rtl");
502   register_stock_icon (factory, GTK_STOCK_GO_UP);
503   register_stock_icon (factory, GTK_STOCK_FILE);
504   register_stock_icon (factory, GTK_STOCK_DIRECTORY);
505   register_stock_icon (factory, GTK_STOCK_ABOUT);
506   register_stock_icon (factory, GTK_STOCK_CONNECT);
507   register_stock_icon (factory, GTK_STOCK_DISCONNECT);
508   register_stock_icon (factory, GTK_STOCK_EDIT);
509   register_bidi_stock_icon (factory, 
510                             GTK_STOCK_MEDIA_FORWARD,
511                             GTK_STOCK_MEDIA_FORWARD "-ltr",
512                             GTK_STOCK_MEDIA_FORWARD "-rtl");
513   register_bidi_stock_icon (factory, 
514                             GTK_STOCK_MEDIA_NEXT,
515                             GTK_STOCK_MEDIA_NEXT "-ltr",
516                             GTK_STOCK_MEDIA_NEXT "-rtl");
517   register_stock_icon (factory, GTK_STOCK_MEDIA_PAUSE);
518   register_bidi_stock_icon (factory, 
519                             GTK_STOCK_MEDIA_PLAY,
520                             GTK_STOCK_MEDIA_PLAY "-ltr",
521                             GTK_STOCK_MEDIA_PLAY "-rtl");
522   register_bidi_stock_icon (factory, 
523                             GTK_STOCK_MEDIA_PREVIOUS,
524                             GTK_STOCK_MEDIA_PREVIOUS "-ltr",
525                             GTK_STOCK_MEDIA_PREVIOUS "-rtl");
526   register_stock_icon (factory, GTK_STOCK_MEDIA_RECORD);
527   register_bidi_stock_icon (factory, 
528                             GTK_STOCK_MEDIA_REWIND,
529                             GTK_STOCK_MEDIA_REWIND "-ltr",
530                             GTK_STOCK_MEDIA_REWIND "-rtl");
531   register_stock_icon (factory, GTK_STOCK_MEDIA_STOP);
532   register_stock_icon (factory, GTK_STOCK_INDEX);
533   register_stock_icon (factory, GTK_STOCK_ZOOM_100);
534   register_stock_icon (factory, GTK_STOCK_ZOOM_IN);
535   register_stock_icon (factory, GTK_STOCK_ZOOM_OUT);
536   register_stock_icon (factory, GTK_STOCK_ZOOM_FIT);
537   register_stock_icon (factory, GTK_STOCK_SELECT_ALL);
538   register_stock_icon (factory, GTK_STOCK_CLEAR);
539   register_stock_icon (factory, GTK_STOCK_SELECT_COLOR);
540   register_stock_icon (factory, GTK_STOCK_COLOR_PICKER);
541 }
542
543 /************************************************************
544  *                    Icon size handling                    *
545  ************************************************************/
546
547 typedef struct _IconSize IconSize;
548
549 struct _IconSize
550 {
551   gint size;
552   gchar *name;
553   
554   gint width;
555   gint height;
556 };
557
558 typedef struct _IconAlias IconAlias;
559
560 struct _IconAlias
561 {
562   gchar *name;
563   gint   target;
564 };
565
566 typedef struct _SettingsIconSize SettingsIconSize;
567
568 struct _SettingsIconSize
569 {
570   gint width;
571   gint height;
572 };
573
574 static GHashTable *icon_aliases = NULL;
575 static IconSize *icon_sizes = NULL;
576 static gint      icon_sizes_allocated = 0;
577 static gint      icon_sizes_used = 0;
578
579 static void
580 init_icon_sizes (void)
581 {
582   if (icon_sizes == NULL)
583     {
584 #define NUM_BUILTIN_SIZES 7
585       gint i;
586
587       icon_aliases = g_hash_table_new (g_str_hash, g_str_equal);
588       
589       icon_sizes = g_new (IconSize, NUM_BUILTIN_SIZES);
590       icon_sizes_allocated = NUM_BUILTIN_SIZES;
591       icon_sizes_used = NUM_BUILTIN_SIZES;
592
593       icon_sizes[GTK_ICON_SIZE_INVALID].size = 0;
594       icon_sizes[GTK_ICON_SIZE_INVALID].name = NULL;
595       icon_sizes[GTK_ICON_SIZE_INVALID].width = 0;
596       icon_sizes[GTK_ICON_SIZE_INVALID].height = 0;
597
598       /* the name strings aren't copied since we don't ever remove
599        * icon sizes, so we don't need to know whether they're static.
600        * Even if we did I suppose removing the builtin sizes would be
601        * disallowed.
602        */
603       
604       icon_sizes[GTK_ICON_SIZE_MENU].size = GTK_ICON_SIZE_MENU;
605       icon_sizes[GTK_ICON_SIZE_MENU].name = "gtk-menu";
606       icon_sizes[GTK_ICON_SIZE_MENU].width = 16;
607       icon_sizes[GTK_ICON_SIZE_MENU].height = 16;
608
609       icon_sizes[GTK_ICON_SIZE_BUTTON].size = GTK_ICON_SIZE_BUTTON;
610       icon_sizes[GTK_ICON_SIZE_BUTTON].name = "gtk-button";
611       icon_sizes[GTK_ICON_SIZE_BUTTON].width = 20;
612       icon_sizes[GTK_ICON_SIZE_BUTTON].height = 20;
613
614       icon_sizes[GTK_ICON_SIZE_SMALL_TOOLBAR].size = GTK_ICON_SIZE_SMALL_TOOLBAR;
615       icon_sizes[GTK_ICON_SIZE_SMALL_TOOLBAR].name = "gtk-small-toolbar";
616       icon_sizes[GTK_ICON_SIZE_SMALL_TOOLBAR].width = 18;
617       icon_sizes[GTK_ICON_SIZE_SMALL_TOOLBAR].height = 18;
618       
619       icon_sizes[GTK_ICON_SIZE_LARGE_TOOLBAR].size = GTK_ICON_SIZE_LARGE_TOOLBAR;
620       icon_sizes[GTK_ICON_SIZE_LARGE_TOOLBAR].name = "gtk-large-toolbar";
621       icon_sizes[GTK_ICON_SIZE_LARGE_TOOLBAR].width = 24;
622       icon_sizes[GTK_ICON_SIZE_LARGE_TOOLBAR].height = 24;
623
624       icon_sizes[GTK_ICON_SIZE_DND].size = GTK_ICON_SIZE_DND;
625       icon_sizes[GTK_ICON_SIZE_DND].name = "gtk-dnd";
626       icon_sizes[GTK_ICON_SIZE_DND].width = 32;
627       icon_sizes[GTK_ICON_SIZE_DND].height = 32;
628
629       icon_sizes[GTK_ICON_SIZE_DIALOG].size = GTK_ICON_SIZE_DIALOG;
630       icon_sizes[GTK_ICON_SIZE_DIALOG].name = "gtk-dialog";
631       icon_sizes[GTK_ICON_SIZE_DIALOG].width = 48;
632       icon_sizes[GTK_ICON_SIZE_DIALOG].height = 48;
633
634       g_assert ((GTK_ICON_SIZE_DIALOG + 1) == NUM_BUILTIN_SIZES);
635
636       /* Alias everything to itself. */
637       i = 1; /* skip invalid size */
638       while (i < NUM_BUILTIN_SIZES)
639         {
640           gtk_icon_size_register_alias (icon_sizes[i].name, icon_sizes[i].size);
641           
642           ++i;
643         }
644       
645 #undef NUM_BUILTIN_SIZES
646     }
647 }
648
649 static void
650 free_settings_sizes (gpointer data)
651 {
652   g_array_free (data, TRUE);
653 }
654
655 static GArray *
656 get_settings_sizes (GtkSettings *settings,
657                     gboolean    *created)
658 {
659   GArray *settings_sizes;
660   static GQuark sizes_quark = 0;
661
662   if (!sizes_quark)
663     sizes_quark = g_quark_from_static_string ("gtk-icon-sizes");
664
665   settings_sizes = g_object_get_qdata (G_OBJECT (settings), sizes_quark);
666   if (!settings_sizes)
667     {
668       settings_sizes = g_array_new (FALSE, FALSE, sizeof (SettingsIconSize));
669       g_object_set_qdata_full (G_OBJECT (settings), sizes_quark,
670                                settings_sizes, free_settings_sizes);
671       if (created)
672         *created = TRUE;
673     }
674
675   return settings_sizes;
676 }
677
678 static void
679 icon_size_set_for_settings (GtkSettings *settings,
680                             const gchar *size_name,
681                             gint         width,
682                             gint         height)
683 {
684   GtkIconSize size;
685   GArray *settings_sizes;
686   SettingsIconSize *settings_size;
687
688   g_return_if_fail (size_name != NULL);
689
690   size = gtk_icon_size_from_name (size_name);
691   if (size == GTK_ICON_SIZE_INVALID)
692     /* Reserve a place */
693     size = icon_size_register_intern (size_name, -1, -1);
694   
695   settings_sizes = get_settings_sizes (settings, NULL);
696   if (size >= settings_sizes->len)
697     {
698       SettingsIconSize unset = { -1, -1 };
699       gint i;
700
701       for (i = settings_sizes->len; i <= size; i++)
702         g_array_append_val (settings_sizes, unset);
703     }
704
705   settings_size = &g_array_index (settings_sizes, SettingsIconSize, size);
706   
707   settings_size->width = width;
708   settings_size->height = height;
709 }
710
711 /* Like pango_parse_word, but accept - as well
712  */
713 static gboolean
714 scan_icon_size_name (const char **pos, GString *out)
715 {
716   const char *p = *pos;
717
718   while (g_ascii_isspace (*p))
719     p++;
720   
721   if (!((*p >= 'A' && *p <= 'Z') ||
722         (*p >= 'a' && *p <= 'z') ||
723         *p == '_' || *p == '-'))
724     return FALSE;
725
726   g_string_truncate (out, 0);
727   g_string_append_c (out, *p);
728   p++;
729
730   while ((*p >= 'A' && *p <= 'Z') ||
731          (*p >= 'a' && *p <= 'z') ||
732          (*p >= '0' && *p <= '9') ||
733          *p == '_' || *p == '-')
734     {
735       g_string_append_c (out, *p);
736       p++;
737     }
738
739   *pos = p;
740
741   return TRUE;
742 }
743
744 static void
745 icon_size_setting_parse (GtkSettings *settings,
746                          const gchar *icon_size_string)
747 {
748   GString *name_buf = g_string_new (NULL);
749   const gchar *p = icon_size_string;
750
751   while (pango_skip_space (&p))
752     {
753       gint width, height;
754       
755       if (!scan_icon_size_name (&p, name_buf))
756         goto err;
757
758       if (!pango_skip_space (&p))
759         goto err;
760
761       if (*p != '=')
762         goto err;
763
764       p++;
765
766       if (!pango_scan_int (&p, &width))
767         goto err;
768
769       if (!pango_skip_space (&p))
770         goto err;
771
772       if (*p != ',')
773         goto err;
774
775       p++;
776
777       if (!pango_scan_int (&p, &height))
778         goto err;
779
780       if (width > 0 && height > 0)
781         {
782           icon_size_set_for_settings (settings, name_buf->str,
783                                       width, height);
784         }
785       else
786         {
787           g_warning ("Invalid size in gtk-icon-sizes: %d,%d\n", width, height);
788         }
789
790       pango_skip_space (&p);
791       if (*p == '\0')
792         break;
793       if (*p == ':')
794         p++;
795       else
796         goto err;
797     }
798
799   g_string_free (name_buf, TRUE);
800   return;
801
802  err:
803   g_warning ("Error parsing gtk-icon-sizes string:\n\t'%s'", icon_size_string);
804   g_string_free (name_buf, TRUE);
805 }
806
807 static void
808 icon_size_set_all_from_settings (GtkSettings *settings)
809 {
810   GArray *settings_sizes;
811   gchar *icon_size_string;
812
813   /* Reset old settings */
814   settings_sizes = get_settings_sizes (settings, NULL);
815   g_array_set_size (settings_sizes, 0);
816
817   g_object_get (settings,
818                 "gtk-icon-sizes", &icon_size_string,
819                 NULL);
820
821   if (icon_size_string)
822     {
823       icon_size_setting_parse (settings, icon_size_string);
824       g_free (icon_size_string);
825     }
826 }
827
828 static void
829 icon_size_settings_changed (GtkSettings  *settings,
830                             GParamSpec   *pspec)
831 {
832   icon_size_set_all_from_settings (settings);
833
834   gtk_rc_reset_styles (settings);
835 }
836
837 static void
838 icon_sizes_init_for_settings (GtkSettings *settings)
839 {
840   g_signal_connect (settings,
841                     "notify::gtk-icon-sizes",
842                     G_CALLBACK (icon_size_settings_changed),
843                     NULL);
844   
845   icon_size_set_all_from_settings (settings);
846 }
847      
848 static gboolean
849 icon_size_lookup_intern (GtkSettings *settings,
850                          GtkIconSize  size,
851                          gint        *widthp,
852                          gint        *heightp)
853 {
854   GArray *settings_sizes;
855   gint width_for_settings = -1;
856   gint height_for_settings = -1;
857   
858   init_icon_sizes ();
859
860   if (size == (GtkIconSize)-1)
861     return FALSE;
862
863   if (size >= icon_sizes_used)
864     return FALSE;
865
866   if (size == GTK_ICON_SIZE_INVALID)
867     return FALSE;
868
869   if (settings)
870     {
871       gboolean initial = FALSE;
872       
873       settings_sizes = get_settings_sizes (settings, &initial);
874       if (initial)
875         icon_sizes_init_for_settings (settings);
876   
877       if (size < settings_sizes->len)
878         {
879           SettingsIconSize *settings_size;
880           
881           settings_size = &g_array_index (settings_sizes, SettingsIconSize, size);
882           
883           width_for_settings = settings_size->width;
884           height_for_settings = settings_size->height;
885         }
886     }
887
888   if (widthp)
889     *widthp = width_for_settings >= 0 ? width_for_settings : icon_sizes[size].width;
890
891   if (heightp)
892     *heightp = height_for_settings >= 0 ? height_for_settings : icon_sizes[size].height;
893
894   return TRUE;
895 }
896
897 /**
898  * gtk_icon_size_lookup_for_settings:
899  * @settings: a #GtkSettings object, used to determine
900  *   which set of user preferences to used.
901  * @size: an icon size
902  * @width: location to store icon width
903  * @height: location to store icon height
904  *
905  * Obtains the pixel size of a semantic icon size, possibly
906  * modified by user preferences for a particular 
907  * #GtkSettings. Normally @size would be
908  * #GTK_ICON_SIZE_MENU, #GTK_ICON_SIZE_BUTTON, etc.  This function
909  * isn't normally needed, gtk_widget_render_icon() is the usual
910  * way to get an icon for rendering, then just look at the size of
911  * the rendered pixbuf. The rendered pixbuf may not even correspond to
912  * the width/height returned by gtk_icon_size_lookup(), because themes
913  * are free to render the pixbuf however they like, including changing
914  * the usual size.
915  * 
916  * Return value: %TRUE if @size was a valid size
917  *
918  * Since: 2.2
919  **/
920 gboolean
921 gtk_icon_size_lookup_for_settings (GtkSettings *settings,
922                                    GtkIconSize  size,
923                                    gint        *width,
924                                    gint        *height)
925 {
926   g_return_val_if_fail (GTK_IS_SETTINGS (settings), FALSE);
927
928   return icon_size_lookup_intern (settings, size, width, height);
929 }
930
931 /**
932  * gtk_icon_size_lookup:
933  * @size: an icon size
934  * @width: location to store icon width
935  * @height: location to store icon height
936  *
937  * Obtains the pixel size of a semantic icon size, possibly
938  * modified by user preferences for the default #GtkSettings.
939  * (See gtk_icon_size_lookup_for_settings().)
940  * Normally @size would be
941  * #GTK_ICON_SIZE_MENU, #GTK_ICON_SIZE_BUTTON, etc.  This function
942  * isn't normally needed, gtk_widget_render_icon() is the usual
943  * way to get an icon for rendering, then just look at the size of
944  * the rendered pixbuf. The rendered pixbuf may not even correspond to
945  * the width/height returned by gtk_icon_size_lookup(), because themes
946  * are free to render the pixbuf however they like, including changing
947  * the usual size.
948  * 
949  * Return value: %TRUE if @size was a valid size
950  **/
951 gboolean
952 gtk_icon_size_lookup (GtkIconSize  size,
953                       gint        *widthp,
954                       gint        *heightp)
955 {
956   GTK_NOTE (MULTIHEAD,
957             g_warning ("gtk_icon_size_lookup ()) is not multihead safe"));
958
959   return gtk_icon_size_lookup_for_settings (gtk_settings_get_default (),
960                                             size, widthp, heightp);
961 }
962
963 static GtkIconSize
964 icon_size_register_intern (const gchar *name,
965                            gint         width,
966                            gint         height)
967 {
968   IconAlias *old_alias;
969   GtkIconSize size;
970   
971   init_icon_sizes ();
972
973   old_alias = g_hash_table_lookup (icon_aliases, name);
974   if (old_alias && icon_sizes[old_alias->target].width > 0)
975     {
976       g_warning ("Icon size name '%s' already exists", name);
977       return GTK_ICON_SIZE_INVALID;
978     }
979
980   if (old_alias)
981     {
982       size = old_alias->target;
983     }
984   else
985     {
986       if (icon_sizes_used == icon_sizes_allocated)
987         {
988           icon_sizes_allocated *= 2;
989           icon_sizes = g_renew (IconSize, icon_sizes, icon_sizes_allocated);
990         }
991
992       size = icon_sizes_used++;
993
994       /* alias to self. */
995       gtk_icon_size_register_alias (name, size);
996
997       icon_sizes[size].size = size;
998       icon_sizes[size].name = g_strdup (name);
999     }
1000
1001   icon_sizes[size].width = width;
1002   icon_sizes[size].height = height;
1003
1004   return size;
1005 }
1006
1007 /**
1008  * gtk_icon_size_register:
1009  * @name: name of the icon size
1010  * @width: the icon width
1011  * @height: the icon height
1012  *
1013  * Registers a new icon size, along the same lines as #GTK_ICON_SIZE_MENU,
1014  * etc. Returns the integer value for the size.
1015  *
1016  * Returns: integer value representing the size
1017  * 
1018  **/
1019 GtkIconSize
1020 gtk_icon_size_register (const gchar *name,
1021                         gint         width,
1022                         gint         height)
1023 {
1024   g_return_val_if_fail (name != NULL, 0);
1025   g_return_val_if_fail (width > 0, 0);
1026   g_return_val_if_fail (height > 0, 0);
1027   
1028   return icon_size_register_intern (name, width, height);
1029 }
1030
1031 /**
1032  * gtk_icon_size_register_alias:
1033  * @alias: an alias for @target
1034  * @target: an existing icon size
1035  *
1036  * Registers @alias as another name for @target.
1037  * So calling gtk_icon_size_from_name() with @alias as argument
1038  * will return @target.
1039  *
1040  **/
1041 void
1042 gtk_icon_size_register_alias (const gchar *alias,
1043                               GtkIconSize  target)
1044 {
1045   IconAlias *ia;
1046   
1047   g_return_if_fail (alias != NULL);
1048
1049   init_icon_sizes ();
1050
1051   if (!icon_size_lookup_intern (NULL, target, NULL, NULL))
1052     g_warning ("gtk_icon_size_register_alias: Icon size %u does not exist", target);
1053
1054   ia = g_hash_table_lookup (icon_aliases, alias);
1055   if (ia)
1056     {
1057       if (icon_sizes[ia->target].width > 0)
1058         {
1059           g_warning ("gtk_icon_size_register_alias: Icon size name '%s' already exists", alias);
1060           return;
1061         }
1062
1063       ia->target = target;
1064     }
1065
1066   if (!ia)
1067     {
1068       ia = g_new (IconAlias, 1);
1069       ia->name = g_strdup (alias);
1070       ia->target = target;
1071
1072       g_hash_table_insert (icon_aliases, ia->name, ia);
1073     }
1074 }
1075
1076 /** 
1077  * gtk_icon_size_from_name:
1078  * @name: the name to look up.
1079  * @returns: the icon size with the given name.
1080  * 
1081  * Looks up the icon size associated with @name.
1082  **/
1083 GtkIconSize
1084 gtk_icon_size_from_name (const gchar *name)
1085 {
1086   IconAlias *ia;
1087
1088   init_icon_sizes ();
1089   
1090   ia = g_hash_table_lookup (icon_aliases, name);
1091
1092   if (ia && icon_sizes[ia->target].width > 0)
1093     return ia->target;
1094   else
1095     return GTK_ICON_SIZE_INVALID;
1096 }
1097
1098 /**
1099  * gtk_icon_size_get_name:
1100  * @size: a #GtkIconSize.
1101  * @returns: the name of the given icon size.
1102  * 
1103  * Gets the canonical name of the given icon size. The returned string 
1104  * is statically allocated and should not be freed.
1105  **/
1106 G_CONST_RETURN gchar*
1107 gtk_icon_size_get_name (GtkIconSize  size)
1108 {
1109   if (size >= icon_sizes_used)
1110     return NULL;
1111   else
1112     return icon_sizes[size].name;
1113 }
1114
1115 /************************************************************/
1116
1117 /* Icon Set */
1118
1119
1120 static GdkPixbuf *find_in_cache     (GtkIconSet       *icon_set,
1121                                      GtkStyle         *style,
1122                                      GtkTextDirection  direction,
1123                                      GtkStateType      state,
1124                                      GtkIconSize       size);
1125 static void       add_to_cache      (GtkIconSet       *icon_set,
1126                                      GtkStyle         *style,
1127                                      GtkTextDirection  direction,
1128                                      GtkStateType      state,
1129                                      GtkIconSize       size,
1130                                      GdkPixbuf        *pixbuf);
1131 /* Clear icon set contents, drop references to all contained
1132  * GdkPixbuf objects and forget all GtkIconSources. Used to
1133  * recycle an icon set.
1134  */
1135 static void       clear_cache       (GtkIconSet       *icon_set,
1136                                      gboolean          style_detach);
1137 static GSList*    copy_cache        (GtkIconSet       *icon_set,
1138                                      GtkIconSet       *copy_recipient);
1139 static void       attach_to_style   (GtkIconSet       *icon_set,
1140                                      GtkStyle         *style);
1141 static void       detach_from_style (GtkIconSet       *icon_set,
1142                                      GtkStyle         *style);
1143 static void       style_dnotify     (gpointer          data);
1144
1145 struct _GtkIconSet
1146 {
1147   guint ref_count;
1148
1149   GSList *sources;
1150
1151   /* Cache of the last few rendered versions of the icon. */
1152   GSList *cache;
1153
1154   guint cache_size;
1155
1156   guint cache_serial;
1157 };
1158
1159 static guint cache_serial = 0;
1160
1161 /**
1162  * gtk_icon_set_new:
1163  * 
1164  * Creates a new #GtkIconSet. A #GtkIconSet represents a single icon
1165  * in various sizes and widget states. It can provide a #GdkPixbuf
1166  * for a given size and state on request, and automatically caches
1167  * some of the rendered #GdkPixbuf objects.
1168  *
1169  * Normally you would use gtk_widget_render_icon() instead of
1170  * using #GtkIconSet directly. The one case where you'd use
1171  * #GtkIconSet is to create application-specific icon sets to place in
1172  * a #GtkIconFactory.
1173  * 
1174  * Return value: a new #GtkIconSet
1175  **/
1176 GtkIconSet*
1177 gtk_icon_set_new (void)
1178 {
1179   GtkIconSet *icon_set;
1180
1181   icon_set = g_new (GtkIconSet, 1);
1182
1183   icon_set->ref_count = 1;
1184   icon_set->sources = NULL;
1185   icon_set->cache = NULL;
1186   icon_set->cache_size = 0;
1187   icon_set->cache_serial = cache_serial;
1188   
1189   return icon_set;
1190 }
1191
1192 /**
1193  * gtk_icon_set_new_from_pixbuf:
1194  * @pixbuf: a #GdkPixbuf
1195  * 
1196  * Creates a new #GtkIconSet with @pixbuf as the default/fallback
1197  * source image. If you don't add any additional #GtkIconSource to the
1198  * icon set, all variants of the icon will be created from @pixbuf,
1199  * using scaling, pixelation, etc. as required to adjust the icon size
1200  * or make the icon look insensitive/prelighted.
1201  * 
1202  * Return value: a new #GtkIconSet
1203  **/
1204 GtkIconSet *
1205 gtk_icon_set_new_from_pixbuf (GdkPixbuf *pixbuf)
1206 {
1207   GtkIconSet *set;
1208
1209   GtkIconSource source = GTK_ICON_SOURCE_INIT (TRUE, TRUE, TRUE);
1210
1211   g_return_val_if_fail (pixbuf != NULL, NULL);
1212
1213   set = gtk_icon_set_new ();
1214
1215   gtk_icon_source_set_pixbuf (&source, pixbuf);
1216   gtk_icon_set_add_source (set, &source);
1217   gtk_icon_source_set_pixbuf (&source, NULL);
1218   
1219   return set;
1220 }
1221
1222
1223 /**
1224  * gtk_icon_set_ref:
1225  * @icon_set: a #GtkIconSet.
1226  * 
1227  * Increments the reference count on @icon_set.
1228  * 
1229  * Return value: @icon_set.
1230  **/
1231 GtkIconSet*
1232 gtk_icon_set_ref (GtkIconSet *icon_set)
1233 {
1234   g_return_val_if_fail (icon_set != NULL, NULL);
1235   g_return_val_if_fail (icon_set->ref_count > 0, NULL);
1236
1237   icon_set->ref_count += 1;
1238
1239   return icon_set;
1240 }
1241
1242 /**
1243  * gtk_icon_set_unref:
1244  * @icon_set: a #GtkIconSet
1245  * 
1246  * Decrements the reference count on @icon_set, and frees memory
1247  * if the reference count reaches 0.
1248  **/
1249 void
1250 gtk_icon_set_unref (GtkIconSet *icon_set)
1251 {
1252   g_return_if_fail (icon_set != NULL);
1253   g_return_if_fail (icon_set->ref_count > 0);
1254
1255   icon_set->ref_count -= 1;
1256
1257   if (icon_set->ref_count == 0)
1258     {
1259       GSList *tmp_list = icon_set->sources;
1260       while (tmp_list != NULL)
1261         {
1262           gtk_icon_source_free (tmp_list->data);
1263
1264           tmp_list = g_slist_next (tmp_list);
1265         }
1266       g_slist_free (icon_set->sources);
1267
1268       clear_cache (icon_set, TRUE);
1269
1270       g_free (icon_set);
1271     }
1272 }
1273
1274 GType
1275 gtk_icon_set_get_type (void)
1276 {
1277   static GType our_type = 0;
1278   
1279   if (our_type == 0)
1280     our_type = g_boxed_type_register_static (I_("GtkIconSet"),
1281                                              (GBoxedCopyFunc) gtk_icon_set_ref,
1282                                              (GBoxedFreeFunc) gtk_icon_set_unref);
1283
1284   return our_type;
1285 }
1286
1287 /**
1288  * gtk_icon_set_copy:
1289  * @icon_set: a #GtkIconSet
1290  * 
1291  * Copies @icon_set by value. 
1292  * 
1293  * Return value: a new #GtkIconSet identical to the first.
1294  **/
1295 GtkIconSet*
1296 gtk_icon_set_copy (GtkIconSet *icon_set)
1297 {
1298   GtkIconSet *copy;
1299   GSList *tmp_list;
1300   
1301   copy = gtk_icon_set_new ();
1302
1303   tmp_list = icon_set->sources;
1304   while (tmp_list != NULL)
1305     {
1306       copy->sources = g_slist_prepend (copy->sources,
1307                                        gtk_icon_source_copy (tmp_list->data));
1308
1309       tmp_list = g_slist_next (tmp_list);
1310     }
1311
1312   copy->sources = g_slist_reverse (copy->sources);
1313
1314   copy->cache = copy_cache (icon_set, copy);
1315   copy->cache_size = icon_set->cache_size;
1316   copy->cache_serial = icon_set->cache_serial;
1317   
1318   return copy;
1319 }
1320
1321 static gboolean
1322 sizes_equivalent (GtkIconSize lhs,
1323                   GtkIconSize rhs)
1324 {
1325   /* We used to consider sizes equivalent if they were
1326    * the same pixel size, but we don't have the GtkSettings
1327    * here, so we can't do that. Plus, it's not clear that
1328    * it is right... it was just a workaround for the fact
1329    * that we register icons by logical size, not pixel size.
1330    */
1331 #if 1
1332   return lhs == rhs;
1333 #else  
1334   
1335   gint r_w, r_h, l_w, l_h;
1336
1337   icon_size_lookup_intern (NULL, rhs, &r_w, &r_h);
1338   icon_size_lookup_intern (NULL, lhs, &l_w, &l_h);
1339
1340   return r_w == l_w && r_h == l_h;
1341 #endif
1342 }
1343
1344 static GtkIconSource *
1345 find_best_matching_source (GtkIconSet       *icon_set,
1346                            GtkTextDirection  direction,
1347                            GtkStateType      state,
1348                            GtkIconSize       size,
1349                            GSList           *failed)
1350 {
1351   GtkIconSource *source;
1352   GSList *tmp_list;
1353   
1354   /* We need to find the best icon source.  Direction matters more
1355    * than state, state matters more than size. icon_set->sources
1356    * is sorted according to wildness, so if we take the first
1357    * match we find it will be the least-wild match (if there are
1358    * multiple matches for a given "wildness" then the RC file contained
1359    * dumb stuff, and we end up with an arbitrary matching source)
1360    */
1361   
1362   source = NULL;
1363   tmp_list = icon_set->sources;
1364   while (tmp_list != NULL)
1365     {
1366       GtkIconSource *s = tmp_list->data;
1367       
1368       if ((s->any_direction || (s->direction == direction)) &&
1369           (s->any_state || (s->state == state)) &&
1370           (s->any_size || size == (GtkIconSize)-1 || (sizes_equivalent (size, s->size))))
1371         {
1372           if (!g_slist_find (failed, s))
1373             {
1374               source = s;
1375               break;
1376             }
1377         }
1378           
1379       tmp_list = g_slist_next (tmp_list);
1380     }
1381
1382   return source;
1383 }
1384   
1385 static gboolean
1386 ensure_filename_pixbuf (GtkIconSet    *icon_set,
1387                         GtkIconSource *source)
1388 {
1389   if (source->filename_pixbuf == NULL)
1390     {
1391       GError *error = NULL;
1392       
1393       source->filename_pixbuf = gdk_pixbuf_new_from_file (source->source.filename, &error);
1394       
1395       if (source->filename_pixbuf == NULL)
1396         {
1397           /* Remove this icon source so we don't keep trying to
1398            * load it.
1399            */
1400           g_warning (_("Error loading icon: %s"), error->message);
1401           g_error_free (error);
1402           
1403           icon_set->sources = g_slist_remove (icon_set->sources, source);
1404           
1405           gtk_icon_source_free (source);
1406
1407           return FALSE;
1408         }
1409     }
1410   
1411   return TRUE;
1412 }
1413  
1414 static GdkPixbuf *
1415 render_icon_name_pixbuf (GtkIconSource    *icon_source,
1416                          GtkStyle         *style,
1417                          GtkTextDirection  direction,
1418                          GtkStateType      state,
1419                          GtkIconSize       size,
1420                          GtkWidget         *widget,
1421                          const char        *detail)
1422 {
1423   GdkPixbuf *pixbuf;
1424   GdkPixbuf *tmp_pixbuf;
1425   GtkIconSource tmp_source;
1426   GdkScreen *screen;
1427   GtkIconTheme *icon_theme;
1428   GtkSettings *settings;
1429   gint width, height, pixel_size;
1430   gint *sizes, *s, dist;
1431   GError *error = NULL;
1432   
1433   if (widget && gtk_widget_has_screen (widget))
1434     screen = gtk_widget_get_screen (widget);
1435   else if (style && style->colormap)
1436     screen = gdk_colormap_get_screen (style->colormap);
1437   else
1438     {
1439       screen = gdk_screen_get_default ();
1440       GTK_NOTE (MULTIHEAD,
1441                 g_warning ("Using the default screen for gtk_icon_source_render_icon()"));
1442     }
1443
1444   icon_theme = gtk_icon_theme_get_for_screen (screen);
1445   settings = gtk_settings_get_for_screen (screen);
1446
1447   if (!gtk_icon_size_lookup_for_settings (settings, size, &width, &height))
1448     {
1449       if (size == (GtkIconSize)-1)
1450         {
1451           /* Find an available size close to 48 
1452            */
1453           sizes = gtk_icon_theme_get_icon_sizes (icon_theme, icon_source->source.icon_name);
1454           dist = 1000;
1455           width = height = 48;
1456           for (s = sizes; *s; s++)
1457             {
1458               if (*s == -1)
1459                 {
1460                   width = height = 48;
1461                   break;
1462                 }
1463               if (*s < 48)
1464                 {
1465                   if (48 - *s < dist)
1466                     {
1467                       width = height = *s;
1468                       dist = 48 - *s;
1469                     }
1470                 }
1471               else 
1472                 {
1473                   if (*s - 48 < dist)
1474                     {
1475                       width = height = *s;
1476                       dist = *s - 48;
1477                     }
1478                 }
1479             }
1480           
1481           g_free (sizes);
1482         }
1483       else
1484         {
1485           g_warning ("Invalid icon size %u\n", size);
1486           width = height = 24;
1487         }
1488     }
1489
1490   pixel_size = MIN (width, height);
1491
1492   tmp_pixbuf = gtk_icon_theme_load_icon (icon_theme,
1493                                          icon_source->source.icon_name,
1494                                          pixel_size, 0,
1495                                          &error);
1496
1497   if (!tmp_pixbuf)
1498     {
1499       g_warning ("Error loading theme icon '%s' for stock: %s", 
1500                  icon_source->source.icon_name, error->message);
1501       g_error_free (error);
1502       return NULL;
1503     }
1504   
1505   tmp_source = *icon_source;
1506   tmp_source.type = GTK_ICON_SOURCE_PIXBUF;
1507   tmp_source.source.pixbuf = tmp_pixbuf;
1508
1509   pixbuf = gtk_style_render_icon (style, &tmp_source,
1510                                   direction, state, -1,
1511                                   widget, detail);
1512
1513   if (!pixbuf)
1514     g_warning ("Failed to render icon");
1515
1516   g_object_unref (tmp_pixbuf);
1517
1518   return pixbuf;
1519 }
1520
1521 static GdkPixbuf *
1522 find_and_render_icon_source (GtkIconSet       *icon_set,
1523                              GtkStyle         *style,
1524                              GtkTextDirection  direction,
1525                              GtkStateType      state,
1526                              GtkIconSize       size,
1527                              GtkWidget         *widget,
1528                              const char        *detail)
1529 {
1530   GSList *failed = NULL;
1531   GdkPixbuf *pixbuf = NULL;
1532
1533   /* We treat failure in two different ways:
1534    *
1535    *  A) If loading a source that specifies a filename fails,
1536    *     we treat that as permanent, and remove the source
1537    *     from the GtkIconSet. (in ensure_filename_pixbuf ()
1538    *  B) If loading a themed icon fails, or scaling an icon
1539    *     fails, we treat that as transient and will try
1540    *     again next time the icon falls out of the cache
1541    *     and we need to recreate it.
1542    */
1543   while (pixbuf == NULL)
1544     {
1545       GtkIconSource *source = find_best_matching_source (icon_set, direction, state, size, failed);
1546       
1547       if (source == NULL)
1548         break;
1549
1550       switch (source->type)
1551         {
1552         case GTK_ICON_SOURCE_FILENAME:
1553           if (!ensure_filename_pixbuf (icon_set, source))
1554             break;
1555           /* Fall through */
1556         case GTK_ICON_SOURCE_PIXBUF:
1557           pixbuf = gtk_style_render_icon (style, source,
1558                                           direction, state, size,
1559                                           widget, detail);
1560           if (!pixbuf)
1561             {
1562               g_warning ("Failed to render icon");
1563               failed = g_slist_prepend (failed, source);
1564             }
1565           break;
1566         case GTK_ICON_SOURCE_ICON_NAME:
1567         case GTK_ICON_SOURCE_STATIC_ICON_NAME:
1568           pixbuf = render_icon_name_pixbuf (source, style,
1569                                             direction, state, size,
1570                                             widget, detail);
1571           if (!pixbuf)
1572             failed = g_slist_prepend (failed, source);
1573           break;
1574         case GTK_ICON_SOURCE_EMPTY:
1575           g_assert_not_reached ();
1576         }
1577     }
1578
1579   g_slist_free (failed);
1580
1581   return pixbuf;
1582 }
1583
1584 extern GtkIconCache *_builtin_cache;
1585
1586 static GdkPixbuf*
1587 render_fallback_image (GtkStyle          *style,
1588                        GtkTextDirection   direction,
1589                        GtkStateType       state,
1590                        GtkIconSize        size,
1591                        GtkWidget         *widget,
1592                        const char        *detail)
1593 {
1594   /* This icon can be used for any direction/state/size */
1595   static GtkIconSource fallback_source = GTK_ICON_SOURCE_INIT (TRUE, TRUE, TRUE);
1596
1597   if (fallback_source.type == GTK_ICON_SOURCE_EMPTY)
1598     {
1599       gint index;
1600       GdkPixbuf *pixbuf;
1601
1602       _gtk_icon_theme_ensure_builtin_cache ();
1603
1604       index = _gtk_icon_cache_get_directory_index (_builtin_cache, "24");
1605       pixbuf = _gtk_icon_cache_get_icon (_builtin_cache,
1606                                          GTK_STOCK_MISSING_IMAGE,
1607                                          index);
1608       gtk_icon_source_set_pixbuf (&fallback_source, pixbuf);
1609       g_object_unref (pixbuf);
1610     }
1611   
1612   return gtk_style_render_icon (style,
1613                                 &fallback_source,
1614                                 direction,
1615                                 state,
1616                                 size,
1617                                 widget,
1618                                 detail);
1619 }
1620
1621 /**
1622  * gtk_icon_set_render_icon:
1623  * @icon_set: a #GtkIconSet
1624  * @style: a #GtkStyle associated with @widget, or %NULL
1625  * @direction: text direction
1626  * @state: widget state
1627  * @size: icon size. A size of (GtkIconSize)-1
1628  *        means render at the size of the source and don't scale.
1629  * @widget: widget that will display the icon, or %NULL.
1630  *          The only use that is typically made of this
1631  *          is to determine the appropriate #GdkScreen.
1632  * @detail: detail to pass to the theme engine, or %NULL.
1633  *          Note that passing a detail of anything but %NULL
1634  *          will disable caching.
1635  * 
1636  * Renders an icon using gtk_style_render_icon(). In most cases,
1637  * gtk_widget_render_icon() is better, since it automatically provides
1638  * most of the arguments from the current widget settings.  This
1639  * function never returns %NULL; if the icon can't be rendered
1640  * (perhaps because an image file fails to load), a default "missing
1641  * image" icon will be returned instead.
1642  * 
1643  * Return value: a #GdkPixbuf to be displayed
1644  **/
1645 GdkPixbuf*
1646 gtk_icon_set_render_icon (GtkIconSet        *icon_set,
1647                           GtkStyle          *style,
1648                           GtkTextDirection   direction,
1649                           GtkStateType       state,
1650                           GtkIconSize        size,
1651                           GtkWidget         *widget,
1652                           const char        *detail)
1653 {
1654   GdkPixbuf *icon;
1655   
1656   g_return_val_if_fail (icon_set != NULL, NULL);
1657   g_return_val_if_fail (style == NULL || GTK_IS_STYLE (style), NULL);
1658
1659   if (icon_set->sources == NULL)
1660     return render_fallback_image (style, direction, state, size, widget, detail);
1661
1662   if (detail == NULL)
1663     {
1664       icon = find_in_cache (icon_set, style, direction,
1665                         state, size);
1666       
1667       if (icon)
1668         {
1669           g_object_ref (icon);
1670           return icon;
1671         }
1672     }
1673
1674
1675   icon = find_and_render_icon_source (icon_set, style, direction, state, size,
1676                                       widget, detail);
1677
1678   if (icon == NULL)
1679     icon = render_fallback_image (style, direction, state, size, widget, detail);
1680
1681   if (detail == NULL)
1682     add_to_cache (icon_set, style, direction, state, size, icon);
1683   
1684   return icon;
1685 }
1686
1687 /* Order sources by their "wildness", so that "wilder" sources are
1688  * greater than "specific" sources; for determining ordering,
1689  * direction beats state beats size.
1690  */
1691
1692 static int
1693 icon_source_compare (gconstpointer ap, gconstpointer bp)
1694 {
1695   const GtkIconSource *a = ap;
1696   const GtkIconSource *b = bp;
1697
1698   if (!a->any_direction && b->any_direction)
1699     return -1;
1700   else if (a->any_direction && !b->any_direction)
1701     return 1;
1702   else if (!a->any_state && b->any_state)
1703     return -1;
1704   else if (a->any_state && !b->any_state)
1705     return 1;
1706   else if (!a->any_size && b->any_size)
1707     return -1;
1708   else if (a->any_size && !b->any_size)
1709     return 1;
1710   else
1711     return 0;
1712 }
1713
1714 /**
1715  * gtk_icon_set_add_source:
1716  * @icon_set: a #GtkIconSet
1717  * @source: a #GtkIconSource
1718  *
1719  * Icon sets have a list of #GtkIconSource, which they use as base
1720  * icons for rendering icons in different states and sizes. Icons are
1721  * scaled, made to look insensitive, etc. in
1722  * gtk_icon_set_render_icon(), but #GtkIconSet needs base images to
1723  * work with. The base images and when to use them are described by
1724  * a #GtkIconSource.
1725  * 
1726  * This function copies @source, so you can reuse the same source immediately
1727  * without affecting the icon set.
1728  *
1729  * An example of when you'd use this function: a web browser's "Back
1730  * to Previous Page" icon might point in a different direction in
1731  * Hebrew and in English; it might look different when insensitive;
1732  * and it might change size depending on toolbar mode (small/large
1733  * icons). So a single icon set would contain all those variants of
1734  * the icon, and you might add a separate source for each one.
1735  *
1736  * You should nearly always add a "default" icon source with all
1737  * fields wildcarded, which will be used as a fallback if no more
1738  * specific source matches. #GtkIconSet always prefers more specific
1739  * icon sources to more generic icon sources. The order in which you
1740  * add the sources to the icon set does not matter.
1741  *
1742  * gtk_icon_set_new_from_pixbuf() creates a new icon set with a
1743  * default icon source based on the given pixbuf.
1744  * 
1745  **/
1746 void
1747 gtk_icon_set_add_source (GtkIconSet *icon_set,
1748                          const GtkIconSource *source)
1749 {
1750   g_return_if_fail (icon_set != NULL);
1751   g_return_if_fail (source != NULL);
1752
1753   if (source->type == GTK_ICON_SOURCE_EMPTY)
1754     {
1755       g_warning ("Useless empty GtkIconSource");
1756       return;
1757     }
1758   
1759   icon_set->sources = g_slist_insert_sorted (icon_set->sources,
1760                                              gtk_icon_source_copy (source),
1761                                              icon_source_compare);
1762 }
1763
1764 /**
1765  * gtk_icon_set_get_sizes:
1766  * @icon_set: a #GtkIconSet
1767  * @sizes: return location for array of sizes
1768  * @n_sizes: location to store number of elements in returned array
1769  *
1770  * Obtains a list of icon sizes this icon set can render. The returned
1771  * array must be freed with g_free().
1772  * 
1773  **/
1774 void
1775 gtk_icon_set_get_sizes (GtkIconSet   *icon_set,
1776                         GtkIconSize **sizes,
1777                         gint         *n_sizes)
1778 {
1779   GSList *tmp_list;
1780   gboolean all_sizes = FALSE;
1781   GSList *specifics = NULL;
1782   
1783   g_return_if_fail (icon_set != NULL);
1784   g_return_if_fail (sizes != NULL);
1785   g_return_if_fail (n_sizes != NULL);
1786   
1787   tmp_list = icon_set->sources;
1788   while (tmp_list != NULL)
1789     {
1790       GtkIconSource *source;
1791
1792       source = tmp_list->data;
1793
1794       if (source->any_size)
1795         {
1796           all_sizes = TRUE;
1797           break;
1798         }
1799       else
1800         specifics = g_slist_prepend (specifics, GINT_TO_POINTER (source->size));
1801       
1802       tmp_list = g_slist_next (tmp_list);
1803     }
1804
1805   if (all_sizes)
1806     {
1807       /* Need to find out what sizes exist */
1808       gint i;
1809
1810       init_icon_sizes ();
1811       
1812       *sizes = g_new (GtkIconSize, icon_sizes_used);
1813       *n_sizes = icon_sizes_used - 1;
1814       
1815       i = 1;      
1816       while (i < icon_sizes_used)
1817         {
1818           (*sizes)[i - 1] = icon_sizes[i].size;
1819           ++i;
1820         }
1821     }
1822   else
1823     {
1824       gint i;
1825       
1826       *n_sizes = g_slist_length (specifics);
1827       *sizes = g_new (GtkIconSize, *n_sizes);
1828
1829       i = 0;
1830       tmp_list = specifics;
1831       while (tmp_list != NULL)
1832         {
1833           (*sizes)[i] = GPOINTER_TO_INT (tmp_list->data);
1834
1835           ++i;
1836           tmp_list = g_slist_next (tmp_list);
1837         }
1838     }
1839
1840   g_slist_free (specifics);
1841 }
1842
1843
1844 /**
1845  * gtk_icon_source_new:
1846  * 
1847  * Creates a new #GtkIconSource. A #GtkIconSource contains a #GdkPixbuf (or
1848  * image filename) that serves as the base image for one or more of the
1849  * icons in a #GtkIconSet, along with a specification for which icons in the
1850  * icon set will be based on that pixbuf or image file. An icon set contains
1851  * a set of icons that represent "the same" logical concept in different states,
1852  * different global text directions, and different sizes.
1853  * 
1854  * So for example a web browser's "Back to Previous Page" icon might
1855  * point in a different direction in Hebrew and in English; it might
1856  * look different when insensitive; and it might change size depending
1857  * on toolbar mode (small/large icons). So a single icon set would
1858  * contain all those variants of the icon. #GtkIconSet contains a list
1859  * of #GtkIconSource from which it can derive specific icon variants in
1860  * the set. 
1861  *
1862  * In the simplest case, #GtkIconSet contains one source pixbuf from
1863  * which it derives all variants. The convenience function
1864  * gtk_icon_set_new_from_pixbuf() handles this case; if you only have
1865  * one source pixbuf, just use that function.
1866  *
1867  * If you want to use a different base pixbuf for different icon
1868  * variants, you create multiple icon sources, mark which variants
1869  * they'll be used to create, and add them to the icon set with
1870  * gtk_icon_set_add_source().
1871  *
1872  * By default, the icon source has all parameters wildcarded. That is,
1873  * the icon source will be used as the base icon for any desired text
1874  * direction, widget state, or icon size.
1875  * 
1876  * Return value: a new #GtkIconSource
1877  **/
1878 GtkIconSource*
1879 gtk_icon_source_new (void)
1880 {
1881   GtkIconSource *src;
1882   
1883   src = g_new0 (GtkIconSource, 1);
1884
1885   src->direction = GTK_TEXT_DIR_NONE;
1886   src->size = GTK_ICON_SIZE_INVALID;
1887   src->state = GTK_STATE_NORMAL;
1888   
1889   src->any_direction = TRUE;
1890   src->any_state = TRUE;
1891   src->any_size = TRUE;
1892   
1893   return src;
1894 }
1895
1896 /**
1897  * gtk_icon_source_copy:
1898  * @source: a #GtkIconSource
1899  * 
1900  * Creates a copy of @source; mostly useful for language bindings.
1901  * 
1902  * Return value: a new #GtkIconSource
1903  **/
1904 GtkIconSource*
1905 gtk_icon_source_copy (const GtkIconSource *source)
1906 {
1907   GtkIconSource *copy;
1908   
1909   g_return_val_if_fail (source != NULL, NULL);
1910
1911   copy = g_new (GtkIconSource, 1);
1912
1913   *copy = *source;
1914   
1915   switch (copy->type)
1916     {
1917     case GTK_ICON_SOURCE_EMPTY:
1918     case GTK_ICON_SOURCE_STATIC_ICON_NAME:
1919       break;
1920     case GTK_ICON_SOURCE_ICON_NAME:
1921       copy->source.icon_name = g_strdup (copy->source.icon_name);
1922       break;
1923     case GTK_ICON_SOURCE_FILENAME:
1924       copy->source.filename = g_strdup (copy->source.filename);
1925 #ifdef G_OS_WIN32
1926       copy->cp_filename = g_strdup (copy->cp_filename);
1927 #endif
1928       if (copy->filename_pixbuf)
1929         g_object_ref (copy->filename_pixbuf);
1930       break;
1931     case GTK_ICON_SOURCE_PIXBUF:
1932       g_object_ref (copy->source.pixbuf);
1933       break;
1934     default:
1935       g_assert_not_reached();
1936     }
1937
1938   return copy;
1939 }
1940
1941 /**
1942  * gtk_icon_source_free:
1943  * @source: a #GtkIconSource
1944  * 
1945  * Frees a dynamically-allocated icon source, along with its
1946  * filename, size, and pixbuf fields if those are not %NULL.
1947  **/
1948 void
1949 gtk_icon_source_free (GtkIconSource *source)
1950 {
1951   g_return_if_fail (source != NULL);
1952
1953   icon_source_clear (source);
1954   g_free (source);
1955 }
1956
1957 GType
1958 gtk_icon_source_get_type (void)
1959 {
1960   static GType our_type = 0;
1961   
1962   if (our_type == 0)
1963     our_type = g_boxed_type_register_static (I_("GtkIconSource"),
1964                                              (GBoxedCopyFunc) gtk_icon_source_copy,
1965                                              (GBoxedFreeFunc) gtk_icon_source_free);
1966
1967   return our_type;
1968 }
1969
1970 static void
1971 icon_source_clear (GtkIconSource *source)
1972 {
1973   switch (source->type)
1974     {
1975     case GTK_ICON_SOURCE_EMPTY:
1976       break;
1977     case GTK_ICON_SOURCE_ICON_NAME:
1978       g_free (source->source.icon_name);
1979       /* fall thru */
1980     case GTK_ICON_SOURCE_STATIC_ICON_NAME:
1981       source->source.icon_name = NULL;
1982       break;
1983     case GTK_ICON_SOURCE_FILENAME:
1984       g_free (source->source.filename);
1985       source->source.filename = NULL;
1986 #ifdef G_OS_WIN32
1987       g_free (source->cp_filename);
1988       source->cp_filename = NULL;
1989 #endif
1990       if (source->filename_pixbuf) 
1991         g_object_unref (source->filename_pixbuf);
1992       source->filename_pixbuf = NULL;
1993       break;
1994     case GTK_ICON_SOURCE_PIXBUF:
1995       g_object_unref (source->source.pixbuf);
1996       source->source.pixbuf = NULL;
1997       break;
1998     default:
1999       g_assert_not_reached();
2000     }
2001
2002   source->type = GTK_ICON_SOURCE_EMPTY;
2003 }
2004
2005 /**
2006  * gtk_icon_source_set_filename:
2007  * @source: a #GtkIconSource
2008  * @filename: image file to use
2009  *
2010  * Sets the name of an image file to use as a base image when creating
2011  * icon variants for #GtkIconSet. The filename must be absolute. 
2012  **/
2013 void
2014 gtk_icon_source_set_filename (GtkIconSource *source,
2015                               const gchar   *filename)
2016 {
2017   g_return_if_fail (source != NULL);
2018   g_return_if_fail (filename == NULL || g_path_is_absolute (filename));
2019
2020   if (source->type == GTK_ICON_SOURCE_FILENAME &&
2021       source->source.filename == filename)
2022     return;
2023   
2024   icon_source_clear (source);
2025   
2026   if (filename != NULL)
2027     {
2028       source->type = GTK_ICON_SOURCE_FILENAME;
2029       source->source.filename = g_strdup (filename);
2030 #ifdef G_OS_WIN32
2031       source->cp_filename = g_locale_from_utf8 (filename, -1, NULL, NULL, NULL);
2032 #endif
2033     }
2034 }
2035
2036 /**
2037  * gtk_icon_source_set_icon_name
2038  * @source: a #GtkIconSource
2039  * @icon_name: name of icon to use
2040  *
2041  * Sets the name of an icon to look up in the current icon theme
2042  * to use as a base image when creating icon variants for #GtkIconSet.
2043  **/
2044 void
2045 gtk_icon_source_set_icon_name (GtkIconSource *source,
2046                                const gchar   *icon_name)
2047 {
2048   g_return_if_fail (source != NULL);
2049
2050   if (source->type == GTK_ICON_SOURCE_ICON_NAME &&
2051       source->source.icon_name == icon_name)
2052     return;
2053
2054   icon_source_clear (source);
2055   
2056   if (icon_name != NULL)
2057     {
2058       source->type = GTK_ICON_SOURCE_ICON_NAME;
2059       source->source.icon_name = g_strdup (icon_name);
2060     }
2061 }
2062
2063 /**
2064  * gtk_icon_source_set_pixbuf:
2065  * @source: a #GtkIconSource
2066  * @pixbuf: pixbuf to use as a source
2067  *
2068  * Sets a pixbuf to use as a base image when creating icon variants
2069  * for #GtkIconSet.
2070  **/
2071 void
2072 gtk_icon_source_set_pixbuf (GtkIconSource *source,
2073                             GdkPixbuf     *pixbuf)
2074 {
2075   g_return_if_fail (source != NULL);
2076   g_return_if_fail (pixbuf == NULL || GDK_IS_PIXBUF (pixbuf));
2077   
2078   if (source->type == GTK_ICON_SOURCE_PIXBUF &&
2079       source->source.pixbuf == pixbuf)
2080     return;
2081
2082   icon_source_clear (source);
2083   
2084   if (pixbuf != NULL)
2085     {
2086       source->type = GTK_ICON_SOURCE_PIXBUF;
2087       source->source.pixbuf = g_object_ref (pixbuf);
2088     }
2089 }
2090
2091 /**
2092  * gtk_icon_source_get_filename:
2093  * @source: a #GtkIconSource
2094  * 
2095  * Retrieves the source filename, or %NULL if none is set. The
2096  * filename is not a copy, and should not be modified or expected to
2097  * persist beyond the lifetime of the icon source.
2098  * 
2099  * Return value: image filename. This string must not be modified
2100  * or freed.
2101  **/
2102 G_CONST_RETURN gchar*
2103 gtk_icon_source_get_filename (const GtkIconSource *source)
2104 {
2105   g_return_val_if_fail (source != NULL, NULL);
2106
2107   if (source->type == GTK_ICON_SOURCE_FILENAME)
2108     return source->source.filename;
2109   else
2110     return NULL;
2111 }
2112
2113 /**
2114  * gtk_icon_source_get_icon_name:
2115  * @source: a #GtkIconSource
2116  * 
2117  * Retrieves the source icon name, or %NULL if none is set. The
2118  * icon_name is not a copy, and should not be modified or expected to
2119  * persist beyond the lifetime of the icon source.
2120  * 
2121  * Return value: icon name. This string must not be modified or freed.
2122  **/
2123 G_CONST_RETURN gchar*
2124 gtk_icon_source_get_icon_name (const GtkIconSource *source)
2125 {
2126   g_return_val_if_fail (source != NULL, NULL);
2127
2128   if (source->type == GTK_ICON_SOURCE_ICON_NAME ||
2129      source->type == GTK_ICON_SOURCE_STATIC_ICON_NAME)
2130     return source->source.icon_name;
2131   else
2132     return NULL;
2133 }
2134
2135 /**
2136  * gtk_icon_source_get_pixbuf:
2137  * @source: a #GtkIconSource
2138  * 
2139  * Retrieves the source pixbuf, or %NULL if none is set.
2140  * In addition, if a filename source is in use, this
2141  * function in some cases will return the pixbuf from
2142  * loaded from the filename. This is, for example, true
2143  * for the GtkIconSource passed to the GtkStyle::render_icon()
2144  * virtual function. The reference count on the pixbuf is
2145  * not incremented.
2146  * 
2147  * Return value: source pixbuf
2148  **/
2149 GdkPixbuf*
2150 gtk_icon_source_get_pixbuf (const GtkIconSource *source)
2151 {
2152   g_return_val_if_fail (source != NULL, NULL);
2153   
2154   if (source->type == GTK_ICON_SOURCE_PIXBUF)
2155     return source->source.pixbuf;
2156   else if (source->type == GTK_ICON_SOURCE_FILENAME)
2157     return source->filename_pixbuf;
2158   else
2159     return NULL;
2160 }
2161
2162 /**
2163  * gtk_icon_source_set_direction_wildcarded:
2164  * @source: a #GtkIconSource
2165  * @setting: %TRUE to wildcard the text direction
2166  *
2167  * If the text direction is wildcarded, this source can be used
2168  * as the base image for an icon in any #GtkTextDirection.
2169  * If the text direction is not wildcarded, then the
2170  * text direction the icon source applies to should be set
2171  * with gtk_icon_source_set_direction(), and the icon source
2172  * will only be used with that text direction.
2173  *
2174  * #GtkIconSet prefers non-wildcarded sources (exact matches) over
2175  * wildcarded sources, and will use an exact match when possible.
2176  * 
2177  **/
2178 void
2179 gtk_icon_source_set_direction_wildcarded (GtkIconSource *source,
2180                                           gboolean       setting)
2181 {
2182   g_return_if_fail (source != NULL);
2183
2184   source->any_direction = setting != FALSE;
2185 }
2186
2187 /**
2188  * gtk_icon_source_set_state_wildcarded:
2189  * @source: a #GtkIconSource
2190  * @setting: %TRUE to wildcard the widget state
2191  *
2192  * If the widget state is wildcarded, this source can be used as the
2193  * base image for an icon in any #GtkStateType.  If the widget state
2194  * is not wildcarded, then the state the source applies to should be
2195  * set with gtk_icon_source_set_state() and the icon source will
2196  * only be used with that specific state.
2197  *
2198  * #GtkIconSet prefers non-wildcarded sources (exact matches) over
2199  * wildcarded sources, and will use an exact match when possible.
2200  *
2201  * #GtkIconSet will normally transform wildcarded source images to
2202  * produce an appropriate icon for a given state, for example
2203  * lightening an image on prelight, but will not modify source images
2204  * that match exactly.
2205  **/
2206 void
2207 gtk_icon_source_set_state_wildcarded (GtkIconSource *source,
2208                                       gboolean       setting)
2209 {
2210   g_return_if_fail (source != NULL);
2211
2212   source->any_state = setting != FALSE;
2213 }
2214
2215
2216 /**
2217  * gtk_icon_source_set_size_wildcarded:
2218  * @source: a #GtkIconSource
2219  * @setting: %TRUE to wildcard the widget state
2220  *
2221  * If the icon size is wildcarded, this source can be used as the base
2222  * image for an icon of any size.  If the size is not wildcarded, then
2223  * the size the source applies to should be set with
2224  * gtk_icon_source_set_size() and the icon source will only be used
2225  * with that specific size.
2226  *
2227  * #GtkIconSet prefers non-wildcarded sources (exact matches) over
2228  * wildcarded sources, and will use an exact match when possible.
2229  *
2230  * #GtkIconSet will normally scale wildcarded source images to produce
2231  * an appropriate icon at a given size, but will not change the size
2232  * of source images that match exactly.
2233  **/
2234 void
2235 gtk_icon_source_set_size_wildcarded (GtkIconSource *source,
2236                                      gboolean       setting)
2237 {
2238   g_return_if_fail (source != NULL);
2239
2240   source->any_size = setting != FALSE;  
2241 }
2242
2243 /**
2244  * gtk_icon_source_get_size_wildcarded:
2245  * @source: a #GtkIconSource
2246  * 
2247  * Gets the value set by gtk_icon_source_set_size_wildcarded().
2248  * 
2249  * Return value: %TRUE if this icon source is a base for any icon size variant
2250  **/
2251 gboolean
2252 gtk_icon_source_get_size_wildcarded (const GtkIconSource *source)
2253 {
2254   g_return_val_if_fail (source != NULL, TRUE);
2255   
2256   return source->any_size;
2257 }
2258
2259 /**
2260  * gtk_icon_source_get_state_wildcarded:
2261  * @source: a #GtkIconSource
2262  * 
2263  * Gets the value set by gtk_icon_source_set_state_wildcarded().
2264  * 
2265  * Return value: %TRUE if this icon source is a base for any widget state variant
2266  **/
2267 gboolean
2268 gtk_icon_source_get_state_wildcarded (const GtkIconSource *source)
2269 {
2270   g_return_val_if_fail (source != NULL, TRUE);
2271
2272   return source->any_state;
2273 }
2274
2275 /**
2276  * gtk_icon_source_get_direction_wildcarded:
2277  * @source: a #GtkIconSource
2278  * 
2279  * Gets the value set by gtk_icon_source_set_direction_wildcarded().
2280  * 
2281  * Return value: %TRUE if this icon source is a base for any text direction variant
2282  **/
2283 gboolean
2284 gtk_icon_source_get_direction_wildcarded (const GtkIconSource *source)
2285 {
2286   g_return_val_if_fail (source != NULL, TRUE);
2287
2288   return source->any_direction;
2289 }
2290
2291 /**
2292  * gtk_icon_source_set_direction:
2293  * @source: a #GtkIconSource
2294  * @direction: text direction this source applies to
2295  *
2296  * Sets the text direction this icon source is intended to be used
2297  * with.
2298  * 
2299  * Setting the text direction on an icon source makes no difference
2300  * if the text direction is wildcarded. Therefore, you should usually
2301  * call gtk_icon_source_set_direction_wildcarded() to un-wildcard it
2302  * in addition to calling this function.
2303  * 
2304  **/
2305 void
2306 gtk_icon_source_set_direction (GtkIconSource   *source,
2307                                GtkTextDirection direction)
2308 {
2309   g_return_if_fail (source != NULL);
2310
2311   source->direction = direction;
2312 }
2313
2314 /**
2315  * gtk_icon_source_set_state:
2316  * @source: a #GtkIconSource
2317  * @state: widget state this source applies to
2318  *
2319  * Sets the widget state this icon source is intended to be used
2320  * with.
2321  * 
2322  * Setting the widget state on an icon source makes no difference
2323  * if the state is wildcarded. Therefore, you should usually
2324  * call gtk_icon_source_set_state_wildcarded() to un-wildcard it
2325  * in addition to calling this function.
2326  * 
2327  **/
2328 void
2329 gtk_icon_source_set_state (GtkIconSource *source,
2330                            GtkStateType   state)
2331 {
2332   g_return_if_fail (source != NULL);
2333
2334   source->state = state;
2335 }
2336
2337 /**
2338  * gtk_icon_source_set_size:
2339  * @source: a #GtkIconSource
2340  * @size: icon size this source applies to
2341  *
2342  * Sets the icon size this icon source is intended to be used
2343  * with.
2344  * 
2345  * Setting the icon size on an icon source makes no difference
2346  * if the size is wildcarded. Therefore, you should usually
2347  * call gtk_icon_source_set_size_wildcarded() to un-wildcard it
2348  * in addition to calling this function.
2349  * 
2350  **/
2351 void
2352 gtk_icon_source_set_size (GtkIconSource *source,
2353                           GtkIconSize    size)
2354 {
2355   g_return_if_fail (source != NULL);
2356
2357   source->size = size;
2358 }
2359
2360 /**
2361  * gtk_icon_source_get_direction:
2362  * @source: a #GtkIconSource
2363  * 
2364  * Obtains the text direction this icon source applies to. The return
2365  * value is only useful/meaningful if the text direction is <emphasis>not</emphasis> 
2366  * wildcarded.
2367  * 
2368  * Return value: text direction this source matches
2369  **/
2370 GtkTextDirection
2371 gtk_icon_source_get_direction (const GtkIconSource *source)
2372 {
2373   g_return_val_if_fail (source != NULL, 0);
2374
2375   return source->direction;
2376 }
2377
2378 /**
2379  * gtk_icon_source_get_state:
2380  * @source: a #GtkIconSource
2381  * 
2382  * Obtains the widget state this icon source applies to. The return
2383  * value is only useful/meaningful if the widget state is <emphasis>not</emphasis>
2384  * wildcarded.
2385  * 
2386  * Return value: widget state this source matches
2387  **/
2388 GtkStateType
2389 gtk_icon_source_get_state (const GtkIconSource *source)
2390 {
2391   g_return_val_if_fail (source != NULL, 0);
2392
2393   return source->state;
2394 }
2395
2396 /**
2397  * gtk_icon_source_get_size:
2398  * @source: a #GtkIconSource
2399  * 
2400  * Obtains the icon size this source applies to. The return value
2401  * is only useful/meaningful if the icon size is <emphasis>not</emphasis> wildcarded.
2402  * 
2403  * Return value: icon size this source matches.
2404  **/
2405 GtkIconSize
2406 gtk_icon_source_get_size (const GtkIconSource *source)
2407 {
2408   g_return_val_if_fail (source != NULL, 0);
2409
2410   return source->size;
2411 }
2412
2413 #define NUM_CACHED_ICONS 8
2414
2415 typedef struct _CachedIcon CachedIcon;
2416
2417 struct _CachedIcon
2418 {
2419   /* These must all match to use the cached pixbuf.
2420    * If any don't match, we must re-render the pixbuf.
2421    */
2422   GtkStyle *style;
2423   GtkTextDirection direction;
2424   GtkStateType state;
2425   GtkIconSize size;
2426
2427   GdkPixbuf *pixbuf;
2428 };
2429
2430 static void
2431 ensure_cache_up_to_date (GtkIconSet *icon_set)
2432 {
2433   if (icon_set->cache_serial != cache_serial)
2434     {
2435       clear_cache (icon_set, TRUE);
2436       icon_set->cache_serial = cache_serial;
2437     }
2438 }
2439
2440 static void
2441 cached_icon_free (CachedIcon *icon)
2442 {
2443   g_object_unref (icon->pixbuf);
2444
2445   if (icon->style)
2446     g_object_unref (icon->style);
2447
2448   g_free (icon);
2449 }
2450
2451 static GdkPixbuf *
2452 find_in_cache (GtkIconSet      *icon_set,
2453                GtkStyle        *style,
2454                GtkTextDirection direction,
2455                GtkStateType     state,
2456                GtkIconSize      size)
2457 {
2458   GSList *tmp_list;
2459   GSList *prev;
2460
2461   ensure_cache_up_to_date (icon_set);
2462   
2463   prev = NULL;
2464   tmp_list = icon_set->cache;
2465   while (tmp_list != NULL)
2466     {
2467       CachedIcon *icon = tmp_list->data;
2468
2469       if (icon->style == style &&
2470           icon->direction == direction &&
2471           icon->state == state &&
2472           (size == (GtkIconSize)-1 || icon->size == size))
2473         {
2474           if (prev)
2475             {
2476               /* Move this icon to the front of the list. */
2477               prev->next = tmp_list->next;
2478               tmp_list->next = icon_set->cache;
2479               icon_set->cache = tmp_list;
2480             }
2481           
2482           return icon->pixbuf;
2483         }
2484           
2485       prev = tmp_list;
2486       tmp_list = g_slist_next (tmp_list);
2487     }
2488
2489   return NULL;
2490 }
2491
2492 static void
2493 add_to_cache (GtkIconSet      *icon_set,
2494               GtkStyle        *style,
2495               GtkTextDirection direction,
2496               GtkStateType     state,
2497               GtkIconSize      size,
2498               GdkPixbuf       *pixbuf)
2499 {
2500   CachedIcon *icon;
2501
2502   ensure_cache_up_to_date (icon_set);
2503
2504   g_object_ref (pixbuf);
2505
2506   /* We have to ref the style, since if the style was finalized
2507    * its address could be reused by another style, creating a
2508    * really weird bug
2509    */
2510   
2511   if (style)
2512     g_object_ref (style);
2513
2514   icon = g_new (CachedIcon, 1);
2515   icon_set->cache = g_slist_prepend (icon_set->cache, icon);
2516   icon_set->cache_size++;
2517
2518   icon->style = style;
2519   icon->direction = direction;
2520   icon->state = state;
2521   icon->size = size;
2522   icon->pixbuf = pixbuf;
2523
2524   if (icon->style)
2525     attach_to_style (icon_set, icon->style);
2526   
2527   if (icon_set->cache_size >= NUM_CACHED_ICONS)
2528     {
2529       /* Remove oldest item in the cache */
2530       GSList *tmp_list;
2531       
2532       tmp_list = icon_set->cache;
2533
2534       /* Find next-to-last link */
2535       g_assert (NUM_CACHED_ICONS > 2);
2536       while (tmp_list->next->next)
2537         tmp_list = tmp_list->next;
2538
2539       g_assert (tmp_list != NULL);
2540       g_assert (tmp_list->next != NULL);
2541       g_assert (tmp_list->next->next == NULL);
2542
2543       /* Free the last icon */
2544       icon = tmp_list->next->data;
2545
2546       g_slist_free (tmp_list->next);
2547       tmp_list->next = NULL;
2548
2549       cached_icon_free (icon);
2550     }
2551 }
2552
2553 static void
2554 clear_cache (GtkIconSet *icon_set,
2555              gboolean    style_detach)
2556 {
2557   GSList *cache, *tmp_list;
2558   GtkStyle *last_style = NULL;
2559
2560   cache = icon_set->cache;
2561   icon_set->cache = NULL;
2562   icon_set->cache_size = 0;
2563   tmp_list = cache;
2564   while (tmp_list != NULL)
2565     {
2566       CachedIcon *icon = tmp_list->data;
2567
2568       if (style_detach)
2569         {
2570           /* simple optimization for the case where the cache
2571            * contains contiguous icons from the same style.
2572            * it's safe to call detach_from_style more than
2573            * once on the same style though.
2574            */
2575           if (last_style != icon->style)
2576             {
2577               detach_from_style (icon_set, icon->style);
2578               last_style = icon->style;
2579             }
2580         }
2581       
2582       cached_icon_free (icon);      
2583       
2584       tmp_list = g_slist_next (tmp_list);
2585     }
2586
2587   g_slist_free (cache);
2588 }
2589
2590 static GSList*
2591 copy_cache (GtkIconSet *icon_set,
2592             GtkIconSet *copy_recipient)
2593 {
2594   GSList *tmp_list;
2595   GSList *copy = NULL;
2596
2597   ensure_cache_up_to_date (icon_set);
2598   
2599   tmp_list = icon_set->cache;
2600   while (tmp_list != NULL)
2601     {
2602       CachedIcon *icon = tmp_list->data;
2603       CachedIcon *icon_copy = g_new (CachedIcon, 1);
2604
2605       *icon_copy = *icon;
2606
2607       if (icon_copy->style)
2608         {
2609           attach_to_style (copy_recipient, icon_copy->style);
2610           g_object_ref (icon_copy->style);
2611         }
2612         
2613       g_object_ref (icon_copy->pixbuf);
2614
2615       icon_copy->size = icon->size;
2616       
2617       copy = g_slist_prepend (copy, icon_copy);      
2618       
2619       tmp_list = g_slist_next (tmp_list);
2620     }
2621
2622   return g_slist_reverse (copy);
2623 }
2624
2625 static void
2626 attach_to_style (GtkIconSet *icon_set,
2627                  GtkStyle   *style)
2628 {
2629   GHashTable *table;
2630
2631   table = g_object_get_qdata (G_OBJECT (style),
2632                               g_quark_try_string ("gtk-style-icon-sets"));
2633
2634   if (table == NULL)
2635     {
2636       table = g_hash_table_new (NULL, NULL);
2637       g_object_set_qdata_full (G_OBJECT (style),
2638                                g_quark_from_static_string ("gtk-style-icon-sets"),
2639                                table,
2640                                style_dnotify);
2641     }
2642
2643   g_hash_table_insert (table, icon_set, icon_set);
2644 }
2645
2646 static void
2647 detach_from_style (GtkIconSet *icon_set,
2648                    GtkStyle   *style)
2649 {
2650   GHashTable *table;
2651
2652   table = g_object_get_qdata (G_OBJECT (style),
2653                               g_quark_try_string ("gtk-style-icon-sets"));
2654
2655   if (table != NULL)
2656     g_hash_table_remove (table, icon_set);
2657 }
2658
2659 static void
2660 iconsets_foreach (gpointer key,
2661                   gpointer value,
2662                   gpointer user_data)
2663 {
2664   GtkIconSet *icon_set = key;
2665
2666   /* We only need to remove cache entries for the given style;
2667    * but that complicates things because in destroy notify
2668    * we don't know which style got destroyed, and 95% of the
2669    * time all cache entries will have the same style,
2670    * so this is faster anyway.
2671    */
2672   
2673   clear_cache (icon_set, FALSE);
2674 }
2675
2676 static void
2677 style_dnotify (gpointer data)
2678 {
2679   GHashTable *table = data;
2680   
2681   g_hash_table_foreach (table, iconsets_foreach, NULL);
2682
2683   g_hash_table_destroy (table);
2684 }
2685
2686 /* This allows the icon set to detect that its cache is out of date. */
2687 void
2688 _gtk_icon_set_invalidate_caches (void)
2689 {
2690   ++cache_serial;
2691 }
2692
2693 /**
2694  * _gtk_icon_factory_list_ids:
2695  * 
2696  * Gets all known IDs stored in an existing icon factory.
2697  * The strings in the returned list aren't copied.
2698  * The list itself should be freed.
2699  * 
2700  * Return value: List of ids in icon factories
2701  **/
2702 GList*
2703 _gtk_icon_factory_list_ids (void)
2704 {
2705   GSList *tmp_list;
2706   GList *ids;
2707
2708   ids = NULL;
2709
2710   _gtk_icon_factory_ensure_default_icons ();
2711   
2712   tmp_list = all_icon_factories;
2713   while (tmp_list != NULL)
2714     {
2715       GList *these_ids;
2716       
2717       GtkIconFactory *factory = GTK_ICON_FACTORY (tmp_list->data);
2718
2719       these_ids = g_hash_table_get_keys (factory->icons);
2720       
2721       ids = g_list_concat (ids, these_ids);
2722       
2723       tmp_list = g_slist_next (tmp_list);
2724     }
2725
2726   return ids;
2727 }
2728
2729 typedef struct {
2730   GSList *sources;
2731   gboolean in_source;
2732   
2733 } IconFactoryParserData;
2734
2735 typedef struct {
2736   gchar            *stock_id;
2737   gchar            *filename;
2738   gchar            *icon_name;
2739   GtkTextDirection  direction;
2740   GtkIconSize       size;
2741   GtkStateType      state;
2742 } IconSourceParserData;
2743
2744 static void
2745 icon_source_start_element (GMarkupParseContext *context,
2746                            const gchar         *element_name,
2747                            const gchar        **names,
2748                            const gchar        **values,
2749                            gpointer             user_data,
2750                            GError             **error)
2751 {
2752   gint i;
2753   gchar *stock_id = NULL;
2754   gchar *filename = NULL;
2755   gchar *icon_name = NULL;
2756   gint size = -1;
2757   gint direction = -1;
2758   gint state = -1;
2759   IconFactoryParserData *parser_data;
2760   IconSourceParserData *source_data;
2761   gchar *error_msg;
2762   GQuark error_domain;
2763   
2764   parser_data = (IconFactoryParserData*)user_data;
2765
2766   if (!parser_data->in_source)
2767     {
2768       if (strcmp (element_name, "sources") != 0)
2769         {
2770           error_msg = g_strdup_printf ("Unexpected element %s, expected <sources>", element_name);
2771           error_domain = GTK_BUILDER_ERROR_INVALID_TAG;
2772           goto error;
2773         }
2774       parser_data->in_source = TRUE;
2775       return;
2776     }
2777   else
2778     {
2779       if (strcmp (element_name, "source") != 0)
2780         {
2781           error_msg = g_strdup_printf ("Unexpected element %s, expected <source>", element_name);
2782           error_domain = GTK_BUILDER_ERROR_INVALID_TAG;
2783           goto error;
2784         }
2785     }
2786   
2787   for (i = 0; names[i]; i++)
2788     {
2789       if (strcmp (names[i], "stock-id") == 0)
2790         stock_id = g_strdup (values[i]);
2791       else if (strcmp (names[i], "filename") == 0)
2792         filename = g_strdup (values[i]);
2793       else if (strcmp (names[i], "icon-name") == 0)
2794         icon_name = g_strdup (values[i]);
2795       else if (strcmp (names[i], "size") == 0)
2796         {
2797           if (!_gtk_builder_enum_from_string (GTK_TYPE_ICON_SIZE,
2798                                               values[i],
2799                                               &size,
2800                                               error))
2801               return;
2802         }
2803       else if (strcmp (names[i], "direction") == 0)
2804         {
2805           if (!_gtk_builder_enum_from_string (GTK_TYPE_TEXT_DIRECTION,
2806                                               values[i],
2807                                               &direction,
2808                                               error))
2809               return;
2810         }
2811       else if (strcmp (names[i], "state") == 0)
2812         {
2813           if (!_gtk_builder_enum_from_string (GTK_TYPE_STATE_TYPE,
2814                                               values[i],
2815                                               &state,
2816                                               error))
2817               return;
2818         }
2819       else
2820         {
2821           error_msg = g_strdup_printf ("'%s' is not a valid attribute of <%s>",
2822                                        names[i], "source");
2823           error_domain = GTK_BUILDER_ERROR_INVALID_ATTRIBUTE;
2824           goto error;
2825         }
2826     }
2827
2828   if (!stock_id || !filename)
2829     {
2830       error_msg = g_strdup_printf ("<source> requires a stock_id and a filename");
2831       error_domain = GTK_BUILDER_ERROR_MISSING_ATTRIBUTE;
2832       goto error;
2833     }
2834
2835   source_data = g_slice_new (IconSourceParserData);
2836   source_data->stock_id = stock_id;
2837   source_data->filename = filename;
2838   source_data->icon_name = icon_name;
2839   source_data->size = size;
2840   source_data->direction = direction;
2841   source_data->state = state;
2842
2843   parser_data->sources = g_slist_prepend (parser_data->sources, source_data);
2844   return;
2845
2846  error:
2847   {
2848     gchar *tmp;
2849     gint line_number, char_number;
2850     
2851     g_markup_parse_context_get_position (context,
2852                                          &line_number,
2853                                          &char_number);
2854
2855     tmp = g_strdup_printf ("%s:%d:%d %s", "input",
2856                            line_number, char_number, error_msg);
2857 #if 0
2858     g_set_error (error,
2859                  GTK_BUILDER_ERROR,
2860                  error_domain,
2861                  tmp);
2862 #else
2863     g_warning (tmp);
2864 #endif    
2865     g_free (tmp);
2866     g_free (stock_id);
2867     g_free (filename);
2868     g_free (icon_name);
2869     return;
2870   }
2871 }
2872
2873 static const GMarkupParser icon_source_parser =
2874   {
2875     icon_source_start_element,
2876   };
2877
2878 static gboolean
2879 gtk_icon_factory_buildable_custom_tag_start (GtkBuildable     *buildable,
2880                                              GtkBuilder       *builder,
2881                                              GObject          *child,
2882                                              const gchar      *tagname,
2883                                              GMarkupParser    *parser,
2884                                              gpointer         *data)
2885 {
2886   g_assert (buildable);
2887
2888   if (strcmp (tagname, "sources") == 0)
2889     {
2890       IconFactoryParserData *parser_data;
2891
2892       parser_data = g_slice_new0 (IconFactoryParserData);
2893       *parser = icon_source_parser;
2894       *data = parser_data;
2895       return TRUE;
2896     }
2897   return FALSE;
2898 }
2899
2900 static void
2901 gtk_icon_factory_buildable_custom_tag_end (GtkBuildable *buildable,
2902                                            GtkBuilder   *builder,
2903                                            GObject      *child,
2904                                            const gchar  *tagname,
2905                                            gpointer     *user_data)
2906 {
2907   GtkIconFactory *icon_factory;
2908   
2909   icon_factory = GTK_ICON_FACTORY (buildable);
2910
2911   if (strcmp (tagname, "sources") == 0)
2912     {
2913       IconFactoryParserData *parser_data;
2914       GtkIconSource *icon_source;
2915       GtkIconSet *icon_set;
2916       GSList *l;
2917
2918       parser_data = (IconFactoryParserData*)user_data;
2919
2920       for (l = parser_data->sources; l; l = l->next)
2921         {
2922           IconSourceParserData *source_data = l->data;
2923
2924           icon_set = gtk_icon_factory_lookup (icon_factory, source_data->stock_id);
2925           if (!icon_set)
2926             {
2927               icon_set = gtk_icon_set_new ();
2928               gtk_icon_factory_add (icon_factory, source_data->stock_id, icon_set);
2929               gtk_icon_set_unref (icon_set);
2930             }
2931
2932           icon_source = gtk_icon_source_new ();
2933
2934           if (source_data->filename)
2935             {
2936               gchar *filename;
2937               filename = _gtk_builder_get_absolute_filename (builder, source_data->filename);
2938               gtk_icon_source_set_filename (icon_source, filename);
2939               g_free (filename);
2940             }
2941           if (source_data->icon_name)
2942             gtk_icon_source_set_icon_name (icon_source, source_data->icon_name);
2943           if (source_data->size != -1)
2944             {
2945               gtk_icon_source_set_size (icon_source, source_data->size);
2946               gtk_icon_source_set_size_wildcarded (icon_source, FALSE);
2947             }
2948           if (source_data->direction != -1)
2949             {
2950               gtk_icon_source_set_direction (icon_source, source_data->direction);
2951               gtk_icon_source_set_direction_wildcarded (icon_source, FALSE);
2952             }
2953           if (source_data->state != -1)
2954             {
2955               gtk_icon_source_set_state (icon_source, source_data->state);
2956               gtk_icon_source_set_state_wildcarded (icon_source, FALSE);
2957             }
2958
2959           /* Inline source_add() to avoid creating a copy */
2960           g_assert (icon_source->type != GTK_ICON_SOURCE_EMPTY);
2961           icon_set->sources = g_slist_insert_sorted (icon_set->sources,
2962                                                      icon_source,
2963                                                      icon_source_compare);
2964
2965           g_free (source_data->stock_id);
2966           g_free (source_data->filename);
2967           g_free (source_data->icon_name);
2968           g_slice_free (IconSourceParserData, source_data);
2969         }
2970       g_slist_free (parser_data->sources);
2971       g_slice_free (IconFactoryParserData, parser_data);
2972
2973       /* TODO: Add an attribute/tag to prevent this.
2974        * Usually it's the right thing to do though.
2975        */
2976       gtk_icon_factory_add_default (icon_factory);
2977     }
2978 }
2979
2980 #ifdef G_OS_WIN32
2981
2982 /* DLL ABI stability backward compatibility versions */
2983
2984 #undef gtk_icon_source_set_filename
2985
2986 void
2987 gtk_icon_source_set_filename (GtkIconSource *source,
2988                               const gchar   *filename)
2989 {
2990   gchar *utf8_filename = g_locale_to_utf8 (filename, -1, NULL, NULL, NULL);
2991
2992   gtk_icon_source_set_filename_utf8 (source, utf8_filename);
2993
2994   g_free (utf8_filename);
2995 }
2996
2997 #undef gtk_icon_source_get_filename
2998
2999 G_CONST_RETURN gchar*
3000 gtk_icon_source_get_filename (const GtkIconSource *source)
3001 {
3002   g_return_val_if_fail (source != NULL, NULL);
3003
3004   if (source->type == GTK_ICON_SOURCE_FILENAME)
3005     return source->cp_filename;
3006   else
3007     return NULL;
3008 }
3009
3010 #endif
3011
3012 #define __GTK_ICON_FACTORY_C__
3013 #include "gtkaliasdef.c"