Beispiel #1
0
// Is this going to leak later?
static gboolean
signature_from_method(SeedContext ctx,
		      SeedObject method_obj,
                      const char **signature,
		      SeedException *exception)
{
  SeedValue signature_value;

  if ((signature_value = seed_object_get_property(ctx,
						 method_obj, "outSignature")))
    {
      *signature = seed_value_to_string (ctx, signature_value, exception);
      if (*signature == NULL)
	{
	  return FALSE;
        }
    }
  else
    {
      /* We default to a{sv} */
      *signature = "a{sv}";
    }

  return TRUE;
}
static void
peas_extension_seed_get_property (GObject    *object,
                                  guint       prop_id,
                                  GValue     *value,
                                  GParamSpec *pspec)
{
  PeasExtensionSeed *sexten = PEAS_EXTENSION_SEED (object);
  SeedValue seed_value;
  SeedException exc = NULL;
  gchar *prop_name;

  /* Don't add properties as they could shadow the instance's */

  prop_name = convert_property_name (pspec->name);

  seed_value = seed_object_get_property (sexten->js_context, sexten->js_object,
                                         prop_name);

  g_free (prop_name);


  seed_value_to_gvalue (sexten->js_context, seed_value,
                        pspec->value_type, value, &exc);

  if (exc != NULL)
    {
      gchar *exc_string;

      exc_string = seed_exception_to_string (sexten->js_context, exc);
      g_warning ("Seed Exception: %s", exc_string);

      g_free (exc_string);
    }
}
Beispiel #3
0
static SeedObject
find_js_property_by_path(SeedContext ctx,
			 SeedObject root_obj,
                         const gchar *path)
{
    gchar **elements;
    gint i;
    SeedObject obj;

    elements = g_strsplit(path, "/", -1);
    obj = root_obj;

    /* g_strsplit returns empty string for the first
     * '/' so we start with elements[1]
     */
    for (i = 1; elements[i] != NULL; ++i)
      {
        obj = seed_object_get_property(ctx, obj, elements[i]);

	if (seed_value_is_undefined (ctx, obj) ||
	    !seed_value_is_object (ctx, obj))
	  {
	    obj = NULL;
	    break;
	  }
      }

    g_strfreev(elements);

    return obj;
}
Beispiel #4
0
static void
test_extension_seed_plugin_info (PeasEngine *engine)
{
  PeasPluginInfo *info;
  PeasExtension *extension;
  PeasExtensionSeed *sexten;
  SeedValue seed_value;
  GValue gvalue = { 0 };

  info = peas_engine_get_plugin_info (engine, "extension-seed");

  g_assert (peas_engine_load_plugin (engine, info));

  extension = peas_engine_create_extension (engine, info,
                                            INTROSPECTION_TYPE_CALLABLE,
                                            NULL);

  g_assert (PEAS_IS_EXTENSION (extension));

  sexten = (PeasExtensionSeed *) extension;
  seed_value = seed_object_get_property (sexten->js_context, sexten->js_object,
                                         "plugin_info");

  g_assert (seed_value_to_gvalue (sexten->js_context, seed_value,
                                  PEAS_TYPE_PLUGIN_INFO, &gvalue,
                                  NULL));

  g_assert (g_value_get_boxed (&gvalue) == info);

  g_value_unset (&gvalue);

  g_object_unref (extension);
}
Beispiel #5
0
static void
seed_builder_connect_func (GtkBuilder *builder,
			   GObject *object,
			   const gchar *signal_name,
			   const gchar *handler_name,
			   GObject *connect_object,
			   GConnectFlags flags,
			   gpointer user_data)
{
  SeedContext ctx;
  SeedObject obj, func;
  builder_ud *priv = (builder_ud *)user_data;
  GClosure *closure;

  ctx = priv->ctx;
  obj = priv->obj;

  func = seed_object_get_property (ctx, obj, handler_name);
  if (!seed_value_is_object (ctx, func) || !seed_value_is_function (ctx, func))
    return;

  closure = seed_closure_new (ctx, func, priv->user_data,
                              "signal handler (GtkBuilder)");
  if (connect_object != NULL)
    g_object_watch_closure (connect_object, closure);

  g_signal_connect_closure (object, signal_name, closure, FALSE);
}
Beispiel #6
0
SeedObject
gjs_compat_define_gi_stuff(SeedEngine* eng)
{
    SeedContext context = eng->context;
    SeedObject module;
    gboolean ret;

    module = seed_make_object(context, seed_create_class(&system_def), NULL);

    SeedValue seed = seed_object_get_property(context, eng->global, "Seed");
    SeedValue argv = seed_object_get_property(context, seed, "argv");

    ret = seed_object_set_property(
      context, module, "version",
      (SeedValue) seed_value_from_int(context, GJS_COMPAT_VERSION, NULL));

    return module;
}
Beispiel #7
0
/**
 * seed_exception_get_line:
 * @ctx: A #SeedContext.
 * @exception: A reference to a #SeedException.
 *
 * Retrieves the line number the given exception was thrown from; keep in mind
 * that exceptions created from C have an undefined line number.
 *
 * Return value: A #guint representing the line number from which @exception
 *               was thrown.
 *
 */
