Exemplo n.º 1
0
static void
in_arguments_to_ruby(GArray *in_args,
                     GArray *out_args,
                     GPtrArray *args_metadata,
                     GArray *rb_args)
{
    guint i;

    for (i = 0; i < args_metadata->len; i++) {
        RBGIArgMetadata *metadata;
        GIArgument *argument;
        GITypeInfo *type_info;
        VALUE rb_arg;

        metadata = g_ptr_array_index(args_metadata, i);

        if (metadata->direction == GI_DIRECTION_OUT) {
            continue;
        }
        if (metadata->closure_p) {
            continue;
        }

        argument = &g_array_index(in_args, GIArgument, metadata->in_arg_index);
        type_info = g_arg_info_get_type(&(metadata->arg_info));
        rb_arg = GI_ARGUMENT2RVAL(argument,
                                  FALSE,
                                  type_info,
                                  in_args,
                                  out_args,
                                  args_metadata);
        g_array_append_val(rb_args, rb_arg);
    }
}
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;
}
Exemplo n.º 3
0
static void
out_arguments_to_raw_data(GICallableInfo *callable_info,
                          VALUE rb_results,
                          void *result,
                          GArray *out_args,
                          GPtrArray *args_metadata)
{
    int i_rb_result = 0;
    guint i;
    GITypeInfo *return_type_info;
    GITypeTag return_type_tag;

    return_type_info = g_callable_info_get_return_type(callable_info);
    return_type_tag = g_type_info_get_tag(return_type_info);
    if (return_type_tag != GI_TYPE_TAG_VOID) {
        GITransfer transfer;
        transfer = g_callable_info_get_caller_owns(callable_info);
        if (out_args->len == 0) {
            VALUE rb_return_value = rb_results;
            out_argument_to_raw_data(callable_info,
                                     rb_return_value,
                                     result,
                                     return_type_info,
                                     transfer,
                                     TRUE);
        } else {
            out_argument_to_raw_data(callable_info,
                                     RARRAY_AREF(rb_results, i_rb_result),
                                     result,
                                     return_type_info,
                                     transfer,
                                     TRUE);
            i_rb_result++;
        }
    }
    g_base_info_unref(return_type_info);

    for (i = 0; i < args_metadata->len; i++) {
        RBGIArgMetadata *metadata;
        GIArgument *argument;
        GITypeInfo *type_info;
        GITransfer transfer;

        metadata = g_ptr_array_index(args_metadata, i);

        /* TODO: support GI_DIRECTION_INOUT */
        if (metadata->direction != GI_DIRECTION_OUT) {
            continue;
        }

        argument = &g_array_index(out_args, GIArgument, metadata->out_arg_index);
        type_info = g_arg_info_get_type(&(metadata->arg_info));
        transfer = g_arg_info_get_ownership_transfer(&(metadata->arg_info));
        out_argument_to_raw_data(callable_info,
                                 RARRAY_AREF(rb_results, i_rb_result),
                                 argument->v_pointer,
                                 type_info,
                                 transfer,
                                 FALSE);
        i_rb_result++;
        g_base_info_unref(type_info);
    }
}
Exemplo n.º 4
0
static void
argument_from_raw_data(GICallableInfo *callable_info,
                       void **raw_args,
                       GArray *in_args,
                       GArray *out_args,
                       GPtrArray *args_metadata,
                       guint i)
{
    RBGIArgMetadata *metadata;
    GIArgument *argument;
    GITypeInfo *type_info;
    GITypeTag type_tag;

    metadata = g_ptr_array_index(args_metadata, i);

    if (metadata->direction == GI_DIRECTION_INOUT) {
        argument = &g_array_index(in_args, GIArgument, metadata->in_arg_index);
        argument->v_pointer = *((gpointer *)(raw_args[i]));
        return;
    } else if (metadata->direction == GI_DIRECTION_OUT) {
        argument = &g_array_index(out_args, GIArgument, metadata->out_arg_index);
        argument->v_pointer = *((gpointer *)(raw_args[i]));
        return;
    }

    argument = &g_array_index(in_args, GIArgument, metadata->in_arg_index);
    type_info = g_arg_info_get_type(&(metadata->arg_info));
    type_tag = g_type_info_get_tag(type_info);

    switch (type_tag) {
      case GI_TYPE_TAG_VOID:
        argument->v_pointer = *((gpointer *)(raw_args[i]));
        break;
      case GI_TYPE_TAG_BOOLEAN:
        argument->v_boolean = *((gboolean *)(raw_args[i]));
        break;
      case GI_TYPE_TAG_INT8:
        argument->v_int8 = *((gint8 *)(raw_args[i]));
        break;
      case GI_TYPE_TAG_UINT8:
        argument->v_uint8 = *((guint8 *)(raw_args[i]));
        break;
      case GI_TYPE_TAG_INT16:
        argument->v_int16 = *((gint16 *)(raw_args[i]));
        break;
      case GI_TYPE_TAG_UINT16:
        argument->v_uint16 = *((guint16 *)(raw_args[i]));
        break;
      case GI_TYPE_TAG_INT32:
        argument->v_int32 = *((gint32 *)(raw_args[i]));
        break;
      case GI_TYPE_TAG_UINT32:
        argument->v_uint32 = *((guint32 *)(raw_args[i]));
        break;
      case GI_TYPE_TAG_INT64:
        argument->v_int64 = *((gint64 *)(raw_args[i]));
        break;
      case GI_TYPE_TAG_UINT64:
        argument->v_uint64 = *((guint64 *)(raw_args[i]));
        break;
      case GI_TYPE_TAG_FLOAT:
        argument->v_float = *((gfloat *)(raw_args[i]));
        break;
      case GI_TYPE_TAG_DOUBLE:
        argument->v_double = *((gdouble *)(raw_args[i]));
        break;
      case GI_TYPE_TAG_GTYPE:
        argument->v_size = *((gsize *)(raw_args[i]));
        break;
      case GI_TYPE_TAG_UTF8:
      case GI_TYPE_TAG_FILENAME:
        argument->v_string = *((gchar **)(raw_args[i]));
        break;
      case GI_TYPE_TAG_ARRAY:
        argument->v_pointer = *((gpointer *)(raw_args[i]));
        break;
      case GI_TYPE_TAG_INTERFACE:
        argument_from_raw_data_interface(callable_info,
                                         raw_args[i],
                                         argument,
                                         type_info);
        break;
      case GI_TYPE_TAG_GLIST:
      case GI_TYPE_TAG_GSLIST:
      case GI_TYPE_TAG_GHASH:
        argument->v_pointer = *((gpointer *)(raw_args[i]));
        break;
      case GI_TYPE_TAG_ERROR:
        argument->v_pointer = *((GError **)(raw_args[i]));
        break;
      case GI_TYPE_TAG_UNICHAR:
        argument->v_uint32 = *((gunichar *)(raw_args[i]));
        break;
      default:
        g_assert_not_reached();
        break;
    }

    g_base_info_unref(type_info);
}
Exemplo n.º 5
0
static void
in_callback_argument_from_ruby(RBGIArgMetadata *metadata, GArray *in_args)
{
    gpointer callback_function;
    GIArgInfo *arg_info;
    GIArgument *callback_argument;
    GIArgument *closure_argument = NULL;
    GIArgument *destroy_argument = NULL;
    RBGICallback *callback = NULL;

    arg_info = &(metadata->arg_info);

    callback_argument = &(g_array_index(in_args,
                                        GIArgument,
                                        metadata->in_arg_index));
    if (metadata->closure_in_arg_index != -1) {
        closure_argument = &(g_array_index(in_args,
                                           GIArgument,
                                           metadata->closure_in_arg_index));
    }
    if (metadata->destroy_in_arg_index != -1) {
        destroy_argument = &(g_array_index(in_args,
                                           GIArgument,
                                           metadata->destroy_in_arg_index));
    }

    if (!rb_block_given_p() && g_arg_info_may_be_null(arg_info)) {
        callback_argument->v_pointer = NULL;
        if (closure_argument) {
            closure_argument->v_pointer = NULL;
        }
        if (destroy_argument) {
            destroy_argument->v_pointer = NULL;
        }
        return;
    }

    callback_function = find_callback_function(arg_info);
    if (callback_function) {
        callback_argument->v_pointer = callback_function;
    } else {
        callback = RB_ZALLOC(RBGICallback);
        callback->type_info = g_arg_info_get_type(arg_info);
        callback->callback_info = g_type_info_get_interface(callback->type_info);
        callback->closure =
            g_callable_info_prepare_closure(callback->callback_info,
                                            &(callback->cif),
                                            ffi_closure_callback,
                                            callback);
        callback_argument->v_pointer = callback->closure;
    }

    if (closure_argument) {
        RBGICallbackData *callback_data;

        callback_data = ALLOC(RBGICallbackData);
        callback_data->callback = callback;
        callback_data->metadata = metadata;
        callback_data->rb_callback = rb_block_proc();
        callback_data_guard_from_gc(callback_data);
        closure_argument->v_pointer = callback_data;
    }

    if (destroy_argument) {
        destroy_argument->v_pointer = destroy_notify;
    }
}
/**
 * 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;
}
Exemplo n.º 7
0
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();
    }
}
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);
	}
Exemplo n.º 9
0
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;
}
Exemplo n.º 10
0
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;
}
Exemplo n.º 11
0
/**
 * 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;
}