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