diff options
author | Emmanuele Bassi <ebassi@linux.intel.com> | 2011-08-18 11:27:24 +0100 |
---|---|---|
committer | Emmanuele Bassi <ebassi@linux.intel.com> | 2011-08-19 15:31:14 +0100 |
commit | 42e79ad6fb4e23be31714559f34e2d679691a0f7 (patch) | |
tree | 91b309f65a825520365c7a5f8fd220564466f856 | |
parent | 5b542fb90afef84bb8e2d1b0507f87417070e080 (diff) | |
download | glib-g-property.tar.gz |
gproperty: Allow control over the accessors copy semanticsg-property
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.
-rw-r--r-- | docs/reference/gobject/gobject-sections.txt | 2 | ||||
-rw-r--r-- | gobject/gobject.symbols | 2 | ||||
-rw-r--r-- | gobject/gproperty.c | 153 | ||||
-rw-r--r-- | gobject/gproperty.h | 14 | ||||
-rw-r--r-- | gobject/tests/autoproperties.c | 2 | ||||
-rw-r--r-- | gobject/tests/gproperty-example-base.c | 3 | ||||
-rw-r--r-- | 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 2e3a93699..e71552501 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 17229244e..fde734a8a 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 b94b62b3e..89ff1d5f7 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, /* explicit setter */ * NULL /* implicit getter */); @@ -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 c1565633c..72c2c14a9 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 69522e8ee..8fdd948ef 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 d8b67f60b..3cb9d4b23 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 bdde06eaf..813c9093e 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]), |