LCOV - code coverage report
Current view: top level - glib/gio - gsettingsbackend.c (source / functions) Hit Total Coverage
Test: unnamed Lines: 207 234 88.5 %
Date: 2024-04-23 05:16:05 Functions: 35 38 92.1 %
Branches: 54 70 77.1 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright © 2009, 2010 Codethink Limited
       3                 :            :  * Copyright © 2010 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 Public
      18                 :            :  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
      19                 :            :  *
      20                 :            :  * Authors: Ryan Lortie <desrt@desrt.ca>
      21                 :            :  *          Matthias Clasen <mclasen@redhat.com>
      22                 :            :  */
      23                 :            : 
      24                 :            : #include "config.h"
      25                 :            : 
      26                 :            : #include "gsettingsbackendinternal.h"
      27                 :            : #include "gsimplepermission.h"
      28                 :            : #include "giomodule-priv.h"
      29                 :            : 
      30                 :            : #include <string.h>
      31                 :            : #include <stdlib.h>
      32                 :            : #include <glib.h>
      33                 :            : #include <glibintl.h>
      34                 :            : 
      35                 :            : 
      36                 :            : typedef struct _GSettingsBackendClosure GSettingsBackendClosure;
      37                 :            : typedef struct _GSettingsBackendWatch   GSettingsBackendWatch;
      38                 :            : 
      39                 :            : struct _GSettingsBackendPrivate
      40                 :            : {
      41                 :            :   GSettingsBackendWatch *watches;
      42                 :            :   GMutex lock;
      43                 :            : };
      44                 :            : 
      45   [ +  +  +  -  :        734 : G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GSettingsBackend, g_settings_backend, G_TYPE_OBJECT)
                   +  + ]
      46                 :            : 
      47                 :            : /* For g_settings_backend_sync_default(), we only want to actually do
      48                 :            :  * the sync if the backend already exists.  This avoids us creating an
      49                 :            :  * entire GSettingsBackend in order to call a do-nothing sync()
      50                 :            :  * operation on it.  This variable lets us avoid that.
      51                 :            :  */
      52                 :            : static gboolean g_settings_has_backend;
      53                 :            : 
      54                 :            : /**
      55                 :            :  * GSettingsBackend:
      56                 :            :  *
      57                 :            :  * The `GSettingsBackend` interface defines a generic interface for
      58                 :            :  * non-strictly-typed data that is stored in a hierarchy. To implement
      59                 :            :  * an alternative storage backend for [class@Gio.Settings], you need to
      60                 :            :  * implement the `GSettingsBackend` interface and then make it implement the
      61                 :            :  * extension point `G_SETTINGS_BACKEND_EXTENSION_POINT_NAME`.
      62                 :            :  *
      63                 :            :  * The interface defines methods for reading and writing values, a
      64                 :            :  * method for determining if writing of certain values will fail
      65                 :            :  * (lockdown) and a change notification mechanism.
      66                 :            :  *
      67                 :            :  * The semantics of the interface are very precisely defined and
      68                 :            :  * implementations must carefully adhere to the expectations of
      69                 :            :  * callers that are documented on each of the interface methods.
      70                 :            :  *
      71                 :            :  * Some of the `GSettingsBackend` functions accept or return a
      72                 :            :  * [struct@GLib.Tree]. These trees always have strings as keys and
      73                 :            :  * [struct@GLib.Variant] as values.
      74                 :            :  *
      75                 :            :  * The `GSettingsBackend` API is exported to allow third-party
      76                 :            :  * implementations, but does not carry the same stability guarantees
      77                 :            :  * as the public GIO API. For this reason, you have to define the
      78                 :            :  * C preprocessor symbol `G_SETTINGS_ENABLE_BACKEND` before including
      79                 :            :  * `gio/gsettingsbackend.h`.
      80                 :            :  **/
      81                 :            : 
      82                 :            : static gboolean
      83                 :        145 : is_key (const gchar *key)
      84                 :            : {
      85                 :            :   gint length;
      86                 :            :   gint i;
      87                 :            : 
      88                 :        145 :   g_return_val_if_fail (key != NULL, FALSE);
      89                 :        145 :   g_return_val_if_fail (key[0] == '/', FALSE);
      90                 :            : 
      91         [ +  + ]:       3303 :   for (i = 1; key[i]; i++)
      92                 :       3158 :     g_return_val_if_fail (key[i] != '/' || key[i + 1] != '/', FALSE);
      93                 :            : 
      94                 :        145 :   length = i;
      95                 :            : 
      96                 :        145 :   g_return_val_if_fail (key[length - 1] != '/', FALSE);
      97                 :            : 
      98                 :        145 :   return TRUE;
      99                 :            : }
     100                 :            : 
     101                 :            : static gboolean
     102                 :         27 : is_path (const gchar *path)
     103                 :            : {
     104                 :            :   gint length;
     105                 :            :   gint i;
     106                 :            : 
     107                 :         27 :   g_return_val_if_fail (path != NULL, FALSE);
     108                 :         27 :   g_return_val_if_fail (path[0] == '/', FALSE);
     109                 :            : 
     110         [ +  + ]:        289 :   for (i = 1; path[i]; i++)
     111                 :        262 :     g_return_val_if_fail (path[i] != '/' || path[i + 1] != '/', FALSE);
     112                 :            : 
     113                 :         27 :   length = i;
     114                 :            : 
     115                 :         27 :   g_return_val_if_fail (path[length - 1] == '/', FALSE);
     116                 :            : 
     117                 :         27 :   return TRUE;
     118                 :            : }
     119                 :            : 
     120                 :            : struct _GSettingsBackendWatch
     121                 :            : {
     122                 :            :   /* Always access the target via the weak reference */
     123                 :            :   GWeakRef                       target;
     124                 :            :   /* The pointer is only for comparison from the weak notify,
     125                 :            :    * at which point the target might already be close to
     126                 :            :    * destroyed. It's not safe to use it for anything anymore
     127                 :            :    * at that point */
     128                 :            :   GObject                       *target_ptr;
     129                 :            :   const GSettingsListenerVTable *vtable;
     130                 :            :   GMainContext                  *context;
     131                 :            :   GSettingsBackendWatch         *next;
     132                 :            : };
     133                 :            : 
     134                 :            : struct _GSettingsBackendClosure
     135                 :            : {
     136                 :            :   void (*function) (GObject           *target,
     137                 :            :                     GSettingsBackend  *backend,
     138                 :            :                     const gchar       *name,
     139                 :            :                     gpointer           origin_tag,
     140                 :            :                     gchar            **names);
     141                 :            : 
     142                 :            :   GMainContext      *context;
     143                 :            :   GObject           *target;
     144                 :            :   GSettingsBackend  *backend;
     145                 :            :   gchar             *name;
     146                 :            :   gpointer           origin_tag;
     147                 :            :   gchar            **names;
     148                 :            : };
     149                 :            : 
     150                 :            : static void
     151                 :         80 : g_settings_backend_watch_weak_notify (gpointer  data,
     152                 :            :                                       GObject  *where_the_object_was)
     153                 :            : {
     154                 :         80 :   GSettingsBackend *backend = data;
     155                 :            :   GSettingsBackendWatch **ptr;
     156                 :            : 
     157                 :            :   /* search and remove */
     158                 :         80 :   g_mutex_lock (&backend->priv->lock);
     159         [ +  - ]:         98 :   for (ptr = &backend->priv->watches; *ptr; ptr = &(*ptr)->next)
     160         [ +  + ]:         98 :     if ((*ptr)->target_ptr == where_the_object_was)
     161                 :            :       {
     162                 :         80 :         GSettingsBackendWatch *tmp = *ptr;
     163                 :            : 
     164                 :         80 :         *ptr = tmp->next;
     165                 :         80 :         g_weak_ref_clear (&tmp->target);
     166                 :         80 :         g_slice_free (GSettingsBackendWatch, tmp);
     167                 :            : 
     168                 :         80 :         g_mutex_unlock (&backend->priv->lock);
     169                 :         80 :         return;
     170                 :            :       }
     171                 :            : 
     172                 :            :   /* we didn't find it.  that shouldn't happen. */
     173                 :            :   g_assert_not_reached ();
     174                 :            : }
     175                 :            : 
     176                 :            : /*< private >
     177                 :            :  * g_settings_backend_watch:
     178                 :            :  * @backend: a #GSettingsBackend
     179                 :            :  * @target: the GObject (typically GSettings instance) to call back to
     180                 :            :  * @context: (nullable): a #GMainContext, or %NULL
     181                 :            :  * ...: callbacks...
     182                 :            :  *
     183                 :            :  * Registers a new watch on a #GSettingsBackend.
     184                 :            :  *
     185                 :            :  * note: %NULL @context does not mean "default main context" but rather,
     186                 :            :  * "it is okay to dispatch in any context".  If the default main context
     187                 :            :  * is specifically desired then it must be given.
     188                 :            :  *
     189                 :            :  * note also: if you want to get meaningful values for the @origin_tag
     190                 :            :  * that appears as an argument to some of the callbacks, you *must* have
     191                 :            :  * @context as %NULL.  Otherwise, you are subject to cross-thread
     192                 :            :  * dispatching and whatever owned @origin_tag at the time that the event
     193                 :            :  * occurred may no longer own it.  This is a problem if you consider that
     194                 :            :  * you may now be the new owner of that address and mistakenly think
     195                 :            :  * that the event in question originated from yourself.
     196                 :            :  *
     197                 :            :  * tl;dr: If you give a non-%NULL @context then you must ignore the
     198                 :            :  * value of @origin_tag given to any callbacks.
     199                 :            :  **/
     200                 :            : void
     201                 :         82 : g_settings_backend_watch (GSettingsBackend              *backend,
     202                 :            :                           const GSettingsListenerVTable *vtable,
     203                 :            :                           GObject                       *target,
     204                 :            :                           GMainContext                  *context)
     205                 :            : {
     206                 :            :   GSettingsBackendWatch *watch;
     207                 :            : 
     208                 :            :   /* For purposes of discussion, we assume that our target is a
     209                 :            :    * GSettings instance.
     210                 :            :    *
     211                 :            :    * Our strategy to defend against the final reference dropping on the
     212                 :            :    * GSettings object in a thread other than the one that is doing the
     213                 :            :    * dispatching is as follows:
     214                 :            :    *
     215                 :            :    *  1) hold a strong reference on the GSettings during an outstanding
     216                 :            :    *     dispatch.  This ensures that the delivery is always possible while
     217                 :            :    *     the GSettings object is alive, and if this was the last reference
     218                 :            :    *     then it will be dropped from the dispatch thread.
     219                 :            :    *
     220                 :            :    *  2) hold a weak reference on the GSettings at other times.  This
     221                 :            :    *     allows us to receive early notification of pending destruction
     222                 :            :    *     of the object.  At this point, it is still safe to obtain a
     223                 :            :    *     reference on the GObject to keep it alive, so #1 will work up
     224                 :            :    *     to that point.  After that point, we'll have been able to drop
     225                 :            :    *     the watch from the list.
     226                 :            :    *
     227                 :            :    * Note, in particular, that it's not possible to simply have an
     228                 :            :    * "unwatch" function that gets called from the finalize function of
     229                 :            :    * the GSettings instance because, by that point it is no longer
     230                 :            :    * possible to keep the object alive using g_object_ref() and we would
     231                 :            :    * have no way of knowing this.
     232                 :            :    *
     233                 :            :    * Note also that we need to hold a reference on the main context here
     234                 :            :    * since the GSettings instance may be finalized before the closure runs.
     235                 :            :    *
     236                 :            :    * All access to the list holds a mutex.  We have some strategies to
     237                 :            :    * avoid some of the pain that would be associated with that.
     238                 :            :    */
     239                 :            : 
     240                 :         82 :   watch = g_slice_new (GSettingsBackendWatch);
     241                 :         82 :   watch->context = context;
     242                 :         82 :   watch->vtable = vtable;
     243                 :         82 :   g_weak_ref_init (&watch->target, target);
     244                 :         82 :   watch->target_ptr = target;
     245                 :         82 :   g_object_weak_ref (target, g_settings_backend_watch_weak_notify, backend);
     246                 :            : 
     247                 :            :   /* linked list prepend */
     248                 :         82 :   g_mutex_lock (&backend->priv->lock);
     249                 :         82 :   watch->next = backend->priv->watches;
     250                 :         82 :   backend->priv->watches = watch;
     251                 :         82 :   g_mutex_unlock (&backend->priv->lock);
     252                 :         82 : }
     253                 :            : 
     254                 :            : void
     255                 :         10 : g_settings_backend_unwatch (GSettingsBackend *backend,
     256                 :            :                             GObject          *target)
     257                 :            : {
     258                 :            :   /* Our caller surely owns a reference on 'target', so the order of
     259                 :            :    * these two calls is unimportant.
     260                 :            :    */
     261                 :         10 :   g_object_weak_unref (target, g_settings_backend_watch_weak_notify, backend);
     262                 :         10 :   g_settings_backend_watch_weak_notify (backend, target);
     263                 :         10 : }
     264                 :            : 
     265                 :            : static gboolean
     266                 :        166 : g_settings_backend_invoke_closure (gpointer user_data)
     267                 :            : {
     268                 :        166 :   GSettingsBackendClosure *closure = user_data;
     269                 :            : 
     270                 :        166 :   closure->function (closure->target, closure->backend, closure->name,
     271                 :            :                      closure->origin_tag, closure->names);
     272                 :            : 
     273         [ +  + ]:        166 :   if (closure->context)
     274                 :        150 :     g_main_context_unref (closure->context);
     275                 :        166 :   g_object_unref (closure->backend);
     276                 :        166 :   g_object_unref (closure->target);
     277                 :        166 :   g_strfreev (closure->names);
     278                 :        166 :   g_free (closure->name);
     279                 :            : 
     280                 :        166 :   g_slice_free (GSettingsBackendClosure, closure);
     281                 :            : 
     282                 :        166 :   return FALSE;
     283                 :            : }
     284                 :            : 
     285                 :            : static void
     286                 :        154 : g_settings_backend_dispatch_signal (GSettingsBackend    *backend,
     287                 :            :                                     gsize                function_offset,
     288                 :            :                                     const gchar         *name,
     289                 :            :                                     gpointer             origin_tag,
     290                 :            :                                     const gchar * const *names)
     291                 :            : {
     292                 :            :   GSettingsBackendWatch *watch;
     293                 :        154 :   GSList *closures = NULL;
     294                 :            : 
     295                 :            :   /* We're in a little bit of a tricky situation here.  We need to hold
     296                 :            :    * a lock while traversing the list, but we don't want to hold the
     297                 :            :    * lock while calling back into user code.
     298                 :            :    *
     299                 :            :    * We work around this by creating a bunch of GSettingsBackendClosure
     300                 :            :    * objects while holding the lock and dispatching them after.  We
     301                 :            :    * never touch the list without holding the lock.
     302                 :            :    */
     303                 :        154 :   g_mutex_lock (&backend->priv->lock);
     304         [ +  + ]:        320 :   for (watch = backend->priv->watches; watch; watch = watch->next)
     305                 :            :     {
     306                 :            :       GSettingsBackendClosure *closure;
     307                 :        166 :       GObject *target = g_weak_ref_get (&watch->target);
     308                 :            : 
     309                 :            :       /* If the target was destroyed in the meantime, just skip it here */
     310         [ -  + ]:        166 :       if (!target)
     311                 :          0 :         continue;
     312                 :            : 
     313                 :        166 :       closure = g_slice_new (GSettingsBackendClosure);
     314                 :        166 :       closure->context = watch->context;
     315         [ +  + ]:        166 :       if (closure->context)
     316                 :        150 :         g_main_context_ref (closure->context);
     317                 :        166 :       closure->backend = g_object_ref (backend);
     318                 :        166 :       closure->target = g_steal_pointer (&target);
     319                 :        166 :       closure->function = G_STRUCT_MEMBER (void *, watch->vtable,
     320                 :            :                                            function_offset);
     321                 :        166 :       closure->name = g_strdup (name);
     322                 :        166 :       closure->origin_tag = origin_tag;
     323                 :        166 :       closure->names = g_strdupv ((gchar **) names);
     324                 :            : 
     325                 :        166 :       closures = g_slist_prepend (closures, closure);
     326                 :            :     }
     327                 :        154 :   g_mutex_unlock (&backend->priv->lock);
     328                 :            : 
     329         [ +  + ]:        320 :   while (closures)
     330                 :            :     {
     331                 :        166 :       GSettingsBackendClosure *closure = closures->data;
     332                 :            : 
     333         [ +  + ]:        166 :       if (closure->context)
     334                 :        150 :         g_main_context_invoke (closure->context,
     335                 :            :                                g_settings_backend_invoke_closure,
     336                 :            :                                closure);
     337                 :            :       else
     338                 :         16 :         g_settings_backend_invoke_closure (closure);
     339                 :            : 
     340                 :        166 :       closures = g_slist_delete_link (closures, closures);
     341                 :            :     }
     342                 :        154 : }
     343                 :            : 
     344                 :            : /**
     345                 :            :  * g_settings_backend_changed:
     346                 :            :  * @backend: a #GSettingsBackend implementation
     347                 :            :  * @key: the name of the key
     348                 :            :  * @origin_tag: the origin tag
     349                 :            :  *
     350                 :            :  * Signals that a single key has possibly changed.  Backend
     351                 :            :  * implementations should call this if a key has possibly changed its
     352                 :            :  * value.
     353                 :            :  *
     354                 :            :  * @key must be a valid key (ie starting with a slash, not containing
     355                 :            :  * '//', and not ending with a slash).
     356                 :            :  *
     357                 :            :  * The implementation must call this function during any call to
     358                 :            :  * g_settings_backend_write(), before the call returns (except in the
     359                 :            :  * case that no keys are actually changed and it cares to detect this
     360                 :            :  * fact).  It may not rely on the existence of a mainloop for
     361                 :            :  * dispatching the signal later.
     362                 :            :  *
     363                 :            :  * The implementation may call this function at any other time it likes
     364                 :            :  * in response to other events (such as changes occurring outside of the
     365                 :            :  * program).  These calls may originate from a mainloop or may originate
     366                 :            :  * in response to any other action (including from calls to
     367                 :            :  * g_settings_backend_write()).
     368                 :            :  *
     369                 :            :  * In the case that this call is in response to a call to
     370                 :            :  * g_settings_backend_write() then @origin_tag must be set to the same
     371                 :            :  * value that was passed to that call.
     372                 :            :  *
     373                 :            :  * Since: 2.26
     374                 :            :  **/
     375                 :            : void
     376                 :        127 : g_settings_backend_changed (GSettingsBackend *backend,
     377                 :            :                             const gchar      *key,
     378                 :            :                             gpointer          origin_tag)
     379                 :            : {
     380                 :        127 :   g_return_if_fail (G_IS_SETTINGS_BACKEND (backend));
     381                 :        127 :   g_return_if_fail (is_key (key));
     382                 :            : 
     383                 :        127 :   g_settings_backend_dispatch_signal (backend,
     384                 :            :                                       G_STRUCT_OFFSET (GSettingsListenerVTable,
     385                 :            :                                                        changed),
     386                 :            :                                       key, origin_tag, NULL);
     387                 :            : }
     388                 :            : 
     389                 :            : /**
     390                 :            :  * g_settings_backend_keys_changed:
     391                 :            :  * @backend: a #GSettingsBackend implementation
     392                 :            :  * @path: the path containing the changes
     393                 :            :  * @items: (array zero-terminated=1): the %NULL-terminated list of changed keys
     394                 :            :  * @origin_tag: the origin tag
     395                 :            :  *
     396                 :            :  * Signals that a list of keys have possibly changed.  Backend
     397                 :            :  * implementations should call this if keys have possibly changed their
     398                 :            :  * values.
     399                 :            :  *
     400                 :            :  * @path must be a valid path (ie starting and ending with a slash and
     401                 :            :  * not containing '//').  Each string in @items must form a valid key
     402                 :            :  * name when @path is prefixed to it (ie: each item must not start or
     403                 :            :  * end with '/' and must not contain '//').
     404                 :            :  *
     405                 :            :  * The meaning of this signal is that any of the key names resulting
     406                 :            :  * from the contatenation of @path with each item in @items may have
     407                 :            :  * changed.
     408                 :            :  *
     409                 :            :  * The same rules for when notifications must occur apply as per
     410                 :            :  * g_settings_backend_changed().  These two calls can be used
     411                 :            :  * interchangeably if exactly one item has changed (although in that
     412                 :            :  * case g_settings_backend_changed() is definitely preferred).
     413                 :            :  *
     414                 :            :  * For efficiency reasons, the implementation should strive for @path to
     415                 :            :  * be as long as possible (ie: the longest common prefix of all of the
     416                 :            :  * keys that were changed) but this is not strictly required.
     417                 :            :  *
     418                 :            :  * Since: 2.26
     419                 :            :  */
     420                 :            : void
     421                 :         19 : g_settings_backend_keys_changed (GSettingsBackend    *backend,
     422                 :            :                                  const gchar         *path,
     423                 :            :                                  gchar const * const *items,
     424                 :            :                                  gpointer             origin_tag)
     425                 :            : {
     426                 :         19 :   g_return_if_fail (G_IS_SETTINGS_BACKEND (backend));
     427                 :         19 :   g_return_if_fail (is_path (path));
     428                 :            : 
     429                 :            :   /* XXX: should do stricter checking (ie: inspect each item) */
     430                 :         19 :   g_return_if_fail (items != NULL);
     431                 :            : 
     432                 :         19 :   g_settings_backend_dispatch_signal (backend,
     433                 :            :                                       G_STRUCT_OFFSET (GSettingsListenerVTable,
     434                 :            :                                                        keys_changed),
     435                 :            :                                       path, origin_tag, items);
     436                 :            : }
     437                 :            : 
     438                 :            : /**
     439                 :            :  * g_settings_backend_path_changed:
     440                 :            :  * @backend: a #GSettingsBackend implementation
     441                 :            :  * @path: the path containing the changes
     442                 :            :  * @origin_tag: the origin tag
     443                 :            :  *
     444                 :            :  * Signals that all keys below a given path may have possibly changed.
     445                 :            :  * Backend implementations should call this if an entire path of keys
     446                 :            :  * have possibly changed their values.
     447                 :            :  *
     448                 :            :  * @path must be a valid path (ie starting and ending with a slash and
     449                 :            :  * not containing '//').
     450                 :            :  *
     451                 :            :  * The meaning of this signal is that any of the key which has a name
     452                 :            :  * starting with @path may have changed.
     453                 :            :  *
     454                 :            :  * The same rules for when notifications must occur apply as per
     455                 :            :  * g_settings_backend_changed().  This call might be an appropriate
     456                 :            :  * reasponse to a 'reset' call but implementations are also free to
     457                 :            :  * explicitly list the keys that were affected by that call if they can
     458                 :            :  * easily do so.
     459                 :            :  *
     460                 :            :  * For efficiency reasons, the implementation should strive for @path to
     461                 :            :  * be as long as possible (ie: the longest common prefix of all of the
     462                 :            :  * keys that were changed) but this is not strictly required.  As an
     463                 :            :  * example, if this function is called with the path of "/" then every
     464                 :            :  * single key in the application will be notified of a possible change.
     465                 :            :  *
     466                 :            :  * Since: 2.26
     467                 :            :  */
     468                 :            : void
     469                 :          0 : g_settings_backend_path_changed (GSettingsBackend *backend,
     470                 :            :                                  const gchar      *path,
     471                 :            :                                  gpointer          origin_tag)
     472                 :            : {
     473                 :          0 :   g_return_if_fail (G_IS_SETTINGS_BACKEND (backend));
     474                 :          0 :   g_return_if_fail (is_path (path));
     475                 :            : 
     476                 :          0 :   g_settings_backend_dispatch_signal (backend,
     477                 :            :                                       G_STRUCT_OFFSET (GSettingsListenerVTable,
     478                 :            :                                                        path_changed),
     479                 :            :                                       path, origin_tag, NULL);
     480                 :            : }
     481                 :            : 
     482                 :            : /**
     483                 :            :  * g_settings_backend_writable_changed:
     484                 :            :  * @backend: a #GSettingsBackend implementation
     485                 :            :  * @key: the name of the key
     486                 :            :  *
     487                 :            :  * Signals that the writability of a single key has possibly changed.
     488                 :            :  *
     489                 :            :  * Since GSettings performs no locking operations for itself, this call
     490                 :            :  * will always be made in response to external events.
     491                 :            :  *
     492                 :            :  * Since: 2.26
     493                 :            :  **/
     494                 :            : void
     495                 :          0 : g_settings_backend_writable_changed (GSettingsBackend *backend,
     496                 :            :                                      const gchar      *key)
     497                 :            : {
     498                 :          0 :   g_return_if_fail (G_IS_SETTINGS_BACKEND (backend));
     499                 :          0 :   g_return_if_fail (is_key (key));
     500                 :            : 
     501                 :          0 :   g_settings_backend_dispatch_signal (backend,
     502                 :            :                                       G_STRUCT_OFFSET (GSettingsListenerVTable,
     503                 :            :                                                        writable_changed),
     504                 :            :                                       key, NULL, NULL);
     505                 :            : }
     506                 :            : 
     507                 :            : /**
     508                 :            :  * g_settings_backend_path_writable_changed:
     509                 :            :  * @backend: a #GSettingsBackend implementation
     510                 :            :  * @path: the name of the path
     511                 :            :  *
     512                 :            :  * Signals that the writability of all keys below a given path may have
     513                 :            :  * changed.
     514                 :            :  *
     515                 :            :  * Since GSettings performs no locking operations for itself, this call
     516                 :            :  * will always be made in response to external events.
     517                 :            :  *
     518                 :            :  * Since: 2.26
     519                 :            :  **/
     520                 :            : void
     521                 :          8 : g_settings_backend_path_writable_changed (GSettingsBackend *backend,
     522                 :            :                                           const gchar      *path)
     523                 :            : {
     524                 :          8 :   g_return_if_fail (G_IS_SETTINGS_BACKEND (backend));
     525                 :          8 :   g_return_if_fail (is_path (path));
     526                 :            : 
     527                 :          8 :   g_settings_backend_dispatch_signal (backend,
     528                 :            :                                       G_STRUCT_OFFSET (GSettingsListenerVTable,
     529                 :            :                                                        path_writable_changed),
     530                 :            :                                       path, NULL, NULL);
     531                 :            : }
     532                 :            : 
     533                 :            : typedef struct
     534                 :            : {
     535                 :            :   const gchar **keys;
     536                 :            :   GVariant **values;
     537                 :            :   gint prefix_len;
     538                 :            :   gchar *prefix;
     539                 :            : } FlattenState;
     540                 :            : 
     541                 :            : static gboolean
     542                 :         18 : g_settings_backend_flatten_one (gpointer key,
     543                 :            :                                 gpointer value,
     544                 :            :                                 gpointer user_data)
     545                 :            : {
     546                 :         18 :   FlattenState *state = user_data;
     547                 :         18 :   const gchar *skey = key;
     548                 :            :   gint i;
     549                 :            : 
     550                 :         18 :   g_return_val_if_fail (is_key (key), TRUE);
     551                 :            : 
     552                 :            :   /* calculate longest common prefix */
     553         [ +  + ]:         18 :   if (state->prefix == NULL)
     554                 :            :     {
     555                 :            :       gchar *last_byte;
     556                 :            : 
     557                 :            :       /* first key?  just take the prefix up to the last '/' */
     558                 :         17 :       state->prefix = g_strdup (skey);
     559                 :         17 :       last_byte = strrchr (state->prefix, '/') + 1;
     560                 :         17 :       state->prefix_len = last_byte - state->prefix;
     561                 :         17 :       *last_byte = '\0';
     562                 :            :     }
     563                 :            :   else
     564                 :            :     {
     565                 :            :       /* find the first character that does not match.  we will
     566                 :            :        * definitely find one because the prefix ends in '/' and the key
     567                 :            :        * does not.  also: no two keys in the tree are the same.
     568                 :            :        */
     569         [ +  + ]:          8 :       for (i = 0; state->prefix[i] == skey[i]; i++);
     570                 :            : 
     571                 :            :       /* check if we need to shorten the prefix */
     572         [ -  + ]:          1 :       if (state->prefix[i] != '\0')
     573                 :            :         {
     574                 :            :           /* find the nearest '/', terminate after it */
     575         [ #  # ]:          0 :           while (state->prefix[i - 1] != '/')
     576                 :          0 :             i--;
     577                 :            : 
     578                 :          0 :           state->prefix[i] = '\0';
     579                 :          0 :           state->prefix_len = i;
     580                 :            :         }
     581                 :            :     }
     582                 :            : 
     583                 :            : 
     584                 :            :   /* save the entire item into the array.
     585                 :            :    * the prefixes will be removed later.
     586                 :            :    */
     587                 :         18 :   *state->keys++ = key;
     588                 :            : 
     589         [ -  + ]:         18 :   if (state->values)
     590                 :          0 :     *state->values++ = value;
     591                 :            : 
     592                 :         18 :   return FALSE;
     593                 :            : }
     594                 :            : 
     595                 :            : /**
     596                 :            :  * g_settings_backend_flatten_tree:
     597                 :            :  * @tree: a #GTree containing the changes
     598                 :            :  * @path: (out): the location to save the path
     599                 :            :  * @keys: (out) (transfer container) (array zero-terminated=1): the
     600                 :            :  *        location to save the relative keys
     601                 :            :  * @values: (out) (optional) (transfer container) (array zero-terminated=1):
     602                 :            :  *          the location to save the values, or %NULL
     603                 :            :  *
     604                 :            :  * Calculate the longest common prefix of all keys in a tree and write
     605                 :            :  * out an array of the key names relative to that prefix and,
     606                 :            :  * optionally, the value to store at each of those keys.
     607                 :            :  *
     608                 :            :  * You must free the value returned in @path, @keys and @values using
     609                 :            :  * g_free().  You should not attempt to free or unref the contents of
     610                 :            :  * @keys or @values.
     611                 :            :  *
     612                 :            :  * Since: 2.26
     613                 :            :  **/
     614                 :            : void
     615                 :         17 : g_settings_backend_flatten_tree (GTree         *tree,
     616                 :            :                                  gchar        **path,
     617                 :            :                                  const gchar ***keys,
     618                 :            :                                  GVariant    ***values)
     619                 :            : {
     620                 :         17 :   FlattenState state = { 0, };
     621                 :            :   gsize nnodes;
     622                 :            : 
     623                 :         17 :   nnodes = g_tree_nnodes (tree);
     624                 :            : 
     625                 :         17 :   *keys = state.keys = g_new (const gchar *, nnodes + 1);
     626                 :         17 :   state.keys[nnodes] = NULL;
     627                 :            : 
     628         [ -  + ]:         17 :   if (values != NULL)
     629                 :            :     {
     630                 :          0 :       *values = state.values = g_new (GVariant *, nnodes + 1);
     631                 :          0 :       state.values[nnodes] = NULL;
     632                 :            :     }
     633                 :            : 
     634                 :         17 :   g_tree_foreach (tree, g_settings_backend_flatten_one, &state);
     635                 :         17 :   g_return_if_fail (*keys + nnodes == state.keys);
     636                 :            : 
     637                 :         17 :   *path = state.prefix;
     638         [ +  + ]:         35 :   while (nnodes--)
     639                 :         18 :     *--state.keys += state.prefix_len;
     640                 :            : }
     641                 :            : 
     642                 :            : /**
     643                 :            :  * g_settings_backend_changed_tree:
     644                 :            :  * @backend: a #GSettingsBackend implementation
     645                 :            :  * @tree: a #GTree containing the changes
     646                 :            :  * @origin_tag: the origin tag
     647                 :            :  *
     648                 :            :  * This call is a convenience wrapper.  It gets the list of changes from
     649                 :            :  * @tree, computes the longest common prefix and calls
     650                 :            :  * g_settings_backend_changed().
     651                 :            :  *
     652                 :            :  * Since: 2.26
     653                 :            :  **/
     654                 :            : void
     655                 :         17 : g_settings_backend_changed_tree (GSettingsBackend *backend,
     656                 :            :                                  GTree            *tree,
     657                 :            :                                  gpointer          origin_tag)
     658                 :            : {
     659                 :            :   const gchar **keys;
     660                 :            :   gchar *path;
     661                 :            : 
     662                 :         17 :   g_return_if_fail (G_IS_SETTINGS_BACKEND (backend));
     663                 :            : 
     664                 :         17 :   g_settings_backend_flatten_tree (tree, &path, &keys, NULL);
     665                 :            : 
     666                 :            : #ifdef DEBUG_CHANGES
     667                 :            :   {
     668                 :            :     gint i;
     669                 :            : 
     670                 :            :     g_print ("----\n");
     671                 :            :     g_print ("changed_tree(): prefix %s\n", path);
     672                 :            :     for (i = 0; keys[i]; i++)
     673                 :            :       g_print ("  %s\n", keys[i]);
     674                 :            :     g_print ("----\n");
     675                 :            :   }
     676                 :            : #endif
     677                 :            : 
     678                 :         17 :   g_settings_backend_keys_changed (backend, path, keys, origin_tag);
     679                 :         17 :   g_free (path);
     680                 :         17 :   g_free (keys);
     681                 :            : }
     682                 :            : 
     683                 :            : /*< private >
     684                 :            :  * g_settings_backend_read:
     685                 :            :  * @backend: a #GSettingsBackend implementation
     686                 :            :  * @key: the key to read
     687                 :            :  * @expected_type: a #GVariantType
     688                 :            :  * @default_value: if the default value should be returned
     689                 :            :  *
     690                 :            :  * Reads a key. This call will never block.
     691                 :            :  *
     692                 :            :  * If the key exists, the value associated with it will be returned.
     693                 :            :  * If the key does not exist, %NULL will be returned.
     694                 :            :  *
     695                 :            :  * The returned value will be of the type given in @expected_type.  If
     696                 :            :  * the backend stored a value of a different type then %NULL will be
     697                 :            :  * returned.
     698                 :            :  *
     699                 :            :  * If @default_value is %TRUE then this gets the default value from the
     700                 :            :  * backend (ie: the one that the backend would contain if
     701                 :            :  * g_settings_reset() were called).
     702                 :            :  *
     703                 :            :  * Returns: (nullable) (transfer full): the value that was read, or %NULL
     704                 :            :  */
     705                 :            : GVariant *
     706                 :        212 : g_settings_backend_read (GSettingsBackend   *backend,
     707                 :            :                          const gchar        *key,
     708                 :            :                          const GVariantType *expected_type,
     709                 :            :                          gboolean            default_value)
     710                 :            : {
     711                 :            :   GVariant *value;
     712                 :            : 
     713                 :        212 :   value = G_SETTINGS_BACKEND_GET_CLASS (backend)
     714                 :        212 :     ->read (backend, key, expected_type, default_value);
     715                 :            : 
     716         [ +  + ]:        212 :   if (value != NULL)
     717                 :        142 :     value = g_variant_take_ref (value);
     718                 :            : 
     719   [ +  +  -  + ]:        212 :   if G_UNLIKELY (value && !g_variant_is_of_type (value, expected_type))
     720                 :            :     {
     721                 :          0 :       g_variant_unref (value);
     722                 :          0 :       value = NULL;
     723                 :            :     }
     724                 :            : 
     725                 :        212 :   return value;
     726                 :            : }
     727                 :            : 
     728                 :            : /*< private >
     729                 :            :  * g_settings_backend_read_user_value:
     730                 :            :  * @backend: a #GSettingsBackend implementation
     731                 :            :  * @key: the key to read
     732                 :            :  * @expected_type: a #GVariantType
     733                 :            :  *
     734                 :            :  * Reads the 'user value' of a key.
     735                 :            :  *
     736                 :            :  * This is the value of the key that the user has control over and has
     737                 :            :  * set for themselves.  Put another way: if the user did not set the
     738                 :            :  * value for themselves, then this will return %NULL (even if the
     739                 :            :  * sysadmin has provided a default value).
     740                 :            :  *
     741                 :            :  * Returns: (nullable) (transfer full): the value that was read, or %NULL
     742                 :            :  */
     743                 :            : GVariant *
     744                 :          3 : g_settings_backend_read_user_value (GSettingsBackend   *backend,
     745                 :            :                                     const gchar        *key,
     746                 :            :                                     const GVariantType *expected_type)
     747                 :            : {
     748                 :            :   GVariant *value;
     749                 :            : 
     750                 :          3 :   value = G_SETTINGS_BACKEND_GET_CLASS (backend)
     751                 :          3 :     ->read_user_value (backend, key, expected_type);
     752                 :            : 
     753         [ +  + ]:          3 :   if (value != NULL)
     754                 :          2 :     value = g_variant_take_ref (value);
     755                 :            : 
     756   [ +  +  -  + ]:          3 :   if G_UNLIKELY (value && !g_variant_is_of_type (value, expected_type))
     757                 :            :     {
     758                 :          0 :       g_variant_unref (value);
     759                 :          0 :       value = NULL;
     760                 :            :     }
     761                 :            : 
     762                 :          3 :   return value;
     763                 :            : }
     764                 :            : 
     765                 :            : /*< private >
     766                 :            :  * g_settings_backend_write:
     767                 :            :  * @backend: a #GSettingsBackend implementation
     768                 :            :  * @key: the name of the key
     769                 :            :  * @value: a #GVariant value to write to this key
     770                 :            :  * @origin_tag: the origin tag
     771                 :            :  *
     772                 :            :  * Writes exactly one key.
     773                 :            :  *
     774                 :            :  * This call does not fail.  During this call a
     775                 :            :  * #GSettingsBackend::changed signal will be emitted if the value of the
     776                 :            :  * key has changed.  The updated key value will be visible to any signal
     777                 :            :  * callbacks.
     778                 :            :  *
     779                 :            :  * One possible method that an implementation might deal with failures is
     780                 :            :  * to emit a second "changed" signal (either during this call, or later)
     781                 :            :  * to indicate that the affected keys have suddenly "changed back" to their
     782                 :            :  * old values.
     783                 :            :  *
     784                 :            :  * If @value has a floating reference, it will be sunk.
     785                 :            :  *
     786                 :            :  * Returns: %TRUE if the write succeeded, %FALSE if the key was not writable
     787                 :            :  */
     788                 :            : gboolean
     789                 :        121 : g_settings_backend_write (GSettingsBackend *backend,
     790                 :            :                           const gchar      *key,
     791                 :            :                           GVariant         *value,
     792                 :            :                           gpointer          origin_tag)
     793                 :            : {
     794                 :            :   gboolean success;
     795                 :            : 
     796                 :        121 :   g_variant_ref_sink (value);
     797                 :        121 :   success = G_SETTINGS_BACKEND_GET_CLASS (backend)
     798                 :        121 :     ->write (backend, key, value, origin_tag);
     799                 :        121 :   g_variant_unref (value);
     800                 :            : 
     801                 :        121 :   return success;
     802                 :            : }
     803                 :            : 
     804                 :            : /*< private >
     805                 :            :  * g_settings_backend_write_tree:
     806                 :            :  * @backend: a #GSettingsBackend implementation
     807                 :            :  * @tree: a #GTree containing key-value pairs to write
     808                 :            :  * @origin_tag: the origin tag
     809                 :            :  *
     810                 :            :  * Writes one or more keys.  This call will never block.
     811                 :            :  *
     812                 :            :  * The key of each item in the tree is the key name to write to and the
     813                 :            :  * value is a #GVariant to write.  The proper type of #GTree for this
     814                 :            :  * call can be created with g_settings_backend_create_tree().  This call
     815                 :            :  * might take a reference to the tree; you must not modified the #GTree
     816                 :            :  * after passing it to this call.
     817                 :            :  *
     818                 :            :  * This call does not fail.  During this call a #GSettingsBackend::changed
     819                 :            :  * signal will be emitted if any keys have been changed.  The new values of
     820                 :            :  * all updated keys will be visible to any signal callbacks.
     821                 :            :  *
     822                 :            :  * One possible method that an implementation might deal with failures is
     823                 :            :  * to emit a second "changed" signal (either during this call, or later)
     824                 :            :  * to indicate that the affected keys have suddenly "changed back" to their
     825                 :            :  * old values.
     826                 :            :  */
     827                 :            : gboolean
     828                 :         14 : g_settings_backend_write_tree (GSettingsBackend *backend,
     829                 :            :                                GTree            *tree,
     830                 :            :                                gpointer          origin_tag)
     831                 :            : {
     832                 :         28 :   return G_SETTINGS_BACKEND_GET_CLASS (backend)
     833                 :         14 :     ->write_tree (backend, tree, origin_tag);
     834                 :            : }
     835                 :            : 
     836                 :            : /*< private >
     837                 :            :  * g_settings_backend_reset:
     838                 :            :  * @backend: a #GSettingsBackend implementation
     839                 :            :  * @key: the name of a key
     840                 :            :  * @origin_tag: the origin tag
     841                 :            :  *
     842                 :            :  * "Resets" the named key to its "default" value (ie: after system-wide
     843                 :            :  * defaults, mandatory keys, etc. have been taken into account) or possibly
     844                 :            :  * unsets it.
     845                 :            :  */
     846                 :            : void
     847                 :         14 : g_settings_backend_reset (GSettingsBackend *backend,
     848                 :            :                           const gchar      *key,
     849                 :            :                           gpointer          origin_tag)
     850                 :            : {
     851                 :         14 :   G_SETTINGS_BACKEND_GET_CLASS (backend)
     852                 :         14 :     ->reset (backend, key, origin_tag);
     853                 :         14 : }
     854                 :            : 
     855                 :            : /*< private >
     856                 :            :  * g_settings_backend_get_writable:
     857                 :            :  * @backend: a #GSettingsBackend implementation
     858                 :            :  * @key: the name of a key
     859                 :            :  *
     860                 :            :  * Finds out if a key is available for writing to.  This is the
     861                 :            :  * interface through which 'lockdown' is implemented.  Locked down
     862                 :            :  * keys will have %FALSE returned by this call.
     863                 :            :  *
     864                 :            :  * You should not write to locked-down keys, but if you do, the
     865                 :            :  * implementation will deal with it.
     866                 :            :  *
     867                 :            :  * Returns: %TRUE if the key is writable
     868                 :            :  */
     869                 :            : gboolean
     870                 :         38 : g_settings_backend_get_writable (GSettingsBackend *backend,
     871                 :            :                                  const gchar      *key)
     872                 :            : {
     873                 :         76 :   return G_SETTINGS_BACKEND_GET_CLASS (backend)
     874                 :         38 :     ->get_writable (backend, key);
     875                 :            : }
     876                 :            : 
     877                 :            : /*< private >
     878                 :            :  * g_settings_backend_unsubscribe:
     879                 :            :  * @backend: a #GSettingsBackend
     880                 :            :  * @name: a key or path to subscribe to
     881                 :            :  *
     882                 :            :  * Reverses the effect of a previous call to
     883                 :            :  * g_settings_backend_subscribe().
     884                 :            :  */
     885                 :            : void
     886                 :         71 : g_settings_backend_unsubscribe (GSettingsBackend *backend,
     887                 :            :                                 const char       *name)
     888                 :            : {
     889                 :         71 :   G_SETTINGS_BACKEND_GET_CLASS (backend)
     890                 :         71 :     ->unsubscribe (backend, name);
     891                 :         71 : }
     892                 :            : 
     893                 :            : /*< private >
     894                 :            :  * g_settings_backend_subscribe:
     895                 :            :  * @backend: a #GSettingsBackend
     896                 :            :  * @name: a key or path to subscribe to
     897                 :            :  *
     898                 :            :  * Requests that change signals be emitted for events on @name.
     899                 :            :  */
     900                 :            : void
     901                 :         63 : g_settings_backend_subscribe (GSettingsBackend *backend,
     902                 :            :                               const gchar      *name)
     903                 :            : {
     904                 :         63 :   G_SETTINGS_BACKEND_GET_CLASS (backend)
     905                 :         63 :     ->subscribe (backend, name);
     906                 :         63 : }
     907                 :            : 
     908                 :            : static void
     909                 :         22 : g_settings_backend_finalize (GObject *object)
     910                 :            : {
     911                 :         22 :   GSettingsBackend *backend = G_SETTINGS_BACKEND (object);
     912                 :            : 
     913                 :         22 :   g_mutex_clear (&backend->priv->lock);
     914                 :            : 
     915                 :         22 :   G_OBJECT_CLASS (g_settings_backend_parent_class)
     916                 :         22 :     ->finalize (object);
     917                 :         22 : }
     918                 :            : 
     919                 :            : static void
     920                 :        122 : ignore_subscription (GSettingsBackend *backend,
     921                 :            :                      const gchar      *key)
     922                 :            : {
     923                 :        122 : }
     924                 :            : 
     925                 :            : static GVariant *
     926                 :          2 : g_settings_backend_real_read_user_value (GSettingsBackend   *backend,
     927                 :            :                                          const gchar        *key,
     928                 :            :                                          const GVariantType *expected_type)
     929                 :            : {
     930                 :          2 :   return g_settings_backend_read (backend, key, expected_type, FALSE);
     931                 :            : }
     932                 :            : 
     933                 :            : static void
     934                 :         24 : g_settings_backend_init (GSettingsBackend *backend)
     935                 :            : {
     936                 :         24 :   backend->priv = g_settings_backend_get_instance_private (backend);
     937                 :         24 :   g_mutex_init (&backend->priv->lock);
     938                 :         24 : }
     939                 :            : 
     940                 :            : static void
     941                 :          7 : g_settings_backend_class_init (GSettingsBackendClass *class)
     942                 :            : {
     943                 :          7 :   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
     944                 :            : 
     945                 :          7 :   class->subscribe = ignore_subscription;
     946                 :          7 :   class->unsubscribe = ignore_subscription;
     947                 :            : 
     948                 :          7 :   class->read_user_value = g_settings_backend_real_read_user_value;
     949                 :            : 
     950                 :          7 :   gobject_class->finalize = g_settings_backend_finalize;
     951                 :          7 : }
     952                 :            : 
     953                 :            : static void
     954                 :         20 : g_settings_backend_variant_unref0 (gpointer data)
     955                 :            : {
     956         [ +  + ]:         20 :   if (data != NULL)
     957                 :         13 :     g_variant_unref (data);
     958                 :         20 : }
     959                 :            : 
     960                 :            : /*< private >
     961                 :            :  * g_settings_backend_create_tree:
     962                 :            :  *
     963                 :            :  * This is a convenience function for creating a tree that is compatible
     964                 :            :  * with g_settings_backend_write().  It merely calls g_tree_new_full()
     965                 :            :  * with strcmp(), g_free() and g_variant_unref().
     966                 :            :  *
     967                 :            :  * Returns: a new #GTree
     968                 :            :  */
     969                 :            : GTree *
     970                 :         25 : g_settings_backend_create_tree (void)
     971                 :            : {
     972                 :         25 :   return g_tree_new_full ((GCompareDataFunc) strcmp, NULL,
     973                 :            :                           g_free, g_settings_backend_variant_unref0);
     974                 :            : }
     975                 :            : 
     976                 :            : static gboolean
     977                 :          4 : g_settings_backend_verify (gpointer impl)
     978                 :            : {
     979                 :          4 :   GSettingsBackend *backend = impl;
     980                 :            : 
     981   [ +  -  -  + ]:          8 :   if (strcmp (G_OBJECT_TYPE_NAME (backend), "GMemorySettingsBackend") == 0 &&
     982                 :          4 :       g_strcmp0 (g_getenv ("GSETTINGS_BACKEND"), "memory") != 0)
     983                 :            :     {
     984                 :          0 :       g_message ("Using the 'memory' GSettings backend.  Your settings "
     985                 :            :                  "will not be saved or shared with other applications.");
     986                 :            :     }
     987                 :            : 
     988                 :          4 :   g_settings_has_backend = TRUE;
     989                 :          4 :   return TRUE;
     990                 :            : }
     991                 :            : 
     992                 :            : /* We need to cache the default #GSettingsBackend for the entire process
     993                 :            :  * lifetime, especially if the backend is #GMemorySettingsBackend: it needs to
     994                 :            :  * keep the in-memory settings around even while there are no #GSettings
     995                 :            :  * instances alive. */
     996                 :            : static GSettingsBackend *settings_backend_default_singleton = NULL;  /* (owned) (atomic) */
     997                 :            : 
     998                 :            : /**
     999                 :            :  * g_settings_backend_get_default:
    1000                 :            :  *
    1001                 :            :  * Returns the default #GSettingsBackend. It is possible to override
    1002                 :            :  * the default by setting the `GSETTINGS_BACKEND` environment variable
    1003                 :            :  * to the name of a settings backend.
    1004                 :            :  *
    1005                 :            :  * The user gets a reference to the backend.
    1006                 :            :  *
    1007                 :            :  * Returns: (not nullable) (transfer full): the default #GSettingsBackend,
    1008                 :            :  *     which will be a dummy (memory) settings backend if no other settings
    1009                 :            :  *     backend is available.
    1010                 :            :  *
    1011                 :            :  * Since: 2.28
    1012                 :            :  */
    1013                 :            : GSettingsBackend *
    1014                 :         56 : g_settings_backend_get_default (void)
    1015                 :            : {
    1016   [ +  +  +  -  :         56 :   if (g_once_init_enter_pointer (&settings_backend_default_singleton))
                   +  + ]
    1017                 :            :     {
    1018                 :            :       GSettingsBackend *singleton;
    1019                 :            : 
    1020                 :          4 :       singleton = _g_io_module_get_default (G_SETTINGS_BACKEND_EXTENSION_POINT_NAME,
    1021                 :            :                                             "GSETTINGS_BACKEND",
    1022                 :            :                                             g_settings_backend_verify);
    1023                 :            : 
    1024                 :          4 :       g_once_init_leave_pointer (&settings_backend_default_singleton, singleton);
    1025                 :            :     }
    1026                 :            : 
    1027                 :         56 :   return g_object_ref (settings_backend_default_singleton);
    1028                 :            : }
    1029                 :            : 
    1030                 :            : /*< private >
    1031                 :            :  * g_settings_backend_get_permission:
    1032                 :            :  * @backend: a #GSettingsBackend
    1033                 :            :  * @path: a path
    1034                 :            :  *
    1035                 :            :  * Gets the permission object associated with writing to keys below
    1036                 :            :  * @path on @backend.
    1037                 :            :  *
    1038                 :            :  * If this is not implemented in the backend, then a %TRUE
    1039                 :            :  * #GSimplePermission is returned.
    1040                 :            :  *
    1041                 :            :  * Returns: (not nullable) (transfer full): a non-%NULL #GPermission.
    1042                 :            :  *     Free with g_object_unref()
    1043                 :            :  */
    1044                 :            : GPermission *
    1045                 :          0 : g_settings_backend_get_permission (GSettingsBackend *backend,
    1046                 :            :                                    const gchar      *path)
    1047                 :            : {
    1048                 :          0 :   GSettingsBackendClass *class = G_SETTINGS_BACKEND_GET_CLASS (backend);
    1049                 :            : 
    1050         [ #  # ]:          0 :   if (class->get_permission)
    1051                 :          0 :     return class->get_permission (backend, path);
    1052                 :            : 
    1053                 :          0 :   return g_simple_permission_new (TRUE);
    1054                 :            : }
    1055                 :            : 
    1056                 :            : /*< private >
    1057                 :            :  * g_settings_backend_sync_default:
    1058                 :            :  *
    1059                 :            :  * Syncs the default backend.
    1060                 :            :  */
    1061                 :            : void
    1062                 :         37 : g_settings_backend_sync_default (void)
    1063                 :            : {
    1064         [ +  + ]:         37 :   if (g_settings_has_backend)
    1065                 :            :     {
    1066                 :            :       GSettingsBackendClass *class;
    1067                 :            :       GSettingsBackend *backend;
    1068                 :            : 
    1069                 :          2 :       backend = g_settings_backend_get_default ();
    1070                 :          2 :       class = G_SETTINGS_BACKEND_GET_CLASS (backend);
    1071                 :            : 
    1072         [ -  + ]:          2 :       if (class->sync)
    1073                 :          0 :         class->sync (backend);
    1074                 :            : 
    1075                 :          2 :       g_object_unref (backend);
    1076                 :            :     }
    1077                 :         37 : }

Generated by: LCOV version 1.14