LCOV - code coverage report
Current view: top level - glib/gio - gicon.c (source / functions) Hit Total Coverage
Test: unnamed Lines: 178 221 80.5 %
Date: 2024-04-16 05:15:53 Functions: 14 14 100.0 %
Branches: 90 152 59.2 %

           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   [ +  +  +  -  :        798 : G_DEFINE_INTERFACE(GIcon, g_icon, G_TYPE_OBJECT)
                   +  + ]
      80                 :            : 
      81                 :            : static void
      82                 :         26 : g_icon_default_init (GIconInterface *iface)
      83                 :            : {
      84                 :         26 : }
      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                 :         10 : 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                 :         10 :   g_return_val_if_fail (icon != NULL, FALSE);
     145                 :         10 :   g_return_val_if_fail (G_IS_ICON (icon), FALSE);
     146                 :            : 
     147                 :         10 :   icon_iface = G_ICON_GET_IFACE (icon);
     148         [ -  + ]:         10 :   if (icon_iface->to_tokens == NULL)
     149                 :          0 :     return FALSE;
     150                 :            : 
     151                 :         10 :   tokens = g_ptr_array_new ();
     152         [ -  + ]:         10 :   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                 :         10 :   g_string_append (s, g_type_name_from_instance ((GTypeInstance *)icon));
     163         [ -  + ]:         10 :   if (version != 0)
     164                 :          0 :     g_string_append_printf (s, ".%d", version);
     165                 :            :   
     166         [ +  + ]:         55 :   for (i = 0; i < tokens->len; i++)
     167                 :            :     {
     168                 :            :       char *token;
     169                 :            : 
     170         [ +  - ]:         45 :       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                 :         45 :       g_string_append_uri_escaped (s, token,
     175                 :            :                                    G_URI_RESERVED_CHARS_ALLOWED_IN_PATH, TRUE);
     176                 :            : 
     177                 :         45 :       g_free (token);
     178                 :            :     }
     179                 :            :   
     180                 :         10 :   g_ptr_array_free (tokens, TRUE);
     181                 :            :   
     182                 :         10 :   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                 :         19 : g_icon_to_string (GIcon *icon)
     213                 :            : {
     214                 :            :   gchar *ret;
     215                 :            : 
     216                 :         19 :   g_return_val_if_fail (icon != NULL, NULL);
     217                 :         19 :   g_return_val_if_fail (G_IS_ICON (icon), NULL);
     218                 :            : 
     219                 :         19 :   ret = NULL;
     220                 :            : 
     221   [ -  +  +  -  :         19 :   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   [ -  +  +  -  :         12 :   else if (G_IS_THEMED_ICON (icon))
             +  +  +  + ]
     239                 :            :     {
     240                 :          9 :       char     **names                 = NULL;
     241                 :          9 :       gboolean   use_default_fallbacks = FALSE;
     242                 :            : 
     243                 :          9 :       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         [ +  - ]:          9 :       if (names != NULL &&
     249         [ +  - ]:          9 :           names[0] != NULL &&
     250   [ +  -  +  - ]:         18 :           names[0][0] != '.' && /* Allowing icons starting with dot would break G_ICON_SERIALIZATION_MAGIC0 */
     251                 :          9 :           g_utf8_validate (names[0], -1, NULL) && /* Only return utf8 strings */
     252         [ +  + ]:          9 :           names[1] == NULL &&
     253         [ +  + ]:          3 :           ! use_default_fallbacks)
     254                 :          4 :         ret = g_strdup (names[0]);
     255                 :            : 
     256                 :          9 :       g_strfreev (names);
     257                 :            :     }
     258                 :            : 
     259         [ +  + ]:         19 :   if (ret == NULL)
     260                 :            :     {
     261                 :            :       GString *s;
     262                 :            : 
     263                 :         10 :       s = g_string_new (G_ICON_SERIALIZATION_MAGIC0);
     264                 :            : 
     265         [ +  - ]:         10 :       if (g_icon_to_string_tokenized (icon, s))
     266                 :         10 :         ret = g_string_free (s, FALSE);
     267                 :            :       else
     268                 :          0 :         g_string_free (s, TRUE);
     269                 :            :     }
     270                 :            : 
     271                 :         19 :   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 1.14