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