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