From 11c17de2bf7fdcee82f790f92a8676e63e976142 Mon Sep 17 00:00:00 2001 From: Rui Guo Date: Sun, 7 Jun 2009 00:51:39 +0800 Subject: [PATCH] First working version of new event dispatching framwork. The cmdcallback.lua demo now works under the new framework. Major changes: 1. Implemented lua event dispatcher. 2. Implemented an event register interface in Screen object. 3. Modify cmdcallback.lua to explicitly register callback. Issues left: 1. Clean up the code. 2. unregister interface. 3. how to work if USEVARARGS not defined? --- src/lua.c | 76 +++++++++++++++++++++++++++++++++++++++++++-- src/process.c | 4 ++- src/script.c | 60 +++++++++++++++++------------------ src/script.h | 9 +++++- src/scripts/cmdcallback.lua | 1 + 5 files changed, 115 insertions(+), 35 deletions(-) diff --git a/src/lua.c b/src/lua.c index a6c01da..8da80f4 100644 --- a/src/lua.c +++ b/src/lua.c @@ -41,6 +41,7 @@ extern struct display *displays, *display; extern struct LayFuncs WinLf; extern struct layer *flayer; +static int LuaDispatch(void *handler, const char *params, va_list va); /** Template {{{ */ #define CHECK_TYPE(name, type) \ @@ -576,12 +577,32 @@ screen_append_msg(lua_State *L) return 0; } +static int +screen_register_event(lua_State *L) +{ + int len; + const char *event, *handler; + struct listener *l; + struct script_event *sev; + event = luaL_checklstring(L, 1, &len); + handler = luaL_checklstring(L, 2, &len); + sev = object_get_event(NULL, event); + if (sev) + { + l = (struct listener *)malloc(sizeof(struct listener)); + l->handler = (void *)handler; + l->dispatcher = LuaDispatch; + register_listener(sev, l); + } +} + static const luaL_reg screen_methods[] = { {"windows", screen_get_windows}, {"displays", screen_get_displays}, {"display", screen_get_display}, {"command", screen_exec_command}, {"append_msg", screen_append_msg}, + {"listen_to", screen_register_event}, {0, 0} }; @@ -639,7 +660,7 @@ LuaCallProcess(const char *name, struct fn_def defs[]) { struct display *d = display; unsigned int len; - char *message = luaL_checklstring(L, -1, &len); + const char *message = luaL_checklstring(L, -1, &len); LMsg(1, "%s", message ? message : "Unknown error"); lua_pop(L, 1); display = d; @@ -662,7 +683,7 @@ int LuaForeWindowChanged(void) if(lua_isstring(L, -1)) { unsigned int len; - char *message = luaL_checklstring(L, -1, &len); + const char *message = luaL_checklstring(L, -1, &len); LMsg(1, "%s", message ? message : "Unknown error"); lua_pop(L, 1); } @@ -713,7 +734,7 @@ int LuaCall(char *func, char **argv) if(lua_isstring(L, -1)) { unsigned int len; - char *message = luaL_checklstring(L, -1, &len); + const char *message = luaL_checklstring(L, -1, &len); LMsg(1, "%s", message ? message : "Unknown error"); lua_pop(L, 1); return 0; @@ -749,6 +770,55 @@ push_stringarray(lua_State *L, void *data) } } +int LuaPushParams(const char *params, va_list va) +{ + int num = 0; + while (*params) + { + switch (*params) + { + case 's': + lua_pushstring(L, va_arg(va, char *)); + break; + case 'S': + push_stringarray(L, va_arg(va, char **)); + break; + case 'i': + lua_pushinteger(L, va_arg(va, int)); + } + params++; + num++; + } + return num; +} + +static int +LuaDispatch(void *handler, const char *params, va_list va) +{ + const char *func = handler; + int argc; + + /*FIXME:Really need this?*/ + lua_settop(L, 0); + + lua_getfield(L, LUA_GLOBALSINDEX, func); + if (lua_isnil(L, -1)) + return 0; + argc = LuaPushParams(params, va); + + if (lua_pcall(L, argc, 0, 0) == LUA_ERRRUN && lua_isstring(L, -1)) + { + struct display *d = display; + unsigned int len; + char *message = luaL_checklstring(L, -1, &len); + LMsg(1, "%s", message ? message : "Unknown error"); + lua_pop(L, 1); + display = d; + return 0; + } + return 1; +} + int LuaCommandExecuted(const char *command, const char **args, int argc) { diff --git a/src/process.c b/src/process.c index b2ada0c..ec9cabf 100644 --- a/src/process.c +++ b/src/process.c @@ -4412,7 +4412,9 @@ int key; #ifdef SCRIPT if (nr < RC_LAST) - ScriptCommandExecuted(comms[nr].name, args, argc); + //ScriptCommandExecuted(comms[nr].name, args, argc); + trigger_sevent(&globalevents.cmdexecuted, comms[nr].name, args); + #endif if (display != odisplay) diff --git a/src/script.c b/src/script.c index b2b3ccd..fb14637 100644 --- a/src/script.c +++ b/src/script.c @@ -123,10 +123,7 @@ ScriptCmd(int argc, const char **argv) /* Event notification handling */ -struct gevents { - struct script_event cmdexecuted; - struct script_event detached; -} globalevents; +struct gevents globalevents; /* To add a new event, introduce a field for that event to the object in * question, and don't forget to put an descriptor here. NOTE: keep the @@ -142,12 +139,12 @@ struct gevents { * */ -struct { +struct sev_description { char *name; char *params; int offset; } event_table[] = { - {"global_cmdexecuted", "sSi", offsetof(struct gevents, cmdexecuted)}, + {"global_cmdexecuted", "sS", offsetof(struct gevents, cmdexecuted)}, {"global_detached", "", offsetof(struct gevents, detached)}, {"window_resize", "", offsetof(struct win, w_sev.resize)}, {"window_can_resize", "", offsetof(struct win, w_sev.canresize)} @@ -157,32 +154,35 @@ struct { * global events are searched. If no event is found, a NULL is returned. */ struct script_event * -object_get_event(char *obj, char *name) { - int lo, hi, n, cmp; - if (!obj) - obj = (char *)&globalevents; - - lo = 0; - n = hi = sizeof(event_table); - while (lo < hi) { - int half; - half = (lo + hi) >> 1; - cmp = strcmp(name, event_table[half].name); - if (cmp > 0) - lo = half + 1; - else - hi = half; +object_get_event(char *obj, const char *name) +{ + int lo, hi, n, cmp; + if (!obj) + obj = (char *)&globalevents; + + lo = 0; + n = hi = sizeof(event_table) / sizeof(struct sev_description); + while (lo < hi) + { + int half; + half = (lo + hi) >> 1; + cmp = strcmp(name, event_table[half].name); + if (cmp > 0) + lo = half + 1; + else + hi = half; } - if (lo >= n || strcmp(name, event_table[lo].name)) - return 0; - else { - /*found an entry.*/ - struct script_event *res; - res = (struct script_event *) (obj + event_table[lo].offset); - /*Setup the parameter record.*/ - res->params = event_table[lo].params; - return res; + if (lo >= n || strcmp(name, event_table[lo].name)) + return 0; + else + { + /*found an entry.*/ + struct script_event *res; + res = (struct script_event *) (obj + event_table[lo].offset); + /*Setup the parameter record.*/ + res->params = event_table[lo].params; + return res; } } diff --git a/src/script.h b/src/script.h index 2492984..b81d935 100644 --- a/src/script.h +++ b/src/script.h @@ -61,7 +61,7 @@ struct listener * The return value is significant: * a non-zero value will stop further * notification to the rest of the chain.*/ - int (*dispatcher) __P((void *handler, char *params, va_list va)); + int (*dispatcher) __P((void *handler, const char *params, va_list va)); /* smaller means higher privilege.*/ int priv; @@ -77,5 +77,12 @@ struct script_event char *params; struct listener *listeners; }; +struct script_event* object_get_event __P((char *obj, const char *name)); +int trigger_sevent(struct script_event *ev, VA_DOTS); +struct gevents { + struct script_event cmdexecuted; + struct script_event detached; +}; +extern struct gevents globalevents; #endif diff --git a/src/scripts/cmdcallback.lua b/src/scripts/cmdcallback.lua index b0c2d83..f6a5431 100644 --- a/src/scripts/cmdcallback.lua +++ b/src/scripts/cmdcallback.lua @@ -12,3 +12,4 @@ function command_executed(name, args) f:close() end +screen.listen_to("global_cmdexecuted", "command_executed") -- 2.11.4.GIT