2 * luaobject.c - useful functions for handling Lua objects
4 * Copyright © 2009 Julien Danjou <julien@danjou.info>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 #include "common/luaobject.h"
23 #include "common/backtrace.h"
25 /** Setup the object system at startup.
26 * \param L The Lua VM state.
29 luaA_object_setup(lua_State
*L
)
31 /* Push identification string */
32 lua_pushliteral(L
, LUAA_OBJECT_REGISTRY_KEY
);
33 /* Create an empty table */
35 /* Create an empty metatable */
37 /* Set this empty table as the registry metatable.
38 * It's used to store the number of reference on stored objects. */
39 lua_setmetatable(L
, -2);
40 /* Register table inside registry */
41 lua_rawset(L
, LUA_REGISTRYINDEX
);
44 /** Increment a object reference in its store table.
45 * \param L The Lua VM state.
46 * \param tud The table index on the stack.
47 * \param oud The object index on the stack.
48 * \return A pointer to the object.
51 luaA_object_incref(lua_State
*L
, int tud
, int oud
)
53 /* Get pointer value of the item */
54 void *pointer
= (void *) lua_topointer(L
, oud
);
56 /* Not reference able. */
63 /* Push the pointer (key) */
64 lua_pushlightuserdata(L
, pointer
);
65 /* Push the data (value) */
66 lua_pushvalue(L
, oud
< 0 ? oud
- 1 : oud
);
67 /* table.lightudata = data */
68 lua_rawset(L
, tud
< 0 ? tud
- 2 : tud
);
72 /* Get the metatable */
73 lua_getmetatable(L
, tud
);
74 /* Push the pointer (key) */
75 lua_pushlightuserdata(L
, pointer
);
76 /* Get the number of references */
78 /* Get the number of references and increment it */
79 int count
= lua_tonumber(L
, -1) + 1;
81 /* Push the pointer (key) */
82 lua_pushlightuserdata(L
, pointer
);
83 /* Push count (value) */
84 lua_pushinteger(L
, count
);
85 /* Set metatable[pointer] = count */
90 /* Remove referenced item */
96 /** Decrement a object reference in its store table.
97 * \param L The Lua VM state.
98 * \param tud The table index on the stack.
99 * \param oud The object index on the stack.
100 * \return A pointer to the object.
103 luaA_object_decref(lua_State
*L
, int tud
, const void *pointer
)
108 /* First, refcount-- */
109 /* Get the metatable */
110 lua_getmetatable(L
, tud
);
111 /* Push the pointer (key) */
112 lua_pushlightuserdata(L
, (void *) pointer
);
113 /* Get the number of references */
115 /* Get the number of references and decrement it */
116 int count
= lua_tonumber(L
, -1) - 1;
117 /* Did we find the item in our table? (tonumber(nil)-1) is -1 */
122 warn("BUG: Reference not found: %d %p\n%s", tud
, pointer
, buf
.s
);
124 /* Pop reference count and metatable */
129 /* Push the pointer (key) */
130 lua_pushlightuserdata(L
, (void *) pointer
);
131 /* Hasn't the ref reached 0? */
133 lua_pushinteger(L
, count
);
135 /* Yup, delete it, set nil as value */
137 /* Set meta[pointer] = count/nil */
142 /* Wait, no more ref? */
145 /* Yes? So remove it from table */
146 lua_pushlightuserdata(L
, (void *) pointer
);
147 /* Push nil as value */
149 /* table[pointer] = nil */
150 lua_rawset(L
, tud
< 0 ? tud
- 2 : tud
);
155 luaA_settype(lua_State
*L
, lua_class_t
*lua_class
)
157 lua_pushlightuserdata(L
, lua_class
);
158 lua_rawget(L
, LUA_REGISTRYINDEX
);
159 lua_setmetatable(L
, -2);
164 luaA_object_connect_signal(lua_State
*L
, int oud
,
165 const char *name
, lua_CFunction fn
)
167 lua_pushcfunction(L
, fn
);
168 luaA_object_connect_signal_from_stack(L
, oud
, name
, -1);
172 luaA_object_disconnect_signal(lua_State
*L
, int oud
,
173 const char *name
, lua_CFunction fn
)
175 lua_pushcfunction(L
, fn
);
176 luaA_object_disconnect_signal_from_stack(L
, oud
, name
, -1);
179 /** Add a signal to an object.
180 * \param L The Lua VM state.
181 * \param oud The object index on the stack.
182 * \param name The name of the signal.
183 * \param ud The index of function to call when signal is emitted.
186 luaA_object_connect_signal_from_stack(lua_State
*L
, int oud
,
187 const char *name
, int ud
)
189 luaA_checkfunction(L
, ud
);
190 lua_object_t
*obj
= lua_touserdata(L
, oud
);
191 signal_connect(&obj
->signals
, name
, luaA_object_ref_item(L
, oud
, ud
));
194 /** Remove a signal to an object.
195 * \param L The Lua VM state.
196 * \param oud The object index on the stack.
197 * \param name The name of the signal.
198 * \param ud The index of function to call when signal is emitted.
201 luaA_object_disconnect_signal_from_stack(lua_State
*L
, int oud
,
202 const char *name
, int ud
)
204 luaA_checkfunction(L
, ud
);
205 lua_object_t
*obj
= lua_touserdata(L
, oud
);
206 void *ref
= (void *) lua_topointer(L
, ud
);
207 signal_disconnect(&obj
->signals
, name
, ref
);
208 luaA_object_unref_item(L
, oud
, ref
);
213 signal_object_emit(lua_State
*L
, signal_array_t
*arr
, const char *name
, int nargs
)
215 signal_t
*sigfound
= signal_array_getbyid(arr
,
216 a_strhash((const unsigned char *) name
));
220 int nbfunc
= sigfound
->sigfuncs
.len
;
221 luaL_checkstack(L
, lua_gettop(L
) + nbfunc
+ nargs
+ 1, "too much signal");
222 /* Push all functions and then execute, because this list can change
223 * while executing funcs. */
224 foreach(func
, sigfound
->sigfuncs
)
225 luaA_object_push(L
, *func
);
227 for(int i
= 0; i
< nbfunc
; i
++)
230 for(int j
= 0; j
< nargs
; j
++)
231 lua_pushvalue(L
, - nargs
- nbfunc
+ i
);
232 /* push first function */
233 lua_pushvalue(L
, - nargs
- nbfunc
+ i
);
234 /* remove this first function */
235 lua_remove(L
, - nargs
- nbfunc
- 1 + i
);
236 luaA_dofunction(L
, nargs
, 0);
239 warn("Trying to emit unknown signal '%s'", name
);
245 /** Emit a signal to an object.
246 * \param L The Lua VM state.
247 * \param oud The object index on the stack.
248 * \param name The name of the signal.
249 * \param nargs The number of arguments to pass to the called functions.
252 luaA_object_emit_signal(lua_State
*L
, int oud
,
253 const char *name
, int nargs
)
255 int oud_abs
= luaA_absindex(L
, oud
);
256 lua_object_t
*obj
= lua_touserdata(L
, oud
);
258 warn("Trying to emit signal '%s' on non-object", name
);
261 signal_t
*sigfound
= signal_array_getbyid(&obj
->signals
,
262 a_strhash((const unsigned char *) name
));
265 int nbfunc
= sigfound
->sigfuncs
.len
;
266 luaL_checkstack(L
, lua_gettop(L
) + nbfunc
+ nargs
+ 2, "too much signal");
267 /* Push all functions and then execute, because this list can change
268 * while executing funcs. */
269 foreach(func
, sigfound
->sigfuncs
)
270 luaA_object_push_item(L
, oud_abs
, *func
);
272 for(int i
= 0; i
< nbfunc
; i
++)
275 lua_pushvalue(L
, oud_abs
);
277 for(int j
= 0; j
< nargs
; j
++)
278 lua_pushvalue(L
, - nargs
- nbfunc
- 1 + i
);
279 /* push first function */
280 lua_pushvalue(L
, - nargs
- nbfunc
- 1 + i
);
281 /* remove this first function */
282 lua_remove(L
, - nargs
- nbfunc
- 2 + i
);
283 luaA_dofunction(L
, nargs
+ 1, 0);
286 warn("Trying to emit unknown signal '%s'", name
);
288 /* Then emit signal on the class */
289 lua_pushvalue(L
, oud
);
290 lua_insert(L
, - nargs
- 1);
291 luaA_class_emit_signal(L
, luaA_class_get(L
, - nargs
- 1), name
, nargs
+ 1);
295 luaA_object_connect_signal_simple(lua_State
*L
)
297 luaA_object_connect_signal_from_stack(L
, 1, luaL_checkstring(L
, 2), 3);
302 luaA_object_disconnect_signal_simple(lua_State
*L
)
304 luaA_object_disconnect_signal_from_stack(L
, 1, luaL_checkstring(L
, 2), 3);
309 luaA_object_emit_signal_simple(lua_State
*L
)
311 luaA_object_emit_signal(L
, 1, luaL_checkstring(L
, 2), lua_gettop(L
) - 2);
316 luaA_object_tostring(lua_State
*L
)
318 lua_class_t
*lua_class
= luaA_class_get(L
, 1);
319 lua_object_t
*object
= luaA_checkudata(L
, 1, lua_class
);
322 for(; lua_class
; lua_class
= lua_class
->parent
, i
++)
326 lua_pushliteral(L
, "/");
327 lua_insert(L
, - (i
* 2));
329 lua_pushstring(L
, NONULL(lua_class
->name
));
330 lua_insert(L
, - (i
* 2) - 1);
333 lua_pushfstring(L
, ": %p", object
);
335 lua_concat(L
, i
* 2);
340 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80