[glib/g-property: 27/27] gproperty: Allow control over the accessors copy semantics



commit 42e79ad6fb4e23be31714559f34e2d679691a0f7
Author: Emmanuele Bassi <ebassi linux intel com>
Date:   Thu Aug 18 11:27:24 2011 +0100

    gproperty: Allow control over the accessors copy semantics
    
    It should be possible to define whether a property will take a
    reference, or make a copy, of the value being set or retrieved,
    so that we can reflect this behaviour inside the introspection
    and documentation.
    
    In order to do that, we can add two new flags to GProperty, detailing
    the behaviour for setter and getter separately (and a simple shorthand
    for both).
    
    By default, GProperty will now not copy a boxed type, or take a
    reference on an object type, when setting a new value; it is up
    to the developer to specify this behaviour.

 docs/reference/gobject/gobject-sections.txt |    2 +
 gobject/gobject.symbols                     |    2 +
 gobject/gproperty.c                         |  153 +++++++++++++++++++++------
 gobject/gproperty.h                         |   14 +++-
 gobject/tests/autoproperties.c              |    2 +-
 gobject/tests/gproperty-example-base.c      |    3 +-
 gobject/tests/gproperty-example-derived.c   |    9 +-
 7 files changed, 144 insertions(+), 41 deletions(-)
---
diff --git a/docs/reference/gobject/gobject-sections.txt b/docs/reference/gobject/gobject-sections.txt
index 2e3a936..e715525 100644
--- a/docs/reference/gobject/gobject-sections.txt
+++ b/docs/reference/gobject/gobject-sections.txt
@@ -892,6 +892,8 @@ g_property_is_writable
 g_property_is_redable
 g_property_is_deprecated
 g_property_is_atomic
+g_property_is_copy_set
+g_property_is_copy_get
 g_property_describe
 g_property_set_range_values
 g_property_get_range_values
diff --git a/gobject/gobject.symbols b/gobject/gobject.symbols
index 1722924..fde734a 100644
--- a/gobject/gobject.symbols
+++ b/gobject/gobject.symbols
@@ -233,6 +233,8 @@ g_property_get_valist
 g_property_get_value
 g_property_get_value_type
 g_property_is_atomic
+g_property_is_copy_get
+g_property_is_copy_set
 g_property_is_deprecated
 g_property_is_readable
 g_property_is_writable
