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