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 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; }