/src/glib/gio/gthemedicon.c
Line | Count | Source |
1 | | /* GIO - GLib Input, Output and Streaming Library |
2 | | * |
3 | | * Copyright (C) 2006-2007 Red Hat, Inc. |
4 | | * |
5 | | * SPDX-License-Identifier: LGPL-2.1-or-later |
6 | | * |
7 | | * This library is free software; you can redistribute it and/or |
8 | | * modify it under the terms of the GNU Lesser General Public |
9 | | * License as published by the Free Software Foundation; either |
10 | | * version 2.1 of the License, or (at your option) any later version. |
11 | | * |
12 | | * This library is distributed in the hope that it will be useful, |
13 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | | * Lesser General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU Lesser General |
18 | | * Public License along with this library; if not, see <http://www.gnu.org/licenses/>. |
19 | | * |
20 | | * Author: Alexander Larsson <alexl@redhat.com> |
21 | | */ |
22 | | |
23 | | #include "config.h" |
24 | | |
25 | | #include <string.h> |
26 | | |
27 | | #include "gthemedicon.h" |
28 | | #include "gicon.h" |
29 | | #include "gioerror.h" |
30 | | #include "glibintl.h" |
31 | | |
32 | | |
33 | | /** |
34 | | * GThemedIcon: |
35 | | * |
36 | | * `GThemedIcon` is an implementation of [iface@Gio.Icon] that supports icon |
37 | | * themes. |
38 | | * |
39 | | * `GThemedIcon` contains a list of all of the icons present in an icon |
40 | | * theme, so that icons can be looked up quickly. `GThemedIcon` does |
41 | | * not provide actual pixmaps for icons, just the icon names. |
42 | | * Ideally something like [method@Gtk.IconTheme.choose_icon] should be used to |
43 | | * resolve the list of names so that fallback icons work nicely with |
44 | | * themes that inherit other themes. |
45 | | **/ |
46 | | |
47 | | static void g_themed_icon_icon_iface_init (GIconIface *iface); |
48 | | |
49 | | struct _GThemedIcon |
50 | | { |
51 | | GObject parent_instance; |
52 | | |
53 | | char **init_names; |
54 | | char **names; |
55 | | gboolean use_default_fallbacks; |
56 | | }; |
57 | | |
58 | | struct _GThemedIconClass |
59 | | { |
60 | | GObjectClass parent_class; |
61 | | }; |
62 | | |
63 | | enum |
64 | | { |
65 | | PROP_0, |
66 | | PROP_NAME, |
67 | | PROP_NAMES, |
68 | | PROP_USE_DEFAULT_FALLBACKS |
69 | | }; |
70 | | |
71 | | static void g_themed_icon_update_names (GThemedIcon *themed); |
72 | | |
73 | 0 | G_DEFINE_TYPE_WITH_CODE (GThemedIcon, g_themed_icon, G_TYPE_OBJECT, |
74 | 0 | G_IMPLEMENT_INTERFACE (G_TYPE_ICON, |
75 | 0 | g_themed_icon_icon_iface_init)) |
76 | 0 |
|
77 | 0 | static void |
78 | 0 | g_themed_icon_get_property (GObject *object, |
79 | 0 | guint prop_id, |
80 | 0 | GValue *value, |
81 | 0 | GParamSpec *pspec) |
82 | 0 | { |
83 | 0 | GThemedIcon *icon = G_THEMED_ICON (object); |
84 | |
|
85 | 0 | switch (prop_id) |
86 | 0 | { |
87 | 0 | case PROP_NAMES: |
88 | 0 | g_value_set_boxed (value, icon->init_names); |
89 | 0 | break; |
90 | | |
91 | 0 | case PROP_USE_DEFAULT_FALLBACKS: |
92 | 0 | g_value_set_boolean (value, icon->use_default_fallbacks); |
93 | 0 | break; |
94 | | |
95 | 0 | default: |
96 | 0 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
97 | 0 | } |
98 | 0 | } |
99 | | |
100 | | static void |
101 | | g_themed_icon_set_property (GObject *object, |
102 | | guint prop_id, |
103 | | const GValue *value, |
104 | | GParamSpec *pspec) |
105 | 0 | { |
106 | 0 | GThemedIcon *icon = G_THEMED_ICON (object); |
107 | 0 | gchar **names; |
108 | 0 | const gchar *name; |
109 | |
|
110 | 0 | switch (prop_id) |
111 | 0 | { |
112 | 0 | case PROP_NAME: |
113 | 0 | name = g_value_get_string (value); |
114 | |
|
115 | 0 | if (!name) |
116 | 0 | break; |
117 | | |
118 | 0 | if (icon->init_names) |
119 | 0 | g_strfreev (icon->init_names); |
120 | |
|
121 | 0 | icon->init_names = g_new (char *, 2); |
122 | 0 | icon->init_names[0] = g_strdup (name); |
123 | 0 | icon->init_names[1] = NULL; |
124 | 0 | break; |
125 | | |
126 | 0 | case PROP_NAMES: |
127 | 0 | names = g_value_dup_boxed (value); |
128 | |
|
129 | 0 | if (!names) |
130 | 0 | break; |
131 | | |
132 | 0 | if (icon->init_names) |
133 | 0 | g_strfreev (icon->init_names); |
134 | |
|
135 | 0 | icon->init_names = names; |
136 | 0 | break; |
137 | | |
138 | 0 | case PROP_USE_DEFAULT_FALLBACKS: |
139 | 0 | icon->use_default_fallbacks = g_value_get_boolean (value); |
140 | 0 | break; |
141 | | |
142 | 0 | default: |
143 | 0 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
144 | 0 | } |
145 | 0 | } |
146 | | |
147 | | static void |
148 | | g_themed_icon_constructed (GObject *object) |
149 | 0 | { |
150 | 0 | g_themed_icon_update_names (G_THEMED_ICON (object)); |
151 | 0 | } |
152 | | |
153 | | static void |
154 | | g_themed_icon_finalize (GObject *object) |
155 | 0 | { |
156 | 0 | GThemedIcon *themed; |
157 | |
|
158 | 0 | themed = G_THEMED_ICON (object); |
159 | |
|
160 | 0 | g_strfreev (themed->init_names); |
161 | 0 | g_strfreev (themed->names); |
162 | |
|
163 | 0 | G_OBJECT_CLASS (g_themed_icon_parent_class)->finalize (object); |
164 | 0 | } |
165 | | |
166 | | static void |
167 | | g_themed_icon_class_init (GThemedIconClass *klass) |
168 | 0 | { |
169 | 0 | GObjectClass *gobject_class = G_OBJECT_CLASS (klass); |
170 | | |
171 | 0 | gobject_class->finalize = g_themed_icon_finalize; |
172 | 0 | gobject_class->constructed = g_themed_icon_constructed; |
173 | 0 | gobject_class->set_property = g_themed_icon_set_property; |
174 | 0 | gobject_class->get_property = g_themed_icon_get_property; |
175 | | |
176 | | /** |
177 | | * GThemedIcon:name: |
178 | | * |
179 | | * The icon name. |
180 | | */ |
181 | 0 | g_object_class_install_property (gobject_class, PROP_NAME, |
182 | 0 | g_param_spec_string ("name", NULL, NULL, |
183 | 0 | NULL, |
184 | 0 | G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK)); |
185 | | |
186 | | /** |
187 | | * GThemedIcon:names: |
188 | | * |
189 | | * A %NULL-terminated array of icon names. |
190 | | */ |
191 | 0 | g_object_class_install_property (gobject_class, PROP_NAMES, |
192 | 0 | g_param_spec_boxed ("names", NULL, NULL, |
193 | 0 | G_TYPE_STRV, |
194 | 0 | G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK)); |
195 | | |
196 | | /** |
197 | | * GThemedIcon:use-default-fallbacks: |
198 | | * |
199 | | * Whether to use the default fallbacks found by shortening the icon name |
200 | | * at '-' characters. If the "names" array has more than one element, |
201 | | * ignores any past the first. |
202 | | * |
203 | | * For example, if the icon name was "gnome-dev-cdrom-audio", the array |
204 | | * would become |
205 | | * |[<!-- language="C" --> |
206 | | * { |
207 | | * "gnome-dev-cdrom-audio", |
208 | | * "gnome-dev-cdrom", |
209 | | * "gnome-dev", |
210 | | * "gnome", |
211 | | * NULL |
212 | | * }; |
213 | | * ]| |
214 | | */ |
215 | 0 | g_object_class_install_property (gobject_class, PROP_USE_DEFAULT_FALLBACKS, |
216 | 0 | g_param_spec_boolean ("use-default-fallbacks", NULL, NULL, |
217 | 0 | FALSE, |
218 | 0 | G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK)); |
219 | 0 | } |
220 | | |
221 | | static void |
222 | | g_themed_icon_init (GThemedIcon *themed) |
223 | 0 | { |
224 | 0 | themed->init_names = NULL; |
225 | 0 | themed->names = NULL; |
226 | 0 | } |
227 | | |
228 | | /** |
229 | | * g_themed_icon_update_names: |
230 | | * @themed: a #GThemedIcon. |
231 | | * |
232 | | * Update the actual icon name list, based on the requested names (from |
233 | | * construction, or later added with g_themed_icon_prepend_name() and |
234 | | * g_themed_icon_append_name()). |
235 | | * The order of the list matters, indicating priority: |
236 | | * |
237 | | * - The first requested icon is first in priority. |
238 | | * - If "use-default-fallbacks" is #TRUE, then it is followed by all its |
239 | | * fallbacks (starting from top to lower context levels). |
240 | | * - Then next requested icons, and optionally their fallbacks, follow. |
241 | | * - Finally all the style variants (symbolic or regular, opposite to whatever |
242 | | * is the requested style) follow in the same order. |
243 | | * |
244 | | * An icon is not added twice in the list if it was previously added. |
245 | | * |
246 | | * For instance, if requested names are: |
247 | | * [ "some-icon-symbolic", "some-other-icon" ] |
248 | | * and use-default-fallbacks is TRUE, the final name list shall be: |
249 | | * [ "some-icon-symbolic", "some-symbolic", "some-other-icon", |
250 | | * "some-other", "some", "some-icon", "some-other-icon-symbolic", |
251 | | * "some-other-symbolic" ] |
252 | | * |
253 | | * Returns: (transfer full) (type GThemedIcon): a new #GThemedIcon |
254 | | **/ |
255 | | static void |
256 | | g_themed_icon_update_names (GThemedIcon *themed) |
257 | 0 | { |
258 | 0 | GList *names = NULL; |
259 | 0 | GList *variants = NULL; |
260 | 0 | GList *iter; |
261 | 0 | guint i; |
262 | |
|
263 | 0 | g_return_if_fail (themed->init_names != NULL && themed->init_names[0] != NULL); |
264 | | |
265 | 0 | for (i = 0; themed->init_names[i]; i++) |
266 | 0 | { |
267 | 0 | gchar *name; |
268 | 0 | gboolean is_symbolic; |
269 | |
|
270 | 0 | is_symbolic = g_str_has_suffix (themed->init_names[i], "-symbolic"); |
271 | 0 | if (is_symbolic) |
272 | 0 | name = g_strndup (themed->init_names[i], strlen (themed->init_names[i]) - 9); |
273 | 0 | else |
274 | 0 | name = g_strdup (themed->init_names[i]); |
275 | |
|
276 | 0 | if (g_list_find_custom (names, name, (GCompareFunc) g_strcmp0)) |
277 | 0 | { |
278 | 0 | g_free (name); |
279 | 0 | continue; |
280 | 0 | } |
281 | | |
282 | 0 | if (is_symbolic) |
283 | 0 | names = g_list_prepend (names, g_strdup (themed->init_names[i])); |
284 | 0 | else |
285 | 0 | names = g_list_prepend (names, name); |
286 | |
|
287 | 0 | if (themed->use_default_fallbacks) |
288 | 0 | { |
289 | 0 | char *dashp; |
290 | 0 | char *last; |
291 | |
|
292 | 0 | last = name; |
293 | |
|
294 | 0 | while ((dashp = strrchr (last, '-')) != NULL) |
295 | 0 | { |
296 | 0 | gchar *tmp = last; |
297 | 0 | gchar *fallback; |
298 | |
|
299 | 0 | last = g_strndup (last, (size_t) (dashp - last)); |
300 | 0 | if (is_symbolic) |
301 | 0 | { |
302 | 0 | g_free (tmp); |
303 | 0 | fallback = g_strdup_printf ("%s-symbolic", last); |
304 | 0 | } |
305 | 0 | else |
306 | 0 | fallback = last; |
307 | 0 | if (g_list_find_custom (names, fallback, (GCompareFunc) g_strcmp0)) |
308 | 0 | { |
309 | 0 | g_free (fallback); |
310 | 0 | break; |
311 | 0 | } |
312 | 0 | names = g_list_prepend (names, fallback); |
313 | 0 | } |
314 | 0 | if (is_symbolic) |
315 | 0 | g_free (last); |
316 | 0 | } |
317 | 0 | else if (is_symbolic) |
318 | 0 | g_free (name); |
319 | 0 | } |
320 | 0 | for (iter = names; iter; iter = iter->next) |
321 | 0 | { |
322 | 0 | gchar *name = (gchar *) iter->data; |
323 | 0 | gchar *variant; |
324 | 0 | gboolean is_symbolic; |
325 | |
|
326 | 0 | is_symbolic = g_str_has_suffix (name, "-symbolic"); |
327 | 0 | if (is_symbolic) |
328 | 0 | variant = g_strndup (name, strlen (name) - 9); |
329 | 0 | else |
330 | 0 | variant = g_strdup_printf ("%s-symbolic", name); |
331 | 0 | if (g_list_find_custom (names, variant, (GCompareFunc) g_strcmp0) || |
332 | 0 | g_list_find_custom (variants, variant, (GCompareFunc) g_strcmp0)) |
333 | 0 | { |
334 | 0 | g_free (variant); |
335 | 0 | continue; |
336 | 0 | } |
337 | | |
338 | 0 | variants = g_list_prepend (variants, variant); |
339 | 0 | } |
340 | 0 | names = g_list_reverse (names); |
341 | |
|
342 | 0 | g_strfreev (themed->names); |
343 | 0 | themed->names = g_new (char *, g_list_length (names) + g_list_length (variants) + 1); |
344 | |
|
345 | 0 | for (iter = names, i = 0; iter; iter = iter->next, i++) |
346 | 0 | themed->names[i] = iter->data; |
347 | 0 | for (iter = variants; iter; iter = iter->next, i++) |
348 | 0 | themed->names[i] = iter->data; |
349 | 0 | themed->names[i] = NULL; |
350 | |
|
351 | 0 | g_list_free (names); |
352 | 0 | g_list_free (variants); |
353 | |
|
354 | 0 | g_object_notify (G_OBJECT (themed), "names"); |
355 | 0 | } |
356 | | |
357 | | /** |
358 | | * g_themed_icon_new: |
359 | | * @iconname: a string containing an icon name. |
360 | | * |
361 | | * Creates a new themed icon for @iconname. |
362 | | * |
363 | | * Returns: (transfer full) (type GThemedIcon): a new #GThemedIcon. |
364 | | **/ |
365 | | GIcon * |
366 | | g_themed_icon_new (const char *iconname) |
367 | 0 | { |
368 | 0 | g_return_val_if_fail (iconname != NULL, NULL); |
369 | | |
370 | 0 | return G_ICON (g_object_new (G_TYPE_THEMED_ICON, "name", iconname, NULL)); |
371 | 0 | } |
372 | | |
373 | | /** |
374 | | * g_themed_icon_new_from_names: |
375 | | * @iconnames: (array length=len): an array of strings containing icon names. |
376 | | * @len: the length of the @iconnames array, or -1 if @iconnames is |
377 | | * %NULL-terminated |
378 | | * |
379 | | * Creates a new themed icon for @iconnames. |
380 | | * |
381 | | * Returns: (transfer full) (type GThemedIcon): a new #GThemedIcon |
382 | | **/ |
383 | | GIcon * |
384 | | g_themed_icon_new_from_names (char **iconnames, |
385 | | int len) |
386 | 0 | { |
387 | 0 | GIcon *icon; |
388 | |
|
389 | 0 | g_return_val_if_fail (iconnames != NULL, NULL); |
390 | | |
391 | 0 | if (len >= 0) |
392 | 0 | { |
393 | 0 | char **names; |
394 | 0 | size_t i; |
395 | |
|
396 | 0 | names = g_new (char *, (size_t) len + 1); |
397 | |
|
398 | 0 | for (i = 0; i < (size_t) len; i++) |
399 | 0 | names[i] = iconnames[i]; |
400 | |
|
401 | 0 | names[i] = NULL; |
402 | |
|
403 | 0 | icon = G_ICON (g_object_new (G_TYPE_THEMED_ICON, "names", names, NULL)); |
404 | |
|
405 | 0 | g_free (names); |
406 | 0 | } |
407 | 0 | else |
408 | 0 | icon = G_ICON (g_object_new (G_TYPE_THEMED_ICON, "names", iconnames, NULL)); |
409 | |
|
410 | 0 | return icon; |
411 | 0 | } |
412 | | |
413 | | /** |
414 | | * g_themed_icon_new_with_default_fallbacks: |
415 | | * @iconname: a string containing an icon name |
416 | | * |
417 | | * Creates a new themed icon for @iconname, and all the names |
418 | | * that can be created by shortening @iconname at '-' characters. |
419 | | * |
420 | | * In the following example, @icon1 and @icon2 are equivalent: |
421 | | * |[<!-- language="C" --> |
422 | | * const char *names[] = { |
423 | | * "gnome-dev-cdrom-audio", |
424 | | * "gnome-dev-cdrom", |
425 | | * "gnome-dev", |
426 | | * "gnome" |
427 | | * }; |
428 | | * |
429 | | * icon1 = g_themed_icon_new_from_names (names, 4); |
430 | | * icon2 = g_themed_icon_new_with_default_fallbacks ("gnome-dev-cdrom-audio"); |
431 | | * ]| |
432 | | * |
433 | | * Returns: (transfer full) (type GThemedIcon): a new #GThemedIcon. |
434 | | */ |
435 | | GIcon * |
436 | | g_themed_icon_new_with_default_fallbacks (const char *iconname) |
437 | 0 | { |
438 | 0 | g_return_val_if_fail (iconname != NULL, NULL); |
439 | | |
440 | 0 | return G_ICON (g_object_new (G_TYPE_THEMED_ICON, "name", iconname, "use-default-fallbacks", TRUE, NULL)); |
441 | 0 | } |
442 | | |
443 | | |
444 | | /** |
445 | | * g_themed_icon_get_names: |
446 | | * @icon: a #GThemedIcon. |
447 | | * |
448 | | * Gets the names of icons from within @icon. |
449 | | * |
450 | | * Returns: (transfer none): a list of icon names. |
451 | | */ |
452 | | const char * const * |
453 | | g_themed_icon_get_names (GThemedIcon *icon) |
454 | 0 | { |
455 | 0 | g_return_val_if_fail (G_IS_THEMED_ICON (icon), NULL); |
456 | 0 | return (const char * const *)icon->names; |
457 | 0 | } |
458 | | |
459 | | /** |
460 | | * g_themed_icon_append_name: |
461 | | * @icon: a #GThemedIcon |
462 | | * @iconname: name of icon to append to list of icons from within @icon. |
463 | | * |
464 | | * Append a name to the list of icons from within @icon. |
465 | | * |
466 | | * Note that doing so invalidates the hash computed by prior calls |
467 | | * to g_icon_hash(). |
468 | | */ |
469 | | void |
470 | | g_themed_icon_append_name (GThemedIcon *icon, |
471 | | const char *iconname) |
472 | 0 | { |
473 | 0 | guint num_names; |
474 | |
|
475 | 0 | g_return_if_fail (G_IS_THEMED_ICON (icon)); |
476 | 0 | g_return_if_fail (iconname != NULL); |
477 | | |
478 | 0 | num_names = g_strv_length (icon->init_names); |
479 | 0 | icon->init_names = g_realloc (icon->init_names, sizeof (char*) * (num_names + 2)); |
480 | 0 | icon->init_names[num_names] = g_strdup (iconname); |
481 | 0 | icon->init_names[num_names + 1] = NULL; |
482 | |
|
483 | 0 | g_themed_icon_update_names (icon); |
484 | 0 | } |
485 | | |
486 | | /** |
487 | | * g_themed_icon_prepend_name: |
488 | | * @icon: a #GThemedIcon |
489 | | * @iconname: name of icon to prepend to list of icons from within @icon. |
490 | | * |
491 | | * Prepend a name to the list of icons from within @icon. |
492 | | * |
493 | | * Note that doing so invalidates the hash computed by prior calls |
494 | | * to g_icon_hash(). |
495 | | * |
496 | | * Since: 2.18 |
497 | | */ |
498 | | void |
499 | | g_themed_icon_prepend_name (GThemedIcon *icon, |
500 | | const char *iconname) |
501 | 0 | { |
502 | 0 | guint num_names; |
503 | 0 | gchar **names; |
504 | 0 | gint i; |
505 | |
|
506 | 0 | g_return_if_fail (G_IS_THEMED_ICON (icon)); |
507 | 0 | g_return_if_fail (iconname != NULL); |
508 | | |
509 | 0 | num_names = g_strv_length (icon->init_names); |
510 | 0 | names = g_new (char*, num_names + 2); |
511 | 0 | for (i = 0; icon->init_names[i]; i++) |
512 | 0 | names[i + 1] = icon->init_names[i]; |
513 | 0 | names[0] = g_strdup (iconname); |
514 | 0 | names[num_names + 1] = NULL; |
515 | |
|
516 | 0 | g_free (icon->init_names); |
517 | 0 | icon->init_names = names; |
518 | |
|
519 | 0 | g_themed_icon_update_names (icon); |
520 | 0 | } |
521 | | |
522 | | static guint |
523 | | g_themed_icon_hash (GIcon *icon) |
524 | 0 | { |
525 | 0 | GThemedIcon *themed = G_THEMED_ICON (icon); |
526 | 0 | guint hash; |
527 | 0 | int i; |
528 | |
|
529 | 0 | hash = 0; |
530 | |
|
531 | 0 | for (i = 0; themed->names[i] != NULL; i++) |
532 | 0 | hash ^= g_str_hash (themed->names[i]); |
533 | | |
534 | 0 | return hash; |
535 | 0 | } |
536 | | |
537 | | static gboolean |
538 | | g_themed_icon_equal (GIcon *icon1, |
539 | | GIcon *icon2) |
540 | 0 | { |
541 | 0 | GThemedIcon *themed1 = G_THEMED_ICON (icon1); |
542 | 0 | GThemedIcon *themed2 = G_THEMED_ICON (icon2); |
543 | 0 | int i; |
544 | |
|
545 | 0 | for (i = 0; themed1->names[i] != NULL && themed2->names[i] != NULL; i++) |
546 | 0 | { |
547 | 0 | if (!g_str_equal (themed1->names[i], themed2->names[i])) |
548 | 0 | return FALSE; |
549 | 0 | } |
550 | | |
551 | 0 | return themed1->names[i] == NULL && themed2->names[i] == NULL; |
552 | 0 | } |
553 | | |
554 | | |
555 | | static gboolean |
556 | | g_themed_icon_to_tokens (GIcon *icon, |
557 | | GPtrArray *tokens, |
558 | | gint *out_version) |
559 | 0 | { |
560 | 0 | GThemedIcon *themed_icon = G_THEMED_ICON (icon); |
561 | 0 | int n; |
562 | |
|
563 | 0 | g_return_val_if_fail (out_version != NULL, FALSE); |
564 | | |
565 | 0 | *out_version = 0; |
566 | |
|
567 | 0 | for (n = 0; themed_icon->names[n] != NULL; n++) |
568 | 0 | g_ptr_array_add (tokens, |
569 | 0 | g_strdup (themed_icon->names[n])); |
570 | | |
571 | 0 | return TRUE; |
572 | 0 | } |
573 | | |
574 | | static GIcon * |
575 | | g_themed_icon_from_tokens (gchar **tokens, |
576 | | gint num_tokens, |
577 | | gint version, |
578 | | GError **error) |
579 | 0 | { |
580 | 0 | GIcon *icon; |
581 | 0 | gchar **names; |
582 | 0 | size_t n; |
583 | | |
584 | | /* This is guaranteed by the GIcon interface */ |
585 | 0 | g_assert (num_tokens >= 0); |
586 | | |
587 | 0 | icon = NULL; |
588 | |
|
589 | 0 | if (version != 0) |
590 | 0 | { |
591 | 0 | g_set_error (error, |
592 | 0 | G_IO_ERROR, |
593 | 0 | G_IO_ERROR_INVALID_ARGUMENT, |
594 | 0 | _("Can’t handle version %d of GThemedIcon encoding"), |
595 | 0 | version); |
596 | 0 | goto out; |
597 | 0 | } |
598 | | |
599 | 0 | names = g_new0 (gchar *, (size_t) num_tokens + 1); |
600 | 0 | for (n = 0; n < (size_t) num_tokens; n++) |
601 | 0 | names[n] = tokens[n]; |
602 | 0 | names[n] = NULL; |
603 | |
|
604 | 0 | icon = g_themed_icon_new_from_names (names, num_tokens); |
605 | 0 | g_free (names); |
606 | |
|
607 | 0 | out: |
608 | 0 | return icon; |
609 | 0 | } |
610 | | |
611 | | static GVariant * |
612 | | g_themed_icon_serialize (GIcon *icon) |
613 | 0 | { |
614 | 0 | GThemedIcon *themed_icon = G_THEMED_ICON (icon); |
615 | |
|
616 | 0 | return g_variant_new ("(sv)", "themed", g_variant_new ("^as", themed_icon->names)); |
617 | 0 | } |
618 | | |
619 | | static void |
620 | | g_themed_icon_icon_iface_init (GIconIface *iface) |
621 | 0 | { |
622 | 0 | iface->hash = g_themed_icon_hash; |
623 | 0 | iface->equal = g_themed_icon_equal; |
624 | 0 | iface->to_tokens = g_themed_icon_to_tokens; |
625 | 0 | iface->from_tokens = g_themed_icon_from_tokens; |
626 | 0 | iface->serialize = g_themed_icon_serialize; |
627 | 0 | } |