[kdbus] sync with kdbus (kdbus.h - commit: 5ae1ecac44cb)
[platform/upstream/glib.git] / gio / gsettings.c
index 4e171ba..23a14bc 100644 (file)
  * the names must begin with a lowercase character, must not end
  * with a '-', and must not contain consecutive dashes.
  *
+ * GSettings supports change notification.  The primary mechanism to
+ * watch for changes is to connect to the "changed" signal.  You can
+ * optionally watch for changes on only a single key by using a signal
+ * detail.  Signals are only guaranteed to be emitted for a given key
+ * after you have read the value of that key while a signal handler was
+ * connected for that key.  Signals may or may not be emitted in the
+ * case that the key "changed" to the value that you had previously
+ * read.  Signals may be reported in additional cases as well and the
+ * "changed" signal should really be treated as "may have changed".
+ *
  * Similar to GConf, the default values in GSettings schemas can be
  * localized, but the localized values are stored in gettext catalogs
  * and looked up with the domain that is specified in the
- * gettext-domain attribute of the <schemalist> or <schema>
+ * gettext-domain attribute of the <schemalist> or <schema>
  * elements and the category that is specified in the l10n attribute of
- * the &lt;key&gt; element.
+ * the <key> element.
  *
  * GSettings uses schemas in a compact binary form that is created
- * by the <link linkend="glib-compile-schemas">glib-compile-schemas</link>
+ * by the [glib-compile-schemas][glib-compile-schemas]
  * utility. The input is a schema description in an XML format.
  *
  * A DTD for the gschema XML format can be found here:
  * [gschema.dtd](https://git.gnome.org/browse/glib/tree/gio/gschema.dtd)
  *
- * The <link linkend="glib-compile-schemas">glib-compile-schemas</link>
- * tool expects schema files to have the extension `.gschema.xml`.
+ * The [glib-compile-schemas][glib-compile-schemas] tool expects schema
+ * files to have the extension `.gschema.xml`.
  *
  * At runtime, schemas are identified by their id (as specified in the
- * id attribute of the &lt;schema&gt; element). The convention for schema
+ * id attribute of the <schema> element). The convention for schema
  * ids is to use a dotted name, similar in style to a D-Bus bus name,
  * e.g. "org.gnome.SessionManager". In particular, if the settings are
  * for a specific service that owns a D-Bus bus name, the D-Bus bus name
  * StudlyCaps, e.g. "org.gnome.font-rendering".
  *
  * In addition to #GVariant types, keys can have types that have
