[glib/gsettings] add GSettings binding support



commit 4bde6e78de38a9e91e0c9c46f8aa10eb99bd4369
Author: Ryan Lortie <desrt desrt ca>
Date:   Tue Sep 29 16:48:03 2009 -0400

    add GSettings binding support

 gio/gsettings.c       |  206 ++++++++++++++++++++++++++++++++++++++++++++++++-
 gio/gsettings.h       |   72 ++++++++++-------
 gio/gsettingsschema.c |   12 +++
 gio/gsettingsschema.h |    4 +-
 4 files changed, 262 insertions(+), 32 deletions(-)
---
diff --git a/gio/gsettings.c b/gio/gsettings.c
index 7d9278c..cdfefe6 100644
--- a/gio/gsettings.c
+++ b/gio/gsettings.c
@@ -461,8 +461,8 @@ g_settings_class_init (GSettingsClass *class)
                   G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
                   G_STRUCT_OFFSET (GSettingsClass, changed),
                   NULL, NULL,
-                  g_cclosure_marshal_VOID__STRING,
-                  G_TYPE_NONE, 1, G_TYPE_STRING);
+                  g_cclosure_marshal_VOID__POINTER,
+                  G_TYPE_NONE, 1, G_TYPE_POINTER);
 
   g_settings_signals[SIGNAL_DESTROYED] =
     g_signal_new ("destroyed", G_TYPE_SETTINGS,
@@ -621,5 +621,207 @@ g_settings_destroy (GSettings *settings)
   g_signal_emit (settings, g_settings_signals[SIGNAL_DESTROYED], 0);
 }
 
