summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Feltman <sfeltman@src.gnome.org>2013-10-12 16:40:58 -0700
committerSimon Feltman <sfeltman@src.gnome.org>2014-02-02 16:02:57 -0800
commit4dcaa2b988239e01224994098c3e7cbe8b455fe0 (patch)
treeacbe101a5d864a2a60a841c2176348551d246a43
parent2cddba811592fbb990322fbf2dce516ffd7e94cd (diff)
downloadpygobject-4dcaa2b988239e01224994098c3e7cbe8b455fe0.tar.gz
cache refactoring: Move GObject arg setup and marshaling into new file
Move GObject argument cache setup and marshaling fragments into isolated file: pygi-object.c. Break GIInterfaceCache creation and setup into API for interface based argument cache usage. https://bugzilla.gnome.org/show_bug.cgi?id=709700
-rw-r--r--gi/Makefile.am2
-rw-r--r--gi/pygi-argument.c7
-rw-r--r--gi/pygi-cache.c183
-rw-r--r--gi/pygi-cache.h7
-rw-r--r--gi/pygi-marshal-cleanup.c27
-rw-r--r--gi/pygi-marshal-cleanup.h10
-rw-r--r--gi/pygi-marshal-from-py.c123
-rw-r--r--gi/pygi-marshal-from-py.h12
-rw-r--r--gi/pygi-marshal-to-py.c31
-rw-r--r--gi/pygi-marshal-to-py.h8
-rw-r--r--gi/pygi-object.c273
-rw-r--r--gi/pygi-object.h46
12 files changed, 416 insertions, 313 deletions
diff --git a/gi/Makefile.am b/gi/Makefile.am
index d19a19d6..3d153f4d 100644
--- a/gi/Makefile.am
+++ b/gi/Makefile.am
@@ -111,6 +111,8 @@ _gi_la_SOURCES = \
pygi-array.h \
pygi-error.c \
pygi-error.h \
+ pygi-object.c \
+ pygi-object.h \
pygi-hashtable.c \
pygi-hashtable.h
_gi_la_CFLAGS = \
diff --git a/gi/pygi-argument.c b/gi/pygi-argument.c
index c58afa37..4624e0f8 100644
--- a/gi/pygi-argument.c
+++ b/gi/pygi-argument.c
@@ -34,6 +34,7 @@
#include "pygi-marshal-from-py.h"
#include "pygi-marshal-to-py.h"
#include "pygi-basictype.h"
+#include "pygi-object.h"
static gboolean
@@ -1063,7 +1064,7 @@ array_success:
case GI_INFO_TYPE_INTERFACE:
case GI_INFO_TYPE_OBJECT:
/* An error within this call will result in a NULL arg */
- _pygi_marshal_from_py_gobject_out_arg (object, &arg, transfer);
+ pygi_arg_gobject_out_arg_from_py (object, &arg, transfer);
break;
default:
@@ -1436,10 +1437,10 @@ _pygi_argument_to_object (GIArgument *arg,
transfer == GI_TRANSFER_NOTHING &&
g_object_is_floating (arg->v_pointer)) {
g_object_ref (arg->v_pointer);
- object = _pygi_marshal_to_py_object (arg, GI_TRANSFER_EVERYTHING);
+ object = pygi_arg_gobject_to_py (arg, GI_TRANSFER_EVERYTHING);
g_object_force_floating (arg->v_pointer);
} else {
- object = _pygi_marshal_to_py_object (arg, transfer);
+ object = pygi_arg_gobject_to_py (arg, transfer);
}
break;
diff --git a/gi/pygi-cache.c b/gi/pygi-cache.c
index aded0256..f26df8c6 100644
--- a/gi/pygi-cache.c
+++ b/gi/pygi-cache.c
@@ -33,15 +33,7 @@
#include "pygi-array.h"
#include "pygi-closure.h"
#include "pygi-error.h"
-
-
-PyGIArgCache * _arg_cache_new_for_interface (GIInterfaceInfo *iface_info,
- GITypeInfo *type_info,
- GIArgInfo *arg_info,
- GITransfer transfer,
- PyGIDirection direction,
- /* will be removed */
- PyGICallableCache *callable_cache);
+#include "pygi-object.h"
/* _arg_info_default_value
@@ -100,32 +92,6 @@ pygi_arg_base_setup (PyGIArgCache *arg_cache,
return TRUE;
}
-
-gboolean
-pygi_arg_interface_setup (PyGIInterfaceCache *iface_cache,
- GITypeInfo *type_info,
- GIArgInfo *arg_info, /* may be NULL for return arguments */
- GITransfer transfer,
- PyGIDirection direction,
- GIInterfaceInfo *iface_info)
-{
- if (!pygi_arg_base_setup ((PyGIArgCache *)iface_cache,
- type_info,
- arg_info,
- transfer,
- direction)) {
- return FALSE;
- }
-
- g_base_info_ref ( (GIBaseInfo *)iface_info);
- iface_cache->interface_info = iface_info;
- iface_cache->arg_cache.type_tag = GI_TYPE_TAG_INTERFACE;
-
- return TRUE;
-}
-
-
-/* cleanup */
void
_pygi_arg_cache_free (PyGIArgCache *cache)
{
@@ -140,6 +106,26 @@ _pygi_arg_cache_free (PyGIArgCache *cache)
g_slice_free (PyGIArgCache, cache);
}
+void
+_pygi_callable_cache_free (PyGICallableCache *cache)
+{
+ if (cache == NULL)
+ return;
+
+ g_slist_free (cache->to_py_args);
+ g_slist_free (cache->arg_name_list);
+ g_hash_table_destroy (cache->arg_name_hash);
+ g_ptr_array_unref (cache->args_cache);
+
+ if (cache->return_cache != NULL)
+ _pygi_arg_cache_free (cache->return_cache);
+
+ g_slice_free (PyGICallableCache, cache);
+}
+
+
+/* PyGIInterfaceCache */
+
static void
_interface_cache_free_func (PyGIInterfaceCache *cache)
{
@@ -153,50 +139,70 @@ _interface_cache_free_func (PyGIInterfaceCache *cache)
}
}
-
-static void
-_sequence_cache_free_func (PyGISequenceCache *cache)
+gboolean
+pygi_arg_interface_setup (PyGIInterfaceCache *iface_cache,
+ GITypeInfo *type_info,
+ GIArgInfo *arg_info, /* may be NULL for return arguments */
+ GITransfer transfer,
+ PyGIDirection direction,
+ GIInterfaceInfo *iface_info)
{
- if (cache != NULL) {
- _pygi_arg_cache_free (cache->item_cache);
- g_slice_free (PyGISequenceCache, cache);
+ if (!pygi_arg_base_setup ((PyGIArgCache *)iface_cache,
+ type_info,
+ arg_info,
+ transfer,
+ direction)) {
+ return FALSE;
}
-}
-void
-_pygi_callable_cache_free (PyGICallableCache *cache)
-{
- if (cache == NULL)
- return;
+ ( (PyGIArgCache *)iface_cache)->destroy_notify = (GDestroyNotify)_interface_cache_free_func;
- g_slist_free (cache->to_py_args);
- g_slist_free (cache->arg_name_list);
- g_hash_table_destroy (cache->arg_name_hash);
- g_ptr_array_unref (cache->args_cache);
+ g_base_info_ref ( (GIBaseInfo *)iface_info);
+ iface_cache->interface_info = iface_info;
+ iface_cache->arg_cache.type_tag = GI_TYPE_TAG_INTERFACE;
+ iface_cache->type_name = _pygi_g_base_info_get_fullname (iface_info);
+ iface_cache->g_type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *)iface_info);
+ iface_cache->py_type = _pygi_type_import_by_gi_info ( (GIBaseInfo *) iface_info);
- if (cache->return_cache != NULL)
- _pygi_arg_cache_free (cache->return_cache);
+ if (iface_cache->py_type == NULL) {
+ return FALSE;
+ }
- g_slice_free (PyGICallableCache, cache);
+ return TRUE;
}
-/* cache generation */
-
-static PyGIInterfaceCache *
-_interface_cache_new (GIInterfaceInfo *iface_info)
+PyGIArgCache *
+pygi_arg_interface_new_from_info (GITypeInfo *type_info,
+ GIArgInfo *arg_info, /* may be NULL for return arguments */
+ GITransfer transfer,
+ PyGIDirection direction,
+ GIInterfaceInfo *iface_info)
{
PyGIInterfaceCache *ic;
ic = g_slice_new0 (PyGIInterfaceCache);
- ( (PyGIArgCache *)ic)->destroy_notify = (GDestroyNotify)_interface_cache_free_func;
- ic->g_type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *)iface_info);
- ic->py_type = _pygi_type_import_by_gi_info ( (GIBaseInfo *) iface_info);
-
- if (ic->py_type == NULL)
+ if (!pygi_arg_interface_setup (ic,
+ type_info,
+ arg_info,
+ transfer,
+ direction,
+ iface_info)) {
+ _pygi_arg_cache_free ((PyGIArgCache *)ic);
return NULL;
+ }
- ic->type_name = _pygi_g_base_info_get_fullname (iface_info);
- return ic;
+ return (PyGIArgCache *)ic;
+}
+
+/* PyGISequenceCache */
+
+static void
+_sequence_cache_free_func (PyGISequenceCache *cache)
+{
+ if (cache != NULL) {
+ _pygi_arg_cache_free (cache->item_cache);
+ g_slice_free (PyGISequenceCache, cache);
+ }
}
gboolean
@@ -287,22 +293,6 @@ _arg_cache_to_py_interface_struct_setup (PyGIArgCache *arg_cache,
}
static void
-_arg_cache_from_py_interface_object_setup (PyGIArgCache *arg_cache,
- GITransfer transfer)
-{
- arg_cache->from_py_marshaller = _pygi_marshal_from_py_interface_object;
- arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_interface_object;
-}
-
-static void
-_arg_cache_to_py_interface_object_setup (PyGIArgCache *arg_cache,
- GITransfer transfer)
-{
- arg_cache->to_py_marshaller = _pygi_marshal_to_py_interface_object_cache_adapter;
- arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_interface_object;
-}
-
-static void
_arg_cache_from_py_interface_enum_setup (PyGIArgCache *arg_cache,
GITransfer transfer)
{
@@ -331,7 +321,7 @@ _arg_cache_to_py_interface_flags_setup (PyGIArgCache *arg_cache,
}
-PyGIArgCache *
+static PyGIArgCache *
_arg_cache_new_for_interface (GIInterfaceInfo *iface_info,
GITypeInfo *type_info,
GIArgInfo *arg_info,
@@ -354,11 +344,22 @@ _arg_cache_new_for_interface (GIInterfaceInfo *iface_info,
iface_info,
callable_cache);
}
+ case GI_INFO_TYPE_OBJECT:
+ case GI_INFO_TYPE_INTERFACE:
+ return pygi_arg_gobject_new_from_info (type_info,
+ arg_info,
+ transfer,
+ direction,
+ iface_info);
default:
; /* pass through to old model of setup */
}
- arg_cache = (PyGIArgCache *)_interface_cache_new (iface_info);
+ arg_cache = pygi_arg_interface_new_from_info (type_info,
+ arg_info,
+ transfer,
+ direction,
+ iface_info);
if (arg_cache == NULL)
return NULL;
@@ -383,15 +384,6 @@ _arg_cache_new_for_interface (GIInterfaceInfo *iface_info,
iface_info,
transfer);
break;
- case GI_INFO_TYPE_OBJECT:
- case GI_INFO_TYPE_INTERFACE:
- if (direction & PYGI_DIRECTION_FROM_PYTHON)
- _arg_cache_from_py_interface_object_setup (arg_cache, transfer);
-
- if (direction & PYGI_DIRECTION_TO_PYTHON)
- _arg_cache_to_py_interface_object_setup (arg_cache, transfer);
-
- break;
case GI_INFO_TYPE_ENUM:
if (direction & PYGI_DIRECTION_FROM_PYTHON)
_arg_cache_from_py_interface_enum_setup (arg_cache, transfer);
@@ -412,13 +404,6 @@ _arg_cache_new_for_interface (GIInterfaceInfo *iface_info,
g_assert_not_reached ();
}
- pygi_arg_interface_setup ((PyGIInterfaceCache *)arg_cache,
- type_info,
- arg_info,
- transfer,
- direction,
- iface_info);
-
return arg_cache;
}
diff --git a/gi/pygi-cache.h b/gi/pygi-cache.h
index d20cb9f9..3cbe2b60 100644
--- a/gi/pygi-cache.h
+++ b/gi/pygi-cache.h
@@ -214,6 +214,13 @@ pygi_arg_sequence_setup (PyGISequenceCache *sc,
GITransfer transfer,
PyGIDirection direction);
+PyGIArgCache *
+pygi_arg_interface_new_from_info (GITypeInfo *type_info,
+ GIArgInfo *arg_info, /* may be NULL for return arguments */
+ GITransfer transfer,
+ PyGIDirection direction,
+ GIInterfaceInfo *iface_info);
+
PyGIArgCache * _arg_cache_alloc (void);
PyGIArgCache * _arg_cache_new (GITypeInfo *type_info,
GIArgInfo *arg_info,
diff --git a/gi/pygi-marshal-cleanup.c b/gi/pygi-marshal-cleanup.c
index 0376e37b..0bbfab68 100644
--- a/gi/pygi-marshal-cleanup.c
+++ b/gi/pygi-marshal-cleanup.c
@@ -206,33 +206,6 @@ pygi_marshal_cleanup_args_to_py_parameter_fail (PyGIInvokeState *state,
state->failed = TRUE;
}
-void
-_pygi_marshal_cleanup_from_py_interface_object (PyGIInvokeState *state,
- PyGIArgCache *arg_cache,
- PyObject *py_arg,
- gpointer data,
- gboolean was_processed)
-{
- /* If we processed the parameter but fail before invoking the method,
- we need to remove the ref we added */
- if (was_processed && state->failed && data != NULL &&
- arg_cache->transfer == GI_TRANSFER_EVERYTHING)
- g_object_unref (G_OBJECT(data));
-}
-
-void
-_pygi_marshal_cleanup_to_py_interface_object (PyGIInvokeState *state,
- PyGIArgCache *arg_cache,
- PyObject *dummy,
- gpointer data,
- gboolean was_processed)
-{
- /* If we error out and the object is not marshalled into a PyGObject
- we must take care of removing the ref */
- if (!was_processed && arg_cache->transfer == GI_TRANSFER_EVERYTHING)
- g_object_unref (G_OBJECT(data));
-}
-
void
_pygi_marshal_cleanup_from_py_interface_struct_gvalue (PyGIInvokeState *state,
PyGIArgCache *arg_cache,
diff --git a/gi/pygi-marshal-cleanup.h b/gi/pygi-marshal-cleanup.h
index 530f5f31..2463cab1 100644
--- a/gi/pygi-marshal-cleanup.h
+++ b/gi/pygi-marshal-cleanup.h
@@ -55,16 +55,6 @@ void _pygi_marshal_cleanup_to_py_interface_struct_foreign (PyGIInvokeState *stat
PyObject *dummy,
gpointer data,
gboolean was_processed);
-void _pygi_marshal_cleanup_from_py_interface_object (PyGIInvokeState *state,
- PyGIArgCache *arg_cache,
- PyObject *py_arg,
- gpointer data,
- gboolean was_processed);
-void _pygi_marshal_cleanup_to_py_interface_object (PyGIInvokeState *state,
- PyGIArgCache *arg_cache,
- PyObject *dummy,
- gpointer data,
- gboolean was_processed);
G_END_DECLS
#endif /* __PYGI_MARSHAL_CLEANUP_H__ */
diff --git a/gi/pygi-marshal-from-py.c b/gi/pygi-marshal-from-py.c
index 92c89c84..ba798591 100644
--- a/gi/pygi-marshal-from-py.c
+++ b/gi/pygi-marshal-from-py.c
@@ -299,40 +299,6 @@ _pygi_marshal_from_py_interface_boxed (PyGIInvokeState *state,
}
gboolean
-_pygi_marshal_from_py_interface_object (PyGIInvokeState *state,
- PyGICallableCache *callable_cache,
- PyGIArgCache *arg_cache,
- PyObject *py_arg,
- GIArgument *arg,
- gpointer *cleanup_data)
-{
- gboolean res = FALSE;
-
- if (py_arg == Py_None) {
- arg->v_pointer = NULL;
- return TRUE;
- }
-
- if (!PyObject_IsInstance (py_arg, ( (PyGIInterfaceCache *)arg_cache)->py_type)) {
- PyObject *module = PyObject_GetAttrString(py_arg, "__module__");
-
- PyErr_Format (PyExc_TypeError, "argument %s: Expected %s, but got %s%s%s",
- arg_cache->arg_name ? arg_cache->arg_name : "self",
- ( (PyGIInterfaceCache *)arg_cache)->type_name,
- module ? PYGLIB_PyUnicode_AsString(module) : "",
- module ? "." : "",
- py_arg->ob_type->tp_name);
- if (module)
- Py_DECREF (module);
- return FALSE;
- }
-
- res = _pygi_marshal_from_py_gobject (py_arg, arg, arg_cache->transfer);
- *cleanup_data = arg->v_pointer;
- return res;
-}
-
-gboolean
_pygi_marshal_from_py_interface_union (PyGIInvokeState *state,
PyGICallableCache *callable_cache,
PyGIArgCache *arg_cache,
@@ -345,95 +311,6 @@ _pygi_marshal_from_py_interface_union (PyGIInvokeState *state,
return FALSE;
}
-/* _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;
- }
-
- if (!pygobject_check (py_arg, &PyGObject_Type)) {
- PyObject *repr = PyObject_Repr (py_arg);
- PyErr_Format(PyExc_TypeError, "expected GObject but got %s",
- PYGLIB_PyUnicode_AsString (repr));
- Py_DECREF (repr);
- return FALSE;
- }
-
- gobj = pygobject_get (py_arg);
- if (transfer == GI_TRANSFER_EVERYTHING) {
- /* For transfer everything, add a new ref that the callee will take ownership of.
- * Pythons existing ref to the GObject will be managed with the PyGObject wrapper.
- */
- g_object_ref (gobj);
- }
-
- arg->v_pointer = gobj;
- return TRUE;
-}
-
-/* _pygi_marshal_from_py_gobject_out_arg:
- * py_arg: (in):
- * arg: (out):
- *
- * A specialization for marshaling Python GObjects used for out/return values
- * from a Python implemented vfuncs, signals, or an assignment to a GObject property.
- */
-gboolean
-_pygi_marshal_from_py_gobject_out_arg (PyObject *py_arg, /*in*/
- GIArgument *arg, /*out*/
- GITransfer transfer) {
- GObject *gobj;
- if (!_pygi_marshal_from_py_gobject (py_arg, arg, transfer)) {
- return FALSE;
- }
-
- /* HACK: At this point the basic marshaling of the GObject was successful
- * but we add some special case hacks for vfunc returns due to buggy APIs:
- * https://bugzilla.gnome.org/show_bug.cgi?id=693393
- */
- gobj = arg->v_pointer;
- 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) {
- /*
- * 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.
- */
- 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);
- }
- }
-
- return TRUE;
-}
/* _pygi_marshal_from_py_gvalue:
* py_arg: (in):
diff --git a/gi/pygi-marshal-from-py.h b/gi/pygi-marshal-from-py.h
index 0172c197..4b59601e 100644
--- a/gi/pygi-marshal-from-py.h
+++ b/gi/pygi-marshal-from-py.h
@@ -57,12 +57,6 @@ gboolean _pygi_marshal_from_py_interface_boxed (PyGIInvokeState *state,
PyObject *py_arg,
GIArgument *arg,
gpointer *cleanup_data);
-gboolean _pygi_marshal_from_py_interface_object (PyGIInvokeState *state,
- PyGICallableCache *callable_cache,
- PyGIArgCache *arg_cache,
- PyObject *py_arg,
- GIArgument *arg,
- gpointer *cleanup_data);
gboolean _pygi_marshal_from_py_interface_union (PyGIInvokeState *state,
PyGICallableCache *callable_cache,
PyGIArgCache *arg_cache,
@@ -71,12 +65,6 @@ gboolean _pygi_marshal_from_py_interface_union (PyGIInvokeState *state,
gpointer *cleanup_data);
/* Simplified marshalers shared between vfunc/closure and direct function calls. */
-gboolean _pygi_marshal_from_py_gobject (PyObject *py_arg, /*in*/
- GIArgument *arg, /*out*/
- GITransfer transfer);
-gboolean _pygi_marshal_from_py_gobject_out_arg (PyObject *py_arg, /*in*/
- GIArgument *arg, /*out*/
- GITransfer transfer);
gboolean _pygi_marshal_from_py_gvalue (PyObject *py_arg, /*in*/
GIArgument *arg, /*out*/
diff --git a/gi/pygi-marshal-to-py.c b/gi/pygi-marshal-to-py.c
index 69a7c1ae..536193c5 100644
--- a/gi/pygi-marshal-to-py.c
+++ b/gi/pygi-marshal-to-py.c
@@ -194,15 +194,6 @@ _pygi_marshal_to_py_interface_boxed (PyGIInvokeState *state,
}
PyObject *
-_pygi_marshal_to_py_interface_object_cache_adapter (PyGIInvokeState *state,
- PyGICallableCache *callable_cache,
- PyGIArgCache *arg_cache,
- GIArgument *arg)
-{
- return _pygi_marshal_to_py_object(arg, arg_cache->transfer);
-}
-
-PyObject *
_pygi_marshal_to_py_interface_union (PyGIInvokeState *state,
PyGICallableCache *callable_cache,
PyGIArgCache *arg_cache,
@@ -216,28 +207,6 @@ _pygi_marshal_to_py_interface_union (PyGIInvokeState *state,
}
PyObject *
-_pygi_marshal_to_py_object (GIArgument *arg, GITransfer transfer) {
- PyObject *pyobj;
-
- if (arg->v_pointer == NULL) {
- pyobj = Py_None;
- Py_INCREF (pyobj);
-
- } else if (G_IS_PARAM_SPEC(arg->v_pointer)) {
- pyobj = pyg_param_spec_new (arg->v_pointer);
- if (transfer == GI_TRANSFER_EVERYTHING)
- g_param_spec_unref (arg->v_pointer);
-
- } else {
- pyobj = pygobject_new_full (arg->v_pointer,
- /*steal=*/ transfer == GI_TRANSFER_EVERYTHING,
- /*type=*/ NULL);
- }
-
- return pyobj;
-}
-
-PyObject *
_pygi_marshal_to_py_interface_struct (GIArgument *arg,
GIInterfaceInfo *interface_info,
GType g_type,
diff --git a/gi/pygi-marshal-to-py.h b/gi/pygi-marshal-to-py.h
index de8f85b7..aa845031 100644
--- a/gi/pygi-marshal-to-py.h
+++ b/gi/pygi-marshal-to-py.h
@@ -42,20 +42,12 @@ PyObject *_pygi_marshal_to_py_interface_boxed (PyGIInvokeState *state,
PyGICallableCache *callable_cache,
PyGIArgCache *arg_cache,
GIArgument *arg);
-PyObject *_pygi_marshal_to_py_interface_object_cache_adapter (PyGIInvokeState *state,
- PyGICallableCache *callable_cache,
- PyGIArgCache *arg_cache,
- GIArgument *arg);
PyObject *_pygi_marshal_to_py_interface_union (PyGIInvokeState *state,
PyGICallableCache *callable_cache,
PyGIArgCache *arg_cache,
GIArgument *arg);
/* Simplified marshalers shared between vfunc/closure and direct function calls. */
-
-PyObject *_pygi_marshal_to_py_object (GIArgument *arg,
- GITransfer transfer);
-
PyObject *_pygi_marshal_to_py_interface_struct (GIArgument *arg,
GIInterfaceInfo *interface_info,
GType g_type,
diff --git a/gi/pygi-object.c b/gi/pygi-object.c
new file mode 100644
index 00000000..4ad58b1b
--- /dev/null
+++ b/gi/pygi-object.c
@@ -0,0 +1,273 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ *
+ * Copyright (C) 2011 John (J5) Palmieri <johnp@redhat.com>
+ * Copyright (C) 2014 Simon Feltman <sfeltman@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <Python.h>
+#include <pyglib-python-compat.h>
+
+#include "pygi-arg-gobject.h"
+#include "pygi-private.h"
+#include "pygparamspec.h"
+
+/*
+ * GObject from Python
+ */
+
+/* _pygi_marshal_from_py_gobject:
+ * py_arg: (in):
+ * arg: (out):
+ */
+static 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;
+ }
+
+ if (!pygobject_check (py_arg, &PyGObject_Type)) {
+ PyObject *repr = PyObject_Repr (py_arg);
+ PyErr_Format(PyExc_TypeError, "expected GObject but got %s",
+ PYGLIB_PyUnicode_AsString (repr));
+ Py_DECREF (repr);
+ return FALSE;
+ }
+
+ gobj = pygobject_get (py_arg);
+ if (transfer == GI_TRANSFER_EVERYTHING) {
+ /* For transfer everything, add a new ref that the callee will take ownership of.
+ * Pythons existing ref to the GObject will be managed with the PyGObject wrapper.
+ */
+ g_object_ref (gobj);
+ }
+
+ arg->v_pointer = gobj;
+ return TRUE;
+}
+
+/* pygi_arg_gobject_out_arg_from_py:
+ * py_arg: (in):
+ * arg: (out):
+ *
+ * A specialization for marshaling Python GObjects used for out/return values
+ * from a Python implemented vfuncs, signals, or an assignment to a GObject property.
+ */
+gboolean
+pygi_arg_gobject_out_arg_from_py (PyObject *py_arg, /*in*/
+ GIArgument *arg, /*out*/
+ GITransfer transfer) {
+ GObject *gobj;
+ if (!_pygi_marshal_from_py_gobject (py_arg, arg, transfer)) {
+ return FALSE;
+ }
+
+ /* HACK: At this point the basic marshaling of the GObject was successful
+ * but we add some special case hacks for vfunc returns due to buggy APIs:
+ * https://bugzilla.gnome.org/show_bug.cgi?id=693393
+ */
+ gobj = arg->v_pointer;
+ 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) {
+ /*
+ * 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.
+ */
+ 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);
+ }
+ }
+
+ return TRUE;
+}
+
+static gboolean
+_pygi_marshal_from_py_interface_object (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg,
+ gpointer *cleanup_data)
+{
+ gboolean res = FALSE;
+
+ if (py_arg == Py_None) {
+ arg->v_pointer = NULL;
+ return TRUE;
+ }
+
+ if (!PyObject_IsInstance (py_arg, ( (PyGIInterfaceCache *)arg_cache)->py_type)) {
+ PyObject *module = PyObject_GetAttrString(py_arg, "__module__");
+
+ PyErr_Format (PyExc_TypeError, "argument %s: Expected %s, but got %s%s%s",
+ arg_cache->arg_name ? arg_cache->arg_name : "self",
+ ( (PyGIInterfaceCache *)arg_cache)->type_name,
+ module ? PYGLIB_PyUnicode_AsString(module) : "",
+ module ? "." : "",
+ py_arg->ob_type->tp_name);
+ if (module)
+ Py_DECREF (module);
+ return FALSE;
+ }
+
+ res = _pygi_marshal_from_py_gobject (py_arg, arg, arg_cache->transfer);
+ *cleanup_data = arg->v_pointer;
+ return res;
+}
+
+static void
+_pygi_marshal_cleanup_from_py_interface_object (PyGIInvokeState *state,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ gpointer data,
+ gboolean was_processed)
+{
+ /* If we processed the parameter but fail before invoking the method,
+ we need to remove the ref we added */
+ if (was_processed && state->failed && data != NULL &&
+ arg_cache->transfer == GI_TRANSFER_EVERYTHING)
+ g_object_unref (G_OBJECT(data));
+}
+
+
+/*
+ * GObject to Python
+ */
+
+PyObject *
+pygi_arg_gobject_to_py (GIArgument *arg, GITransfer transfer) {
+ PyObject *pyobj;
+
+ if (arg->v_pointer == NULL) {
+ pyobj = Py_None;
+ Py_INCREF (pyobj);
+
+ } else if (G_IS_PARAM_SPEC(arg->v_pointer)) {
+ pyobj = pyg_param_spec_new (arg->v_pointer);
+ if (transfer == GI_TRANSFER_EVERYTHING)
+ g_param_spec_unref (arg->v_pointer);
+
+ } else {
+ pyobj = pygobject_new_full (arg->v_pointer,
+ /*steal=*/ transfer == GI_TRANSFER_EVERYTHING,
+ /*type=*/ NULL);
+ }
+
+ return pyobj;
+}
+
+static PyObject *
+_pygi_marshal_to_py_interface_object_cache_adapter (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg)
+{
+ return pygi_arg_gobject_to_py(arg, arg_cache->transfer);
+}
+
+static void
+_pygi_marshal_cleanup_to_py_interface_object (PyGIInvokeState *state,
+ PyGIArgCache *arg_cache,
+ PyObject *dummy,
+ gpointer data,
+ gboolean was_processed)
+{
+ /* If we error out and the object is not marshalled into a PyGObject
+ we must take care of removing the ref */
+ if (!was_processed && arg_cache->transfer == GI_TRANSFER_EVERYTHING)
+ g_object_unref (G_OBJECT(data));
+}
+
+static gboolean
+pygi_arg_gobject_setup_from_info (PyGIArgCache *arg_cache,
+ GITypeInfo *type_info,
+ GIArgInfo *arg_info,
+ GITransfer transfer,
+ PyGIDirection direction)
+{
+ /* NOTE: usage of pygi_arg_interface_new_from_info already calls
+ * pygi_arg_interface_setup so no need to do it here.
+ */
+
+ if (direction & PYGI_DIRECTION_FROM_PYTHON) {
+ arg_cache->from_py_marshaller = _pygi_marshal_from_py_interface_object;
+ arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_interface_object;
+ }
+
+ if (direction & PYGI_DIRECTION_TO_PYTHON) {
+ arg_cache->to_py_marshaller = _pygi_marshal_to_py_interface_object_cache_adapter;
+ arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_interface_object;
+ }
+
+ return TRUE;
+}
+
+PyGIArgCache *
+pygi_arg_gobject_new_from_info (GITypeInfo *type_info,
+ GIArgInfo *arg_info,
+ GITransfer transfer,
+ PyGIDirection direction,
+ GIInterfaceInfo *iface_info)
+{
+ gboolean res = FALSE;
+ PyGIArgCache *cache = NULL;
+
+ cache = pygi_arg_interface_new_from_info (type_info,
+ arg_info,
+ transfer,
+ direction,
+ iface_info);
+ if (cache == NULL)
+ return NULL;
+
+ res = pygi_arg_gobject_setup_from_info (cache,
+ type_info,
+ arg_info,
+ transfer,
+ direction);
+ if (res) {
+ return cache;
+ } else {
+ _pygi_arg_cache_free (cache);
+ return NULL;
+ }
+}
diff --git a/gi/pygi-object.h b/gi/pygi-object.h
new file mode 100644
index 00000000..4a8800e3
--- /dev/null
+++ b/gi/pygi-object.h
@@ -0,0 +1,46 @@
+/* -*- Mode: C; c-basic-offset: 4 -*-
+ * vim: tabstop=4 shiftwidth=4 expandtab
+ *
+ * Copyright (C) 2014 Simon Feltman <sfeltman@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __PYGI_OBJECT_H__
+#define __PYGI_OBJECT_H__
+
+#include <girepository.h>
+#include "pygi-cache.h"
+
+G_BEGIN_DECLS
+
+gboolean
+pygi_arg_gobject_out_arg_from_py (PyObject *py_arg, /* in */
+ GIArgument *arg, /* out */
+ GITransfer transfer);
+
+PyObject *
+pygi_arg_gobject_to_py (GIArgument *arg,
+ GITransfer transfer);
+
+PyGIArgCache *
+pygi_arg_gobject_new_from_info (GITypeInfo *type_info,
+ GIArgInfo *arg_info, /* may be null */
+ GITransfer transfer,
+ PyGIDirection direction,
+ GIInterfaceInfo *iface_info);
+
+G_END_DECLS
+
+#endif /*__PYGI_OBJECT_H__*/