]> Pileus Git - ~andy/gtk/blob - gtk/gtkiconfactory.c
Fixes #136082 and #135265, patch by Morten Welinder.
[~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->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
1742  * @widget: widget that will display the icon, or %NULL.
1743  *          The only use that is typically made of this
1744  *          is to determine the appropriate #GdkScreen.
1745  * @detail: detail to pass to the theme engine, or %NULL.
1746  *          Note that passing a detail of anything but %NULL
1747  *          will disable caching.
1748  * 
1749  * Renders an icon using gtk_style_render_icon(). In most cases,
1750  * gtk_widget_render_icon() is better, since it automatically provides
1751  * most of the arguments from the current widget settings.  This
1752  * function never returns %NULL; if the icon can't be rendered
1753  * (perhaps because an image file fails to load), a default "missing
1754  * image" icon will be returned instead.
1755  * 
1756  * Return value: a #GdkPixbuf to be displayed
1757  **/
1758 GdkPixbuf*
1759 gtk_icon_set_render_icon (GtkIconSet        *icon_set,
1760                           GtkStyle          *style,
1761                           GtkTextDirection   direction,
1762                           GtkStateType       state,
1763                           GtkIconSize        size,
1764                           GtkWidget         *widget,
1765                           const char        *detail)
1766 {
1767   GdkPixbuf *icon;
1768   
1769   g_return_val_if_fail (icon_set != NULL, NULL);
1770   g_return_val_if_fail (GTK_IS_STYLE (style), NULL);
1771
1772   if (icon_set->sources == NULL)
1773     return render_fallback_image (style, direction, state, size, widget, detail);
1774
1775   if (detail == NULL)
1776     {
1777       icon = find_in_cache (icon_set, style, direction,
1778                         state, size);
1779       
1780       if (icon)
1781         {
1782           g_object_ref (icon);
1783           return icon;
1784         }
1785     }
1786
1787
1788   icon = find_and_render_icon_source (icon_set, style, direction, state, size,
1789                                       widget, detail);
1790
1791   if (icon == NULL)
1792     icon = render_fallback_image (style, direction, state, size, widget, detail);
1793
1794   if (detail == NULL)
1795     add_to_cache (icon_set, style, direction, state, size, icon);
1796   
1797   return icon;
1798 }
1799
1800 /* Order sources by their "wildness", so that "wilder" sources are
1801  * greater than "specific" sources; for determining ordering,
1802  * direction beats state beats size.
1803  */
1804
1805 static int
1806 icon_source_compare (gconstpointer ap, gconstpointer bp)
1807 {
1808   const GtkIconSource *a = ap;
1809   const GtkIconSource *b = bp;
1810
1811   if (!a->any_direction && b->any_direction)
1812     return -1;
1813   else if (a->any_direction && !b->any_direction)
1814     return 1;
1815   else if (!a->any_state && b->any_state)
1816     return -1;
1817   else if (a->any_state && !b->any_state)
1818     return 1;
1819   else if (!a->any_size && b->any_size)
1820     return -1;
1821   else if (a->any_size && !b->any_size)
1822     return 1;
1823   else
1824     return 0;
1825 }
1826
1827 /**
1828  * gtk_icon_set_add_source:
1829  * @icon_set: a #GtkIconSet
1830  * @source: a #GtkIconSource
1831  *
1832  * Icon sets have a list of #GtkIconSource, which they use as base
1833  * icons for rendering icons in different states and sizes. Icons are
1834  * scaled, made to look insensitive, etc. in
1835  * gtk_icon_set_render_icon(), but #GtkIconSet needs base images to
1836  * work with. The base images and when to use them are described by
1837  * a #GtkIconSource.
1838  * 
1839  * This function copies @source, so you can reuse the same source immediately
1840  * without affecting the icon set.
1841  *
1842  * An example of when you'd use this function: a web browser's "Back
1843  * to Previous Page" icon might point in a different direction in
1844  * Hebrew and in English; it might look different when insensitive;
1845  * and it might change size depending on toolbar mode (small/large
1846  * icons). So a single icon set would contain all those variants of
1847  * the icon, and you might add a separate source for each one.
1848  *
1849  * You should nearly always add a "default" icon source with all
1850  * fields wildcarded, which will be used as a fallback if no more
1851  * specific source matches. #GtkIconSet always prefers more specific
1852  * icon sources to more generic icon sources. The order in which you
1853  * add the sources to the icon set does not matter.
1854  *
1855  * gtk_icon_set_new_from_pixbuf() creates a new icon set with a
1856  * default icon source based on the given pixbuf.
1857  * 
1858  **/
1859 void
1860 gtk_icon_set_add_source (GtkIconSet *icon_set,
1861                          const GtkIconSource *source)
1862 {
1863   g_return_if_fail (icon_set != NULL);
1864   g_return_if_fail (source != NULL);
1865
1866   if (source->type == GTK_ICON_SOURCE_EMPTY)
1867     {
1868       g_warning ("Useless empty GtkIconSource");
1869       return;
1870     }
1871   
1872   icon_set->sources = g_slist_insert_sorted (icon_set->sources,
1873                                              gtk_icon_source_copy (source),
1874                                              icon_source_compare);
1875 }
1876
1877 /**
1878  * gtk_icon_set_get_sizes:
1879  * @icon_set: a #GtkIconSet
1880  * @sizes: return location for array of sizes
1881  * @n_sizes: location to store number of elements in returned array
1882  *
1883  * Obtains a list of icon sizes this icon set can render. The returned
1884  * array must be freed with g_free().
1885  * 
1886  **/
1887 void
1888 gtk_icon_set_get_sizes (GtkIconSet   *icon_set,
1889                         GtkIconSize **sizes,
1890                         gint         *n_sizes)
1891 {
1892   GSList *tmp_list;
1893   gboolean all_sizes = FALSE;
1894   GSList *specifics = NULL;
1895   
1896   g_return_if_fail (icon_set != NULL);
1897   g_return_if_fail (sizes != NULL);
1898   g_return_if_fail (n_sizes != NULL);
1899   
1900   tmp_list = icon_set->sources;
1901   while (tmp_list != NULL)
1902     {
1903       GtkIconSource *source;
1904
1905       source = tmp_list->data;
1906
1907       if (source->any_size)
1908         {
1909           all_sizes = TRUE;
1910           break;
1911         }
1912       else
1913         specifics = g_slist_prepend (specifics, GINT_TO_POINTER (source->size));
1914       
1915       tmp_list = g_slist_next (tmp_list);
1916     }
1917
1918   if (all_sizes)
1919     {
1920       /* Need to find out what sizes exist */
1921       gint i;
1922
1923       init_icon_sizes ();
1924       
1925       *sizes = g_new (GtkIconSize, icon_sizes_used);
1926       *n_sizes = icon_sizes_used - 1;
1927       
1928       i = 1;      
1929       while (i < icon_sizes_used)
1930         {
1931           (*sizes)[i - 1] = icon_sizes[i].size;
1932           ++i;
1933         }
1934     }
1935   else
1936     {
1937       gint i;
1938       
1939       *n_sizes = g_slist_length (specifics);
1940       *sizes = g_new (GtkIconSize, *n_sizes);
1941
1942       i = 0;
1943       tmp_list = specifics;
1944       while (tmp_list != NULL)
1945         {
1946           (*sizes)[i] = GPOINTER_TO_INT (tmp_list->data);
1947
1948           ++i;
1949           tmp_list = g_slist_next (tmp_list);
1950         }
1951     }
1952
1953   g_slist_free (specifics);
1954 }
1955
1956
1957 /**
1958  * gtk_icon_source_new:
1959  * 
1960  * Creates a new #GtkIconSource. A #GtkIconSource contains a #GdkPixbuf (or
1961  * image filename) that serves as the base image for one or more of the
1962  * icons in a #GtkIconSet, along with a specification for which icons in the
1963  * icon set will be based on that pixbuf or image file. An icon set contains
1964  * a set of icons that represent "the same" logical concept in different states,
1965  * different global text directions, and different sizes.
1966  * 
1967  * So for example a web browser's "Back to Previous Page" icon might
1968  * point in a different direction in Hebrew and in English; it might
1969  * look different when insensitive; and it might change size depending
1970  * on toolbar mode (small/large icons). So a single icon set would
1971  * contain all those variants of the icon. #GtkIconSet contains a list
1972  * of #GtkIconSource from which it can derive specific icon variants in
1973  * the set. 
1974  *
1975  * In the simplest case, #GtkIconSet contains one source pixbuf from
1976  * which it derives all variants. The convenience function
1977  * gtk_icon_set_new_from_pixbuf() handles this case; if you only have
1978  * one source pixbuf, just use that function.
1979  *
1980  * If you want to use a different base pixbuf for different icon
1981  * variants, you create multiple icon sources, mark which variants
1982  * they'll be used to create, and add them to the icon set with
1983  * gtk_icon_set_add_source().
1984  *
1985  * By default, the icon source has all parameters wildcarded. That is,
1986  * the icon source will be used as the base icon for any desired text
1987  * direction, widget state, or icon size.
1988  * 
1989  * Return value: a new #GtkIconSource
1990  **/
1991 GtkIconSource*
1992 gtk_icon_source_new (void)
1993 {
1994   GtkIconSource *src;
1995   
1996   src = g_new0 (GtkIconSource, 1);
1997
1998   src->direction = GTK_TEXT_DIR_NONE;
1999   src->size = GTK_ICON_SIZE_INVALID;
2000   src->state = GTK_STATE_NORMAL;
2001   
2002   src->any_direction = TRUE;
2003   src->any_state = TRUE;
2004   src->any_size = TRUE;
2005   
2006   return src;
2007 }
2008
2009 /**
2010  * gtk_icon_source_copy:
2011  * @source: a #GtkIconSource
2012  * 
2013  * Creates a copy of @source; mostly useful for language bindings.
2014  * 
2015  * Return value: a new #GtkIconSource
2016  **/
2017 GtkIconSource*
2018 gtk_icon_source_copy (const GtkIconSource *source)
2019 {
2020   GtkIconSource *copy;
2021   
2022   g_return_val_if_fail (source != NULL, NULL);
2023
2024   copy = g_new (GtkIconSource, 1);
2025
2026   *copy = *source;
2027   
2028   switch (copy->type)
2029     {
2030     case GTK_ICON_SOURCE_EMPTY:
2031       break;
2032     case GTK_ICON_SOURCE_ICON_NAME:
2033       copy->source.icon_name = g_strdup (copy->source.icon_name);
2034       break;
2035     case GTK_ICON_SOURCE_FILENAME:
2036       copy->source.filename = g_strdup (copy->source.filename);
2037       if (copy->filename_pixbuf)
2038         g_object_ref (copy->filename_pixbuf);
2039       break;
2040     case GTK_ICON_SOURCE_PIXBUF:
2041       g_object_ref (copy->source.pixbuf);
2042       break;
2043     default:
2044       g_assert_not_reached();
2045     }
2046
2047   return copy;
2048 }
2049
2050 /**
2051  * gtk_icon_source_free:
2052  * @source: a #GtkIconSource
2053  * 
2054  * Frees a dynamically-allocated icon source, along with its
2055  * filename, size, and pixbuf fields if those are not %NULL.
2056  **/
2057 void
2058 gtk_icon_source_free (GtkIconSource *source)
2059 {
2060   g_return_if_fail (source != NULL);
2061
2062   icon_source_clear (source);
2063   g_free (source);
2064 }
2065
2066 GType
2067 gtk_icon_source_get_type (void)
2068 {
2069   static GType our_type = 0;
2070   
2071   if (our_type == 0)
2072     our_type = g_boxed_type_register_static ("GtkIconSource",
2073                                              (GBoxedCopyFunc) gtk_icon_source_copy,
2074                                              (GBoxedFreeFunc) gtk_icon_source_free);
2075
2076   return our_type;
2077 }
2078
2079 static void
2080 icon_source_clear (GtkIconSource *source)
2081 {
2082   switch (source->type)
2083     {
2084     case GTK_ICON_SOURCE_EMPTY:
2085       break;
2086     case GTK_ICON_SOURCE_ICON_NAME:
2087       g_free (source->source.icon_name);
2088       source->source.icon_name = NULL;
2089       break;
2090     case GTK_ICON_SOURCE_FILENAME:
2091       g_free (source->source.filename);
2092       source->source.filename = NULL;
2093       g_free (source->filename_pixbuf);
2094       source->filename_pixbuf = NULL;
2095       break;
2096     case GTK_ICON_SOURCE_PIXBUF:
2097       g_object_unref (source->source.pixbuf);
2098       source->source.pixbuf = NULL;
2099       break;
2100     default:
2101       g_assert_not_reached();
2102     }
2103
2104   source->type = GTK_ICON_SOURCE_EMPTY;
2105 }
2106
2107 /**
2108  * gtk_icon_source_set_filename:
2109  * @source: a #GtkIconSource
2110  * @filename: image file to use
2111  *
2112  * Sets the name of an image file to use as a base image when creating
2113  * icon variants for #GtkIconSet. The filename must be absolute. 
2114  **/
2115 void
2116 gtk_icon_source_set_filename (GtkIconSource *source,
2117                               const gchar   *filename)
2118 {
2119   g_return_if_fail (source != NULL);
2120   g_return_if_fail (filename == NULL || g_path_is_absolute (filename));
2121
2122   if (source->type == GTK_ICON_SOURCE_FILENAME &&
2123       source->source.filename == filename)
2124     return;
2125   
2126   icon_source_clear (source);
2127   
2128   if (filename != NULL)
2129     {
2130       source->type = GTK_ICON_SOURCE_FILENAME;
2131       source->source.filename = g_strdup (filename);
2132     }
2133 }
2134
2135 /**
2136  * gtk_icon_source_set_icon_name
2137  * @source: a #GtkIconSource
2138  * @icon_name: name of icon to use
2139  *
2140  * Sets the name of an icon to look up in the current icon theme
2141  * to use as a base image when creating icon variants for #GtkIconSet.
2142  **/
2143 void
2144 gtk_icon_source_set_icon_name (GtkIconSource *source,
2145                                const gchar   *icon_name)
2146 {
2147   g_return_if_fail (source != NULL);
2148
2149   if (source->type == GTK_ICON_SOURCE_ICON_NAME &&
2150       source->source.icon_name == icon_name)
2151     return;
2152
2153   icon_source_clear (source);
2154   
2155   if (icon_name != NULL)
2156     {
2157       source->type = GTK_ICON_SOURCE_ICON_NAME;
2158       source->source.icon_name = g_strdup (icon_name);
2159     }
2160 }
2161
2162 /**
2163  * gtk_icon_source_set_pixbuf:
2164  * @source: a #GtkIconSource
2165  * @pixbuf: pixbuf to use as a source
2166  *
2167  * Sets a pixbuf to use as a base image when creating icon variants
2168  * for #GtkIconSet.
2169  **/
2170 void
2171 gtk_icon_source_set_pixbuf (GtkIconSource *source,
2172                             GdkPixbuf     *pixbuf)
2173 {
2174   g_return_if_fail (source != NULL);
2175   g_return_if_fail (pixbuf == NULL || GDK_IS_PIXBUF (pixbuf));
2176   
2177   if (source->type == GTK_ICON_SOURCE_PIXBUF &&
2178       source->source.pixbuf == pixbuf)
2179     return;
2180
2181   icon_source_clear (source);
2182   
2183   if (pixbuf != NULL)
2184     {
2185       source->type = GTK_ICON_SOURCE_PIXBUF;
2186       source->source.pixbuf = g_object_ref (pixbuf);
2187     }
2188 }
2189
2190 /**
2191  * gtk_icon_source_get_filename:
2192  * @source: a #GtkIconSource
2193  * 
2194  * Retrieves the source filename, or %NULL if none is set. The
2195  * filename is not a copy, and should not be modified or expected to
2196  * persist beyond the lifetime of the icon source.
2197  * 
2198  * Return value: image filename. This string must not be modified
2199  * or freed.
2200  **/
2201 G_CONST_RETURN gchar*
2202 gtk_icon_source_get_filename (const GtkIconSource *source)
2203 {
2204   g_return_val_if_fail (source != NULL, NULL);
2205
2206   if (source->type == GTK_ICON_SOURCE_FILENAME)
2207     return source->source.filename;
2208   else
2209     return NULL;
2210 }
2211
2212 /**
2213  * gtk_icon_source_get_icon_name:
2214  * @source: a #GtkIconSource
2215  * 
2216  * Retrieves the source icon name, or %NULL if none is set. The
2217  * icon_name is not a copy, and should not be modified or expected to
2218  * persist beyond the lifetime of the icon source.
2219  * 
2220  * Return value: icon name. This string must not be modified or freed.
2221  **/
2222 G_CONST_RETURN gchar*
2223 gtk_icon_source_get_icon_name (const GtkIconSource *source)
2224 {
2225   g_return_val_if_fail (source != NULL, NULL);
2226
2227   if (source->type == GTK_ICON_SOURCE_ICON_NAME)
2228     return source->source.icon_name;
2229   else
2230     return NULL;
2231 }
2232
2233 /**
2234  * gtk_icon_source_get_pixbuf:
2235  * @source: a #GtkIconSource
2236  * 
2237  * Retrieves the source pixbuf, or %NULL if none is set.
2238  * In addition, if a filename source is in use, this
2239  * function in some cases will return the pixbuf from
2240  * loaded from the filename. This is, for example, true
2241  * for the GtkIconSource passed to the GtkStyle::render_icon()
2242  * virtual function. The reference count on the pixbuf is
2243  * not incremented.
2244  * 
2245  * Return value: source pixbuf
2246  **/
2247 GdkPixbuf*
2248 gtk_icon_source_get_pixbuf (const GtkIconSource *source)
2249 {
2250   g_return_val_if_fail (source != NULL, NULL);
2251   
2252   if (source->type == GTK_ICON_SOURCE_PIXBUF)
2253     return source->source.pixbuf;
2254   else if (source->type == GTK_ICON_SOURCE_FILENAME)
2255     return source->filename_pixbuf;
2256   else
2257     return NULL;
2258 }
2259
2260 /**
2261  * gtk_icon_source_set_direction_wildcarded:
2262  * @source: a #GtkIconSource
2263  * @setting: %TRUE to wildcard the text direction
2264  *
2265  * If the text direction is wildcarded, this source can be used
2266  * as the base image for an icon in any #GtkTextDirection.
2267  * If the text direction is not wildcarded, then the
2268  * text direction the icon source applies to should be set
2269  * with gtk_icon_source_set_direction(), and the icon source
2270  * will only be used with that text direction.
2271  *
2272  * #GtkIconSet prefers non-wildcarded sources (exact matches) over
2273  * wildcarded sources, and will use an exact match when possible.
2274  * 
2275  **/
2276 void
2277 gtk_icon_source_set_direction_wildcarded (GtkIconSource *source,
2278                                           gboolean       setting)
2279 {
2280   g_return_if_fail (source != NULL);
2281
2282   source->any_direction = setting != FALSE;
2283 }
2284
2285 /**
2286  * gtk_icon_source_set_state_wildcarded:
2287  * @source: a #GtkIconSource
2288  * @setting: %TRUE to wildcard the widget state
2289  *
2290  * If the widget state is wildcarded, this source can be used as the
2291  * base image for an icon in any #GtkStateType.  If the widget state
2292  * is not wildcarded, then the state the source applies to should be
2293  * set with gtk_icon_source_set_state() and the icon source will
2294  * only be used with that specific state.
2295  *
2296  * #GtkIconSet prefers non-wildcarded sources (exact matches) over
2297  * wildcarded sources, and will use an exact match when possible.
2298  *
2299  * #GtkIconSet will normally transform wildcarded source images to
2300  * produce an appropriate icon for a given state, for example
2301  * lightening an image on prelight, but will not modify source images
2302  * that match exactly.
2303  **/
2304 void
2305 gtk_icon_source_set_state_wildcarded (GtkIconSource *source,
2306                                       gboolean       setting)
2307 {
2308   g_return_if_fail (source != NULL);
2309
2310   source->any_state = setting != FALSE;
2311 }
2312
2313
2314 /**
2315  * gtk_icon_source_set_size_wildcarded:
2316  * @source: a #GtkIconSource
2317  * @setting: %TRUE to wildcard the widget state
2318  *
2319  * If the icon size is wildcarded, this source can be used as the base
2320  * image for an icon of any size.  If the size is not wildcarded, then
2321  * the size the source applies to should be set with
2322  * gtk_icon_source_set_size() and the icon source will only be used
2323  * with that specific size.
2324  *
2325  * #GtkIconSet prefers non-wildcarded sources (exact matches) over
2326  * wildcarded sources, and will use an exact match when possible.
2327  *
2328  * #GtkIconSet will normally scale wildcarded source images to produce
2329  * an appropriate icon at a given size, but will not change the size
2330  * of source images that match exactly.
2331  **/
2332 void
2333 gtk_icon_source_set_size_wildcarded (GtkIconSource *source,
2334                                      gboolean       setting)
2335 {
2336   g_return_if_fail (source != NULL);
2337
2338   source->any_size = setting != FALSE;  
2339 }
2340
2341 /**
2342  * gtk_icon_source_get_size_wildcarded:
2343  * @source: a #GtkIconSource
2344  * 
2345  * Gets the value set by gtk_icon_source_set_size_wildcarded().
2346  * 
2347  * Return value: %TRUE if this icon source is a base for any icon size variant
2348  **/
2349 gboolean
2350 gtk_icon_source_get_size_wildcarded (const GtkIconSource *source)
2351 {
2352   g_return_val_if_fail (source != NULL, TRUE);
2353   
2354   return source->any_size;
2355 }
2356
2357 /**
2358  * gtk_icon_source_get_state_wildcarded:
2359  * @source: a #GtkIconSource
2360  * 
2361  * Gets the value set by gtk_icon_source_set_state_wildcarded().
2362  * 
2363  * Return value: %TRUE if this icon source is a base for any widget state variant
2364  **/
2365 gboolean
2366 gtk_icon_source_get_state_wildcarded (const GtkIconSource *source)
2367 {
2368   g_return_val_if_fail (source != NULL, TRUE);
2369
2370   return source->any_state;
2371 }
2372
2373 /**
2374  * gtk_icon_source_get_direction_wildcarded:
2375  * @source: a #GtkIconSource
2376  * 
2377  * Gets the value set by gtk_icon_source_set_direction_wildcarded().
2378  * 
2379  * Return value: %TRUE if this icon source is a base for any text direction variant
2380  **/
2381 gboolean
2382 gtk_icon_source_get_direction_wildcarded (const GtkIconSource *source)
2383 {
2384   g_return_val_if_fail (source != NULL, TRUE);
2385
2386   return source->any_direction;
2387 }
2388
2389 /**
2390  * gtk_icon_source_set_direction:
2391  * @source: a #GtkIconSource
2392  * @direction: text direction this source applies to
2393  *
2394  * Sets the text direction this icon source is intended to be used
2395  * with.
2396  * 
2397  * Setting the text direction on an icon source makes no difference
2398  * if the text direction is wildcarded. Therefore, you should usually
2399  * call gtk_icon_source_set_direction_wildcarded() to un-wildcard it
2400  * in addition to calling this function.
2401  * 
2402  **/
2403 void
2404 gtk_icon_source_set_direction (GtkIconSource   *source,
2405                                GtkTextDirection direction)
2406 {
2407   g_return_if_fail (source != NULL);
2408
2409   source->direction = direction;
2410 }
2411
2412 /**
2413  * gtk_icon_source_set_state:
2414  * @source: a #GtkIconSource
2415  * @state: widget state this source applies to
2416  *
2417  * Sets the widget state this icon source is intended to be used
2418  * with.
2419  * 
2420  * Setting the widget state on an icon source makes no difference
2421  * if the state is wildcarded. Therefore, you should usually
2422  * call gtk_icon_source_set_state_wildcarded() to un-wildcard it
2423  * in addition to calling this function.
2424  * 
2425  **/
2426 void
2427 gtk_icon_source_set_state (GtkIconSource *source,
2428                            GtkStateType   state)
2429 {
2430   g_return_if_fail (source != NULL);
2431
2432   source->state = state;
2433 }
2434
2435 /**
2436  * gtk_icon_source_set_size:
2437  * @source: a #GtkIconSource
2438  * @size: icon size this source applies to
2439  *
2440  * Sets the icon size this icon source is intended to be used
2441  * with.
2442  * 
2443  * Setting the icon size on an icon source makes no difference
2444  * if the size is wildcarded. Therefore, you should usually
2445  * call gtk_icon_source_set_size_wildcarded() to un-wildcard it
2446  * in addition to calling this function.
2447  * 
2448  **/
2449 void
2450 gtk_icon_source_set_size (GtkIconSource *source,
2451                           GtkIconSize    size)
2452 {
2453   g_return_if_fail (source != NULL);
2454
2455   source->size = size;
2456 }
2457
2458 /**
2459  * gtk_icon_source_get_direction:
2460  * @source: a #GtkIconSource
2461  * 
2462  * Obtains the text direction this icon source applies to. The return
2463  * value is only useful/meaningful if the text direction is <emphasis>not</emphasis> 
2464  * wildcarded.
2465  * 
2466  * Return value: text direction this source matches
2467  **/
2468 GtkTextDirection
2469 gtk_icon_source_get_direction (const GtkIconSource *source)
2470 {
2471   g_return_val_if_fail (source != NULL, 0);
2472
2473   return source->direction;
2474 }
2475
2476 /**
2477  * gtk_icon_source_get_state:
2478  * @source: a #GtkIconSource
2479  * 
2480  * Obtains the widget state this icon source applies to. The return
2481  * value is only useful/meaningful if the widget state is <emphasis>not</emphasis>
2482  * wildcarded.
2483  * 
2484  * Return value: widget state this source matches
2485  **/
2486 GtkStateType
2487 gtk_icon_source_get_state (const GtkIconSource *source)
2488 {
2489   g_return_val_if_fail (source != NULL, 0);
2490
2491   return source->state;
2492 }
2493
2494 /**
2495  * gtk_icon_source_get_size:
2496  * @source: a #GtkIconSource
2497  * 
2498  * Obtains the icon size this source applies to. The return value
2499  * is only useful/meaningful if the icon size is <emphasis>not</emphasis> wildcarded.
2500  * 
2501  * Return value: icon size this source matches.
2502  **/
2503 GtkIconSize
2504 gtk_icon_source_get_size (const GtkIconSource *source)
2505 {
2506   g_return_val_if_fail (source != NULL, 0);
2507
2508   return source->size;
2509 }
2510
2511 #define NUM_CACHED_ICONS 8
2512
2513 typedef struct _CachedIcon CachedIcon;
2514
2515 struct _CachedIcon
2516 {
2517   /* These must all match to use the cached pixbuf.
2518    * If any don't match, we must re-render the pixbuf.
2519    */
2520   GtkStyle *style;
2521   GtkTextDirection direction;
2522   GtkStateType state;
2523   GtkIconSize size;
2524
2525   GdkPixbuf *pixbuf;
2526 };
2527
2528 static void
2529 ensure_cache_up_to_date (GtkIconSet *icon_set)
2530 {
2531   if (icon_set->cache_serial != cache_serial)
2532     {
2533       clear_cache (icon_set, TRUE);
2534       icon_set->cache_serial = cache_serial;
2535     }
2536 }
2537
2538 static void
2539 cached_icon_free (CachedIcon *icon)
2540 {
2541   g_object_unref (icon->pixbuf);
2542
2543   if (icon->style)
2544     g_object_unref (icon->style);
2545
2546   g_free (icon);
2547 }
2548
2549 static GdkPixbuf *
2550 find_in_cache (GtkIconSet      *icon_set,
2551                GtkStyle        *style,
2552                GtkTextDirection direction,
2553                GtkStateType     state,
2554                GtkIconSize      size)
2555 {
2556   GSList *tmp_list;
2557   GSList *prev;
2558
2559   ensure_cache_up_to_date (icon_set);
2560   
2561   prev = NULL;
2562   tmp_list = icon_set->cache;
2563   while (tmp_list != NULL)
2564     {
2565       CachedIcon *icon = tmp_list->data;
2566
2567       if (icon->style == style &&
2568           icon->direction == direction &&
2569           icon->state == state &&
2570           icon->size == size)
2571         {
2572           if (prev)
2573             {
2574               /* Move this icon to the front of the list. */
2575               prev->next = tmp_list->next;
2576               tmp_list->next = icon_set->cache;
2577               icon_set->cache = tmp_list;
2578             }
2579           
2580           return icon->pixbuf;
2581         }
2582           
2583       prev = tmp_list;
2584       tmp_list = g_slist_next (tmp_list);
2585     }
2586
2587   return NULL;
2588 }
2589
2590 static void
2591 add_to_cache (GtkIconSet      *icon_set,
2592               GtkStyle        *style,
2593               GtkTextDirection direction,
2594               GtkStateType     state,
2595               GtkIconSize      size,
2596               GdkPixbuf       *pixbuf)
2597 {
2598   CachedIcon *icon;
2599
2600   ensure_cache_up_to_date (icon_set);
2601   
2602   g_object_ref (pixbuf);
2603
2604   /* We have to ref the style, since if the style was finalized
2605    * its address could be reused by another style, creating a
2606    * really weird bug
2607    */
2608   
2609   if (style)
2610     g_object_ref (style);
2611   
2612
2613   icon = g_new (CachedIcon, 1);
2614   icon_set->cache = g_slist_prepend (icon_set->cache, icon);
2615
2616   icon->style = style;
2617   icon->direction = direction;
2618   icon->state = state;
2619   icon->size = size;
2620   icon->pixbuf = pixbuf;
2621
2622   if (icon->style)
2623     attach_to_style (icon_set, icon->style);
2624   
2625   if (icon_set->cache_size >= NUM_CACHED_ICONS)
2626     {
2627       /* Remove oldest item in the cache */
2628       
2629       GSList *tmp_list;
2630       
2631       tmp_list = icon_set->cache;
2632
2633       /* Find next-to-last link */
2634       g_assert (NUM_CACHED_ICONS > 2);
2635       while (tmp_list->next->next)
2636         tmp_list = tmp_list->next;
2637
2638       g_assert (tmp_list != NULL);
2639       g_assert (tmp_list->next != NULL);
2640       g_assert (tmp_list->next->next == NULL);
2641
2642       /* Free the last icon */
2643       icon = tmp_list->next->data;
2644
2645       g_slist_free (tmp_list->next);
2646       tmp_list->next = NULL;
2647
2648       cached_icon_free (icon);
2649     }
2650 }
2651
2652 static void
2653 clear_cache (GtkIconSet *icon_set,
2654              gboolean    style_detach)
2655 {
2656   GSList *tmp_list;
2657   GtkStyle *last_style = NULL;
2658
2659   tmp_list = icon_set->cache;
2660   while (tmp_list != NULL)
2661     {
2662       CachedIcon *icon = tmp_list->data;
2663
2664       if (style_detach)
2665         {
2666           /* simple optimization for the case where the cache
2667            * contains contiguous icons from the same style.
2668            * it's safe to call detach_from_style more than
2669            * once on the same style though.
2670            */
2671           if (last_style != icon->style)
2672             {
2673               detach_from_style (icon_set, icon->style);
2674               last_style = icon->style;
2675             }
2676         }
2677       
2678       cached_icon_free (icon);      
2679       
2680       tmp_list = g_slist_next (tmp_list);
2681     }
2682
2683   g_slist_free (icon_set->cache);
2684   icon_set->cache = NULL;
2685   icon_set->cache_size = 0;
2686 }
2687
2688 static GSList*
2689 copy_cache (GtkIconSet *icon_set,
2690             GtkIconSet *copy_recipient)
2691 {
2692   GSList *tmp_list;
2693   GSList *copy = NULL;
2694
2695   ensure_cache_up_to_date (icon_set);
2696   
2697   tmp_list = icon_set->cache;
2698   while (tmp_list != NULL)
2699     {
2700       CachedIcon *icon = tmp_list->data;
2701       CachedIcon *icon_copy = g_new (CachedIcon, 1);
2702
2703       *icon_copy = *icon;
2704
2705       if (icon_copy->style)
2706         {
2707           attach_to_style (copy_recipient, icon_copy->style);
2708           g_object_ref (icon_copy->style);
2709         }
2710         
2711       g_object_ref (icon_copy->pixbuf);
2712
2713       icon_copy->size = icon->size;
2714       
2715       copy = g_slist_prepend (copy, icon_copy);      
2716       
2717       tmp_list = g_slist_next (tmp_list);
2718     }
2719
2720   return g_slist_reverse (copy);
2721 }
2722
2723 static void
2724 attach_to_style (GtkIconSet *icon_set,
2725                  GtkStyle   *style)
2726 {
2727   GHashTable *table;
2728
2729   table = g_object_get_qdata (G_OBJECT (style),
2730                               g_quark_try_string ("gtk-style-icon-sets"));
2731
2732   if (table == NULL)
2733     {
2734       table = g_hash_table_new (NULL, NULL);
2735       g_object_set_qdata_full (G_OBJECT (style),
2736                                g_quark_from_static_string ("gtk-style-icon-sets"),
2737                                table,
2738                                style_dnotify);
2739     }
2740
2741   g_hash_table_insert (table, icon_set, icon_set);
2742 }
2743
2744 static void
2745 detach_from_style (GtkIconSet *icon_set,
2746                    GtkStyle   *style)
2747 {
2748   GHashTable *table;
2749
2750   table = g_object_get_qdata (G_OBJECT (style),
2751                               g_quark_try_string ("gtk-style-icon-sets"));
2752
2753   if (table != NULL)
2754     g_hash_table_remove (table, icon_set);
2755 }
2756
2757 static void
2758 iconsets_foreach (gpointer key,
2759                   gpointer value,
2760                   gpointer user_data)
2761 {
2762   GtkIconSet *icon_set = key;
2763
2764   /* We only need to remove cache entries for the given style;
2765    * but that complicates things because in destroy notify
2766    * we don't know which style got destroyed, and 95% of the
2767    * time all cache entries will have the same style,
2768    * so this is faster anyway.
2769    */
2770   
2771   clear_cache (icon_set, FALSE);
2772 }
2773
2774 static void
2775 style_dnotify (gpointer data)
2776 {
2777   GHashTable *table = data;
2778   
2779   g_hash_table_foreach (table, iconsets_foreach, NULL);
2780
2781   g_hash_table_destroy (table);
2782 }
2783
2784 /* This allows the icon set to detect that its cache is out of date. */
2785 void
2786 _gtk_icon_set_invalidate_caches (void)
2787 {
2788   ++cache_serial;
2789 }
2790
2791 static void
2792 listify_foreach (gpointer key, gpointer value, gpointer data)
2793 {
2794   GSList **list = data;
2795
2796   *list = g_slist_prepend (*list, key);
2797 }
2798
2799 static GSList *
2800 g_hash_table_get_keys (GHashTable *table)
2801 {
2802   GSList *list = NULL;
2803
2804   g_hash_table_foreach (table, listify_foreach, &list);
2805
2806   return list;
2807 }
2808
2809 /**
2810  * _gtk_icon_factory_list_ids:
2811  * 
2812  * Gets all known IDs stored in an existing icon factory.
2813  * The strings in the returned list aren't copied.
2814  * The list itself should be freed.
2815  * 
2816  * Return value: List of ids in icon factories
2817  **/
2818 GSList*
2819 _gtk_icon_factory_list_ids (void)
2820 {
2821   GSList *tmp_list;
2822   GSList *ids;
2823
2824   ids = NULL;
2825
2826   ensure_default_icons ();
2827   
2828   tmp_list = all_icon_factories;
2829   while (tmp_list != NULL)
2830     {
2831       GSList *these_ids;
2832       
2833       GtkIconFactory *factory = GTK_ICON_FACTORY (tmp_list->data);
2834
2835       these_ids = g_hash_table_get_keys (factory->icons);
2836       
2837       ids = g_slist_concat (ids, these_ids);
2838       
2839       tmp_list = g_slist_next (tmp_list);
2840     }
2841
2842   return ids;
2843 }