+typedef struct
+{
+  GSettings *settings;
+  GObject *object;
+
+  guint property_handler_id;
+  const GParamSpec *property;
+  guint key_handler_id;
+  const GVariantType *type;
+  const gchar *key;
+
+  /* prevent recursion */
+  gboolean running;
+} GSettingsBinding;
+
+static void
+g_settings_binding_free (gpointer data)
+{
+  GSettingsBinding *binding = data;
+
+  g_assert (!binding->running);
+
+  if (binding->key_handler_id)
+    g_signal_handler_disconnect (binding->settings,
+                                 binding->key_handler_id);
+
+  if (binding->property_handler_id)
+  g_signal_handler_disconnect (binding->object,
+                               binding->property_handler_id);
+
+  g_object_unref (binding->settings);
+
+  g_slice_free (GSettingsBinding, binding);
+}
+
+static GQuark
+g_settings_binding_quark (const char *property)
+{
+  GQuark quark;
+  gchar *tmp;
+
+  tmp = g_strdup_printf ("gsettingsbinding-%s", property);
+  quark = g_quark_from_string (tmp);
+  g_free (tmp);
+
+  return quark;
+}
+
+static void
+g_settings_binding_key_changed (GSettings   *settings,
+                                const gchar *key,
+                                gpointer     user_data)
+{
+  GSettingsBinding *binding = user_data;
+  GValue value = {  };
+  GVariant *variant;
+
+  g_assert (settings == binding->settings);
+  g_assert (key == binding->key);
+
+  if (binding->running)
+    return;
+
+  binding->running = TRUE;
+
+  g_value_init (&value, binding->property->value_type);
+  variant = g_settings_get_value (settings, key);
+  if (g_value_deserialise (&value, variant))
+    g_object_set_property (binding->object,
+                           binding->property->name,
+                           &value);
+  g_value_unset (&value);
+
+  binding->running = FALSE;
+}
+
+static void
+g_settings_binding_property_changed (GObject          *object,
+                                     const GParamSpec *pspec,
+                                     gpointer          user_data)
+{
+  GSettingsBinding *binding = user_data;
+  GValue value = {  };
+  GVariant *variant;
+
+  g_assert (object == binding->object);
+  g_assert (pspec == binding->property);
+
+  if (binding->running)
+    return;
+
+  binding->running = TRUE;
+
+  g_value_init (&value, pspec->value_type);
+  g_object_get_property (object, pspec->name, &value);
+  if ((variant = g_value_serialise (&value, binding->type)))
+    {
+      g_settings_set_value (binding->settings,
+                            binding->key,
+                            variant);
+      g_variant_unref (variant);
+    }
+  g_value_unset (&value);
+
+  binding->running = FALSE;
+}
+
+void
+g_settings_bind (GSettings          *settings,
+                 const gchar        *key,
+                 gpointer            object,
+                 const gchar        *property,
+                 GSettingsBindFlags  flags)
+{
+  GSettingsBinding *binding;
+  GObjectClass *objectclass;
+  gchar *detailed_signal;
+  GQuark binding_quark;
+
+  objectclass = G_OBJECT_GET_CLASS (object);
+
+  binding = g_slice_new (GSettingsBinding);
+  binding->settings = g_object_ref (settings);
+  binding->object = object;
+  binding->key = g_intern_string (key);
+  binding->property = g_object_class_find_property (objectclass, property);
+  binding->running = FALSE;
+
+  if (!(flags & (G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET)))
+    flags |= G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET;
+
+  if (binding->property == NULL)
+    {
+      g_critical ("g_settings_bind: no property '%s' on class '%s'",
+                  property, G_OBJECT_TYPE_NAME (object));
+      return;
+    }
+
+  binding->type = g_settings_schema_get_key_type (settings->priv->schema,
+                                                  key);
+
+  if (binding->type == NULL)
+    {
+      g_critical ("g_settings_bind: no key '%s' on schema '%s'",
+                  key, settings->priv->schema_name);
+      return;
+    }
+
+  if (!g_type_serialiser_check (G_PARAM_SPEC_VALUE_TYPE (binding->property),
+                                binding->type))
+    {
+      g_critical ("g_settings_bind: property '%s' on class '%s' has type"
+                  "'%s' which is not compatible with type '%s' of key '%s'"
+                  "on schema '%s'", property, G_OBJECT_TYPE_NAME (object),
+                  g_type_name (binding->property->value_type),
+                  g_variant_type_dup_string (binding->type), key,
+                  settings->priv->schema_name);
+      return;
+    }
+
+  if (flags & G_SETTINGS_BIND_SET)
+    {
+      detailed_signal = g_strdup_printf ("notify::%s", property);
+      binding->property_handler_id =
+        g_signal_connect (object, detailed_signal,
+                          G_CALLBACK (g_settings_binding_property_changed),
+                          binding);
+      g_free (detailed_signal);
+
+      if (~flags & G_SETTINGS_BIND_GET)
+        g_settings_binding_property_changed (object,
+                                             binding->property,
+                                             binding);
+    }
+
+  if (flags & G_SETTINGS_BIND_GET)
+    {
+      detailed_signal = g_strdup_printf ("changed::%s", key);
+      binding->key_handler_id = 
+        g_signal_connect (settings, detailed_signal,
+                          G_CALLBACK (g_settings_binding_key_changed),
+                          binding);
+      g_free (detailed_signal);
+
+      g_settings_binding_key_changed (settings, binding->key, binding);
+    }
+
+  binding_quark = g_settings_binding_quark (property);
+  g_object_set_qdata_full (object, binding_quark,
+                           binding, g_settings_binding_free);
+}
+
+void
+g_settings_unbind (gpointer     object,
+                   const gchar *property)
+{
+  GQuark binding_quark;
+
+  binding_quark = g_settings_binding_quark (property);
+  g_object_set_qdata (object, binding_quark, NULL);
+}
+
 #define _gsettings_c_
 #include "gioaliasdef.c"
diff --git a/gio/gsettings.h b/gio/gsettings.h
index 508a7a8..03c9f98 100644
--- a/gio/gsettings.h
+++ b/gio/gsettings.h
@@ -50,47 +50,61 @@ struct _GSettings
   GSettingsPrivate *priv;
 };
 
+typedef enum
+{
+  G_SETTINGS_BIND_DEFAULT,
+  G_SETTINGS_BIND_GET            = (1<<0),
+  G_SETTINGS_BIND_SET            = (1<<1)
+} GSettingsBindFlags;
+
 G_BEGIN_DECLS
 
 GType                   g_settings_get_type                             (void);
-void                    g_settings_revert                               (GSettings      *settings);
-void                    g_settings_apply                                (GSettings      *settings);
+void                    g_settings_revert                               (GSettings          *settings);
+void                    g_settings_apply                                (GSettings          *settings);
 
-gboolean                g_settings_get_delay_apply                      (GSettings      *settings);
-gboolean                g_settings_get_has_unapplied                    (GSettings      *settings);
-void                    g_settings_set_delay_apply                      (GSettings      *settings,
-                                                                         gboolean        delay_apply);
-gboolean                g_settings_get_locked                           (GSettings      *settings);
-void                    g_settings_lock                                 (GSettings      *settings);
+gboolean                g_settings_get_delay_apply                      (GSettings          *settings);
+gboolean                g_settings_get_has_unapplied                    (GSettings          *settings);
+void                    g_settings_set_delay_apply                      (GSettings          *settings,
+                                                                         gboolean            delay_apply);
+gboolean                g_settings_get_locked                           (GSettings          *settings);
+void                    g_settings_lock                                 (GSettings          *settings);
 
