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