static VALUE rg_invoke(VALUE self, VALUE rb_receiver, VALUE rb_arguments) { GIFunctionInfo *info; GICallableInfo *callable_info; GIArgument return_value; GITypeInfo return_value_info; info = SELF(self); callable_info = (GICallableInfo *)info; if (NIL_P(rb_receiver)) { rb_raise(rb_eArgError, "receiver is missing"); } /* TODO: use rb_protect */ rb_gi_function_info_invoke_raw(info, self, Qnil, rb_arguments, &return_value, NULL); g_callable_info_load_return_type(callable_info, &return_value_info); initialize_receiver(rb_receiver, &return_value_info, &return_value); return rb_receiver; }
static VALUE rg_invoke(VALUE self, VALUE rb_arguments) { GIFunctionInfo *info; VALUE rb_out_args; VALUE rb_return_value; info = SELF(self); /* TODO: use rb_protect() */ rb_out_args = rb_gi_function_info_invoke_raw(info, self, Qnil, rb_arguments, NULL, &rb_return_value); if (NIL_P(rb_out_args)) { return rb_return_value; } else { GICallableInfo *callable_info = (GICallableInfo *)info; GITypeInfo return_value_info; g_callable_info_load_return_type(callable_info, &return_value_info); if (g_type_info_get_tag(&return_value_info) != GI_TYPE_TAG_VOID) { rb_ary_unshift(rb_out_args, rb_return_value); } if (RARRAY_LEN(rb_out_args) == 1) { return RARRAY_PTR(rb_out_args)[0]; } else { return rb_out_args; } } }
VALUE rb_gi_return_argument_to_ruby(GIArgument *argument, GICallableInfo *callable_info) { gboolean may_return_null; GITypeInfo return_value_info; may_return_null = g_callable_info_may_return_null(callable_info); if (may_return_null && !argument->v_pointer) { return Qnil; } g_callable_info_load_return_type(callable_info, &return_value_info); return rb_gi_argument_to_ruby(argument, &return_value_info); }
static void handle_method_impl (ffi_cif *cif, gpointer result, gpointer *args, gpointer data) { MethodImpl *impl = (MethodImpl *) data; GIArgInfo arg_info; GITypeInfo type_info; GITypeInfo return_type_info; gint n_args, i; PeasExtensionWrapper *instance; GIArgument *arguments; GIArgument return_value; gboolean success; instance = *((PeasExtensionWrapper **) args[0]); g_assert (PEAS_IS_EXTENSION_WRAPPER (instance)); n_args = g_callable_info_get_n_args (impl->invoker_info); g_return_if_fail (n_args >= 0); arguments = g_newa (GIArgument, n_args); for (i = 0; i < n_args; i++) { g_callable_info_load_arg (impl->invoker_info, i, &arg_info); g_arg_info_load_type (&arg_info, &type_info); if (g_arg_info_get_direction (&arg_info) == GI_DIRECTION_IN) peas_gi_pointer_to_argument (&type_info, args[i + 1], &arguments[i]); else arguments[i].v_pointer = *((gpointer **) args[i + 1]); } success = peas_extension_wrapper_callv (instance, impl->interface_type, impl->invoker_info, impl->method_name, arguments, &return_value); if (!success) memset (&return_value, 0, sizeof (GIArgument)); g_callable_info_load_return_type (impl->invoker_info, &return_type_info); if (g_type_info_get_tag (&return_type_info) != GI_TYPE_TAG_VOID) peas_gi_argument_to_pointer (&return_type_info, &return_value, result); }
static gboolean source_func_p(GIArgInfo *info) { GITypeInfo type_info; GIBaseInfo *interface_info; GICallableInfo *callback_info; GITypeInfo return_type_info; GIArgInfo first_arg_info; GITypeInfo first_arg_type_info; g_arg_info_load_type(info, &type_info); if (g_type_info_get_tag(&type_info) != GI_TYPE_TAG_INTERFACE) { return FALSE; } interface_info = g_type_info_get_interface(&type_info); if (g_base_info_get_type(interface_info) != GI_INFO_TYPE_CALLBACK) { g_base_info_unref(interface_info); return FALSE; } callback_info = (GICallableInfo *)interface_info; g_callable_info_load_return_type(callback_info, &return_type_info); if (g_type_info_get_tag(&return_type_info) != GI_TYPE_TAG_BOOLEAN) { g_base_info_unref(interface_info); return FALSE; } if (g_callable_info_get_n_args(interface_info) != 1) { g_base_info_unref(interface_info); return FALSE; } g_callable_info_load_arg(interface_info, 0, &first_arg_info); g_arg_info_load_type(&first_arg_info, &first_arg_type_info); if (g_type_info_get_tag(&first_arg_type_info) != GI_TYPE_TAG_VOID) { g_base_info_unref(interface_info); return FALSE; } g_base_info_unref(interface_info); return TRUE; }
/** * peas_extension_call_valist: (skip) * @exten: A #PeasExtension. * @method_name: the name of the method that should be called. * @args: the arguments for the method. * * Call a method of the object behind @extension, using @args as arguments. * * See peas_extension_call() for more information. * * Return value: %TRUE on successful call. * * Deprecated: 1.2. Use the dynamically implemented interface instead. */ gboolean peas_extension_call_valist (PeasExtension *exten, const gchar *method_name, va_list args) { GICallableInfo *callable_info; GITypeInfo retval_info; GIArgument *gargs; GIArgument retval; gpointer retval_ptr; gboolean ret; gint n_args; g_return_val_if_fail (PEAS_IS_EXTENSION (exten), FALSE); g_return_val_if_fail (method_name != NULL, FALSE); callable_info = peas_gi_get_method_info (peas_extension_get_extension_type (exten), method_name); /* Already warned */ if (callable_info == NULL) return FALSE; n_args = g_callable_info_get_n_args (callable_info); g_return_val_if_fail (n_args >= 0, FALSE); gargs = g_newa (GIArgument, n_args); peas_gi_valist_to_arguments (callable_info, args, gargs, &retval_ptr); ret = peas_extension_callv (exten, method_name, gargs, &retval); if (retval_ptr != NULL) { g_callable_info_load_return_type (callable_info, &retval_info); peas_gi_argument_to_pointer (&retval_info, &retval, retval_ptr); } g_base_info_unref ((GIBaseInfo *) callable_info); return ret; }
static void fill_metadata_array_from_callable_info(GPtrArray *args_metadata, GICallableInfo *info) { GITypeInfo return_type_info; RBGIArgMetadata *array_length_metadata; gint array_length_index = -1; g_callable_info_load_return_type(info, &return_type_info); if (g_type_info_get_tag(&return_type_info) != GI_TYPE_TAG_ARRAY) { return; } array_length_index = g_type_info_get_array_length(&return_type_info); if (array_length_index == -1) { return; } array_length_metadata = g_ptr_array_index(args_metadata, array_length_index); array_length_metadata->array_length_p = TRUE; array_length_metadata->rb_arg_index = -1; }
static gboolean peas_extension_gjs_call (PeasExtensionWrapper *exten, GType exten_type, GICallableInfo *func_info, const gchar *method_name, GIArgument *args, GIArgument *retval) { PeasExtensionGjs *gexten = PEAS_EXTENSION_GJS (exten); gboolean success = FALSE; jsval js_method, js_retval; jsval *js_args; CachedArg *arg_cache; gint i, n_args, nth_out_arg; gint n_in_args = 0; gint n_out_args = 0; gint cached_args = 0; /* Fetch the JS method we want to call */ if (!JS_GetProperty (gexten->js_context, gexten->js_object, method_name, &js_method) || JSVAL_IS_VOID (js_method)) { g_warning ("Method '%s.%s' was not found", g_type_name (exten_type), method_name); return FALSE; } if (JSVAL_IS_NULL (js_method) || !JSVAL_IS_OBJECT (js_method) || !JS_ObjectIsFunction (gexten->js_context, JSVAL_TO_OBJECT (js_method))) { g_warning ("Method '%s.%s' in not a function", g_type_name (exten_type), method_name); return FALSE; } n_args = g_callable_info_get_n_args (func_info); if (n_args < 0) { g_warn_if_fail (n_args >= 0); return FALSE; } js_args = g_newa (jsval, n_args); arg_cache = g_newa (CachedArg, n_args + 1); /* Return value is an out arg */ g_callable_info_load_return_type (func_info, &arg_cache[0].type_info); if (g_type_info_get_tag (&arg_cache[0].type_info) != GI_TYPE_TAG_VOID) { ++n_out_args; arg_cache[cached_args++].ptr = &retval->v_pointer; } /* Handle the arguments */ for (i = 0; i < n_args; ++i, ++cached_args) { GIDirection direction; g_callable_info_load_arg (func_info, i, &arg_cache[cached_args].arg_info); direction = g_arg_info_get_direction (&arg_cache[cached_args].arg_info); g_arg_info_load_type (&arg_cache[cached_args].arg_info, &arg_cache[cached_args].type_info); if (direction == GI_DIRECTION_IN && !gjs_value_from_g_argument (gexten->js_context, &js_args[n_in_args++], &arg_cache[cached_args].type_info, &args[i], TRUE)) { g_warning ("Error failed to convert argument '%s'", g_base_info_get_name (&arg_cache[cached_args].arg_info)); return FALSE; } if (direction == GI_DIRECTION_INOUT) { GIArgument arg; peas_gi_pointer_to_argument (&arg_cache[cached_args].type_info, args[i].v_pointer, &arg); if (!gjs_value_from_g_argument (gexten->js_context, &js_args[n_in_args++], &arg_cache[cached_args].type_info, &arg, TRUE)) { g_warning ("Error failed to convert argument '%s'", g_base_info_get_name (&arg_cache[cached_args].arg_info)); return FALSE; } } if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT) { ++n_out_args; arg_cache[cached_args].ptr = args[i].v_pointer; } } success = JS_CallFunctionValue (gexten->js_context, gexten->js_object, js_method, n_in_args, js_args, &js_retval); if (!success) { if (!gjs_log_exception (gexten->js_context, NULL)) { g_warning ("Error while calling '%s.%s'", g_type_name (exten_type), method_name); } return FALSE; } /* First we need to release in argument */ for (i = 0; i < cached_args; ++i) { GIDirection direction; /* First cached argument may be the return value */ if (i == 0 && cached_args > n_args) continue; direction = g_arg_info_get_direction (&arg_cache[i].arg_info); if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT) { GITransfer transfer; transfer = g_arg_info_get_ownership_transfer (&arg_cache[i].arg_info); if (!gjs_g_argument_release_in_arg (gexten->js_context, transfer, &arg_cache[i].type_info, &args[i])) { g_warning ("Error failed to release IN argument '%s'", g_base_info_get_name (&arg_cache[i].arg_info)); } } } /* Check that we have a valid return value */ if (n_out_args > 1) { if (!JSVAL_IS_OBJECT (js_retval) || !JS_IsArrayObject (gexten->js_context, JSVAL_TO_OBJECT (js_retval))) { g_warning ("Error return value is not an array"); return FALSE; } } /* Set out arguments */ for (i = 0, nth_out_arg = 0; i < cached_args && success; ++i) { gboolean is_return_value; is_return_value = i == 0 && cached_args > n_args; /* Return value does not have a GIArgInfo and is always out */ if (!is_return_value) { GIDirection direction; direction = g_arg_info_get_direction (&arg_cache[i].arg_info); if (direction == GI_DIRECTION_IN) continue; } if (n_out_args == 1) { success = set_out_arg (gexten->js_context, func_info, is_return_value, &arg_cache[i].arg_info, &arg_cache[i].type_info, arg_cache[i].ptr, js_retval); break; } else if (n_out_args > 1) { jsval js_value; if (!JS_GetElement (gexten->js_context, JSVAL_TO_OBJECT (js_retval), nth_out_arg++, &js_value) || js_value == JSVAL_VOID) { g_warning ("Error failed to get out argument %i", nth_out_arg); return FALSE; } else { success = set_out_arg (gexten->js_context, func_info, is_return_value, &arg_cache[i].arg_info, &arg_cache[i].type_info, arg_cache[i].ptr, js_value); } } } return success; }
static gboolean peas_extension_seed_call (PeasExtensionWrapper *exten, const gchar *method_name, GIArgument *args, GIArgument *retval) { PeasExtensionSeed *sexten = PEAS_EXTENSION_SEED (exten); GType exten_type; SeedValue js_method; GICallableInfo *func_info; gint n_args, i; SeedValue *js_in_args; OutArg *out_args; SeedValue js_ret, val; SeedException exc = NULL; gchar *exc_string; gint n_in_args = 0; gint n_out_args = 0; GIArgument argument; g_return_val_if_fail (sexten->js_context != NULL, FALSE); g_return_val_if_fail (sexten->js_object != NULL, FALSE); exten_type = peas_extension_wrapper_get_extension_type (exten); /* Fetch the JS method we want to call */ js_method = seed_object_get_property (sexten->js_context, sexten->js_object, method_name); if (seed_value_is_undefined (sexten->js_context, js_method)) { g_warning ("Method '%s.%s' is not defined", g_type_name (exten_type), method_name); return FALSE; } /* We want to display an error if the method is defined but is not a function. */ if (!seed_value_is_function (sexten->js_context, js_method)) { g_warning ("Method '%s.%s' is not a function", g_type_name (exten_type), method_name); return FALSE; } /* Prepare the arguments */ func_info = peas_gi_get_method_info (exten_type, method_name); if (func_info == NULL) return FALSE; n_args = g_callable_info_get_n_args (func_info); g_return_val_if_fail (n_args >= 0, FALSE); js_in_args = g_newa (SeedValue, n_args); out_args = g_newa (OutArg, n_args + 1); /* We put the return value first in the out tuple, as it seems to be * the common behaviour for GI-based bindings */ g_callable_info_load_return_type (func_info, &out_args[0].type_info); if (g_type_info_get_tag (&out_args[0].type_info) != GI_TYPE_TAG_VOID) out_args[n_out_args++].ptr = &retval->v_pointer; /* Handle the other arguments */ for (i = 0; i < n_args && exc == NULL; i++) { GIArgInfo arg_info; GIDirection direction; g_callable_info_load_arg (func_info, i, &arg_info); direction = g_arg_info_get_direction (&arg_info); g_arg_info_load_type (&arg_info, &out_args[n_out_args].type_info); if (direction == GI_DIRECTION_IN) { js_in_args[n_in_args++] = seed_value_from_gi_argument (sexten->js_context, &args[i], &out_args[n_out_args].type_info, &exc); } if (direction == GI_DIRECTION_INOUT) { GIArgument arg; peas_gi_pointer_to_argument (&out_args[n_out_args].type_info, args[i].v_pointer, &arg); js_in_args[n_in_args++] = seed_value_from_gi_argument (sexten->js_context, &arg, &out_args[n_out_args].type_info, &exc); } if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT) out_args[n_out_args++].ptr = args[i].v_pointer; } if (exc != NULL) goto cleanup; js_ret = seed_object_call (sexten->js_context, js_method, sexten->js_object, n_in_args, js_in_args, &exc); if (exc != NULL) goto cleanup; if (n_out_args == 1) { if (seed_value_to_gi_argument (sexten->js_context, js_ret, &out_args[0].type_info, &argument, &exc)) { peas_gi_argument_to_pointer (&out_args[0].type_info, &argument, out_args[0].ptr); } } else if (n_out_args > 0 && seed_value_is_object (sexten->js_context, js_ret)) { for (i = 0; i < n_out_args && exc == NULL; i++) { val = seed_object_get_property_at_index (sexten->js_context, js_ret, i, exc); if (exc == NULL && seed_value_to_gi_argument (sexten->js_context, val, &out_args[i].type_info, &argument, &exc)) { peas_gi_argument_to_pointer (&out_args[i].type_info, &argument, out_args[i].ptr); } } } cleanup: g_base_info_unref ((GIBaseInfo *) func_info); if (exc == NULL) return TRUE; exc_string = seed_exception_to_string (sexten->js_context, exc); g_warning ("Seed Exception: %s", exc_string); g_free (exc_string); return FALSE; }
void peas_gi_valist_to_arguments (GICallableInfo *callable_info, va_list va_args, GIArgument *arguments, gpointer *return_value) { gint i, n_args; GIArgInfo arg_info; GITypeInfo arg_type_info; GITypeInfo retval_info; GIArgument *cur_arg; g_return_if_fail (callable_info != NULL); n_args = g_callable_info_get_n_args (callable_info); for (i = 0; i < n_args; i++) { g_callable_info_load_arg (callable_info, i, &arg_info); g_arg_info_load_type (&arg_info, &arg_type_info); cur_arg = &arguments[i]; switch (g_arg_info_get_direction (&arg_info)) { case GI_DIRECTION_IN: { /* Notes: According to GCC 4.4, * - int8, uint8, int16, uint16, short and ushort are promoted to int when passed through '...' * - float is promoted to double when passed through '...' */ switch (g_type_info_get_tag (&arg_type_info)) { case GI_TYPE_TAG_VOID: cur_arg->v_pointer = va_arg (va_args, gpointer); break; case GI_TYPE_TAG_BOOLEAN: cur_arg->v_boolean = va_arg (va_args, gboolean); break; case GI_TYPE_TAG_INT8: cur_arg->v_int8 = va_arg (va_args, gint); break; case GI_TYPE_TAG_UINT8: cur_arg->v_uint8 = va_arg (va_args, gint); break; case GI_TYPE_TAG_INT16: cur_arg->v_int16 = va_arg (va_args, gint); break; case GI_TYPE_TAG_UINT16: cur_arg->v_uint16 = va_arg (va_args, gint); break; case GI_TYPE_TAG_INT32: cur_arg->v_int32 = va_arg (va_args, gint32); break; case GI_TYPE_TAG_UNICHAR: case GI_TYPE_TAG_UINT32: cur_arg->v_uint32 = va_arg (va_args, guint32); break; case GI_TYPE_TAG_INT64: cur_arg->v_int64 = va_arg (va_args, gint64); break; case GI_TYPE_TAG_UINT64: cur_arg->v_uint64 = va_arg (va_args, guint64); break; case GI_TYPE_TAG_FLOAT: cur_arg->v_float = va_arg (va_args, gdouble); break; case GI_TYPE_TAG_DOUBLE: cur_arg->v_double = va_arg (va_args, gdouble); break; case GI_TYPE_TAG_GTYPE: /* apparently, GType is meant to be a gsize, from gobject/gtype.h in glib */ cur_arg->v_size = va_arg (va_args, GType); break; case GI_TYPE_TAG_UTF8: case GI_TYPE_TAG_FILENAME: cur_arg->v_string = va_arg (va_args, gchar *); break; case GI_TYPE_TAG_ARRAY: case GI_TYPE_TAG_INTERFACE: case GI_TYPE_TAG_GLIST: case GI_TYPE_TAG_GSLIST: case GI_TYPE_TAG_GHASH: case GI_TYPE_TAG_ERROR: cur_arg->v_pointer = va_arg (va_args, gpointer); break; default: g_warn_if_reached (); cur_arg->v_pointer = va_arg (va_args, gpointer); break; } break; } /* In the other cases, we expect we will always have a pointer. */ case GI_DIRECTION_INOUT: case GI_DIRECTION_OUT: cur_arg->v_pointer = va_arg (va_args, gpointer); break; } } if (return_value != NULL) { g_callable_info_load_return_type (callable_info, &retval_info); if (g_type_info_get_tag (&retval_info) != GI_TYPE_TAG_VOID) *return_value = va_arg (va_args, gpointer); else *return_value = NULL; } }