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