[glib] GSettings: add G_SETTINGS_BIND_INVERT_BOOLEAN flag



commit ca3b7b75bff00ea05c967eea06e2c3397da17e41
Author: Ryan Lortie <desrt desrt ca>
Date:   Tue Aug 3 02:08:03 2010 -0400

    GSettings: add G_SETTINGS_BIND_INVERT_BOOLEAN flag
    
    When binding a boolean setting to a boolean property, invert the values.
    This avoids the requirement for writing a pair of mapping functions for
    this extremely common case.
    
    Add a test.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=625833

 gio/gsettings.c                    |   71 +++++++++++++++++++++++++++++++++---
 gio/gsettings.h                    |    6 +++-
 gio/tests/gsettings.c              |   21 ++++++++++-
 gio/tests/org.gtk.test.gschema.xml |    3 ++
 4 files changed, 93 insertions(+), 8 deletions(-)
---
diff --git a/gio/gsettings.c b/gio/gsettings.c
index 8636d66..4433971 100644
--- a/gio/gsettings.c
+++ b/gio/gsettings.c
@@ -2285,6 +2285,23 @@ g_settings_binding_property_changed (GObject          *object,
   binding->running = FALSE;
 }
 
+static gboolean
+g_settings_bind_invert_boolean_get_mapping (GValue   *value,
+                                            GVariant *variant,
+                                            gpointer  user_data)
+{
+  g_value_set_boolean (value, !g_variant_get_boolean (variant));
+  return TRUE;
+}
+
+static GVariant *
+g_settings_bind_invert_boolean_set_mapping (const GValue       *value,
+                                            const GVariantType *expected_type,
+                                            gpointer            user_data)
+{
+  return g_variant_new_boolean (!g_value_get_boolean (value));
+}
+
 /**
  * g_settings_bind:
  * @settings: a #GSettings object
@@ -2323,8 +2340,20 @@ g_settings_bind (GSettings          *settings,
                  const gchar        *property,
                  GSettingsBindFlags  flags)
 {
-  g_settings_bind_with_mapping (settings, key, object, property,
-                                flags, NULL, NULL, NULL, NULL);
+  GSettingsBindGetMapping get_mapping = NULL;
+  GSettingsBindSetMapping set_mapping = NULL;
+
+  if (flags & G_SETTINGS_BIND_INVERT_BOOLEAN)
+    {
+      get_mapping = g_settings_bind_invert_boolean_get_mapping;
+      set_mapping = g_settings_bind_invert_boolean_set_mapping;
+
+      /* can't pass this flag to g_settings_bind_with_mapping() */
+      flags &= ~G_SETTINGS_BIND_INVERT_BOOLEAN;
+    }
+
+  g_settings_bind_with_mapping (settings, key, object, property, flags,
+                                get_mapping, set_mapping, NULL, NULL);
 }
 
 /**
@@ -2371,6 +2400,7 @@ g_settings_bind_with_mapping (GSettings               *settings,
   GQuark binding_quark;
 
   g_return_if_fail (G_IS_SETTINGS (settings));
+  g_return_if_fail (~flags & G_SETTINGS_BIND_INVERT_BOOLEAN);
 
   objectclass = G_OBJECT_GET_CLASS (object);
 
@@ -2408,10 +2438,39 @@ 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))) &&
-      !g_settings_mapping_is_compatible (binding->property->value_type,
-                                         binding->info.type))
+  if (get_mapping == g_settings_bind_invert_boolean_get_mapping)
+    {
+      /* g_settings_bind_invert_boolean_get_mapping() is a private
+       * function, so if we are here it means that g_settings_bind() was
+       * called with G_SETTINGS_BIND_INVERT_BOOLEAN.
+       *
+       * Ensure that both sides are boolean.
+       */
+
+      if (binding->property->value_type != G_TYPE_BOOLEAN)
+        {
+          g_critical ("g_settings_bind: G_SETTINGS_BIND_INVERT_BOOLEAN "
+                      "was specified, but property `%s' on type `%s' has "
+                      "type `%s'", property, G_OBJECT_TYPE_NAME (object),
+                      g_type_name ((binding->property->value_type)));
+          return;
+        }
+
+      if (!g_variant_type_equal (binding->info.type, G_VARIANT_TYPE_BOOLEAN))
+        {
+          g_critical ("g_settings_bind: G_SETTINGS_BIND_INVERT_BOOLEAN "
+                      "was specified, but key `%s' on schema `%s' has "
+                      "type `%s'", key, settings->priv->schema_name,
+                      g_variant_type_dup_string (binding->info.type));
+          return;
+        }
+
+    }
+
+  else 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->info.type))
     {
       g_critical ("g_settings_bind: property '%s' on class '%s' has type "
                   "'%s' which is not compatible with type '%s' of key '%s' "
diff --git a/gio/gsettings.h b/gio/gsettings.h
index 799370e..938ec1e 100644
--- a/gio/gsettings.h
+++ b/gio/gsettings.h
@@ -207,6 +207,9 @@ typedef gboolean      (*GSettingsGetMapping)                            (GVarian
  * @G_SETTINGS_BIND_NO_SENSITIVITY: Do not try to bind a "sensitivity" property to the writability of the setting
  * @G_SETTINGS_BIND_GET_NO_CHANGES: When set in addition to #G_SETTINGS_BIND_GET, set the #GObject property
  *     value initially from the setting, but do not listen for changes of the setting
+ * @G_SETTINGS_BIND_INVERT_BOOLEAN: When passed to g_settings_bind(), uses a pair of mapping functions that invert
+ *     the boolean value when mapping between the setting and the property.  The setting and property must both
+ *     be booleans.  You can not pass this flag to g_settings_bind_with_mapping().
  *
  * Flags used when creating a binding. These flags determine in which
  * direction the binding works. The default is to synchronize in both
@@ -218,7 +221,8 @@ typedef enum
   G_SETTINGS_BIND_GET            = (1<<0),
   G_SETTINGS_BIND_SET            = (1<<1),
   G_SETTINGS_BIND_NO_SENSITIVITY = (1<<2),
-  G_SETTINGS_BIND_GET_NO_CHANGES = (1<<3)
+  G_SETTINGS_BIND_GET_NO_CHANGES = (1<<3),
+  G_SETTINGS_BIND_INVERT_BOOLEAN = (1<<4)
 } GSettingsBindFlags;
 
 void                    g_settings_bind                                 (GSettings               *settings,
diff --git a/gio/tests/gsettings.c b/gio/tests/gsettings.c
index 864871c..1f6942f 100644
--- a/gio/tests/gsettings.c
+++ b/gio/tests/gsettings.c
@@ -681,6 +681,7 @@ enum
 {
   PROP_0,
   PROP_BOOL,
+  PROP_ANTI_BOOL,
   PROP_BYTE,
   PROP_INT16,
   PROP_UINT16,
@@ -701,6 +702,7 @@ typedef struct
   GObject parent_instance;
 
   gboolean bool_prop;
+  gboolean anti_bool_prop;
   gchar byte_prop;
   gint int16_prop;
   guint16 uint16_prop;
@@ -750,6 +752,9 @@ test_object_get_property (GObject    *object,
     case PROP_BOOL:
       g_value_set_boolean (value, test_object->bool_prop);
       break;
+    case PROP_ANTI_BOOL:
+      g_value_set_boolean (value, test_object->anti_bool_prop);
+      break;
     case PROP_BYTE:
       g_value_set_char (value, test_object->byte_prop);
       break;
@@ -805,6 +810,9 @@ test_object_set_property (GObject      *object,
     case PROP_BOOL:
       test_object->bool_prop = g_value_get_boolean (value);
       break;
+    case PROP_ANTI_BOOL:
+      test_object->anti_bool_prop = g_value_get_boolean (value);
+      break;
     case PROP_BYTE:
       test_object->byte_prop = g_value_get_char (value);
       break;
@@ -883,6 +891,8 @@ test_object_class_init (TestObjectClass *class)
 
   g_object_class_install_property (gobject_class, PROP_BOOL,
     g_param_spec_boolean ("bool", "", "", FALSE, G_PARAM_READWRITE));
+  g_object_class_install_property (gobject_class, PROP_ANTI_BOOL,
+    g_param_spec_boolean ("anti-bool", "", "", FALSE, G_PARAM_READWRITE));
   g_object_class_install_property (gobject_class, PROP_BYTE,
     g_param_spec_char ("byte", "", "", G_MININT8, G_MAXINT8, 0, G_PARAM_READWRITE));
   g_object_class_install_property (gobject_class, PROP_INT16,
@@ -942,7 +952,6 @@ test_simple_binding (void)
   obj = test_object_new ();
 
   g_settings_bind (settings, "bool", obj, "bool", G_SETTINGS_BIND_DEFAULT);
-
   g_object_set (obj, "bool", TRUE, NULL);
   g_assert_cmpint (g_settings_get_boolean (settings, "bool"), ==, TRUE);
 
@@ -951,6 +960,16 @@ test_simple_binding (void)
   g_object_get (obj, "bool", &b, NULL);
   g_assert_cmpint (b, ==, FALSE);
 
+  g_settings_bind (settings, "anti-bool", obj, "anti-bool",
+                   G_SETTINGS_BIND_INVERT_BOOLEAN);
+  g_object_set (obj, "anti-bool", FALSE, NULL);
+  g_assert_cmpint (g_settings_get_boolean (settings, "anti-bool"), ==, TRUE);
+
+  g_settings_set_boolean (settings, "anti-bool", FALSE);
+  b = FALSE;
+  g_object_get (obj, "anti-bool", &b, NULL);
+  g_assert_cmpint (b, ==, TRUE);
+
   g_settings_bind (settings, "byte", obj, "byte", G_SETTINGS_BIND_DEFAULT);
 
   g_object_set (obj, "byte", 123, NULL);
diff --git a/gio/tests/org.gtk.test.gschema.xml b/gio/tests/org.gtk.test.gschema.xml
index 4bc5bcd..6d166d8 100644
--- a/gio/tests/org.gtk.test.gschema.xml
+++ b/gio/tests/org.gtk.test.gschema.xml
@@ -81,6 +81,9 @@
     <key name="bool" type="b">
       <default>false</default>
     </key>
+    <key name="anti-bool" type="b">
+      <default>false</default>
+    </key>
     <key name="byte" type="y">
       <default>0</default>
     </key>



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