Coverage Report

Created: 2025-07-11 06:47

/src/tinysparql/subprojects/glib-2.80.3/gio/gicon.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
#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
G_DEFINE_INTERFACE(GIcon, g_icon, G_TYPE_OBJECT)
80
81
static void
82
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
  int num_tokens;
286
0
  int i;
287
288
0
  icon = NULL;
289
0
  klass = NULL;
290
291
0
  num_tokens = g_strv_length (tokens);
292
293
0
  if (num_tokens < 1)
294
0
    {
295
0
      g_set_error (error,
296
0
                   G_IO_ERROR,
297
0
                   G_IO_ERROR_INVALID_ARGUMENT,
298
0
                   _("Wrong number of tokens (%d)"),
299
0
                   num_tokens);
300
0
      goto out;
301
0
    }
302
  
303
0
  typename = tokens[0];
304
0
  version_str = strchr (typename, '.');
305
0
  if (version_str)
306
0
    {
307
0
      *version_str = 0;
308
0
      version_str += 1;
309
0
    }
310
  
311
  
312
0
  type = g_type_from_name (tokens[0]);
313
0
  if (type == 0)
314
0
    {
315
0
      g_set_error (error,
316
0
                   G_IO_ERROR,
317
0
                   G_IO_ERROR_INVALID_ARGUMENT,
318
0
                   _("No type for class name %s"),
319
0
                   tokens[0]);
320
0
      goto out;
321
0
    }
322
323
0
  if (!g_type_is_a (type, G_TYPE_ICON))
324
0
    {
325
0
      g_set_error (error,
326
0
                   G_IO_ERROR,
327
0
                   G_IO_ERROR_INVALID_ARGUMENT,
328
0
                   _("Type %s does not implement the GIcon interface"),
329
0
                   tokens[0]);
330
0
      goto out;
331
0
    }
332
333
0
  klass = g_type_class_ref (type);
334
0
  if (klass == NULL)
335
0
    {
336
0
      g_set_error (error,
337
0
                   G_IO_ERROR,
338
0
                   G_IO_ERROR_INVALID_ARGUMENT,
339
0
                   _("Type %s is not classed"),
340
0
                   tokens[0]);
341
0
      goto out;
342
0
    }
343
344
0
  version = 0;
345
0
  if (version_str)
346
0
    {
347
0
      version = strtol (version_str, &endp, 10);
348
0
      if (endp == NULL || *endp != '\0')
349
0
  {
350
0
    g_set_error (error,
351
0
           G_IO_ERROR,
352
0
           G_IO_ERROR_INVALID_ARGUMENT,
353
0
           _("Malformed version number: %s"),
354
0
           version_str);
355
0
    goto out;
356
0
  }
357
0
    }
358
359
0
  icon_iface = g_type_interface_peek (klass, G_TYPE_ICON);
360
0
  g_assert (icon_iface != NULL);
361
362
0
  if (icon_iface->from_tokens == NULL)
363
0
    {
364
0
      g_set_error (error,
365
0
                   G_IO_ERROR,
366
0
                   G_IO_ERROR_INVALID_ARGUMENT,
367
0
                   _("Type %s does not implement from_tokens() on the GIcon interface"),
368
0
                   tokens[0]);
369
0
      goto out;
370
0
    }
371
372
0
  for (i = 1;  i < num_tokens; i++)
373
0
    {
374
0
      char *escaped;
375
376
0
      escaped = tokens[i];
377
0
      tokens[i] = g_uri_unescape_string (escaped, NULL);
378
0
      g_free (escaped);
379
0
    }
380
  
381
0
  icon = icon_iface->from_tokens (tokens + 1, num_tokens - 1, version, error);
382
383
0
 out:
384
0
  if (klass != NULL)
385
0
    g_type_class_unref (klass);
386
0
  return icon;