guint
seed_exception_get_line (JSContextRef ctx, JSValueRef e)
{
  JSValueRef line;
  g_assert ((e));
  if (!JSValueIsObject (ctx, e))
    return 0;
  line = seed_object_get_property (ctx, (JSObjectRef) e, "line");
  return seed_value_to_uint (ctx, line, NULL);
}
Beispiel #8
0
/**
 * seed_exception_get_file:
 * @ctx: A #SeedContext.
 * @exception: A reference to a #SeedException.
 *
 * Retrieves the file name the given exception was thrown from; keep in mind
 * that exceptions created from C have an undefined file name.
 *
 * Return value: A #gchar* representing the name of the file from which
 *               @exception was thrown.
 *
 */
gchar *
seed_exception_get_file (JSContextRef ctx, JSValueRef e)
{
  JSValueRef line;
  g_assert ((e));
  if (!JSValueIsObject (ctx, e))
    return 0;
  line = seed_object_get_property (ctx, (JSObjectRef) e, "sourceURL");
  return seed_value_to_string (ctx, line, 0);
}
Beispiel #9
0
/**
 * seed_exception_get_message:
 * @ctx: A #SeedContext.
 * @exception: A reference to a #SeedException.
 *
 * Retrieves the message of the given exception; this should be a
 * human-readable string describing the exception enough that a developer
 * could utilize the message in order to determine where to look to debug
 * the problem.
 *
 * Return value: A #gchar* representing the detailed message of @exception.
 *
 */
