/** * _pygi_argument_array_length_marshal: * @length_arg_index: Index of length argument in the callables args list. * @user_data1: (type Array(GValue)): Array of GValue arguments to retrieve length * @user_data2: (type GICallableInfo): Callable info to get the argument from. * * Generic marshalling policy for array length arguments in callables. * * Returns: The length of the array or -1 on failure. */ gssize _pygi_argument_array_length_marshal (gsize length_arg_index, void *user_data1, void *user_data2) { GIArgInfo length_arg_info; GITypeInfo length_type_info; GIArgument length_arg; gssize array_len = -1; GValue *values = (GValue *)user_data1; GICallableInfo *callable_info = (GICallableInfo *)user_data2; g_callable_info_load_arg (callable_info, length_arg_index, &length_arg_info); g_arg_info_load_type (&length_arg_info, &length_type_info); length_arg = _pygi_argument_from_g_value (&(values[length_arg_index]), &length_type_info); if (!pygi_argument_to_gssize (&length_arg, g_type_info_get_tag (&length_type_info), &array_len)) { return -1; } return array_len; }
static void pygi_signal_closure_marshal(GClosure *closure, GValue *return_value, guint n_param_values, const GValue *param_values, gpointer invocation_hint, gpointer marshal_data) { PyGILState_STATE state; PyGClosure *pc = (PyGClosure *)closure; PyObject *params, *ret = NULL; guint i; GISignalInfo *signal_info; gint n_sig_info_args; gint sig_info_highest_arg; GSList *list_item = NULL; GSList *pass_by_ref_structs = NULL; state = PyGILState_Ensure(); signal_info = ((PyGISignalClosure *)closure)->signal_info; n_sig_info_args = g_callable_info_get_n_args(signal_info); /* the first argument to a signal callback is instance, but instance is not counted in the introspection data */ sig_info_highest_arg = n_sig_info_args + 1; g_assert_cmpint(sig_info_highest_arg, ==, n_param_values); /* construct Python tuple for the parameter values */ params = PyTuple_New(n_param_values); for (i = 0; i < n_param_values; i++) { /* swap in a different initial data for connect_object() */ if (i == 0 && G_CCLOSURE_SWAP_DATA(closure)) { g_return_if_fail(pc->swap_data != NULL); Py_INCREF(pc->swap_data); PyTuple_SetItem(params, 0, pc->swap_data); } else if (i == 0) { PyObject *item = pyg_value_as_pyobject(¶m_values[i], FALSE); if (!item) { goto out; } PyTuple_SetItem(params, i, item); } else if (i < sig_info_highest_arg) { GIArgInfo arg_info; GITypeInfo type_info; GITypeTag type_tag; GIArgument arg = { 0, }; PyObject *item = NULL; gboolean free_array = FALSE; gboolean pass_struct_by_ref = FALSE; g_callable_info_load_arg(signal_info, i - 1, &arg_info); g_arg_info_load_type(&arg_info, &type_info); arg = _pygi_argument_from_g_value(¶m_values[i], &type_info); type_tag = g_type_info_get_tag (&type_info); if (type_tag == GI_TYPE_TAG_ARRAY) { /* Skip the self argument of param_values */ arg.v_pointer = _pygi_argument_to_array (&arg, _pygi_argument_array_length_marshal, (void *)(param_values + 1), signal_info, &type_info, &free_array); } /* Hack to ensure struct arguments are passed-by-reference allowing * callback implementors to modify the struct values. This is needed * for keeping backwards compatibility and should be removed in future * versions which support signal output arguments as return values. * See: https://bugzilla.gnome.org/show_bug.cgi?id=735486 * * Note the logic here must match the logic path taken in _pygi_argument_to_object. */ if (type_tag == GI_TYPE_TAG_INTERFACE) { GIBaseInfo *info = g_type_info_get_interface (&type_info); GIInfoType info_type = g_base_info_get_type (info); if (info_type == GI_INFO_TYPE_STRUCT || info_type == GI_INFO_TYPE_BOXED || info_type == GI_INFO_TYPE_UNION) { GType gtype = g_registered_type_info_get_g_type ((GIRegisteredTypeInfo *) info); gboolean is_foreign = (info_type == GI_INFO_TYPE_STRUCT) && (g_struct_info_is_foreign ((GIStructInfo *) info)); if (!is_foreign && !g_type_is_a (gtype, G_TYPE_VALUE) && g_type_is_a (gtype, G_TYPE_BOXED)) { pass_struct_by_ref = TRUE; } } g_base_info_unref (info); } if (pass_struct_by_ref) { /* transfer everything will ensure the struct is not copied when wrapped. */ item = _pygi_argument_to_object (&arg, &type_info, GI_TRANSFER_EVERYTHING); if (item && PyObject_IsInstance (item, (PyObject *) &PyGIBoxed_Type)) { ((PyGBoxed *)item)->free_on_dealloc = FALSE; pass_by_ref_structs = g_slist_prepend (pass_by_ref_structs, item); } } else { item = _pygi_argument_to_object (&arg, &type_info, GI_TRANSFER_NOTHING); } if (free_array) { g_array_free (arg.v_pointer, FALSE); } if (item == NULL) { PyErr_Print (); goto out; } PyTuple_SetItem(params, i, item); } } /* params passed to function may have extra arguments */ if (pc->extra_args) { PyObject *tuple = params; params = PySequence_Concat(tuple, pc->extra_args); Py_DECREF(tuple); } ret = PyObject_CallObject(pc->callback, params); if (ret == NULL) { if (pc->exception_handler) pc->exception_handler(return_value, n_param_values, param_values); else PyErr_Print(); goto out; } if (G_IS_VALUE(return_value) && pyg_value_from_pyobject(return_value, ret) != 0) { PyErr_SetString(PyExc_TypeError, "can't convert return value to desired type"); if (pc->exception_handler) pc->exception_handler(return_value, n_param_values, param_values); else PyErr_Print(); } Py_DECREF(ret); /* Run through the list of structs which have been passed by reference and * check if they are being held longer than the duration of the callback * execution. This is determined if the ref count is greater than 1. * A single ref is held by the argument list and any more would mean the callback * stored a ref somewhere else. In this case we make an internal copy of * the boxed struct so Python can own the memory to it. */ list_item = pass_by_ref_structs; while (list_item) { PyObject *item = list_item->data; if (item->ob_refcnt > 1) { _pygi_boxed_copy_in_place ((PyGIBoxed *)item); } list_item = g_slist_next (list_item); } out: g_slist_free (pass_by_ref_structs); Py_DECREF(params); PyGILState_Release(state); }