[glib/new-gsettings] g_settings_bind() fixes



commit eedfbdf80f8f074f4374e34f2af4d5b6966aac9b
Author: Ryan Lortie <desrt desrt ca>
Date:   Fri Apr 16 22:49:35 2010 -0400

    g_settings_bind() fixes
    
     - track sensitivity changes
     - move vuntz-mapping code to new file
     - option to only get initial value from settings

 gio/Makefile.am         |    2 +
 gio/gsettings-mapping.c |  367 ++++++++++++++++++++++++++++++++++++++
 gio/gsettings-mapping.h |   39 ++++
 gio/gsettings.c         |  446 ++++++++---------------------------------------
 gio/gsettings.h         |    3 +-
 5 files changed, 485 insertions(+), 372 deletions(-)
---
diff --git a/gio/Makefile.am b/gio/Makefile.am
index 272695f..8b61721 100644
--- a/gio/Makefile.am
+++ b/gio/Makefile.am
@@ -97,6 +97,8 @@ settings_sources = \
 	gsettingsbackend.c		\
 	gsettingsschema.h		\
 	gsettingsschema.c		\
+	gsettings-mapping.h		\
+	gsettings-mapping.c		\
 	gsettings.c
 
 local_sources = \
diff --git a/gio/gsettings-mapping.c b/gio/gsettings-mapping.c
new file mode 100644
index 0000000..e7f1ba5
--- /dev/null
+++ b/gio/gsettings-mapping.c
@@ -0,0 +1,367 @@
+/*
+ * Copyright © 2010 Novell, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Vincent Untz <vuntz gnome org>
+ */
+
+#include "config.h"
+
+#include "gsettings-mapping.h"
+
+static GVariant *
+g_settings_set_mapping_numeric (const GValue       *value,
+                                const GVariantType *expected_type)
+{
+  GVariant *variant = NULL;
+  glong l;
+
+  if (G_VALUE_HOLDS_INT (value))
+    l = g_value_get_int (value);
+  else if (G_VALUE_HOLDS_INT64 (value))
+    l = g_value_get_int64 (value);
+  else if (G_VALUE_HOLDS_DOUBLE (value))
+    l = g_value_get_double (value);
+  else
+    return NULL;
+
+  if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_INT16))
+    {
+      if (G_MININT16 <= l && l <= G_MAXINT16)
+        variant = g_variant_new_int16 ((gint16) l);
+    }
+  else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_UINT16))
+    {
+      if (0 <= l && l <= G_MAXUINT16)
+        variant = g_variant_new_uint16 ((guint16) l);
+    }
+  else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_INT32))
+    {
+      if (G_MININT32 <= l && l <= G_MAXINT32)
+        variant = g_variant_new_int32 ((gint) l);
+    }
+  else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_UINT32))
+    {
+      if (0 <= l && l <= G_MAXUINT32)
+        variant = g_variant_new_uint32 ((guint) l);
+    }
+  else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_INT64))
+    {
+      if (G_MININT64 <= l && l <= G_MAXINT64)
+        variant = g_variant_new_int64 ((gint64) l);
+    }
+  else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_UINT64))
+    {
+      if (0 <= l && l <= G_MAXUINT64)
+        variant = g_variant_new_uint64 ((guint64) l);
+    }
+  else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_HANDLE))
+    {
+      if (0 <= l && l <= G_MAXUINT32)
+        variant = g_variant_new_handle ((guint) l);
+    }
+  else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_DOUBLE))
+    variant = g_variant_new_double ((double) l);
+
+  return variant;
+}
+
+static GVariant *
+g_settings_set_mapping_unsigned_numeric (const GValue       *value,
+                                         const GVariantType *expected_type)
+{
+  GVariant *variant = NULL;
+  gulong u;
+
+  if (G_VALUE_HOLDS_UINT (value))
+    u = g_value_get_uint (value);
+  else if (G_VALUE_HOLDS_UINT64 (value))
+    u = g_value_get_uint64 (value);
+  else
+    return NULL;
+
+  if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_INT16))
+    {
+      if (u <= G_MAXINT16)
+        variant = g_variant_new_int16 ((gint16) u);
+    }
+  else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_UINT16))
+    {
+      if (u <= G_MAXUINT16)
+        variant = g_variant_new_uint16 ((guint16) u);
+    }
+  else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_INT32))
+    {
+      if (u <= G_MAXINT32)
+        variant = g_variant_new_int32 ((gint) u);
+    }
+  else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_UINT32))
+    {
+      if (u <= G_MAXUINT32)
+        variant = g_variant_new_uint32 ((guint) u);
+    }
+  else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_INT64))
+    {
+      if (u <= G_MAXINT64)
+        variant = g_variant_new_int64 ((gint64) u);
+    }
+  else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_UINT64))
+    {
+      if (u <= G_MAXUINT64)
+        variant = g_variant_new_uint64 ((guint64) u);
+    }
+  else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_HANDLE))
+    {
+      if (u <= G_MAXUINT32)
+        variant = g_variant_new_handle ((guint) u);
+    }
+  else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_DOUBLE))
+    variant = g_variant_new_double ((double) u);
+
+  return variant;
+}
+
+static gboolean
+g_settings_get_mapping_numeric (GValue   *value,
+                                GVariant *variant)
+{
+  const GVariantType *type;
+  glong l;
+
+  type = g_variant_get_type (variant);
+
+  if (g_variant_type_equal (type, G_VARIANT_TYPE_INT16))
+    l = g_variant_get_int16 (variant);
+  else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT32))
+    l = g_variant_get_int32 (variant);
+  else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT64))
+    l = g_variant_get_int64 (variant);
+  else if (g_variant_type_equal (type, G_VARIANT_TYPE_DOUBLE))
+    l = g_variant_get_double (variant);
+  else
+    return FALSE;
+
+  if (G_VALUE_HOLDS_INT (value))
+    {
+      g_value_set_int (value, l);
+      return (G_MININT32 <= l && l <= G_MAXINT32);
+    }
+  else if (G_VALUE_HOLDS_UINT (value))
+    {
+      g_value_set_uint (value, l);
+      return (0 <= l && l <= G_MAXUINT32);
+    }
+  else if (G_VALUE_HOLDS_INT64 (value))
+    {
+      g_value_set_int64 (value, l);
+      return (G_MININT64 <= l && l <= G_MAXINT64);
+    }
+  else if (G_VALUE_HOLDS_UINT64 (value))
+    {
+      g_value_set_uint64 (value, l);
+      return (0 <= l && l <= G_MAXUINT64);
+    }
+  else if (G_VALUE_HOLDS_DOUBLE (value))
+    {
+      g_value_set_double (value, l);
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static gboolean
+g_settings_get_mapping_unsigned_numeric (GValue   *value,
+                                         GVariant *variant)
+{
+  const GVariantType *type;
+  gulong u;
+
+  type = g_variant_get_type (variant);
+
+  if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT16))
+    u = g_variant_get_uint16 (variant);
+  else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT32))
+    u = g_variant_get_uint32 (variant);
+  else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT64))
+    u = g_variant_get_uint64 (variant);
+  else if (g_variant_type_equal (type, G_VARIANT_TYPE_HANDLE))
+    u = g_variant_get_handle (variant);
+  else
+    return FALSE;
+
+  if (G_VALUE_HOLDS_INT (value))
+    {
+      g_value_set_int (value, u);
+      return (u <= G_MAXINT32);
+    }
+  else if (G_VALUE_HOLDS_UINT (value))
+    {
+      g_value_set_uint (value, u);
+      return (u <= G_MAXUINT32);
+    }
+  else if (G_VALUE_HOLDS_INT64 (value))
+    {
+      g_value_set_int64 (value, u);
+      return (u <= G_MAXINT64);
+    }
+  else if (G_VALUE_HOLDS_UINT64 (value))
+    {
+      g_value_set_uint64 (value, u);
+      return (u <= G_MAXUINT64);
+    }
+  else if (G_VALUE_HOLDS_DOUBLE (value))
+    {
+      g_value_set_double (value, u);
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+GVariant *
+g_settings_set_mapping (const GValue       *value,
+                        const GVariantType *expected_type,
+                        gpointer            user_data)
+{
+  gchar *type_string;
+
+  if (G_VALUE_HOLDS_BOOLEAN (value))
+    {
+      if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_BOOLEAN))
+        return g_variant_new_boolean (g_value_get_boolean (value));
+    }
+
+  else if (G_VALUE_HOLDS_CHAR (value)  ||
+           G_VALUE_HOLDS_UCHAR (value))
+    {
+      if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_BYTE))
+        {
+          if (G_VALUE_HOLDS_CHAR (value))
+            return g_variant_new_byte (g_value_get_char (value));
+          else
+            return g_variant_new_byte (g_value_get_uchar (value));
+        }
+    }
+
+  else if (G_VALUE_HOLDS_INT (value)   ||
+           G_VALUE_HOLDS_INT64 (value) ||
+           G_VALUE_HOLDS_DOUBLE (value))
+    return g_settings_set_mapping_numeric (value, expected_type);
+
+  else if (G_VALUE_HOLDS_UINT (value)  ||
+           G_VALUE_HOLDS_UINT64 (value))
+    return g_settings_set_mapping_unsigned_numeric (value, expected_type);
+
+  else if (G_VALUE_HOLDS_STRING (value))
+    {
+      if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_STRING))
+        return g_variant_new_string (g_value_get_string (value));
+      else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_OBJECT_PATH))
+        return g_variant_new_object_path (g_value_get_string (value));
+      else if (g_variant_type_equal (expected_type, G_VARIANT_TYPE_SIGNATURE))
+        return g_variant_new_signature (g_value_get_string (value));
+    }
+
+  type_string = g_variant_type_dup_string (expected_type);
+  g_critical ("No GSettings bind handler for type \"%s\".", type_string);
+  g_free (type_string);
+
+  return NULL;
+}
+
+gboolean
+g_settings_get_mapping (GValue   *value,
+                        GVariant *variant,
+                        gpointer  user_data)
+{
+  if (g_variant_is_of_type (variant, G_VARIANT_TYPE_BOOLEAN))
+    {
+      if (!G_VALUE_HOLDS_BOOLEAN (value))
+        return FALSE;
+      g_value_set_boolean (value, g_variant_get_boolean (variant));
+      return TRUE;
+    }
+
+  else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_BYTE))
+    {
+      if (G_VALUE_HOLDS_UCHAR (value))
+        g_value_set_uchar (value, g_variant_get_byte (variant));
+      else if (G_VALUE_HOLDS_CHAR (value))
+        g_value_set_char (value, (gchar) g_variant_get_byte (variant));
+      else
+        return FALSE;
+      return TRUE;
+    }
+
+  else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_INT16)  ||
+           g_variant_is_of_type (variant, G_VARIANT_TYPE_INT32)  ||
+           g_variant_is_of_type (variant, G_VARIANT_TYPE_INT64)  ||
+           g_variant_is_of_type (variant, G_VARIANT_TYPE_DOUBLE))
+    return g_settings_get_mapping_numeric (value, variant);
+
+  else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT16) ||
+           g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT32) ||
+           g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT64) ||
+           g_variant_is_of_type (variant, G_VARIANT_TYPE_HANDLE))
+    return g_settings_get_mapping_unsigned_numeric (value, variant);
+
+  else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING)      ||
+           g_variant_is_of_type (variant, G_VARIANT_TYPE_OBJECT_PATH) ||
+           g_variant_is_of_type (variant, G_VARIANT_TYPE_SIGNATURE))
+    {
+      g_value_set_string (value, g_variant_get_string (variant, NULL));
+      return TRUE;
+    }
+
+  g_critical ("No GSettings bind handler for type \"%s\".",
+              g_variant_get_type_string (variant));
+
+  return FALSE;
+}
+
+gboolean
+g_settings_mapping_is_compatible (GType               gvalue_type,
+                                  const GVariantType *variant_type)
+{
+  gboolean ok = FALSE;
+
+  if (gvalue_type == G_TYPE_BOOLEAN)
+    ok = g_variant_type_equal (variant_type, G_VARIANT_TYPE_BOOLEAN);
+  else if (gvalue_type == G_TYPE_CHAR  ||
+           gvalue_type == G_TYPE_UCHAR)
+    ok = g_variant_type_equal (variant_type, G_VARIANT_TYPE_BYTE);
+  else if (gvalue_type == G_TYPE_INT    ||
+           gvalue_type == G_TYPE_UINT   ||
+           gvalue_type == G_TYPE_INT64  ||
+           gvalue_type == G_TYPE_UINT64 ||
+           gvalue_type == G_TYPE_DOUBLE)
+    ok = (g_variant_type_equal (variant_type, G_VARIANT_TYPE_INT16)  ||
+          g_variant_type_equal (variant_type, G_VARIANT_TYPE_UINT16) ||
+          g_variant_type_equal (variant_type, G_VARIANT_TYPE_INT32)  ||
+          g_variant_type_equal (variant_type, G_VARIANT_TYPE_UINT32) ||
+          g_variant_type_equal (variant_type, G_VARIANT_TYPE_INT64)  ||
+          g_variant_type_equal (variant_type, G_VARIANT_TYPE_UINT64) ||
+          g_variant_type_equal (variant_type, G_VARIANT_TYPE_HANDLE) ||
+          g_variant_type_equal (variant_type, G_VARIANT_TYPE_DOUBLE));
+  else if (gvalue_type == G_TYPE_STRING)
+    ok = (g_variant_type_equal (variant_type, G_VARIANT_TYPE_STRING)      ||
+          g_variant_type_equal (variant_type, G_VARIANT_TYPE_OBJECT_PATH) ||
+          g_variant_type_equal (variant_type, G_VARIANT_TYPE_SIGNATURE));
+
+  return ok;
+}
diff --git a/gio/gsettings-mapping.h b/gio/gsettings-mapping.h
new file mode 100644
index 0000000..18ce318
--- /dev/null
+++ b/gio/gsettings-mapping.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright © 2010 Novell, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Vincent Untz <vuntz gnome org>
+ */
+
+#ifndef __G_SETTINGS_MAPPING_H__
+#define __G_SETTINGS_MAPPING_H__
+
+#include <glib-object.h>
+
+G_GNUC_INTERNAL
+GVariant *              g_settings_set_mapping                          (const GValue       *value,
+                                                                         const GVariantType *expected_type,
+                                                                         gpointer            user_data);
+G_GNUC_INTERNAL
+gboolean                g_settings_get_mapping                          (GValue             *value,
+                                                                         GVariant           *variant,
+                                                                         gpointer            user_data);
+G_GNUC_INTERNAL
+gboolean                g_settings_mapping_is_compatible                (GType               gvalue_type,
+                                                                         const GVariantType *variant_type);
+
+#endif /* __G_SETTINGS_MAPPING_H__ */
diff --git a/gio/gsettings.c b/gio/gsettings.c
index 92ae788..4d42838 100644
--- a/gio/gsettings.c
+++ b/gio/gsettings.c
@@ -1,11 +1,22 @@
 /*
- * Copyright © 2009 Codethink Limited
+ * Copyright © 2009, 2010 Codethink Limited
  *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of version 3 of the GNU General Public License as
- * published by the Free Software Foundation.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
  *
- * See the included COPYING file for more information.
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Ryan Lortie <desrt desrt ca>
  */
 
 #include "config.h"
