LCOV - code coverage report
Current view: top level - gio - gsettingsbackend.c (source / functions) Coverage Total Hit
Test: unnamed Lines: 88.5 % 234 207
Test Date: 2024-11-26 05:23:01 Functions: 92.1 % 38 35
Branches: - 0 0

             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                 :         755 : 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                 :          43 : g_settings_backend_sync_default (void)
    1063                 :             : {
    1064                 :          43 :   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                 :          43 : }
        

Generated by: LCOV version 2.0-1