From 761a71bb8692ba42c26ed5ef872c4209b20bc470 Mon Sep 17 00:00:00 2001 From: DongHun Kwak Date: Wed, 12 Jul 2017 08:37:54 +0900 Subject: Imported Upstream version 3.0.1 Change-Id: I26a0bcadb4a71ef2c031860ee9d617b250d3a6d7 Signed-off-by: DongHun Kwak --- gi/_gobject/gobjectmodule.c | 37 ++++++++++++++----------- gi/_gobject/pygobject-private.h | 3 +++ gi/_gobject/pygobject.c | 27 ++++++++++++++++++- gi/_gobject/pygobject.h | 3 ++- gi/pygi-marshal-from-py.c | 60 ++++++++++++++++++++++++++++++++++++++--- 5 files changed, 109 insertions(+), 21 deletions(-) (limited to 'gi') diff --git a/gi/_gobject/gobjectmodule.c b/gi/_gobject/gobjectmodule.c index ffa323b..ac065a5 100644 --- a/gi/_gobject/gobjectmodule.c +++ b/gi/_gobject/gobjectmodule.c @@ -1048,7 +1048,7 @@ pygobject__g_instance_init(GTypeInstance *instance, gpointer g_class) { GObject *object = (GObject *) instance; - PyObject *wrapper; + PyObject *wrapper, *args, *kwargs; wrapper = g_object_get_qdata(object, pygobject_wrapper_key); if (wrapper == NULL) { @@ -1059,6 +1059,27 @@ pygobject__g_instance_init(GTypeInstance *instance, } } pygobject_init_wrapper_set(NULL); + if (wrapper == NULL) { + /* this looks like a python object created through + * g_object_new -> we have no python wrapper, so create it + * now */ + PyGILState_STATE state; + state = pyglib_gil_state_ensure(); + wrapper = pygobject_new_full(object, FALSE, g_class); + + /* float the wrapper ref here because we are going to orphan it + * so we don't destroy the wrapper. The next call to pygobject_new_full + * will take the ref */ + pygobject_ref_float (wrapper); + args = PyTuple_New(0); + kwargs = PyDict_New(); + if (Py_TYPE(wrapper)->tp_init(wrapper, args, kwargs)) + PyErr_Print(); + + Py_DECREF(args); + Py_DECREF(kwargs); + pyglib_gil_state_release(state); + } } @@ -1730,22 +1751,8 @@ pyg_object_new (PyGObject *self, PyObject *args, PyObject *kwargs) g_type_class_unref(class); if (obj) { - PyObject *empty_args; - PyObject *empty_kwargs; - PyGILState_STATE state; - pygobject_sink (obj); self = (PyGObject *) pygobject_new_full((GObject *)obj, FALSE, NULL); - empty_args = PyTuple_New(0); - empty_kwargs = PyDict_New(); - - state = pyglib_gil_state_ensure(); - if (Py_TYPE(self)->tp_init((PyObject *)self, empty_args, empty_kwargs)) - PyErr_Print(); - pyglib_gil_state_release(state); - - Py_DECREF(empty_args); - Py_DECREF(empty_kwargs); g_object_unref(obj); } else self = NULL; diff --git a/gi/_gobject/pygobject-private.h b/gi/_gobject/pygobject-private.h index dabf0a4..1b1d6db 100644 --- a/gi/_gobject/pygobject-private.h +++ b/gi/_gobject/pygobject-private.h @@ -96,6 +96,9 @@ PyObject *pyg_integer_richcompare(PyObject *v, gboolean pyg_gerror_exception_check(GError **error); +void pygobject_ref_float(PyGObject *self); +void pygobject_ref_sink(PyGObject *self); + /* from pygtype.h */ extern PyTypeObject PyGTypeWrapper_Type; diff --git a/gi/_gobject/pygobject.c b/gi/_gobject/pygobject.c index 48a9f18..0f0e5e2 100644 --- a/gi/_gobject/pygobject.c +++ b/gi/_gobject/pygobject.c @@ -560,6 +560,31 @@ pygobject_switch_to_toggle_ref(PyGObject *self) g_object_unref(self->obj); } +/* Called when an custom gobject is initalized via g_object_new instead of + its constructor. The next time the wrapper is access via + pygobject_new_full it will sink the floating reference instead of + adding a new reference and causing a leak */ + +void +pygobject_ref_float(PyGObject *self) +{ + /* should only be floated once */ + g_assert(!(self->private_flags.flags & PYGOBJECT_IS_FLOATING_REF)); + + self->private_flags.flags |= PYGOBJECT_IS_FLOATING_REF; +} + +/* Called by gobject_new_full, if the floating flag is set remove it, otherwise + ref the pyobject */ +void +pygobject_ref_sink(PyGObject *self) +{ + if (self->private_flags.flags & PYGOBJECT_IS_FLOATING_REF) + self->private_flags.flags &= ~PYGOBJECT_IS_FLOATING_REF; + else + Py_INCREF ( (PyObject *) self); +} + /** * pygobject_register_wrapper: * @self: the wrapper instance @@ -888,7 +913,7 @@ pygobject_new_full(GObject *obj, gboolean sink, gpointer g_class) /* we already have a wrapper for this object -- return it. */ self = (PyGObject *)g_object_get_qdata(obj, pygobject_wrapper_key); if (self != NULL) { - Py_INCREF(self); + pygobject_ref_sink(self); } else { /* create wrapper */ PyGObjectData *inst_data = pyg_object_peek_inst_data(obj); diff --git a/gi/_gobject/pygobject.h b/gi/_gobject/pygobject.h index f728e15..8879fd0 100644 --- a/gi/_gobject/pygobject.h +++ b/gi/_gobject/pygobject.h @@ -23,7 +23,8 @@ struct _PyGClosure { }; typedef enum { - PYGOBJECT_USING_TOGGLE_REF = 1 << 0 + PYGOBJECT_USING_TOGGLE_REF = 1 << 0, + PYGOBJECT_IS_FLOATING_REF = 1 << 1 } PyGObjectFlags; /* closures is just an alias for what is found in the diff --git a/gi/pygi-marshal-from-py.c b/gi/pygi-marshal-from-py.c index fa74a22..b78cfe3 100644 --- a/gi/pygi-marshal-from-py.c +++ b/gi/pygi-marshal-from-py.c @@ -1416,10 +1416,62 @@ gboolean _pygi_marshal_from_py_interface_instance (PyGIInvokeState *state, GType type = iface_cache->g_type; if (!PyObject_IsInstance (py_arg, iface_cache->py_type)) { - PyErr_Format (PyExc_TypeError, "Expected a %s, but got %s", - iface_cache->type_name, - py_arg->ob_type->tp_name); - return FALSE; + /* wait, we might be a member of a union so manually check */ + if (info_type == GI_INFO_TYPE_UNION) { + gint i; + gint n_fields; + gboolean is_member = FALSE; + GIUnionInfo *union_info = (GIUnionInfo *) iface_cache->interface_info; + + n_fields = g_union_info_get_n_fields (union_info); + + for (i = 0; i < n_fields; i++) { + GIFieldInfo *field_info; + GITypeInfo *field_type_info; + + field_info = g_union_info_get_field (union_info, i); + field_type_info = g_field_info_get_type (field_info); + + /* we can only check if the members are interfaces */ + if (g_type_info_get_tag (field_type_info) == + GI_TYPE_TAG_INTERFACE) { + PyObject *py_type; + GIInterfaceInfo *field_iface_info = + g_type_info_get_interface(field_type_info); + + py_type = _pygi_type_import_by_gi_info ( + (GIBaseInfo *) field_iface_info); + + if (PyObject_IsInstance (py_arg, py_type)) { + is_member = TRUE; + break; + } + + Py_XDECREF (py_type); + g_base_info_unref ( ( GIBaseInfo *) field_iface_info); + + } + + g_base_info_unref ( ( GIBaseInfo *) field_type_info); + g_base_info_unref ( ( GIBaseInfo *) field_info); + + if (is_member) + break; + } + + if (!is_member) { + PyErr_Format (PyExc_TypeError, + "Expected a %s, but got %s", + iface_cache->type_name, + py_arg->ob_type->tp_name); + return FALSE; + } + } else { + PyErr_Format (PyExc_TypeError, "Expected a %s, but got %s", + iface_cache->type_name, + py_arg->ob_type->tp_name); + return FALSE; + } } if (g_type_is_a (type, G_TYPE_BOXED)) { -- cgit v1.2.3