@@ -17,6 +28,7 @@
 
 #include "gdelayedsettingsbackend.h"
 #include "gsettingsbackendinternal.h"
+#include "gsettings-mapping.h"
 #include "gio-marshal.h"
 #include "gsettingsschema.h"
 
@@ -1086,6 +1098,7 @@ typedef struct
   gpointer user_data;
   GDestroyNotify destroy;
 
+  guint writable_handler_id;
   guint property_handler_id;
   const GParamSpec *property;
   guint key_handler_id;
@@ -1103,8 +1116,11 @@ g_settings_binding_free (gpointer data)
 
   g_assert (!binding->running);
 
-  if (g_signal_handler_is_connected (binding->settings,
-                                     binding->key_handler_id))
+  if (binding->writable_handler_id)
+    g_signal_handler_disconnect (binding->settings,
+                                 binding->writable_handler_id);
+
+  if (binding->key_handler_id)
     g_signal_handler_disconnect (binding->settings,
                                  binding->key_handler_id);
 
@@ -1164,6 +1180,21 @@ g_settings_binding_key_changed (GSettings   *settings,
 }
 
 static void
+g_settings_binding_writable_changed (GSettings   *settings,
+                                     const gchar *key,
+                                     gpointer     user_data)
+{
+  GSettingsBinding *binding = user_data;
+  gboolean writable;
+
+  g_assert (settings == binding->settings);
+  g_assert (key == binding->key);
+
+  writable = g_settings_is_writable (settings, key);
+  g_object_set (binding->object, "sensitive", writable, NULL);
+}
+
+static void
 g_settings_binding_property_changed (GObject          *object,
                                      const GParamSpec *pspec,
                                      gpointer          user_data)
