Here's a patch implementing the proposed API (with the GDataset flags hack). A test case is included. As always, if the patch is approved, I'll move the docs to the tmpl files to match the rest of libgobject. Regards, Owen
? gobject/gobject.save
? tests/gobject/references
Index: glib/gdataset.c
===================================================================
RCS file: /cvs/gnome/glib/glib/gdataset.c,v
retrieving revision 1.22
diff -u -p -u -r1.22 gdataset.c
--- glib/gdataset.c 14 Mar 2005 05:30:08 -0000 1.22
+++ glib/gdataset.c 25 Apr 2005 22:57:13 -0000
@@ -91,6 +91,12 @@ static GHashTable *g_quark_ht = NULL;
static gchar **g_quarks = NULL;
static GQuark g_quark_seq_id = 0;
+#define G_DATALIST_GET_POINTER(datalist) \
+ ((GData *)((gulong)*(datalist) & ~(gulong)G_DATALIST_FLAGS_MASK))
+#define G_DATALIST_SET_POINTER(datalist,pointer) G_STMT_START { \
+ *(datalist) = (GData *)(G_DATALIST_GET_FLAGS (datalist) | \
+ (gulong)pointer); \
+} G_STMT_END
/* --- functions --- */
@@ -133,14 +139,20 @@ g_datalist_clear_i (GData **datalist)
void
g_datalist_clear (GData **datalist)
{
+ GData *tmp;
+
g_return_if_fail (datalist != NULL);
G_LOCK (g_dataset_global);
if (!g_dataset_location_ht)
g_data_initialize ();
- while (*datalist)
- g_datalist_clear_i (datalist);
+ tmp = G_DATALIST_GET_POINTER (datalist);
+ while (tmp)
+ g_datalist_clear_i (&tmp);
+
+ G_DATALIST_SET_POINTER (datalist, NULL);
+
G_UNLOCK (g_dataset_global);
}
@@ -363,6 +375,8 @@ g_datalist_id_set_data_full (GData **d
gpointer data,
GDestroyNotify destroy_func)
{
+ GData *tmp;
+
g_return_if_fail (datalist != NULL);
if (!data)
g_return_if_fail (destroy_func == NULL);
@@ -377,8 +391,10 @@ g_datalist_id_set_data_full (GData **d
G_LOCK (g_dataset_global);
if (!g_dataset_location_ht)
g_data_initialize ();
-
- g_data_set_internal (datalist, key_id, data, destroy_func, NULL);
+
+ tmp = G_DATALIST_GET_POINTER (datalist);
+ g_data_set_internal (&tmp, key_id, data, destroy_func, NULL);
+ G_DATALIST_SET_POINTER (datalist, tmp);
G_UNLOCK (g_dataset_global);
}
@@ -414,7 +430,12 @@ g_datalist_id_remove_no_notify (GData **
G_LOCK (g_dataset_global);
if (key_id && g_dataset_location_ht)
- ret_data = g_data_set_internal (datalist, key_id, NULL, (GDestroyNotify) 42, NULL);
+ {
+ GData *tmp = G_DATALIST_GET_POINTER (datalist);
+ ret_data = g_data_set_internal (&tmp, key_id, NULL, (GDestroyNotify) 42, NULL);
+ G_DATALIST_SET_POINTER (datalist, tmp);
+ }
+
G_UNLOCK (g_dataset_global);
return ret_data;
@@ -459,7 +480,7 @@ g_datalist_id_get_data (GData **datalis
{
register GData *list;
- for (list = *datalist; list; list = list->next)
+ for (list = G_DATALIST_GET_POINTER (datalist); list; list = list->next)
if (list->id == key_id)
return list->data;
}
@@ -509,7 +530,7 @@ g_datalist_foreach (GData **datalist,
g_return_if_fail (datalist != NULL);
g_return_if_fail (func != NULL);
- for (list = *datalist; list; list = next)
+ for (list = G_DATALIST_GET_POINTER (datalist); list; list = next)
{
next = list->next;
func (list->id, list->data, user_data);
@@ -520,7 +541,7 @@ void
g_datalist_init (GData **datalist)
{
g_return_if_fail (datalist != NULL);
-
+
*datalist = NULL;
}
Index: glib/gdataset.h
===================================================================
RCS file: /cvs/gnome/glib/glib/gdataset.h,v
retrieving revision 1.2
diff -u -p -u -r1.2 gdataset.h
--- glib/gdataset.h 26 Jun 2001 16:01:14 -0000 1.2
+++ glib/gdataset.h 25 Apr 2005 22:57:13 -0000
@@ -39,6 +39,15 @@ typedef void (*GDataForeachFu
/* Keyed Data List
*/
+#define G_DATALIST_FLAGS_MASK 0x3
+
+#define G_DATALIST_GET_FLAGS(datalist) \
+ ((gulong)*(datalist) & G_DATALIST_FLAGS_MASK)
+#define G_DATALIST_SET_FLAGS(datalist, flags) G_STMT_START { \
+ *datalist = (GData *)((flags) | \
+ ((gulong)*(datalist) & ~(gulong)G_DATALIST_FLAGS_MASK)); \
+} G_STMT_END
+
void g_datalist_init (GData **datalist);
void g_datalist_clear (GData **datalist);
gpointer g_datalist_id_get_data (GData **datalist,
Index: gobject/gobject.c
===================================================================
RCS file: /cvs/gnome/glib/gobject/gobject.c,v
retrieving revision 1.66
diff -u -p -u -r1.66 gobject.c
--- gobject/gobject.c 14 Mar 2005 06:47:51 -0000 1.66
+++ gobject/gobject.c 25 Apr 2005 22:57:13 -0000
@@ -39,6 +39,10 @@
#define PARAM_SPEC_PARAM_ID(pspec) ((pspec)->param_id)
#define PARAM_SPEC_SET_PARAM_ID(pspec, id) ((pspec)->param_id = (id))
+#define OBJECT_HAS_TOGGLE_REF_FLAG 0x1
+#define OBJECT_HAS_TOGGLE_REF(object) \
+ ((G_DATALIST_GET_FLAGS(&(object)->qdata) & OBJECT_HAS_TOGGLE_REF_FLAG) != 0)
+
/* --- signals --- */
enum {
@@ -105,6 +109,7 @@ static void object_interface_check_prope
/* --- variables --- */
static GQuark quark_closure_array = 0;
static GQuark quark_weak_refs = 0;
+static GQuark quark_toggle_refs = 0;
static GParamSpecPool *pspec_pool = NULL;
static GObjectNotifyContext property_notify_context = { 0, };
static gulong gobject_signals[LAST_SIGNAL] = { 0, };
@@ -241,6 +246,7 @@ g_object_do_class_init (GObjectClass *cl
quark_closure_array = g_quark_from_static_string ("GObject-closure-array");
quark_weak_refs = g_quark_from_static_string ("GObject-weak-references");
+ quark_toggle_refs = g_quark_from_static_string ("GObject-toggle-references");
pspec_pool = g_param_spec_pool_new (TRUE);
property_notify_context.quark_notify_queue = g_quark_from_static_string ("GObject-notify-queue");
property_notify_context.dispatcher = g_object_notify_dispatcher;
@@ -1482,7 +1488,7 @@ g_object_weak_ref (GObject *object,
if (wstack)
{
i = wstack->n_weak_refs++;
- wstack = g_realloc (wstack, sizeof (*wstack) + sizeof (wstack->weak_refs[0]) * i);
+ wstack = g_realloc (wstack, sizeof (*wstack) + sizeof (wstack->weak_refs[0]) * (i - 1));
}
else
{
@@ -1519,10 +1525,8 @@ g_object_weak_unref (GObject *object,
found_one = TRUE;
wstack->n_weak_refs -= 1;
if (i != wstack->n_weak_refs)
- {
- wstack->weak_refs[i].notify = wstack->weak_refs[wstack->n_weak_refs].notify;
- wstack->weak_refs[i].data = wstack->weak_refs[wstack->n_weak_refs].data;
- }
+ wstack->weak_refs[i] = wstack->weak_refs[wstack->n_weak_refs];
+
break;
}
}
@@ -1554,6 +1558,133 @@ g_object_remove_weak_pointer (GObject *
weak_pointer_location);
}
+typedef struct {
+ GObject *object;
+ guint n_toggle_refs;
+ struct {
+ GToggleNotify notify;
+ gpointer data;
+ } toggle_refs[1]; /* flexible array */
+} ToggleRefStack;
+
+static void
+toggle_refs_notify (GObject *object,
+ gboolean is_last_ref)
+{
+ ToggleRefStack *wstack = g_datalist_id_get_data (&object->qdata, quark_toggle_refs);
+
+ /* Reentrancy here is not as tricky as it seems, because a toggle reference
+ * will only be notified when there is exactly one of them.
+ */
+ g_assert (wstack->n_toggle_refs == 1);
+ wstack->toggle_refs[0].notify (wstack->toggle_refs[0].data, wstack->object, is_last_ref);
+}
+
+/**
+ * g_object_add_toggle_ref:
+ * @object: a #GObject
+ * @notify: a function to call when this reference is the
+ * last reference to the object, or is no longer
+ * the last reference.
+ * @data: data to pass to @notify
+ *
+ * Increases the reference count of the object by one and
+ * sets a callback to be called when all other references
+ * to the object are dropped, or when this is already the
+ * last reference to the object and another reference is
+ * established.
+ *
+ * Multiple toggle references may be added to the same
+ * gobject, however if there are multiple toggle references
+ * to an object, none of them will ever be notified until
+ * all but one are removed.
+ */
+void
+g_object_add_toggle_ref (GObject *object,
+ GToggleNotify notify,
+ gpointer data)
+{
+ ToggleRefStack *wstack;
+ guint i;
+
+ g_return_if_fail (G_IS_OBJECT (object));
+ g_return_if_fail (notify != NULL);
+ g_return_if_fail (object->ref_count >= 1);
+
+ g_object_ref (object);
+
+ wstack = g_datalist_id_remove_no_notify (&object->qdata, quark_toggle_refs);
+ if (wstack)
+ {
+ i = wstack->n_toggle_refs++;
+ wstack = g_realloc (wstack, sizeof (*wstack) + sizeof (wstack->toggle_refs[0]) * (i - 1));
+ }
+ else
+ {
+ wstack = g_renew (ToggleRefStack, NULL, 1);
+ wstack->object = object;
+ wstack->n_toggle_refs = 1;
+ i = 0;
+ }
+
+ if (wstack->n_toggle_refs == 1)
+ G_DATALIST_SET_FLAGS(&object->qdata, OBJECT_HAS_TOGGLE_REF_FLAG);
+
+ wstack->toggle_refs[i].notify = notify;
+ wstack->toggle_refs[i].data = data;
+ g_datalist_id_set_data_full (&object->qdata, quark_toggle_refs, wstack,
+ (GDestroyNotify)g_free);
+}
+
+/**
+ * g_object_remove_toggle_ref:
+ * @object: a #GObject
+ * @notify: a function to call when this reference is the
+ * last reference to the object, or is no longer
+ * the last reference.
+ * @data: data to pass to @notify
+ *
+ * Removes a reference added with g_object_add_toggle_ref(). The
+ * reference count of the object is decreased by one.
+ */
+void
+g_object_remove_toggle_ref (GObject *object,
+ GToggleNotify notify,
+ gpointer data)
+{
+ ToggleRefStack *wstack;
+ gboolean found_one = FALSE;
+
+ g_return_if_fail (G_IS_OBJECT (object));
+ g_return_if_fail (notify != NULL);
+
+ wstack = g_datalist_id_get_data (&object->qdata, quark_toggle_refs);
+ if (wstack)
+ {
+ guint i;
+
+ for (i = 0; i < wstack->n_toggle_refs; i++)
+ if (wstack->toggle_refs[i].notify == notify &&
+ wstack->toggle_refs[i].data == data)
+ {
+ found_one = TRUE;
+ wstack->n_toggle_refs -= 1;
+ if (i != wstack->n_toggle_refs)
+ wstack->toggle_refs[i] = wstack->toggle_refs[wstack->n_toggle_refs];
+
+ if (wstack->n_toggle_refs == 0)
+ G_DATALIST_SET_FLAGS(&object->qdata, 0);
+
+ g_object_unref (object);
+
+ break;
+ }
+ }
+
+ if (!found_one)
+ g_warning ("%s: couldn't find toggle ref %p(%p)", G_STRFUNC, notify, data);
+}
+
gpointer
g_object_ref (gpointer _object)
{
@@ -1568,6 +1699,8 @@ g_object_ref (gpointer _object)
#endif /* G_ENABLE_DEBUG */
object->ref_count += 1;
+ if (object->ref_count == 2 && OBJECT_HAS_TOGGLE_REF (object))
+ toggle_refs_notify (object, FALSE);
return object;
}
@@ -1586,7 +1719,11 @@ g_object_unref (gpointer _object)
#endif /* G_ENABLE_DEBUG */
if (object->ref_count > 1)
- object->ref_count -= 1;
+ {
+ object->ref_count -= 1;
+ if (object->ref_count == 1 && OBJECT_HAS_TOGGLE_REF (object))
+ toggle_refs_notify (object, TRUE);
+ }
else
g_object_last_unref (object);
}
Index: gobject/gobject.h
===================================================================
RCS file: /cvs/gnome/glib/gobject/gobject.h,v
retrieving revision 1.30
diff -u -p -u -r1.30 gobject.h
--- gobject/gobject.h 8 Mar 2005 05:41:42 -0000 1.30
+++ gobject/gobject.h 25 Apr 2005 22:57:13 -0000
@@ -178,6 +178,31 @@ void g_object_add_weak_pointer
gpointer *weak_pointer_location);
void g_object_remove_weak_pointer (GObject *object,
gpointer *weak_pointer_location);
+
+/**
+ * GToggleNotify:
+ * @data: Callback data passed to g_object_add_toggle_ref()
+ * @object: The object on which g_object_add_toggle_ref() was
+ * called.
+ * @is_last_ref: %TRUE if the toggle reference is now the
+ * last reference to the object. %FALSE if the toggle
+ * reference was the last reference and there are now other
+ * references.
+ *
+ * A callback function used for notification when the state
+ * of a toggle reference changes. See g_object_add_toggle_ref().
+ */
+typedef void (*GToggleNotify) (gpointer data,
+ GObject *object,
+ gboolean is_last_ref);
+
+void g_object_add_toggle_ref (GObject *object,
+ GToggleNotify notify,
+ gpointer data);
+void g_object_remove_toggle_ref (GObject *object,
+ GToggleNotify notify,
+ gpointer data);
+
gpointer g_object_get_qdata (GObject *object,
GQuark quark);
void g_object_set_qdata (GObject *object,
Index: tests/gobject/Makefile.am
===================================================================
RCS file: /cvs/gnome/glib/tests/gobject/Makefile.am,v
retrieving revision 1.7
diff -u -p -u -r1.7 Makefile.am
--- tests/gobject/Makefile.am 24 Oct 2003 03:41:22 -0000 1.7
+++ tests/gobject/Makefile.am 25 Apr 2005 22:57:13 -0000
@@ -52,7 +52,8 @@ test_programs = \
ifaceinit \
ifaceinherit \
ifaceproperties \
- override
+ override \
+ references
check_PROGRAMS = $(test_programs)
Index: tests/gobject/references.c
===================================================================
RCS file: tests/gobject/references.c
diff -N tests/gobject/references.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tests/gobject/references.c 25 Apr 2005 22:57:13 -0000
@@ -0,0 +1,281 @@
+/* GObject - GLib Type, Object, Parameter and Signal Library
+ * Copyright (C) 2005 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * 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.
+ */
+
+#undef G_LOG_DOMAIN
+#define G_LOG_DOMAIN "TestReferences"
+
+#undef G_DISABLE_ASSERT
+#undef G_DISABLE_CHECKS
+#undef G_DISABLE_CAST_CHECKS
+
+#include <glib-object.h>
+
+/* This test tests weak and toggle references
+ */
+
+static GObject *global_object;
+
+static gboolean object_destroyed;
+static gboolean weak_ref1_notified;
+static gboolean weak_ref2_notified;
+static gboolean toggle_ref1_weakened;
+static gboolean toggle_ref1_strengthened;
+static gboolean toggle_ref2_weakened;
+static gboolean toggle_ref2_strengthened;
+static gboolean toggle_ref3_weakened;
+static gboolean toggle_ref3_strengthened;
+
+/*
+ * TestObject, a parent class for TestObject
+ */
+#define TEST_TYPE_OBJECT (test_object_get_type ())
+typedef struct _TestObject TestObject;
+typedef struct _TestObjectClass TestObjectClass;
+
+struct _TestObject
+{
+ GObject parent_instance;
+};
+struct _TestObjectClass
+{
+ GObjectClass parent_class;
+};
+
+G_DEFINE_TYPE (TestObject, test_object, G_TYPE_OBJECT);
+
+static void
+test_object_finalize (GObject *object)
+{
+ object_destroyed = TRUE;
+
+ G_OBJECT_CLASS (test_object_parent_class)->finalize (object);
+}
+
+static void
+test_object_class_init (TestObjectClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ object_class->finalize = test_object_finalize;
+}
+
+static void
+test_object_init (TestObject *test_object)
+{
+}
+
+static void
+clear_flags (void)
+{
+ object_destroyed = FALSE;
+ weak_ref1_notified = FALSE;
+ weak_ref2_notified = FALSE;
+ toggle_ref1_weakened = FALSE;
+ toggle_ref1_strengthened = FALSE;
+ toggle_ref2_weakened = FALSE;
+ toggle_ref2_strengthened = FALSE;
+ toggle_ref3_weakened = FALSE;
+ toggle_ref3_strengthened = FALSE;
+}
+
+static void
+weak_ref1 (gpointer data,
+ GObject *object)
+{
+ g_assert (object == global_object);
+ g_assert (data == GUINT_TO_POINTER (42));
+
+ weak_ref1_notified = TRUE;
+}
+
+static void
+weak_ref2 (gpointer data,
+ GObject *object)
+{
+ g_assert (object == global_object);
+ g_assert (data == GUINT_TO_POINTER (24));
+
+ weak_ref2_notified = TRUE;
+}
+
+static void
+toggle_ref1 (gpointer data,
+ GObject *object,
+ gboolean is_last_ref)
+{
+ g_assert (object == global_object);
+ g_assert (data == GUINT_TO_POINTER (42));
+
+ if (is_last_ref)
+ toggle_ref1_weakened = TRUE;
+ else
+ toggle_ref1_strengthened = TRUE;
+}
+
+static void
+toggle_ref2 (gpointer data,
+ GObject *object,
+ gboolean is_last_ref)
+{
+ g_assert (object == global_object);
+ g_assert (data == GUINT_TO_POINTER (24));
+
+ if (is_last_ref)
+ toggle_ref2_weakened = TRUE;
+ else
+ toggle_ref2_strengthened = TRUE;
+}
+
+static void
+toggle_ref3 (gpointer data,
+ GObject *object,
+ gboolean is_last_ref)
+{
+ g_assert (object == global_object);
+ g_assert (data == GUINT_TO_POINTER (34));
+
+ if (is_last_ref)
+ {
+ toggle_ref3_weakened = TRUE;
+ g_object_remove_toggle_ref (object, toggle_ref3, GUINT_TO_POINTER (34));
+ }
+ else
+ toggle_ref3_strengthened = TRUE;
+}
+
+int
+main (int argc,
+ char *argv[])
+{
+ GObject *object;
+
+ g_log_set_always_fatal (g_log_set_always_fatal (G_LOG_FATAL_MASK) |
+ G_LOG_LEVEL_WARNING |
+ G_LOG_LEVEL_CRITICAL);
+ g_type_init ();
+
+ /* Test basic weak reference operation
+ */
+ global_object = object = g_object_new (TEST_TYPE_OBJECT, NULL);
+
+ g_object_weak_ref (object, weak_ref1, GUINT_TO_POINTER (42));
+
+ clear_flags ();
+ g_object_unref (object);
+ g_assert (weak_ref1_notified == TRUE);
+ g_assert (object_destroyed == TRUE);
+
+ /* Test two weak references at once
+ */
+ global_object = object = g_object_new (TEST_TYPE_OBJECT, NULL);
+
+ g_object_weak_ref (object, weak_ref1, GUINT_TO_POINTER (42));
+ g_object_weak_ref (object, weak_ref2, GUINT_TO_POINTER (24));
+
+ clear_flags ();
+ g_object_unref (object);
+ g_assert (weak_ref1_notified == TRUE);
+ g_assert (weak_ref2_notified == TRUE);
+ g_assert (object_destroyed == TRUE);
+
+ /* Test remove weak references
+ */
+ global_object = object = g_object_new (TEST_TYPE_OBJECT, NULL);
+
+ g_object_weak_ref (object, weak_ref1, GUINT_TO_POINTER (42));
+ g_object_weak_ref (object, weak_ref2, GUINT_TO_POINTER (24));
+ g_object_weak_unref (object, weak_ref1, GUINT_TO_POINTER (42));
+
+ clear_flags ();
+ g_object_unref (object);
+ g_assert (weak_ref1_notified == FALSE);
+ g_assert (weak_ref2_notified == TRUE);
+ g_assert (object_destroyed == TRUE);
+
+ /* Test basic toggle reference operation
+ */
+ global_object = object = g_object_new (TEST_TYPE_OBJECT, NULL);
+
+ g_object_add_toggle_ref (object, toggle_ref1, GUINT_TO_POINTER (42));
+
+ clear_flags ();
+ g_object_unref (object);
+ g_assert (toggle_ref1_weakened == TRUE);
+ g_assert (toggle_ref1_strengthened == FALSE);
+ g_assert (object_destroyed == FALSE);
+
+ clear_flags ();
+ g_object_ref (object);
+ g_assert (toggle_ref1_weakened == FALSE);
+ g_assert (toggle_ref1_strengthened == TRUE);
+ g_assert (object_destroyed == FALSE);
+
+ g_object_unref (object);
+
+ clear_flags ();
+ g_object_remove_toggle_ref (object, toggle_ref1, GUINT_TO_POINTER (42));
+ g_assert (toggle_ref1_weakened == FALSE);
+ g_assert (toggle_ref1_strengthened == FALSE);
+ g_assert (object_destroyed == TRUE);
+
+ global_object = object = g_object_new (TEST_TYPE_OBJECT, NULL);
+
+ /* Test two toggle references at once
+ */
+ g_object_add_toggle_ref (object, toggle_ref1, GUINT_TO_POINTER (42));
+ g_object_add_toggle_ref (object, toggle_ref2, GUINT_TO_POINTER (24));
+
+ clear_flags ();
+ g_object_unref (object);
+ g_assert (toggle_ref1_weakened == FALSE);
+ g_assert (toggle_ref1_strengthened == FALSE);
+ g_assert (toggle_ref2_weakened == FALSE);
+ g_assert (toggle_ref2_strengthened == FALSE);
+ g_assert (object_destroyed == FALSE);
+
+ clear_flags ();
+ g_object_remove_toggle_ref (object, toggle_ref1, GUINT_TO_POINTER (42));
+ g_assert (toggle_ref1_weakened == FALSE);
+ g_assert (toggle_ref1_strengthened == FALSE);
+ g_assert (toggle_ref2_weakened == TRUE);
+ g_assert (toggle_ref2_strengthened == FALSE);
+ g_assert (object_destroyed == FALSE);
+
+ clear_flags ();
+ g_object_remove_toggle_ref (object, toggle_ref2, GUINT_TO_POINTER (24));
+ g_assert (toggle_ref1_weakened == FALSE);
+ g_assert (toggle_ref1_strengthened == FALSE);
+ g_assert (toggle_ref2_weakened == FALSE);
+ g_assert (toggle_ref2_strengthened == FALSE);
+ g_assert (object_destroyed == TRUE);
+
+ /* Test a toggle reference that removes itself
+ */
+ global_object = object = g_object_new (TEST_TYPE_OBJECT, NULL);
+
+ g_object_add_toggle_ref (object, toggle_ref3, GUINT_TO_POINTER (34));
+
+ clear_flags ();
+ g_object_unref (object);
+ g_assert (toggle_ref3_weakened == TRUE);
+ g_assert (toggle_ref3_strengthened == FALSE);
+ g_assert (object_destroyed == TRUE);
+
+ return 0;
+}
Attachment:
signature.asc
Description: This is a digitally signed message part