[pygobject] Fall back to use the floating references API in glib if there isn't a sinkfunc defined.



commit 00a85f6a844714d1715e2f67431747d1a4cdacb1
Author: Tomeu Vizoso <tomeu vizoso collabora co uk>
Date:   Mon Jun 21 17:33:56 2010 +0200

    Fall back to use the floating references API in glib if there isn't a sinkfunc defined.
    
    * tests/*: Add ref counting tests for floating objects
    * gobject/gobjectmodule.c, gobject/pygobject.c: Fall back to g_object_ref_sink
      or g_object_ref if there isn't a sinkfunc defined. Make sure that
      pygobject_sink gets called only once per GObject instance.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=583909

 gobject/gobjectmodule.c  |    2 -
 gobject/pygobject.c      |   50 +++++++++++++--------
 gobject/pygobject.h      |    1 +
 tests/Makefile.am        |    2 +
 tests/test-floating.c    |   95 ++++++++++++++++++++++++++++++++++++++++
 tests/test-floating.h    |   60 +++++++++++++++++++++++++
 tests/test_gobject.py    |   19 ++++++++-
 tests/testhelpermodule.c |  109 ++++++++++++++++++++++++++++++++++++++++++++++
 8 files changed, 315 insertions(+), 23 deletions(-)
---
diff --git a/gobject/gobjectmodule.c b/gobject/gobjectmodule.c
index be0bc0b..09244b8 100644
--- a/gobject/gobjectmodule.c
+++ b/gobject/gobjectmodule.c
@@ -1758,7 +1758,6 @@ pyg_object_new (PyGObject *self, PyObject *args, PyObject *kwargs)
     if (obj) {
 	self = (PyGObject *) pygobject_new_full((GObject *)obj, FALSE, NULL);
         g_object_unref(obj);
-        pygobject_sink(obj);
     } else
         self = NULL;
 
@@ -2259,7 +2258,6 @@ pygobject_constructv(PyGObject  *self,
         pygobject_init_wrapper_set(NULL);
         if (self->obj == NULL) {
             self->obj = obj;
-            pygobject_sink(obj);
             pygobject_register_wrapper((PyObject *) self);
         }
     } else {
diff --git a/gobject/pygobject.c b/gobject/pygobject.c
index 4a88384..2671fa9 100644
--- a/gobject/pygobject.c
+++ b/gobject/pygobject.c
@@ -142,10 +142,18 @@ pygobject_sink(GObject *obj)
 	    if (g_type_is_a(G_OBJECT_TYPE(obj),
 			    g_array_index(sink_funcs, SinkFunc, i).type)) {
 		g_array_index(sink_funcs, SinkFunc, i).sinkfunc(obj);
-		break;
+		return;
 	    }
 	}
     }
+    if (G_IS_INITIALLY_UNOWNED(obj) && !g_object_is_floating(obj)) {
+        /* GtkWindow and GtkInvisible does not return a ref to caller of
+         * g_object_new.
+         */
+        g_object_ref(obj);
+    } else if (g_object_is_floating(obj)) {
+        g_object_ref_sink(obj);
+    }
 }
 
 /**
@@ -160,12 +168,17 @@ pygobject_sink(GObject *obj)
  *
  * The sinkfunc should be able to remove the floating reference on
  * instances of the given type, or any subclasses.
+ *
+ * Deprecated: Since 2.22, sinkfuncs are not needed.
  */
 void
 pygobject_register_sinkfunc(GType type, void (* sinkfunc)(GObject *object))
 {
     SinkFunc sf;
 
+    g_message ("pygobject_register_sinkfunc is deprecated (%s)",
+               g_type_name(type));
+
 #if 0
     g_return_if_fail(G_TYPE_IS_OBJECT(type));
 #endif
@@ -592,27 +605,24 @@ pygobject_switch_to_toggle_ref(PyGObject *self)
  * In the constructor of PyGTK wrappers, this function should be
  * called after setting the obj member.  It will tie the wrapper
  * instance to the GObject so that the same wrapper instance will
- * always be used for this GObject instance.  It may also sink any
- * floating references on the GObject.
+ * always be used for this GObject instance.
  */
-static inline void
-pygobject_register_wrapper_full(PyGObject *self, gboolean sink)
-{
-    GObject *obj = self->obj;
-
-    if (sink)
-        pygobject_sink(obj);
-    g_assert(obj->ref_count >= 1);
-      /* save wrapper pointer so we can access it later */
-    g_object_set_qdata_full(obj, pygobject_wrapper_key, self, NULL);
-    if (self->inst_dict)
-        pygobject_switch_to_toggle_ref(self);
-}
-
 void
 pygobject_register_wrapper(PyObject *self)
 {
-    pygobject_register_wrapper_full((PyGObject *)self, TRUE);
+    PyGObject *gself;
+
+    g_return_if_fail(self != NULL);
+    g_return_if_fail(PyObject_TypeCheck(self, &PyGObject_Type));
+
+    gself = (PyGObject *)self;
+
+    pygobject_sink(gself->obj);
+    g_assert(gself->obj->ref_count >= 1);
+      /* save wrapper pointer so we can access it later */
+    g_object_set_qdata_full(gself->obj, pygobject_wrapper_key, gself, NULL);
+    if (gself->inst_dict)
+        pygobject_switch_to_toggle_ref(gself);
 }
 
 static PyObject *
@@ -891,7 +901,7 @@ pygobject_lookup_class(GType gtype)
 /**
  * pygobject_new_full:
  * @obj: a GObject instance.
- * @sink: whether to sink any floating reference found on the GObject.
+ * @sink: whether to sink any floating reference found on the GObject. DEPRECATED.
  * @g_class: the GObjectClass
  *
  * This function gets a reference to a wrapper for the given GObject
@@ -941,7 +951,7 @@ pygobject_new_full(GObject *obj, gboolean sink, gpointer g_class)
 	self->private_flags.flags = 0;
 	self->obj = obj;
 	g_object_ref(obj);
-	pygobject_register_wrapper_full(self, sink);
+	pygobject_register_wrapper((PyObject *)self);
 	PyObject_GC_Track((PyObject *)self);
     }
 
diff --git a/gobject/pygobject.h b/gobject/pygobject.h
index d7eba07..85d8bca 100644
--- a/gobject/pygobject.h
+++ b/gobject/pygobject.h
@@ -210,6 +210,7 @@ struct _PyGObject_Functions *_PyGObject_API;
 
 #define pygobject_register_class    (_PyGObject_API->register_class)
 #define pygobject_register_wrapper  (_PyGObject_API->register_wrapper)
+/* This is deprecated, sinkfuncs are not needed anymore */
 #define pygobject_register_sinkfunc (_PyGObject_API->register_sinkfunc)
 #define pygobject_lookup_class      (_PyGObject_API->lookup_class)
 #define pygobject_new               (_PyGObject_API->newgobj)
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 8d2f50f..fcdffe1 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -8,6 +8,7 @@ EXTRA_DIST = \
 	common.py \
 	runtests.py \
 	testmodule.py \
+	test-floating.h \
 	test-thread.h \
 	test-unknown.h
 
@@ -18,6 +19,7 @@ testhelper_la_LDFLAGS = -module -avoid-version
 testhelper_la_LIBADD = $(GLIB_LIBS)
 testhelper_la_SOURCES = \
 	testhelpermodule.c \
+	test-floating.c \
 	test-thread.c \
 	test-unknown.c 
 
diff --git a/tests/test-floating.c b/tests/test-floating.c
new file mode 100644
index 0000000..918a42d
--- /dev/null
+++ b/tests/test-floating.c
@@ -0,0 +1,95 @@
+/*
+ * test-floating.c - Source for TestFloatingWithSinkFunc and TestFloatingWithoutSinkFunc
+ * Copyright (C) 2010 Collabora Ltd.
+ *
+ * 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.1 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "test-floating.h"
+
+/* TestFloatingWithSinkFunc */
+
+G_DEFINE_TYPE(TestFloatingWithSinkFunc, test_floating_with_sink_func, G_TYPE_INITIALLY_UNOWNED)
+
+static void
+test_floating_with_sink_func_finalize (GObject *gobject)
+{
+  TestFloatingWithSinkFunc *object = TEST_FLOATING_WITH_SINK_FUNC (gobject);
+
+  if (g_object_is_floating (object))
+    {
+      g_warning ("A floating object was finalized. This means that someone\n"
+		 "called g_object_unref() on an object that had only a floating\n"
+		 "reference; the initial floating reference is not owned by anyone\n"
+		 "and must be removed with g_object_ref_sink().");
+    }
+  
+  G_OBJECT_CLASS (test_floating_with_sink_func_parent_class)->finalize (gobject);
+}
+
+static void
+test_floating_with_sink_func_class_init (TestFloatingWithSinkFuncClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->finalize = test_floating_with_sink_func_finalize;
+}
+
+static void
+test_floating_with_sink_func_init (TestFloatingWithSinkFunc *self)
+{
+}
+
+void
+sink_test_floating_with_sink_func (GObject *object)
+{
+    if (g_object_is_floating(object)) {
+	    g_object_ref_sink(object);
+    }
+}
+
+/* TestFloatingWithoutSinkFunc */
+
+G_DEFINE_TYPE(TestFloatingWithoutSinkFunc, test_floating_without_sink_func, G_TYPE_INITIALLY_UNOWNED)
+
+static void
+test_floating_without_sink_func_finalize (GObject *gobject)
+{
+  TestFloatingWithoutSinkFunc *object = TEST_FLOATING_WITHOUT_SINK_FUNC (gobject);
+
+  if (g_object_is_floating (object))
+    {
+      g_warning ("A floating object was finalized. This means that someone\n"
+		 "called g_object_unref() on an object that had only a floating\n"
+		 "reference; the initial floating reference is not owned by anyone\n"
+		 "and must be removed without g_object_ref_sink().");
+    }
+
+  G_OBJECT_CLASS (test_floating_without_sink_func_parent_class)->finalize (gobject);
+}
+
+static void
+test_floating_without_sink_func_class_init (TestFloatingWithoutSinkFuncClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->finalize = test_floating_without_sink_func_finalize;
+}
+
+static void
+test_floating_without_sink_func_init (TestFloatingWithoutSinkFunc *self)
+{
+}
+
diff --git a/tests/test-floating.h b/tests/test-floating.h
new file mode 100644
index 0000000..e53df32
--- /dev/null
+++ b/tests/test-floating.h
@@ -0,0 +1,60 @@
+/*
+ * test-floating.h - Header for TestFloatingWithSinkFunc and TestFloatingWithoutSinkFunc
+ * Copyright (C) 2010 Collabora Ltd.
+ *
+ * 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.1 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <glib-object.h>
+
+/* TestFloatingWithSinkFunc */
+
+typedef struct {
+  GInitiallyUnowned parent;
+} TestFloatingWithSinkFunc;
+
+typedef struct {
+  GInitiallyUnownedClass parent_class;
+} TestFloatingWithSinkFuncClass;
+
+#define TEST_TYPE_FLOATING_WITH_SINK_FUNC (test_floating_with_sink_func_get_type())
+#define TEST_FLOATING_WITH_SINK_FUNC(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), TEST_TYPE_FLOATING_WITH_SINK_FUNC, TestFloatingWithSinkFunc))
+#define TEST_FLOATING_WITH_SINK_FUNC_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), TEST_TYPE_FLOATING_WITH_SINK_FUNC, TestFloatingWithSinkFuncClass))
+#define TEST_IS_FLOATING_WITH_SINK_FUNC(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TEST_TYPE_FLOATING_WITH_SINK_FUNC))
+#define TEST_IS_FLOATING_WITH_SINK_FUNC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), TEST_TYPE_FLOATING_WITH_SINK_FUNC))
+#define TEST_FLOATING_WITH_SINK_FUNC_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), TEST_TYPE_FLOATING_WITH_SINK_FUNC, TestFloatingWithSinkFuncClass))
+
+GType test_floating_with_sink_func_get_type (void);
+void sink_test_floating_with_sink_func (GObject *object);
+
+/* TestFloatingWithoutSinkFunc */
+
+typedef struct {
+  GInitiallyUnowned parent;
+} TestFloatingWithoutSinkFunc;
+
+typedef struct {
+  GInitiallyUnownedClass parent_class;
+} TestFloatingWithoutSinkFuncClass;
+
+#define TEST_TYPE_FLOATING_WITHOUT_SINK_FUNC (test_floating_without_sink_func_get_type())
+#define TEST_FLOATING_WITHOUT_SINK_FUNC(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), TEST_TYPE_FLOATING_WITHOUT_SINK_FUNC, TestFloatingWithoutSinkFunc))
+#define TEST_FLOATING_WITHOUT_SINK_FUNC_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), TEST_TYPE_FLOATING_WITHOUT_SINK_FUNC, TestFloatingWithoutSinkFuncClass))
+#define TEST_IS_FLOATING_WITHOUT_SINK_FUNC(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TEST_TYPE_FLOATING_WITHOUT_SINK_FUNC))
+#define TEST_IS_FLOATING_WITHOUT_SINK_FUNC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), TEST_TYPE_FLOATING_WITHOUT_SINK_FUNC))
+#define TEST_FLOATING_WITHOUT_SINK_FUNC_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), TEST_TYPE_FLOATING_WITHOUT_SINK_FUNC, TestFloatingWithoutSinkFuncClass))
+
+GType test_floating_without_sink_func_get_type (void);
+
diff --git a/tests/test_gobject.py b/tests/test_gobject.py
index 34ba094..d91f3ad 100644
--- a/tests/test_gobject.py
+++ b/tests/test_gobject.py
@@ -2,7 +2,7 @@
 
 import unittest
 
-from common import gobject
+from common import gobject, testhelper
 
 
 class TestGObjectAPI(unittest.TestCase):
@@ -10,3 +10,20 @@ class TestGObjectAPI(unittest.TestCase):
         obj = gobject.GObject()
         self.assertEquals(obj.__module__,
                           'gobject._gobject')
+        self.assertEquals(obj.__grefcount__, 1)
+
+
+class TestFloating(unittest.TestCase):
+    def testFloatingWithSinkFunc(self):
+        obj = testhelper.FloatingWithSinkFunc()
+        self.assertEquals(obj.__grefcount__, 1)
+
+        obj = gobject.new(testhelper.FloatingWithSinkFunc)
+        self.assertEquals(obj.__grefcount__, 1)
+
+    def testFloatingWithoutSinkFunc(self):
+        obj = testhelper.FloatingWithoutSinkFunc()
+        self.assertEquals(obj.__grefcount__, 1)
+
+        obj = gobject.new(testhelper.FloatingWithoutSinkFunc)
+        self.assertEquals(obj.__grefcount__, 1)
diff --git a/tests/testhelpermodule.c b/tests/testhelpermodule.c
index d78cf55..21679bc 100644
--- a/tests/testhelpermodule.c
+++ b/tests/testhelpermodule.c
@@ -3,6 +3,7 @@
 
 #include "test-thread.h"
 #include "test-unknown.h"
+#include "test-floating.h"
 
 static PyTypeObject *_PyGObject_Type;
 #define PyGObject_Type (*_PyGObject_Type)
@@ -311,6 +312,100 @@ static const GInterfaceInfo __TestInterface__iinfo = {
     NULL
 };
 
+/* TestFloatingWithSinkFunc */
+
+PyTypeObject PyTestFloatingWithSinkFunc_Type = {
+    PyObject_HEAD_INIT(NULL)
+    0,                                 /* ob_size */
+    "testhelper.FloatingWithSinkFunc", /* tp_name */
+    sizeof(PyGObject),          /* tp_basicsize */
+    0,                                 /* tp_itemsize */
+    /* methods */
+    (destructor)0,        /* tp_dealloc */
+    (printfunc)0,                      /* tp_print */
+    (getattrfunc)0,       /* tp_getattr */
+    (setattrfunc)0,       /* tp_setattr */
+    (cmpfunc)0,           /* tp_compare */
+    (reprfunc)0,             /* tp_repr */
+    (PyNumberMethods*)0,     /* tp_as_number */
+    (PySequenceMethods*)0, /* tp_as_sequence */
+    (PyMappingMethods*)0,   /* tp_as_mapping */
+    (hashfunc)0,             /* tp_hash */
+    (ternaryfunc)0,          /* tp_call */
+    (reprfunc)0,              /* tp_str */
+    (getattrofunc)0,     /* tp_getattro */
+    (setattrofunc)0,     /* tp_setattro */
+    (PyBufferProcs*)0,  /* tp_as_buffer */
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,                      /* tp_flags */
+    NULL,                        /* Documentation string */
+    (traverseproc)0,     /* tp_traverse */
+    (inquiry)0,             /* tp_clear */
+    (richcmpfunc)0,   /* tp_richcompare */
+    offsetof(PyGObject, weakreflist),             /* tp_weaklistoffset */
+    (getiterfunc)0,          /* tp_iter */
+    (iternextfunc)0,     /* tp_iternext */
+    (struct PyMethodDef*)0, /* tp_methods */
+    (struct PyMemberDef*)0,              /* tp_members */
+    (struct PyGetSetDef*)0,  /* tp_getset */
+    NULL,                              /* tp_base */
+    NULL,                              /* tp_dict */
+    (descrgetfunc)0,    /* tp_descr_get */
+    (descrsetfunc)0,    /* tp_descr_set */
+    offsetof(PyGObject, inst_dict),                 /* tp_dictoffset */
+    (initproc)0,             /* tp_init */
+    (allocfunc)0,           /* tp_alloc */
+    (newfunc)0,               /* tp_new */
+    (freefunc)0,             /* tp_free */
+    (inquiry)0              /* tp_is_gc */
+};
+
+/* TestFloatingWithoutSinkFunc */
+
+PyTypeObject PyTestFloatingWithoutSinkFunc_Type = {
+    PyObject_HEAD_INIT(NULL)
+    0,                                 /* ob_size */
+    "testhelper.FloatingWithoutSinkFunc", /* tp_name */
+    sizeof(PyGObject),          /* tp_basicsize */
+    0,                                 /* tp_itemsize */
+    /* methods */
+    (destructor)0,        /* tp_dealloc */
+    (printfunc)0,                      /* tp_print */
+    (getattrfunc)0,       /* tp_getattr */
+    (setattrfunc)0,       /* tp_setattr */
+    (cmpfunc)0,           /* tp_compare */
+    (reprfunc)0,             /* tp_repr */
+    (PyNumberMethods*)0,     /* tp_as_number */
+    (PySequenceMethods*)0, /* tp_as_sequence */
+    (PyMappingMethods*)0,   /* tp_as_mapping */
+    (hashfunc)0,             /* tp_hash */
+    (ternaryfunc)0,          /* tp_call */
+    (reprfunc)0,              /* tp_str */
+    (getattrofunc)0,     /* tp_getattro */
+    (setattrofunc)0,     /* tp_setattro */
+    (PyBufferProcs*)0,  /* tp_as_buffer */
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,                      /* tp_flags */
+    NULL,                        /* Documentation string */
+    (traverseproc)0,     /* tp_traverse */
+    (inquiry)0,             /* tp_clear */
+    (richcmpfunc)0,   /* tp_richcompare */
+    offsetof(PyGObject, weakreflist),             /* tp_weaklistoffset */
+    (getiterfunc)0,          /* tp_iter */
+    (iternextfunc)0,     /* tp_iternext */
+    (struct PyMethodDef*)0, /* tp_methods */
+    (struct PyMemberDef*)0,              /* tp_members */
+    (struct PyGetSetDef*)0,  /* tp_getset */
+    NULL,                              /* tp_base */
+    NULL,                              /* tp_dict */
+    (descrgetfunc)0,    /* tp_descr_get */
+    (descrsetfunc)0,    /* tp_descr_set */
+    offsetof(PyGObject, inst_dict),                 /* tp_dictoffset */
+    (initproc)0,             /* tp_init */
+    (allocfunc)0,           /* tp_alloc */
+    (newfunc)0,               /* tp_new */
+    (freefunc)0,             /* tp_free */
+    (inquiry)0              /* tp_is_gc */
+};
+
 #include <string.h>
 #include <glib-object.h>
 
@@ -566,5 +661,19 @@ inittesthelper ()
   pyg_set_object_has_new_constructor(TEST_TYPE_UNKNOWN);
   //pyg_register_class_init(TEST_TYPE_UNKNOWN, __GtkUIManager_class_init);
 
+  /* TestFloatingWithSinkFunc */
+  pygobject_register_class(d, "FloatingWithSinkFunc", TEST_TYPE_FLOATING_WITH_SINK_FUNC,
+			   &PyTestFloatingWithSinkFunc_Type,
+			   Py_BuildValue("(O)",
+					 &PyGObject_Type));
+  pyg_set_object_has_new_constructor(TEST_TYPE_FLOATING_WITH_SINK_FUNC);
+  pygobject_register_sinkfunc(TEST_TYPE_FLOATING_WITH_SINK_FUNC, sink_test_floating_with_sink_func);
+
+  /* TestFloatingWithoutSinkFunc */
+  pygobject_register_class(d, "FloatingWithoutSinkFunc", TEST_TYPE_FLOATING_WITHOUT_SINK_FUNC,
+			   &PyTestFloatingWithoutSinkFunc_Type,
+			   Py_BuildValue("(O)",
+					 &PyGObject_Type));
+  pyg_set_object_has_new_constructor(TEST_TYPE_FLOATING_WITHOUT_SINK_FUNC);
 }
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]