~ubuntu-branches/ubuntu/natty/lua-gtk/natty

« back to all changes in this revision

Viewing changes to src/voidptr.c

  • Committer: Bazaar Package Importer
  • Author(s): Enrico Tassi
  • Date: 2009-05-17 18:16:21 UTC
  • mfrom: (1.2.1 upstream) (4.1.1 experimental)
  • Revision ID: james.westby@ubuntu.com-20090517181621-9kmdd82nxg54jsio
* new upstream snapshot comprising many more GNOME libraries:
    Gtk, GDK, GLib, Pango, Atk, Libxml2, Cairo, Clutter, Gtkhtml, 
    GtkSourceView, Gio, Gtkspell and GConf. 
* new upstream release includes a new configure script written in Lua,
  no more bashisms there (Closes: #507205)
* renamed binary packages to liblua5.1-gnome-*
* updated standards-version to 3.8.1, no changes needed
* patch to load .so.* version of libraries and not .so (that was requiring
  -dev packages) (Closes: #522087)
* removed redundant Architecture line from the source stanza of control
  (Closes: #498120)
* updated copyright file, Wolfgang Oertl holds it for 2009 too.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/** vim:sw=4:sts=4
2
 
 * Handle void* wrappers.
3
 
 * This is part of lua-gtk.
4
 
 */
5
 
 
6
 
#include "luagtk.h"
7
 
#include <lauxlib.h>
8
 
#include <string.h>         // strcmp
9
 
 
10
 
#define LUAGTK_WRAPPER "void* wrapper"
11
 
 
12
 
#define VALUE_WRAPPER_MAGIC1 0x89737948
13
 
#define VALUE_WRAPPER_MAGIC2 0xa0d7dfaa
14
 
 
15
 
struct value_wrapper {
16
 
    unsigned int magic1;
17
 
    unsigned int magic2;
18
 
    int ref;
19
 
    int refcount;               /* how many Lua objects use this wrapper? */
20
 
};
21
 
 
22
 
/* content of a userdata that wraps the wrapper... duh. */
23
 
struct _value_wrapper2 {
24
 
    struct value_wrapper *wrapper;
25
 
};
26
 
 
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;
29
 
 
30
 
 
31
 
/**
32
 
 * Determine whether the void* points to a value wrapper; it relies on
33
 
 * a "magic" signature, which might give false positives in pathological
34
 
 * cases.
35
 
 */
36
 
int luagtk_is_vwrapper(void *p)
37
 
{
38
 
    struct value_wrapper *wrp = (struct value_wrapper*) p;
39
 
    return wrp->magic1 == VALUE_WRAPPER_MAGIC1
40
 
        && wrp->magic2 == VALUE_WRAPPER_MAGIC2;
41
 
}
42
 
        
43
 
/**
44
 
 * Push the Lua object wrapped by the given value_wrapper onto the stack.
45
 
 */
46
 
int luagtk_vwrapper_get(lua_State *L, struct value_wrapper *wrp)
47
 
{
48
 
    lua_rawgeti(L, LUA_REGISTRYINDEX, wrp->ref);
49
 
    return 1;
50
 
}
51
 
 
52
 
/**
53
 
 * Try to convert a Userdata to a pointer.
54
 
 *
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
58
 
 *
59
 
 * @return   0=ok, pointer  1=ok, integer
60
 
 */
61
 
int luagtk_userdata_to_ffi(lua_State *L, int index, union gtk_arg_types *dest,
62
 
    int only_ptr)
63
 
{
64
 
    void *p = (void*) lua_topointer(L, index);
65
 
 
66
 
    // NULL pointer or no metatable - pass pointer as is
67
 
    if (p == NULL || !lua_getmetatable(L, index)) {
68
 
        dest->p = p;
69
 
        return 0;
70
 
    }
71
 
    // stack: metatable
72
 
 
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)) {
77
 
        if (only_ptr)
78
 
            luaL_error(L, "ENUM given for a pointer parameter\n");
79
 
        dest->l = ((struct luagtk_enum_t*)p)->value;
80
 
        lua_pop(L, 2);
81
 
        return 1;
82
 
    }
83
 
    lua_pop(L, 1);
84
 
 
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;
90
 
        lua_pop(L, 2);
91
 
        return 1;
92
 
    }
93
 
    lua_pop(L, 1);
94
 
 
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)) {
99
 
        lua_pop(L, 2);
100
 
        dest->p = p;
101
 
        return 0;
102
 
    }
103
 
 
104
 
    // this is a widget - pass the pointer
105
 
    dest->p = ((struct widget*)p)->p;
