summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gobject/gbinding.c7
-rw-r--r--gobject/tests/binding.c77
2 files changed, 82 insertions, 2 deletions
diff --git a/gobject/gbinding.c b/gobject/gbinding.c
index 6872b9662..42dcb366f 100644
--- a/gobject/gbinding.c
+++ b/gobject/gbinding.c
@@ -373,6 +373,7 @@ g_binding_unbind_internal (GBinding *binding,
gboolean unref_binding)
{
gboolean source_is_target = binding->source == binding->target;
+ gboolean binding_was_removed = FALSE;
/* dispose of the transformation data */
if (binding->notify != NULL)
@@ -392,6 +393,7 @@ g_binding_unbind_internal (GBinding *binding,
binding->source_notify = 0;
binding->source = NULL;
+ binding_was_removed = TRUE;
}
if (binding->target != NULL)
@@ -404,9 +406,10 @@ g_binding_unbind_internal (GBinding *binding,
binding->target_notify = 0;
binding->target = NULL;
+ binding_was_removed = TRUE;
}
- if (unref_binding)
+ if (binding_was_removed && unref_binding)
g_object_unref (binding);
}
@@ -748,7 +751,7 @@ g_binding_get_target_property (GBinding *binding)
/**
* g_binding_unbind:
- * @binding: (transfer full): a #GBinding
+ * @binding: a #GBinding
*
* Explicitly releases the binding between the source and the target
* property expressed by @binding.
diff --git a/gobject/tests/binding.c b/gobject/tests/binding.c
index e088ca7a4..eeba37ed9 100644
--- a/gobject/tests/binding.c
+++ b/gobject/tests/binding.c
@@ -625,6 +625,81 @@ binding_unbind (void)
g_object_unref (source);
}
+/* When source or target die, so does the binding if there is no other ref */
+static void
+binding_unbind_weak (void)
+{
+ GBinding *binding;
+ BindingSource *source;
+ BindingTarget *target;
+
+ /* first source, then target */
+ source = g_object_new (binding_source_get_type (), NULL);
+ target = g_object_new (binding_target_get_type (), NULL);
+ binding = g_object_bind_property (source, "foo",
+ target, "bar",
+ G_BINDING_DEFAULT);
+ g_object_add_weak_pointer (G_OBJECT (binding), (gpointer *) &binding);
+ g_assert (binding != NULL);
+ g_object_unref (source);
+ g_assert (binding == NULL);
+ g_object_unref (target);
+ g_assert (binding == NULL);
+
+ /* first target, then source */
+ source = g_object_new (binding_source_get_type (), NULL);
+ target = g_object_new (binding_target_get_type (), NULL);
+ binding = g_object_bind_property (source, "foo",
+ target, "bar",
+ G_BINDING_DEFAULT);
+ g_object_add_weak_pointer (G_OBJECT (binding), (gpointer *) &binding);
+ g_assert (binding != NULL);
+ g_object_unref (target);
+ g_assert (binding == NULL);
+ g_object_unref (source);
+ g_assert (binding == NULL);
+
+ /* target and source are the same */
+ source = g_object_new (binding_source_get_type (), NULL);
+ binding = g_object_bind_property (source, "foo",
+ source, "bar",
+ G_BINDING_DEFAULT);
+ g_object_add_weak_pointer (G_OBJECT (binding), (gpointer *) &binding);
+ g_assert (binding != NULL);
+ g_object_unref (source);
+ g_assert (binding == NULL);
+}
+
+/* Test that every call to unbind() after the first is a noop */
+static void
+binding_unbind_multiple (void)
+{
+ BindingSource *source = g_object_new (binding_source_get_type (), NULL);
+ BindingTarget *target = g_object_new (binding_target_get_type (), NULL);
+ GBinding *binding;
+ int i;
+
+ binding = g_object_bind_property (source, "foo",
+ target, "bar",
+ G_BINDING_DEFAULT);
+ g_object_ref (binding);
+ g_object_add_weak_pointer (G_OBJECT (binding), (gpointer *) &binding);
+ g_assert (binding != NULL);
+
+ /* this shouldn't crash */
+ for (i = 0; i < 50; i++)
+ {
+ g_binding_unbind (binding);
+ g_assert (binding != NULL);
+ }
+
+ g_object_unref (binding);
+ g_assert (binding == NULL);
+
+ g_object_unref (source);
+ g_object_unref (target);
+}
+
static void
binding_fail (void)
{
@@ -665,6 +740,8 @@ main (int argc, char *argv[])
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);
+ g_test_add_func ("/binding/unbind-weak", binding_unbind_weak);
+ g_test_add_func ("/binding/unbind-multiple", binding_unbind_multiple);
g_test_add_func ("/binding/fail", binding_fail);
return g_test_run ();