Make callbacks to rules.execute optional
[awesome.git] / common / luaobject.c
blob118be3a3ac666202349f4c4e8a88db460e1cab61
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"
23 #include "common/backtrace.h"
25 /** Setup the object system at startup.
26 * \param L The Lua VM state.
28 void
29 luaA_object_setup(lua_State *L)
31 /* Push identification string */
32 lua_pushliteral(L, LUAA_OBJECT_REGISTRY_KEY);
33 /* Create an empty table */
34 lua_newtable(L);
35 /* Create an empty metatable */
36 lua_newtable(L);
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.
50 void *
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. */
57 if(!pointer)
59 lua_remove(L, oud);
60 return NULL;
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);
70 /* refcount++ */
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 */
77 lua_rawget(L, -2);
78 /* Get the number of references and increment it */
79 int count = lua_tonumber(L, -1) + 1;
80 lua_pop(L, 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 */
86 lua_rawset(L, -3);
87 /* Pop metatable */
88 lua_pop(L, 1);
90 /* Remove referenced item */
91 lua_remove(L, oud);
93 return pointer;
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.
102 void
103 luaA_object_decref(lua_State *L, int tud, const void *pointer)
105 if(!pointer)
106 return;
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 */
114 lua_rawget(L, -2);
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 */
118 if (count < 0)
120 buffer_t buf;
121 backtrace_get(&buf);
122 warn("BUG: Reference not found: %d %p\n%s", tud, pointer, buf.s);
124 /* Pop reference count and metatable */
125 lua_pop(L, 2);
126 return;
128 lua_pop(L, 1);
129 /* Push the pointer (key) */
130 lua_pushlightuserdata(L, (void *) pointer);
131 /* Hasn't the ref reached 0? */
132 if(count)
133 lua_pushinteger(L, count);
134 else
135 /* Yup, delete it, set nil as value */
136 lua_pushnil(L);
137 /* Set meta[pointer] = count/nil */
138 lua_rawset(L, -3);
139 /* Pop metatable */
140 lua_pop(L, 1);
142 /* Wait, no more ref? */
143 if(!count)
145 /* Yes? So remove it from table */
146 lua_pushlightuserdata(L, (void *) pointer);
147 /* Push nil as value */
148 lua_pushnil(L);
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);
160 return 1;
163 void
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);
171 void
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.
185 void
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.
200 void
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);
209 lua_remove(L, ud);
212 void
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));
218 if(sigfound)
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++)
229 /* push all args */
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);
238 } else
239 warn("Trying to emit unknown signal '%s'", name);
241 /* remove args */
242 lua_pop(L, nargs);
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.
251 void
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);
257 if(!obj) {
258 warn("Trying to emit signal '%s' on non-object", name);
259 return;
261 signal_t *sigfound = signal_array_getbyid(&obj->signals,
262 a_strhash((const unsigned char *) name));
263 if(sigfound)
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++)
274 /* push object */
275 lua_pushvalue(L, oud_abs);
276 /* push all args */
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);
285 } else
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);
298 return 0;
302 luaA_object_disconnect_signal_simple(lua_State *L)
304 luaA_object_disconnect_signal_from_stack(L, 1, luaL_checkstring(L, 2), 3);
305 return 0;
309 luaA_object_emit_signal_simple(lua_State *L)
311 luaA_object_emit_signal(L, 1, luaL_checkstring(L, 2), lua_gettop(L) - 2);
312 return 0;
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);
321 int i = 0;
322 for(; lua_class; lua_class = lua_class->parent, i++)
324 if(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);
337 return 1;
340 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:textwidth=80