Coverage Report

Created: 2026-04-10 07:07

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