mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-01-12 15:36:17 +01: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_property
|
||||
g_binding_get_flags
|
||||
g_binding_release
|
||||
<SUBSECTION>
|
||||
g_object_bind_property
|
||||
GBindingTransformFunc
|
||||
|
@ -96,6 +96,11 @@
|
||||
* either one of the #GObject instances it refers to are finalized, or when
|
||||
* 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
|
||||
*/
|
||||
|
||||
@ -244,6 +249,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 +264,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;
|
||||
}
|
||||
|
||||
@ -431,35 +440,7 @@ g_binding_finalize (GObject *gobject)
|
||||
{
|
||||
GBinding *binding = G_BINDING (gobject);
|
||||
|
||||
/* dispose of the transformation data */
|
||||
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_binding_unbind (binding);
|
||||
|
||||
G_OBJECT_CLASS (g_binding_parent_class)->finalize (gobject);
|
||||
}
|
||||
@ -771,6 +752,56 @@ g_binding_get_target_property (GBinding *binding)
|
||||
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:
|
||||
* @source: (type GObject.Object): the source #GObject
|
||||
|
@ -115,6 +115,8 @@ GLIB_AVAILABLE_IN_ALL
|
||||
const gchar * g_binding_get_source_property (GBinding *binding);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
const gchar * g_binding_get_target_property (GBinding *binding);
|
||||
GLIB_AVAILABLE_IN_2_38
|
||||
void g_binding_unbind (GBinding *binding);
|
||||
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
GBinding *g_object_bind_property (gpointer source,
|
||||
|
@ -570,6 +570,37 @@ binding_same_object (void)
|
||||
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
|
||||
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/invert-boolean", binding_invert_boolean);
|
||||
g_test_add_func ("/binding/same-object", binding_same_object);
|
||||
g_test_add_func ("/binding/unbind", binding_unbind);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user