LCOV - code coverage report
Current view: top level - gio - gicon.c (source / functions) Coverage Total Hit
Test: unnamed Lines: 80.5 % 221 178
Test Date: 2024-11-26 05:23:01 Functions: 100.0 % 14 14
Branches: - 0 0

             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                 :             : }
        

Generated by: LCOV version 2.0-1