gchar *
seed_exception_get_message (JSContextRef ctx, JSValueRef e)
{
  JSValueRef name;
  g_assert ((e));
  if (!JSValueIsObject (ctx, e))
    return 0;

  name = seed_object_get_property (ctx, (JSObjectRef) e, "message");
  return seed_value_to_string (ctx, name, NULL);
}
Beispiel #10
0
static gboolean
find_method(SeedContext ctx,
	    SeedObject obj,
            const gchar *method_name,
            SeedValue      *method_value)
{
  *method_value = seed_object_get_property (ctx, obj, method_name);
    if (seed_value_is_undefined (ctx, *method_value) ||
	!seed_value_is_object (ctx, *method_value))
      return FALSE;

  return TRUE;
}
Beispiel #11
0
static gboolean
seed_ffi_build_signature (SeedContext ctx,
			  seed_ffi_function_priv *priv,
			  SeedObject sig,
			  SeedException *exception)
{
  SeedObject arguments;
  SeedValue ret_type_ref, length_ref;
  guint length, i;
  
  arguments = seed_object_get_property (ctx, sig, "arguments");
  ret_type_ref = seed_object_get_property (ctx, sig, "returns");
  
  if (!seed_value_is_object (ctx, arguments))
    {
      seed_make_exception (ctx, exception, "FFIError", 
			   "Signature arguments member must be an array describing argument types");
      return FALSE;
    }
  length_ref = seed_object_get_property (ctx, arguments, "length");
  
  length = seed_value_to_uint (ctx, length_ref, exception);
  priv->n_args = length;
  priv->args = g_slice_alloc (length * sizeof (GType));
  
  for (i = 0; i < length; i++)
    {
      SeedValue type = seed_object_get_property_at_index (ctx, arguments, 
							  i, exception);
      priv->args[i] = seed_value_to_int (ctx, type, exception);
    }
  priv->ret_val = seed_value_to_int (ctx, ret_type_ref, exception);
  
  priv->signature_obj = sig;
  seed_value_protect (ctx, sig);

  return TRUE;
}
Beispiel #12
0
static gboolean
dbus_reply_from_exception_and_sender(SeedContext  ctx,
                                     const gchar  *sender,
                                     dbus_uint32_t serial,
                                     DBusMessage **reply_p,
				     SeedException *exception)
{
  SeedValue name_val;
  gchar *s;
  const gchar *name = NULL;


  *reply_p = NULL;

  if (seed_value_is_undefined (ctx, *exception) ||
      seed_value_is_null (ctx, *exception) ||
      !seed_value_is_object (ctx, *exception))
    return FALSE;

  name_val = seed_object_get_property(ctx, *exception, "dbusErrorName");
  name = seed_value_to_string (ctx, name_val, NULL);

  s = seed_exception_to_string (ctx, *exception);
  g_warning("JS exception we will send as dbus reply to %s: %s",
	    sender,
	    s);

    *reply_p = dbus_message_new(DBUS_MESSAGE_TYPE_ERROR);
    dbus_message_set_destination(*reply_p, sender);
    dbus_message_set_reply_serial(*reply_p, serial);
    dbus_message_set_no_reply(*reply_p, TRUE);
    dbus_message_set_error_name(*reply_p, name ? name : DBUS_ERROR_FAILED);
    if (s != NULL) {
         DBusMessageIter iter;

        dbus_message_iter_init_append(*reply_p, &iter);

        if (!dbus_message_iter_append_basic(&iter,
                                            DBUS_TYPE_STRING,
                                            &s)) {
            dbus_message_unref(*reply_p);
            g_free(s);
            return FALSE;
        }
        g_free(s);
    }

    return TRUE;
}
static gboolean
peas_plugin_loader_seed_provides_extension  (PeasPluginLoader *loader,
                                             PeasPluginInfo   *info,
                                             GType             exten_type)
{
  PeasPluginLoaderSeed *sloader = PEAS_PLUGIN_LOADER_SEED (loader);
  SeedInfo *sinfo;
  SeedValue extension;

  sinfo = (SeedInfo *) g_hash_table_lookup (sloader->loaded_plugins, info);

  extension = seed_object_get_property (sinfo->context,
                                        sinfo->extensions,
                                        g_type_name (exten_type));
  return extension && seed_value_is_object (sinfo->context, extension);
}
static gboolean
peas_plugin_loader_seed_load (PeasPluginLoader *loader,
                              PeasPluginInfo   *info)
{
  PeasPluginLoaderSeed *sloader = PEAS_PLUGIN_LOADER_SEED (loader);
  SeedContext context;
  gchar *script;
  SeedException exc = NULL;
  SeedObject global, extensions;
  SeedInfo *sinfo;

  context = seed_context_create (seed->group, NULL);

  seed_prepare_global_context (context);
  script = get_script_for_plugin_info (info, context);

  seed_simple_evaluate (context, script, &exc);
  g_free (script);

  if (exc)
    {
      gchar *exc_string = seed_exception_to_string (context, exc);
      g_warning ("Seed Exception: %s", exc_string);
      g_free (exc_string);
      seed_context_unref (context);
      return FALSE;
    }

  global = seed_context_get_global_object (context);
  extensions = seed_object_get_property (context, global, "extensions");

  if (seed_value_is_object (context, extensions))
    {
      sinfo = (SeedInfo *) g_slice_new (SeedInfo);
      sinfo->context = context;
      sinfo->extensions = extensions;
      seed_context_ref (context);
      seed_value_protect (context, extensions);

      g_hash_table_insert (sloader->loaded_plugins, info, sinfo);
    }

  seed_context_unref (context);

  return TRUE;
}
Beispiel #15
0
gulong
seed_gobject_signal_connect (JSContextRef ctx,
			     const gchar * signal_name,
			     GObject * on_obj,
			     JSObjectRef func,
			     JSObjectRef this_obj, JSObjectRef user_data)
{
  GSignalQuery query;
  GClosure *closure;

  if (g_str_has_prefix (signal_name, "notify::"))
    g_signal_query (g_signal_lookup ("notify", G_OBJECT_TYPE (on_obj)),
                    &query);
  else
    g_signal_query (g_signal_lookup (signal_name, G_OBJECT_TYPE (on_obj)),
                    &query);

#ifdef SEED_ENABLE_DEBUG
  {
    guint function_arity = seed_value_to_uint (ctx,
					       seed_object_get_property (ctx,
									 func,
									 "length"),
					       NULL);
    if (function_arity != query.n_params)
      {
	SEED_MARK ();
	SEED_NOTE (SIGNAL,
		   "Connecting signal: %s. Function has arity %d, signal expects %d",
		   query.signal_name, function_arity, query.n_params);
	SEED_MARK ();
      }
  }
#endif

  closure = seed_closure_new_for_signal (ctx, func, user_data, "signal handler", query.signal_id);

  // This seems wrong...
  ((SeedClosure *) closure)->return_type = query.return_type;
  return g_signal_connect_closure (on_obj, signal_name, closure, FALSE);
}
Beispiel #16
0
static SeedValue
async_call_callback(SeedContext ctx,
		    SeedObject function,
		    SeedObject this_object,
		    gsize argument_count,
		    const SeedValue arguments[],
		    SeedException *exception)
{
    DBusConnection *connection;
    DBusBusType which_bus;
    DBusMessage *reply;
    const char *sender;
    dbus_uint32_t serial;
    SeedValue prop_value, retval;
    const char *signature;
    gboolean thrown;

    retval = seed_make_undefined (ctx);
    reply = NULL;
    thrown = FALSE;

    prop_value = seed_object_get_property (ctx, function, "_dbusSender");
    sender = seed_value_to_string (ctx, prop_value, exception);
    if (!sender)
      return FALSE;

    prop_value = seed_object_get_property(ctx,
                                     function,
					  "_dbusSerial");


    serial = seed_value_to_uint (ctx, prop_value, exception);
    prop_value = seed_object_get_property(ctx,
					  function,
					  "_dbusBusType");

    which_bus = seed_value_to_int(ctx, prop_value, exception);

    /* From now we have enough information to
     * send the exception back to the callee so we'll do so
     */
    prop_value = seed_object_get_property(ctx,
					  function,
					  "_dbusOutSignature");

    signature = seed_value_to_string (ctx, prop_value, exception);
    if (!signature)
        return FALSE;

    if (argument_count != 1) {
      seed_make_exception(ctx, exception, "ArgumentError",
			  "The callback to async DBus calls takes one argument, "
			  "the return value or array of return values");
        thrown = TRUE;
        goto out;
    }

    reply = build_reply_from_jsval(ctx,
                                   signature,
                                   sender,
                                   serial,
                                   arguments[0],
				   exception);

out:
    if (!reply && thrown)
      {
	if (!dbus_reply_from_exception_and_sender(ctx, sender, serial, &reply, exception))
	  g_warning("dbus method invocation failed but no exception was set?");
      }

    if (reply)
      {
        big_dbus_add_bus_weakref(which_bus, &connection);
        if (!connection)
	  {
            seed_make_exception(ctx, exception, "DBusError",
				"We were disconnected from the bus before the callback "
				"to some async remote call was called");
            dbus_message_unref(reply);
            big_dbus_remove_bus_weakref(which_bus, &connection);
            return FALSE;
	  }
        dbus_connection_send(connection, reply, NULL);
        big_dbus_remove_bus_weakref(which_bus, &connection);
        dbus_message_unref(reply);
    }

    return retval;
}
static PeasExtension *
peas_plugin_loader_seed_create_extension (PeasPluginLoader *loader,
                                          PeasPluginInfo   *info,
                                          GType             exten_type,
                                          guint             n_parameters,
                                          GParameter       *parameters)
{
  PeasPluginLoaderSeed *sloader = PEAS_PLUGIN_LOADER_SEED (loader);
  SeedInfo *sinfo;
  SeedValue extension_ctor, extension;
  guint i, j;
  SeedValue value;
  GValue gvalue = { 0 };
  GArray *interfaces;
  gchar **property_names;

  sinfo = (SeedInfo *) g_hash_table_lookup (sloader->loaded_plugins, info);

  /* FIXME: instantiate new object and pass the parameters */
  extension_ctor = seed_object_get_property (sinfo->context,
                                             sinfo->extensions,
                                             g_type_name (exten_type));
  if (!extension_ctor ||
      seed_value_is_undefined (sinfo->context, extension_ctor) ||
      seed_value_is_null (sinfo->context, extension_ctor))
    return NULL;

  if (!seed_value_is_object (sinfo->context, extension_ctor))
    {
      g_warning ("Extension '%s' in plugin '%s' is not a Seed object",
                 g_type_name (exten_type), peas_plugin_info_get_module_name (info));
      return NULL;
    }

  /* Instantiate the ctor object into a new specific object. */
  extension = JSObjectCallAsConstructor (sinfo->context, extension_ctor, 0, NULL, NULL);

  if (extension == NULL)
    {
#ifndef PEAS_DISABLE_DEPRECATED_FEATURES
      gchar **property_names;

      g_warning ("DEPRECATION WARNING: Extension '%s' in plugin '%s' is not a valid "
                 "constructor function. Support for extension initialization by array "
                 "copy will be dropped soon.",
                 g_type_name (exten_type), peas_plugin_info_get_module_name (info));

      extension = seed_make_object (sinfo->context, NULL, NULL);
      property_names = seed_object_copy_property_names (sinfo->context,
                                                        extension_ctor);
      for (i = 0; property_names[i] != NULL; i++)
        {
          SeedValue value;
          value = seed_object_get_property (sinfo->context,
                                            extension_ctor,
                                            property_names[i]);
          seed_object_set_property (sinfo->context,
                                    extension,
                                    property_names[i],
                                    value);
        }

        g_strfreev (property_names);
#else
      g_warning ("Extension '%s' in plugin '%s' is not a valid constructor",
                 g_type_name (exten_type), peas_plugin_info_get_module_name (info));
      return NULL;
#endif
    }

  /* Set the properties as well, cannot use
   * g_object_set_property() because it may be construct-only
   */
  for (i = 0; i < n_parameters; i++)
    {
      gchar *key;

      /* We want to normalize the property names to have a '_' instead of the
       * conventional '-', to make them accessible through this.property_name */
      key = g_strdup (parameters[i].name);
      for (j = 0; key[j] != '\0'; j++)
        {
          if (key[j] == '-')
            key[j] = '_';
        }

      value = seed_value_from_gvalue (sinfo->context,
                                      &parameters[i].value,
                                      NULL);
      seed_object_set_property (sinfo->context,
                                extension,
                                key,
                                value);

      g_free (key);
    }

  /* Set the plugin info as an attribute of the instance */
  g_value_init (&gvalue, PEAS_TYPE_PLUGIN_INFO);
  g_value_set_boxed (&gvalue, info);

  value = seed_value_from_gvalue (sinfo->context, &gvalue, NULL);
  seed_object_set_property (sinfo->context, extension, "plugin_info", value);

  g_value_unset (&gvalue);


  /* Do not add exten_type as it will be added below */
  interfaces = g_array_new (TRUE, FALSE, sizeof (GType));

  property_names = seed_object_copy_property_names (sinfo->context,
                                                    sinfo->extensions);

  for (i = 0; property_names[i] != NULL; ++i)
    {
      gchar *property_name = property_names[i];
      SeedValue *prop_extension_ctor;
      GType the_type;

      prop_extension_ctor = seed_object_get_property (sinfo->context,
                                                      sinfo->extensions,
                                                      property_name);

      if (prop_extension_ctor != extension_ctor)
        continue;

      if (!seed_value_is_object (sinfo->context, extension_ctor))
        {
          g_warning ("Extension '%s' in plugin '%s' is not a Seed object",
                     property_name, peas_plugin_info_get_module_name (info));
          continue;
        }

      the_type = peas_gi_get_type_from_name (property_name);

      if (the_type == G_TYPE_INVALID)
        {
          g_warning ("Could not find GType for '%s', "
                     "did you forget to import it?", property_name);
        }
      else
        {
          g_array_append_val (interfaces, the_type);
        }
    }

  g_array_sort (interfaces, (GCompareFunc) prerequisites_sort);

  g_strfreev (property_names);

  return peas_extension_seed_new (exten_type,
                                  (GType *) g_array_free (interfaces, FALSE),
                                  sinfo->context, extension);
}
static gboolean
peas_plugin_loader_seed_load (PeasPluginLoader *loader,
                              PeasPluginInfo   *info)
{
  PeasPluginLoaderSeed *sloader = PEAS_PLUGIN_LOADER_SEED (loader);
  gchar *filename;
  gchar *content;
  GError *error = NULL;
  SeedContext context;
  SeedScript *script;
  SeedException exc = NULL;
  SeedObject global, extensions;
  SeedInfo *sinfo;

  filename = get_script_filename_for_plugin_info (info);

  g_debug ("Seed script filename is '%s'", filename);

  if (!g_file_get_contents (filename, &content, NULL, &error))
    {
      g_warning ("Error: %s", error->message);
      g_error_free (error);
      g_free (filename);
      return FALSE;
    }

  context = seed_context_create (seed->group, NULL);
  seed_prepare_global_context (context);

  script = seed_make_script (context, content, filename, 0);

  seed_evaluate (context, script, NULL);
  exc = seed_script_exception (script);

  seed_script_destroy (script);
  g_free (content);
  g_free (filename);

  if (exc)
    {
      gchar *exc_string = seed_exception_to_string (context, exc);
      g_warning ("Seed Exception: %s", exc_string);
      g_free (exc_string);
      seed_context_unref (context);
      return FALSE;
    }

  global = seed_context_get_global_object (context);
  extensions = seed_object_get_property (context, global, "extensions");

  if (seed_value_is_object (context, extensions))
    {
      sinfo = (SeedInfo *) g_slice_new (SeedInfo);
      sinfo->context = context;
      sinfo->extensions = extensions;
      seed_value_protect (context, extensions);

      g_hash_table_insert (sloader->loaded_plugins, info, sinfo);
      return TRUE;
    }
  else
    {
      g_warning ("extensions is not an object in plugin '%s'",
                 peas_plugin_info_get_module_name (info));
      seed_context_unref (context);
      return FALSE;
    }
}
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;
}