awful.menu: enhance description
[awesome.git] / common / luaobject.c
blob10a9597914a0272eac76ecb6d94d1f616ba6cf4f
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 referencable. */
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 /** Add a signal to an object.
152 * \param L The Lua VM state.
153 * \param oud The object index on the stack.
154 * \param name The name of the signal.
155 * \param ud The index of function to call when signal is emited.
157 void
158 luaA_object_add_signal(lua_State *L, int oud,
159 const char *name, int ud)
161 luaA_checkfunction(L, ud);
162 lua_object_t *obj = lua_touserdata(L, oud);
163 signal_add(&obj->signals, name, luaA_object_ref_item(L, oud, ud));
166 /** Remove a signal to an object.
167 * \param L The Lua VM state.
168 * \param oud The object index on the stack.
169 * \param name The name of the signal.
170 * \param ud The index of function to call when signal is emited.
172 void
173 luaA_object_remove_signal(lua_State *L, int oud,
174 const char *name, int ud)
176 luaA_checkfunction(L, ud);
177 lua_object_t *obj = lua_touserdata(L, oud);
178 void *ref = (void *) lua_topointer(L, ud);
179 signal_remove(&obj->signals, name, ref);
180 luaA_object_unref_item(L, oud, ref);
181 lua_remove(L, ud);
184 void
185 signal_object_emit(lua_State *L, signal_array_t *arr, const char *name, int nargs)
187 signal_t *sigfound = signal_array_getbyid(arr,
188 a_strhash((const unsigned char *) name));
190 if(sigfound)
192 int nbfunc = sigfound->sigfuncs.len;
193 luaL_checkstack(L, lua_gettop(L) + nbfunc + nargs + 1, "too much signal");
194 /* Push all functions and then execute, because this list can change
195 * while executing funcs. */
196 foreach(func, sigfound->sigfuncs)
197 luaA_object_push(L, (void *) *func);
199 for(int i = 0; i < nbfunc; i++)
201 /* push all args */
202 for(int j = 0; j < nargs; j++)
203 lua_pushvalue(L, - nargs - nbfunc + i);
204 /* push first function */
205 lua_pushvalue(L, - nargs - nbfunc + i);
206 /* remove this first function */
207 lua_remove(L, - nargs - nbfunc - 1 + i);
208 luaA_dofunction(L, nargs, 0);
211 /* remove args */
212 lua_pop(L, nargs);
215 /** Emit a signal to an object.
216 * \param L The Lua VM state.
217 * \param oud The object index on the stack.
218 * \param name The name of the signal.
219 * \param nargs The number of arguments to pass to the called functions.
221 void
222 luaA_object_emit_signal(lua_State *L, int oud,
223 const char *name, int nargs)
225 int oud_abs = luaA_absindex(L, oud);
226 lua_object_t *obj = lua_touserdata(L, oud);
227 if(!obj)
228 luaL_error(L, "trying to emit signal on non-object");
229 signal_t *sigfound = signal_array_getbyid(&obj->signals,
230 a_strhash((const unsigned char *) name));
231 if(sigfound)
233 int nbfunc = sigfound->sigfuncs.len;
234 luaL_checkstack(L, lua_gettop(L) + nbfunc + nargs + 2, "too much signal");
235 /* Push all functions and then execute, because this list can change
236 * while executing funcs. */
237 foreach(func, sigfound->sigfuncs)
238 luaA_object_push_item(L, oud_abs, (void *) *func);
240 for(int i = 0; i < nbfunc; i++)
242 /* push object */
243 lua_pushvalue(L, oud_abs);
244 /* push all args */
245 for(int j = 0; j < nargs; j++)
246 lua_pushvalue(L, - nargs - nbfunc - 1 + i);
247 /* push first function */
248 lua_pushvalue(L, - nargs - nbfunc - 1 + i);
249 /* remove this first function */
250 lua_remove(L, - nargs - nbfunc - 2 + i);
251 luaA_dofunction(L, nargs + 1, 0);
254 lua_pop(L, nargs);
258 luaA_object_add_signal_simple(lua_State *L)
260 luaA_object_add_signal(L, 1, luaL_checkstring(L, 2), 3);
261 return 0;
265 luaA_object_remove_signal_simple(lua_State *L)
267 luaA_object_remove_signal(L, 1, luaL_checkstring(L, 2), 3);
268 return 0;
272 luaA_object_emit_signal_simple(lua_State *L)
274 luaA_object_emit_signal(L, 1, luaL_checkstring(L, 2), lua_gettop(L) - 2);
275 return 0;
279 luaA_object_tostring(lua_State *L)
281 lua_class_t *lua_class = luaA_class_get(L, 1);
282 lua_pushfstring(L, "%s: %p", lua_class->name, luaA_checkudata(L, 1, lua_class));
283 return 1;
286 /** Garbage collect a Lua object.
287 * \param L The Lua VM state.
288 * \return The number of elements pushed on stack.
291 luaA_object_gc(lua_State *L)
293 lua_object_t *item = lua_touserdata(L, 1);
294 signal_array_wipe(&item->signals);
295 return 0;
298 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80