Coverage Report

Created: 2026-07-25 06:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/glib/gio/gicon.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
#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
0
#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
0
G_DEFINE_INTERFACE(GIcon, g_icon, G_TYPE_OBJECT)
80
0
81
0
static void
82
0
g_icon_default_init (GIconInterface *iface)
83
0
{
84
0
}
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
g_icon_hash (gconstpointer icon)
97
0
{
98
0
  GIconIface *iface;
99
100
0
  g_return_val_if_fail (G_IS_ICON (icon), 0);
101
102
0
  iface = G_ICON_GET_IFACE (icon);
103
104
0
  return (* iface->hash) ((GIcon *)icon);
105
0
}
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
g_icon_equal (GIcon *icon1,
118
        GIcon *icon2)
119
0
{
120
0
  GIconIface *iface;
121
122
0
  if (icon1 == NULL && icon2 == NULL)
123
0
    return TRUE;
124
125
0
  if (icon1 == NULL || icon2 == NULL)
126
0
    return FALSE;
127
  
128
0
  if (G_TYPE_FROM_INSTANCE (icon1) != G_TYPE_FROM_INSTANCE (icon2))
129
0
    return FALSE;
130
131
0
  iface = G_ICON_GET_IFACE (icon1);
132
  
133
0
  return (* iface->equal) (icon1, icon2);
134
0
}
135
136
static gboolean
137
g_icon_to_string_tokenized (GIcon *icon, GString *s)
138
0
{
139
0
  GPtrArray *tokens;
140
0
  gint version;
141
0
  GIconIface *icon_iface;
142
0
  guint i;
143
144
0
  g_return_val_if_fail (icon != NULL, FALSE);
145
0
  g_return_val_if_fail (G_IS_ICON (icon), FALSE);
146
147
0
  icon_iface = G_ICON_GET_IFACE (icon);
148
0
  if (icon_iface->to_tokens == NULL)
149
0
    return FALSE;
150
151
0
  tokens = g_ptr_array_new ();
152
0
  if (!icon_iface->to_tokens (icon, tokens, &version))
153
0
    {
154
0
      g_ptr_array_free (tokens, TRUE);
155
0
      return FALSE;
156
0
    }
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
0
  g_string_append (s, g_type_name_from_instance ((GTypeInstance *)icon));
163
0
  if (version != 0)
164
0
    g_string_append_printf (s, ".%d", version);
165
  
166
0
  for (i = 0; i < tokens->len; i++)
167
0
    {
168
0
      char *token;
169
170
0
      token = g_ptr_array_index (tokens, i);
171
172
0
      g_string_append_c (s, ' ');
173
      /* We really only need to escape spaces here, so allow lots of otherwise reserved chars */
174
0
      g_string_append_uri_escaped (s, token,
175
0
           G_URI_RESERVED_CHARS_ALLOWED_IN_PATH, TRUE);
176
177
0
      g_free (token);
178
0
    }
179
  
180
0
  g_ptr_array_free (tokens, TRUE);
181
  
182
0
  return TRUE;
183
0
}
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
g_icon_to_string (GIcon *icon)
213
0
{
214
0
  gchar *ret;
215
216
0
  g_return_val_if_fail (icon != NULL, NULL);
217
0
  g_return_val_if_fail (G_IS_ICON (icon), NULL);
218
219
0
  ret = NULL;
220
221
0
  if (G_IS_FILE_ICON (icon))
222
0
    {
223
0
      GFile *file;
224
225
0
      file = g_file_icon_get_file (G_FILE_ICON (icon));
226
0
      if (g_file_is_native (file))
227
0
  {
228
0
    ret = g_file_get_path (file);
229
0
    if (!g_utf8_validate (ret, -1, NULL))
230
0
      {
231
0
        g_free (ret);
232
0
        ret = NULL;
233
0
      }
234
0
  }
235
0
      else
236
0
        ret = g_file_get_uri (file);
237
0
    }
238
0
  else if (G_IS_THEMED_ICON (icon))
239
0
    {
240
0
      char     **names                 = NULL;
241
0
      gboolean   use_default_fallbacks = FALSE;
242
243
0
      g_object_get (G_OBJECT (icon),
244
0
                    "names",                 &names,
245
0
                    "use-default-fallbacks", &use_default_fallbacks,
246
0
                    NULL);
247
      /* Themed icon initialized with a single name and no fallbacks. */
248
0
      if (names != NULL &&
249
0
    names[0] != NULL &&
250
0
    names[0][0] != '.' && /* Allowing icons starting with dot would break G_ICON_SERIALIZATION_MAGIC0 */
251
0
    g_utf8_validate (names[0], -1, NULL) && /* Only return utf8 strings */
252
0
          names[1] == NULL &&
253
0
          ! use_default_fallbacks)
254
0
  ret = g_strdup (names[0]);
255
256
0
      g_strfreev (names);
257
0
    }
258
259
0
  if (ret == NULL)
260
0
    {
261
0
      GString *s;
262
263
0
      s = g_string_new (G_ICON_SERIALIZATION_MAGIC0);
264
265
0
      if (g_icon_to_string_tokenized (icon, s))
266
0
  ret = g_string_free (s, FALSE);
267
0
      else
268
0
  g_string_free (s, TRUE);
269
0
    }
270
271
0
  return ret;
272
0
}
273
274
static GIcon *
275
g_icon_new_from_tokens (char   **tokens,
276
      GError **error)
