Naughty: Port to new widget system
[awesome.git] / common / luaobject.c
blob46450a2d000d87df9dfba4369a1da8f08eb1a1dc
1 /*
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"
24 /** Setup the object system at startup.
25 * \param L The Lua VM state.
27 void
28 luaA_object_setup(lua_State *L)
30 /* Push identification string */
31 lua_pushliteral(L, LUAA_OBJECT_REGISTRY_KEY);
32 /* Create an empty table */
33 lua_newtable(L);
34 /* Create an empty metatable */
35 lua_newtable(L);
36 /* Set this empty table as the registry metatable.
37 * It's used to store the number of reference on stored objects. */
38 lua_setmetatable(L, -2);
39 /* Register table inside registry */
40 lua_rawset(L, LUA_REGISTRYINDEX);
43 /** Increment a object reference in its store table.
44 * \param L The Lua VM state.
45 * \param tud The table index on the stack.
46 * \param oud The object index on the stack.
47 * \return A pointer to the object.
49 void *
50 luaA_object_incref(lua_State *L, int tud, int oud)
52 /* Get pointer value of the item */
53 void *pointer = (void *) lua_topointer(L, oud);
55 /* Not reference able. */
56 if(!pointer)
58 lua_remove(L, oud);
59 return NULL;
62 /* Push the pointer (key) */
63 lua_pushlightuserdata(L, pointer);
64 /* Push the data (value) */
65 lua_pushvalue(L, oud < 0 ? oud - 1 : oud);
66 /* table.lightudata = data */
67 lua_rawset(L, tud < 0 ? tud - 2 : tud);
69 /* refcount++ */
71 /* Get the metatable */
72 lua_getmetatable(L, tud);
73 /* Push the pointer (key) */
74 lua_pushlightuserdata(L, pointer);
75 /* Get the number of references */
76 lua_rawget(L, -2);
77 /* Get the number of references and increment it */
78 int count = lua_tonumber(L, -1) + 1;
79 lua_pop(L, 1);
80 /* Push the pointer (key) */
81 lua_pushlightuserdata(L, pointer);
82 /* Push count (value) */
83 lua_pushinteger(L, count);
84 /* Set metatable[pointer] = count */
85 lua_rawset(L, -3);
86 /* Pop metatable */
87 lua_pop(L, 1);
89 /* Remove referenced item */
90 lua_remove(L, oud);
92 return pointer;
95 /** Decrement a object reference in its store table.
96 * \param L The Lua VM state.
97 * \param tud The table index on the stack.
98 * \param oud The object index on the stack.
99 * \return A pointer to the object.
101 void
102 luaA_object_decref(lua_State *L, int tud, void *pointer)
104 if(!pointer)
105 return;
107 /* First, refcount-- */
108 /* Get the metatable */
109 lua_getmetatable(L, tud);
110 /* Push the pointer (key) */
111 lua_pushlightuserdata(L, pointer);
112 /* Get the number of references */
113 lua_rawget(L, -2);
114 /* Get the number of references and decrement it */
115 int count = lua_tonumber(L, -1) - 1;
116 lua_pop(L, 1);
117 /* Push the pointer (key) */
118 lua_pushlightuserdata(L, pointer);
119 /* Hasn't the ref reached 0? */
120 if(count)
121 lua_pushinteger(L, count);
122 else
123 /* Yup, delete it, set nil as value */
124 lua_pushnil(L);
125 /* Set meta[pointer] = count/nil */
126 lua_rawset(L, -3);
127 /* Pop metatable */
128 lua_pop(L, 1);
130 /* Wait, no more ref? */
131 if(!count)
133 /* Yes? So remove it from table */
134 lua_pushlightuserdata(L, pointer);
135 /* Push nil as value */
136 lua_pushnil(L);
137 /* table[pointer] = nil */
138 lua_rawset(L, tud < 0 ? tud - 2 : tud);
143 luaA_settype(lua_State *L, lua_class_t *lua_class)
145 lua_pushlightuserdata(L, lua_class);
146 lua_rawget(L, LUA_REGISTRYINDEX);
147 lua_setmetatable(L, -2);
148 return 1;
151 void
152 luaA_object_connect_signal(lua_State *L, int oud,
153 const char *name, lua_CFunction fn)
155 lua_pushcfunction(L, fn);
156 luaA_object_connect_signal_from_stack(L, oud, name, -1);
159 void
160 luaA_object_disconnect_signal(lua_State *L, int oud,
161 const char *name, lua_CFunction fn)
163 lua_pushcfunction(L, fn);
164 luaA_object_disconnect_signal_from_stack(L, oud, name, -1);
167 /** Add a signal to an object.
168 * \param L The Lua VM state.
169 * \param oud The object index on the stack.
170 * \param name The name of the signal.
171 * \param ud The index of function to call when signal is emitted.
173 void
174 luaA_object_connect_signal_from_stack(lua_State *L, int oud,
175 const char *name, int ud)
177 luaA_checkfunction(L, ud);
178 lua_object_t *obj = lua_touserdata(L, oud);
179 signal_connect(&obj->signals, name, luaA_object_ref_item(L, oud, ud));
182 /** Remove a signal to an object.
183 * \param L The Lua VM state.
184 * \param oud The object index on the stack.
185 * \param name The name of the signal.
186 * \param ud The index of function to call when signal is emitted.
188 void
189 luaA_object_disconnect_signal_from_stack(lua_State *L, int oud,
190 const char *name, int ud)
192 luaA_checkfunction(L, ud);
193 lua_object_t *obj = lua_touserdata(L, oud);
194 void *ref = (void *) lua_topointer(L, ud);
195 signal_disconnect(&obj->signals, name, ref);
196 luaA_object_unref_item(L, oud, ref);
197 lua_remove(L, ud);
200 void
201 signal_object_emit(lua_State *L, signal_array_t *arr, const char *name, int nargs)
203 signal_t *sigfound = signal_array_getbyid(arr,
204 a_strhash((const unsigned char *) name));
206 if(sigfound)
208 int nbfunc = sigfound->sigfuncs.len;
209 luaL_checkstack(L, lua_gettop(L) + nbfunc + nargs + 1, "too much signal");
210 /* Push all functions and then execute, because this list can change
211 * while executing funcs. */
212 foreach(func, sigfound->sigfuncs)
213 luaA_object_push(L, (void *) *func);
215 for(int i = 0; i < nbfunc; i++)
217 /* push all args */
218 for(int j = 0; j < nargs; j++)
219 lua_pushvalue(L, - nargs - nbfunc + i);
220 /* push first function */
221 lua_pushvalue(L, - nargs - nbfunc + i);
222 /* remove this first function */
223 lua_remove(L, - nargs - nbfunc - 1 + i);
224 luaA_dofunction(L, nargs, 0);
226 } else
227 warn("Trying to emit unknown signal '%s'", name);
229 /* remove args */
230 lua_pop(L, nargs);
233 /** Emit a signal to an object.
234 * \param L The Lua VM state.
235 * \param oud The object index on the stack.
236 * \param name The name of the signal.
237 * \param nargs The number of arguments to pass to the called functions.
239 void
240 luaA_object_emit_signal(lua_State *L, int oud,
241 const char *name, int nargs)
243 int oud_abs = luaA_absindex(L, oud);
244 lua_object_t *obj = lua_touserdata(L, oud);
245 if(!obj)
246 luaL_error(L, "trying to emit signal on non-object");
247 signal_t *sigfound = signal_array_getbyid(&obj->signals,
248 a_strhash((const unsigned char *) name));
249 if(sigfound)
251 int nbfunc = sigfound->sigfuncs.len;
252 luaL_checkstack(L, lua_gettop(L) + nbfunc + nargs + 2, "too much signal");
253 /* Push all functions and then execute, because this list can change
254 * while executing funcs. */
255 foreach(func, sigfound->sigfuncs)
256 luaA_object_push_item(L, oud_abs, (void *) *func);
258 for(int i = 0; i < nbfunc; i++)
260 /* push object */
261 lua_pushvalue(L, oud_abs);
262 /* push all args */
263 for(int j = 0; j < nargs; j++)
264 lua_pushvalue(L, - nargs - nbfunc - 1 + i);
265 /* push first function */
266 lua_pushvalue(L, - nargs - nbfunc - 1 + i);
267 /* remove this first function */
268 lua_remove(L, - nargs - nbfunc - 2 + i);
269 luaA_dofunction(L, nargs + 1, 0);
271 } else
272 warn("Trying to emit unknown signal '%s'", name);
274 /* Then emit signal on the class */
275 lua_pushvalue(L, oud);
276 lua_insert(L, - nargs - 1);
277 luaA_class_emit_signal(L, luaA_class_get(L, - nargs - 1), name, nargs + 1);
281 luaA_object_connect_signal_simple(lua_State *L)
283 luaA_object_connect_signal_from_stack(L, 1, luaL_checkstring(L, 2), 3);
284 return 0;
288 luaA_object_disconnect_signal_simple(lua_State *L)
290 luaA_object_disconnect_signal_from_stack(L, 1, luaL_checkstring(L, 2), 3);
291 return 0;
295 luaA_object_emit_signal_simple(lua_State *L)
297 luaA_object_emit_signal(L, 1, luaL_checkstring(L, 2), lua_gettop(L) - 2);
298 return 0;
302 luaA_object_tostring(lua_State *L)
304 lua_class_t *lua_class = luaA_class_get(L, 1);
305 lua_object_t *object = luaA_checkudata(L, 1, lua_class);
307 int i = 0;
308 for(; lua_class; lua_class = lua_class->parent, i++)
310 if(i)
312 lua_pushliteral(L, "/");
313 lua_insert(L, - (i * 2));
315 lua_pushstring(L, NONULL(lua_class->name));
316 lua_insert(L, - (i * 2) - 1);
319 lua_pushfstring(L, ": %p", object);
321 lua_concat(L, i * 2);
323 return 1;
326 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80