387
0
}
388
389
static void
390
ensure_builtin_icon_types (void)
391
0
{
392
0
  g_type_ensure (G_TYPE_THEMED_ICON);
393
0
  g_type_ensure (G_TYPE_FILE_ICON);
394
0
  g_type_ensure (G_TYPE_EMBLEMED_ICON);
395
0
  g_type_ensure (G_TYPE_EMBLEM);
396
0
}
397
398
/* handles the 'simple' cases: GFileIcon and GThemedIcon */
399
static GIcon *
400
g_icon_new_for_string_simple (const gchar *str)
401
0
{
402
0
  gchar *scheme;
403
0
  GIcon *icon;
404
405
0
  if (str[0] == '.')
406
0
    return NULL;
407
408
  /* handle special GFileIcon and GThemedIcon cases */
409
0
  scheme = g_uri_parse_scheme (str);
410
0
  if (scheme != NULL || str[0] == '/' || str[0] == G_DIR_SEPARATOR)
411
0
    {
412
0
      GFile *location;
413
0
      location = g_file_new_for_commandline_arg (str);
414
0
      icon = g_file_icon_new (location);
415
0
      g_object_unref (location);
416
0
    }
417
0
  else
418
0
    icon = g_themed_icon_new (str);
419
420
0
  g_free (scheme);
421
422
0
  return icon;
423
0
}
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
g_icon_new_for_string (const gchar   *str,
444
                       GError       **error)
445
0
{
446
0
  GIcon *icon = NULL;
447
448
0
  g_return_val_if_fail (str != NULL, NULL);
449
450
0
  icon = g_icon_new_for_string_simple (str);
451
0
  if (icon)
452
0
    return icon;
453
454
0
  ensure_builtin_icon_types ();
455
456
0
  if (g_str_has_prefix (str, G_ICON_SERIALIZATION_MAGIC0))
457
0
    {
458
0
      gchar **tokens;
459
460
      /* handle tokenized encoding */
461
0
      tokens = g_strsplit (str + sizeof (G_ICON_SERIALIZATION_MAGIC0) - 1, " ", 0);
462
0
      icon = g_icon_new_from_tokens (tokens, error);
463
0
      g_strfreev (tokens);
464
0
    }
465
0
  else
466
0
    g_set_error_literal (error,
467
0
                         G_IO_ERROR,
468
0
                         G_IO_ERROR_INVALID_ARGUMENT,
469
0
                         _("Can’t handle the supplied version of the icon encoding"));
470
471
0
  return icon;
472
0
}
473
474
static GEmblem *
475
g_icon_deserialize_emblem (GVariant *value)
476
0
{
477
0
  GVariant *emblem_metadata;
478
0
  GVariant *emblem_data;
479
0
  const gchar *origin_nick;
480
0
  GIcon *emblem_icon;
481
0
  GEmblem *emblem;
482
483
0
  g_variant_get (value, "(v@a{sv})", &emblem_data, &emblem_metadata);
484
485
0
  emblem = NULL;
486
487
0
  emblem_icon = g_icon_deserialize (emblem_data);
488
0
  if (emblem_icon != NULL)
489
0
    {
490
      /* Check if we should create it with an origin. */
491
0
      if (g_variant_lookup (emblem_metadata, "origin", "&s", &origin_nick))
492
0
        {
493
0
          GEnumClass *origin_class;
494
0
          GEnumValue *origin_value;
495
496
0
          origin_class = g_type_class_ref (G_TYPE_EMBLEM_ORIGIN);
497
0
          origin_value = g_enum_get_value_by_nick (origin_class, origin_nick);
498
0
          if (origin_value)
499
0
            emblem = g_emblem_new_with_origin (emblem_icon, origin_value->value);
500
0
          g_type_class_unref (origin_class);
501
0
        }
502
503
      /* We didn't create it with an origin, so do it without. */
504
0
      if (emblem == NULL)
505
0
        emblem = g_emblem_new (emblem_icon);
506
507
0
      g_object_unref (emblem_icon);
508
0
    }
509
510
0
  g_variant_unref (emblem_metadata);
511
0
  g_variant_unref (emblem_data);
512
513
0
  return emblem;
514
0
}
515
516
static GIcon *
517
g_icon_deserialize_emblemed (GVariant *value)
518
0
{
519
0
  GVariantIter *emblems;
520
0
  GVariant *icon_data;
521
0
  GIcon *main_icon;
522
0
  GIcon *icon;
523
524
0
  g_variant_get (value, "(va(va{sv}))", &icon_data, &emblems);
525
0
  main_icon = g_icon_deserialize (icon_data);
526
527
0
  if (main_icon)
528
0
    {
529
0
      GVariant *emblem_data;
530
531
0
      icon = g_emblemed_icon_new (main_icon, NULL);
532
533
0
      while ((emblem_data = g_variant_iter_next_value (emblems)))
534
0
        {
535
0
          GEmblem *emblem;
536
537
0
          emblem = g_icon_deserialize_emblem (emblem_data);
538
539
0
          if (emblem)
540
0
            {
541
0
              g_emblemed_icon_add_emblem (G_EMBLEMED_ICON (icon), emblem);
542
0
              g_object_unref (emblem);
543
0
            }
544
545
0
          g_variant_unref (emblem_data);
546
0
        }
547
548
0
      g_object_unref (main_icon);
549
0
    }
550
0
  else
551
0
    icon = NULL;
552
553
0
  g_variant_iter_free (emblems);
554
0
  g_variant_unref (icon_data);
555
556
0
  return icon;
557
0
}
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
g_icon_deserialize (GVariant *value)
571
0
{
572
0
  const gchar *tag;
573
0
  GVariant *val;
574
0
  GIcon *icon;
575
576
0
  g_return_val_if_fail (value != NULL, NULL);
577
0
  g_return_val_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE_STRING) ||