277
0
{
278
0
  GIcon *icon;
279
0
  char *typename, *version_str;
280
0
  GType type;
281
0
  gpointer klass;
282
0
  GIconIface *icon_iface;
283
0
  gint version;
284
0
  char *endp;
285
0
  unsigned int num_tokens;
286
0
  unsigned int i;
287
288
0
  icon = NULL;
289
0
  klass = NULL;
290
291
0
  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
0
  if (num_tokens < 1 || num_tokens > INT_MAX)
298
0
    {
299
0
      g_set_error (error,
300
0
                   G_IO_ERROR,
301
0
                   G_IO_ERROR_INVALID_ARGUMENT,
302
0
                   _("Wrong number of tokens (%d)"),
303
0
                   num_tokens);
304
0
      goto out;
305
0
    }
306
  
307
0
  typename = tokens[0];
308
0
  version_str = strchr (typename, '.');
309
0
  if (version_str)
310
0
    {
311
0
      *version_str = 0;
312
0
      version_str += 1;
313
0
    }
314
  
315
  
316
0
  type = g_type_from_name (tokens[0]);
317
0
  if (type == 0)
318
0
    {
319
0
      g_set_error (error,
320
0
                   G_IO_ERROR,
321
0
                   G_IO_ERROR_INVALID_ARGUMENT,
322
0
                   _("No type for class name %s"),
323
0
                   tokens[0]);
324
0
      goto out;
325
0
    }
326
327
0
  if (!g_type_is_a (type, G_TYPE_ICON))
328
0
    {
329
0
      g_set_error (error,
330
0
                   G_IO_ERROR,
331
0
                   G_IO_ERROR_INVALID_ARGUMENT,
332
0
                   _("Type %s does not implement the GIcon interface"),
333
0
                   tokens[0]);
334
0
      goto out;
335
0
    }
336
337
0
  klass = g_type_class_ref (type);
338
0
  if (klass == NULL)
339
0
    {
340
0
      g_set_error (error,
341
0
                   G_IO_ERROR,
342
0
                   G_IO_ERROR_INVALID_ARGUMENT,
343
0
                   _("Type %s is not classed"),
344
0
                   tokens[0]);
345
0
      goto out;
346
0
    }
347
348
0
  version = 0;
349
0
  if (version_str)
350
0
    {
351
0
      version = strtol (version_str, &endp, 10);
352
0
      if (endp == NULL || *endp != '\0')
353
0
  {
354
0
    g_set_error (error,
355
0
           G_IO_ERROR,
356
0
           G_IO_ERROR_INVALID_ARGUMENT,
357
0
           _("Malformed version number: %s"),
358
0
           version_str);
359
0
    goto out;
360
0
  }
361
0
    }
362
363
0
  icon_iface = g_type_interface_peek (klass, G_TYPE_ICON);
364
0
  g_assert (icon_iface != NULL);
365
366
0
  if (icon_iface->from_tokens == NULL)
367
0
    {
368
0
      g_set_error (error,
369
0
                   G_IO_ERROR,
370
0
                   G_IO_ERROR_INVALID_ARGUMENT,
371
0
                   _("Type %s does not implement from_tokens() on the GIcon interface"),
372
0
                   tokens[0]);
373
0
      goto out;
374
0
    }
375
376
0
  for (i = 1;  i < num_tokens; i++)
377
0
    {
378
0
      char *escaped;
379
380
0
      escaped = tokens[i];
381
0
      tokens[i] = g_uri_unescape_string (escaped, NULL);
382
0
      g_free (escaped);
383
0
    }
384
  
385
0
  icon = icon_iface->from_tokens (tokens + 1, (int) num_tokens - 1, version, error);
386
387
0
 out:
388
0
  if (klass != NULL)
389
0
    g_type_class_unref (klass);
390
0
  return icon;
391
0
}
392
393
static void
394
ensure_builtin_icon_types (void)
395
0
{
396
0
  g_type_ensure (G_TYPE_THEMED_ICON);
397
0
  g_type_ensure (G_TYPE_FILE_ICON);
398
0
  g_type_ensure (G_TYPE_EMBLEMED_ICON);
399
0
  g_type_ensure (G_TYPE_EMBLEM);
400
0
}
401
402
/* handles the 'simple' cases: GFileIcon and GThemedIcon */
403
static GIcon *
404
g_icon_new_for_string_simple (const gchar *str)
405
0
{
406
0
  gchar *scheme;
407
0
  GIcon *icon;
408
409
0
  if (str[0] == '.')
410
0
    return NULL;
411
412
  /* handle special GFileIcon and GThemedIcon cases */
413
0
  scheme = g_uri_parse_scheme (str);
414
0
  if (scheme != NULL || str[0] == '/' || str[0] == G_DIR_SEPARATOR)
415
0
    {
416
0
      GFile *location;
417
0
      location = g_file_new_for_commandline_arg (str);
418
0
      icon = g_file_icon_new (location);
419
0
      g_object_unref (location);
420
0
    }
421
0
  else
422
0
    icon = g_themed_icon_new (str);
423
424
0
  g_free (scheme);
425
426
0
  return icon;
427
0
}
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
g_icon_new_for_string (const gchar   *str,
448
                       GError       **error)
