示例#1
0
static void
fill_metadata_callback(GPtrArray *args_metadata)
{
    guint i;

    for (i = 0; i < args_metadata->len; i++) {
        RBGIArgMetadata *metadata;
        GIArgInfo *arg_info;
        gint closure_index;
        gint destroy_index;

        metadata = g_ptr_array_index(args_metadata, i);

        arg_info = &(metadata->arg_info);
        closure_index = g_arg_info_get_closure(arg_info);
        if (closure_index != -1) {
            RBGIArgMetadata *closure_metadata;
            closure_metadata = g_ptr_array_index(args_metadata, closure_index);
            closure_metadata->closure_p = TRUE;
            metadata->closure_in_arg_index = closure_metadata->in_arg_index;
        }

        destroy_index = g_arg_info_get_destroy(arg_info);
        if (destroy_index != -1) {
            RBGIArgMetadata *destroy_metadata;
            destroy_metadata = g_ptr_array_index(args_metadata, destroy_index);
            destroy_metadata->destroy_p = TRUE;
            metadata->destroy_in_arg_index = destroy_metadata->in_arg_index;
        }
    }
}
static gpointer
sv_to_callback (GIArgInfo * arg_info,
                GITypeInfo * type_info,
                SV * sv,
                GPerlI11nInvocationInfo * invocation_info)
{
	GIBaseInfo *callback_interface_info;
	GPerlI11nPerlCallbackInfo *callback_info;
	GIScopeType scope;

	/* the destroy notify func is handled by _handle_automatic_arg */

	dwarn ("      Perl callback at %d (%s)\n",
	       invocation_info->current_pos,
	       g_base_info_get_name (arg_info));

	callback_interface_info = g_type_info_get_interface (type_info);
	callback_info = create_perl_callback_closure (callback_interface_info, sv);
	callback_info->data_pos = g_arg_info_get_closure (arg_info);
	callback_info->destroy_pos = g_arg_info_get_destroy (arg_info);
	callback_info->free_after_use = FALSE;
	g_base_info_unref (callback_interface_info);

	dwarn ("      Perl callback data at %d, destroy at %d\n",
	       callback_info->data_pos, callback_info->destroy_pos);

	scope = (!gperl_sv_is_defined (sv))
		? GI_SCOPE_TYPE_CALL
		: g_arg_info_get_scope (arg_info);
	switch (scope) {
	    case GI_SCOPE_TYPE_CALL:
		dwarn ("      Perl callback has scope 'call'\n");
		free_after_call (invocation_info,
		                 (GFunc) release_perl_callback, callback_info);
		break;
	    case GI_SCOPE_TYPE_NOTIFIED:
		dwarn ("      Perl callback has scope 'notified'\n");
		/* This case is already taken care of by the notify
		 * stuff above */
		break;
	    case GI_SCOPE_TYPE_ASYNC:
		dwarn ("      Perl callback has scope 'async'\n");
		/* FIXME: callback_info->free_after_use = TRUE; */
		break;
	    default:
		ccroak ("unhandled scope type %d encountered",
		       g_arg_info_get_scope (arg_info));
	}

	invocation_info->callback_infos =
		g_slist_prepend (invocation_info->callback_infos,
		                 callback_info);

	dwarn ("      returning Perl closure %p from info %p\n",
	       callback_info->closure, callback_info);
	return callback_info->closure;
}
示例#3
0
文件: marshal.c 项目: ntd/lgi
/* Marshalls given callable from Lua to C. */
static int
marshal_2c_callable (lua_State *L, GICallableInfo *ci, GIArgInfo *ai,
		     gpointer *callback, int narg, gboolean optional,
		     GICallableInfo *argci, void **args)
{
  int nret = 0;
  GIScopeType scope;
  gpointer user_data = NULL;
  gint nargs = 0;

  if (argci != NULL)
    nargs = g_callable_info_get_n_args (argci);

  /* Check 'nil' in optional case.  In this case, return NULL as
     callback. */
  if (lua_isnoneornil (L, narg))
    {
      if (optional)
	{
	  *callback = NULL;

	  /* Also set associated destroy handler to NULL, because some
	     callees tend to call it when left as garbage even when
	     main callback is NULL (gtk_menu_popup_for_device()
	     case). */
	  if (ai != NULL)
	    {
	      gint arg = g_arg_info_get_destroy (ai);
	      if (arg >= 0 && arg < nargs)
		((GIArgument *) args[arg])->v_pointer = NULL;
	    }
	  return 0;
	}
      else
	return luaL_argerror (L, narg, "nil is not allowed");
    }

  /* Check lightuserdata case; simply use that data if provided. */
  if (lua_islightuserdata (L, narg))
    {
      *callback = lua_touserdata (L, narg);
      return 0;
    }

  if (argci != NULL)
    {
      gint arg = g_arg_info_get_closure (ai);

      /* user_data block is already preallocated from function call. */
      g_assert (args != NULL);
      if (arg >= 0 && arg < nargs)
	{
	  user_data = ((GIArgument *) args[arg])->v_pointer;
	  arg = g_arg_info_get_destroy (ai);
	  if (arg >= 0 && arg < nargs)
	    ((GIArgument *) args[arg])->v_pointer = lgi_closure_destroy;
	}
    }

  scope = g_arg_info_get_scope (ai);
  if (user_data == NULL)
    {
      /* Closure without user_data block.  Create new data block,
	 setup destruction according to scope. */
      user_data = lgi_closure_allocate (L, 1);
      if (scope == GI_SCOPE_TYPE_CALL)
	{
	  *lgi_guard_create (L, lgi_closure_destroy) = user_data;
	  nret++;
	}
      else
	g_assert (scope == GI_SCOPE_TYPE_ASYNC);
    }

  /* Create the closure. */
  lgi_callable_create (L, ci, NULL);
  *callback = lgi_closure_create (L, user_data, narg,
				  scope == GI_SCOPE_TYPE_ASYNC);
  return nret;
}
示例#4
0
文件: marshal.c 项目: ntd/lgi
/* Marshalls single value from GLib/C to Lua.  Returns 1 if something
   was pushed to the stack. */
