[glib/new-gsettings] maybe bindings work now. maybe not.
- From: Ryan Lortie <ryanl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib/new-gsettings] maybe bindings work now. maybe not.
- Date: Thu, 15 Apr 2010 04:15:57 +0000 (UTC)
commit 28c8a8f31f2cd876f3c1862c092afd75ea224529
Author: Ryan Lortie <desrt desrt ca>
Date: Thu Apr 15 00:12:19 2010 -0400
maybe bindings work now. maybe not.
gio/gsettings.c | 277 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
gio/gsettings.h | 32 +++++++
2 files changed, 309 insertions(+), 0 deletions(-)
---
diff --git a/gio/gsettings.c b/gio/gsettings.c
index 28e8090..9a886a8 100644
--- a/gio/gsettings.c
+++ b/gio/gsettings.c
@@ -939,3 +939,280 @@ g_settings_new_with_context_and_path (const gchar *schema,
"path", path,
NULL);
}
+
+typedef struct
+{
+ GSettings *settings;
+ GObject *object;
+
+ GSettingsBindGetMapping get_mapping;
+ GSettingsBindSetMapping set_mapping;
+ gpointer user_data;
+
+ guint property_handler_id;
+ const GParamSpec *property;
+ guint key_handler_id;
+ 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_variant_type_free (binding->type);
+ 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 (binding->get_mapping (&value, variant, binding->user_data))
+ 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 = binding->set_mapping (&value, binding->type,
+ binding->user_data)))
+ {
+ g_settings_set_value (binding->settings,
+ binding->key,
+ variant);
+ g_variant_unref (variant);
+ }
+ g_value_unset (&value);
+
+ binding->running = FALSE;
+}
+
+static GVariant *
+g_settings_set_mapping (const GValue *value,
+ const GVariantType *expected_type,
+ gpointer user_data)
+{
+ if (g_variant_type_is_subtype_of (expected_type, G_VARIANT_TYPE_BOOLEAN))
+ return g_variant_new_boolean (g_value_get_boolean (value));
+
+ g_error ("Sorry; non-boolean bindings are not supported\n");
+}
+
+static gboolean
+g_settings_get_mapping (GValue *value,
+ GVariant *variant,
+ gpointer user_data)
+{
+ if (g_variant_is_of_type (variant, G_VARIANT_TYPE_BOOLEAN))
+ g_value_set_boolean (value, g_variant_get_boolean (variant));
+ else
+ g_error ("Sorry; non-boolean bindings are not supported\n");
+
+ return TRUE;
+}
+
+void
+g_settings_bind (GSettings *settings,
+ const gchar *key,
+ gpointer object,
+ const gchar *property,
+ GSettingsBindFlags flags)
+{
+ g_settings_bind_with_mapping (settings, key, object, property,
+ flags, NULL, NULL, NULL);
+}
+
+void
+g_settings_bind_with_mapping (GSettings *settings,
+ const gchar *key,
+ gpointer object,
+ const gchar *property,
+ GSettingsBindFlags flags,
+ GSettingsBindGetMapping get_mapping,
+ GSettingsBindSetMapping set_mapping,
+ gpointer user_data)
+{
+ GSettingsBinding *binding;
+ GObjectClass *objectclass;
+ gchar *detailed_signal;
+ GQuark binding_quark;
+ gboolean insensitive;
+
+ 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;
+ binding->user_data = user_data;
+ binding->get_mapping = get_mapping ? get_mapping : g_settings_get_mapping;
+ binding->set_mapping = set_mapping ? set_mapping : g_settings_set_mapping;
+
+ 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;
+ }
+
+ {
+ GVariant *value;
+
+ value = g_settings_schema_get_value (settings->priv->schema, key, NULL);
+ binding->type = g_variant_type_copy (g_variant_get_type (value));
+ g_variant_unref (value);
+ }
+
+ if (binding->type == NULL)
+ {
+ g_critical ("g_settings_bind: no key '%s' on schema '%s'",
+ key, settings->priv->schema_name);
+ return;
+ }
+
+ if (get_mapping == NULL || set_mapping == NULL)
+ {
+ /* XXX do some simple checks for type compatibility
+
+ 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_NO_SENSITIVITY)
+ {
+ GParamSpec *sensitive;
+
+ sensitive = g_object_class_find_property (objectclass, "sensitive");
+ if (sensitive && sensitive->value_type == G_TYPE_BOOLEAN)
+ {
+ insensitive = !g_settings_is_writable (settings, key);
+ g_object_set (object, "sensitive", !insensitive, NULL);
+ }
+ else
+ insensitive = FALSE;
+ }
+ else
+ insensitive = FALSE;
+
+ if (!insensitive && (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);
+}
diff --git a/gio/gsettings.h b/gio/gsettings.h
index 4cac482..1805466 100644
--- a/gio/gsettings.h
+++ b/gio/gsettings.h
@@ -103,6 +103,38 @@ gboolean g_settings_get_has_unapplied (GSettin
void g_settings_set_delay_apply (GSettings *settings,
gboolean delay);
+typedef GVariant * (*GSettingsBindSetMapping) (const GValue *value,
+ const GVariantType *expected_type,
+ gpointer user_data);
+
+typedef gboolean (*GSettingsBindGetMapping) (GValue *value,
+ GVariant *variant,
+ gpointer user_data);
+
+typedef enum
+{
+ G_SETTINGS_BIND_DEFAULT,
+ G_SETTINGS_BIND_GET = (1<<0),
+ G_SETTINGS_BIND_SET = (1<<1),
+ G_SETTINGS_BIND_NO_SENSITIVITY = (1<<2)
+} GSettingsBindFlags;
+
+void g_settings_bind (GSettings *settings,
+ const gchar *key,
+ gpointer object,
+ const gchar *property,
+ GSettingsBindFlags flags);
+void g_settings_bind_with_mapping (GSettings *settings,
+ const gchar *key,
+ gpointer object,
+ const gchar *property,
+ GSettingsBindFlags flags,
+ GSettingsBindGetMapping get_mapping,
+ GSettingsBindSetMapping set_mapping,
+ gpointer user_data);
+void g_settings_unbind (gpointer object,
+ const gchar *key);
+
G_END_DECLS
#endif /* __G_SETTINGS_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]