449
0
{
450
0
  GIcon *icon = NULL;
451
452
0
  g_return_val_if_fail (str != NULL, NULL);
453
454
0
  icon = g_icon_new_for_string_simple (str);
455
0
  if (icon)
456
0
    return icon;
457
458
0
  ensure_builtin_icon_types ();
459
460
0
  if (g_str_has_prefix (str, G_ICON_SERIALIZATION_MAGIC0))
461
0
    {
462
0
      gchar **tokens;
463
464
      /* handle tokenized encoding */
465
0
      tokens = g_strsplit (str + sizeof (G_ICON_SERIALIZATION_MAGIC0) - 1, " ", 0);
466
0
      icon = g_icon_new_from_tokens (tokens, error);
467
0
      g_strfreev (tokens);
468
0
    }
469
0
  else
470
0
    g_set_error_literal (error,
471
0
                         G_IO_ERROR,
472
0
                         G_IO_ERROR_INVALID_ARGUMENT,
473
0
                         _("Can’t handle the supplied version of the icon encoding"));
474
475
0
  return icon;
476
0
}
477
478
static GEmblem *
479
g_icon_deserialize_emblem (GVariant *value)
480
0
{
481
0
  GVariant *emblem_metadata;
482
0
  GVariant *emblem_data;
483
0
  const gchar *origin_nick;
484
0
  GIcon *emblem_icon;
485
0
  GEmblem *emblem;
486
487
0
  g_variant_get (value, "(v@a{sv})", &emblem_data, &emblem_metadata);
488
489
0
  emblem = NULL;
490
491
0
  emblem_icon = g_icon_deserialize (emblem_data);
492
0
  if (emblem_icon != NULL)
493
0
    {
494
      /* Check if we should create it with an origin. */
495
0
      if (g_variant_lookup (emblem_metadata, "origin", "&s", &origin_nick))
496
0
        {
497
0
          GEnumClass *origin_class;
498
0
          GEnumValue *origin_value;
499
500
0
          origin_class = g_type_class_ref (G_TYPE_EMBLEM_ORIGIN);
501
0
          origin_value = g_enum_get_value_by_nick (origin_class, origin_nick);
502
0
          if (origin_value)
503
0
            emblem = g_emblem_new_with_origin (emblem_icon, (GEmblemOrigin) origin_value->value);
504
0
          g_type_class_unref (origin_class);
505
0
        }
506
507
      /* We didn't create it with an origin, so do it without. */
508
0
      if (emblem == NULL)
509
0
        emblem = g_emblem_new (emblem_icon);
510
511
0
      g_object_unref (emblem_icon);
512
0
    }
513
514
0
  g_variant_unref (emblem_metadata);
515
0
  g_variant_unref (emblem_data);
516
517
0
  return emblem;
518
0
}
519
520
static GIcon *
521
g_icon_deserialize_emblemed (GVariant *value)
522
0
{
523
0
  GVariantIter *emblems;
524
0
  GVariant *icon_data;
525
0
  GIcon *main_icon;
526
0
  GIcon *icon;
527
528
0
  g_variant_get (value, "(va(va{sv}))", &icon_data, &emblems);
529
0
  main_icon = g_icon_deserialize (icon_data);
530
531
0
  if (main_icon)
532
0
    {
533
0
      GVariant *emblem_data;
534
535
0
      icon = g_emblemed_icon_new (main_icon, NULL);
536
537
0
      while ((emblem_data = g_variant_iter_next_value (emblems)))
538
0
        {
539
0
          GEmblem *emblem;
540
541
0
          emblem = g_icon_deserialize_emblem (emblem_data);
542
543
0
          if (emblem)
544
0
            {
545
0
              g_emblemed_icon_add_emblem (G_EMBLEMED_ICON (icon), emblem);
546
0
              g_object_unref (emblem);
547
0
            }
548
549
0
          g_variant_unref (emblem_data);
550
0
        }
551
552
0
      g_object_unref (main_icon);
553
0
    }
554
0
  else
555
0
    icon = NULL;
556
557
0
  g_variant_iter_free (emblems);
558
0
  g_variant_unref (icon_data);
559
560
0
  return icon;
561
0
}
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
g_icon_deserialize (GVariant *value)
575
0
{
576
0
  const gchar *tag;
577
0
  GVariant *val;
578
0
  GIcon *icon;
579
580
0
  g_return_val_if_fail (value != NULL, NULL);
581
0
  g_return_val_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE_STRING) ||
