static PyObject * _wrap_g_callable_info_get_arguments (PyGIBaseInfo *self) { gssize n_infos; PyObject *infos; gssize i; n_infos = g_callable_info_get_n_args ( (GICallableInfo *) self->info); infos = PyTuple_New (n_infos); if (infos == NULL) { return NULL; } for (i = 0; i < n_infos; i++) { GIBaseInfo *info; PyObject *py_info; info = (GIBaseInfo *) g_callable_info_get_arg ( (GICallableInfo *) self->info, i); g_assert (info != NULL); py_info = _pygi_info_new (info); g_base_info_unref (info); if (py_info == NULL) { Py_CLEAR (infos); break; } PyTuple_SET_ITEM (infos, i, py_info); } return infos; }
static void prepare_invocation_info (GPerlI11nInvocationInfo *iinfo, GICallableInfo *info) { gint orig_n_args; guint i; dwarn ("invoke: %s\n" " n_args: %d\n", g_base_info_get_name (info), g_callable_info_get_n_args (info)); iinfo->interface = info; iinfo->is_function = GI_IS_FUNCTION_INFO (info); iinfo->is_vfunc = GI_IS_VFUNC_INFO (info); iinfo->is_callback = (g_base_info_get_type (info) == GI_INFO_TYPE_CALLBACK); iinfo->is_signal = GI_IS_SIGNAL_INFO (info); dwarn (" is_function = %d, is_vfunc = %d, is_callback = %d\n", iinfo->is_function, iinfo->is_vfunc, iinfo->is_callback); orig_n_args = g_callable_info_get_n_args (info); g_assert (orig_n_args >= 0); iinfo->n_args = (guint) orig_n_args; if (iinfo->n_args) { iinfo->arg_infos = gperl_alloc_temp (sizeof (GITypeInfo*) * iinfo->n_args); iinfo->arg_types = gperl_alloc_temp (sizeof (GITypeInfo*) * iinfo->n_args); iinfo->aux_args = gperl_alloc_temp (sizeof (GIArgument) * iinfo->n_args); } else { iinfo->arg_infos = NULL; iinfo->arg_types = NULL; iinfo->aux_args = NULL; } for (i = 0 ; i < iinfo->n_args ; i++) { iinfo->arg_infos[i] = g_callable_info_get_arg (info, (gint) i); iinfo->arg_types[i] = g_arg_info_get_type (iinfo->arg_infos[i]); } iinfo->return_type_info = g_callable_info_get_return_type (info); iinfo->has_return_value = GI_TYPE_TAG_VOID != g_type_info_get_tag (iinfo->return_type_info); iinfo->return_type_ffi = g_type_info_get_ffi_type (iinfo->return_type_info); iinfo->return_type_transfer = g_callable_info_get_caller_owns (info); iinfo->callback_infos = NULL; iinfo->array_infos = NULL; iinfo->free_after_call = NULL; }
void _pygi_closure_handle (ffi_cif *cif, void *result, void **args, void *data) { PyGILState_STATE state; PyGICClosure *closure = data; gint n_args, i; GIArgInfo *arg_info; GIDirection arg_direction; GITypeInfo *arg_type; GITransfer arg_transfer; GITypeTag arg_tag; GITypeTag return_tag; GITransfer return_transfer; GITypeInfo *return_type; PyObject *retval; PyObject *py_args; PyObject *pyarg; gint n_in_args, n_out_args; /* Lock the GIL as we are coming into this code without the lock and we may be executing python code */ state = PyGILState_Ensure(); return_type = g_callable_info_get_return_type(closure->info); return_tag = g_type_info_get_tag(return_type); return_transfer = g_callable_info_get_caller_owns(closure->info); n_args = g_callable_info_get_n_args (closure->info); py_args = PyTuple_New(n_args); if (py_args == NULL) { PyErr_Clear(); goto end; } n_in_args = 0; for (i = 0; i < n_args; i++) { arg_info = g_callable_info_get_arg (closure->info, i); arg_type = g_arg_info_get_type (arg_info); arg_transfer = g_arg_info_get_ownership_transfer(arg_info); arg_tag = g_type_info_get_tag(arg_type); arg_direction = g_arg_info_get_direction(arg_info); switch (arg_tag) { case GI_TYPE_TAG_VOID: { if (g_type_info_is_pointer(arg_type)) { if (PyTuple_SetItem(py_args, n_in_args, closure->user_data) != 0) { PyErr_Clear(); goto end; } n_in_args++; continue; } } case GI_TYPE_TAG_ERROR: { continue; } default: { pyarg = _pygi_argument_to_object (args[i], arg_type, arg_transfer); if(PyTuple_SetItem(py_args, n_in_args, pyarg) != 0) { PyErr_Clear(); goto end; } n_in_args++; g_base_info_unref((GIBaseInfo*)arg_info); g_base_info_unref((GIBaseInfo*)arg_type); } } } if(_PyTuple_Resize (&py_args, n_in_args) != 0) { PyErr_Clear(); goto end; } retval = PyObject_CallObject((PyObject *)closure->function, py_args); Py_DECREF(py_args); if (retval == NULL) { goto end; } *(GArgument*)result = _pygi_argument_from_object(retval, return_type, return_transfer); end: g_base_info_unref((GIBaseInfo*)return_type); PyGILState_Release(state); if (closure->user_data) Py_XDECREF(closure->user_data); /* Now that the closure has finished we can make a decision about how to free it. Scope call gets free'd now, scope notified will be freed when the notify is called and we can free async anytime we want once we return from this function */ switch (closure->scope) { case GI_SCOPE_TYPE_CALL: _pygi_invoke_closure_free(closure); break; case GI_SCOPE_TYPE_NOTIFIED: break; case GI_SCOPE_TYPE_ASYNC: /* Append this PyGICClosure to a list of closure that we will free after we're done with this function invokation */ async_free_list = g_slist_prepend(async_free_list, closure); break; default: g_assert_not_reached(); } }
/** * g_function_info_prep_invoker: * @info: A #GIFunctionInfo * @invoker: Output invoker structure * @error: A #GError * * Initialize the caller-allocated @invoker structure with a cache * of information needed to invoke the C function corresponding to * @info with the platform's default ABI. * * A primary intent of this function is that a dynamic structure allocated * by a language binding could contain a #GIFunctionInvoker structure * inside the binding's function mapping. * * Returns: %TRUE on success, %FALSE otherwise with @error set. */ gboolean g_function_info_prep_invoker (GIFunctionInfo *info, GIFunctionInvoker *invoker, GError **error) { const char *symbol; ffi_type *rtype; ffi_type **atypes; GITypeInfo *tinfo; GIArgInfo *ainfo; gboolean is_method; gboolean throws; gint n_args, n_invoke_args, i; g_return_val_if_fail (info != NULL, FALSE); g_return_val_if_fail (invoker != NULL, FALSE); symbol = g_function_info_get_symbol ((GIFunctionInfo*) info); if (!g_typelib_symbol (g_base_info_get_typelib((GIBaseInfo *) info), symbol, &(invoker->native_address))) { g_set_error (error, G_INVOKE_ERROR, G_INVOKE_ERROR_SYMBOL_NOT_FOUND, "Could not locate %s: %s", symbol, g_module_error ()); return FALSE; } is_method = (g_function_info_get_flags (info) & GI_FUNCTION_IS_METHOD) != 0 && (g_function_info_get_flags (info) & GI_FUNCTION_IS_CONSTRUCTOR) == 0; throws = g_function_info_get_flags (info) & GI_FUNCTION_THROWS; tinfo = g_callable_info_get_return_type ((GICallableInfo *)info); rtype = g_type_info_get_ffi_type (tinfo); g_base_info_unref ((GIBaseInfo *)tinfo); n_args = g_callable_info_get_n_args ((GICallableInfo *)info); if (is_method) n_invoke_args = n_args+1; else n_invoke_args = n_args; if (throws) /* Add an argument for the GError */ n_invoke_args ++; /* TODO: avoid malloc here? */ atypes = g_malloc0 (sizeof (ffi_type*) * n_invoke_args); if (is_method) { atypes[0] = &ffi_type_pointer; } for (i = 0; i < n_args; i++) { int offset = (is_method ? 1 : 0); ainfo = g_callable_info_get_arg ((GICallableInfo *)info, i); switch (g_arg_info_get_direction (ainfo)) { case GI_DIRECTION_IN: tinfo = g_arg_info_get_type (ainfo); atypes[i+offset] = g_type_info_get_ffi_type (tinfo); g_base_info_unref ((GIBaseInfo *)tinfo); break; case GI_DIRECTION_OUT: case GI_DIRECTION_INOUT: atypes[i+offset] = &ffi_type_pointer; break; default: g_assert_not_reached (); } g_base_info_unref ((GIBaseInfo *)ainfo); } if (throws) { atypes[n_invoke_args - 1] = &ffi_type_pointer; } return ffi_prep_cif (&(invoker->cif), FFI_DEFAULT_ABI, n_invoke_args, rtype, atypes) == FFI_OK; }
static void invoke_callback (ffi_cif* cif, gpointer resp, gpointer* args, gpointer userdata) { GPerlI11nPerlCallbackInfo *info; GICallableInfo *cb_interface; GPerlI11nInvocationInfo iinfo = {0,}; guint i; guint in_inout; guint n_return_values, n_returned; I32 context; dGPERL_CALLBACK_MARSHAL_SP; PERL_UNUSED_VAR (cif); /* unwrap callback info struct from userdata */ info = (GPerlI11nPerlCallbackInfo *) userdata; cb_interface = (GICallableInfo *) info->interface; prepare_perl_invocation_info (&iinfo, cb_interface); /* set perl context */ GPERL_CALLBACK_MARSHAL_INIT (info); ENTER; SAVETMPS; PUSHMARK (SP); /* find arguments; use type information from interface to find in and * in-out args and their types, count in-out and out args, and find * suitable converters; push in and in-out arguments onto the perl * stack */ in_inout = 0; for (i = 0; i < iinfo.n_args; i++) { GIArgInfo *arg_info = g_callable_info_get_arg (cb_interface, i); GITypeInfo *arg_type = g_arg_info_get_type (arg_info); GITransfer transfer = g_arg_info_get_ownership_transfer (arg_info); GIDirection direction = g_arg_info_get_direction (arg_info); iinfo.current_pos = i; /* the closure argument, which we handle separately, is marked * by having get_closure == i */ if (g_arg_info_get_closure (arg_info) == (gint) i) { g_base_info_unref ((GIBaseInfo *) arg_info); g_base_info_unref ((GIBaseInfo *) arg_type); continue; } dwarn ("arg info: %s (%p)\n" " direction: %d\n" " is return value: %d\n" " is optional: %d\n" " may be null: %d\n" " transfer: %d\n", g_base_info_get_name (arg_info), arg_info, g_arg_info_get_direction (arg_info), g_arg_info_is_return_value (arg_info), g_arg_info_is_optional (arg_info), g_arg_info_may_be_null (arg_info), g_arg_info_get_ownership_transfer (arg_info)); dwarn ("arg type: %p\n" " is pointer: %d\n" " tag: %s (%d)\n", arg_type, g_type_info_is_pointer (arg_type), g_type_tag_to_string (g_type_info_get_tag (arg_type)), g_type_info_get_tag (arg_type)); if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT) { GIArgument arg; SV *sv; raw_to_arg (args[i], &arg, arg_type); sv = arg_to_sv (&arg, arg_type, transfer, &iinfo); /* If arg_to_sv returns NULL, we take that as 'skip * this argument'; happens for GDestroyNotify, for * example. */ if (sv) XPUSHs (sv_2mortal (sv)); } if (direction == GI_DIRECTION_INOUT || direction == GI_DIRECTION_OUT) { in_inout++; } g_base_info_unref ((GIBaseInfo *) arg_info); g_base_info_unref ((GIBaseInfo *) arg_type); } /* push user data onto the Perl stack */ if (info->data) XPUSHs (sv_2mortal (SvREFCNT_inc (info->data))); PUTBACK; /* determine suitable Perl call context */ context = G_VOID | G_DISCARD; if (iinfo.has_return_value) { context = in_inout > 0 ? G_ARRAY : G_SCALAR; } else { if (in_inout == 1) { context = G_SCALAR; } else if (in_inout > 1) { context = G_ARRAY; } } /* do the call, demand #in-out+#out+#return-value return values */ n_return_values = iinfo.has_return_value ? in_inout + 1 : in_inout; n_returned = info->sub_name ? call_method (info->sub_name, context) : call_sv (info->code, context); if (n_return_values != 0 && n_returned != n_return_values) { ccroak ("callback returned %d values " "but is supposed to return %d values", n_returned, n_return_values); } /* call-scoped callback infos are freed by * Glib::Object::Introspection::_FuncWrapper::DESTROY */ SPAGAIN; /* convert in-out and out values and stuff them back into args */ if (in_inout > 0) { SV **returned_values; int out_index; returned_values = g_new0 (SV *, in_inout); /* pop scalars off the stack and put them into the array; * reverse the order since POPs pops items off of the end of * the stack. */ for (i = 0; i < in_inout; i++) { returned_values[in_inout - i - 1] = POPs; } out_index = 0; for (i = 0; i < iinfo.n_args; i++) { GIArgInfo *arg_info = g_callable_info_get_arg (cb_interface, i); GITypeInfo *arg_type = g_arg_info_get_type (arg_info); GIDirection direction = g_arg_info_get_direction (arg_info); gpointer out_pointer = * (gpointer *) args[i]; if (!out_pointer) { dwarn ("skipping out arg %d\n", i); g_base_info_unref (arg_info); g_base_info_unref (arg_type); continue; } if (direction == GI_DIRECTION_INOUT || direction == GI_DIRECTION_OUT) { GIArgument tmp_arg; GITransfer transfer = g_arg_info_get_ownership_transfer (arg_info); gboolean may_be_null = g_arg_info_may_be_null (arg_info); gboolean is_caller_allocated = g_arg_info_is_caller_allocates (arg_info); if (is_caller_allocated) { tmp_arg.v_pointer = out_pointer; } sv_to_arg (returned_values[out_index], &tmp_arg, arg_info, arg_type, transfer, may_be_null, &iinfo); if (!is_caller_allocated) { arg_to_raw (&tmp_arg, out_pointer, arg_type); } out_index++; } g_base_info_unref (arg_info); g_base_info_unref (arg_type); } g_free (returned_values); }
static JSBool gjs_value_from_g_value_internal(JSContext *context, jsval *value_p, const GValue *gvalue, gboolean no_copy, GSignalQuery *signal_query, gint arg_n) { GType gtype; gtype = G_VALUE_TYPE(gvalue); gjs_debug_marshal(GJS_DEBUG_GCLOSURE, "Converting gtype %s to jsval", g_type_name(gtype)); if (gtype == G_TYPE_STRING) { const char *v; v = g_value_get_string(gvalue); if (v == NULL) { gjs_debug_marshal(GJS_DEBUG_GCLOSURE, "Converting NULL string to JSVAL_NULL"); *value_p = JSVAL_NULL; } else { if (!gjs_string_from_utf8(context, v, -1, value_p)) return JS_FALSE; } } else if (gtype == G_TYPE_CHAR) { char v; v = g_value_get_schar(gvalue); *value_p = INT_TO_JSVAL(v); } else if (gtype == G_TYPE_UCHAR) { unsigned char v; v = g_value_get_uchar(gvalue); *value_p = INT_TO_JSVAL(v); } else if (gtype == G_TYPE_INT) { int v; v = g_value_get_int(gvalue); return JS_NewNumberValue(context, v, value_p); } else if (gtype == G_TYPE_UINT) { uint v; v = g_value_get_uint(gvalue); return JS_NewNumberValue(context, v, value_p); } else if (gtype == G_TYPE_DOUBLE) { double d; d = g_value_get_double(gvalue); return JS_NewNumberValue(context, d, value_p); } else if (gtype == G_TYPE_FLOAT) { double d; d = g_value_get_float(gvalue); return JS_NewNumberValue(context, d, value_p); } else if (gtype == G_TYPE_BOOLEAN) { gboolean v; v = g_value_get_boolean(gvalue); *value_p = BOOLEAN_TO_JSVAL(v); } else if (g_type_is_a(gtype, G_TYPE_OBJECT) || g_type_is_a(gtype, G_TYPE_INTERFACE)) { GObject *gobj; JSObject *obj; gobj = g_value_get_object(gvalue); obj = gjs_object_from_g_object(context, gobj); *value_p = OBJECT_TO_JSVAL(obj); } else if (gtype == G_TYPE_STRV) { if (!gjs_array_from_strv (context, value_p, g_value_get_boxed (gvalue))) { gjs_throw(context, "Failed to convert strv to array"); return JS_FALSE; } } else if (g_type_is_a(gtype, G_TYPE_HASH_TABLE) || g_type_is_a(gtype, G_TYPE_ARRAY) || g_type_is_a(gtype, G_TYPE_BYTE_ARRAY) || g_type_is_a(gtype, G_TYPE_PTR_ARRAY)) { gjs_throw(context, "Unable to introspect element-type of container in GValue"); return JS_FALSE; } else if (g_type_is_a(gtype, G_TYPE_BOXED) || g_type_is_a(gtype, G_TYPE_VARIANT)) { GjsBoxedCreationFlags boxed_flags; GIBaseInfo *info; void *gboxed; JSObject *obj; if (g_type_is_a(gtype, G_TYPE_BOXED)) gboxed = g_value_get_boxed(gvalue); else gboxed = g_value_get_variant(gvalue); boxed_flags = GJS_BOXED_CREATION_NONE; /* special case GError */ if (g_type_is_a(gtype, G_TYPE_ERROR)) { obj = gjs_error_from_gerror(context, gboxed, FALSE); *value_p = OBJECT_TO_JSVAL(obj); return TRUE; } /* The only way to differentiate unions and structs is from * their g-i info as both GBoxed */ info = g_irepository_find_by_gtype(g_irepository_get_default(), gtype); if (info == NULL) { gjs_throw(context, "No introspection information found for %s", g_type_name(gtype)); return JS_FALSE; } if (g_base_info_get_type(info) == GI_INFO_TYPE_STRUCT && g_struct_info_is_foreign((GIStructInfo*)info)) { JSBool ret; GIArgument arg; arg.v_pointer = gboxed; ret = gjs_struct_foreign_convert_from_g_argument(context, value_p, info, &arg); g_base_info_unref(info); return ret; } switch (g_base_info_get_type(info)) { case GI_INFO_TYPE_BOXED: case GI_INFO_TYPE_STRUCT: if (no_copy) boxed_flags |= GJS_BOXED_CREATION_NO_COPY; obj = gjs_boxed_from_c_struct(context, (GIStructInfo *)info, gboxed, boxed_flags); break; case GI_INFO_TYPE_UNION: obj = gjs_union_from_c_union(context, (GIUnionInfo *)info, gboxed); break; default: gjs_throw(context, "Unexpected introspection type %d for %s", g_base_info_get_type(info), g_type_name(gtype)); g_base_info_unref(info); return JS_FALSE; } *value_p = OBJECT_TO_JSVAL(obj); g_base_info_unref(info); } else if (g_type_is_a(gtype, G_TYPE_ENUM)) { return convert_int_to_enum(context, value_p, gtype, g_value_get_enum(gvalue)); } else if (g_type_is_a(gtype, G_TYPE_PARAM)) { GParamSpec *gparam; JSObject *obj; gparam = g_value_get_param(gvalue); obj = gjs_param_from_g_param(context, gparam); *value_p = OBJECT_TO_JSVAL(obj); } else if (signal_query && g_type_is_a(gtype, G_TYPE_POINTER)) { JSBool res; GArgument arg; GIArgInfo *arg_info; GIBaseInfo *obj; GISignalInfo *signal_info; GITypeInfo type_info; obj = g_irepository_find_by_gtype(NULL, signal_query->itype); if (!obj) { gjs_throw(context, "Signal argument with GType %s isn't introspectable", g_type_name(signal_query->itype)); return JS_FALSE; } signal_info = g_object_info_find_signal((GIObjectInfo*)obj, signal_query->signal_name); if (!signal_info) { gjs_throw(context, "Unknown signal."); g_base_info_unref((GIBaseInfo*)obj); return JS_FALSE; } arg_info = g_callable_info_get_arg(signal_info, arg_n - 1); g_arg_info_load_type(arg_info, &type_info); arg.v_pointer = g_value_get_pointer(gvalue); res = gjs_value_from_g_argument(context, value_p, &type_info, &arg, TRUE); g_base_info_unref((GIBaseInfo*)arg_info); g_base_info_unref((GIBaseInfo*)signal_info); g_base_info_unref((GIBaseInfo*)obj); return res; } else if (g_type_is_a(gtype, G_TYPE_POINTER)) { gpointer pointer; pointer = g_value_get_pointer(gvalue); if (pointer == NULL) { *value_p = JSVAL_NULL; } else { gjs_throw(context, "Can't convert non-null pointer to JS value"); return JS_FALSE; } } else if (g_value_type_transformable(gtype, G_TYPE_DOUBLE)) { GValue double_value = { 0, }; double v; g_value_init(&double_value, G_TYPE_DOUBLE); g_value_transform(gvalue, &double_value); v = g_value_get_double(&double_value); return JS_NewNumberValue(context, v, value_p); } else if (g_value_type_transformable(gtype, G_TYPE_INT)) { GValue int_value = { 0, }; int v; g_value_init(&int_value, G_TYPE_INT); g_value_transform(gvalue, &int_value); v = g_value_get_int(&int_value); return JS_NewNumberValue(context, v, value_p); } else { gjs_throw(context, "Don't know how to convert GType %s to JavaScript object", g_type_name(gtype)); return JS_FALSE; } return JS_TRUE; }
gboolean _pygi_scan_for_callbacks (GIFunctionInfo *function_info, gboolean is_method, guint8 *callback_index, guint8 *user_data_index, guint8 *destroy_notify_index) { guint i, n_args; *callback_index = G_MAXUINT8; *user_data_index = G_MAXUINT8; *destroy_notify_index = G_MAXUINT8; n_args = g_callable_info_get_n_args ( (GICallableInfo *) function_info); for (i = 0; i < n_args; i++) { GIDirection direction; GIArgInfo *arg_info; GITypeInfo *type_info; guint8 destroy, closure; GITypeTag type_tag; arg_info = g_callable_info_get_arg ( (GICallableInfo*) function_info, i); type_info = g_arg_info_get_type (arg_info); type_tag = g_type_info_get_tag (type_info); if (type_tag == GI_TYPE_TAG_INTERFACE) { GIBaseInfo* interface_info; GIInfoType interface_type; interface_info = g_type_info_get_interface (type_info); interface_type = g_base_info_get_type (interface_info); if (interface_type == GI_INFO_TYPE_CALLBACK && ! (strcmp (g_base_info_get_namespace ( (GIBaseInfo*) interface_info), "GLib") == 0 && (strcmp (g_base_info_get_name ( (GIBaseInfo*) interface_info), "DestroyNotify") == 0 || (strcmp (g_base_info_get_name ( (GIBaseInfo*) interface_info), "FreeFunc") == 0)))) { if (*callback_index != G_MAXUINT8) { PyErr_Format (PyExc_TypeError, "Function %s.%s has multiple callbacks, not supported", g_base_info_get_namespace ( (GIBaseInfo*) function_info), g_base_info_get_name ( (GIBaseInfo*) function_info)); g_base_info_unref (interface_info); return FALSE; } *callback_index = i; } g_base_info_unref (interface_info); } destroy = g_arg_info_get_destroy (arg_info); closure = g_arg_info_get_closure (arg_info); direction = g_arg_info_get_direction (arg_info); if (destroy > 0 && destroy < n_args) { if (*destroy_notify_index != G_MAXUINT8) { PyErr_Format (PyExc_TypeError, "Function %s has multiple GDestroyNotify, not supported", g_base_info_get_name ( (GIBaseInfo*) function_info)); return FALSE; } *destroy_notify_index = destroy; } if (closure > 0 && closure < n_args) { if (*user_data_index != G_MAXUINT8) { PyErr_Format (PyExc_TypeError, "Function %s has multiple user_data arguments, not supported", g_base_info_get_name ( (GIBaseInfo*) function_info)); return FALSE; } *user_data_index = closure; } g_base_info_unref ( (GIBaseInfo*) arg_info); g_base_info_unref ( (GIBaseInfo*) type_info); } return TRUE; }
gboolean _pygi_create_callback (GIBaseInfo *function_info, gboolean is_method, gboolean is_constructor, int n_args, Py_ssize_t py_argc, PyObject *py_argv, guint8 callback_index, guint8 user_data_index, guint8 destroy_notify_index, PyGICClosure **closure_out) { GIArgInfo *callback_arg; GITypeInfo *callback_type; GICallbackInfo *callback_info; GIScopeType scope; gboolean found_py_function; PyObject *py_function; guint8 i, py_argv_pos; PyObject *py_user_data; gboolean allow_none; callback_arg = g_callable_info_get_arg ( (GICallableInfo*) function_info, callback_index); scope = g_arg_info_get_scope (callback_arg); allow_none = g_arg_info_may_be_null (callback_arg); callback_type = g_arg_info_get_type (callback_arg); g_assert (g_type_info_get_tag (callback_type) == GI_TYPE_TAG_INTERFACE); callback_info = (GICallbackInfo*) g_type_info_get_interface (callback_type); g_assert (g_base_info_get_type ( (GIBaseInfo*) callback_info) == GI_INFO_TYPE_CALLBACK); /* Find the Python function passed for the callback */ found_py_function = FALSE; py_function = Py_None; py_user_data = NULL; /* if its a method then we need to skip over 'self' */ if (is_method || is_constructor) py_argv_pos = 1; else py_argv_pos = 0; for (i = 0; i < n_args && i < py_argc; i++) { if (i == callback_index) { py_function = PyTuple_GetItem (py_argv, py_argv_pos); /* if we allow none then set the closure to NULL and return */ if (allow_none && py_function == Py_None) { *closure_out = NULL; goto out; } found_py_function = TRUE; } else if (i == user_data_index) { py_user_data = PyTuple_GetItem (py_argv, py_argv_pos); } py_argv_pos++; } if (!found_py_function || (py_function == Py_None || !PyCallable_Check (py_function))) { PyErr_Format (PyExc_TypeError, "Error invoking %s.%s: Unexpected value " "for argument '%s'", g_base_info_get_namespace ( (GIBaseInfo*) function_info), g_base_info_get_name ( (GIBaseInfo*) function_info), g_base_info_get_name ( (GIBaseInfo*) callback_arg)); g_base_info_unref ( (GIBaseInfo*) callback_info); g_base_info_unref ( (GIBaseInfo*) callback_type); return FALSE; } /** Now actually build the closure **/ *closure_out = _pygi_make_native_closure ( (GICallableInfo *) callback_info, g_arg_info_get_scope (callback_arg), py_function, py_user_data); out: g_base_info_unref ( (GIBaseInfo*) callback_info); g_base_info_unref ( (GIBaseInfo*) callback_type); return TRUE; }
/** * g_callable_info_invoke: * @info: TODO * @function: TODO * @in_args: TODO * @n_in_args: TODO * @out_args: TODO * @n_out_args: TODO * @return_value: TODO * @is_method: TODO * @throws: TODO * @error: TODO * * TODO */ gboolean g_callable_info_invoke (GIFunctionInfo *info, gpointer function, const GIArgument *in_args, int n_in_args, const GIArgument *out_args, int n_out_args, GIArgument *return_value, gboolean is_method, gboolean throws, GError **error) { ffi_cif cif; ffi_type *rtype; ffi_type **atypes; GITypeInfo *tinfo; GITypeInfo *rinfo; GITypeTag rtag; GIArgInfo *ainfo; gint n_args, n_invoke_args, in_pos, out_pos, i; gpointer *args; gboolean success = FALSE; GError *local_error = NULL; gpointer error_address = &local_error; GIFFIReturnValue ffi_return_value; gpointer return_value_p; /* Will point inside the union return_value */ rinfo = g_callable_info_get_return_type ((GICallableInfo *)info); rtype = g_type_info_get_ffi_type (rinfo); rtag = g_type_info_get_tag(rinfo); in_pos = 0; out_pos = 0; n_args = g_callable_info_get_n_args ((GICallableInfo *)info); if (is_method) { if (n_in_args == 0) { g_set_error (error, G_INVOKE_ERROR, G_INVOKE_ERROR_ARGUMENT_MISMATCH, "Too few \"in\" arguments (handling this)"); goto out; } n_invoke_args = n_args+1; in_pos++; } else n_invoke_args = n_args; if (throws) /* Add an argument for the GError */ n_invoke_args ++; atypes = g_alloca (sizeof (ffi_type*) * n_invoke_args); args = g_alloca (sizeof (gpointer) * n_invoke_args); if (is_method) { atypes[0] = &ffi_type_pointer; args[0] = (gpointer) &in_args[0]; } for (i = 0; i < n_args; i++) { int offset = (is_method ? 1 : 0); ainfo = g_callable_info_get_arg ((GICallableInfo *)info, i); switch (g_arg_info_get_direction (ainfo)) { case GI_DIRECTION_IN: tinfo = g_arg_info_get_type (ainfo); atypes[i+offset] = g_type_info_get_ffi_type (tinfo); g_base_info_unref ((GIBaseInfo *)tinfo); if (in_pos >= n_in_args) { g_set_error (error, G_INVOKE_ERROR, G_INVOKE_ERROR_ARGUMENT_MISMATCH, "Too few \"in\" arguments (handling in)"); goto out; } args[i+offset] = (gpointer)&in_args[in_pos]; in_pos++; break; case GI_DIRECTION_OUT: atypes[i+offset] = &ffi_type_pointer; if (out_pos >= n_out_args) { g_set_error (error, G_INVOKE_ERROR, G_INVOKE_ERROR_ARGUMENT_MISMATCH, "Too few \"out\" arguments (handling out)"); goto out; } args[i+offset] = (gpointer)&out_args[out_pos]; out_pos++; break; case GI_DIRECTION_INOUT: atypes[i+offset] = &ffi_type_pointer; if (in_pos >= n_in_args) { g_set_error (error, G_INVOKE_ERROR, G_INVOKE_ERROR_ARGUMENT_MISMATCH, "Too few \"in\" arguments (handling inout)"); goto out; } if (out_pos >= n_out_args) { g_set_error (error, G_INVOKE_ERROR, G_INVOKE_ERROR_ARGUMENT_MISMATCH, "Too few \"out\" arguments (handling inout)"); goto out; } args[i+offset] = (gpointer)&in_args[in_pos]; in_pos++; out_pos++; break; default: g_assert_not_reached (); } g_base_info_unref ((GIBaseInfo *)ainfo); } if (throws) { args[n_invoke_args - 1] = &error_address; atypes[n_invoke_args - 1] = &ffi_type_pointer; } if (in_pos < n_in_args) { g_set_error (error, G_INVOKE_ERROR, G_INVOKE_ERROR_ARGUMENT_MISMATCH, "Too many \"in\" arguments (at end)"); goto out; } if (out_pos < n_out_args) { g_set_error (error, G_INVOKE_ERROR, G_INVOKE_ERROR_ARGUMENT_MISMATCH, "Too many \"out\" arguments (at end)"); goto out; } if (ffi_prep_cif (&cif, FFI_DEFAULT_ABI, n_invoke_args, rtype, atypes) != FFI_OK) goto out; g_return_val_if_fail (return_value, FALSE); /* See comment for GIFFIReturnValue above */ switch (rtag) { case GI_TYPE_TAG_FLOAT: return_value_p = &ffi_return_value.v_float; break; case GI_TYPE_TAG_DOUBLE: return_value_p = &ffi_return_value.v_double; break; case GI_TYPE_TAG_INT64: case GI_TYPE_TAG_UINT64: return_value_p = &ffi_return_value.v_uint64; break; default: return_value_p = &ffi_return_value.v_long; } ffi_call (&cif, function, return_value_p, args); if (local_error) { g_propagate_error (error, local_error); success = FALSE; } else { gi_type_info_extract_ffi_return_value (rinfo, &ffi_return_value, return_value); success = TRUE; } out: g_base_info_unref ((GIBaseInfo *)rinfo); return success; }