2
* Handle void* wrappers.
3
* This is part of lua-gtk.
8
#include <string.h> // strcmp
10
#define LUAGTK_WRAPPER "void* wrapper"
12
#define VALUE_WRAPPER_MAGIC1 0x89737948
13
#define VALUE_WRAPPER_MAGIC2 0xa0d7dfaa
15
struct value_wrapper {
19
int refcount; /* how many Lua objects use this wrapper? */
22
/* content of a userdata that wraps the wrapper... duh. */
23
struct _value_wrapper2 {
24
struct value_wrapper *wrapper;
27
/* Keep track of how many wrappers exist. Use this to catch leaks. */
28
int vwrapper_count = 0, vwrapper_alloc_count = 0, vwrapper_objects = 0;
32
* Determine whether the void* points to a value wrapper; it relies on
33
* a "magic" signature, which might give false positives in pathological
36
int luagtk_is_vwrapper(void *p)
38
struct value_wrapper *wrp = (struct value_wrapper*) p;
39
return wrp->magic1 == VALUE_WRAPPER_MAGIC1
40
&& wrp->magic2 == VALUE_WRAPPER_MAGIC2;
44
* Push the Lua object wrapped by the given value_wrapper onto the stack.
46
int luagtk_vwrapper_get(lua_State *L, struct value_wrapper *wrp)
48
lua_rawgeti(L, LUA_REGISTRYINDEX, wrp->ref);
53
* Try to convert a Userdata to a pointer.
55
* @param index Position of the value on the Lua stack
56
* @param dest Where to store the converted value
57
* @param only_ptr Only accept a pointer type; otherwise, ENUM (integer) is OK
59
* @return 0=ok, pointer 1=ok, integer
61
int luagtk_userdata_to_ffi(lua_State *L, int index, union gtk_arg_types *dest,
64
void *p = (void*) lua_topointer(L, index);
66
// NULL pointer or no metatable - pass pointer as is
67
if (p == NULL || !lua_getmetatable(L, index)) {
73
// is this an enum/flag?
74
// XXX this meta might not be initialized yet
75
lua_getfield(L, LUA_REGISTRYINDEX, ENUM_META);
76
if (lua_rawequal(L, -1, -2)) {
78
luaL_error(L, "ENUM given for a pointer parameter\n");
79
dest->l = ((struct luagtk_enum_t*)p)->value;
85
// Is this a value wrapper wrapper? If so, pass the wrapper.
86
lua_getfield(L, LUA_REGISTRYINDEX, LUAGTK_WRAPPER);
87
if (lua_rawequal(L, -1, -2)) {
88
struct _value_wrapper2 *wrp = (struct _value_wrapper2*) p;
89
dest->p = wrp->wrapper;
95
// is this a widget? if not, pass pointer as is
96
lua_getfield(L, -1, "_classname");
97
// stack: metatable, _classname/nil
98
if (lua_isnil(L, -1)) {
104
// this is a widget - pass the pointer
105
dest->p = ((struct widget*)p)->p;
112
* Garbage collection of a Lua wrapper. Free the referenced C wrapper if
113
* its refcount now drops to zero.
115
static int wrapper_gc(lua_State *L)
117
struct _value_wrapper2 *a = (struct _value_wrapper2*) lua_topointer(L, 1);
118
if (a->wrapper && --a->wrapper->refcount == 0) {
119
luaL_unref(L, LUA_REGISTRYINDEX, a->wrapper->ref);
121
a->wrapper->magic1 = 0;
122
a->wrapper->magic2 = 0;
132
* The :destroy method decreases the refcount by one, if it is > 1. It must
133
* not be set to 0, because the userdata object will be garbage collected
134
* eventually, and then the refcount is decreased again.
136
static int wrapper_destroy(lua_State *L)
138
struct _value_wrapper2 *a = (struct _value_wrapper2*) lua_topointer(L, 1);
139
if (a->wrapper && a->wrapper->refcount > 1)
140
a->wrapper->refcount --;
146
* Access to a wrapper's fields - value or destroy(). __index in the metatable
147
* points to this function instead of itself, because in case of value, a
148
* function must be called.
150
int wrapper_index(lua_State *L)
152
const struct _value_wrapper2 *a = lua_topointer(L, 1);
153
const char *key = lua_tostring(L, 2);
154
if (!strcmp(key, "value")) {
155
lua_rawgeti(L, LUA_REGISTRYINDEX, a->wrapper->ref);
158
if (!strcmp(key, "destroy")) {
159
lua_pushcfunction(L, wrapper_destroy);
167
* Debug function: show the wrapper's address and content.
169
static int wrapper_tostring(lua_State *L)
171
const struct _value_wrapper2 *a = lua_topointer(L, 1);
172
lua_pushliteral(L, "[void* wrapper: ");
173
lua_getglobal(L, "tostring");
174
lua_rawgeti(L, LUA_REGISTRYINDEX, a->wrapper->ref);
176
lua_pushliteral(L, "]");
182
static const luaL_reg wrapper_methods[] = {
183
{ "__index", wrapper_index },
184
{ "__gc", wrapper_gc },
185
{ "__tostring", wrapper_tostring },
191
* A value should be passed to a Gtk function as void*. This is most likely
192
* a "data" argument that will be given to a callback, or a value in a
193
* collection class like a tree etc. Create a special userdata that transports
196
* Note: This wrapper is initialized with a refcount of 0. This function
197
* is either called by gtk.void_ptr(), which immediately creates a Lua
198
* wrapper for it, or by lua2ffi_void_ptr. In the latter case, refcount
199
* remains at 0 until Gtk chooses to pass the value to a Lua callback; then
200
* ffi2lua_void_ptr calls luagtk_push_value_wrapper, which increases the
203
struct value_wrapper *luagtk_make_value_wrapper(lua_State *L, int index)
205
lua_pushvalue(L, index);
206
struct value_wrapper *wrp = (struct value_wrapper*) g_malloc(sizeof(*wrp));
207
wrp->magic1 = VALUE_WRAPPER_MAGIC1;
208
wrp->magic2 = VALUE_WRAPPER_MAGIC2;
209
wrp->ref = luaL_ref(L, LUA_REGISTRYINDEX);
212
vwrapper_alloc_count ++;
217
* Make a Lua wrapper for the C wrapper for the Lua value.
219
int luagtk_push_value_wrapper(lua_State *L, struct value_wrapper *wrp)
221
struct _value_wrapper2 *p = lua_newuserdata(L, sizeof(*p));
226
// add a metatable with some methods
227
if (luaL_newmetatable(L, LUAGTK_WRAPPER))
228
luaL_register(L, NULL, wrapper_methods);
230
lua_setmetatable(L, -2);
235
* The C function expects a void* pointer. Any datatype should be permissible;
236
* nil and lightuserdata are easy; userdata may be ENUM or contain a widget.
237
* For other data types, a reference is created, which is then wrapped in a
238
* small memory block with a "magic" signature. This signature will then be
239
* recognized in ffi2lua_void_ptr.
241
* The problem is that it's unknown how long this value is required. The C
242
* function might store it somewhere (e.g. g_tree_insert key and value) or not
243
* (e.g. g_tree_foreach user_data), so it can't be freed automatically.
245
int lua2ffi_void_ptr(struct argconv_t *ar)
247
lua_State *L = ar->L;
249
switch (ar->lua_type) {
254
case LUA_TLIGHTUSERDATA:
255
ar->arg->p = (void*) lua_topointer(L, ar->index);
259
luagtk_userdata_to_ffi(L, ar->index, ar->arg, 1);
263
struct value_wrapper *w = luagtk_make_value_wrapper(ar->L,
265
/* this reference isn't owned... leak unless :destroy is called */