582
0
                        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
0
  if (g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
590
0
    return g_icon_new_for_string_simple (g_variant_get_string (value, NULL));
591
592
  /* Otherwise, use the tagged union format */
593
0
  g_variant_get (value, "(&sv)", &tag, &val);
594
595
0
  icon = NULL;
596
597
0
  if (g_str_equal (tag, "file") && g_variant_is_of_type (val, G_VARIANT_TYPE_STRING))
598
0
    {
599
0
      GFile *file;
600
601
0
      file = g_file_new_for_commandline_arg (g_variant_get_string (val, NULL));
602
0
      icon = g_file_icon_new (file);
603
0
      g_object_unref (file);
604
0
    }
605
0
  else if (g_str_equal (tag, "themed") && g_variant_is_of_type (val, G_VARIANT_TYPE_STRING_ARRAY))
606
0
    {
607
0
      const gchar **names;
608
0
      gsize size;
609
610
0
      names = g_variant_get_strv (val, &size);
611
0
      icon = g_themed_icon_new_from_names ((gchar **) names, size);
612
0
      g_free (names);
613
0
    }
614
0
  else if (g_str_equal (tag, "bytes") && g_variant_is_of_type (val, G_VARIANT_TYPE_BYTESTRING))
615
0
    {
616
0
      GBytes *bytes;
617
618
0
      bytes = g_variant_get_data_as_bytes (val);
619
0
      icon = g_bytes_icon_new (bytes);
620
0
      g_bytes_unref (bytes);
621
0
    }
622
0
  else if (g_str_equal (tag, "emblem") && g_variant_is_of_type (val, G_VARIANT_TYPE ("(va{sv})")))
623
0
    {
624
0
      GEmblem *emblem;
625
626
0
      emblem = g_icon_deserialize_emblem (val);
627
0
      if (emblem)
628
0
        icon = G_ICON (emblem);
629
0
    }
630
0
  else if (g_str_equal (tag, "emblemed") && g_variant_is_of_type (val, G_VARIANT_TYPE ("(va(va{sv}))")))
631
0
    {
632
0
      icon = g_icon_deserialize_emblemed (val);
633
0
    }
634
0
  else if (g_str_equal (tag, "gvfs"))
635
0
    {
636
0
      GVfsClass *class;
637
0
      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
0
    }
644
645
0
  g_variant_unref (val);
646
647
0
  return icon;
648
0
}
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
g_icon_serialize (GIcon *icon)
666
0
{
667
0
  GIconInterface *iface;
668
0
  GVariant *result;
669
670
0
  iface = G_ICON_GET_IFACE (icon);
671
672
0
  if (!iface->serialize)
673
0
    {
674
0
      g_critical ("g_icon_serialize() on icon type '%s' is not implemented", G_OBJECT_TYPE_NAME (icon));
675
0
      return NULL;
676
0
    }
677
678
0
  result = (* iface->serialize) (icon);
679
680
0
  if (result)
681
0
    {
682
0
      g_variant_take_ref (result);
683
684
0
      if (!g_variant_is_of_type (result, G_VARIANT_TYPE ("(sv)")))
685
0
        {
686
0
          g_critical ("g_icon_serialize() on icon type '%s' returned GVariant of type '%s' but it must return "
687
0
                      "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
0
        }
691
0
    }
692
693
0
  return result;
694
0
}