diff --git a/gobject/gproperty.c b/gobject/gproperty.c
index b94b62b..89ff1d5 100644
--- a/gobject/gproperty.c
+++ b/gobject/gproperty.c
@@ -156,11 +156,18 @@
  * ]|
  *     <para>Note that calling g_property_set() for a property holding a
  *     complex type (e.g. #GObject or #GBoxed) without a specific setter
- *     function will result in the value being copied in the private data
- *     structure's field. In contrast, calling g_property_get() will return
- *     a pointer to the private data structure's field: it is up to the
- *     getter function to decide whether to return a copy of the internal
- *     data or the pointer itself.</para>
+ *     function will, by default, result in the pointer to the new value
+ *     being copied in the private data structure's field; if you need to
+ *     copy a boxed type, or take a reference on an object type, you will
+ *     need to set the %G_PROPERTY_COPY_SET flag when creating the
+ *     property.</para>
+ *
+ *     <para>Calling g_property_get() will return a pointer to the private
+ *     data structure's field, unless %G_PROPERTY_COPY_GET is set when
+ *     creating the property, in which case the returned value will either
+ *     be a copy of the private data structure field if it is a boxed type
+ *     or the instance with its reference count increased if it is an object
+ *     type.</para>
  *   </refsect3>
  *
  *   <refsect3>
@@ -363,7 +370,7 @@
  *
  * |[
  *     test_object_property[PROP_WIDTH] =
- *       g_int_property_new ("width", G_PROPERTY_READWRITE,
+ *       g_int_property_new ("width", G_PROPERTY_READWRITE | G_PROPERTY_COPY_SET,
  *                           G_STRUCT_OFFSET (TestObjectPrivate, width),
  *                           test_object_set_width, /&ast; explicit setter &ast;/
  *                           NULL                   /&ast; implicit getter &ast;/);
@@ -432,7 +439,7 @@
  * |[
  *   G_DEFINE_PROPERTY_GET (TestObject, test_object, int, width)
  *   G_DEFINE_PROPERTY_SET_WITH_CODE (Test_object, test_object, int, width,
- *                                    test_object_queue_resize (self))
+ *                                    test_object_queue_action (self))
  * ]|
  *
  *   <para>The WITH_CODE variant of the setter will define the "self" and
@@ -2405,8 +2412,13 @@ g_string_property_set_value (GProperty   *property,
           return FALSE;
         }
 
-      g_free (str);
-      (* (gpointer *) field_p) = g_strdup (value);
+      if (property->flags & G_PROPERTY_COPY_SET)
+        {
+          g_free (str);
+          (* (gpointer *) field_p) = g_strdup (value);
+        }
+      else
+        (* (gpointer *) field_p) = (gpointer) value;
 
       property_unlock_internal (property, gobject);
 
@@ -2446,7 +2458,10 @@ g_string_property_get_value (GProperty *property,
       priv_p = get_private_pointer (gobject, property->priv_offset);
       field_p = G_STRUCT_MEMBER_P (priv_p, property->field_offset);
 
-      retval = (* (gpointer *) field_p);
+      if (property->flags & G_PROPERTY_COPY_GET)
+        retval = g_strdup ((* (gpointer *) field_p));
+      else
+        retval = (* (gpointer *) field_p);
 
       return retval;
     }
@@ -2612,15 +2627,20 @@ g_boxed_property_set_value (GProperty *property,
       priv_p = get_private_pointer (gobject, property->priv_offset);
       field_p = G_STRUCT_MEMBER_P (priv_p, property->field_offset);
 
-      old_value = (* (gpointer *) field_p);
+      if (property->flags & G_PROPERTY_COPY_SET)
+        {
+          old_value = (* (gpointer *) field_p);
 
-      if (value != NULL)
-        (* (gpointer *) field_p) = g_boxed_copy (((GParamSpec *) property)->value_type, value);
-      else
-        (* (gpointer *) field_p) = NULL;
+          if (value != NULL)
+            (* (gpointer *) field_p) = g_boxed_copy (((GParamSpec *) property)->value_type, value);
+          else
+            (* (gpointer *) field_p) = NULL;
 
-      if (old_value != NULL)
-        g_boxed_free (((GParamSpec *) property)->value_type, old_value);
+          if (old_value != NULL)
+            g_boxed_free (((GParamSpec *) property)->value_type, old_value);
+        }
+      else
+        (* (gpointer *) field_p) = value;
 
       property_unlock_internal (property, gobject);
 
@@ -2659,7 +2679,11 @@ g_boxed_property_get_value (GProperty *property,
 
       priv_p = get_private_pointer (gobject, property->priv_offset);
       field_p = G_STRUCT_MEMBER_P (priv_p, property->field_offset);
-      value = (* (gpointer *) field_p);
+
+      if (property->flags & G_PROPERTY_COPY_GET)
+        value = g_boxed_copy (((GParamSpec *) property)->value_type, (* (gpointer *) field_p));
+      else
+        value = (* (gpointer *) field_p);
 
       return value;
     }
@@ -2836,19 +2860,24 @@ g_object_property_set_value (GProperty *property,
           return FALSE;
         }
 
-      obj = (* (gpointer *) field_p);
-      if (obj != NULL)
-        g_object_unref (obj);
-
-      (* (gpointer *) field_p) = obj = value;
-
-      if (obj != NULL)
+      if (property->flags & G_PROPERTY_COPY_SET)
         {
-          if (G_IS_INITIALLY_UNOWNED (obj))
-            g_object_ref_sink (obj);
-          else
-            g_object_ref (obj);
+          obj = (* (gpointer *) field_p);
+          if (obj != NULL)
+            g_object_unref (obj);
+
+          (* (gpointer *) field_p) = obj = value;
+
+          if (obj != NULL)
+            {
+              if (G_IS_INITIALLY_UNOWNED (obj))
+                g_object_ref_sink (obj);
+              else
+                g_object_ref (obj);
+            }
         }
+      else
+        (* (gpointer *) field_p) = value;
 
       property_unlock_internal (property, gobject);
 
@@ -2887,7 +2916,17 @@ g_object_property_get_value (GProperty *property,
       priv_p = g_type_instance_get_private (gobject, G_OBJECT_TYPE (gobject));
       field_p = G_STRUCT_MEMBER_P (priv_p, property->field_offset);
 
-      return (* (gpointer *) field_p);
+      if (property->flags & G_PROPERTY_COPY_GET)
+        {
+          gpointer value = (* (gpointer *) field_p);
+
+          if (value != NULL)
+            return g_object_ref (value);
+          else
+            return NULL;
+        }
+      else
+        return (* (gpointer *) field_p);
     }
   else
     {
@@ -4558,8 +4597,11 @@ g_property_get_valist (GProperty             *property,
 
         value = g_string_property_get_value (property, gobject);
 
-        if ((flags & G_PROPERTY_COLLECT_COPY) != 0)
-          (* (gchar **) ret_p) = g_strdup (value);
+        if (((flags & G_PROPERTY_COLLECT_COPY) != 0) &&
+            (property->flags & G_PROPERTY_COPY_GET) == 0)
+          {
+            (* (gchar **) ret_p) = g_strdup (value);
+          }
         else
           (* (gconstpointer *) ret_p) = value;
       }
@@ -4571,7 +4613,8 @@ g_property_get_valist (GProperty             *property,
 
         boxed = g_boxed_property_get_value (property, gobject);
 
-        if ((flags & G_PROPERTY_COLLECT_COPY) != 0)
+        if (((flags & G_PROPERTY_COLLECT_COPY) != 0) &&
+            (property->flags & G_PROPERTY_COPY_GET) == 0)
           {
             if (boxed != NULL)
               (* (gpointer *) ret_p) = g_boxed_copy (gtype, boxed);
@@ -4587,8 +4630,12 @@ g_property_get_valist (GProperty             *property,
       {
         gpointer obj = g_object_property_get_value (property, gobject);
 
-        if (((flags & G_PROPERTY_COLLECT_REF) != 0) && obj != NULL)
-          (* (gpointer *) ret_p) = g_object_ref (obj);
+        if ((((flags & G_PROPERTY_COLLECT_REF) != 0) &&
+            (property->flags & G_PROPERTY_COPY_GET) == 0) &&
+            (obj != NULL))
+          {
+            (* (gpointer *) ret_p) = g_object_ref (obj);
+          }
         else
           (* (gpointer *) ret_p) = obj;
       }
@@ -5349,6 +5396,42 @@ g_property_is_atomic (GProperty *property)
 }
 
 /**
+ * g_property_is_copy_set:
+ * @property: a #GProperty
+ *
+ * Checks whether the @property has the %G_PROPERTY_COPY_SET flag set.
+ *
+ * Return value: %TRUE if the flag is set, and %FALSE otherwise
+ *
+ * Since: 2.30
+ */
+gboolean
+g_property_is_copy_set (GProperty *property)
+{
+  g_return_val_if_fail (G_IS_PROPERTY (property), FALSE);
+
+  return (property->flags & G_PROPERTY_COPY_SET) !=  0;
+}
+
+/**
+ * g_property_is_copy_get:
+ * @property: a #GProperty
+ *
+ * Checks whether the @property has the %G_PROPERTY_COPY_GET flag set.
+ *
+ * Return value: %TRUE if the flag is set, and %FALSE otherwise
+ *
+ * Since: 2.30
+ */
+gboolean
+g_property_is_copy_get (GProperty *property)
+{
+  g_return_val_if_fail (G_IS_PROPERTY (property), FALSE);
+
+  return (property->flags & G_PROPERTY_COPY_GET) !=  0;
+}
+
+/**
  * g_property_lock:
  * @property: a #GProperty
  * @gobject: a #GObject
diff --git a/gobject/gproperty.h b/gobject/gproperty.h
index c156563..72c2c14 100644
--- a/gobject/gproperty.h
+++ b/gobject/gproperty.h
@@ -57,6 +57,13 @@ typedef struct _GProperty       GProperty;
  * @G_PROPERTY_ATOMIC: Whether the autogenerated setter function should
  *   be thread-safe, and acquire a lock when changing the value of the
  *   property.
+ * @G_PROPERTY_COPY_SET: Whether the property will make a copy or
+ *   take a reference when being set to a new value
+ * @G_PROPERTY_COPY_GET: Whether the property will make a copy or
+ *   take a reference when the value is being retrieved
+ * @G_PROPERTY_COPY: Whether the property will make a copy, or take a
+ *   reference, of the new value being set, and return a copy, or
+ *   increase the reference count, of the value being retrieved
  *
  * Flags for properties declared using #GProperty and relative macros.
  *
@@ -70,7 +77,10 @@ typedef enum {
   G_PROPERTY_READWRITE      = (G_PROPERTY_READABLE | G_PROPERTY_WRITABLE),
 
   G_PROPERTY_DEPRECATED     = 1 << 2,
-  G_PROPERTY_ATOMIC         = 1 << 3
+  G_PROPERTY_ATOMIC         = 1 << 3,
+  G_PROPERTY_COPY_SET       = 1 << 4,
+  G_PROPERTY_COPY_GET       = 1 << 5,
+  G_PROPERTY_COPY           = (G_PROPERTY_COPY_SET | G_PROPERTY_COPY_GET)
 } GPropertyFlags;
 
 GType           g_property_get_type             (void) G_GNUC_CONST;
@@ -84,6 +94,8 @@ gboolean        g_property_is_writable                  (GProperty    *property)
 gboolean        g_property_is_readable                  (GProperty    *property);
 gboolean        g_property_is_deprecated                (GProperty    *property);
 gboolean        g_property_is_atomic                    (GProperty    *property);
+gboolean        g_property_is_copy_set                  (GProperty    *property);
+gboolean        g_property_is_copy_get                  (GProperty    *property);
 
 void            g_property_describe                     (GProperty    *property,
                                                          const char   *nick,
diff --git a/gobject/tests/autoproperties.c b/gobject/tests/autoproperties.c
index 69522e8..8fdd948 100644
--- a/gobject/tests/autoproperties.c
+++ b/gobject/tests/autoproperties.c
@@ -333,7 +333,7 @@ test_object_class_init (TestObjectClass *klass)
                           TEST_FLAGS_VALUE_FOO);
 
   test_object_properties[PROP_BOXED] =
-    g_boxed_property_new ("boxed", G_PROPERTY_READWRITE,
+    g_boxed_property_new ("boxed", G_PROPERTY_READWRITE | G_PROPERTY_COPY_SET,
                           G_STRUCT_OFFSET (TestObjectPrivate, boxed),
                           NULL, NULL);
   g_property_set_prerequisite (G_PROPERTY (test_object_properties[PROP_BOXED]),
diff --git a/gobject/tests/gproperty-example-base.c b/gobject/tests/gproperty-example-base.c
index d8b67f6..3cb9d4b 100644
--- a/gobject/tests/gproperty-example-base.c
+++ b/gobject/tests/gproperty-example-base.c
@@ -90,7 +90,8 @@ test_file_class_init (TestFileClass *klass)
   g_type_class_add_private (klass, sizeof (TestFilePrivate));
 
   test_file_properties[PROP_PATH] =
-    g_string_property_new ("path", G_PROPERTY_READWRITE,
+    g_string_property_new ("path",
+                           G_PROPERTY_READWRITE | G_PROPERTY_COPY_SET,
                            G_STRUCT_OFFSET (TestFilePrivate, path),
                            (GPropertyStringSet) test_file_set_path,
                            NULL);
diff --git a/gobject/tests/gproperty-example-derived.c b/gobject/tests/gproperty-example-derived.c
index bdde06e..813c909 100644
--- a/gobject/tests/gproperty-example-derived.c
+++ b/gobject/tests/gproperty-example-derived.c
@@ -207,7 +207,8 @@ test_file_mp3_class_init (TestFileMp3Class *klass)
   g_type_class_add_private (klass, sizeof (TestFileMp3Private));
 
   test_file_mp3_properties[PROP_ALBUM] =
-    g_string_property_new ("album", G_PROPERTY_READWRITE,
+    g_string_property_new ("album",
+                           G_PROPERTY_READWRITE | G_PROPERTY_COPY_SET,
                            G_STRUCT_OFFSET (TestFileMp3Private, album),
                            NULL, NULL);
   g_property_set_default (G_PROPERTY (test_file_mp3_properties[PROP_ALBUM]),
@@ -215,7 +216,8 @@ test_file_mp3_class_init (TestFileMp3Class *klass)
                           "Unknown Album");
 
   test_file_mp3_properties[PROP_ARTIST] =
-    g_string_property_new ("artist", G_PROPERTY_READWRITE,
+    g_string_property_new ("artist",
+                           G_PROPERTY_READWRITE | G_PROPERTY_COPY_SET,
                            G_STRUCT_OFFSET (TestFileMp3Private, artist),
                            NULL, NULL);
   g_property_set_default (G_PROPERTY (test_file_mp3_properties[PROP_ARTIST]),
@@ -223,7 +225,8 @@ test_file_mp3_class_init (TestFileMp3Class *klass)
                           "Unknown Author");
 
   test_file_mp3_properties[PROP_TITLE] =
-    g_string_property_new ("title", G_PROPERTY_READWRITE,
+    g_string_property_new ("title",
+                           G_PROPERTY_READWRITE | G_PROPERTY_COPY_SET,
                            G_STRUCT_OFFSET (TestFileMp3Private, title),
                            NULL, NULL);
   g_property_set_default (G_PROPERTY (test_file_mp3_properties[PROP_TITLE]),



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