From 9456ba70fdb98b3a4eb7ee2f630182387a54ca00 Mon Sep 17 00:00:00 2001 From: Martin Pitt Date: Tue, 19 Feb 2013 15:39:56 +0100 Subject: [PATCH] Move property and signal creation into _class_init() We must not add class interfaces after g_type_class_ref() has been called the first time. Move signal and property creation from pyg_type_register() into pyg_object_class_init(), and drop the hack of registering interfaces twice. This is a backport of commit efcb0f9fd for 2.28.x. This allows old pygtk applications to work with pygobject 2.28.x and glib 2.35.x. https://bugzilla.gnome.org/show_bug.cgi?id=694108 --- gobject/gobjectmodule.c | 177 +++++++++++++++++++----------------------------- 1 file changed, 70 insertions(+), 107 deletions(-) diff --git a/gobject/gobjectmodule.c b/gobject/gobjectmodule.c index 2a84606..91f7315 100644 --- a/gobject/gobjectmodule.c +++ b/gobject/gobjectmodule.c @@ -312,13 +312,6 @@ pyg_object_get_property (GObject *object, guint property_id, pyglib_gil_state_release(state); } -static void -pyg_object_class_init(GObjectClass *class, PyObject *py_class) -{ - class->set_property = pyg_object_set_property; - class->get_property = pyg_object_get_property; -} - typedef struct _PyGSignalAccumulatorData { PyObject *callable; PyObject *user_data; @@ -484,15 +477,14 @@ override_signal(GType instance_type, const gchar *signal_name) } static PyObject * -add_signals (GType instance_type, PyObject *signals) +add_signals (GObjectClass *klass, PyObject *signals) { gboolean ret = TRUE; - GObjectClass *oclass; Py_ssize_t pos = 0; PyObject *key, *value, *overridden_signals = NULL; + GType instance_type = G_OBJECT_CLASS_TYPE (klass); overridden_signals = PyDict_New(); - oclass = g_type_class_ref(instance_type); while (PyDict_Next(signals, &pos, &key, &value)) { const gchar *signal_name; gchar *signal_name_canon, *c; @@ -530,7 +522,6 @@ add_signals (GType instance_type, PyObject *signals) if (!ret) break; } - g_type_class_unref(oclass); if (ret) return overridden_signals; else { @@ -800,14 +791,12 @@ pyg_param_spec_from_object (PyObject *tuple) } static gboolean -add_properties (GType instance_type, PyObject *properties) +add_properties (GObjectClass *klass, PyObject *properties) { gboolean ret = TRUE; - GObjectClass *oclass; Py_ssize_t pos = 0; PyObject *key, *value; - oclass = g_type_class_ref(instance_type); while (PyDict_Next(properties, &pos, &key, &value)) { const gchar *prop_name; GType prop_type; @@ -873,7 +862,7 @@ add_properties (GType instance_type, PyObject *properties) Py_DECREF(slice); if (pspec) { - g_object_class_install_property(oclass, 1, pspec); + g_object_class_install_property(klass, 1, pspec); } else { PyObject *type, *value, *traceback; ret = FALSE; @@ -883,7 +872,7 @@ add_properties (GType instance_type, PyObject *properties) g_snprintf(msg, 256, "%s (while registering property '%s' for GType '%s')", PYGLIB_PyUnicode_AsString(value), - prop_name, g_type_name(instance_type)); + prop_name, G_OBJECT_CLASS_NAME(klass)); Py_DECREF(value); value = PYGLIB_PyUnicode_FromString(msg); } @@ -892,11 +881,63 @@ add_properties (GType instance_type, PyObject *properties) } } - g_type_class_unref(oclass); return ret; } static void +pyg_object_class_init(GObjectClass *class, PyObject *py_class) +{ + PyObject *gproperties, *gsignals, *overridden_signals; + PyObject *class_dict = ((PyTypeObject*) py_class)->tp_dict; + + class->set_property = pyg_object_set_property; + class->get_property = pyg_object_get_property; + + /* install signals */ + /* we look this up in the instance dictionary, so we don't + * accidentally get a parent type's __gsignals__ attribute. */ + gsignals = PyDict_GetItemString(class_dict, "__gsignals__"); + if (gsignals) { + if (!PyDict_Check(gsignals)) { + PyErr_SetString(PyExc_TypeError, + "__gsignals__ attribute not a dict!"); + return; + } + if (!(overridden_signals = add_signals(class, gsignals))) { + return; + } + if (PyDict_SetItemString(class_dict, "__gsignals__", + overridden_signals)) { + return; + } + Py_DECREF(overridden_signals); + + PyDict_DelItemString(class_dict, "__gsignals__"); + } else { + PyErr_Clear(); + } + + /* install properties */ + /* we look this up in the instance dictionary, so we don't + * accidentally get a parent type's __gproperties__ attribute. */ + gproperties = PyDict_GetItemString(class_dict, "__gproperties__"); + if (gproperties) { + if (!PyDict_Check(gproperties)) { + PyErr_SetString(PyExc_TypeError, + "__gproperties__ attribute not a dict!"); + return; + } + if (!add_properties(class, gproperties)) { + return; + } + PyDict_DelItemString(class_dict, "__gproperties__"); + /* Borrowed reference. Py_DECREF(gproperties); */ + } else { + PyErr_Clear(); + } +} + +static void pyg_register_class_init(GType gtype, PyGClassInitFunc class_init) { GSList *list; @@ -1068,7 +1109,7 @@ pygobject__g_instance_init(GTypeInstance *instance, */ static void pyg_type_add_interfaces(PyTypeObject *class, GType instance_type, - PyObject *bases, gboolean new_interfaces, + PyObject *bases, GType *parent_interfaces, guint n_parent_interfaces) { int i; @@ -1082,7 +1123,6 @@ pyg_type_add_interfaces(PyTypeObject *class, GType instance_type, guint k; PyObject *base = PyTuple_GET_ITEM(bases, i); GType itype; - gboolean is_new = TRUE; const GInterfaceInfo *iinfo; GInterfaceInfo iinfo_copy; @@ -1099,16 +1139,6 @@ pyg_type_add_interfaces(PyTypeObject *class, GType instance_type, if (!G_TYPE_IS_INTERFACE(itype)) continue; - for (k = 0; k < n_parent_interfaces; ++k) { - if (parent_interfaces[k] == itype) { - is_new = FALSE; - break; - } - } - - if ((new_interfaces && !is_new) || (!new_interfaces && is_new)) - continue; - iinfo = pyg_lookup_interface_info(itype); if (!iinfo) { gchar *error; @@ -1129,7 +1159,7 @@ pyg_type_add_interfaces(PyTypeObject *class, GType instance_type, int pyg_type_register(PyTypeObject *class, const char *type_name) { - PyObject *gtype, *gsignals, *gproperties, *overridden_signals; + PyObject *gtype; GType parent_type, instance_type; GType *parent_interfaces; guint n_parent_interfaces; @@ -1216,88 +1246,22 @@ pyg_type_register(PyTypeObject *class, const char *type_name) } /* - * Note: Interfaces to be implemented are searched twice. First - * we register interfaces that are already implemented by a parent - * type. The second time, the remaining interfaces are - * registered, i.e. the ones that are not implemented by a parent - * type. In between these two loops, properties and signals are - * registered. It has to be done this way, in two steps, - * otherwise glib will complain. If registering all interfaces - * always before properties, you get an error like: - * - * ../gobject:121: Warning: Object class - * test_interface+MyObject doesn't implement property - * 'some-property' from interface 'TestInterface' - * - * If, on the other hand, you register interfaces after - * registering the properties, you get something like: - * - * ../gobject:121: Warning: cannot add interface type - * `TestInterface' to type `test_interface+MyUnknown', since - * type `test_interface+MyUnknown' already conforms to - * interface - * - * This looks like a GLib quirk, but no bug has been filed - * upstream. However we have a unit test for this particular - * problem, which can be found in test_interfaces.py, class - * TestInterfaceImpl. + * Note, all interfaces need to be registered before the first + * g_type_class_ref(), see bug #686149. * * See also comment above pyg_type_add_interfaces(). */ - pyg_type_add_interfaces(class, instance_type, class->tp_bases, FALSE, + pyg_type_add_interfaces(class, instance_type, class->tp_bases, parent_interfaces, n_parent_interfaces); - /* we look this up in the instance dictionary, so we don't - * accidentally get a parent type's __gsignals__ attribute. */ - gsignals = PyDict_GetItemString(class->tp_dict, "__gsignals__"); - if (gsignals) { - if (!PyDict_Check(gsignals)) { - PyErr_SetString(PyExc_TypeError, - "__gsignals__ attribute not a dict!"); - g_free(parent_interfaces); - return -1; - } - if (!(overridden_signals = add_signals(instance_type, gsignals))) { - g_free(parent_interfaces); - return -1; - } - if (PyDict_SetItemString(class->tp_dict, "__gsignals__", - overridden_signals)) { - g_free(parent_interfaces); - return -1; - } - Py_DECREF(overridden_signals); - } else { - PyErr_Clear(); - } - /* we look this up in the instance dictionary, so we don't - * accidentally get a parent type's __gsignals__ attribute. */ - gproperties = PyDict_GetItemString(class->tp_dict, "__gproperties__"); - if (gproperties) { - if (!PyDict_Check(gproperties)) { - PyErr_SetString(PyExc_TypeError, - "__gproperties__ attribute not a dict!"); - g_free(parent_interfaces); - return -1; - } - if (!add_properties(instance_type, gproperties)) { - g_free(parent_interfaces); - return -1; - } - PyDict_DelItemString(class->tp_dict, "__gproperties__"); - /* Borrowed reference. Py_DECREF(gproperties); */ - } else { - PyErr_Clear(); + gclass = g_type_class_ref(instance_type); + if (PyErr_Occurred() != NULL) { + g_type_class_unref(gclass); + g_free(parent_interfaces); + return -1; } - /* Register new interfaces, that are _not_ already defined by - * the parent type. FIXME: See above. - */ - pyg_type_add_interfaces(class, instance_type, class->tp_bases, TRUE, - parent_interfaces, n_parent_interfaces); - - gclass = g_type_class_ref(instance_type); if (pyg_run_class_init(instance_type, gclass, class)) { g_type_class_unref(gclass); g_free(parent_interfaces); @@ -1306,9 +1270,8 @@ pyg_type_register(PyTypeObject *class, const char *type_name) g_type_class_unref(gclass); g_free(parent_interfaces); - if (gsignals) - PyDict_DelItemString(class->tp_dict, "__gsignals__"); - + if (PyErr_Occurred() != NULL) + return -1; return 0; } -- 1.8.3.2