summaryrefslogtreecommitdiff
path: root/gi/pygi-marshal-from-py.c
diff options
context:
space:
mode:
Diffstat (limited to 'gi/pygi-marshal-from-py.c')
-rw-r--r--gi/pygi-marshal-from-py.c196
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;
+}