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