void
lgi_marshal_2lua (lua_State *L, GITypeInfo *ti, GIArgInfo *ai, GIDirection dir,
		  GITransfer transfer, gpointer source, int parent,
		  GICallableInfo *ci, void **args)
{
  gboolean own = (transfer != GI_TRANSFER_NOTHING);
  GITypeTag tag = g_type_info_get_tag (ti);
  GIArgument *arg = source;

  /* Make sure that parent is absolute index so that it is fixed even
     when we add/remove from the stack. */
  lgi_makeabs (L, parent);

  switch (tag)
    {
    case GI_TYPE_TAG_VOID:
      if (g_type_info_is_pointer (ti))
	/* Marshal pointer to simple lightuserdata. */
	lua_pushlightuserdata (L, arg->v_pointer);
      else
	lua_pushnil (L);
      break;

    case GI_TYPE_TAG_BOOLEAN:
      if (parent == LGI_PARENT_IS_RETVAL)
	{
	  ReturnUnion *ru = (ReturnUnion *) arg;
	  ru->arg.v_boolean = ru->s;
	}
      lua_pushboolean (L, arg->v_boolean);
      break;

    case GI_TYPE_TAG_FLOAT:
    case GI_TYPE_TAG_DOUBLE:
      g_return_if_fail (parent != LGI_PARENT_FORCE_POINTER);
      lua_pushnumber (L, (tag == GI_TYPE_TAG_FLOAT)
		      ? arg->v_float : arg->v_double);
      break;

    case GI_TYPE_TAG_UTF8:
    case GI_TYPE_TAG_FILENAME:
      {
	gchar *str = (parent == LGI_PARENT_FORCE_POINTER)
	  ? arg->v_pointer : arg->v_string;
	if (tag == GI_TYPE_TAG_FILENAME && str != NULL)
	  {
	    gchar *utf8 = g_filename_to_utf8 (str, -1, NULL, NULL, NULL);
	    lua_pushstring (L, utf8);
	    g_free (utf8);
	  }
	else
	  lua_pushstring (L, str);
	if (transfer == GI_TRANSFER_EVERYTHING)
	  g_free (str);
	break;
      }

    case GI_TYPE_TAG_INTERFACE:
      {
	GIBaseInfo *info = g_type_info_get_interface (ti);
	GIInfoType type = g_base_info_get_type (info);
	int info_guard;
	lgi_gi_info_new (L, info);
	info_guard = lua_gettop (L);
	switch (type)
	  {
	  case GI_INFO_TYPE_ENUM:
	  case GI_INFO_TYPE_FLAGS:
	    /* Prepare repotable of enum/flags on the stack. */
	    lgi_type_get_repotype (L, G_TYPE_INVALID, info);

	    /* Unmarshal the numeric value. */
	    marshal_2lua_int (L, g_enum_info_get_storage_type (info),
			      arg, parent);

	    /* Get symbolic value from the table. */
	    lua_gettable (L, -2);

	    /* Remove the table from the stack. */
	    lua_remove (L, -2);
	    break;

	  case GI_INFO_TYPE_STRUCT:
	  case GI_INFO_TYPE_UNION:
	    {
	      gboolean by_ref = parent == LGI_PARENT_FORCE_POINTER ||
		g_type_info_is_pointer (ti);
	      if (parent < LGI_PARENT_CALLER_ALLOC && by_ref)
		parent = 0;
	      lgi_type_get_repotype (L, G_TYPE_INVALID, info);
	      lgi_record_2lua (L, by_ref ? arg->v_pointer : source,
			       own, parent);
	      break;
	    }

	  case GI_INFO_TYPE_OBJECT:
	  case GI_INFO_TYPE_INTERFACE:
	    /* Avoid sinking for input arguments, because it wreaks
	       havoc to input arguments of vfunc callbacks during
	       InitiallyUnowned construction phase. */
	    lgi_object_2lua (L, arg->v_pointer, own, dir == GI_DIRECTION_IN);
	    break;

	  case GI_INFO_TYPE_CALLBACK:
	    if (arg->v_pointer == NULL)
	      lua_pushnil (L);
	    else
	      {
		lgi_callable_create (L, info, arg->v_pointer);
		if (ai != NULL && args != NULL)
		  {
		    gint closure = g_arg_info_get_closure (ai);
		    if (closure >= 0)
		      {
			/* Store context associated with the callback
			   to the callback object. */
			GIArgument *arg = args[closure];
			lua_pushlightuserdata (L, arg->v_pointer);
			lua_setfield (L, -2, "user_data");
		      }
		  }
	      }
	    break;

	  default:
	    g_assert_not_reached ();
	  }
	lua_remove (L, info_guard);
      }
      break;

    case GI_TYPE_TAG_ARRAY:
      {
	GIArrayType atype = g_type_info_get_array_type (ti);
	gssize size = -1;
	array_get_or_set_length (ti, &size, 0, ci, args);
	marshal_2lua_array (L, ti, dir, atype, transfer, arg->v_pointer, size,
			    parent);
      }
      break;

    case GI_TYPE_TAG_GSLIST:
    case GI_TYPE_TAG_GLIST:
      marshal_2lua_list (L, ti, dir, tag, transfer, arg->v_pointer);
      break;

    case GI_TYPE_TAG_GHASH:
      marshal_2lua_hash (L, ti, dir, transfer, arg->v_pointer);
      break;

    case GI_TYPE_TAG_ERROR:
      marshal_2lua_error (L, transfer, arg->v_pointer);
      break;

    default:
      marshal_2lua_int (L, tag, arg, parent);
    }
}
示例#5
0
static gboolean
pygi_arg_callback_setup_from_info (PyGICallbackCache  *arg_cache,
                                   GITypeInfo         *type_info,
                                   GIArgInfo          *arg_info,   /* may be null */
                                   GITransfer          transfer,
                                   PyGIDirection       direction,
                                   GIInterfaceInfo    *iface_info,
                                   PyGICallableCache  *callable_cache)
{
    PyGIArgCache *cache = (PyGIArgCache *)arg_cache;
    gssize child_offset = 0;

    if (!pygi_arg_base_setup ((PyGIArgCache *)arg_cache,
                              type_info,
                              arg_info,
                              transfer,
                              direction)) {
        return FALSE;
    }

    if (callable_cache != NULL)
        child_offset = callable_cache->args_offset;

    ( (PyGIArgCache *)arg_cache)->destroy_notify = (GDestroyNotify)_callback_cache_free_func;

    arg_cache->user_data_index = g_arg_info_get_closure (arg_info);
    if (arg_cache->user_data_index != -1)
        arg_cache->user_data_index += child_offset;

    arg_cache->destroy_notify_index = g_arg_info_get_destroy (arg_info);
    if (arg_cache->destroy_notify_index != -1)
        arg_cache->destroy_notify_index += child_offset;

    if (arg_cache->user_data_index >= 0) {
        PyGIArgCache *user_data_arg_cache = pygi_arg_cache_alloc ();
        user_data_arg_cache->meta_type = PYGI_META_ARG_TYPE_CHILD_WITH_PYARG;
        user_data_arg_cache->direction = direction;
        user_data_arg_cache->has_default = TRUE; /* always allow user data with a NULL default. */
        _pygi_callable_cache_set_arg (callable_cache, arg_cache->user_data_index,
                                      user_data_arg_cache);
    }

    if (arg_cache->destroy_notify_index >= 0) {
        PyGIArgCache *destroy_arg_cache = pygi_arg_cache_alloc ();
        destroy_arg_cache->meta_type = PYGI_META_ARG_TYPE_CHILD;
        destroy_arg_cache->direction = direction;
        _pygi_callable_cache_set_arg (callable_cache, arg_cache->destroy_notify_index,
                                      destroy_arg_cache);
    }

    arg_cache->scope = g_arg_info_get_scope (arg_info);
    g_base_info_ref( (GIBaseInfo *)iface_info);
    arg_cache->interface_info = iface_info;

    if (direction & PYGI_DIRECTION_FROM_PYTHON) {
        cache->from_py_marshaller = _pygi_marshal_from_py_interface_callback;
        cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_interface_callback;
    }

    if (direction & PYGI_DIRECTION_TO_PYTHON) {
        cache->to_py_marshaller = _pygi_marshal_to_py_interface_callback;
    }

    return TRUE;
}
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);
	}
示例#7
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;
}