From 1f3ddb9f464c17eea57e9619301f540d68b43c68 Mon Sep 17 00:00:00 2001 From: Rui Guo Date: Mon, 8 Jun 2009 00:03:38 +0800 Subject: [PATCH] Event dispatching: Improvement & bugfix 1. The reg/unreg interfaces are now called hook/unhook, the listen_to method no longer exists. 2. Implement unregister logic, The privlege is unsigned now, and default to 31. 3. Check to prevent double reg/unreg the same handler. 4. Modify cmdcallback demo to enable toogle of logging. --- src/lua.c | 45 ++++++++++++++++++++++++++-------------- src/script.c | 50 +++++++++++++++++++++++++++++++-------------- src/script.h | 6 ++++-- src/scripts/cmdcallback.lua | 9 +++++++- 4 files changed, 77 insertions(+), 33 deletions(-) diff --git a/src/lua.c b/src/lua.c index aabfd6e..490b96e 100644 --- a/src/lua.c +++ b/src/lua.c @@ -43,6 +43,7 @@ extern struct layer *flayer; static int LuaDispatch(void *handler, const char *params, va_list va); static int LuaRegEvent(lua_State *L); +static int LuaUnRegEvent(lua_State *L); /** Template {{{ */ @@ -260,7 +261,7 @@ window_get_monitor_status(lua_State *L) static const luaL_reg window_methods[] = { {"get_monitor_status", window_get_monitor_status}, - {"listen_to", LuaRegEvent}, + {"hook", LuaRegEvent}, {0, 0} }; @@ -592,7 +593,8 @@ static const luaL_reg screen_methods[] = { {"display", screen_get_display}, {"command", screen_exec_command}, {"append_msg", screen_append_msg}, - {"listen_to", LuaRegEvent}, + {"hook", LuaRegEvent}, + {"unhook", LuaUnRegEvent}, {0, 0} }; @@ -815,19 +817,20 @@ LuaCommandExecuted(const char *command, const char **args, int argc) return LuaCallProcess("command_executed", params); }*/ +#define SEVNAME_MAX 30 static int LuaRegEvent(lua_State *L) { - /* signature: listen_to(obj, event, handler, priv); - * or: listen_to(event, handler, priv) + /* signature: hook(obj, event, handler, priv); + * or: hook(event, handler, priv) * returns: A ticket for later unregister. */ int idx = 1, argc = lua_gettop(L); - int priv = 0; + int priv = 31; /* Default privilege */ char *obj = NULL; const char *objname = "global"; - static char evbuf[30]; + static char evbuf[SEVNAME_MAX]; const char *event, *handler; struct script_event *sev; @@ -845,7 +848,7 @@ LuaRegEvent(lua_State *L) } event = luaL_checkstring(L, idx++); - snprintf(evbuf, 30, "%s_%s", objname, event); + snprintf(evbuf, SEVNAME_MAX, "%s_%s", objname, event); handler = luaL_checkstring(L, idx++); if (idx <= argc) priv = luaL_checkinteger(L, idx); @@ -860,7 +863,11 @@ LuaRegEvent(lua_State *L) l->handler = (void *)handler; l->priv = priv; l->dispatcher = LuaDispatch; - register_listener(sev, l); + if (register_listener(sev, l)) + { + free(l); + return luaL_error(L, "Handler %s has already been registered", handler); + } /*Return the handler for un-register*/ lua_pushlightuserdata(L, l); } @@ -874,27 +881,35 @@ static int LuaUnRegEvent(lua_State *L) { /* signature: release([obj], ticket, handler) - * returns: zero of success, non-zero otherwise */ + * returns: true of success, false otherwise */ int idx = 1; struct listener *l; const char *handler; - if (lua_isuserdata(L, idx)) - idx++; - luaL_checktype(L, idx, LUA_TLIGHTUSERDATA); + /* If the param is not as expected */ + if (!lua_islightuserdata(L, idx)) + { + /* Then it should be the userdata to be ignore, but if not ... */ + if (!lua_isuserdata(L, idx)) + luaL_checktype(L, idx, LUA_TLIGHTUSERDATA); + idx++; + luaL_checktype(L, idx, LUA_TLIGHTUSERDATA); + } + l = (struct listener*)lua_touserdata(L, idx++); handler = luaL_checkstring(L, idx++); /*Validate the listener structure*/ - if (strcmp((char *)handler, (char *)l->handler)) + if (!l || !l->handler + || strncmp((char *)handler, (char *)l->handler, SEVNAME_MAX)) { /* invalid */ - lua_pushinteger(L, 1); + lua_pushboolean(L,0); } else { unregister_listener(l); - lua_pushinteger(L, 0); + lua_pushboolean(L, 1); } return 1; diff --git a/src/script.c b/src/script.c index 3faf4bc..4759c27 100644 --- a/src/script.c +++ b/src/script.c @@ -187,32 +187,51 @@ object_get_event(char *obj, const char *name) } /* Put a listener in a proper position in the chain - * according to the privlege.*/ -#define PRIV_MIN -31 -void + * according to the privlege. + * Not insert duplicate entry. return zero if successful.*/ +int register_listener(struct script_event *ev, struct listener *l) { - int priv; - struct listener head, *p; - head.chain = ev->listeners; - p = &head; + unsigned int priv = l->priv; + struct listener *p, *iter = &ev->listeners; - if (l->priv < PRIV_MIN) - l->priv = PRIV_MIN; - priv = l->priv; + while(iter->chain && priv >= iter->chain->priv) + { + iter = iter->chain; + /* return if duplicate found*/ + if (iter->handler == l->handler + && iter->dispatcher == l->dispatcher) + return 1; + } + p = iter; - while (p->chain && priv >= p->chain->priv) - p = p->chain; + while(iter->chain) + { + iter = iter->chain; + /* return if duplicate found*/ + if (iter->handler == l->handler + && iter->dispatcher == l->dispatcher) + return 1; + } l->chain = p->chain; + l->prev = p; + if (p->chain) + p->chain->prev = l; p->chain = l; - ev->listeners = head.chain; + return 0; } void unregister_listener(struct listener *l) { - /*TODO*/ + struct listener *p = l->prev; + p->chain = l->chain; + if (l->chain) + l->chain->prev = p; + l->chain = l->prev = 0; + l->handler = 0; + free(l); } /* Trigger event with given parameters.*/ @@ -228,7 +247,7 @@ trigger_sevent(struct script_event *ev, VA_DOTS) return 0; /*process the chain in order, stop if any of the handler returns true.*/ - chain = ev->listeners; + chain = ev->listeners.chain; params = ev->params; while (chain) { @@ -237,6 +256,7 @@ trigger_sevent(struct script_event *ev, VA_DOTS) VA_END(va); if (res) break; + chain = chain->chain; } return res; diff --git a/src/script.h b/src/script.h index 10762f8..c268eb5 100644 --- a/src/script.h +++ b/src/script.h @@ -50,6 +50,7 @@ void ScriptCmd __P((int argc, const char **argv)); /***Script events***/ +struct script_event; /* Script event listener */ struct listener { @@ -63,8 +64,9 @@ struct listener int (*dispatcher) __P((void *handler, const char *params, va_list va)); /* smaller means higher privilege.*/ - int priv; + unsigned int priv; struct listener *chain; + struct listener *prev; }; /* the script_event structure needs to be zeroed before using. @@ -74,7 +76,7 @@ struct script_event { /* expected parameter description of this event. */ char *params; - struct listener *listeners; + struct listener listeners; }; struct script_event* object_get_event __P((char *obj, const char *name)); int trigger_sevent(struct script_event *ev, VA_DOTS); diff --git a/src/scripts/cmdcallback.lua b/src/scripts/cmdcallback.lua index 7fbd9bc..d905954 100644 --- a/src/scripts/cmdcallback.lua +++ b/src/scripts/cmdcallback.lua @@ -12,4 +12,11 @@ function command_executed(name, args) f:close() end -screen.listen_to("cmdexecuted", "command_executed") +function toogle_cmd_log() + if (type(ticket) == "nil") then + ticket = screen.hook("cmdexecuted", "command_executed") + else + screen.unhook(ticket, "command_executed") + ticket = nil + end +end -- 2.11.4.GIT