- * enumerated types. These can be described by a &lt;choice&gt;,
- * &lt;enum&gt; or &lt;flags&gt; element, see
- * <xref linkend="schema-enumerated"/>. The underlying type of
- * such a key is string, but you can use g_settings_get_enum(),
- * g_settings_set_enum(), g_settings_get_flags(), g_settings_set_flags()
- * access the numeric values corresponding to the string value of enum
- * and flags keys.
+ * enumerated types. These can be described by a <choice>,
+ * <enum> or <flags> element, as seen in the
+ * [example][schema-enumerated]. The underlying type of such a key
+ * is string, but you can use g_settings_get_enum(), g_settings_set_enum(),
+ * g_settings_get_flags(), g_settings_set_flags() access the numeric values
+ * corresponding to the string value of enum and flags keys.
  *
  * An example for default value:
  * |[
  * an application. Sometimes, it is necessary for a vendor or distributor
  * to adjust these defaults. Since patching the XML source for the schema
  * is inconvenient and error-prone,
- * <link linkend="glib-compile-schemas">glib-compile-schemas</link> reads
- * so-called 'vendor override' files. These are keyfiles in the same
- * directory as the XML schema sources which can override default values.
- * The schema id serves as the group name in the key file, and the values
- * are expected in serialized GVariant form, as in the following example:
+ * [glib-compile-schemas][glib-compile-schemas] reads so-called vendor
+ * override' files. These are keyfiles in the same directory as the XML
+ * schema sources which can override default values. The schema id serves
+ * as the group name in the key file, and the values are expected in
+ * serialized GVariant form, as in the following example:
  * |[
  *     [org.gtk.Example]
  *     key1='string'
@@ -230,6 +239,8 @@ struct _GSettingsPrivate
   GSettingsSchema *schema;
   gchar *path;
 
+  gboolean is_subscribed;
+
   GDelayedSettingsBackend *delayed;
 };
 
@@ -305,6 +316,32 @@ g_settings_real_writable_change_event (GSettings *settings,
   return FALSE;
 }
 
+static gboolean
+g_settings_has_signal_handlers (GSettings   *settings,
+                                const gchar *key)
+{
+  GSettingsClass *class = G_SETTINGS_GET_CLASS (settings);
+  GQuark keyq;
+
+  if (class->change_event != g_settings_real_change_event ||
+      class->writable_change_event != g_settings_real_writable_change_event)
+    return TRUE;
+
+  keyq = g_quark_from_string (key);
+
+  if (g_signal_has_handler_pending (settings, g_settings_signals[SIGNAL_WRITABLE_CHANGE_EVENT], 0, TRUE) ||
+      g_signal_has_handler_pending (settings, g_settings_signals[SIGNAL_WRITABLE_CHANGED], 0, TRUE) ||
+      g_signal_has_handler_pending (settings, g_settings_signals[SIGNAL_WRITABLE_CHANGED], keyq, TRUE) ||
+      g_signal_has_handler_pending (settings, g_settings_signals[SIGNAL_CHANGE_EVENT], 0, TRUE) ||
+      g_signal_has_handler_pending (settings, g_settings_signals[SIGNAL_CHANGED], 0, TRUE) ||
+      g_signal_has_handler_pending (settings, g_settings_signals[SIGNAL_CHANGED], keyq, TRUE))
+    return TRUE;
+
+  /* None of that?  Then surely nobody is watching.... */
+  return FALSE;
+}
+
+
 static void
 settings_backend_changed (GObject             *target,
                           GSettingsBackend    *backend,
@@ -358,8 +395,8 @@ static void
 settings_backend_keys_changed (GObject             *target,
                                GSettingsBackend    *backend,
                                const gchar         *path,
-                               const gchar * const *items,
-                               gpointer             origin_tag)
+                               gpointer             origin_tag,
+                               const gchar * const *items)
 {
   GSettings *settings = G_SETTINGS (target);
   gboolean ignore_this;
@@ -571,8 +608,6 @@ g_settings_constructed (GObject *object)
   g_settings_backend_watch (settings->priv->backend,
                             &listener_vtable, G_OBJECT (settings),
                             settings->priv->main_context);
-  g_settings_backend_subscribe (settings->priv->backend,
-                                settings->priv->path);
 }
 
 static void
@@ -580,8 +615,10 @@ g_settings_finalize (GObject *object)
 {
   GSettings *settings = G_SETTINGS (object);
 
-  g_settings_backend_unsubscribe (settings->priv->backend,
-                                  settings->priv->path);
+  if (settings->priv->is_subscribed)
+    g_settings_backend_unsubscribe (settings->priv->backend,
+                                    settings->priv->path);
+
   g_main_context_unref (settings->priv->main_context);
   g_object_unref (settings->priv->backend);
   g_settings_schema_unref (settings->priv->schema);
@@ -1046,6 +1083,13 @@ g_settings_read_from_backend (GSettings          *settings,
   GVariant *fixup;
   gchar *path;
 
+  /* If we are not yet watching for changes, consider doing it now... */
+  if (!settings->priv->is_subscribed && g_settings_has_signal_handlers (settings, key->name))
+    {
+      g_settings_backend_subscribe (settings->priv->backend, settings->priv->path);
+      settings->priv->is_subscribed = TRUE;
+    }
+
   path = g_strconcat (settings->priv->path, key->name, NULL);
   if (user_value_only)
     value = g_settings_backend_read_user_value (settings->priv->backend, path, key->type);
@@ -2172,14 +2216,14 @@ g_settings_is_writable (GSettings   *settings,
 /**
  * g_settings_get_child:
  * @settings: a #GSettings object
- * @name: the name of the 'child' schema
+ * @name: the name of the child schema
  *
- * Creates a 'child' settings object which has a base path of
- * <replaceable>base-path</replaceable>/@name, where
- * <replaceable>base-path</replaceable> is the base path of @settings.
+ * Creates a child settings object which has a base path of
+ * `base-path/@name`, where `base-path` is the base path of
+ * @settings.
  *
  * The schema for the child settings object must have been declared
- * in the schema of @settings using a &lt;child&gt; element.
+ * in the schema of @settings using a <child> element.
  *
  * Returns: (transfer full): a 'child' settings object
  *