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