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 : 870 : 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 : 15 : 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 : : unsigned int num_tokens;
286 : : unsigned int i;
287 : :
288 : 15 : icon = NULL;
289 : 15 : klass = NULL;
290 : :
291 : 15 : num_tokens = g_strv_length (tokens);
292 : :
293 : : /* Unfortunately we have to set an upper bound on `num_tokens`, as
294 : : * `GIcon.from_tokens()` takes the number of tokens as an `int` (for
295 : : * historical reasons), and that can’t be changed (e.g. to `size_t`) without
296 : : * breaking API. */
297 : 15 : if (num_tokens < 1 || num_tokens > INT_MAX)
298 : : {
299 : 0 : g_set_error (error,
300 : : G_IO_ERROR,
301 : : G_IO_ERROR_INVALID_ARGUMENT,
302 : : _("Wrong number of tokens (%d)"),
303 : : num_tokens);
304 : 0 : goto out;
305 : : }
306 : :
307 : 15 : typename = tokens[0];
308 : 15 : version_str = strchr (typename, '.');
309 : 15 : if (version_str)
310 : : {
311 : 0 : *version_str = 0;
312 : 0 : version_str += 1;
313 : : }
314 : :
315 : :
316 : 15 : type = g_type_from_name (tokens[0]);
317 : 15 : if (type == 0)
318 : : {
319 : 0 : g_set_error (error,
320 : : G_IO_ERROR,
321 : : G_IO_ERROR_INVALID_ARGUMENT,
322 : : _("No type for class name %s"),
323 : : tokens[0]);
324 : 0 : goto out;
325 : : }
326 : :
327 : 15 : if (!g_type_is_a (type, G_TYPE_ICON))
328 : : {
329 : 0 : g_set_error (error,
330 : : G_IO_ERROR,
331 : : G_IO_ERROR_INVALID_ARGUMENT,
332 : : _("Type %s does not implement the GIcon interface"),
333 : : tokens[0]);
334 : 0 : goto out;
335 : : }
336 : :
337 : 15 : klass = g_type_class_ref (type);
338 : 15 : if (klass == NULL)
339 : : {
340 : 0 : g_set_error (error,
341 : : G_IO_ERROR,
342 : : G_IO_ERROR_INVALID_ARGUMENT,
343 : : _("Type %s is not classed"),
344 : : tokens[0]);
345 : 0 : goto out;
346 : : }
347 : :
348 : 15 : version = 0;
349 : 15 : if (version_str)
350 : : {
351 : 0 : version = strtol (version_str, &endp, 10);
352 : 0 : if (endp == NULL || *endp != '\0')
353 : : {
354 : 0 : g_set_error (error,
355 : : G_IO_ERROR,
356 : : G_IO_ERROR_INVALID_ARGUMENT,
357 : : _("Malformed version number: %s"),
358 : : version_str);
359 : 0 : goto out;
360 : : }
361 : : }
362 : :
363 : 15 : icon_iface = g_type_interface_peek (klass, G_TYPE_ICON);
364 : 15 : g_assert (icon_iface != NULL);
365 : :
366 : 15 : if (icon_iface->from_tokens == NULL)
367 : : {
368 : 0 : g_set_error (error,
369 : : G_IO_ERROR,
370 : : G_IO_ERROR_INVALID_ARGUMENT,
371 : : _("Type %s does not implement from_tokens() on the GIcon interface"),
372 : : tokens[0]);
373 : 0 : goto out;
374 : : }
375 : :
376 : 64 : for (i = 1; i < num_tokens; i++)
377 : : {
378 : : char *escaped;
379 : :
380 : 49 : escaped = tokens[i];
381 : 49 : tokens[i] = g_uri_unescape_string (escaped, NULL);
382 : 49 : g_free (escaped);
383 : : }
384 : :
385 : 15 : icon = icon_iface->from_tokens (tokens + 1, (int) num_tokens - 1, version, error);
386 : :
387 : 15 : out:
388 : 15 : if (klass != NULL)
389 : 15 : g_type_class_unref (klass);
390 : 15 : return icon;
391 : : }
392 : :
393 : : static void
394 : 16 : ensure_builtin_icon_types (void)
395 : : {
396 : 16 : g_type_ensure (G_TYPE_THEMED_ICON);
397 : 16 : g_type_ensure (G_TYPE_FILE_ICON);
398 : 16 : g_type_ensure (G_TYPE_EMBLEMED_ICON);
399 : 16 : g_type_ensure (G_TYPE_EMBLEM);
400 : 16 : }
401 : :
402 : : /* handles the 'simple' cases: GFileIcon and GThemedIcon */
403 : : static GIcon *
404 : 37 : g_icon_new_for_string_simple (const gchar *str)
405 : : {
406 : : gchar *scheme;
407 : : GIcon *icon;
408 : :
409 : 37 : if (str[0] == '.')
410 : 16 : return NULL;
411 : :
412 : : /* handle special GFileIcon and GThemedIcon cases */
413 : 21 : scheme = g_uri_parse_scheme (str);
414 : 21 : if (scheme != NULL || str[0] == '/' || str[0] == G_DIR_SEPARATOR)
415 : 11 : {
416 : : GFile *location;
417 : 11 : location = g_file_new_for_commandline_arg (str);
418 : 11 : icon = g_file_icon_new (location);
419 : 11 : g_object_unref (location);
420 : : }
421 : : else
422 : 10 : icon = g_themed_icon_new (str);
423 : :
424 : 21 : g_free (scheme);
425 : :
426 : 21 : return icon;
427 : : }
428 : :
429 : : /**
430 : : * g_icon_new_for_string:
431 : : * @str: A string obtained via g_icon_to_string().
432 : : * @error: Return location for error.
433 : : *
434 : : * Generate a #GIcon instance from @str. This function can fail if
435 : : * @str is not valid - see g_icon_to_string() for discussion.
436 : : *
437 : : * If your application or library provides one or more #GIcon
438 : : * implementations you need to ensure that each #GType is registered
439 : : * with the type system prior to calling g_icon_new_for_string().
440 : : *
441 : : * Returns: (transfer full): An object implementing the #GIcon
442 : : * interface or %NULL if @error is set.
443 : : *
444 : : * Since: 2.20
445 : : **/
446 : : GIcon *
447 : 33 : g_icon_new_for_string (const gchar *str,
448 : : GError **error)
449 : : {
450 : 33 : GIcon *icon = NULL;
451 : :
452 : 33 : g_return_val_if_fail (str != NULL, NULL);
453 : :
454 : 33 : icon = g_icon_new_for_string_simple (str);
455 : 33 : if (icon)
456 : 17 : return icon;
457 : :
458 : 16 : ensure_builtin_icon_types ();
459 : :
460 : 16 : if (g_str_has_prefix (str, G_ICON_SERIALIZATION_MAGIC0))
461 : : {
462 : : gchar **tokens;
463 : :
464 : : /* handle tokenized encoding */
465 : 15 : tokens = g_strsplit (str + sizeof (G_ICON_SERIALIZATION_MAGIC0) - 1, " ", 0);
466 : 15 : icon = g_icon_new_from_tokens (tokens, error);
467 : 15 : g_strfreev (tokens);
468 : : }
469 : : else
470 : 1 : g_set_error_literal (error,
471 : : G_IO_ERROR,
472 : : G_IO_ERROR_INVALID_ARGUMENT,
473 : : _("Can’t handle the supplied version of the icon encoding"));
474 : :
475 : 16 : return icon;
476 : : }
477 : :
478 : : static GEmblem *
479 : 4 : g_icon_deserialize_emblem (GVariant *value)
480 : : {
481 : : GVariant *emblem_metadata;
482 : : GVariant *emblem_data;
483 : : const gchar *origin_nick;
484 : : GIcon *emblem_icon;
485 : : GEmblem *emblem;
486 : :
487 : 4 : g_variant_get (value, "(v@a{sv})", &emblem_data, &emblem_metadata);
488 : :
489 : 4 : emblem = NULL;
490 : :
491 : 4 : emblem_icon = g_icon_deserialize (emblem_data);
492 : 4 : if (emblem_icon != NULL)
493 : : {
494 : : /* Check if we should create it with an origin. */
495 : 4 : if (g_variant_lookup (emblem_metadata, "origin", "&s", &origin_nick))
496 : : {
497 : : GEnumClass *origin_class;
498 : : GEnumValue *origin_value;
499 : :
500 : 4 : origin_class = g_type_class_ref (G_TYPE_EMBLEM_ORIGIN);
501 : 4 : origin_value = g_enum_get_value_by_nick (origin_class, origin_nick);
502 : 4 : if (origin_value)
503 : 4 : emblem = g_emblem_new_with_origin (emblem_icon, (GEmblemOrigin) origin_value->value);
504 : 4 : g_type_class_unref (origin_class);
505 : : }
506 : :
507 : : /* We didn't create it with an origin, so do it without. */
508 : 4 : if (emblem == NULL)
509 : 0 : emblem = g_emblem_new (emblem_icon);
510 : :
511 : 4 : g_object_unref (emblem_icon);
512 : : }
513 : :
514 : 4 : g_variant_unref (emblem_metadata);
515 : 4 : g_variant_unref (emblem_data);
516 : :
517 : 4 : return emblem;
518 : : }
519 : :
520 : : static GIcon *
521 : 2 : g_icon_deserialize_emblemed (GVariant *value)
522 : : {
523 : : GVariantIter *emblems;
524 : : GVariant *icon_data;
525 : : GIcon *main_icon;
526 : : GIcon *icon;
527 : :
528 : 2 : g_variant_get (value, "(va(va{sv}))", &icon_data, &emblems);
529 : 2 : main_icon = g_icon_deserialize (icon_data);
530 : :
531 : 2 : if (main_icon)
532 : : {
533 : : GVariant *emblem_data;
534 : :
535 : 2 : icon = g_emblemed_icon_new (main_icon, NULL);
536 : :
537 : 6 : while ((emblem_data = g_variant_iter_next_value (emblems)))
538 : : {
539 : : GEmblem *emblem;
540 : :
541 : 4 : emblem = g_icon_deserialize_emblem (emblem_data);
542 : :
543 : 4 : if (emblem)
544 : : {
545 : 4 : g_emblemed_icon_add_emblem (G_EMBLEMED_ICON (icon), emblem);
546 : 4 : g_object_unref (emblem);
547 : : }
548 : :
549 : 4 : g_variant_unref (emblem_data);
550 : : }
551 : :
552 : 2 : g_object_unref (main_icon);
553 : : }
554 : : else
555 : 0 : icon = NULL;
556 : :
557 : 2 : g_variant_iter_free (emblems);
558 : 2 : g_variant_unref (icon_data);
559 : :
560 : 2 : return icon;
561 : : }
562 : :
563 : : /**
564 : : * g_icon_deserialize:
565 : : * @value: (transfer none): a #GVariant created with g_icon_serialize()
566 : : *
567 : : * Deserializes a #GIcon previously serialized using g_icon_serialize().
568 : : *
569 : : * Returns: (nullable) (transfer full): a #GIcon, or %NULL when deserialization fails.
570 : : *
571 : : * Since: 2.38
572 : : */
573 : : GIcon *
574 : 18 : g_icon_deserialize (GVariant *value)
575 : : {
576 : : const gchar *tag;
577 : : GVariant *val;
578 : : GIcon *icon;
579 : :
580 : 18 : g_return_val_if_fail (value != NULL, NULL);
581 : 18 : g_return_val_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE_STRING) ||
582 : : g_variant_is_of_type (value, G_VARIANT_TYPE ("(sv)")), NULL);
583 : :
584 : : /* Handle some special cases directly so that people can hard-code
585 : : * stuff into GMenuModel xml files without resorting to using GVariant
586 : : * text format to describe one of the explicitly-tagged possibilities
587 : : * below.
588 : : */
589 : 18 : if (g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
590 : 4 : return g_icon_new_for_string_simple (g_variant_get_string (value, NULL));
591 : :
592 : : /* Otherwise, use the tagged union format */
593 : 14 : g_variant_get (value, "(&sv)", &tag, &val);
594 : :
595 : 14 : icon = NULL;
596 : :
597 : 14 : if (g_str_equal (tag, "file") && g_variant_is_of_type (val, G_VARIANT_TYPE_STRING))
598 : 2 : {
599 : : GFile *file;
600 : :
601 : 2 : file = g_file_new_for_commandline_arg (g_variant_get_string (val, NULL));
602 : 2 : icon = g_file_icon_new (file);
603 : 2 : g_object_unref (file);
604 : : }
605 : 12 : else if (g_str_equal (tag, "themed") && g_variant_is_of_type (val, G_VARIANT_TYPE_STRING_ARRAY))
606 : 9 : {
607 : : const gchar **names;
608 : : gsize size;
609 : :
610 : 9 : names = g_variant_get_strv (val, &size);
611 : 9 : icon = g_themed_icon_new_from_names ((gchar **) names, size);
612 : 9 : g_free (names);
613 : : }
614 : 3 : else if (g_str_equal (tag, "bytes") && g_variant_is_of_type (val, G_VARIANT_TYPE_BYTESTRING))
615 : 1 : {
616 : : GBytes *bytes;
617 : :
618 : 1 : bytes = g_variant_get_data_as_bytes (val);
619 : 1 : icon = g_bytes_icon_new (bytes);
620 : 1 : g_bytes_unref (bytes);
621 : : }
622 : 2 : else if (g_str_equal (tag, "emblem") && g_variant_is_of_type (val, G_VARIANT_TYPE ("(va{sv})")))
623 : 0 : {
624 : : GEmblem *emblem;
625 : :
626 : 0 : emblem = g_icon_deserialize_emblem (val);
627 : 0 : if (emblem)
628 : 0 : icon = G_ICON (emblem);
629 : : }
630 : 2 : else if (g_str_equal (tag, "emblemed") && g_variant_is_of_type (val, G_VARIANT_TYPE ("(va(va{sv}))")))
631 : : {
632 : 2 : icon = g_icon_deserialize_emblemed (val);
633 : : }
634 : 0 : else if (g_str_equal (tag, "gvfs"))
635 : : {
636 : : GVfsClass *class;
637 : : GVfs *vfs;
638 : :
639 : 0 : vfs = g_vfs_get_default ();
640 : 0 : class = G_VFS_GET_CLASS (vfs);
641 : 0 : if (class->deserialize_icon)
642 : 0 : icon = (* class->deserialize_icon) (vfs, val);
643 : : }
644 : :
645 : 14 : g_variant_unref (val);
646 : :
647 : 14 : return icon;
648 : : }
649 : :
650 : : /**
651 : : * g_icon_serialize: (virtual serialize)
652 : : * @icon: a #GIcon
653 : : *
654 : : * Serializes a #GIcon into a #GVariant. An equivalent #GIcon can be retrieved
655 : : * back by calling g_icon_deserialize() on the returned value.
656 : : * As serialization will avoid using raw icon data when possible, it only
657 : : * makes sense to transfer the #GVariant between processes on the same machine,
658 : : * (as opposed to over the network), and within the same file system namespace.
659 : : *
660 : : * Returns: (nullable) (transfer full): a #GVariant, or %NULL when serialization fails. The #GVariant will not be floating.
661 : : *
662 : : * Since: 2.38
663 : : */
664 : : GVariant *
665 : 21 : g_icon_serialize (GIcon *icon)
666 : : {
667 : : GIconInterface *iface;
668 : : GVariant *result;
669 : :
670 : 21 : iface = G_ICON_GET_IFACE (icon);
671 : :
672 : 21 : if (!iface->serialize)
673 : : {
674 : 0 : g_critical ("g_icon_serialize() on icon type '%s' is not implemented", G_OBJECT_TYPE_NAME (icon));
675 : 0 : return NULL;
676 : : }
677 : :
678 : 21 : result = (* iface->serialize) (icon);
679 : :
680 : 21 : if (result)
681 : : {
682 : 21 : g_variant_take_ref (result);
683 : :
684 : 21 : if (!g_variant_is_of_type (result, G_VARIANT_TYPE ("(sv)")))
685 : : {
686 : 0 : g_critical ("g_icon_serialize() on icon type '%s' returned GVariant of type '%s' but it must return "
687 : : "one with type '(sv)'", G_OBJECT_TYPE_NAME (icon), g_variant_get_type_string (result));
688 : 0 : g_variant_unref (result);
689 : 0 : result = NULL;
690 : : }
691 : : }
692 : :
693 : 21 : return result;
694 : : }
|