106
 
    lua_pop(L, 2);
107
 
    return 0;
108
 
}
109
 
 
110
 
 
111
 
/**
112
 
 * Garbage collection of a Lua wrapper.  Free the referenced C wrapper if
113
 
 * its refcount now drops to zero.
114
 
 */
115
 
static int wrapper_gc(lua_State *L)
116
 
{
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);
120
 
        a->wrapper->ref = 0;
121
 
        a->wrapper->magic1 = 0;
122
 
        a->wrapper->magic2 = 0;
123
 
        g_free(a->wrapper);
124
 
        vwrapper_count --;
125
 
    }
126
 
    a->wrapper = NULL;
127
 
    return 0;
128
 
}
129
 
 
130
 
 
131
 
/**
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.
135
 
 */
136
 
static int wrapper_destroy(lua_State *L)
137
 
{
138
 
    struct _value_wrapper2 *a = (struct _value_wrapper2*) lua_topointer(L, 1);
139
 
    if (a->wrapper && a->wrapper->refcount > 1)
140
 
        a->wrapper->refcount --;
141
 
    return 0;
142
 
}
143
 
 
144
 
 
145
 
/**
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.
149
 
 */
150
 
int wrapper_index(lua_State *L)
151
 
{
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);
156
 
        return 1;
157
 
    }
158
 
    if (!strcmp(key, "destroy")) {
159
 
        lua_pushcfunction(L, wrapper_destroy);
160
 
        return 1;
161
 
    }
162
 
 
163
 
    return 0;
164
 
}
165
 
 
166
 
/**
167
 
 * Debug function: show the wrapper's address and content.
168
 
 */
169
 
static int wrapper_tostring(lua_State *L)
170
 
{
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);
175
 
    lua_call(L, 1, 1);
176
 
    lua_pushliteral(L, "]");
177
 
    lua_concat(L, 3);
178
 
    return 1;
179
 
}
180
 
 
181
 
 
182
 
static const luaL_reg wrapper_methods[] = {
183
 
    { "__index", wrapper_index },
184
 
    { "__gc", wrapper_gc },
185
 
    { "__tostring", wrapper_tostring },
186
 
    { NULL, NULL }
187
 
};
188
 
 
189
 
 
190
 
/**
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
194
 
 * a reference.
195
 
 *
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
201
 
 * refcount.
202
 
 */
203
 
struct value_wrapper *luagtk_make_value_wrapper(lua_State *L, int index)
204
 
{
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);
210
 
    wrp->refcount = 0;
211
 
    vwrapper_count ++;
212
 
    vwrapper_alloc_count ++;
213
 
    return wrp;
214
 
}
215
 
 
216
 
/**
217
 
 * Make a Lua wrapper for the C wrapper for the Lua value.
218
 
 */
219
 
int luagtk_push_value_wrapper(lua_State *L, struct value_wrapper *wrp)
220
 
{
221
 
    struct _value_wrapper2 *p = lua_newuserdata(L, sizeof(*p));
222
 
    p->wrapper = wrp;
223
 
    wrp->refcount ++;
224
 
    vwrapper_objects ++;
225
 
 
226
 
    // add a metatable with some methods
227
 
    if (luaL_newmetatable(L, LUAGTK_WRAPPER))
228
 
        luaL_register(L, NULL, wrapper_methods);
229
 
 
230
 
    lua_setmetatable(L, -2);
231
 
    return 1;
232
 
233
 
 
234
 
/**
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.
240
 
 *
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.
244
 
 */
245
 
int lua2ffi_void_ptr(struct argconv_t *ar)
246
 
{
247
 
    lua_State *L = ar->L;
248
 
 
249
 
    switch (ar->lua_type) {
250
 
        case LUA_TNIL:
251
 
            ar->arg->p = NULL;
252
 
            break;
253
 
        
254
 
        case LUA_TLIGHTUSERDATA:
255
 
            ar->arg->p = (void*) lua_topointer(L, ar->index);
256
 
            break;
257
 
        
258
 
        case LUA_TUSERDATA:
259
 
            luagtk_userdata_to_ffi(L, ar->index, ar->arg, 1);
260
 
            break;
261
 
        
262
 
        default:;
263
 
            struct value_wrapper *w = luagtk_make_value_wrapper(ar->L,
264
 
                ar->index);
265
 
            /* this reference isn't owned...  leak unless :destroy is called */
266
 
            w->refcount ++;
267
 
            ar->arg->p = w;
268
 
    }
269
 
 
270
 
    return 1;
271
 
}
272
 
 
273