[glib/gsettings] add GSettings binding support
- From: Ryan Lortie <ryanl src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [glib/gsettings] add GSettings binding support
- Date: Wed, 30 Sep 2009 15:58:38 +0000 (UTC)
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]