mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-04-26 17:16:53 +02:00
binding: Add an explicit unbind()
Higher order languages with garbage collection can have issues releasing a binding, as they do not control the last reference being dropped on the binding, source, or target instances. https://bugzilla.gnome.org/show_bug.cgi?id=698018
This commit is contained in:
parent
f61daa6ed2
commit
a360b314aa
@ -935,6 +935,7 @@ g_binding_get_source_property
|
|||||||
g_binding_get_target
|
g_binding_get_target
|
||||||
g_binding_get_target_property
|
g_binding_get_target_property
|
||||||
g_binding_get_flags
|
g_binding_get_flags
|
||||||
|
g_binding_release
|
||||||
<SUBSECTION>
|
<SUBSECTION>
|
||||||
g_object_bind_property
|
g_object_bind_property
|
||||||
GBindingTransformFunc
|
GBindingTransformFunc
|
||||||
|
@ -96,6 +96,11 @@
|
|||||||
* either one of the #GObject instances it refers to are finalized, or when
|
* either one of the #GObject instances it refers to are finalized, or when
|
||||||
* the #GBinding instance loses its last reference.
|
* the #GBinding instance loses its last reference.
|
||||||
*
|
*
|
||||||
|
* <note><para>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.</para></note>
|
||||||
|
*
|
||||||
* #GBinding is available since GObject 2.26
|
* #GBinding is available since GObject 2.26
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -244,6 +249,8 @@ weak_unbind (gpointer user_data,
|
|||||||
|
|
||||||
g_object_weak_unref (binding->source, weak_unbind, user_data);
|
g_object_weak_unref (binding->source, weak_unbind, user_data);
|
||||||
remove_binding_qdata (binding->source, binding);
|
remove_binding_qdata (binding->source, binding);
|
||||||
|
|
||||||
|
binding->source_notify = 0;
|
||||||
binding->source = NULL;
|
binding->source = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -257,6 +264,8 @@ weak_unbind (gpointer user_data,
|
|||||||
|
|
||||||
g_object_weak_unref (binding->target, weak_unbind, user_data);
|
g_object_weak_unref (binding->target, weak_unbind, user_data);
|
||||||
remove_binding_qdata (binding->target, binding);
|
remove_binding_qdata (binding->target, binding);
|
||||||
|
|
||||||
|
binding->target_notify = 0;
|
||||||
binding->target = NULL;
|
binding->target = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -431,35 +440,7 @@ g_binding_finalize (GObject *gobject)
|
|||||||
{
|
{
|
||||||
GBinding *binding = G_BINDING (gobject);
|
GBinding *binding = G_BINDING (gobject);
|
||||||
|
|
||||||
/* dispose of the transformation data */
|
g_binding_unbind (binding);
|
||||||
if (binding->notify != NULL)
|
|
||||||
{
|
|
||||||
binding->notify (binding->transform_data);
|
|
||||||
|
|
||||||
binding->transform_data = NULL;
|
|
||||||
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)
|
|
||||||
g_signal_handler_disconnect (binding->source, binding->source_notify);
|
|
||||||
|
|
||||||
g_object_weak_unref (binding->source, weak_unbind, binding);
|
|
||||||
remove_binding_qdata (binding->source, binding);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (binding->target != NULL)
|
|
||||||
{
|
|
||||||
if (binding->target_notify != 0)
|
|
||||||
g_signal_handler_disconnect (binding->target, binding->target_notify);
|
|
||||||
|
|
||||||
g_object_weak_unref (binding->target, weak_unbind, binding);
|
|
||||||
remove_binding_qdata (binding->target, binding);
|
|
||||||
}
|
|
||||||
|
|
||||||
G_OBJECT_CLASS (g_binding_parent_class)->finalize (gobject);
|
G_OBJECT_CLASS (g_binding_parent_class)->finalize (gobject);
|
||||||
}
|
}
|
||||||
@ -771,6 +752,56 @@ g_binding_get_target_property (GBinding *binding)
|
|||||||
return binding->target_property;
|
return binding->target_property;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* g_binding_unbind:
|
||||||
|
* @binding: a #GBinding
|
||||||
|
*
|
||||||
|
* Explicitly releases the binding between the source and the target
|
||||||
|
* property expressed by @binding.
|
||||||
|
*
|
||||||
|
* This function does not change the reference count of @binding.
|
||||||
|
*
|
||||||
|
* Since: 2.38
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
g_binding_unbind (GBinding *binding)
|
||||||
|
{
|
||||||
|
g_return_if_fail (G_IS_BINDING (binding));
|
||||||
|
|
||||||
|
/* dispose of the transformation data */
|
||||||
|
if (binding->notify != NULL)
|
||||||
|
{
|
||||||
|
binding->notify (binding->transform_data);
|
||||||
|
|
||||||
|
binding->transform_data = NULL;
|
||||||
|
binding->notify = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (binding->source != NULL)
|
||||||
|
{
|
||||||
|
if (binding->source_notify != 0)
|
||||||
|
g_signal_handler_disconnect (binding->source, binding->source_notify);
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
if (binding->target_notify != 0)
|
||||||
|
g_signal_handler_disconnect (binding->target, binding->target_notify);
|
||||||
|
|
||||||
|
g_object_weak_unref (binding->target, weak_unbind, binding);
|
||||||
|
remove_binding_qdata (binding->target, binding);
|
||||||
|
|
||||||
|
binding->target_notify = 0;
|
||||||
|
binding->target = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* g_object_bind_property_full:
|
* g_object_bind_property_full:
|
||||||
* @source: (type GObject.Object): the source #GObject
|
* @source: (type GObject.Object): the source #GObject
|
||||||
|
@ -115,6 +115,8 @@ GLIB_AVAILABLE_IN_ALL
|
|||||||
const gchar * g_binding_get_source_property (GBinding *binding);
|
const gchar * g_binding_get_source_property (GBinding *binding);
|
||||||
GLIB_AVAILABLE_IN_ALL
|
GLIB_AVAILABLE_IN_ALL
|
||||||
const gchar * g_binding_get_target_property (GBinding *binding);
|
const gchar * g_binding_get_target_property (GBinding *binding);
|
||||||
|
GLIB_AVAILABLE_IN_2_38
|
||||||
|
void g_binding_unbind (GBinding *binding);
|
||||||
|
|
||||||
GLIB_AVAILABLE_IN_ALL
|
GLIB_AVAILABLE_IN_ALL
|
||||||
GBinding *g_object_bind_property (gpointer source,
|
GBinding *g_object_bind_property (gpointer source,
|
||||||
|
@ -570,6 +570,37 @@ binding_same_object (void)
|
|||||||
g_object_unref (source);
|
g_object_unref (source);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
binding_unbind (void)
|
||||||
|
{
|
||||||
|
BindingSource *source = g_object_new (binding_source_get_type (), NULL);
|
||||||
|
BindingTarget *target = g_object_new (binding_target_get_type (), NULL);
|
||||||
|
GBinding *binding;
|
||||||
|
|
||||||
|
binding = g_object_bind_property (source, "foo",
|
||||||
|
target, "bar",
|
||||||
|
G_BINDING_DEFAULT);
|
||||||
|
g_object_add_weak_pointer (G_OBJECT (binding), (gpointer *) &binding);
|
||||||
|
|
||||||
|
|
||||||
|
g_object_set (source, "foo", 42, NULL);
|
||||||
|
g_assert_cmpint (source->foo, ==, target->bar);
|
||||||
|
|
||||||
|
g_object_set (target, "bar", 47, NULL);
|
||||||
|
g_assert_cmpint (source->foo, !=, target->bar);
|
||||||
|
|
||||||
|
g_binding_unbind (binding);
|
||||||
|
g_assert (binding != NULL);
|
||||||
|
|
||||||
|
g_object_set (source, "foo", 0, NULL);
|
||||||
|
g_assert_cmpint (source->foo, !=, target->bar);
|
||||||
|
|
||||||
|
g_object_unref (source);
|
||||||
|
g_object_unref (target);
|
||||||
|
g_object_unref (binding);
|
||||||
|
g_assert (binding == NULL);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main (int argc, char *argv[])
|
main (int argc, char *argv[])
|
||||||
{
|
{
|
||||||
@ -586,6 +617,7 @@ main (int argc, char *argv[])
|
|||||||
g_test_add_func ("/binding/sync-create", binding_sync_create);
|
g_test_add_func ("/binding/sync-create", binding_sync_create);
|
||||||
g_test_add_func ("/binding/invert-boolean", binding_invert_boolean);
|
g_test_add_func ("/binding/invert-boolean", binding_invert_boolean);
|
||||||
g_test_add_func ("/binding/same-object", binding_same_object);
|
g_test_add_func ("/binding/same-object", binding_same_object);
|
||||||
|
g_test_add_func ("/binding/unbind", binding_unbind);
|
||||||
|
|
||||||
return g_test_run ();
|
return g_test_run ();
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user