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