diff options
Diffstat (limited to 'gi/pygi-marshal-from-py.c')
-rw-r--r-- | gi/pygi-marshal-from-py.c | 196 |
1 files changed, 144 insertions, 52 deletions
diff --git a/gi/pygi-marshal-from-py.c b/gi/pygi-marshal-from-py.c index 9f7d874..01138bc 100644 --- a/gi/pygi-marshal-from-py.c +++ b/gi/pygi-marshal-from-py.c @@ -893,7 +893,7 @@ _pygi_marshal_from_py_array (PyGIInvokeState *state, GIArgument *arg) { PyGIMarshalFromPyFunc from_py_marshaller; - int i; + int i = 0; Py_ssize_t length; gssize item_size; gboolean is_ptr_array; @@ -1629,53 +1629,11 @@ _pygi_marshal_from_py_interface_struct (PyGIInvokeState *state, */ if (iface_cache->g_type == G_TYPE_CLOSURE) { - GClosure *closure; - GType object_gtype = pyg_type_from_object_strict (py_arg, FALSE); - - if ( !(PyCallable_Check(py_arg) || - g_type_is_a (object_gtype, G_TYPE_CLOSURE))) { - PyErr_Format (PyExc_TypeError, "Must be callable, not %s", - py_arg->ob_type->tp_name); - return FALSE; - } - - if (g_type_is_a (object_gtype, G_TYPE_CLOSURE)) - closure = (GClosure *)pyg_boxed_get (py_arg, void); - else - closure = pyg_closure_new (py_arg, NULL, NULL); - - if (closure == NULL) { - PyErr_SetString (PyExc_RuntimeError, "PyObject conversion to GClosure failed"); - return FALSE; - } - - arg->v_pointer = closure; - return TRUE; + return pygi_marshal_from_py_gclosure (py_arg, arg); } else if (iface_cache->g_type == G_TYPE_VALUE) { - GValue *value; - GType object_type; - - object_type = pyg_type_from_object_strict ( (PyObject *) py_arg->ob_type, FALSE); - if (object_type == G_TYPE_INVALID) { - PyErr_SetString (PyExc_RuntimeError, "unable to retrieve object's GType"); - return FALSE; - } - - /* if already a gvalue, use that, else marshal into gvalue */ - if (object_type == G_TYPE_VALUE) { - value = (GValue *)( (PyGObject *)py_arg)->obj; - } else { - value = g_slice_new0 (GValue); - g_value_init (value, object_type); - if (pyg_value_from_pyobject (value, py_arg) < 0) { - g_slice_free (GValue, value); - PyErr_SetString (PyExc_RuntimeError, "PyObject conversion to GValue failed"); - return FALSE; - } - } - - arg->v_pointer = value; - return TRUE; + return pygi_marshal_from_py_gvalue(py_arg, arg, + arg_cache->transfer, + arg_cache->is_caller_allocates); } else if (iface_cache->is_foreign) { PyObject *success; success = pygi_struct_foreign_convert_to_g_argument (py_arg, @@ -1760,11 +1718,7 @@ _pygi_marshal_from_py_interface_object (PyGIInvokeState *state, return FALSE; } - arg->v_pointer = pygobject_get(py_arg); - if (arg_cache->transfer == GI_TRANSFER_EVERYTHING) - g_object_ref (arg->v_pointer); - - return TRUE; + return pygi_marshal_from_py_gobject (py_arg, arg, arg_cache->transfer); } gboolean @@ -1855,3 +1809,141 @@ gboolean _pygi_marshal_from_py_interface_instance (PyGIInvokeState *state, return TRUE; } + +/* pygi_marshal_from_py_gobject: + * py_arg: (in): + * arg: (out): + */ +gboolean +pygi_marshal_from_py_gobject (PyObject *py_arg, /*in*/ + GIArgument *arg, /*out*/ + GITransfer transfer) { + GObject *gobj; + + if (py_arg == Py_None) { + arg->v_pointer = NULL; + return TRUE; + } + + gobj = pygobject_get (py_arg); + if (transfer == GI_TRANSFER_EVERYTHING) { + /* An easy case of adding a new ref that the caller will take ownership of. + * Pythons existing ref to the GObject will be managed normally with the wrapper. + */ + g_object_ref (gobj); + + } else if (py_arg->ob_refcnt == 1 && gobj->ref_count == 1) { + /* If both object ref counts are only 1 at this point (the reference held + * in a return tuple), we assume the GObject will be free'd before reaching + * its target and become invalid. So instead of getting invalid object errors + * we add a new GObject ref. + */ + g_object_ref (gobj); + + if (((PyGObject *)py_arg)->private_flags.flags & PYGOBJECT_GOBJECT_WAS_FLOATING) { + /* HACK: + * We want to re-float instances that were floating and the Python + * wrapper assumed ownership. With the additional caveat that there + * are not any strong references beyond the return tuple. + * This should be removed once the following ticket is fixed: + * https://bugzilla.gnome.org/show_bug.cgi?id=693393 + */ + g_object_force_floating (gobj); + + } else { + PyObject *repr = PyObject_Repr (py_arg); + gchar *msg = g_strdup_printf ("Expecting to marshal a borrowed reference for %s, " + "but nothing in Python is holding a reference to this object. " + "See: https://bugzilla.gnome.org/show_bug.cgi?id=687522", + PYGLIB_PyUnicode_AsString(repr)); + Py_DECREF (repr); + if (PyErr_WarnEx (PyExc_RuntimeWarning, msg, 2)) { + g_free (msg); + return FALSE; + } + g_free (msg); + } + } + + arg->v_pointer = gobj; + return TRUE; +} + +/* pygi_marshal_from_py_gvalue: + * py_arg: (in): + * arg: (out): + * transfer: + * is_allocated: TRUE if arg->v_pointer is an already allocated GValue + */ +gboolean +pygi_marshal_from_py_gvalue (PyObject *py_arg, + GIArgument *arg, + GITransfer transfer, + gboolean is_allocated) { + GValue *value; + GType object_type; + + object_type = pyg_type_from_object_strict ( (PyObject *) py_arg->ob_type, FALSE); + if (object_type == G_TYPE_INVALID) { + PyErr_SetString (PyExc_RuntimeError, "unable to retrieve object's GType"); + return FALSE; + } + + if (is_allocated) + value = (GValue *)arg->v_pointer; + else + value = g_slice_new0 (GValue); + + /* if already a gvalue, use that, else marshal into gvalue */ + if (object_type == G_TYPE_VALUE) { + GValue *source_value = pyg_boxed_get (py_arg, GValue); + if (G_VALUE_TYPE (value) == G_TYPE_INVALID) + g_value_init (value, G_VALUE_TYPE (source_value)); + g_value_copy (source_value, value); + } else { + if (G_VALUE_TYPE (value) == G_TYPE_INVALID) + g_value_init (value, object_type); + + if (pyg_value_from_pyobject (value, py_arg) < 0) { + if (!is_allocated) + g_slice_free (GValue, value); + PyErr_SetString (PyExc_RuntimeError, "PyObject conversion to GValue failed"); + return FALSE; + } + } + + arg->v_pointer = value; + return TRUE; +} + +/* pygi_marshal_from_py_gclosure: + * py_arg: (in): + * arg: (out): + */ +gboolean +pygi_marshal_from_py_gclosure(PyObject *py_arg, + GIArgument *arg) +{ + GClosure *closure; + GType object_gtype = pyg_type_from_object_strict (py_arg, FALSE); + + if ( !(PyCallable_Check(py_arg) || + g_type_is_a (object_gtype, G_TYPE_CLOSURE))) { + PyErr_Format (PyExc_TypeError, "Must be callable, not %s", + py_arg->ob_type->tp_name); + return FALSE; + } + + if (g_type_is_a (object_gtype, G_TYPE_CLOSURE)) + closure = (GClosure *)pyg_boxed_get (py_arg, void); + else + closure = pyg_closure_new (py_arg, NULL, NULL); + + if (closure == NULL) { + PyErr_SetString (PyExc_RuntimeError, "PyObject conversion to GClosure failed"); + return FALSE; + } + + arg->v_pointer = closure; + return TRUE; +} |