X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gobject%2Fgbinding.c;h=0e17b898b868bb2a38c9852d2cd39fd233e47367;hb=49cc207e35ef6b6ce7f4954a4c067ab43145f6bf;hp=99a7207865c3dd6be941f3e621df498c6028923f;hpb=36741245cca56e979fe85e3de676fb3912058f2c;p=platform%2Fupstream%2Fglib.git diff --git a/gobject/gbinding.c b/gobject/gbinding.c index 99a7207..0e17b89 100644 --- a/gobject/gbinding.c +++ b/gobject/gbinding.c @@ -13,9 +13,7 @@ * 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. + * Public License along with this library; if not, see . * * Author: Emmanuele Bassi */ @@ -31,21 +29,21 @@ * value is applied to the target property; for instance, the following * binding: * - * |[ + * |[ * g_object_bind_property (object1, "property-a", * object2, "property-b", * G_BINDING_DEFAULT); * ]| * - * will cause object2:property-b to be updated every - * time g_object_set() or the specific accessor changes the value of - * object1:property-a. + * will cause the property named "property-b" of @object2 to be updated + * every time g_object_set() or the specific accessor changes the value of + * the property "property-a" of @object1. * * It is possible to create a bidirectional binding between two properties * of two #GObject instances, so that if either property changes, the * other is updated as well, for instance: * - * |[ + * |[ * g_object_bind_property (object1, "property-a", * object2, "property-b", * G_BINDING_BIDIRECTIONAL); @@ -58,7 +56,7 @@ * transformation from the source value to the target value before * applying it; for instance, the following binding: * - * |[ + * |[ * g_object_bind_property_full (adjustment1, "value", * adjustment2, "value", * G_BINDING_BIDIRECTIONAL, @@ -67,15 +65,15 @@ * NULL, NULL); * ]| * - * will keep the value property of the two adjustments - * in sync; the celsius_to_fahrenheit function will be - * called whenever the adjustment1:value property changes - * and will transform the current value of the property before applying it - * to the adjustment2:value property; vice versa, the - * fahrenheit_to_celsius function will be called whenever - * the adjustment2:value property changes, and will - * transform the current value of the property before applying it to the - * adjustment1:value. + * will keep the "value" property of the two adjustments in sync; the + * @celsius_to_fahrenheit function will be called whenever the "value" + * property of @adjustment1 changes and will transform the current value + * of the property before applying it to the "value" property of @adjustment2. + * + * Vice versa, the @fahrenheit_to_celsius function will be called whenever + * the "value" property of @adjustment2 changes, and will transform the + * current value of the property before applying it to the "value" property + * of @adjustment1. * * Note that #GBinding does not resolve cycles by itself; a cycle like * @@ -96,6 +94,11 @@ * either one of the #GObject instances it refers to are finalized, or when * the #GBinding instance loses its last reference. * + * Bindings for languages with garbage collection can use + * g_binding_unbind() to explicitly release a binding between the source + * and target properties, instead of relying on the last reference on the + * binding, source, and target instances to drop. + * * #GBinding is available since GObject 2.26 */ @@ -151,8 +154,8 @@ struct _GBinding GObject *target; /* the property names are interned, so they should not be freed */ - gchar *source_property; - gchar *target_property; + const gchar *source_property; + const gchar *target_property; GParamSpec *source_pspec; GParamSpec *target_pspec; @@ -205,10 +208,10 @@ add_binding_qdata (GObject *gobject, g_object_set_qdata_full (gobject, quark_gbinding, bindings, - (GDestroyNotify) g_hash_table_destroy); + (GDestroyNotify) g_hash_table_unref); } - g_hash_table_insert (bindings, binding, GUINT_TO_POINTER (1)); + g_hash_table_add (bindings, binding); } static inline void @@ -218,7 +221,8 @@ remove_binding_qdata (GObject *gobject, GHashTable *bindings; bindings = g_object_get_qdata (gobject, quark_gbinding); - g_hash_table_remove (bindings, binding); + if (binding != NULL) + g_hash_table_remove (bindings, binding); } /* the basic assumption is that if either the source or the target @@ -244,6 +248,8 @@ weak_unbind (gpointer user_data, g_object_weak_unref (binding->source, weak_unbind, user_data); remove_binding_qdata (binding->source, binding); + + binding->source_notify = 0; binding->source = NULL; } @@ -257,6 +263,8 @@ weak_unbind (gpointer user_data, g_object_weak_unref (binding->target, weak_unbind, user_data); remove_binding_qdata (binding->target, binding); + + binding->target_notify = 0; binding->target = NULL; } @@ -350,8 +358,8 @@ on_source_notify (GObject *gobject, GBinding *binding) { const gchar *p_name; - GValue source_value = { 0, }; - GValue target_value = { 0, }; + GValue from_value = G_VALUE_INIT; + GValue to_value = G_VALUE_INIT; gboolean res; if (binding->is_frozen) @@ -362,27 +370,27 @@ on_source_notify (GObject *gobject, if (p_name != binding->source_property) return; - g_value_init (&source_value, G_PARAM_SPEC_VALUE_TYPE (binding->source_pspec)); - g_value_init (&target_value, G_PARAM_SPEC_VALUE_TYPE (binding->target_pspec)); + g_value_init (&from_value, G_PARAM_SPEC_VALUE_TYPE (binding->source_pspec)); + g_value_init (&to_value, G_PARAM_SPEC_VALUE_TYPE (binding->target_pspec)); - g_object_get_property (binding->source, binding->source_pspec->name, &source_value); + g_object_get_property (binding->source, binding->source_pspec->name, &from_value); res = binding->transform_s2t (binding, - &source_value, - &target_value, + &from_value, + &to_value, binding->transform_data); if (res) { binding->is_frozen = TRUE; - g_param_value_validate (binding->target_pspec, &target_value); - g_object_set_property (binding->target, binding->target_pspec->name, &target_value); + g_param_value_validate (binding->target_pspec, &to_value); + g_object_set_property (binding->target, binding->target_pspec->name, &to_value); binding->is_frozen = FALSE; } - g_value_unset (&source_value); - g_value_unset (&target_value); + g_value_unset (&from_value); + g_value_unset (&to_value); } static void @@ -391,8 +399,8 @@ on_target_notify (GObject *gobject, GBinding *binding) { const gchar *p_name; - GValue source_value = { 0, }; - GValue target_value = { 0, }; + GValue from_value = G_VALUE_INIT; + GValue to_value = G_VALUE_INIT; gboolean res; if (binding->is_frozen) @@ -403,34 +411,33 @@ on_target_notify (GObject *gobject, if (p_name != binding->target_property) return; - g_value_init (&source_value, G_PARAM_SPEC_VALUE_TYPE (binding->target_pspec)); - g_value_init (&target_value, G_PARAM_SPEC_VALUE_TYPE (binding->source_pspec)); + g_value_init (&from_value, G_PARAM_SPEC_VALUE_TYPE (binding->target_pspec)); + g_value_init (&to_value, G_PARAM_SPEC_VALUE_TYPE (binding->source_pspec)); - g_object_get_property (binding->target, binding->target_pspec->name, &source_value); + g_object_get_property (binding->target, binding->target_pspec->name, &from_value); res = binding->transform_t2s (binding, - &source_value, - &target_value, + &from_value, + &to_value, binding->transform_data); if (res) { binding->is_frozen = TRUE; - g_param_value_validate (binding->source_pspec, &target_value); - g_object_set_property (binding->source, binding->source_pspec->name, &target_value); + g_param_value_validate (binding->source_pspec, &to_value); + g_object_set_property (binding->source, binding->source_pspec->name, &to_value); binding->is_frozen = FALSE; } - g_value_unset (&source_value); - g_value_unset (&target_value); + g_value_unset (&from_value); + g_value_unset (&to_value); } -static void -g_binding_finalize (GObject *gobject) +static inline void +g_binding_unbind_internal (GBinding *binding, + gboolean unref_binding) { - GBinding *binding = G_BINDING (gobject); - /* dispose of the transformation data */ if (binding->notify != NULL) { @@ -440,9 +447,6 @@ g_binding_finalize (GObject *gobject) binding->notify = NULL; } - /* we need this in case the source and target instance are still - * valid, and it was the GBinding that was unreferenced - */ if (binding->source != NULL) { if (binding->source_notify != 0) @@ -450,6 +454,9 @@ g_binding_finalize (GObject *gobject) g_object_weak_unref (binding->source, weak_unbind, binding); remove_binding_qdata (binding->source, binding); + + binding->source_notify = 0; + binding->source = NULL; } if (binding->target != NULL) @@ -459,8 +466,22 @@ g_binding_finalize (GObject *gobject) g_object_weak_unref (binding->target, weak_unbind, binding); remove_binding_qdata (binding->target, binding); + + binding->target_notify = 0; + binding->target = NULL; } + if (unref_binding) + g_object_unref (binding); +} + +static void +g_binding_finalize (GObject *gobject) +{ + GBinding *binding = G_BINDING (gobject); + + g_binding_unbind_internal (binding, FALSE); + G_OBJECT_CLASS (g_binding_parent_class)->finalize (gobject); } @@ -575,9 +596,11 @@ g_binding_constructed (GObject *gobject) G_CALLBACK (on_target_notify), binding); - g_object_weak_ref (binding->target, weak_unbind, binding); - add_binding_qdata (binding->target, binding); - + if (binding->target != binding->source) + { + g_object_weak_ref (binding->target, weak_unbind, binding); + add_binding_qdata (binding->target, binding); + } } static void @@ -681,9 +704,9 @@ g_binding_init (GBinding *binding) * g_binding_get_flags: * @binding: a #GBinding * - * Retrieves the flags passed when constructing the #GBinding + * Retrieves the flags passed when constructing the #GBinding. * - * Return value: the #GBindingFlags used by the #GBinding + * Returns: the #GBindingFlags used by the #GBinding * * Since: 2.26 */ @@ -699,9 +722,9 @@ g_binding_get_flags (GBinding *binding) * g_binding_get_source: * @binding: a #GBinding * - * Retrieves the #GObject instance used as the source of the binding + * Retrieves the #GObject instance used as the source of the binding. * - * Return value: (transfer none): the source #GObject + * Returns: (transfer none): the source #GObject * * Since: 2.26 */ @@ -717,9 +740,9 @@ g_binding_get_source (GBinding *binding) * g_binding_get_target: * @binding: a #GBinding * - * Retrieves the #GObject instance used as the target of the binding + * Retrieves the #GObject instance used as the target of the binding. * - * Return value: (transfer none): the target #GObject + * Returns: (transfer none): the target #GObject * * Since: 2.26 */ @@ -736,9 +759,9 @@ g_binding_get_target (GBinding *binding) * @binding: a #GBinding * * Retrieves the name of the property of #GBinding:source used as the source - * of the binding + * of the binding. * - * Return value: the name of the source property + * Returns: the name of the source property * * Since: 2.26 */ @@ -755,9 +778,9 @@ g_binding_get_source_property (GBinding *binding) * @binding: a #GBinding * * Retrieves the name of the property of #GBinding:target used as the target - * of the binding + * of the binding. * - * Return value: the name of the target property + * Returns: the name of the target property * * Since: 2.26 */ @@ -770,20 +793,42 @@ g_binding_get_target_property (GBinding *binding) } /** + * g_binding_unbind: + * @binding: a #GBinding + * + * Explicitly releases the binding between the source and the target + * property expressed by @binding. + * + * This function will release the reference that is being held on + * the @binding instance; if you want to hold on to the #GBinding instance + * after calling g_binding_unbind(), you will need to hold a reference + * to it. + * + * Since: 2.38 + */ +void +g_binding_unbind (GBinding *binding) +{ + g_return_if_fail (G_IS_BINDING (binding)); + + g_binding_unbind_internal (binding, TRUE); +} + +/** * g_object_bind_property_full: - * @source: the source #GObject + * @source: (type GObject.Object): the source #GObject * @source_property: the property on @source to bind - * @target: the target #GObject + * @target: (type GObject.Object): the target #GObject * @target_property: the property on @target to bind * @flags: flags to pass to #GBinding * @transform_to: (scope notified) (allow-none): the transformation function - * from the @source to the @target, or %NULL to use the default + * from the @source to the @target, or %NULL to use the default * @transform_from: (scope notified) (allow-none): the transformation function - * from the @target to the @source, or %NULL to use the default + * from the @target to the @source, or %NULL to use the default * @user_data: custom data to be passed to the transformation functions, - * or %NULL + * or %NULL * @notify: function to be called when disposing the binding, to free the - * resources used by the transformation functions + * resources used by the transformation functions * * Complete version of g_object_bind_property(). * @@ -803,15 +848,15 @@ g_binding_get_target_property (GBinding *binding) * * A #GObject can have multiple bindings. * - * The same @user_data parameter will be used for both @transform_to + * The same @user_data parameter will be used for both @transform_to * and @transform_from transformation functions; the @notify function will * be called once, when the binding is removed. If you need different data * for each transformation function, please use - * g_object_bind_property_with_closures() instead. + * g_object_bind_property_with_closures() instead. * - * Return value: (transfer none): the #GBinding instance representing the - * binding between the two #GObject instances. The binding is released - * whenever the #GBinding reference count reaches zero. + * Returns: (transfer none): the #GBinding instance representing the + * binding between the two #GObject instances. The binding is released + * whenever the #GBinding reference count reaches zero. * * Since: 2.26 */ @@ -912,7 +957,7 @@ g_object_bind_property_full (gpointer source, if ((flags & G_BINDING_BIDIRECTIONAL) && !(pspec->flags & G_PARAM_READABLE)) { - g_warning ("%s: The starget object of type %s has no writable property called '%s'", + g_warning ("%s: The target object of type %s has no readable property called '%s'", G_STRLOC, G_OBJECT_TYPE_NAME (target), target_property); @@ -961,9 +1006,9 @@ g_object_bind_property_full (gpointer source, /** * g_object_bind_property: - * @source: the source #GObject + * @source: (type GObject.Object): the source #GObject * @source_property: the property on @source to bind - * @target: the target #GObject + * @target: (type GObject.Object): the target #GObject * @target_property: the property on @target to bind * @flags: flags to pass to #GBinding * @@ -990,9 +1035,9 @@ g_object_bind_property_full (gpointer source, * * A #GObject can have multiple bindings. * - * Return value: (transfer none): the #GBinding instance representing the - * binding between the two #GObject instances. The binding is released - * whenever the #GBinding reference count reaches zero. + * Returns: (transfer none): the #GBinding instance representing the + * binding between the two #GObject instances. The binding is released + * whenever the #GBinding reference count reaches zero. * * Since: 2.26 */ @@ -1026,8 +1071,8 @@ bind_with_closures_transform_to (GBinding *binding, gpointer data) { TransformData *t_data = data; - GValue params[3] = { { 0, }, { 0, }, { 0, } }; - GValue retval = { 0, }; + GValue params[3] = { G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT }; + GValue retval = G_VALUE_INIT; gboolean res; g_value_init (¶ms[0], G_TYPE_BINDING); @@ -1069,8 +1114,8 @@ bind_with_closures_transform_from (GBinding *binding, gpointer data) { TransformData *t_data = data; - GValue params[3] = { { 0, }, { 0, }, { 0, } }; - GValue retval = { 0, }; + GValue params[3] = { G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT }; + GValue retval = G_VALUE_INIT; gboolean res; g_value_init (¶ms[0], G_TYPE_BINDING); @@ -1121,29 +1166,29 @@ bind_with_closures_free_func (gpointer data) /** * g_object_bind_property_with_closures: - * @source: the source #GObject + * @source: (type GObject.Object): the source #GObject * @source_property: the property on @source to bind - * @target: the target #GObject + * @target: (type GObject.Object): the target #GObject * @target_property: the property on @target to bind * @flags: flags to pass to #GBinding * @transform_to: a #GClosure wrapping the transformation function - * from the @source to the @target, or %NULL to use the default + * from the @source to the @target, or %NULL to use the default * @transform_from: a #GClosure wrapping the transformation function - * from the @target to the @source, or %NULL to use the default + * from the @target to the @source, or %NULL to use the default * * Creates a binding between @source_property on @source and @target_property * on @target, allowing you to set the transformation functions to be used by * the binding. * * This function is the language bindings friendly version of - * g_object_bind_property_full(), using #GClosures instead of + * g_object_bind_property_full(), using #GClosures instead of * function pointers. * * Rename to: g_object_bind_property_full * - * Return value: (transfer none): the #GBinding instance representing the - * binding between the two #GObject instances. The binding is released - * whenever the #GBinding reference count reaches zero. + * Returns: (transfer none): the #GBinding instance representing the + * binding between the two #GObject instances. The binding is released + * whenever the #GBinding reference count reaches zero. * * Since: 2.26 */