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