]> Pileus Git - ~andy/gtk/blob - gtk/gtkiconfactory.c
fix so that default icons are created if you call gtk_stock_list_ids()
[~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 "gtkiconfactory.h"
28 #include "stock-icons/gtkstockpixbufs.h"
29 #include "gtkstock.h"
30 #include "gtkintl.h"
31 #include <stdlib.h>
32 #include <errno.h>
33 #include <ctype.h>
34 #include <string.h>
35
36 static GSList *all_icon_factories = NULL;
37
38 struct _GtkIconSource
39 {
40   /* Either filename or pixbuf can be NULL. If both are non-NULL,
41    * the pixbuf is assumed to be the already-loaded contents of the
42    * file.
43    */
44   gchar *filename;
45   GdkPixbuf *pixbuf;
46
47   GtkTextDirection direction;
48   GtkStateType state;
49   GtkIconSize size;
50
51   /* If TRUE, then the parameter is wildcarded, and the above
52    * fields should be ignored. If FALSE, the parameter is
53    * specified, and the above fields should be valid.
54    */
55   guint any_direction : 1;
56   guint any_state : 1;
57   guint any_size : 1;
58 };
59
60 /* FIXME use a better icon for this */
61 #define MISSING_IMAGE_INLINE dialog_error
62
63 static gpointer parent_class = NULL;
64
65 static void gtk_icon_factory_init       (GtkIconFactory      *icon_factory);
66 static void gtk_icon_factory_class_init (GtkIconFactoryClass *klass);
67 static void gtk_icon_factory_finalize   (GObject             *object);
68 static void get_default_icons           (GtkIconFactory      *icon_factory);
69
70 GType
71 gtk_icon_factory_get_type (void)
72 {
73   static GType object_type = 0;
74
75   if (!object_type)
76     {
77       static const GTypeInfo object_info =
78       {
79         sizeof (GtkIconFactoryClass),
80         (GBaseInitFunc) NULL,
81         (GBaseFinalizeFunc) NULL,
82         (GClassInitFunc) gtk_icon_factory_class_init,
83         NULL,           /* class_finalize */
84         NULL,           /* class_data */
85         sizeof (GtkIconFactory),
86         0,              /* n_preallocs */
87         (GInstanceInitFunc) gtk_icon_factory_init,
88       };
89       
90       object_type = g_type_register_static (G_TYPE_OBJECT,
91                                             "GtkIconFactory",
92                                             &object_info, 0);
93     }
94   
95   return object_type;
96 }
97
98 static void
99 gtk_icon_factory_init (GtkIconFactory *factory)
100 {
101   factory->icons = g_hash_table_new (g_str_hash, g_str_equal);
102   all_icon_factories = g_slist_prepend (all_icon_factories, factory);
103 }
104
105 static void
106 gtk_icon_factory_class_init (GtkIconFactoryClass *klass)
107 {
108   GObjectClass *object_class = G_OBJECT_CLASS (klass);
109   
110   parent_class = g_type_class_peek_parent (klass);
111
112   object_class->finalize = gtk_icon_factory_finalize;
113 }
114
115 static void
116 free_icon_set (gpointer key, gpointer value, gpointer data)
117 {
118   g_free (key);
119   gtk_icon_set_unref (value);
120 }
121
122 static void
123 gtk_icon_factory_finalize (GObject *object)
124 {
125   GtkIconFactory *factory = GTK_ICON_FACTORY (object);
126
127   all_icon_factories = g_slist_remove (all_icon_factories, factory);
128   
129   g_hash_table_foreach (factory->icons, free_icon_set, NULL);
130   
131   g_hash_table_destroy (factory->icons);
132   
133   G_OBJECT_CLASS (parent_class)->finalize (object);
134 }
135
136 /**
137  * gtk_icon_factory_new:
138  *
139  * Creates a new #GtkIconFactory. An icon factory manages a collection
140  * of #GtkIconSet; a #GtkIconSet manages a set of variants of a
141  * particular icon (i.e. a #GtkIconSet contains variants for different
142  * sizes and widget states). Icons in an icon factory are named by a
143  * stock ID, which is a simple string identifying the icon. Each
144  * #GtkStyle has a list of #GtkIconFactory derived from the current
145  * theme; those icon factories are consulted first when searching for
146  * an icon. If the theme doesn't set a particular icon, GTK+ looks for
147  * the icon in a list of default icon factories, maintained by
148  * gtk_icon_factory_add_default() and
149  * gtk_icon_factory_remove_default(). Applications with icons should
150  * add a default icon factory with their icons, which will allow
151  * themes to override the icons for the application.
152  * 
153  * Return value: a new #GtkIconFactory
154  **/
155 GtkIconFactory*
156 gtk_icon_factory_new (void)
157 {
158   return GTK_ICON_FACTORY (g_object_new (GTK_TYPE_ICON_FACTORY, NULL));
159 }
160
161 /**
162  * gtk_icon_factory_add:
163  * @factory: a #GtkIconFactory
164  * @stock_id: icon name
165  * @icon_set: icon set
166  *
167  * Adds the given @icon_set to the icon factory, under the name
168  * @stock_id.  @stock_id should be namespaced for your application,
169  * e.g. "myapp-whatever-icon".  Normally applications create a
170  * #GtkIconFactory, then add it to the list of default factories with
171  * gtk_icon_factory_add_default(). Then they pass the @stock_id to
172  * widgets such as #GtkImage to display the icon. Themes can provide
173  * an icon with the same name (such as "myapp-whatever-icon") to
174  * override your application's default icons. If an icon already
175  * existed in @factory for @stock_id, it is unreferenced and replaced
176  * with the new @icon_set.
177  * 
178  **/
179 void
180 gtk_icon_factory_add (GtkIconFactory *factory,
181                       const gchar    *stock_id,
182                       GtkIconSet     *icon_set)
183 {
184   gpointer old_key = NULL;
185   gpointer old_value = NULL;
186
187   g_return_if_fail (GTK_IS_ICON_FACTORY (factory));
188   g_return_if_fail (stock_id != NULL);
189   g_return_if_fail (icon_set != NULL);  
190
191   g_hash_table_lookup_extended (factory->icons, stock_id,
192                                 &old_key, &old_value);
193
194   if (old_value == icon_set)
195     return;
196   
197   gtk_icon_set_ref (icon_set);
198
199   /* GHashTable key memory management is so fantastically broken. */
200   if (old_key)
201     g_hash_table_insert (factory->icons, old_key, icon_set);
202   else
203     g_hash_table_insert (factory->icons, g_strdup (stock_id), icon_set);
204
205   if (old_value)
206     gtk_icon_set_unref (old_value);
207 }
208
209 /**
210  * gtk_icon_factory_lookup:
211  * @factory: a #GtkIconFactory
212  * @stock_id: an icon name
213  * 
214  * Looks up @stock_id in the icon factory, returning an icon set
215  * if found, otherwise %NULL. For display to the user, you should
216  * use gtk_style_lookup_icon_set() on the #GtkStyle for the
217  * widget that will display the icon, instead of using this
218  * function directly, so that themes are taken into account.
219  * 
220  * Return value: icon set of @stock_id.
221  **/
222 GtkIconSet *
223 gtk_icon_factory_lookup (GtkIconFactory *factory,
224                          const gchar    *stock_id)
225 {
226   g_return_val_if_fail (GTK_IS_ICON_FACTORY (factory), NULL);
227   g_return_val_if_fail (stock_id != NULL, NULL);
228   
229   return g_hash_table_lookup (factory->icons, stock_id);
230 }
231
232 static GtkIconFactory *gtk_default_icons = NULL;
233 static GSList *default_factories = NULL;
234
235 /**
236  * gtk_icon_factory_add_default:
237  * @factory: a #GtkIconFactory
238  * 
239  * Adds an icon factory to the list of icon factories searched by
240  * gtk_style_lookup_icon_set(). This means that, for example,
241  * gtk_image_new_from_stock() will be able to find icons in @factory.
242  * There will normally be an icon factory added for each library or
243  * application that comes with icons. The default icon factories
244  * can be overridden by themes.
245  * 
246  **/
247 void
248 gtk_icon_factory_add_default (GtkIconFactory *factory)
249 {
250   g_return_if_fail (GTK_IS_ICON_FACTORY (factory));
251
252   g_object_ref (G_OBJECT (factory));
253   
254   default_factories = g_slist_prepend (default_factories, factory);
255 }
256
257 /**
258  * gtk_icon_factory_remove_default:
259  * @factory: a #GtkIconFactory previously added with gtk_icon_factory_add_default()
260  *
261  * Removes an icon factory from the list of default icon
262  * factories. Not normally used; you might use it for a library that
263  * can be unloaded or shut down.
264  * 
265  **/
266 void
267 gtk_icon_factory_remove_default (GtkIconFactory  *factory)
268 {
269   g_return_if_fail (GTK_IS_ICON_FACTORY (factory));
270
271   default_factories = g_slist_remove (default_factories, factory);
272
273   g_object_unref (G_OBJECT (factory));
274 }
275
276 static void
277 ensure_default_icons (void)
278 {
279   if (gtk_default_icons == NULL)
280     {
281       gtk_default_icons = gtk_icon_factory_new ();
282
283       get_default_icons (gtk_default_icons);
284     }
285 }
286
287 /**
288  * gtk_icon_factory_lookup_default:
289  * @stock_id: an icon name
290  *
291  * Looks for an icon in the list of default icon factories.  For
292  * display to the user, you should use gtk_style_lookup_icon_set() on
293  * the #GtkStyle for the widget that will display the icon, instead of
294  * using this function directly, so that themes are taken into
295  * account.
296  * 
297  * 
298  * Return value: a #GtkIconSet, or %NULL
299  **/
300 GtkIconSet *
301 gtk_icon_factory_lookup_default (const gchar *stock_id)
302 {
303   GSList *tmp_list;
304
305   g_return_val_if_fail (stock_id != NULL, NULL);
306   
307   tmp_list = default_factories;
308   while (tmp_list != NULL)
309     {
310       GtkIconSet *icon_set =
311         gtk_icon_factory_lookup (GTK_ICON_FACTORY (tmp_list->data),
312                                  stock_id);
313
314       if (icon_set)
315         return icon_set;
316
317       tmp_list = g_slist_next (tmp_list);
318     }
319
320   ensure_default_icons ();
321   
322   return gtk_icon_factory_lookup (gtk_default_icons, stock_id);
323 }
324
325 static GtkIconSet *
326 sized_icon_set_from_inline (const guchar *inline_data,
327                             GtkIconSize   size)
328 {
329   GtkIconSet *set;
330
331   GtkIconSource source = { NULL, NULL, 0, 0, 0,
332                            TRUE, TRUE, FALSE };
333
334   source.size = size;
335
336   set = gtk_icon_set_new ();
337
338   source.pixbuf = gdk_pixbuf_new_from_inline (inline_data, FALSE, -1, NULL);
339
340   g_assert (source.pixbuf);
341
342   gtk_icon_set_add_source (set, &source);
343
344   g_object_unref (G_OBJECT (source.pixbuf));
345   
346   return set;
347 }
348
349
350 static GtkIconSet *
351 sized_with_fallback_icon_set_from_inline (const guchar *fallback_data,
352                                           const guchar *inline_data,
353                                           GtkIconSize   size)
354 {
355   GtkIconSet *set;
356
357   GtkIconSource source = { NULL, NULL, 0, 0, 0,
358                            TRUE, TRUE, FALSE };
359
360   source.size = size;
361
362   set = gtk_icon_set_new ();
363
364   source.pixbuf = gdk_pixbuf_new_from_inline (inline_data, FALSE, -1, NULL);
365
366   g_assert (source.pixbuf);
367
368   gtk_icon_set_add_source (set, &source);
369
370   g_object_unref (G_OBJECT (source.pixbuf));
371   
372   source.any_size = TRUE;
373
374   source.pixbuf = gdk_pixbuf_new_from_inline (fallback_data, FALSE, -1, NULL);
375
376   g_assert (source.pixbuf);
377
378   gtk_icon_set_add_source (set, &source);
379
380   g_object_unref (G_OBJECT (source.pixbuf));  
381   
382   return set;
383 }
384
385 static GtkIconSet *
386 unsized_icon_set_from_inline (const guchar *inline_data)
387 {
388   GtkIconSet *set;
389
390   /* This icon can be used for any direction/state/size */
391   GtkIconSource source = { NULL, NULL, 0, 0, 0,
392                            TRUE, TRUE, TRUE };
393
394   set = gtk_icon_set_new ();
395
396   source.pixbuf = gdk_pixbuf_new_from_inline (inline_data, FALSE, -1, NULL);
397
398   g_assert (source.pixbuf);
399
400   gtk_icon_set_add_source (set, &source);
401
402   g_object_unref (G_OBJECT (source.pixbuf));
403   
404   return set;
405 }
406
407 static void
408 add_sized (GtkIconFactory *factory,
409            const guchar   *inline_data,
410            GtkIconSize     size,
411            const gchar    *stock_id)
412 {
413   GtkIconSet *set;
414   
415   set = sized_icon_set_from_inline (inline_data, size);
416   
417   gtk_icon_factory_add (factory, stock_id, set);
418
419   gtk_icon_set_unref (set);
420 }
421
422 static void
423 add_sized_with_fallback (GtkIconFactory *factory,
424                          const guchar   *fallback_data,
425                          const guchar   *inline_data,
426                          GtkIconSize     size,
427                          const gchar    *stock_id)
428 {
429   GtkIconSet *set;
430   
431   set = sized_with_fallback_icon_set_from_inline (fallback_data, inline_data, size);
432   
433   gtk_icon_factory_add (factory, stock_id, set);
434
435   gtk_icon_set_unref (set);
436 }
437
438 static void
439 add_unsized (GtkIconFactory *factory,
440              const guchar   *inline_data,
441              const gchar    *stock_id)
442 {
443   GtkIconSet *set;
444   
445   set = unsized_icon_set_from_inline (inline_data);
446   
447   gtk_icon_factory_add (factory, stock_id, set);
448
449   gtk_icon_set_unref (set);
450 }
451
452 static void
453 get_default_icons (GtkIconFactory *factory)
454 {
455   /* KEEP IN SYNC with gtkstock.c */
456
457   add_unsized (factory, MISSING_IMAGE_INLINE, GTK_STOCK_MISSING_IMAGE);
458   
459   add_sized (factory, dialog_error, GTK_ICON_SIZE_DIALOG, GTK_STOCK_DIALOG_ERROR);
460   add_sized (factory, dialog_info, GTK_ICON_SIZE_DIALOG, GTK_STOCK_DIALOG_INFO);
461   add_sized (factory, dialog_question, GTK_ICON_SIZE_DIALOG, GTK_STOCK_DIALOG_QUESTION);
462   add_sized (factory, dialog_warning, GTK_ICON_SIZE_DIALOG, GTK_STOCK_DIALOG_WARNING);
463   
464   /* Only have button sizes */
465   add_sized (factory, stock_button_apply, GTK_ICON_SIZE_BUTTON, GTK_STOCK_APPLY);
466   add_sized (factory, stock_button_cancel, GTK_ICON_SIZE_BUTTON, GTK_STOCK_CANCEL);
467   add_sized (factory, stock_button_no, GTK_ICON_SIZE_BUTTON, GTK_STOCK_NO);
468   add_sized (factory, stock_button_ok, GTK_ICON_SIZE_BUTTON, GTK_STOCK_OK);
469   add_sized (factory, stock_button_yes, GTK_ICON_SIZE_BUTTON, GTK_STOCK_YES);
470
471   /* Generic + button sizes */
472   add_sized_with_fallback (factory,
473                            stock_close,
474                            stock_button_close,
475                            GTK_ICON_SIZE_BUTTON,
476                            GTK_STOCK_CLOSE);
477
478   /* Generic + menu sizes */  
479
480   add_sized_with_fallback (factory,
481                            stock_print_preview,
482                            stock_menu_print_preview,
483                            GTK_ICON_SIZE_MENU,
484                            GTK_STOCK_PRINT_PREVIEW);
485
486   add_sized_with_fallback (factory,
487                            stock_sort_descending,
488                            stock_menu_sort_descending,
489                            GTK_ICON_SIZE_MENU,
490                            GTK_STOCK_SORT_DESCENDING);
491   
492   /* Generic size only */
493
494   add_unsized (factory, stock_add, GTK_STOCK_ADD);
495   add_unsized (factory, stock_align_center, GTK_STOCK_JUSTIFY_CENTER);
496   add_unsized (factory, stock_align_justify, GTK_STOCK_JUSTIFY_FILL);
497   add_unsized (factory, stock_align_left, GTK_STOCK_JUSTIFY_LEFT);
498   add_unsized (factory, stock_align_right, GTK_STOCK_JUSTIFY_RIGHT);
499   add_unsized (factory, stock_bottom, GTK_STOCK_GOTO_BOTTOM);  
500   add_unsized (factory, stock_cdrom, GTK_STOCK_CDROM);
501   add_unsized (factory, stock_clear, GTK_STOCK_CLEAR);
502   add_unsized (factory, stock_colorselector, GTK_STOCK_SELECT_COLOR);
503   add_unsized (factory, stock_convert, GTK_STOCK_CONVERT);
504   add_unsized (factory, stock_copy, GTK_STOCK_COPY);
505   add_unsized (factory, stock_cut, GTK_STOCK_CUT);
506   add_unsized (factory, stock_down_arrow, GTK_STOCK_GO_DOWN);
507   add_unsized (factory, stock_exec, GTK_STOCK_EXECUTE);
508   add_unsized (factory, stock_exit, GTK_STOCK_QUIT);
509   add_unsized (factory, stock_first, GTK_STOCK_GOTO_FIRST);
510   add_unsized (factory, stock_font, GTK_STOCK_SELECT_FONT);
511   add_unsized (factory, stock_help, GTK_STOCK_HELP);
512   add_unsized (factory, stock_home, GTK_STOCK_HOME);
513   add_unsized (factory, stock_index, GTK_STOCK_INDEX);
514   add_unsized (factory, stock_jump_to, GTK_STOCK_JUMP_TO);
515   add_unsized (factory, stock_last, GTK_STOCK_GOTO_LAST);
516   add_unsized (factory, stock_left_arrow, GTK_STOCK_GO_BACK);
517   add_unsized (factory, stock_new, GTK_STOCK_NEW);
518   add_unsized (factory, stock_open, GTK_STOCK_OPEN);
519   add_unsized (factory, stock_paste, GTK_STOCK_PASTE);
520   add_unsized (factory, stock_preferences, GTK_STOCK_PREFERENCES);
521   add_unsized (factory, stock_print, GTK_STOCK_PRINT);
522   add_unsized (factory, stock_properties, GTK_STOCK_PROPERTIES);
523   add_unsized (factory, stock_redo, GTK_STOCK_REDO);
524   add_unsized (factory, stock_refresh, GTK_STOCK_REFRESH);
525   add_unsized (factory, stock_remove, GTK_STOCK_REMOVE);
526   add_unsized (factory, stock_revert, GTK_STOCK_REVERT_TO_SAVED);
527   add_unsized (factory, stock_right_arrow, GTK_STOCK_GO_FORWARD);
528   add_unsized (factory, stock_save, GTK_STOCK_FLOPPY);
529   add_unsized (factory, stock_save, GTK_STOCK_SAVE);
530   add_unsized (factory, stock_save_as, GTK_STOCK_SAVE_AS);
531   add_unsized (factory, stock_search, GTK_STOCK_FIND);
532   add_unsized (factory, stock_search_replace, GTK_STOCK_FIND_AND_REPLACE);
533   add_unsized (factory, stock_sort_ascending, GTK_STOCK_SORT_ASCENDING);
534   add_unsized (factory, stock_spellcheck, GTK_STOCK_SPELL_CHECK);
535   add_unsized (factory, stock_stop, GTK_STOCK_STOP);
536   add_unsized (factory, stock_text_bold, GTK_STOCK_BOLD);
537   add_unsized (factory, stock_text_italic, GTK_STOCK_ITALIC);
538   add_unsized (factory, stock_text_strikeout, GTK_STOCK_STRIKETHROUGH);
539   add_unsized (factory, stock_text_underline, GTK_STOCK_UNDERLINE);
540   add_unsized (factory, stock_top, GTK_STOCK_GOTO_TOP);
541   add_unsized (factory, stock_trash, GTK_STOCK_DELETE);
542   add_unsized (factory, stock_undelete, GTK_STOCK_UNDELETE);
543   add_unsized (factory, stock_undo, GTK_STOCK_UNDO);
544   add_unsized (factory, stock_up_arrow, GTK_STOCK_GO_UP);
545   add_unsized (factory, stock_zoom_1, GTK_STOCK_ZOOM_100);
546   add_unsized (factory, stock_zoom_fit, GTK_STOCK_ZOOM_FIT);
547   add_unsized (factory, stock_zoom_in, GTK_STOCK_ZOOM_IN);
548   add_unsized (factory, stock_zoom_out, GTK_STOCK_ZOOM_OUT);
549 }
550
551 /* Sizes */
552
553 typedef struct _IconSize IconSize;
554
555 struct _IconSize
556 {
557   gint size;
558   gchar *name;
559   
560   gint width;
561   gint height;
562 };
563
564 typedef struct _IconAlias IconAlias;
565
566 struct _IconAlias
567 {
568   gchar *name;
569   gint   target;
570 };
571
572 static GHashTable *icon_aliases = NULL;
573 static IconSize *icon_sizes = NULL;
574 static gint      icon_sizes_allocated = 0;
575 static gint      icon_sizes_used = 0;
576
577 static void
578 init_icon_sizes (void)
579 {
580   if (icon_sizes == NULL)
581     {
582 #define NUM_BUILTIN_SIZES 6
583       gint i;
584
585       icon_aliases = g_hash_table_new (g_str_hash, g_str_equal);
586       
587       icon_sizes = g_new (IconSize, NUM_BUILTIN_SIZES);
588       icon_sizes_allocated = NUM_BUILTIN_SIZES;
589       icon_sizes_used = NUM_BUILTIN_SIZES;
590
591       icon_sizes[GTK_ICON_SIZE_INVALID].size = 0;
592       icon_sizes[GTK_ICON_SIZE_INVALID].name = NULL;
593       icon_sizes[GTK_ICON_SIZE_INVALID].width = 0;
594       icon_sizes[GTK_ICON_SIZE_INVALID].height = 0;
595
596       /* the name strings aren't copied since we don't ever remove
597        * icon sizes, so we don't need to know whether they're static.
598        * Even if we did I suppose removing the builtin sizes would be
599        * disallowed.
600        */
601       
602       icon_sizes[GTK_ICON_SIZE_MENU].size = GTK_ICON_SIZE_MENU;
603       icon_sizes[GTK_ICON_SIZE_MENU].name = "gtk-menu";
604       icon_sizes[GTK_ICON_SIZE_MENU].width = 16;
605       icon_sizes[GTK_ICON_SIZE_MENU].height = 16;
606
607       icon_sizes[GTK_ICON_SIZE_BUTTON].size = GTK_ICON_SIZE_BUTTON;
608       icon_sizes[GTK_ICON_SIZE_BUTTON].name = "gtk-button";
609       icon_sizes[GTK_ICON_SIZE_BUTTON].width = 24;
610       icon_sizes[GTK_ICON_SIZE_BUTTON].height = 24;
611
612       icon_sizes[GTK_ICON_SIZE_SMALL_TOOLBAR].size = GTK_ICON_SIZE_SMALL_TOOLBAR;
613       icon_sizes[GTK_ICON_SIZE_SMALL_TOOLBAR].name = "gtk-small-toolbar";
614       icon_sizes[GTK_ICON_SIZE_SMALL_TOOLBAR].width = 18;
615       icon_sizes[GTK_ICON_SIZE_SMALL_TOOLBAR].height = 18;
616       
617       icon_sizes[GTK_ICON_SIZE_LARGE_TOOLBAR].size = GTK_ICON_SIZE_LARGE_TOOLBAR;
618       icon_sizes[GTK_ICON_SIZE_LARGE_TOOLBAR].name = "gtk-large-toolbar";
619       icon_sizes[GTK_ICON_SIZE_LARGE_TOOLBAR].width = 24;
620       icon_sizes[GTK_ICON_SIZE_LARGE_TOOLBAR].height = 24;
621
622       icon_sizes[GTK_ICON_SIZE_DIALOG].size = GTK_ICON_SIZE_DIALOG;
623       icon_sizes[GTK_ICON_SIZE_DIALOG].name = "gtk-dialog";
624       icon_sizes[GTK_ICON_SIZE_DIALOG].width = 48;
625       icon_sizes[GTK_ICON_SIZE_DIALOG].height = 48;
626
627       g_assert ((GTK_ICON_SIZE_DIALOG + 1) == NUM_BUILTIN_SIZES);
628
629       /* Alias everything to itself. */
630       i = 1; /* skip invalid size */
631       while (i < NUM_BUILTIN_SIZES)
632         {
633           gtk_icon_size_register_alias (icon_sizes[i].name, icon_sizes[i].size);
634           
635           ++i;
636         }
637       
638 #undef NUM_BUILTIN_SIZES
639     }
640 }
641
642 /**
643  * gtk_icon_size_lookup:
644  * @size: an icon size
645  * @width: location to store icon width
646  * @height: location to store icon height
647  *
648  * Obtains the pixel size of a semantic icon size, normally @size would be
649  * #GTK_ICON_SIZE_MENU, #GTK_ICON_SIZE_BUTTON, etc.  This function
650  * isn't normally needed, gtk_widget_render_icon() is the usual
651  * way to get an icon for rendering, then just look at the size of
652  * the rendered pixbuf. The rendered pixbuf may not even correspond to
653  * the width/height returned by gtk_icon_size_lookup(), because themes
654  * are free to render the pixbuf however they like, including changing
655  * the usual size.
656  * 
657  * Return value: %TRUE if @size was a valid size
658  **/
659 gboolean
660 gtk_icon_size_lookup (GtkIconSize  size,
661                       gint        *widthp,
662                       gint        *heightp)
663 {
664   init_icon_sizes ();
665
666   if (size >= icon_sizes_used)
667     return FALSE;
668
669   if (size == GTK_ICON_SIZE_INVALID)
670     return FALSE;
671   
672   if (widthp)
673     *widthp = icon_sizes[size].width;
674
675   if (heightp)
676     *heightp = icon_sizes[size].height;
677
678   return TRUE;
679 }
680
681 /**
682  * gtk_icon_size_register:
683  * @name: name of the icon size
684  * @width: the icon width
685  * @height: the icon height
686  *
687  * Registers a new icon size, along the same lines as #GTK_ICON_SIZE_MENU,
688  * etc. Returns the integer value for the size.
689  *
690  * Returns: integer value representing the size
691  * 
692  **/
693 GtkIconSize
694 gtk_icon_size_register (const gchar *name,
695                         gint         width,
696                         gint         height)
697 {
698   g_return_val_if_fail (name != NULL, 0);
699   g_return_val_if_fail (width > 0, 0);
700   g_return_val_if_fail (height > 0, 0);
701   
702   init_icon_sizes ();
703
704   if (icon_sizes_used == icon_sizes_allocated)
705     {
706       icon_sizes_allocated *= 2;
707       icon_sizes = g_renew (IconSize, icon_sizes, icon_sizes_allocated);
708     }
709   
710   icon_sizes[icon_sizes_used].size = icon_sizes_used;
711   icon_sizes[icon_sizes_used].name = g_strdup (name);
712   icon_sizes[icon_sizes_used].width = width;
713   icon_sizes[icon_sizes_used].height = height;
714
715   /* alias to self. */
716   gtk_icon_size_register_alias (icon_sizes[icon_sizes_used].name,
717                                 icon_sizes[icon_sizes_used].size);
718   
719   ++icon_sizes_used;
720
721   return icon_sizes_used - 1;
722 }
723
724 /**
725  * gtk_icon_size_register_alias:
726  * @alias: an alias for @target
727  * @target: an existing icon size
728  *
729  * Registers @alias as another name for @target.
730  * So calling gtk_icon_size_from_name() with @alias as argument
731  * will return @target.
732  *
733  **/
734 void
735 gtk_icon_size_register_alias (const gchar *alias,
736                               GtkIconSize  target)
737 {
738   IconAlias *ia;
739   
740   g_return_if_fail (alias != NULL);
741
742   init_icon_sizes ();
743
744   if (g_hash_table_lookup (icon_aliases, alias))
745     g_warning ("gtk_icon_size_register_alias: Icon size name '%s' already exists", alias);
746
747   if (!gtk_icon_size_lookup (target, NULL, NULL))
748     g_warning ("gtk_icon_size_register_alias: Icon size %d does not exist", target);
749   
750   ia = g_new (IconAlias, 1);
751   ia->name = g_strdup (alias);
752   ia->target = target;
753
754   g_hash_table_insert (icon_aliases, ia->name, ia);
755 }
756
757 GtkIconSize
758 gtk_icon_size_from_name (const gchar *name)
759 {
760   IconAlias *ia;
761
762   init_icon_sizes ();
763   
764   ia = g_hash_table_lookup (icon_aliases, name);
765
766   if (ia)
767     return ia->target;
768   else
769     return GTK_ICON_SIZE_INVALID;
770 }
771
772 G_CONST_RETURN gchar*
773 gtk_icon_size_get_name (GtkIconSize  size)
774 {
775   if (size >= icon_sizes_used)
776     return NULL;
777   else
778     return icon_sizes[size].name;
779 }
780
781 /* Icon Set */
782
783
784 /* Clear icon set contents, drop references to all contained
785  * GdkPixbuf objects and forget all GtkIconSources. Used to
786  * recycle an icon set.
787  */
788 static GdkPixbuf *find_in_cache     (GtkIconSet       *icon_set,
789                                      GtkStyle         *style,
790                                      GtkTextDirection  direction,
791                                      GtkStateType      state,
792                                      GtkIconSize       size);
793 static void       add_to_cache      (GtkIconSet       *icon_set,
794                                      GtkStyle         *style,
795                                      GtkTextDirection  direction,
796                                      GtkStateType      state,
797                                      GtkIconSize       size,
798                                      GdkPixbuf        *pixbuf);
799 static void       clear_cache       (GtkIconSet       *icon_set,
800                                      gboolean          style_detach);
801 static GSList*    copy_cache        (GtkIconSet       *icon_set,
802                                      GtkIconSet       *copy_recipient);
803 static void       attach_to_style   (GtkIconSet       *icon_set,
804                                      GtkStyle         *style);
805 static void       detach_from_style (GtkIconSet       *icon_set,
806                                      GtkStyle         *style);
807 static void       style_dnotify     (gpointer          data);
808
809 struct _GtkIconSet
810 {
811   guint ref_count;
812
813   GSList *sources;
814
815   /* Cache of the last few rendered versions of the icon. */
816   GSList *cache;
817
818   guint cache_size;
819
820   guint cache_serial;
821 };
822
823 static guint cache_serial = 0;
824
825 /**
826  * gtk_icon_set_new:
827  * 
828  * Creates a new #GtkIconSet. A #GtkIconSet represents a single icon
829  * in various sizes and widget states. It can provide a #GdkPixbuf
830  * for a given size and state on request, and automatically caches
831  * some of the rendered #GdkPixbuf objects.
832  *
833  * Normally you would use gtk_widget_render_icon() instead of
834  * using #GtkIconSet directly. The one case where you'd use
835  * #GtkIconSet is to create application-specific icon sets to place in
836  * a #GtkIconFactory.
837  * 
838  * Return value: a new #GtkIconSet
839  **/
840 GtkIconSet*
841 gtk_icon_set_new (void)
842 {
843   GtkIconSet *icon_set;
844
845   icon_set = g_new (GtkIconSet, 1);
846
847   icon_set->ref_count = 1;
848   icon_set->sources = NULL;
849   icon_set->cache = NULL;
850   icon_set->cache_size = 0;
851   icon_set->cache_serial = cache_serial;
852   
853   return icon_set;
854 }
855
856 /**
857  * gtk_icon_set_new_from_pixbuf:
858  * @pixbuf: a #GdkPixbuf
859  * 
860  * Creates a new #GtkIconSet with @pixbuf as the default/fallback
861  * source image. If you don't add any additional #GtkIconSource to the
862  * icon set, all variants of the icon will be created from @pixbuf,
863  * using scaling, pixelation, etc. as required to adjust the icon size
864  * or make the icon look insensitive/prelighted.
865  * 
866  * Return value: a new #GtkIconSet
867  **/
868 GtkIconSet *
869 gtk_icon_set_new_from_pixbuf (GdkPixbuf *pixbuf)
870 {
871   GtkIconSet *set;
872
873   GtkIconSource source = { NULL, NULL, 0, 0, 0,
874                            TRUE, TRUE, TRUE };
875
876   g_return_val_if_fail (pixbuf != NULL, NULL);
877
878   set = gtk_icon_set_new ();
879
880   source.pixbuf = pixbuf;
881
882   gtk_icon_set_add_source (set, &source);
883   
884   return set;
885 }
886
887
888 /**
889  * gtk_icon_set_ref:
890  * @icon_set: a #GtkIconSet
891  * 
892  * Increments the reference count on @icon_set
893  * 
894  * Return value: @icon_set is returned
895  **/
896 GtkIconSet*
897 gtk_icon_set_ref (GtkIconSet *icon_set)
898 {
899   g_return_val_if_fail (icon_set != NULL, NULL);
900   g_return_val_if_fail (icon_set->ref_count > 0, NULL);
901
902   icon_set->ref_count += 1;
903
904   return icon_set;
905 }
906
907 /**
908  * gtk_icon_set_unref:
909  * @icon_set: a #GtkIconSet
910  * 
911  * Decrements the reference count on @icon_set, and frees memory
912  * if the reference count reaches 0.
913  **/
914 void
915 gtk_icon_set_unref (GtkIconSet *icon_set)
916 {
917   g_return_if_fail (icon_set != NULL);
918   g_return_if_fail (icon_set->ref_count > 0);
919
920   icon_set->ref_count -= 1;
921
922   if (icon_set->ref_count == 0)
923     {
924       GSList *tmp_list = icon_set->sources;
925       while (tmp_list != NULL)
926         {
927           gtk_icon_source_free (tmp_list->data);
928
929           tmp_list = g_slist_next (tmp_list);
930         }
931
932       clear_cache (icon_set, TRUE);
933
934       g_free (icon_set);
935     }
936 }
937
938 /**
939  * gtk_icon_set_copy:
940  * @icon_set: a #GtkIconSet
941  * 
942  * Copies @icon_set by value. 
943  * 
944  * Return value: a new #GtkIconSet identical to the first.
945  **/
946 GtkIconSet*
947 gtk_icon_set_copy (GtkIconSet *icon_set)
948 {
949   GtkIconSet *copy;
950   GSList *tmp_list;
951   
952   copy = gtk_icon_set_new ();
953
954   tmp_list = icon_set->sources;
955   while (tmp_list != NULL)
956     {
957       copy->sources = g_slist_prepend (copy->sources,
958                                        gtk_icon_source_copy (tmp_list->data));
959
960       tmp_list = g_slist_next (tmp_list);
961     }
962
963   copy->sources = g_slist_reverse (copy->sources);
964
965   copy->cache = copy_cache (icon_set, copy);
966   copy->cache_size = icon_set->cache_size;
967   copy->cache_serial = icon_set->cache_serial;
968   
969   return copy;
970 }
971
972
973 static gboolean
974 sizes_equivalent (GtkIconSize lhs,
975                   GtkIconSize rhs)
976 {
977   gint r_w, r_h, l_w, l_h;
978
979   gtk_icon_size_lookup (rhs, &r_w, &r_h);
980   gtk_icon_size_lookup (lhs, &l_w, &l_h);
981
982   return r_w == l_w && r_h == l_h;
983 }
984
985 static GtkIconSource*
986 find_and_prep_icon_source (GtkIconSet       *icon_set,
987                            GtkTextDirection  direction,
988                            GtkStateType      state,
989                            GtkIconSize       size)
990 {
991   GtkIconSource *source;
992   GSList *tmp_list;
993
994
995   /* We need to find the best icon source.  Direction matters more
996    * than state, state matters more than size. icon_set->sources
997    * is sorted according to wildness, so if we take the first
998    * match we find it will be the least-wild match (if there are
999    * multiple matches for a given "wildness" then the RC file contained
1000    * dumb stuff, and we end up with an arbitrary matching source)
1001    */
1002   
1003   source = NULL;
1004   tmp_list = icon_set->sources;
1005   while (tmp_list != NULL)
1006     {
1007       GtkIconSource *s = tmp_list->data;
1008       
1009       if ((s->any_direction || (s->direction == direction)) &&
1010           (s->any_state || (s->state == state)) &&
1011           (s->any_size || (sizes_equivalent (size, s->size))))
1012         {
1013           source = s;
1014           break;
1015         }
1016       
1017       tmp_list = g_slist_next (tmp_list);
1018     }
1019
1020   if (source == NULL)
1021     return NULL;
1022   
1023   if (source->pixbuf == NULL)
1024     {
1025       GError *error;
1026       gchar *full;
1027       
1028       g_assert (source->filename);
1029
1030       if (g_path_is_absolute (source->filename))
1031         full = g_strdup (source->filename);
1032       else
1033         full = gtk_rc_find_pixmap_in_path (NULL, source->filename);
1034
1035       error = NULL;
1036       source->pixbuf = gdk_pixbuf_new_from_file (full, &error);
1037
1038       g_free (full);
1039       
1040       if (source->pixbuf == NULL)
1041         {
1042           /* Remove this icon source so we don't keep trying to
1043            * load it.
1044            */
1045           g_warning (_("Error loading icon: %s"), error->message);
1046           g_error_free (error);
1047           
1048           icon_set->sources = g_slist_remove (icon_set->sources, source);
1049
1050           gtk_icon_source_free (source);
1051
1052           /* Try to fall back to other sources */
1053           if (icon_set->sources != NULL)
1054             return find_and_prep_icon_source (icon_set,
1055                                               direction,
1056                                               state,
1057                                               size);
1058           else
1059             return NULL;
1060         }
1061     }
1062
1063   return source;
1064 }
1065
1066 static GdkPixbuf*
1067 render_fallback_image (GtkStyle          *style,
1068                        GtkTextDirection   direction,
1069                        GtkStateType       state,
1070                        GtkIconSize        size,
1071                        GtkWidget         *widget,
1072                        const char        *detail)
1073 {
1074   /* This icon can be used for any direction/state/size */
1075   static GtkIconSource fallback_source = { NULL, NULL, 0, 0, 0, TRUE, TRUE, TRUE };
1076
1077   if (fallback_source.pixbuf == NULL)
1078     fallback_source.pixbuf = gdk_pixbuf_new_from_inline (MISSING_IMAGE_INLINE, FALSE, -1, NULL);
1079   
1080   return gtk_style_render_icon (style,
1081                                 &fallback_source,
1082                                 direction,
1083                                 state,
1084                                 size,
1085                                 widget,
1086                                 detail);
1087 }
1088
1089 /**
1090  * gtk_icon_set_render_icon:
1091  * @icon_set: a #GtkIconSet
1092  * @style: a #GtkStyle associated with @widget, or %NULL
1093  * @direction: text direction
1094  * @state: widget state
1095  * @size: icon size
1096  * @widget: widget that will display the icon, or %NULL
1097  * @detail: detail to pass to the theme engine, or %NULL
1098  * 
1099  * Renders an icon using gtk_style_render_icon(). In most cases,
1100  * gtk_widget_render_icon() is better, since it automatically provides
1101  * most of the arguments from the current widget settings.  This
1102  * function never returns %NULL; if the icon can't be rendered
1103  * (perhaps because an image file fails to load), a default "missing
1104  * image" icon will be returned instead.
1105  * 
1106  * Return value: a #GdkPixbuf to be displayed
1107  **/
1108 GdkPixbuf*
1109 gtk_icon_set_render_icon (GtkIconSet        *icon_set,
1110                           GtkStyle          *style,
1111                           GtkTextDirection   direction,
1112                           GtkStateType       state,
1113                           GtkIconSize        size,
1114                           GtkWidget         *widget,
1115                           const char        *detail)
1116 {
1117   GdkPixbuf *icon;
1118   GtkIconSource *source;
1119   
1120   g_return_val_if_fail (icon_set != NULL, NULL);
1121   g_return_val_if_fail (GTK_IS_STYLE (style), NULL);
1122
1123   if (icon_set->sources == NULL)
1124     return render_fallback_image (style, direction, state, size, widget, detail);
1125   
1126   icon = find_in_cache (icon_set, style, direction,
1127                         state, size);
1128
1129   if (icon)
1130     {
1131       g_object_ref (G_OBJECT (icon));
1132       return icon;
1133     }
1134
1135   
1136   source = find_and_prep_icon_source (icon_set, direction, state, size);
1137
1138   if (source == NULL)
1139     return render_fallback_image (style, direction, state, size, widget, detail);
1140
1141   g_assert (source->pixbuf != NULL);
1142   
1143   icon = gtk_style_render_icon (style,
1144                                 source,
1145                                 direction,
1146                                 state,
1147                                 size,
1148                                 widget,
1149                                 detail);
1150
1151   if (icon == NULL)
1152     {
1153       g_warning ("Theme engine failed to render icon");
1154       return NULL;
1155     }
1156   
1157   add_to_cache (icon_set, style, direction, state, size, icon);
1158   
1159   return icon;
1160 }
1161
1162 /* Order sources by their "wildness", so that "wilder" sources are
1163  * greater than "specific" sources; for determining ordering,
1164  * direction beats state beats size.
1165  */
1166
1167 static int
1168 icon_source_compare (gconstpointer ap, gconstpointer bp)
1169 {
1170   const GtkIconSource *a = ap;
1171   const GtkIconSource *b = bp;
1172
1173   if (!a->any_direction && b->any_direction)
1174     return -1;
1175   else if (a->any_direction && !b->any_direction)
1176     return 1;
1177   else if (!a->any_state && b->any_state)
1178     return -1;
1179   else if (a->any_state && !b->any_state)
1180     return 1;
1181   else if (!a->any_size && b->any_size)
1182     return -1;
1183   else if (a->any_size && !b->any_size)
1184     return 1;
1185   else
1186     return 0;
1187 }
1188
1189 /**
1190  * gtk_icon_set_add_source:
1191  * @icon_set: a #GtkIconSet
1192  * @source: a #GtkIconSource
1193  *
1194  * Icon sets have a list of #GtkIconSource, which they use as base
1195  * icons for rendering icons in different states and sizes. Icons are
1196  * scaled, made to look insensitive, etc. in
1197  * gtk_icon_set_render_icon(), but #GtkIconSet needs base images to
1198  * work with. The base images and when to use them are described by
1199  * a #GtkIconSource.
1200  * 
1201  * This function copies @source, so you can reuse the same source immediately
1202  * without affecting the icon set.
1203  *
1204  * An example of when you'd use this function: a web browser's "Back
1205  * to Previous Page" icon might point in a different direction in
1206  * Hebrew and in English; it might look different when insensitive;
1207  * and it might change size depending on toolbar mode (small/large
1208  * icons). So a single icon set would contain all those variants of
1209  * the icon, and you might add a separate source for each one.
1210  *
1211  * You should nearly always add a "default" icon source with all
1212  * fields wildcarded, which will be used as a fallback if no more
1213  * specific source matches. #GtkIconSet always prefers more specific
1214  * icon sources to more generic icon sources. The order in which you
1215  * add the sources to the icon set does not matter.
1216  *
1217  * gtk_icon_set_new_from_pixbuf() creates a new icon set with a
1218  * default icon source based on the given pixbuf.
1219  * 
1220  **/
1221 void
1222 gtk_icon_set_add_source (GtkIconSet *icon_set,
1223                          const GtkIconSource *source)
1224 {
1225   g_return_if_fail (icon_set != NULL);
1226   g_return_if_fail (source != NULL);
1227
1228   if (source->pixbuf == NULL &&
1229       source->filename == NULL)
1230     {
1231       g_warning ("Useless GtkIconSource contains NULL filename and pixbuf");
1232       return;
1233     }
1234   
1235   icon_set->sources = g_slist_insert_sorted (icon_set->sources,
1236                                              gtk_icon_source_copy (source),
1237                                              icon_source_compare);
1238 }
1239
1240 /**
1241  * gtk_icon_set_get_sizes:
1242  * @icon_set: a #GtkIconSet
1243  * @sizes: return location for array of sizes
1244  * @n_sizes: location to store number of elements in returned array
1245  *
1246  * Obtains a list of icon sizes this icon set can render. The returned
1247  * array must be freed with g_free().
1248  * 
1249  **/
1250 void
1251 gtk_icon_set_get_sizes (GtkIconSet   *icon_set,
1252                         GtkIconSize **sizes,
1253                         gint         *n_sizes)
1254 {
1255   GSList *tmp_list;
1256   gboolean all_sizes = FALSE;
1257   GSList *specifics = NULL;
1258   
1259   g_return_if_fail (icon_set != NULL);
1260   g_return_if_fail (sizes != NULL);
1261   g_return_if_fail (n_sizes != NULL);
1262   
1263   tmp_list = icon_set->sources;
1264   while (tmp_list != NULL)
1265     {
1266       GtkIconSource *source;
1267
1268       source = tmp_list->data;
1269
1270       if (source->any_size)
1271         {
1272           all_sizes = TRUE;
1273           break;
1274         }
1275       else
1276         specifics = g_slist_prepend (specifics, GINT_TO_POINTER (source->size));
1277       
1278       tmp_list = g_slist_next (tmp_list);
1279     }
1280
1281   if (all_sizes)
1282     {
1283       /* Need to find out what sizes exist */
1284       gint i;
1285
1286       init_icon_sizes ();
1287       
1288       *sizes = g_new (GtkIconSize, icon_sizes_used);
1289       *n_sizes = icon_sizes_used;
1290       
1291       i = 0;      
1292       while (i < icon_sizes_used)
1293         {
1294           (*sizes)[i] = icon_sizes[i].size;
1295           ++i;
1296         }
1297     }
1298   else
1299     {
1300       gint i;
1301       
1302       *n_sizes = g_slist_length (specifics);
1303       *sizes = g_new (GtkIconSize, *n_sizes);
1304
1305       i = 0;
1306       tmp_list = specifics;
1307       while (tmp_list != NULL)
1308         {
1309           (*sizes)[i] = GPOINTER_TO_INT (tmp_list->data);
1310
1311           ++i;
1312           tmp_list = g_slist_next (tmp_list);
1313         }
1314     }
1315
1316   g_slist_free (specifics);
1317 }
1318
1319
1320 /**
1321  * gtk_icon_source_new:
1322  * 
1323  * Creates a new #GtkIconSource. A #GtkIconSource contains a #GdkPixbuf (or
1324  * image filename) that serves as the base image for one or more of the
1325  * icons in a #GtkIconSet, along with a specification for which icons in the
1326  * icon set will be based on that pixbuf or image file. An icon set contains
1327  * a set of icons that represent "the same" logical concept in different states,
1328  * different global text directions, and different sizes.
1329  * 
1330  * So for example a web browser's "Back to Previous Page" icon might
1331  * point in a different direction in Hebrew and in English; it might
1332  * look different when insensitive; and it might change size depending
1333  * on toolbar mode (small/large icons). So a single icon set would
1334  * contain all those variants of the icon. #GtkIconSet contains a list
1335  * of #GtkIconSource from which it can derive specific icon variants in
1336  * the set. 
1337  *
1338  * In the simplest case, #GtkIconSet contains one source pixbuf from
1339  * which it derives all variants. The convenience function
1340  * gtk_icon_set_new_from_pixbuf() handles this case; if you only have
1341  * one source pixbuf, just use that function.
1342  *
1343  * If you want to use a different base pixbuf for different icon
1344  * variants, you create multiple icon sources, mark which variants
1345  * they'll be used to create, and add them to the icon set with
1346  * gtk_icon_set_add_source().
1347  *
1348  * By default, the icon source has all parameters wildcarded. That is,
1349  * the icon source will be used as the base icon for any desired text
1350  * direction, widget state, or icon size.
1351  * 
1352  * Return value: a new #GtkIconSource
1353  **/
1354 GtkIconSource*
1355 gtk_icon_source_new (void)
1356 {
1357   GtkIconSource *src;
1358   
1359   src = g_new0 (GtkIconSource, 1);
1360
1361   src->direction = GTK_TEXT_DIR_NONE;
1362   src->size = GTK_ICON_SIZE_INVALID;
1363   src->state = GTK_STATE_NORMAL;
1364   
1365   src->any_direction = TRUE;
1366   src->any_state = TRUE;
1367   src->any_size = TRUE;
1368   
1369   return src;
1370 }
1371
1372 /**
1373  * gtk_icon_source_copy:
1374  * @source: a #GtkIconSource
1375  * 
1376  * Creates a copy of @source; mostly useful for language bindings.
1377  * 
1378  * Return value: a new #GtkIconSource
1379  **/
1380 GtkIconSource*
1381 gtk_icon_source_copy (const GtkIconSource *source)
1382 {
1383   GtkIconSource *copy;
1384   
1385   g_return_val_if_fail (source != NULL, NULL);
1386
1387   copy = g_new (GtkIconSource, 1);
1388
1389   *copy = *source;
1390   
1391   copy->filename = g_strdup (source->filename);
1392   copy->size = source->size;
1393   if (copy->pixbuf)
1394     g_object_ref (G_OBJECT (copy->pixbuf));
1395
1396   return copy;
1397 }
1398
1399 /**
1400  * gtk_icon_source_free:
1401  * @source: a #GtkIconSource
1402  * 
1403  * Frees a dynamically-allocated icon source, along with its
1404  * filename, size, and pixbuf fields if those are not %NULL.
1405  **/
1406 void
1407 gtk_icon_source_free (GtkIconSource *source)
1408 {
1409   g_return_if_fail (source != NULL);
1410
1411   g_free ((char*) source->filename);
1412   if (source->pixbuf)
1413     g_object_unref (G_OBJECT (source->pixbuf));
1414
1415   g_free (source);
1416 }
1417
1418 /**
1419  * gtk_icon_source_set_filename:
1420  * @source: a #GtkIconSource
1421  * @filename: image file to use
1422  *
1423  * Sets the name of an image file to use as a base image when creating icon
1424  * variants for #GtkIconSet. If the filename is absolute, GTK+ will
1425  * attempt to open the exact file given. If the filename is relative,
1426  * GTK+ will search for it in the "pixmap path" which can be configured
1427  * by users in their gtkrc files or specified as part of a theme's gtkrc
1428  * file. See #GtkRcStyle for information on gtkrc files.
1429  * 
1430  **/
1431 void
1432 gtk_icon_source_set_filename             (GtkIconSource *source,
1433                                           const gchar   *filename)
1434 {
1435   g_return_if_fail (source != NULL);
1436
1437   if (source->filename == filename)
1438     return;
1439   
1440   if (source->filename)
1441     g_free (source->filename);
1442
1443   source->filename = g_strdup (filename);  
1444 }
1445
1446 /**
1447  * gtk_icon_source_set_pixbuf:
1448  * @source: a #GtkIconSource
1449  * @pixbuf: pixbuf to use as a source
1450  *
1451  * Sets a pixbuf to use as a base image when creating icon variants
1452  * for #GtkIconSet. If an icon source has both a filename and a pixbuf
1453  * set, the pixbuf will take priority.
1454  * 
1455  **/
1456 void
1457 gtk_icon_source_set_pixbuf (GtkIconSource *source,
1458                             GdkPixbuf     *pixbuf)
1459 {
1460   g_return_if_fail (source != NULL);
1461
1462   if (pixbuf)
1463     g_object_ref (G_OBJECT (pixbuf));
1464
1465   if (source->pixbuf)
1466     g_object_unref (G_OBJECT (source->pixbuf));
1467
1468   source->pixbuf = pixbuf;
1469 }
1470
1471 /**
1472  * gtk_icon_source_get_filename:
1473  * @source: a #GtkIconSource
1474  * 
1475  * Retrieves the source filename, or %NULL if none is set.  The
1476  * filename is not a copy, and should not be modified or expected to
1477  * persist beyond the lifetime of the icon source.
1478  * 
1479  * Return value: image filename
1480  **/
1481 G_CONST_RETURN gchar*
1482 gtk_icon_source_get_filename (const GtkIconSource *source)
1483 {
1484   g_return_val_if_fail (source != NULL, NULL);
1485   
1486   return source->filename;
1487 }
1488
1489 /**
1490  * gtk_icon_source_get_pixbuf:
1491  * @source: a #GtkIconSource
1492  * 
1493  * Retrieves the source pixbuf, or %NULL if none is set.
1494  * The reference count on the pixbuf is not incremented.
1495  * 
1496  * Return value: source pixbuf
1497  **/
1498 GdkPixbuf*
1499 gtk_icon_source_get_pixbuf (const GtkIconSource *source)
1500 {
1501   g_return_val_if_fail (source != NULL, NULL);
1502   
1503   return source->pixbuf;
1504 }
1505
1506 /**
1507  * gtk_icon_source_set_direction_wildcarded:
1508  * @source: a #GtkIconSource
1509  * @setting: %TRUE to wildcard the text direction
1510  *
1511  * If the text direction is wildcarded, this source can be used
1512  * as the base image for an icon in any #GtkTextDirection.
1513  * If the text direction is not wildcarded, then the
1514  * text direction the icon source applies to should be set
1515  * with gtk_icon_source_set_direction(), and the icon source
1516  * will only be used with that text direction.
1517  *
1518  * #GtkIconSet prefers non-wildcarded sources (exact matches) over
1519  * wildcarded sources, and will use an exact match when possible.
1520  * 
1521  **/
1522 void
1523 gtk_icon_source_set_direction_wildcarded (GtkIconSource *source,
1524                                           gboolean       setting)
1525 {
1526   g_return_if_fail (source != NULL);
1527
1528   source->any_direction = setting != FALSE;
1529 }
1530
1531 /**
1532  * gtk_icon_source_set_state_wildcarded:
1533  * @source: a #GtkIconSource
1534  * @setting: %TRUE to wildcard the widget state
1535  *
1536  * If the widget state is wildcarded, this source can be used as the
1537  * base image for an icon in any #GtkStateType.  If the widget state
1538  * is not wildcarded, then the state the source applies to should be
1539  * set with gtk_icon_source_set_state() and the icon source will
1540  * only be used with that specific state.
1541  *
1542  * #GtkIconSet prefers non-wildcarded sources (exact matches) over
1543  * wildcarded sources, and will use an exact match when possible.
1544  *
1545  * #GtkIconSet will normally transform wildcarded source images to
1546  * produce an appropriate icon for a given state, for example
1547  * lightening an image on prelight, but will not modify source images
1548  * that match exactly.
1549  **/
1550 void
1551 gtk_icon_source_set_state_wildcarded (GtkIconSource *source,
1552                                       gboolean       setting)
1553 {
1554   g_return_if_fail (source != NULL);
1555
1556   source->any_state = setting != FALSE;
1557 }
1558
1559
1560 /**
1561  * gtk_icon_source_set_size_wildcarded:
1562  * @source: a #GtkIconSource
1563  * @setting: %TRUE to wildcard the widget state
1564  *
1565  * If the icon size is wildcarded, this source can be used as the base
1566  * image for an icon of any size.  If the size is not wildcarded, then
1567  * the size the source applies to should be set with
1568  * gtk_icon_source_set_size() and the icon source will only be used
1569  * with that specific size.
1570  *
1571  * #GtkIconSet prefers non-wildcarded sources (exact matches) over
1572  * wildcarded sources, and will use an exact match when possible.
1573  *
1574  * #GtkIconSet will normally scale wildcarded source images to produce
1575  * an appropriate icon at a given size, but will not change the size
1576  * of source images that match exactly.
1577  **/
1578 void
1579 gtk_icon_source_set_size_wildcarded (GtkIconSource *source,
1580                                      gboolean       setting)
1581 {
1582   g_return_if_fail (source != NULL);
1583
1584   source->any_size = setting != FALSE;  
1585 }
1586
1587 /**
1588  * gtk_icon_source_get_size_wildcarded:
1589  * @source: a #GtkIconSource
1590  * 
1591  * Gets the value set by gtk_icon_source_set_size_wildcarded().
1592  * 
1593  * Return value: %TRUE if this icon source is a base for any icon size variant
1594  **/
1595 gboolean
1596 gtk_icon_source_get_size_wildcarded (const GtkIconSource *source)
1597 {
1598   g_return_val_if_fail (source != NULL, TRUE);
1599   
1600   return source->any_size;
1601 }
1602
1603 /**
1604  * gtk_icon_source_get_state_wildcarded:
1605  * @source: a #GtkIconSource
1606  * 
1607  * Gets the value set by gtk_icon_source_set_state_wildcarded().
1608  * 
1609  * Return value: %TRUE if this icon source is a base for any widget state variant
1610  **/
1611 gboolean
1612 gtk_icon_source_get_state_wildcarded (const GtkIconSource *source)
1613 {
1614   g_return_val_if_fail (source != NULL, TRUE);
1615
1616   return source->any_state;
1617 }
1618
1619 /**
1620  * gtk_icon_source_get_direction_wildcarded:
1621  * @source: a #GtkIconSource
1622  * 
1623  * Gets the value set by gtk_icon_source_set_direction_wildcarded().
1624  * 
1625  * Return value: %TRUE if this icon source is a base for any text direction variant
1626  **/
1627 gboolean
1628 gtk_icon_source_get_direction_wildcarded (const GtkIconSource *source)
1629 {
1630   g_return_val_if_fail (source != NULL, TRUE);
1631
1632   return source->any_direction;
1633 }
1634
1635 /**
1636  * gtk_icon_source_set_direction:
1637  * @source: a #GtkIconSource
1638  * @direction: text direction this source applies to
1639  *
1640  * Sets the text direction this icon source is intended to be used
1641  * with.
1642  * 
1643  * Setting the text direction on an icon source makes no difference
1644  * if the text direction is wildcarded. Therefore, you should usually
1645  * call gtk_icon_source_set_direction_wildcarded() to un-wildcard it
1646  * in addition to calling this function.
1647  * 
1648  **/
1649 void
1650 gtk_icon_source_set_direction (GtkIconSource   *source,
1651                                GtkTextDirection direction)
1652 {
1653   g_return_if_fail (source != NULL);
1654
1655   source->direction = direction;
1656 }
1657
1658 /**
1659  * gtk_icon_source_set_state:
1660  * @source: a #GtkIconSource
1661  * @state: widget state this source applies to
1662  *
1663  * Sets the widget state this icon source is intended to be used
1664  * with.
1665  * 
1666  * Setting the widget state on an icon source makes no difference
1667  * if the state is wildcarded. Therefore, you should usually
1668  * call gtk_icon_source_set_state_wildcarded() to un-wildcard it
1669  * in addition to calling this function.
1670  * 
1671  **/
1672 void
1673 gtk_icon_source_set_state (GtkIconSource *source,
1674                            GtkStateType   state)
1675 {
1676   g_return_if_fail (source != NULL);
1677
1678   source->state = state;
1679 }
1680
1681 /**
1682  * gtk_icon_source_set_size:
1683  * @source: a #GtkIconSource
1684  * @size: icon size this source applies to
1685  *
1686  * Sets the icon size this icon source is intended to be used
1687  * with.
1688  * 
1689  * Setting the icon size on an icon source makes no difference
1690  * if the size is wildcarded. Therefore, you should usually
1691  * call gtk_icon_source_set_size_wildcarded() to un-wildcard it
1692  * in addition to calling this function.
1693  * 
1694  **/
1695 void
1696 gtk_icon_source_set_size (GtkIconSource *source,
1697                           GtkIconSize    size)
1698 {
1699   g_return_if_fail (source != NULL);
1700
1701   source->size = size;
1702 }
1703
1704 /**
1705  * gtk_icon_source_get_direction:
1706  * @source: a #GtkIconSource
1707  * 
1708  * Obtains the text direction this icon source applies to. The return
1709  * value is only useful/meaningful if the text direction is NOT
1710  * wildcarded.
1711  * 
1712  * Return value: text direction this source matches
1713  **/
1714 GtkTextDirection
1715 gtk_icon_source_get_direction (const GtkIconSource *source)
1716 {
1717   g_return_val_if_fail (source != NULL, 0);
1718
1719   return source->direction;
1720 }
1721
1722 /**
1723  * gtk_icon_source_get_state:
1724  * @source: a #GtkIconSource
1725  * 
1726  * Obtains the widget state this icon source applies to. The return
1727  * value is only useful/meaningful if the widget state is NOT
1728  * wildcarded.
1729  * 
1730  * Return value: widget state this source matches
1731  **/
1732 GtkStateType
1733 gtk_icon_source_get_state (const GtkIconSource *source)
1734 {
1735   g_return_val_if_fail (source != NULL, 0);
1736
1737   return source->state;
1738 }
1739
1740 /**
1741  * gtk_icon_source_get_size:
1742  * @source: a #GtkIconSource
1743  * 
1744  * Obtains the icon size this source applies to. The return value
1745  * is only useful/meaningful if the icon size is NOT wildcarded.
1746  * 
1747  * Return value: icon size this source matches.
1748  **/
1749 GtkIconSize
1750 gtk_icon_source_get_size (const GtkIconSource *source)
1751 {
1752   g_return_val_if_fail (source != NULL, 0);
1753
1754   return source->size;
1755 }
1756
1757 /* Note that the logical maximum is 20 per GtkTextDirection, so we could
1758  * eventually set this to >20 to never throw anything out.
1759  */
1760 #define NUM_CACHED_ICONS 8
1761
1762 typedef struct _CachedIcon CachedIcon;
1763
1764 struct _CachedIcon
1765 {
1766   /* These must all match to use the cached pixbuf.
1767    * If any don't match, we must re-render the pixbuf.
1768    */
1769   GtkStyle *style;
1770   GtkTextDirection direction;
1771   GtkStateType state;
1772   GtkIconSize size;
1773
1774   GdkPixbuf *pixbuf;
1775 };
1776
1777 static void
1778 ensure_cache_up_to_date (GtkIconSet *icon_set)
1779 {
1780   if (icon_set->cache_serial != cache_serial)
1781     clear_cache (icon_set, TRUE);
1782 }
1783
1784 static void
1785 cached_icon_free (CachedIcon *icon)
1786 {
1787   g_object_unref (G_OBJECT (icon->pixbuf));
1788
1789   g_free (icon);
1790 }
1791
1792 static GdkPixbuf *
1793 find_in_cache (GtkIconSet      *icon_set,
1794                GtkStyle        *style,
1795                GtkTextDirection direction,
1796                GtkStateType     state,
1797                GtkIconSize      size)
1798 {
1799   GSList *tmp_list;
1800   GSList *prev;
1801
1802   ensure_cache_up_to_date (icon_set);
1803   
1804   prev = NULL;
1805   tmp_list = icon_set->cache;
1806   while (tmp_list != NULL)
1807     {
1808       CachedIcon *icon = tmp_list->data;
1809
1810       if (icon->style == style &&
1811           icon->direction == direction &&
1812           icon->state == state &&
1813           icon->size == size)
1814         {
1815           if (prev)
1816             {
1817               /* Move this icon to the front of the list. */
1818               prev->next = tmp_list->next;
1819               tmp_list->next = icon_set->cache;
1820               icon_set->cache = tmp_list;
1821             }
1822           
1823           return icon->pixbuf;
1824         }
1825           
1826       prev = tmp_list;
1827       tmp_list = g_slist_next (tmp_list);
1828     }
1829
1830   return NULL;
1831 }
1832
1833 static void
1834 add_to_cache (GtkIconSet      *icon_set,
1835               GtkStyle        *style,
1836               GtkTextDirection direction,
1837               GtkStateType     state,
1838               GtkIconSize      size,
1839               GdkPixbuf       *pixbuf)
1840 {
1841   CachedIcon *icon;
1842
1843   ensure_cache_up_to_date (icon_set);
1844   
1845   g_object_ref (G_OBJECT (pixbuf));
1846
1847   /* We have to ref the style, since if the style was finalized
1848    * its address could be reused by another style, creating a
1849    * really weird bug
1850    */
1851   
1852   if (style)
1853     g_object_ref (G_OBJECT (style));
1854   
1855
1856   icon = g_new (CachedIcon, 1);
1857   icon_set->cache = g_slist_prepend (icon_set->cache, icon);
1858
1859   icon->style = style;
1860   icon->direction = direction;
1861   icon->state = state;
1862   icon->size = size;
1863   icon->pixbuf = pixbuf;
1864
1865   if (icon->style)
1866     attach_to_style (icon_set, icon->style);
1867   
1868   if (icon_set->cache_size >= NUM_CACHED_ICONS)
1869     {
1870       /* Remove oldest item in the cache */
1871       
1872       GSList *tmp_list;
1873       
1874       tmp_list = icon_set->cache;
1875
1876       /* Find next-to-last link */
1877       g_assert (NUM_CACHED_ICONS > 2);
1878       while (tmp_list->next->next)
1879         tmp_list = tmp_list->next;
1880
1881       g_assert (tmp_list != NULL);
1882       g_assert (tmp_list->next != NULL);
1883       g_assert (tmp_list->next->next == NULL);
1884
1885       /* Free the last icon */
1886       icon = tmp_list->next->data;
1887
1888       g_slist_free (tmp_list->next);
1889       tmp_list->next = NULL;
1890
1891       cached_icon_free (icon);
1892     }
1893 }
1894
1895 static void
1896 clear_cache (GtkIconSet *icon_set,
1897              gboolean    style_detach)
1898 {
1899   GSList *tmp_list;
1900   GtkStyle *last_style = NULL;
1901
1902   tmp_list = icon_set->cache;
1903   while (tmp_list != NULL)
1904     {
1905       CachedIcon *icon = tmp_list->data;
1906
1907       if (style_detach)
1908         {
1909           /* simple optimization for the case where the cache
1910            * contains contiguous icons from the same style.
1911            * it's safe to call detach_from_style more than
1912            * once on the same style though.
1913            */
1914           if (last_style != icon->style)
1915             {
1916               detach_from_style (icon_set, icon->style);
1917               last_style = icon->style;
1918             }
1919         }
1920       
1921       cached_icon_free (icon);      
1922       
1923       tmp_list = g_slist_next (tmp_list);
1924     }
1925
1926   g_slist_free (icon_set->cache);
1927   icon_set->cache = NULL;
1928   icon_set->cache_size = 0;
1929 }
1930
1931 static GSList*
1932 copy_cache (GtkIconSet *icon_set,
1933             GtkIconSet *copy_recipient)
1934 {
1935   GSList *tmp_list;
1936   GSList *copy = NULL;
1937
1938   ensure_cache_up_to_date (icon_set);
1939   
1940   tmp_list = icon_set->cache;
1941   while (tmp_list != NULL)
1942     {
1943       CachedIcon *icon = tmp_list->data;
1944       CachedIcon *icon_copy = g_new (CachedIcon, 1);
1945
1946       *icon_copy = *icon;
1947
1948       if (icon_copy->style)
1949         attach_to_style (copy_recipient, icon_copy->style);
1950         
1951       g_object_ref (G_OBJECT (icon_copy->pixbuf));
1952
1953       icon_copy->size = icon->size;
1954       
1955       copy = g_slist_prepend (copy, icon_copy);      
1956       
1957       tmp_list = g_slist_next (tmp_list);
1958     }
1959
1960   return g_slist_reverse (copy);
1961 }
1962
1963 static void
1964 attach_to_style (GtkIconSet *icon_set,
1965                  GtkStyle   *style)
1966 {
1967   GHashTable *table;
1968
1969   table = g_object_get_qdata (G_OBJECT (style),
1970                               g_quark_try_string ("gtk-style-icon-sets"));
1971
1972   if (table == NULL)
1973     {
1974       table = g_hash_table_new (NULL, NULL);
1975       g_object_set_qdata_full (G_OBJECT (style),
1976                                g_quark_from_static_string ("gtk-style-icon-sets"),
1977                                table,
1978                                style_dnotify);
1979     }
1980
1981   g_hash_table_insert (table, icon_set, icon_set);
1982 }
1983
1984 static void
1985 detach_from_style (GtkIconSet *icon_set,
1986                    GtkStyle   *style)
1987 {
1988   GHashTable *table;
1989
1990   table = g_object_get_qdata (G_OBJECT (style),
1991                               g_quark_try_string ("gtk-style-icon-sets"));
1992
1993   if (table != NULL)
1994     g_hash_table_remove (table, icon_set);
1995 }
1996
1997 static void
1998 iconsets_foreach (gpointer key,
1999                   gpointer value,
2000                   gpointer user_data)
2001 {
2002   GtkIconSet *icon_set = key;
2003
2004   /* We only need to remove cache entries for the given style;
2005    * but that complicates things because in destroy notify
2006    * we don't know which style got destroyed, and 95% of the
2007    * time all cache entries will have the same style,
2008    * so this is faster anyway.
2009    */
2010   
2011   clear_cache (icon_set, FALSE);
2012 }
2013
2014 static void
2015 style_dnotify (gpointer data)
2016 {
2017   GHashTable *table = data;
2018   
2019   g_hash_table_foreach (table, iconsets_foreach, NULL);
2020
2021   g_hash_table_destroy (table);
2022 }
2023
2024 /* This allows the icon set to detect that its cache is out of date. */
2025 void
2026 _gtk_icon_set_invalidate_caches (void)
2027 {
2028   ++cache_serial;
2029 }
2030
2031 static void
2032 listify_foreach (gpointer key, gpointer value, gpointer data)
2033 {
2034   GSList **list = data;
2035
2036   *list = g_slist_prepend (*list, key);
2037 }
2038
2039 static GSList *
2040 g_hash_table_get_keys (GHashTable *table)
2041 {
2042   GSList *list = NULL;
2043
2044   g_hash_table_foreach (table, listify_foreach, &list);
2045
2046   return list;
2047 }
2048
2049 /**
2050  * _gtk_icon_factory_list_ids:
2051  * 
2052  * Gets all known IDs stored in an existing icon factory.
2053  * The strings in the returned list aren't copied.
2054  * The list itself should be freed.
2055  * 
2056  * Return value: List of ids in icon factories
2057  **/
2058 GSList*
2059 _gtk_icon_factory_list_ids (void)
2060 {
2061   GSList *tmp_list;
2062   GSList *ids;
2063
2064   ids = NULL;
2065
2066   ensure_default_icons ();
2067   
2068   tmp_list = all_icon_factories;
2069   while (tmp_list != NULL)
2070     {
2071       GSList *these_ids;
2072       
2073       GtkIconFactory *factory = GTK_ICON_FACTORY (tmp_list->data);
2074
2075       these_ids = g_hash_table_get_keys (factory->icons);
2076       
2077       ids = g_slist_concat (ids, these_ids);
2078       
2079       tmp_list = g_slist_next (tmp_list);
2080     }
2081
2082   return ids;
2083 }