summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBilal Elmoussaoui <belmouss@redhat.com>2022-02-15 15:02:54 +0100
committerBilal Elmoussaoui <belmouss@redhat.com>2022-07-26 19:27:09 +0200
commitae542670ac9f0899e54ca907199b4489571a869f (patch)
treea0eae51b1dfce13bbff8b4eea6636eb318ac8975
parent3e46d7c47b218056b136db8e95eb04f4e5338ef7 (diff)
downloadpygobject-ae542670ac9f0899e54ca907199b4489571a869f.tar.gz
object: Allow overriding dispose implementation
In GTK4 people are expected to unparent their custom GtkWidget implementation in the object's dispose method which is the main motivation behind this patch
-rw-r--r--gi/gimodule.c41
-rw-r--r--tests/test_gobject.py15
2 files changed, 56 insertions, 0 deletions
diff --git a/gi/gimodule.c b/gi/gimodule.c
index 766fd341..0e735872 100644
--- a/gi/gimodule.c
+++ b/gi/gimodule.c
@@ -938,6 +938,46 @@ pyg_object_set_property (GObject *object, guint property_id,
}
static void
+pyg_object_dispose (GObject *object)
+{
+ PyObject *object_wrapper, *retval;
+ PyGILState_STATE state;
+ GObjectClass *parent_class = g_type_class_peek (g_type_parent (G_TYPE_FROM_INSTANCE (object)));
+ if (parent_class == NULL)
+ return;
+ state = PyGILState_Ensure();
+
+ object_wrapper = g_object_get_qdata(object, pygobject_wrapper_key);
+
+ if (object_wrapper)
+ Py_INCREF (object_wrapper);
+ else
+ object_wrapper = pygobject_new(object);
+
+ if (object_wrapper == NULL) {
+ PyGILState_Release(state);
+ return;
+ }
+ // Chain up only if the object override dispose
+ if (PyObject_HasAttrString (object_wrapper, "do_dispose")) {
+ retval = PyObject_CallMethod(object_wrapper, "do_dispose", NULL);
+ if (retval) {
+ Py_DECREF(retval);
+ } else {
+ PyErr_Print();
+ }
+
+ // Chain up the dispose call
+ if (parent_class->dispose) {
+ parent_class->dispose(object);
+ }
+ }
+ Py_DECREF(object_wrapper);
+
+ PyGILState_Release(state);
+}
+
+static void
pyg_object_class_init(GObjectClass *class, PyObject *py_class)
{
PyObject *gproperties, *gsignals, *overridden_signals;
@@ -945,6 +985,7 @@ pyg_object_class_init(GObjectClass *class, PyObject *py_class)
class->set_property = pyg_object_set_property;
class->get_property = pyg_object_get_property;
+ class->dispose = pyg_object_dispose;
/* install signals */
/* we look this up in the instance dictionary, so we don't
diff --git a/tests/test_gobject.py b/tests/test_gobject.py
index fbc3bb79..6a4f52ab 100644
--- a/tests/test_gobject.py
+++ b/tests/test_gobject.py
@@ -775,6 +775,21 @@ class TestGValue(unittest.TestCase):
value = GObject.Value(GObject.TYPE_OBJECT, obj)
self.assertEqual(value.get_value(), obj)
+ def test_dispose_object(self):
+ class TestObject(GObject.Object):
+ def __init__(self):
+ super().__init__()
+ self.child = "Some Child"
+ def do_dispose(self):
+ print("running dispose")
+ self.child = None
+ return True
+ obj = TestObject()
+ print(obj)
+ obj.run_dispose()
+ print("test")
+ self.assertEqual(obj.child, None)
+
def test_value_array(self):
value = GObject.Value(GObject.ValueArray)
self.assertEqual(value.g_type, GObject.type_from_name('GValueArray'))