-GSettings *             g_settings_new                                  (const gchar    *schema);
-GSettings *             g_settings_new_from_path                        (const gchar    *path);
+GSettings *             g_settings_new                                  (const gchar        *schema);
+GSettings *             g_settings_new_from_path                        (const gchar        *path);
 
-void                    g_settings_set_value                            (GSettings      *settings,
-                                                                         const gchar    *key,
-                                                                         GVariant       *value);
+void                    g_settings_set_value                            (GSettings          *settings,
+                                                                         const gchar        *key,
+                                                                         GVariant           *value);
 
-GVariant *              g_settings_get_value                            (GSettings      *settings,
-                                                                         const gchar    *key);
+GVariant *              g_settings_get_value                            (GSettings          *settings,
+                                                                         const gchar        *key);
 
-void                    g_settings_set                                  (GSettings      *settings,
-                                                                         const gchar    *first_key,
+void                    g_settings_set                                  (GSettings          *settings,
+                                                                         const gchar        *first_key,
                                                                          ...);
 
-void                    g_settings_get                                  (GSettings      *settings,
-                                                                         const gchar     *first_key,
+void                    g_settings_get                                  (GSettings          *settings,
+                                                                         const gchar        *first_key,
                                                                          ...);
 
-GSettings *             g_settings_get_settings                         (GSettings      *settings,
-                                                                         const gchar    *name);
-
-gboolean                g_settings_is_writable                          (GSettings      *settings,
-                                                                         const gchar    *name);
-void                    g_settings_changes                              (GSettings      *settings,
-                                                                         const GQuark   *keys,
-                                                                         gint            n_keys);
-void                    g_settings_destroy                              (GSettings      *settings);
-
+GSettings *             g_settings_get_settings                         (GSettings          *settings,
+                                                                         const gchar        *name);
+
+gboolean                g_settings_is_writable                          (GSettings          *settings,
+                                                                         const gchar        *name);
+void                    g_settings_changes                              (GSettings          *settings,
+                                                                         const GQuark       *keys,
+                                                                         gint                n_keys);
+void                    g_settings_destroy                              (GSettings          *settings);
+
+void                    g_settings_bind                                 (GSettings          *settings,
+                                                                         const gchar        *key,
+                                                                         gpointer            object,
+                                                                         const gchar        *property,
+                                                                         GSettingsBindFlags  flags);
+void                    g_settings_unbind                               (gpointer            object,
+                                                                         const gchar        *key);
 
 G_END_DECLS
 
diff --git a/gio/gsettingsschema.c b/gio/gsettingsschema.c
index 29e54fe..02c1c04 100644
--- a/gio/gsettingsschema.c
+++ b/gio/gsettingsschema.c
@@ -123,6 +123,18 @@ g_settings_schema_get_key_default (GSettingsSchema *schema,
   return value;
 }
 
+const GVariantType *
+g_settings_schema_get_key_type (GSettingsSchema *schema,
+                                const gchar     *key)
+{
+  GVariant *value;
+
+  if (!g_variant_lookup (schema->priv->keys, key, "(sv)", NULL, &value))
+    return NULL;
+
+  return g_variant_get_type (value);
+}
+
 gboolean
 g_settings_schema_type_check_key (GSettingsSchema *schema,
                                   const gchar     *key,
diff --git a/gio/gsettingsschema.h b/gio/gsettingsschema.h
index e01059b..c7987ce 100644
--- a/gio/gsettingsschema.h
+++ b/gio/gsettingsschema.h
@@ -56,8 +56,10 @@ gboolean                g_settings_schema_type_check_key                (GSettin
                                                                          GVariant        *value);
 gboolean                g_settings_schema_check_key                     (GSettingsSchema *schema,
                                                                          const gchar     *key);
+const GVariantType *    g_settings_schema_get_key_type                  (GSettingsSchema *schema,
+                                                                         const gchar     *key);
 
-const gchar     *       g_settings_schema_get_schema                    (GSettingsSchema *schema,
+const gchar *           g_settings_schema_get_schema                    (GSettingsSchema *schema,
                                                                          const gchar     *item);
 
 GVariant *              g_settings_schema_get_list_items                (GSettingsSchema *schema);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]