summaryrefslogtreecommitdiff
path: root/gi
diff options
context:
space:
mode:
Diffstat (limited to 'gi')
-rw-r--r--gi/pygi-array.c5
-rw-r--r--gi/pygi-basictype.c4
-rw-r--r--gi/pygi-basictype.h36
-rw-r--r--gi/pygi-cache.c30
-rw-r--r--gi/pygi-closure.c403
-rw-r--r--gi/pygi-invoke.c3
6 files changed, 271 insertions, 210 deletions
diff --git a/gi/pygi-array.c b/gi/pygi-array.c
index 1db04eea..4cfbd172 100644
--- a/gi/pygi-array.c
+++ b/gi/pygi-array.c
@@ -25,6 +25,7 @@
#include "pygi-array.h"
#include "pygi-private.h"
#include "pygi-marshal-cleanup.h"
+#include "pygi-basictype.h"
/* Needed for _pygi_marshal_cleanup_from_py_interface_struct_gvalue hack */
#include "pygi-struct-marshal.h"
@@ -800,8 +801,8 @@ pygi_arg_garray_len_arg_setup (PyGIArgCache *arg_cache,
child_cache->meta_type = PYGI_META_ARG_TYPE_CHILD;
child_cache->direction = direction;
- child_cache->to_py_marshaller = NULL;
- child_cache->from_py_marshaller = NULL;
+ child_cache->to_py_marshaller = _pygi_marshal_to_py_basic_type_cache_adapter;
+ child_cache->from_py_marshaller = _pygi_marshal_from_py_basic_type_cache_adapter;
/* ugly edge case code:
*
diff --git a/gi/pygi-basictype.c b/gi/pygi-basictype.c
index ab4d6321..e199741e 100644
--- a/gi/pygi-basictype.c
+++ b/gi/pygi-basictype.c
@@ -507,7 +507,7 @@ _pygi_marshal_from_py_basic_type (PyObject *object, /* in */
return TRUE;
}
-static gboolean
+gboolean
_pygi_marshal_from_py_basic_type_cache_adapter (PyGIInvokeState *state,
PyGICallableCache *callable_cache,
PyGIArgCache *arg_cache,
@@ -705,7 +705,7 @@ _pygi_marshal_to_py_basic_type (GIArgument *arg,
return NULL;
}
-static PyObject *
+PyObject *
_pygi_marshal_to_py_basic_type_cache_adapter (PyGIInvokeState *state,
PyGICallableCache *callable_cache,
PyGIArgCache *arg_cache,
diff --git a/gi/pygi-basictype.h b/gi/pygi-basictype.h
index 7207e542..466c7d4a 100644
--- a/gi/pygi-basictype.h
+++ b/gi/pygi-basictype.h
@@ -25,18 +25,30 @@
G_BEGIN_DECLS
-gboolean _pygi_marshal_from_py_basic_type (PyObject *object, /* in */
- GIArgument *arg, /* out */
- GITypeTag type_tag,
- GITransfer transfer,
- gpointer *cleanup_data);
-PyObject *_pygi_marshal_to_py_basic_type (GIArgument *arg, /* in */
- GITypeTag type_tag,
- GITransfer transfer);
-PyGIArgCache *pygi_arg_basic_type_new_from_info (GITypeInfo *type_info,
- GIArgInfo *arg_info, /* may be null */
- GITransfer transfer,
- PyGIDirection direction);
+gboolean _pygi_marshal_from_py_basic_type (PyObject *object, /* in */
+ GIArgument *arg, /* out */
+ GITypeTag type_tag,
+ GITransfer transfer,
+ gpointer *cleanup_data);
+gboolean _pygi_marshal_from_py_basic_type_cache_adapter (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ PyObject *py_arg,
+ GIArgument *arg,
+ gpointer *cleanup_data);
+
+PyObject *_pygi_marshal_to_py_basic_type (GIArgument *arg, /* in */
+ GITypeTag type_tag,
+ GITransfer transfer);
+PyObject *_pygi_marshal_to_py_basic_type_cache_adapter (PyGIInvokeState *state,
+ PyGICallableCache *callable_cache,
+ PyGIArgCache *arg_cache,
+ GIArgument *arg);
+
+PyGIArgCache *pygi_arg_basic_type_new_from_info (GITypeInfo *type_info,
+ GIArgInfo *arg_info, /* may be null */
+ GITransfer transfer,
+ PyGIDirection direction);
G_END_DECLS
#endif /*__PYGI_ARG_BASICTYPE_H__*/
diff --git a/gi/pygi-cache.c b/gi/pygi-cache.c
index 8d1d7127..16828902 100644
--- a/gi/pygi-cache.c
+++ b/gi/pygi-cache.c
@@ -574,12 +574,7 @@ _callable_cache_generate_args_cache_real (PyGICallableCache *callable_cache,
_pygi_callable_cache_set_arg (callable_cache, arg_index, arg_cache);
}
- /* TODO: Remove once pygi-closure.c doesn't need the type info */
- if (arg_cache->type_info == NULL) {
- arg_cache->type_info = type_info;
- } else {
- g_base_info_unref (type_info);
- }
+ g_base_info_unref (type_info);
}
/* Ensure arguments always have a name when available */
@@ -1058,6 +1053,7 @@ pygi_vfunc_cache_new (GICallableInfo *info)
PyGIClosureCache *
pygi_closure_cache_new (GICallableInfo *info)
{
+ gssize i;
PyGIClosureCache *closure_cache;
PyGICallableCache *callable_cache;
@@ -1071,6 +1067,28 @@ pygi_closure_cache_new (GICallableInfo *info)
return NULL;
}
+ /* For backwards compatibility closures include the array's length.
+ *
+ * See: https://bugzilla.gnome.org/show_bug.cgi?id=652115
+ */
+ for (i = 0; i < _pygi_callable_cache_args_len (callable_cache); i++) {
+ PyGIArgCache *arg_cache;
+ PyGIArgGArray *garray_cache;
+ PyGIArgCache *len_arg_cache;
+
+ arg_cache = g_ptr_array_index (callable_cache->args_cache, i);
+ if (arg_cache->type_tag != GI_TYPE_TAG_ARRAY)
+ continue;
+
+ garray_cache = (PyGIArgGArray *) arg_cache;
+ if (garray_cache->len_arg_index == -1)
+ continue;
+
+ len_arg_cache = g_ptr_array_index (callable_cache->args_cache,
+ garray_cache->len_arg_index);
+ len_arg_cache->meta_type = PYGI_META_ARG_TYPE_PARENT;
+ }
+
return closure_cache;
}
diff --git a/gi/pygi-closure.c b/gi/pygi-closure.c
index 47696f06..3b642a1e 100644
--- a/gi/pygi-closure.c
+++ b/gi/pygi-closure.c
@@ -19,6 +19,7 @@
#include "pygi-private.h"
#include "pygi-closure.h"
+#include "pygi-marshal-cleanup.h"
typedef struct _PyGICallbackCache
@@ -297,57 +298,101 @@ _pygi_closure_convert_ffi_arguments (PyGICallableCache *cache, void **args)
}
static gboolean
-_pygi_closure_convert_arguments (PyGIClosureCache *closure_cache,
- GICallableInfo *callable_info, void **args,
- void *user_data, PyObject **py_args,
- GIArgument **out_args)
+_invoke_state_init_from_cache (PyGIInvokeState *state,
+ PyGIClosureCache *closure_cache,
+ void **args)
+{
+ PyGICallableCache *cache = (PyGICallableCache *) closure_cache;
+
+ state->n_args = _pygi_callable_cache_args_len (cache);
+
+ state->py_in_args = PyTuple_New (state->n_args);
+ if (state->py_in_args == NULL) {
+ PyErr_NoMemory ();
+ return FALSE;
+ }
+ state->n_py_in_args = state->n_args;
+
+ if (cache->throws) {
+ state->n_args++;
+ }
+
+ state->args = NULL;
+
+ state->args_cleanup_data = g_slice_alloc0 (state->n_args * sizeof (gpointer));
+ if (state->args_cleanup_data == NULL && state->n_args != 0) {
+ PyErr_NoMemory();
+ return FALSE;
+ }
+
+ state->arg_values = _pygi_closure_convert_ffi_arguments (cache, args);
+ if (state->arg_values == NULL && state->n_args != 0) {
+ PyErr_NoMemory ();
+ return FALSE;
+ }
+
+ state->arg_pointers = g_slice_alloc0 (state->n_args * sizeof(GIArgument));
+ if (state->arg_pointers == NULL && state->n_args != 0) {
+ PyErr_NoMemory ();
+ return FALSE;
+ }
+
+ state->error = NULL;
+
+ if (cache->throws) {
+ gssize error_index = state->n_args - 1;
+
+ state->arg_pointers[error_index].v_pointer = &state->error;
+ state->arg_values[error_index].v_pointer = state->error;
+ }
+
+ return TRUE;
+}
+
+static void
+_invoke_state_clear (PyGIInvokeState *state)
+{
+ g_slice_free1 (state->n_args * sizeof(gpointer), state->args_cleanup_data);
+ g_free (state->arg_values);
+ g_slice_free1 (state->n_args * sizeof(GIArgument), state->arg_pointers);
+
+ Py_XDECREF (state->py_in_args);
+}
+
+static gboolean
+_pygi_closure_convert_arguments (PyGIInvokeState *state,
+ PyGIClosureCache *closure_cache)
{
PyGICallableCache *cache = (PyGICallableCache *) closure_cache;
- gssize n_args;
gssize n_in_args = 0;
- gssize n_out_args = 0;
gssize i;
- gssize user_data_arg = -1;
- gssize destroy_notify_arg = -1;
- GIArgument *g_args = NULL;
- n_args = _pygi_callable_cache_args_len (cache);
-
- *py_args = NULL;
- *py_args = PyTuple_New (n_args);
- if (*py_args == NULL)
- goto error;
+ /* Must set all the arg_pointers and update the arg_values before
+ * marshaling otherwise out args wouldn't have the correct values.
+ */
+ for (i = 0; i < _pygi_callable_cache_args_len (cache); i++) {
+ PyGIArgCache *arg_cache = g_ptr_array_index (cache->args_cache, i);
- *out_args = NULL;
- *out_args = g_new0 (GIArgument, n_args);
- g_args = _pygi_closure_convert_ffi_arguments (cache, args);
+ if (arg_cache->direction & PYGI_DIRECTION_FROM_PYTHON) {
+ state->arg_pointers[i].v_pointer = state->arg_values[i].v_pointer;
+ state->arg_values[i] = *(GIArgument *) state->arg_values[i].v_pointer;
+ }
+ }
- for (i = 0; i < n_args; i++) {
- PyGIDirection direction;
+ for (i = 0; i < _pygi_callable_cache_args_len (cache); i++) {
PyGIArgCache *arg_cache;
-
- /* Special case callbacks and skip over userdata and Destroy Notify */
- if (i == user_data_arg || i == destroy_notify_arg)
- continue;
+ PyGIDirection direction;
arg_cache = g_ptr_array_index (cache->args_cache, i);
direction = arg_cache->direction;
if (direction & PYGI_DIRECTION_TO_PYTHON) {
- GITypeTag arg_tag;
- GITransfer transfer;
PyObject *value;
- GIArgument *arg;
- gboolean free_array;
-
- arg_tag = arg_cache->type_tag;
- transfer = arg_cache->transfer;
- free_array = FALSE;
- if (direction == PYGI_DIRECTION_TO_PYTHON && arg_tag == GI_TYPE_TAG_VOID &&
+ if (direction == PYGI_DIRECTION_TO_PYTHON &&
+ arg_cache->type_tag == GI_TYPE_TAG_VOID &&
arg_cache->is_pointer) {
-
- if (user_data == NULL) {
+ if (state->user_data == NULL) {
/* user_data can be NULL for connect functions which don't accept
* user_data or as the default for user_data in the middle of function
* arguments.
@@ -357,120 +402,63 @@ _pygi_closure_convert_arguments (PyGIClosureCache *closure_cache,
} else {
/* Extend the callbacks args with user_data as variable args. */
gssize j, user_data_len;
- PyObject *py_user_data = user_data;
+ PyObject *py_user_data = state->user_data;
if (!PyTuple_Check (py_user_data)) {
PyErr_SetString (PyExc_TypeError, "expected tuple for callback user_data");
- goto error;
+ return FALSE;
}
user_data_len = PyTuple_Size (py_user_data);
- _PyTuple_Resize (py_args, n_args + user_data_len - 1);
+ _PyTuple_Resize (&state->py_in_args,
+ state->n_py_in_args + user_data_len - 1);
+
for (j = 0; j < user_data_len; j++, n_in_args++) {
value = PyTuple_GetItem (py_user_data, j);
Py_INCREF (value);
- PyTuple_SET_ITEM (*py_args, n_in_args, value);
+ PyTuple_SET_ITEM (state->py_in_args, n_in_args, value);
}
/* We can assume user_data args are never going to be inout,
* so just continue here.
*/
continue;
}
- } else if (direction == PYGI_DIRECTION_TO_PYTHON &&
- arg_tag == GI_TYPE_TAG_INTERFACE) {
- /* Handle callbacks as a special case */
- GIBaseInfo *info;
- GIInfoType info_type;
-
- info = ((PyGIInterfaceCache *) arg_cache)->interface_info;
- info_type = g_base_info_get_type (info);
-
- arg = (GIArgument*) &g_args[i];
-
- if (info_type == GI_INFO_TYPE_CALLBACK) {
- PyGICallbackCache *arg_callback_cache = (PyGICallbackCache *) arg_cache;
- gpointer user_data = NULL;
- GDestroyNotify destroy_notify = NULL;
- GIScopeType scope;
-
- scope = arg_callback_cache->scope;
- user_data_arg = arg_callback_cache->user_data_index;
- destroy_notify_arg = arg_callback_cache->destroy_notify_index;
-
- if (user_data_arg != -1)
- user_data = g_args[user_data_arg].v_pointer;
-
- if (destroy_notify_arg != -1)
- destroy_notify = (GDestroyNotify) g_args[destroy_notify_arg].v_pointer;
-
- value = _pygi_ccallback_new(arg->v_pointer,
- user_data,
- scope,
- (GIFunctionInfo *) info,
- destroy_notify);
- } else {
- value = _pygi_argument_to_object (arg, arg_cache->type_info, transfer);
- }
-
- if (value == NULL)
- goto error;
+ } else if (arg_cache->meta_type != PYGI_META_ARG_TYPE_PARENT) {
+ continue;
} else {
- if (direction == PYGI_DIRECTION_TO_PYTHON)
- arg = (GIArgument*) &g_args[i];
- else
- arg = (GIArgument*) g_args[i].v_pointer;
-
- if (arg_tag == GI_TYPE_TAG_ARRAY)
- arg->v_pointer = _pygi_argument_to_array (arg, (GIArgument **) args,
- NULL, callable_info,
- arg_cache->type_info, &free_array);
-
- value = _pygi_argument_to_object (arg, arg_cache->type_info, transfer);
-
- if (free_array)
- g_array_free (arg->v_pointer, FALSE);
-
- if (value == NULL)
- goto error;
+ value = arg_cache->to_py_marshaller (state,
+ cache,
+ arg_cache,
+ &state->arg_values[i]);
+
+ if (value == NULL) {
+ pygi_marshal_cleanup_args_to_py_parameter_fail (state,
+ cache,
+ i);
+ return FALSE;
+ }
}
- PyTuple_SET_ITEM (*py_args, n_in_args, value);
- n_in_args++;
- }
- if (direction & PYGI_DIRECTION_FROM_PYTHON) {
- (*out_args) [n_out_args] = g_args[i];
- n_out_args++;
+ PyTuple_SET_ITEM (state->py_in_args, n_in_args, value);
+ n_in_args++;
}
}
- if (_PyTuple_Resize (py_args, n_in_args) == -1)
- goto error;
+ if (_PyTuple_Resize (&state->py_in_args, n_in_args) == -1)
+ return FALSE;
- g_free (g_args);
return TRUE;
-
-error:
- Py_CLEAR (*py_args);
- g_free (*out_args);
- *out_args = NULL;
- g_free (g_args);
-
- return FALSE;
}
-static void
-_pygi_closure_set_out_arguments (PyGICallableCache *cache,
- GICallableInfo *callable_info,
- PyObject *py_retval, GIArgument *out_args,
+static gboolean
+_pygi_closure_set_out_arguments (PyGIInvokeState *state,
+ PyGICallableCache *cache,
+ PyObject *py_retval,
void *resp)
{
- gssize n_args;
gssize i;
gssize i_py_retval = 0;
- gssize i_out_args = 0;
- GIArgument arg;
-
- n_args = _pygi_callable_cache_args_len (cache);
+ gboolean success;
if (cache->return_cache->type_tag != GI_TYPE_TAG_VOID) {
PyObject *item = py_retval;
@@ -479,15 +467,25 @@ _pygi_closure_set_out_arguments (PyGICallableCache *cache,
item = PyTuple_GET_ITEM (py_retval, 0);
}
- arg = _pygi_argument_from_object (item,
- cache->return_cache->type_info,
- cache->return_cache->transfer);
- _pygi_closure_assign_pyobj_to_retval (resp, &arg,
+ success = cache->return_cache->from_py_marshaller (state,
+ cache,
+ cache->return_cache,
+ item,
+ &state->return_arg,
+ &state->args_cleanup_data[0]);
+
+ if (!success) {
+ pygi_marshal_cleanup_args_return_fail (state,
+ cache);
+ return FALSE;
+ }
+
+ _pygi_closure_assign_pyobj_to_retval (resp, &state->return_arg,
cache->return_cache);
i_py_retval++;
}
- for (i = 0; i < n_args; i++) {
+ for (i = 0; i < _pygi_callable_cache_args_len (cache); i++) {
PyGIArgCache *arg_cache = g_ptr_array_index (cache->args_cache, i);
if (arg_cache->direction & PYGI_DIRECTION_FROM_PYTHON) {
@@ -495,27 +493,41 @@ _pygi_closure_set_out_arguments (PyGICallableCache *cache,
if (arg_cache->type_tag == GI_TYPE_TAG_ERROR) {
/* TODO: check if an exception has been set and convert it to a GError */
- out_args[i_out_args].v_pointer = NULL;
- i_out_args++;
+ * (GError **) state->arg_pointers[i].v_pointer = NULL;
continue;
}
if (PyTuple_Check (py_retval)) {
item = PyTuple_GET_ITEM (py_retval, i_py_retval);
} else if (i_py_retval != 0) {
- g_assert_not_reached ();
+ pygi_marshal_cleanup_args_to_py_parameter_fail (state,
+ cache,
+ i_py_retval);
+ return FALSE;
}
- arg = _pygi_argument_from_object (item,
- arg_cache->type_info,
- arg_cache->transfer);
- _pygi_closure_assign_pyobj_to_out_argument (out_args[i_out_args].v_pointer,
- &arg, arg_cache);
+ success = arg_cache->from_py_marshaller (state,
+ cache,
+ arg_cache,
+ item,
+ &state->arg_values[i],
+ &state->args_cleanup_data[i_py_retval]);
+
+ if (!success) {
+ pygi_marshal_cleanup_args_to_py_parameter_fail (state,
+ cache,
+ i_py_retval);
+ return FALSE;
+ }
+
+ _pygi_closure_assign_pyobj_to_out_argument (state->arg_pointers[i].v_pointer,
+ &state->arg_values[i], arg_cache);
- i_out_args++;
i_py_retval++;
}
}
+
+ return TRUE;
}
static void
@@ -535,15 +547,15 @@ _pygi_closure_handle (ffi_cif *cif,
void **args,
void *data)
{
- PyGILState_STATE state;
+ PyGILState_STATE py_state;
PyGICClosure *closure = data;
PyObject *retval;
- PyObject *py_args;
- GIArgument *out_args = NULL;
+ gboolean success;
+ PyGIInvokeState state = { 0, };
/* Lock the GIL as we are coming into this code without the lock and we
may be executing python code */
- state = PyGILState_Ensure();
+ py_state = PyGILState_Ensure ();
if (closure->cache == NULL) {
closure->cache = pygi_closure_cache_new ((GICallableInfo *) closure->info);
@@ -552,34 +564,38 @@ _pygi_closure_handle (ffi_cif *cif,
goto end;
}
- if (!_pygi_closure_convert_arguments (closure->cache,
- (GICallableInfo *) closure->info, args,
- closure->user_data,
- &py_args, &out_args)) {
+ state.user_data = closure->user_data;
+
+ _invoke_state_init_from_cache (&state, closure->cache, args);
+
+ if (!_pygi_closure_convert_arguments (&state, closure->cache)) {
if (PyErr_Occurred ())
- PyErr_Print();
+ PyErr_Print ();
goto end;
}
- retval = PyObject_CallObject ( (PyObject *) closure->function, py_args);
- Py_DECREF (py_args);
+ retval = PyObject_CallObject ( (PyObject *) closure->function, state.py_in_args);
if (retval == NULL) {
_pygi_closure_clear_retval (closure->cache, result);
- PyErr_Print();
+ PyErr_Print ();
goto end;
}
- _pygi_closure_set_out_arguments (closure->cache, closure->info, retval, out_args, result);
- if (PyErr_Occurred ()) {
+ success = _pygi_closure_set_out_arguments (&state, closure->cache, retval, result);
+ /*pygi_marshal_cleanup_args_to_py_marshal_success (&state, closure->cache);*/
+
+ if (!success) {
+ pygi_marshal_cleanup_args_from_py_marshal_success (&state, closure->cache);
_pygi_closure_clear_retval (closure->cache, result);
- PyErr_Print();
+
+ if (PyErr_Occurred ())
+ PyErr_Print ();
}
Py_DECREF (retval);
end:
- g_free (out_args);
/* Now that the closure has finished we can make a decision about how
to free it. Scope call gets free'd at the end of wrap_g_function_info_invoke.
@@ -604,7 +620,8 @@ end:
g_base_info_get_name (closure->info));
}
- PyGILState_Release (state);
+ _invoke_state_clear (&state);
+ PyGILState_Release (py_state);
}
void _pygi_invoke_closure_free (gpointer data)
@@ -825,11 +842,26 @@ _pygi_marshal_to_py_interface_callback (PyGIInvokeState *state,
PyGIArgCache *arg_cache,
GIArgument *arg)
{
- PyObject *py_obj = NULL;
+ PyGICallbackCache *callback_cache = (PyGICallbackCache *) arg_cache;
+ gssize user_data_index;
+ gssize destroy_notify_index;
+ gpointer user_data = NULL;
+ GDestroyNotify destroy_notify = NULL;
- PyErr_Format (PyExc_NotImplementedError,
- "Marshalling a callback to PyObject is not supported");
- return py_obj;
+ user_data_index = callback_cache->user_data_index;
+ destroy_notify_index = callback_cache->destroy_notify_index;
+
+ if (user_data_index != -1)
+ user_data = state->arg_values[user_data_index].v_pointer;
+
+ if (destroy_notify_index != -1)
+ destroy_notify = state->arg_values[destroy_notify_index].v_pointer;
+
+ return _pygi_ccallback_new (arg->v_pointer,
+ user_data,
+ callback_cache->scope,
+ (GIFunctionInfo *) callback_cache->interface_info,
+ destroy_notify);
}
static void
@@ -851,37 +883,12 @@ _pygi_marshal_cleanup_from_py_interface_callback (PyGIInvokeState *state,
gboolean was_processed)
{
PyGICallbackCache *callback_cache = (PyGICallbackCache *)arg_cache;
+
if (was_processed && callback_cache->scope == GI_SCOPE_TYPE_CALL) {
_pygi_invoke_closure_free (data);
}
}
-static void
-_arg_cache_from_py_interface_callback_setup (PyGIArgCache *arg_cache,
- PyGICallableCache *callable_cache)
-{
- PyGICallbackCache *callback_cache = (PyGICallbackCache *)arg_cache;
- if (callback_cache->user_data_index >= 0) {
- PyGIArgCache *user_data_arg_cache = pygi_arg_cache_alloc ();
- user_data_arg_cache->meta_type = PYGI_META_ARG_TYPE_CHILD_WITH_PYARG;
- user_data_arg_cache->direction = PYGI_DIRECTION_FROM_PYTHON;
- user_data_arg_cache->has_default = TRUE; /* always allow user data with a NULL default. */
- _pygi_callable_cache_set_arg (callable_cache, callback_cache->user_data_index,
- user_data_arg_cache);
- }
-
- if (callback_cache->destroy_notify_index >= 0) {
- PyGIArgCache *destroy_arg_cache = pygi_arg_cache_alloc ();
- destroy_arg_cache->meta_type = PYGI_META_ARG_TYPE_CHILD;
- destroy_arg_cache->direction = PYGI_DIRECTION_FROM_PYTHON;
- _pygi_callable_cache_set_arg (callable_cache, callback_cache->destroy_notify_index,
- destroy_arg_cache);
- }
- arg_cache->from_py_marshaller = _pygi_marshal_from_py_interface_callback;
- arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_interface_callback;
-}
-
-
static gboolean
pygi_arg_callback_setup_from_info (PyGICallbackCache *arg_cache,
GITypeInfo *type_info,
@@ -891,6 +898,7 @@ pygi_arg_callback_setup_from_info (PyGICallbackCache *arg_cache,
GIInterfaceInfo *iface_info,
PyGICallableCache *callable_cache)
{
+ PyGIArgCache *cache = (PyGIArgCache *)arg_cache;
gssize child_offset = 0;
if (!pygi_arg_base_setup ((PyGIArgCache *)arg_cache,
@@ -901,10 +909,6 @@ pygi_arg_callback_setup_from_info (PyGICallbackCache *arg_cache,
return FALSE;
}
- if (direction & PYGI_DIRECTION_TO_PYTHON) {
- ((PyGIArgCache *)arg_cache)->to_py_marshaller = _pygi_marshal_to_py_interface_callback;
- }
-
if (callable_cache != NULL)
child_offset = callable_cache->args_offset;
@@ -913,15 +917,40 @@ pygi_arg_callback_setup_from_info (PyGICallbackCache *arg_cache,
arg_cache->user_data_index = g_arg_info_get_closure (arg_info);
if (arg_cache->user_data_index != -1)
arg_cache->user_data_index += child_offset;
+
arg_cache->destroy_notify_index = g_arg_info_get_destroy (arg_info);
if (arg_cache->destroy_notify_index != -1)
arg_cache->destroy_notify_index += child_offset;
+
+ if (arg_cache->user_data_index >= 0) {
+ PyGIArgCache *user_data_arg_cache = pygi_arg_cache_alloc ();
+ user_data_arg_cache->meta_type = PYGI_META_ARG_TYPE_CHILD_WITH_PYARG;
+ user_data_arg_cache->direction = direction;
+ user_data_arg_cache->has_default = TRUE; /* always allow user data with a NULL default. */
+ _pygi_callable_cache_set_arg (callable_cache, arg_cache->user_data_index,
+ user_data_arg_cache);
+ }
+
+ if (arg_cache->destroy_notify_index >= 0) {
+ PyGIArgCache *destroy_arg_cache = pygi_arg_cache_alloc ();
+ destroy_arg_cache->meta_type = PYGI_META_ARG_TYPE_CHILD;
+ destroy_arg_cache->direction = direction;
+ _pygi_callable_cache_set_arg (callable_cache, arg_cache->destroy_notify_index,
+ destroy_arg_cache);
+ }
+
arg_cache->scope = g_arg_info_get_scope (arg_info);
g_base_info_ref( (GIBaseInfo *)iface_info);
arg_cache->interface_info = iface_info;
- if (direction & PYGI_DIRECTION_FROM_PYTHON)
- _arg_cache_from_py_interface_callback_setup ((PyGIArgCache *)arg_cache, callable_cache);
+ if (direction & PYGI_DIRECTION_FROM_PYTHON) {
+ cache->from_py_marshaller = _pygi_marshal_from_py_interface_callback;
+ cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_interface_callback;
+ }
+
+ if (direction & PYGI_DIRECTION_TO_PYTHON) {
+ cache->to_py_marshaller = _pygi_marshal_to_py_interface_callback;
+ }
return TRUE;
}
diff --git a/gi/pygi-invoke.c b/gi/pygi-invoke.c
index 3f72576f..a65274a0 100644
--- a/gi/pygi-invoke.c
+++ b/gi/pygi-invoke.c
@@ -465,7 +465,8 @@ _invoke_marshal_in_args (PyGIInvokeState *state, PyGIFunctionCache *function_cac
if (py_arg == _PyGIDefaultArgPlaceholder) {
*c_arg = arg_cache->default_value;
- } else if (arg_cache->from_py_marshaller != NULL) {
+ } else if (arg_cache->from_py_marshaller != NULL &&
+ arg_cache->meta_type != PYGI_META_ARG_TYPE_CHILD) {
gboolean success;
gpointer cleanup_data = NULL;