578
0
                        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
0
  if (g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
586
0
    return g_icon_new_for_string_simple (g_variant_get_string (value, NULL));
587
588
  /* Otherwise, use the tagged union format */
589
0
  g_variant_get (value, "(&sv)", &tag, &val);
590
591
0
  icon = NULL;
592
593
0
  if (g_str_equal (tag, "file") && g_variant_is_of_type (val, G_VARIANT_TYPE_STRING))
594
0
    {
595
0
      GFile *file;
596
597
0
      file = g_file_new_for_commandline_arg (g_variant_get_string (val, NULL));
598
0
      icon = g_file_icon_new (file);
599
0
      g_object_unref (file);
600
0
    }
601
0
  else if (g_str_equal (tag, "themed") && g_variant_is_of_type (val, G_VARIANT_TYPE_STRING_ARRAY))
602
0
    {
603
0
      const gchar **names;
604
0
      gsize size;
605
606
0
      names = g_variant_get_strv (val, &size);
607
0
      icon = g_themed_icon_new_from_names ((gchar **) names, size);
608
0
      g_free (names);
609
0
    }
610
0
  else if (g_str_equal (tag, "bytes") && g_variant_is_of_type (val, G_VARIANT_TYPE_BYTESTRING))
611
0
    {
612
0
      GBytes *bytes;
613
614
0
      bytes = g_variant_get_data_as_bytes (val);
615
0
      icon = g_bytes_icon_new (bytes);
616
0
      g_bytes_unref (bytes);
617
0
    }
618
0
  else if (g_str_equal (tag, "emblem") && g_variant_is_of_type (val, G_VARIANT_TYPE ("(va{sv})")))
619
0
    {
620
0
      GEmblem *emblem;
621
622
0
      emblem = g_icon_deserialize_emblem (val);
623
0
      if (emblem)
624
0
        icon = G_ICON (emblem);
625
0
    }
626
0
  else if (g_str_equal (tag, "emblemed") && g_variant_is_of_type (val, G_VARIANT_TYPE ("(va(va{sv}))")))
627
0
    {
628
0
      icon = g_icon_deserialize_emblemed (val);
629
0
    }
630
0
  else if (g_str_equal (tag, "gvfs"))
631
0
    {
632
0
      GVfsClass *class;
633
0
      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
0
    }
640
641
0
  g_variant_unref (val);
642
643
0
  return icon;
644
0
}
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
g_icon_serialize (GIcon *icon)
662
0
{
663
0
  GIconInterface *iface;
664
0
  GVariant *result;
665
666
0
  iface = G_ICON_GET_IFACE (icon);
667
668
0
  if (!iface->serialize)
669
0
    {
670
0
      g_critical ("g_icon_serialize() on icon type '%s' is not implemented", G_OBJECT_TYPE_NAME (icon));
671
0
      return NULL;
672
0
    }
673
674
0
  result = (* iface->serialize) (icon);
675
676
0
  if (result)
677
0
    {
678
0
      g_variant_take_ref (result);
679
680
0
      if (!g_variant_is_of_type (result, G_VARIANT_TYPE ("(sv)")))
681
0
        {
682
0
          g_critical ("g_icon_serialize() on icon type '%s' returned GVariant of type '%s' but it must return "
683
0
                      "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
0
        }
687
0
    }
688
689
0
  return result;
690
0
}