@@ -1195,316 +1226,6 @@ g_settings_binding_property_changed (GObject          *object,
   binding->running = FALSE;
 }
 
-static GVariant *
-g_settings_set_mapping_numeric (const GValue       *value,
-                                const GVariantType *expected_type)
-{
-  GVariant *variant = NULL;
-  glong l;
-
-  if (G_VALUE_HOLDS_INT (value))
-    l = g_value_get_int (value);
-  else if (G_VALUE_HOLDS_INT64 (value))
-    l = g_value_get_int64 (value);
-  else if (G_VALUE_HOLDS_DOUBLE (value))
-    l = g_value_get_double (value);
-  else
-    return NULL;
-
-  if (g_variant_type_is_subtype_of (expected_type, G_VARIANT_TYPE_INT16))
-    {
-      if (G_MININT16 <= l && l <= G_MAXINT16)
-        variant = g_variant_new_int16 ((gint16) l);
-    }
-  else if (g_variant_type_is_subtype_of (expected_type, G_VARIANT_TYPE_UINT16))
-    {
-      if (0 <= l && l <= G_MAXUINT16)
-        variant = g_variant_new_uint16 ((guint16) l);
-    }
-  else if (g_variant_type_is_subtype_of (expected_type, G_VARIANT_TYPE_INT32))
-    {
-      if (G_MININT32 <= l && l <= G_MAXINT32)
-        variant = g_variant_new_int32 ((gint) l);
-    }
-  else if (g_variant_type_is_subtype_of (expected_type, G_VARIANT_TYPE_UINT32))
-    {
-      if (0 <= l && l <= G_MAXUINT32)
-        variant = g_variant_new_uint32 ((guint) l);
-    }
-  else if (g_variant_type_is_subtype_of (expected_type, G_VARIANT_TYPE_INT64))
-    {
-      if (G_MININT64 <= l && l <= G_MAXINT64)
-        variant = g_variant_new_int64 ((gint64) l);
-    }
-  else if (g_variant_type_is_subtype_of (expected_type, G_VARIANT_TYPE_UINT64))
-    {
-      if (0 <= l && l <= G_MAXUINT64)
-        variant = g_variant_new_uint64 ((guint64) l);
-    }
-  else if (g_variant_type_is_subtype_of (expected_type, G_VARIANT_TYPE_HANDLE))
-    {
-      if (0 <= l && l <= G_MAXUINT32)
-        variant = g_variant_new_handle ((guint) l);
-    }
-  else if (g_variant_type_is_subtype_of (expected_type, G_VARIANT_TYPE_DOUBLE))
-    variant = g_variant_new_double ((double) l);
-
-  return variant;
-}
-
-static GVariant *
-g_settings_set_mapping_unsigned_numeric (const GValue       *value,
-                                         const GVariantType *expected_type)
-{
-  GVariant *variant = NULL;
-  gulong u;
-
-  if (G_VALUE_HOLDS_UINT (value))
-    u = g_value_get_uint (value);
-  else if (G_VALUE_HOLDS_UINT64 (value))
-    u = g_value_get_uint64 (value);
-  else
-    return NULL;
-
-  if (g_variant_type_is_subtype_of (expected_type, G_VARIANT_TYPE_INT16))
-    {
-      if (u <= G_MAXINT16)
-        variant = g_variant_new_int16 ((gint16) u);
-    }
-  else if (g_variant_type_is_subtype_of (expected_type, G_VARIANT_TYPE_UINT16))
-    {
-      if (u <= G_MAXUINT16)
-        variant = g_variant_new_uint16 ((guint16) u);
-    }
-  else if (g_variant_type_is_subtype_of (expected_type, G_VARIANT_TYPE_INT32))
-    {
-      if (u <= G_MAXINT32)
-        variant = g_variant_new_int32 ((gint) u);
-    }
-  else if (g_variant_type_is_subtype_of (expected_type, G_VARIANT_TYPE_UINT32))
-    {
-      if (u <= G_MAXUINT32)
-        variant = g_variant_new_uint32 ((guint) u);
-    }
-  else if (g_variant_type_is_subtype_of (expected_type, G_VARIANT_TYPE_INT64))
-    {
-      if (u <= G_MAXINT64)
-        variant = g_variant_new_int64 ((gint64) u);
-    }
-  else if (g_variant_type_is_subtype_of (expected_type, G_VARIANT_TYPE_UINT64))
-    {
-      if (u <= G_MAXUINT64)
-        variant = g_variant_new_uint64 ((guint64) u);
-    }
-  else if (g_variant_type_is_subtype_of (expected_type, G_VARIANT_TYPE_HANDLE))
-    {
-      if (u <= G_MAXUINT32)
-        variant = g_variant_new_handle ((guint) u);
-    }
-  else if (g_variant_type_is_subtype_of (expected_type, G_VARIANT_TYPE_DOUBLE))
-    variant = g_variant_new_double ((double) u);
-
-  return variant;
-}
-
-static gboolean
-g_settings_get_mapping_numeric (GValue   *value,
-                                GVariant *variant)
-{
-  const GVariantType *type;
-  glong l;
-
-  type = g_variant_get_type (variant);
-
-  if (g_variant_type_is_subtype_of (type, G_VARIANT_TYPE_INT16))
-    l = g_variant_get_int16 (variant);
-  else if (g_variant_type_is_subtype_of (type, G_VARIANT_TYPE_INT32))
-    l = g_variant_get_int32 (variant);
-  else if (g_variant_type_is_subtype_of (type, G_VARIANT_TYPE_INT64))
-    l = g_variant_get_int64 (variant);
-  else if (g_variant_type_is_subtype_of (type, G_VARIANT_TYPE_DOUBLE))
-    l = g_variant_get_double (variant);
-  else
-    return FALSE;
-
-  if (G_VALUE_HOLDS_INT (value))
-    {
-      g_value_set_int (value, l);
-      return (G_MININT32 <= l && l <= G_MAXINT32);
-    }
-  else if (G_VALUE_HOLDS_UINT (value))
-    {
-      g_value_set_uint (value, l);
-      return (0 <= l && l <= G_MAXUINT32);
-    }
-  else if (G_VALUE_HOLDS_INT64 (value))
-    {
-      g_value_set_int64 (value, l);
-      return (G_MININT64 <= l && l <= G_MAXINT64);
-    }
-  else if (G_VALUE_HOLDS_UINT64 (value))
-    {
-      g_value_set_uint64 (value, l);
-      return (0 <= l && l <= G_MAXUINT64);
-    }
-  else if (G_VALUE_HOLDS_DOUBLE (value))
-    {
-      g_value_set_double (value, l);
-      return TRUE;
-    }
-
-  return FALSE;
-}
-
-static gboolean
-g_settings_get_mapping_unsigned_numeric (GValue   *value,
-                                         GVariant *variant)
-{
-  const GVariantType *type;
-  gulong u;
-
-  type = g_variant_get_type (variant);
-
-  if (g_variant_type_is_subtype_of (type, G_VARIANT_TYPE_UINT16))
-    u = g_variant_get_uint16 (variant);
-  else if (g_variant_type_is_subtype_of (type, G_VARIANT_TYPE_UINT32))
-    u = g_variant_get_uint32 (variant);
-  else if (g_variant_type_is_subtype_of (type, G_VARIANT_TYPE_UINT64))
-    u = g_variant_get_uint64 (variant);
-  else if (g_variant_type_is_subtype_of (type, G_VARIANT_TYPE_HANDLE))
-    u = g_variant_get_handle (variant);
-  else
-    return FALSE;
-
-  if (G_VALUE_HOLDS_INT (value))
-    {
-      g_value_set_int (value, u);
-      return (u <= G_MAXINT32);
-    }
-  else if (G_VALUE_HOLDS_UINT (value))
-    {
-      g_value_set_uint (value, u);
-      return (u <= G_MAXUINT32);
-    }
-  else if (G_VALUE_HOLDS_INT64 (value))
-    {
-      g_value_set_int64 (value, u);
-      return (u <= G_MAXINT64);
-    }
-  else if (G_VALUE_HOLDS_UINT64 (value))
-    {
-      g_value_set_uint64 (value, u);
-      return (u <= G_MAXUINT64);
-    }
-  else if (G_VALUE_HOLDS_DOUBLE (value))
-    {
-      g_value_set_double (value, u);
-      return TRUE;
-    }
-
-  return FALSE;
-}
-
-static GVariant *
-g_settings_set_mapping (const GValue       *value,
-                        const GVariantType *expected_type,
-                        gpointer            user_data)
-{
-  gchar *type_string;
-
-  if (G_VALUE_HOLDS_BOOLEAN (value))
-    {
-      if (g_variant_type_is_subtype_of (expected_type, G_VARIANT_TYPE_BOOLEAN))
-        return g_variant_new_boolean (g_value_get_boolean (value));
-    }
-
-  else if (G_VALUE_HOLDS_CHAR (value)  ||
-           G_VALUE_HOLDS_UCHAR (value))
-    {
-      if (g_variant_type_is_subtype_of (expected_type, G_VARIANT_TYPE_BYTE))
-        {
-          if (G_VALUE_HOLDS_CHAR (value))
-            return g_variant_new_byte (g_value_get_char (value));
-          else
-            return g_variant_new_byte (g_value_get_uchar (value));
-        }
-    }
-
-  else if (G_VALUE_HOLDS_INT (value)   ||
-           G_VALUE_HOLDS_INT64 (value) ||
-           G_VALUE_HOLDS_DOUBLE (value))
-    return g_settings_set_mapping_numeric (value, expected_type);
-
-  else if (G_VALUE_HOLDS_UINT (value)  ||
-           G_VALUE_HOLDS_UINT64 (value))
-    return g_settings_set_mapping_unsigned_numeric (value, expected_type);
-
-  else if (G_VALUE_HOLDS_STRING (value))
-    {
-      if (g_variant_type_is_subtype_of (expected_type, G_VARIANT_TYPE_STRING))
-        return g_variant_new_string (g_value_get_string (value));
-      else if (g_variant_type_is_subtype_of (expected_type, G_VARIANT_TYPE_OBJECT_PATH))
-        return g_variant_new_object_path (g_value_get_string (value));
-      else if (g_variant_type_is_subtype_of (expected_type, G_VARIANT_TYPE_SIGNATURE))
-        return g_variant_new_signature (g_value_get_string (value));
-    }
-
-  type_string = g_variant_type_dup_string (expected_type);
-  g_critical ("No GSettings bind handler for type \"%s\".", type_string);
-  g_free (type_string);
-
-  return NULL;
-}
-
-static gboolean
-g_settings_get_mapping (GValue   *value,
-                        GVariant *variant,
-                        gpointer  user_data)
-{
-  if (g_variant_is_of_type (variant, G_VARIANT_TYPE_BOOLEAN))
-    {
-      if (!G_VALUE_HOLDS_BOOLEAN (value))
-        return FALSE;
-      g_value_set_boolean (value, g_variant_get_boolean (variant));
-      return TRUE;
-    }
-
-  else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_BYTE))
-    {
-      if (G_VALUE_HOLDS_UCHAR (value))
-        g_value_set_uchar (value, g_variant_get_byte (variant));
-      else if (G_VALUE_HOLDS_CHAR (value))
-        g_value_set_char (value, (gchar) g_variant_get_byte (variant));
-      else
-        return FALSE;
-      return TRUE;
-    }
-
-  else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_INT16)  ||
-           g_variant_is_of_type (variant, G_VARIANT_TYPE_INT32)  ||
-           g_variant_is_of_type (variant, G_VARIANT_TYPE_INT64)  ||
-           g_variant_is_of_type (variant, G_VARIANT_TYPE_DOUBLE))
-    return g_settings_get_mapping_numeric (value, variant);
-
-  else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT16) ||
-           g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT32) ||
-           g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT64) ||
-           g_variant_is_of_type (variant, G_VARIANT_TYPE_HANDLE))
-    return g_settings_get_mapping_unsigned_numeric (value, variant);
-
-  else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING)      ||
-           g_variant_is_of_type (variant, G_VARIANT_TYPE_OBJECT_PATH) ||
-           g_variant_is_of_type (variant, G_VARIANT_TYPE_SIGNATURE))
-    {
-      g_value_set_string (value, g_variant_get_string (variant, NULL));
-      return TRUE;
-    }
-
-  g_critical ("No GSettings bind handler for type \"%s\".", g_variant_get_type_string (variant));
-
-  return FALSE;
-}
-
 /**
  * g_settings_bind:
  * @settings: a #GSettings object
@@ -1581,18 +1302,17 @@ g_settings_bind_with_mapping (GSettings               *settings,
 {
   GSettingsBinding *binding;
   GObjectClass *objectclass;
+  gboolean bind_sensitive;
   gchar *detailed_signal;
   GQuark binding_quark;
-  gboolean insensitive;
 
   objectclass = G_OBJECT_GET_CLASS (object);
 
-  binding = g_slice_new (GSettingsBinding);
+  binding = g_slice_new0 (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->destroy = destroy;
   binding->get_mapping = get_mapping ? get_mapping : g_settings_get_mapping;
@@ -1624,63 +1344,32 @@ g_settings_bind_with_mapping (GSettings               *settings,
       return;
     }
 
-  if ((get_mapping == NULL && (flags & G_SETTINGS_BIND_GET)) ||
-      (set_mapping == NULL && (flags & G_SETTINGS_BIND_SET)))
+  if (((get_mapping == NULL && (flags & G_SETTINGS_BIND_GET)) ||
+       (set_mapping == NULL && (flags & G_SETTINGS_BIND_SET))) &&
+      !g_settings_mapping_is_compatible (binding->property->value_type,
+                                         binding->type))
     {
-      gboolean ok = FALSE;
-
-      if (binding->property->value_type == G_TYPE_BOOLEAN)
-        ok = g_variant_type_is_subtype_of (binding->type, G_VARIANT_TYPE_BOOLEAN);
-      else if (binding->property->value_type == G_TYPE_CHAR  ||
-               binding->property->value_type == G_TYPE_UCHAR)
-        ok = g_variant_type_is_subtype_of (binding->type, G_VARIANT_TYPE_BYTE);
-      else if (binding->property->value_type == G_TYPE_INT    ||
-               binding->property->value_type == G_TYPE_UINT   ||
-               binding->property->value_type == G_TYPE_INT64  ||
-               binding->property->value_type == G_TYPE_UINT64 ||
-               binding->property->value_type == G_TYPE_DOUBLE)
-        ok = (g_variant_type_is_subtype_of (binding->type, G_VARIANT_TYPE_INT16)  ||
-              g_variant_type_is_subtype_of (binding->type, G_VARIANT_TYPE_UINT16) ||
-              g_variant_type_is_subtype_of (binding->type, G_VARIANT_TYPE_INT32)  ||
-              g_variant_type_is_subtype_of (binding->type, G_VARIANT_TYPE_UINT32) ||
-              g_variant_type_is_subtype_of (binding->type, G_VARIANT_TYPE_INT64)  ||
-              g_variant_type_is_subtype_of (binding->type, G_VARIANT_TYPE_UINT64) ||
-              g_variant_type_is_subtype_of (binding->type, G_VARIANT_TYPE_HANDLE) ||
-              g_variant_type_is_subtype_of (binding->type, G_VARIANT_TYPE_DOUBLE));
-      else if (binding->property->value_type == G_TYPE_STRING)
-        ok = (g_variant_type_is_subtype_of (binding->type, G_VARIANT_TYPE_STRING)      ||
-              g_variant_type_is_subtype_of (binding->type, G_VARIANT_TYPE_OBJECT_PATH) ||
-              g_variant_type_is_subtype_of (binding->type, G_VARIANT_TYPE_SIGNATURE));
-
-      if (!ok)
-        {
-          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;
-        }
+      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)
+  if ((flags & G_SETTINGS_BIND_SET) &&
+      (~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;
+      bind_sensitive = sensitive && sensitive->value_type == G_TYPE_BOOLEAN;
     }
   else
-    insensitive = FALSE;
+    bind_sensitive = FALSE;
 
-  if (!insensitive && (flags & G_SETTINGS_BIND_SET))
+  if (flags & G_SETTINGS_BIND_SET)
     {
       detailed_signal = g_strdup_printf ("notify::%s", property);
       binding->property_handler_id =
@@ -1697,14 +1386,29 @@ g_settings_bind_with_mapping (GSettings               *settings,
 
   if (flags & G_SETTINGS_BIND_GET)
     {
-      detailed_signal = g_strdup_printf ("changed::%s", key);
-      binding->key_handler_id =
+      if (~flags & G_SETTINGS_BIND_GET_NO_CHANGES)
+        {
+          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);
+    }
+
+  if (bind_sensitive)
+    {
+      detailed_signal = g_strdup_printf ("writable-changed::%s", key);
+      binding->writable_handler_id =
         g_signal_connect (settings, detailed_signal,
-                          G_CALLBACK (g_settings_binding_key_changed),
+                          G_CALLBACK (g_settings_binding_writable_changed),
                           binding);
       g_free (detailed_signal);
 
-      g_settings_binding_key_changed (settings, binding->key, binding);
+      g_settings_binding_writable_changed (settings, binding->key, binding);
     }
 
   binding_quark = g_settings_binding_quark (property);
diff --git a/gio/gsettings.h b/gio/gsettings.h
index 7902922..5a70b5d 100644
--- a/gio/gsettings.h
+++ b/gio/gsettings.h
@@ -177,7 +177,8 @@ 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)
+  G_SETTINGS_BIND_NO_SENSITIVITY = (1<<2),
+  G_SETTINGS_BIND_GET_NO_CHANGES = (1<<3)
 } GSettingsBindFlags;
 
 void                    g_settings_bind                                 (GSettings               *settings,



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