Branch data Line data Source code
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 : : #include <stdlib.h>
25 : : #include <string.h>
26 : :
27 : : #include "gicon.h"
28 : : #include "gthemedicon.h"
29 : : #include "gfileicon.h"
30 : : #include "gemblemedicon.h"
31 : : #include "gbytesicon.h"
32 : : #include "gfile.h"
33 : : #include "gioerror.h"
34 : : #include "gioenumtypes.h"
35 : : #include "gvfs.h"
36 : :
37 : : #include "glibintl.h"
38 : :
39 : :
40 : : /* There versioning of this is implicit, version 1 would be ".1 " */
41 : : #define G_ICON_SERIALIZATION_MAGIC0 ". "
42 : :
43 : : /**
44 : : * GIcon:
45 : : *
46 : : * `GIcon` is a very minimal interface for icons. It provides functions
47 : : * for checking the equality of two icons, hashing of icons and
48 : : * serializing an icon to and from strings.
49 : : *
50 : : * `GIcon` does not provide the actual pixmap for the icon as this is out
51 : : * of GIO's scope, however implementations of `GIcon` may contain the name
52 : : * of an icon (see [class@Gio.ThemedIcon]), or the path to an icon
53 : : * (see [iface@Gio.LoadableIcon]).
54 : : *
55 : : * To obtain a hash of a `GIcon`, see [method@Gio.Icon.hash].
56 : : *
57 : : * To check if two `GIcon`s are equal, see [method@Gio.Icon.equal].
58 : : *
59 : : * For serializing a `GIcon`, use [method@Gio.Icon.serialize] and
60 : : * [func@Gio.Icon.deserialize].
61 : : *
62 : : * If you want to consume `GIcon` (for example, in a toolkit) you must
63 : : * be prepared to handle at least the three following cases:
64 : : * [iface@Gio.LoadableIcon], [class@Gio.ThemedIcon] and [class@Gio.EmblemedIcon].
65 : : * It may also make sense to have fast-paths for other cases (like handling
66 : : * [`GdkPixbuf`](https://docs.gtk.org/gdk-pixbuf/class.Pixbuf.html) directly,
67 : : * for example) but all compliant `GIcon` implementations outside of GIO must
68 : : * implement [iface@Gio.LoadableIcon].
69 : : *
70 : : * If your application or library provides one or more `GIcon`
71 : : * implementations you need to ensure that your new implementation also
72 : : * implements [iface@Gio.LoadableIcon]. Additionally, you must provide an
73 : : * implementation of [method@Gio.Icon.serialize] that gives a result that is
74 : : * understood by [func@Gio.Icon.deserialize], yielding one of the built-in
75 : : * icon types.
76 : : **/
77 : :
78 : : typedef GIconIface GIconInterface;
79 : 834 : G_DEFINE_INTERFACE(GIcon, g_icon, G_TYPE_OBJECT)
80 : :
81 : : static void
82 : 27 : g_icon_default_init (GIconInterface *iface)
83 : : {
84 : 27 : }
85 : :
86 : : /**
87 : : * g_icon_hash: (virtual hash)
88 : : * @icon: (not nullable) (type Gio.Icon): #gconstpointer to an icon object.
89 : : *
90 : : * Gets a hash for an icon.
91 : : *
92 : : * Returns: a #guint containing a hash for the @icon, suitable for
93 : : * use in a #GHashTable or similar data structure.
94 : : **/
95 : : guint
96 : 44 : g_icon_hash (gconstpointer icon)
97 : : {
98 : : GIconIface *iface;
99 : :
100 : 44 : g_return_val_if_fail (G_IS_ICON (icon), 0);
101 : :
102 : 44 : iface = G_ICON_GET_IFACE (icon);
103 : :
104 : 44 : return (* iface->hash) ((GIcon *)icon);
105 : : }
106 : :
107 : : /**
108 : : * g_icon_equal: (virtual equal)
109 : : * @icon1: (nullable): pointer to the first #GIcon.
110 : : * @icon2: (nullable): pointer to the second #GIcon.
111 : : *
112 : : * Checks if two icons are equal.
113 : : *
114 : : * Returns: %TRUE if @icon1 is equal to @icon2. %FALSE otherwise.
115 : : **/
116 : : gboolean
117 : 51 : g_icon_equal (GIcon *icon1,
118 : : GIcon *icon2)
119 : : {
120 : : GIconIface *iface;
121 : :
122 : 51 : if (icon1 == NULL && icon2 == NULL)
123 : 0 : return TRUE;
124 : :
125 : 51 : if (icon1 == NULL || icon2 == NULL)
126 : 0 : return FALSE;
127 : :
128 : 51 : if (G_TYPE_FROM_INSTANCE (icon1) != G_TYPE_FROM_INSTANCE (icon2))
129 : 0 : return FALSE;
130 : :
131 : 51 : iface = G_ICON_GET_IFACE (icon1);
132 : :
133 : 51 : return (* iface->equal) (icon1, icon2);
134 : : }
135 : :
136 : : static gboolean
137 : 18 : g_icon_to_string_tokenized (GIcon *icon, GString *s)
138 : : {
139 : : GPtrArray *tokens;
140 : : gint version;
141 : : GIconIface *icon_iface;
142 : : guint i;
143 : :
144 : 18 : g_return_val_if_fail (icon != NULL, FALSE);
145 : 18 : g_return_val_if_fail (G_IS_ICON (icon), FALSE);
146 : :
147 : 18 : icon_iface = G_ICON_GET_IFACE (icon);
148 : 18 : if (icon_iface->to_tokens == NULL)
149 : 0 : return FALSE;
150 : :
151 : 18 : tokens = g_ptr_array_new ();
152 : 18 : if (!icon_iface->to_tokens (icon, tokens, &version))
153 : : {
154 : 0 : g_ptr_array_free (tokens, TRUE);
155 : 0 : return FALSE;
156 : : }
157 : :
158 : : /* format: TypeName[.Version] <token_0> .. <token_N-1>
159 : : version 0 is implicit and can be omitted
160 : : all the tokens are url escaped to ensure they have no spaces in them */
161 : :
162 : 18 : g_string_append (s, g_type_name_from_instance ((GTypeInstance *)icon));
163 : 18 : if (version != 0)
164 : 0 : g_string_append_printf (s, ".%d", version);
165 : :
166 : 111 : for (i = 0; i < tokens->len; i++)
167 : : {
168 : : char *token;
169 : :
170 : 93 : token = g_ptr_array_index (tokens, i);
171 : :
172 : : g_string_append_c (s, ' ');
173 : : /* We really only need to escape spaces here, so allow lots of otherwise reserved chars */
174 : 93 : g_string_append_uri_escaped (s, token,
175 : : G_URI_RESERVED_CHARS_ALLOWED_IN_PATH, TRUE);
176 : :
177 : 93 : g_free (token);
178 : : }
179 : :
180 : 18 : g_ptr_array_free (tokens, TRUE);
181 : :
182 : 18 : return TRUE;
183 : : }
184 : :
185 : : /**
186 : : * g_icon_to_string:
187 : : * @icon: a #GIcon.
188 : : *
189 : : * Generates a textual representation of @icon that can be used for
190 : : * serialization such as when passing @icon to a different process or
191 : : * saving it to persistent storage. Use g_icon_new_for_string() to
192 : : * get @icon back from the returned string.
193 : : *
194 : : * The encoding of the returned string is proprietary to #GIcon except
195 : : * in the following two cases
196 : : *
197 : : * - If @icon is a #GFileIcon, the returned string is a native path
198 : : * (such as `/path/to/my icon.png`) without escaping
199 : : * if the #GFile for @icon is a native file. If the file is not
200 : : * native, the returned string is the result of g_file_get_uri()
201 : : * (such as `sftp://path/to/my%20icon.png`).
202 : : *
203 : : * - If @icon is a #GThemedIcon with exactly one name and no fallbacks,
204 : : * the encoding is simply the name (such as `network-server`).
205 : : *
206 : : * Returns: (nullable): An allocated NUL-terminated UTF8 string or
207 : : * %NULL if @icon can't be serialized. Use g_free() to free.
208 : : *
209 : : * Since: 2.20
210 : : */
211 : : gchar *
212 : 27 : g_icon_to_string (GIcon *icon)
213 : : {
214 : : gchar *ret;
215 : :
216 : 27 : g_return_val_if_fail (icon != NULL, NULL);
217 : 27 : g_return_val_if_fail (G_IS_ICON (icon), NULL);
218 : :
219 : 27 : ret = NULL;
220 : :
221 : 27 : if (G_IS_FILE_ICON (icon))
222 : : {
223 : : GFile *file;
224 : :
225 : 7 : file = g_file_icon_get_file (G_FILE_ICON (icon));
226 : 7 : if (g_file_is_native (file))
227 : : {
228 : 5 : ret = g_file_get_path (file);
229 : 5 : if (!g_utf8_validate (ret, -1, NULL))
230 : : {
231 : 0 : g_free (ret);
232 : 0 : ret = NULL;
233 : : }
234 : : }
235 : : else
236 : 2 : ret = g_file_get_uri (file);
237 : : }
238 : 20 : else if (G_IS_THEMED_ICON (icon))
239 : : {
240 : 17 : char **names = NULL;
241 : 17 : gboolean use_default_fallbacks = FALSE;
242 : :
243 : 17 : g_object_get (G_OBJECT (icon),
244 : : "names", &names,
245 : : "use-default-fallbacks", &use_default_fallbacks,
246 : : NULL);
247 : : /* Themed icon initialized with a single name and no fallbacks. */
248 : 17 : if (names != NULL &&
249 : 17 : names[0] != NULL &&
250 : 34 : names[0][0] != '.' && /* Allowing icons starting with dot would break G_ICON_SERIALIZATION_MAGIC0 */
251 : 17 : g_utf8_validate (names[0], -1, NULL) && /* Only return utf8 strings */
252 : 17 : names[1] == NULL &&
253 : 11 : ! use_default_fallbacks)
254 : 4 : ret = g_strdup (names[0]);
255 : :
256 : 17 : g_strfreev (names);
257 : : }
258 : :
259 : 27 : if (ret == NULL)
260 : : {
261 : : GString *s;
262 : :
263 : 18 : s = g_string_new (G_ICON_SERIALIZATION_MAGIC0);
264 : :
265 : 18 : if (g_icon_to_string_tokenized (icon, s))
266 : 18 : ret = g_string_free (s, FALSE);
267 : : else
268 : 0 : g_string_free (s, TRUE);
269 : : }
270 : :
271 : 27 : return ret;
272 : : }
273 : :
274 : : static GIcon *
275 : 9 : g_icon_new_from_tokens (char **tokens,
276 : : GError **error)
277 : : {
278 : : GIcon *icon;
279 : : char *typename, *version_str;
280 : : GType type;
281 : : gpointer klass;
282 : : GIconIface *icon_iface;
283 : : gint version;
284 : : char *endp;
285 : : int num_tokens;
286 : : int i;
287 : :
288 : 9 : icon = NULL;
289 : 9 : klass = NULL;
290 : :
291 : 9 : num_tokens = g_strv_length (tokens);
292 : :
293 : 9 : if (num_tokens < 1)
294 : : {
295 : 0 : g_set_error (error,
296 : : G_IO_ERROR,
297 : : G_IO_ERROR_INVALID_ARGUMENT,
298 : : _("Wrong number of tokens (%d)"),
299 : : num_tokens);
300 : 0 : goto out;
301 : : }
302 : :
303 : 9 : typename = tokens[0];
304 : 9 : version_str = strchr (typename, '.');
305 : 9 : if (version_str)
306 : : {
307 : 0 : *version_str = 0;
308 : 0 : version_str += 1;
309 : : }
310 : :
311 : :
312 : 9 : type = g_type_from_name (tokens[0]);
313 : 9 : if (type == 0)
314 : : {
315 : 0 : g_set_error (error,
316 : : G_IO_ERROR,
317 : : G_IO_ERROR_INVALID_ARGUMENT,
318 : : _("No type for class name %s"),
319 : : tokens[0]);
320 : 0 : goto out;
321 : : }
322 : :
323 : 9 : if (!g_type_is_a (type, G_TYPE_ICON))
324 : : {
325 : 0 : g_set_error (error,
326 : : G_IO_ERROR,
327 : : G_IO_ERROR_INVALID_ARGUMENT,
328 : : _("Type %s does not implement the GIcon interface"),
329 : : tokens[0]);
330 : 0 : goto out;
331 : : }
332 : :
333 : 9 : klass = g_type_class_ref (type);
334 : 9 : if (klass == NULL)
335 : : {
336 : 0 : g_set_error (error,
337 : : G_IO_ERROR,
338 : : G_IO_ERROR_INVALID_ARGUMENT,
339 : : _("Type %s is not classed"),
340 : : tokens[0]);
341 : 0 : goto out;
342 : : }
343 : :
344 : 9 : version = 0;
345 : 9 : if (version_str)
346 : : {
347 : 0 : version = strtol (version_str, &endp, 10);
348 : 0 : if (endp == NULL || *endp != '\0')
349 : : {
350 : 0 : g_set_error (error,
351 : : G_IO_ERROR,
352 : : G_IO_ERROR_INVALID_ARGUMENT,
353 : : _("Malformed version number: %s"),
354 : : version_str);
355 : 0 : goto out;
356 : : }
357 : : }
358 : :
359 : 9 : icon_iface = g_type_interface_peek (klass, G_TYPE_ICON);
360 : 9 : g_assert (icon_iface != NULL);
361 : :
362 : 9 : if (icon_iface->from_tokens == NULL)
363 : : {
364 : 0 : g_set_error (error,
365 : : G_IO_ERROR,
366 : : G_IO_ERROR_INVALID_ARGUMENT,
367 : : _("Type %s does not implement from_tokens() on the GIcon interface"),
368 : : tokens[0]);
369 : 0 : goto out;
370 : : }
371 : :
372 : 46 : for (i = 1; i < num_tokens; i++)
373 : : {
374 : : char *escaped;
375 : :
376 : 37 : escaped = tokens[i];
377 : 37 : tokens[i] = g_uri_unescape_string (escaped, NULL);
378 : 37 : g_free (escaped);
379 : : }
380 : :
381 : 9 : icon = icon_iface->from_tokens (tokens + 1, num_tokens - 1, version, error);
382 : :
383 : 9 : out:
384 : 9 : if (klass != NULL)
385 : 9 : g_type_class_unref (klass);
386 : 9 : return icon;
387 : : }
388 : :
389 : : static void
390 : 9 : ensure_builtin_icon_types (void)
391 : : {
392 : 9 : g_type_ensure (G_TYPE_THEMED_ICON);
393 : 9 : g_type_ensure (G_TYPE_FILE_ICON);
394 : 9 : g_type_ensure (G_TYPE_EMBLEMED_ICON);
395 : 9 : g_type_ensure (G_TYPE_EMBLEM);
396 : 9 : }
397 : :
398 : : /* handles the 'simple' cases: GFileIcon and GThemedIcon */
399 : : static GIcon *
400 : 24 : g_icon_new_for_string_simple (const gchar *str)
401 : : {
402 : : gchar *scheme;
403 : : GIcon *icon;
404 : :
405 : 24 : if (str[0] == '.')
406 : 9 : return NULL;
407 : :
408 : : /* handle special GFileIcon and GThemedIcon cases */
409 : 15 : scheme = g_uri_parse_scheme (str);
410 : 15 : if (scheme != NULL || str[0] == '/' || str[0] == G_DIR_SEPARATOR)
411 : 11 : {
412 : : GFile *location;
413 : 11 : location = g_file_new_for_commandline_arg (str);
414 : 11 : icon = g_file_icon_new (location);
415 : 11 : g_object_unref (location);
416 : : }
417 : : else
418 : 4 : icon = g_themed_icon_new (str);
419 : :
420 : 15 : g_free (scheme);
421 : :
422 : 15 : return icon;
423 : : }
424 : :
425 : : /**
426 : : * g_icon_new_for_string:
427 : : * @str: A string obtained via g_icon_to_string().
428 : : * @error: Return location for error.
429 : : *
430 : : * Generate a #GIcon instance from @str. This function can fail if
431 : : * @str is not valid - see g_icon_to_string() for discussion.
432 : : *
433 : : * If your application or library provides one or more #GIcon
434 : : * implementations you need to ensure that each #GType is registered
435 : : * with the type system prior to calling g_icon_new_for_string().
436 : : *
437 : : * Returns: (transfer full): An object implementing the #GIcon
438 : : * interface or %NULL if @error is set.
439 : : *
440 : : * Since: 2.20
441 : : **/
442 : : GIcon *
443 : 20 : g_icon_new_for_string (const gchar *str,
444 : : GError **error)
445 : : {
446 : 20 : GIcon *icon = NULL;
447 : :
448 : 20 : g_return_val_if_fail (str != NULL, NULL);
449 : :
450 : 20 : icon = g_icon_new_for_string_simple (str);
451 : 20 : if (icon)
452 : 11 : return icon;
453 : :
454 : 9 : ensure_builtin_icon_types ();
455 : :
456 : 9 : if (g_str_has_prefix (str, G_ICON_SERIALIZATION_MAGIC0))
457 : : {
458 : : gchar **tokens;
459 : :
460 : : /* handle tokenized encoding */
461 : 9 : tokens = g_strsplit (str + sizeof (G_ICON_SERIALIZATION_MAGIC0) - 1, " ", 0);
462 : 9 : icon = g_icon_new_from_tokens (tokens, error);
463 : 9 : g_strfreev (tokens);
464 : : }
465 : : else
466 : 0 : g_set_error_literal (error,
467 : : G_IO_ERROR,
468 : : G_IO_ERROR_INVALID_ARGUMENT,
469 : : _("Can’t handle the supplied version of the icon encoding"));
470 : :
471 : 9 : return icon;
472 : : }
473 : :
474 : : static GEmblem *
475 : 4 : g_icon_deserialize_emblem (GVariant *value)
476 : : {
477 : : GVariant *emblem_metadata;
478 : : GVariant *emblem_data;
479 : : const gchar *origin_nick;
480 : : GIcon *emblem_icon;
481 : : GEmblem *emblem;
482 : :
483 : 4 : g_variant_get (value, "(v@a{sv})", &emblem_data, &emblem_metadata);
484 : :
485 : 4 : emblem = NULL;
486 : :
487 : 4 : emblem_icon = g_icon_deserialize (emblem_data);
488 : 4 : if (emblem_icon != NULL)
489 : : {
490 : : /* Check if we should create it with an origin. */
491 : 4 : if (g_variant_lookup (emblem_metadata, "origin", "&s", &origin_nick))
492 : : {
493 : : GEnumClass *origin_class;
494 : : GEnumValue *origin_value;
495 : :
496 : 4 : origin_class = g_type_class_ref (G_TYPE_EMBLEM_ORIGIN);
497 : 4 : origin_value = g_enum_get_value_by_nick (origin_class, origin_nick);
498 : 4 : if (origin_value)
499 : 4 : emblem = g_emblem_new_with_origin (emblem_icon, origin_value->value);
500 : 4 : g_type_class_unref (origin_class);
501 : : }
502 : :
503 : : /* We didn't create it with an origin, so do it without. */
504 : 4 : if (emblem == NULL)
505 : 0 : emblem = g_emblem_new (emblem_icon);
506 : :
507 : 4 : g_object_unref (emblem_icon);
508 : : }
509 : :
510 : 4 : g_variant_unref (emblem_metadata);
511 : 4 : g_variant_unref (emblem_data);
512 : :
513 : 4 : return emblem;
514 : : }
515 : :
516 : : static GIcon *
517 : 2 : g_icon_deserialize_emblemed (GVariant *value)
518 : : {
519 : : GVariantIter *emblems;
520 : : GVariant *icon_data;
521 : : GIcon *main_icon;
522 : : GIcon *icon;
523 : :
524 : 2 : g_variant_get (value, "(va(va{sv}))", &icon_data, &emblems);
525 : 2 : main_icon = g_icon_deserialize (icon_data);
526 : :
527 : 2 : if (main_icon)
528 : : {
529 : : GVariant *emblem_data;
530 : :
531 : 2 : icon = g_emblemed_icon_new (main_icon, NULL);
532 : :
533 : 6 : while ((emblem_data = g_variant_iter_next_value (emblems)))
534 : : {
535 : : GEmblem *emblem;
536 : :
537 : 4 : emblem = g_icon_deserialize_emblem (emblem_data);
538 : :
539 : 4 : if (emblem)
540 : : {
541 : 4 : g_emblemed_icon_add_emblem (G_EMBLEMED_ICON (icon), emblem);
542 : 4 : g_object_unref (emblem);
543 : : }
544 : :
545 : 4 : g_variant_unref (emblem_data);
546 : : }
547 : :
548 : 2 : g_object_unref (main_icon);
549 : : }
550 : : else
551 : 0 : icon = NULL;
552 : :
553 : 2 : g_variant_iter_free (emblems);
554 : 2 : g_variant_unref (icon_data);
555 : :
556 : 2 : return icon;
557 : : }
558 : :
559 : : /**
560 : : * g_icon_deserialize:
561 : : * @value: (transfer none): a #GVariant created with g_icon_serialize()
562 : : *
563 : : * Deserializes a #GIcon previously serialized using g_icon_serialize().
564 : : *
565 : : * Returns: (nullable) (transfer full): a #GIcon, or %NULL when deserialization fails.
566 : : *
567 : : * Since: 2.38
568 : : */
569 : : GIcon *
570 : 18 : g_icon_deserialize (GVariant *value)
571 : : {
572 : : const gchar *tag;
573 : : GVariant *val;
574 : : GIcon *icon;
575 : :
576 : 18 : g_return_val_if_fail (value != NULL, NULL);
577 : 18 : g_return_val_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE_STRING) ||
578 : : g_variant_is_of_type (value, G_VARIANT_TYPE ("(sv)")), NULL);
579 : :
580 : : /* Handle some special cases directly so that people can hard-code
581 : : * stuff into GMenuModel xml files without resorting to using GVariant
582 : : * text format to describe one of the explicitly-tagged possibilities
583 : : * below.
584 : : */
585 : 18 : if (g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
586 : 4 : return g_icon_new_for_string_simple (g_variant_get_string (value, NULL));
587 : :
588 : : /* Otherwise, use the tagged union format */
589 : 14 : g_variant_get (value, "(&sv)", &tag, &val);
590 : :
591 : 14 : icon = NULL;
592 : :
593 : 14 : if (g_str_equal (tag, "file") && g_variant_is_of_type (val, G_VARIANT_TYPE_STRING))
594 : 2 : {
595 : : GFile *file;
596 : :
597 : 2 : file = g_file_new_for_commandline_arg (g_variant_get_string (val, NULL));
598 : 2 : icon = g_file_icon_new (file);
599 : 2 : g_object_unref (file);
600 : : }
601 : 12 : else if (g_str_equal (tag, "themed") && g_variant_is_of_type (val, G_VARIANT_TYPE_STRING_ARRAY))
602 : 9 : {
603 : : const gchar **names;
604 : : gsize size;
605 : :
606 : 9 : names = g_variant_get_strv (val, &size);
607 : 9 : icon = g_themed_icon_new_from_names ((gchar **) names, size);
608 : 9 : g_free (names);
609 : : }
610 : 3 : else if (g_str_equal (tag, "bytes") && g_variant_is_of_type (val, G_VARIANT_TYPE_BYTESTRING))
611 : 1 : {
612 : : GBytes *bytes;
613 : :
614 : 1 : bytes = g_variant_get_data_as_bytes (val);
615 : 1 : icon = g_bytes_icon_new (bytes);
616 : 1 : g_bytes_unref (bytes);
617 : : }
618 : 2 : else if (g_str_equal (tag, "emblem") && g_variant_is_of_type (val, G_VARIANT_TYPE ("(va{sv})")))
619 : 0 : {
620 : : GEmblem *emblem;
621 : :
622 : 0 : emblem = g_icon_deserialize_emblem (val);
623 : 0 : if (emblem)
624 : 0 : icon = G_ICON (emblem);
625 : : }
626 : 2 : else if (g_str_equal (tag, "emblemed") && g_variant_is_of_type (val, G_VARIANT_TYPE ("(va(va{sv}))")))
627 : : {
628 : 2 : icon = g_icon_deserialize_emblemed (val);
629 : : }
630 : 0 : else if (g_str_equal (tag, "gvfs"))
631 : : {
632 : : GVfsClass *class;
633 : : GVfs *vfs;
634 : :
635 : 0 : vfs = g_vfs_get_default ();
636 : 0 : class = G_VFS_GET_CLASS (vfs);
637 : 0 : if (class->deserialize_icon)
638 : 0 : icon = (* class->deserialize_icon) (vfs, val);
639 : : }
640 : :
641 : 14 : g_variant_unref (val);
642 : :
643 : 14 : return icon;
644 : : }
645 : :
646 : : /**
647 : : * g_icon_serialize: (virtual serialize)
648 : : * @icon: a #GIcon
649 : : *
650 : : * Serializes a #GIcon into a #GVariant. An equivalent #GIcon can be retrieved
651 : : * back by calling g_icon_deserialize() on the returned value.
652 : : * As serialization will avoid using raw icon data when possible, it only
653 : : * makes sense to transfer the #GVariant between processes on the same machine,
654 : : * (as opposed to over the network), and within the same file system namespace.
655 : : *
656 : : * Returns: (nullable) (transfer full): a #GVariant, or %NULL when serialization fails. The #GVariant will not be floating.
657 : : *
658 : : * Since: 2.38
659 : : */
660 : : GVariant *
661 : 21 : g_icon_serialize (GIcon *icon)
662 : : {
663 : : GIconInterface *iface;
664 : : GVariant *result;
665 : :
666 : 21 : iface = G_ICON_GET_IFACE (icon);
667 : :
668 : 21 : if (!iface->serialize)
669 : : {
670 : 0 : g_critical ("g_icon_serialize() on icon type '%s' is not implemented", G_OBJECT_TYPE_NAME (icon));
671 : 0 : return NULL;
672 : : }
673 : :
674 : 21 : result = (* iface->serialize) (icon);
675 : :
676 : 21 : if (result)
677 : : {
678 : 21 : g_variant_take_ref (result);
679 : :
680 : 21 : if (!g_variant_is_of_type (result, G_VARIANT_TYPE ("(sv)")))
681 : : {
682 : 0 : g_critical ("g_icon_serialize() on icon type '%s' returned GVariant of type '%s' but it must return "
683 : : "one with type '(sv)'", G_OBJECT_TYPE_NAME (icon), g_variant_get_type_string (result));
684 : 0 : g_variant_unref (result);
685 : 0 : result = NULL;
686 : : }
687 : : }
688 : :
689 : 21 : return result;
690 : : }
|