From eed9864ab04b3d255b5777d76601df671da68b25 Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Sat, 20 Jun 2009 14:44:05 +0200 Subject: [PATCH] luaobject: add signals Signed-off-by: Julien Danjou --- common/lualib.h | 68 +++++++++++++++++++++++++++++++++ common/luaobject.c | 59 ++++++++++++++++++++++++++++ common/luaobject.h | 12 ++++-- common/signal.h | 95 ++++++++++++++++++++++++++++++++++++++++++++++ luaa.c | 12 +++--- luaa.h | 27 ------------- 6 files changed, 236 insertions(+), 37 deletions(-) create mode 100644 common/lualib.h create mode 100644 common/signal.h diff --git a/common/lualib.h b/common/lualib.h new file mode 100644 index 000000000..2db68b964 --- /dev/null +++ b/common/lualib.h @@ -0,0 +1,68 @@ +/* + * lualib.h - useful functions and type for Lua + * + * Copyright © 2009 Julien Danjou + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#ifndef AWESOME_COMMON_LUALIB +#define AWESOME_COMMON_LUALIB + +#include +#include "common/util.h" + +#define luaA_checkfunction(L, n) \ + do { \ + if(!lua_isfunction(L, n)) \ + luaL_typerror(L, n, "function"); \ + } while(0) + +/** Convert s stack index to positive. + * \param L The Lua VM state. + * \param ud The index. + * \return A positive index. + */ +static inline int +luaA_absindex(lua_State *L, int ud) +{ + return (ud > 0 || ud <= LUA_REGISTRYINDEX) ? ud : lua_gettop(L) + ud + 1; +} + +/** Execute an Lua function on top of the stack. + * \param L The Lua stack. + * \param nargs The number of arguments for the Lua function. + * \param nret The number of returned value from the Lua function. + * \return True on no error, false otherwise. + */ +static inline bool +luaA_dofunction(lua_State *L, int nargs, int nret) +{ + if(nargs) + lua_insert(L, - (nargs + 1)); + if(lua_pcall(L, nargs, nret, 0)) + { + warn("error running function: %s", + lua_tostring(L, -1)); + lua_pop(L, 1); + return false; + } + return true; +} + +#endif + +// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80 diff --git a/common/luaobject.c b/common/luaobject.c index 672b6eced..60eec0282 100644 --- a/common/luaobject.c +++ b/common/luaobject.c @@ -139,4 +139,63 @@ luaA_object_decref(lua_State *L, int tud, void *pointer) } } +/** Add a signal to an object. + * \param L The Lua VM state. + * \param oud The object index on the stack. + * \param name The name of the signal. + * \param ud The index of function to call when signal is emited. + */ +void +luaA_object_add_signal(lua_State *L, int oud, + const char *name, int ud) +{ + luaA_checkfunction(L, ud); + lua_object_t *obj = lua_touserdata(L, oud); + signal_add(&obj->signals, name, luaA_object_ref_item(L, oud, ud)); +} + +/** Remove a signal to an object. + * \param L The Lua VM state. + * \param oud The object index on the stack. + * \param name The name of the signal. + * \param ud The index of function to call when signal is emited. + */ +void +luaA_object_remove_signal(lua_State *L, int oud, + const char *name, int ud) +{ + luaA_checkfunction(L, ud); + lua_object_t *obj = lua_touserdata(L, oud); + void *ref = (void *) lua_topointer(L, ud); + signal_remove(&obj->signals, name, ref); + luaA_object_unref_item(L, oud, ref); + lua_remove(L, ud); +} + +/** Emit a signal to an object. + * \param L The Lua VM state. + * \param oud The object index on the stack. + * \param name The name of the signal. + * \param nargs The number of arguments to pass to the called functions. + */ +void +luaA_object_emit_signal(lua_State *L, int oud, + const char *name, int nargs) +{ + int oud_abs = luaA_absindex(L, oud); + lua_object_t *obj = lua_touserdata(L, oud); + signal_t *sigfound = signal_array_getbyid(&obj->signals, + a_strhash((const unsigned char *) name)); + if(sigfound) + foreach(ref, sigfound->sigfuncs) + { + lua_pushvalue(L, oud_abs); + for(int i = 0; i < nargs; i++) + lua_pushvalue(L, - nargs - 1); + luaA_object_push_item(L, oud_abs, (void *) *ref); + luaA_dofunction(L, nargs + 1, 0); + } + lua_pop(L, nargs); +} + // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80 diff --git a/common/luaobject.h b/common/luaobject.h index 8f9b1878f..ccf45d235 100644 --- a/common/luaobject.h +++ b/common/luaobject.h @@ -22,8 +22,7 @@ #ifndef AWESOME_COMMON_LUAOBJECT #define AWESOME_COMMON_LUAOBJECT -#include -#include "common/array.h" +#include "common/signal.h" static inline int luaA_settype(lua_State *L, const char *type) @@ -142,7 +141,12 @@ luaA_object_push(lua_State *L, void *pointer) return 1; } -#define LUA_OBJECT_HEADER +void luaA_object_add_signal(lua_State *, int, const char *, int); +void luaA_object_remove_signal(lua_State *, int, const char *, int); +void luaA_object_emit_signal(lua_State *, int, const char *, int); + +#define LUA_OBJECT_HEADER \ + signal_array_t signals; /** Generic type for all objects. * All Lua objects can be casted to this type. @@ -201,6 +205,8 @@ typedef struct static inline int luaA_object_gc(lua_State *L) { + lua_object_t *item = lua_touserdata(L, 1); + signal_array_wipe(&item->signals); return 0; } diff --git a/common/signal.h b/common/signal.h new file mode 100644 index 000000000..477b61f75 --- /dev/null +++ b/common/signal.h @@ -0,0 +1,95 @@ +/* + * common/signal.h - Signal handling functions + * + * Copyright © 2009 Julien Danjou + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#ifndef AWESOME_COMMON_SIGNAL +#define AWESOME_COMMON_SIGNAL + +#include "common/lualib.h" +#include "common/array.h" + +DO_ARRAY(const void *, cptr, DO_NOTHING) + +typedef struct +{ + unsigned long id; + cptr_array_t sigfuncs; +} signal_t; + +static inline int +signal_cmp(const void *a, const void *b) +{ + const signal_t *x = a, *y = b; + return x->id > y->id ? 1 : (x->id < y->id ? -1 : 0); +} + +DO_BARRAY(signal_t, signal, DO_NOTHING, signal_cmp) + +static inline signal_t * +signal_array_getbyid(signal_array_t *arr, unsigned long id) +{ + signal_t sig = { .id = id }; + return signal_array_lookup(arr, &sig); +} + +/** Add a signal inside a signal array. + * You are in charge of reference counting. + * \param arr The signal array. + * \param name The signal name. + * \param ref The reference to add. + */ +static inline void +signal_add(signal_array_t *arr, const char *name, const void *ref) +{ + unsigned long tok = a_strhash((const unsigned char *) name); + signal_t *sigfound = signal_array_getbyid(arr, tok); + if(sigfound) + cptr_array_append(&sigfound->sigfuncs, ref); + else + { + signal_t sig = { .id = tok }; + cptr_array_append(&sig.sigfuncs, ref); + signal_array_insert(arr, sig); + } +} + +/** Remove a signal inside a signal array. + * You are in charge of reference counting. + * \param arr The signal array. + * \param name The signal name. + * \param ref The reference to remove. + */ +static inline void +signal_remove(signal_array_t *arr, const char *name, const void *ref) +{ + signal_t *sigfound = signal_array_getbyid(arr, + a_strhash((const unsigned char *) name)); + if(sigfound) + foreach(func, sigfound->sigfuncs) + if(ref == *func) + { + cptr_array_remove(&sigfound->sigfuncs, func); + break; + } +} + +#endif + +// vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80 diff --git a/luaa.c b/luaa.c index 159cb197f..93a916c0b 100644 --- a/luaa.c +++ b/luaa.c @@ -70,8 +70,6 @@ extern const struct luaL_reg awesome_wibox_meta[]; extern const struct luaL_reg awesome_key_methods[]; extern const struct luaL_reg awesome_key_meta[]; -DO_ARRAY(const void *, void, DO_NOTHING) - /** Quit awesome. * \param L The Lua VM state. * \return The number of elements pushed on stack. @@ -501,7 +499,7 @@ luaA_hasitem(lua_State *L, const void *item) * \return False if we encounter an elements already in list. */ static bool -luaA_isloop_check(lua_State *L, void_array_t *elems) +luaA_isloop_check(lua_State *L, cptr_array_t *elems) { if(lua_istable(L, -1)) { @@ -513,7 +511,7 @@ luaA_isloop_check(lua_State *L, void_array_t *elems) return false; /* push the table in the elements list */ - void_array_append(elems, object); + cptr_array_append(elems, object); /* look every object in the "table" */ lua_pushnil(L); @@ -543,9 +541,9 @@ luaA_isloop(lua_State *L, int idx) { /* elems is an elements array that we will fill with all array we * encounter while browsing the tables */ - void_array_t elems; + cptr_array_t elems; - void_array_init(&elems); + cptr_array_init(&elems); /* push table on top */ lua_pushvalue(L, idx); @@ -555,7 +553,7 @@ luaA_isloop(lua_State *L, int idx) /* remove pushed table */ lua_pop(L, 1); - void_array_wipe(&elems); + cptr_array_wipe(&elems); return !ret; } diff --git a/luaa.h b/luaa.h index 113afb0bd..5f0975f05 100644 --- a/luaa.h +++ b/luaa.h @@ -50,12 +50,6 @@ luaL_typerror(L, n, "table"); \ } while(0) -#define luaA_checkfunction(L, n) \ - do { \ - if(!lua_isfunction(L, n)) \ - luaL_typerror(L, n, "function"); \ - } while(0) - #define luaA_checkscreen(screen) \ do { \ if(screen < 0 || screen >= globalconf.screens.len) \ @@ -239,27 +233,6 @@ luaA_registerfct(lua_State *L, int idx, int *fct) return luaA_register(L, idx, fct); } -/** Execute an Lua function on top of the stack. - * \param L The Lua stack. - * \param nargs The number of arguments for the Lua function. - * \param nret The number of returned value from the Lua function. - * \return True on no error, false otherwise. - */ -static inline bool -luaA_dofunction(lua_State *L, int nargs, int nret) -{ - if(nargs) - lua_insert(L, - (nargs + 1)); - if(lua_pcall(L, nargs, nret, 0)) - { - warn("error running function: %s", - lua_tostring(L, -1)); - lua_pop(L, 1); - return false; - } - return true; -} - /** Grab a function from the registry and execute it. * \param L The Lua stack. * \param ref The function reference.