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