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