First working version of new event dispatching framwork.
authorRui Guo <firemeteor.guo@gmail.com>
Sat, 6 Jun 2009 16:51:39 +0000 (7 00:51 +0800)
committerRui Guo <firemeteor.guo@gmail.com>
Sat, 6 Jun 2009 16:51:39 +0000 (7 00:51 +0800)
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
src/process.c
src/script.c
src/script.h
src/scripts/cmdcallback.lua

index a6c01da..8da80f4 100644 (file)
--- 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)
 {
index b2ada0c..ec9cabf 100644 (file)
@@ -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)
index b2b3ccd..fb14637 100644 (file)
@@ -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;
     }
 }
 
index 2492984..b81d935 100644 (file)
@@ -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
index b0c2d83..f6a5431 100644 (file)
@@ -12,3 +12,4 @@ function command_executed(name, args)
   f:close()
 end
 
+screen.listen_to("global_cmdexecuted", "command_executed")