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;
}
예제 #2
0
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;
        }
    }
}
예제 #3
0
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);
}
예제 #5
0
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;
}
예제 #6
0
/**
 * 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;
}
예제 #7
0
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;
}
예제 #8
0
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;
}
예제 #9
0
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;
}
예제 #10
0
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;
    }
}