Fix duplicate check on event hooking.
[screen-lua.git] / src / lua.c
blob496e7bbbe5dc0d23782e939206eaa98beb173d79
1 /* Lua scripting support
3 * Copyright (c) 2008 Sadrul Habib Chowdhury (sadrul@users.sf.net)
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3, or (at your option)
8 * any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program (see the file COPYING); if not, write to the
17 * Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
20 ****************************************************************
22 #include <sys/types.h>
23 #include "config.h"
24 #include "screen.h"
25 #include <sys/stat.h>
26 #include <unistd.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <stdlib.h>
32 #include "extern.h"
33 #include "logfile.h"
35 #include <lua.h>
36 #include <lauxlib.h>
37 #include <lualib.h>
39 static int StackDump(lua_State *L, const char *message)
41 FILE *f = fopen("/tmp/debug/stack", "ab");
42 int i = lua_gettop(L);
43 if (message)
44 fprintf(f, "%s", message);
45 while (i)
47 int t = lua_type(L, i);
48 switch (t)
50 case LUA_TSTRING:
51 fprintf(f, "String: %s\n", lua_tostring(L, i));
52 break;
54 case LUA_TBOOLEAN:
55 fprintf(f, "Boolean: %s\n", lua_toboolean(L, i) ? "true" : "false");
56 break;
58 case LUA_TNUMBER:
59 fprintf(f, "Number: %g\n", lua_tonumber(L, i));
60 break;
62 default:
63 fprintf(f, "Type: %s\n", lua_typename(L, t));
65 i--;
67 if (message)
68 fprintf(f, "----\n");
69 fclose(f);
70 return 0;
73 extern struct win *windows, *fore;
74 extern struct display *displays, *display;
75 extern struct LayFuncs WinLf;
76 extern struct layer *flayer;
78 static int LuaDispatch(void *handler, const char *params, va_list va);
79 static int LuaRegEvent(lua_State *L);
80 static int LuaUnRegEvent(lua_State *L);
81 static void LuaShowErr(lua_State *L);
82 struct binding lua_binding;
84 typedef int lua_handler;
85 #define LuaAllocHandler(a) a
86 #define LuaFreeHandler(a)
88 /** Template {{{ */
90 #define CHECK_TYPE(name, type) \
91 static type * \
92 check_##name(lua_State *L, int index) \
93 { \
94 type **var; \
95 luaL_checktype(L, index, LUA_TUSERDATA); \
96 var = (type **) luaL_checkudata(L, index, #name); \
97 if (!var || !*var) \
98 luaL_typerror(L, index, #name); \
99 return *var; \
102 #define PUSH_TYPE(name, type) \
103 static void \
104 push_##name(lua_State *L, type **t) \
106 if (!t || !*t) \
107 lua_pushnil(L); \
108 else \
110 type **r; \
111 r = (type **)lua_newuserdata(L, sizeof(type *)); \
112 *r = *t; \
113 luaL_getmetatable(L, #name); \
114 lua_setmetatable(L,-2); \
118 /* Much of the following template comes from:
119 * http://lua-users.org/wiki/BindingWithMembersAndMethods
122 static int get_int (lua_State *L, void *v)
124 lua_pushinteger (L, *(int*)v);
125 return 1;
128 static int set_int (lua_State *L, void *v)
130 *(int*)v = luaL_checkint(L, 3);
131 return 0;
134 static int get_number (lua_State *L, void *v)
136 lua_pushnumber(L, *(lua_Number*)v);
137 return 1;
140 static int set_number (lua_State *L, void *v)
142 *(lua_Number*)v = luaL_checknumber(L, 3);
143 return 0;
146 static int get_string (lua_State *L, void *v)
148 lua_pushstring(L, (char*)v );
149 return 1;
152 static int set_string (lua_State *L, void *v)
154 *(const char**)v = luaL_checkstring(L, 3);
155 return 0;
158 typedef int (*Xet_func) (lua_State *L, void *v);
160 /* member info for get and set handlers */
161 struct Xet_reg
163 const char *name; /* member name */
164 Xet_func func; /* get or set function for type of member */
165 size_t offset; /* offset of member within the struct */
166 int (*absolute)(lua_State *);
169 static void Xet_add (lua_State *L, const struct Xet_reg *l)
171 if (!l)
172 return;
173 for (; l->name; l++)
175 lua_pushstring(L, l->name);
176 lua_pushlightuserdata(L, (void*)l);
177 lua_settable(L, -3);
181 static int Xet_call (lua_State *L)
183 /* for get: stack has userdata, index, lightuserdata */
184 /* for set: stack has userdata, index, value, lightuserdata */
185 const struct Xet_reg *m = (const struct Xet_reg *)lua_touserdata(L, -1); /* member info */
186 lua_pop(L, 1); /* drop lightuserdata */
187 luaL_checktype(L, 1, LUA_TUSERDATA);
188 if (m->absolute)
189 return m->absolute(L);
190 return m->func(L, *(char**)lua_touserdata(L, 1) + m->offset);
193 static int index_handler (lua_State *L)
195 /* stack has userdata, index */
196 lua_pushvalue(L, 2); /* dup index */
197 lua_rawget(L, lua_upvalueindex(1)); /* lookup member by name */
198 if (!lua_islightuserdata(L, -1))
200 lua_pop(L, 1); /* drop value */
201 lua_pushvalue(L, 2); /* dup index */
202 lua_gettable(L, lua_upvalueindex(2)); /* else try methods */
203 if (lua_isnil(L, -1)) /* invalid member */
204 luaL_error(L, "cannot get member '%s'", lua_tostring(L, 2));
205 return 1;
207 return Xet_call(L); /* call get function */
210 static int newindex_handler (lua_State *L)
212 /* stack has userdata, index, value */
213 lua_pushvalue(L, 2); /* dup index */
214 lua_rawget(L, lua_upvalueindex(1)); /* lookup member by name */
215 if (!lua_islightuserdata(L, -1)) /* invalid member */
216 luaL_error(L, "cannot set member '%s'", lua_tostring(L, 2));
217 return Xet_call(L); /* call set function */
220 static int
221 struct_register(lua_State *L, const char *name, const luaL_reg fn_methods[], const luaL_reg meta_methods[],
222 const struct Xet_reg setters[], const struct Xet_reg getters[])
224 int metatable, methods;
226 /* create methods table & add it to the table of globals */
227 luaL_register(L, name, fn_methods);
228 methods = lua_gettop(L);
230 /* create metatable & add it to the registry */
231 luaL_newmetatable(L, name);
232 luaL_register(L, 0, meta_methods); /* fill metatable */
234 /* To identify the type of object */
235 lua_pushstring(L, "_objname");
236 lua_pushstring(L, name);
237 lua_rawset(L, -3);
239 metatable = lua_gettop(L);
241 lua_pushliteral(L, "__metatable");
242 lua_pushvalue(L, methods); /* dup methods table*/
243 lua_rawset(L, metatable); /* hide metatable:
244 metatable.__metatable = methods */
246 lua_pushliteral(L, "__index");
247 lua_pushvalue(L, metatable); /* upvalue index 1 */
248 Xet_add(L, getters); /* fill metatable with getters */
249 lua_pushvalue(L, methods); /* upvalue index 2 */
250 lua_pushcclosure(L, index_handler, 2);
251 lua_rawset(L, metatable); /* metatable.__index = index_handler */
253 lua_pushliteral(L, "__newindex");
254 lua_newtable(L); /* table for members you can set */
255 Xet_add(L, setters); /* fill with setters */
256 lua_pushcclosure(L, newindex_handler, 1);
257 lua_rawset(L, metatable); /* metatable.__newindex = newindex_handler */
259 /* FIXME: Why do we leave an element on the stack? */
260 lua_pop(L, 1); /* drop metatable */
261 return 1; /* return methods on the stack */
264 /** }}} */
266 /** Window {{{ */
268 PUSH_TYPE(window, struct win)
270 CHECK_TYPE(window, struct win)
272 static int get_window(lua_State *L, void *v)
274 push_window(L, (struct win **)v);
275 return 1;
278 static int
279 window_change_title(lua_State *L)
281 struct win *w = check_window(L, 1);
282 unsigned int len;
283 const char *title = luaL_checklstring(L, 2, &len);
284 ChangeAKA(w, (char *)title, len);
285 return 0;
288 static int
289 window_get_monitor_status(lua_State *L)
291 struct win *w = check_window(L, 1);
292 int activity = luaL_checkint(L, 2);
293 if (activity)
294 /*monitor*/
295 lua_pushinteger(L, w->w_monitor != MON_OFF);
296 else
297 /*silence*/
298 lua_pushinteger(L, w->w_silence == SILENCE_ON ? w->w_silencewait: 0);
300 return 1;
303 static const luaL_reg window_methods[] = {
304 {"get_monitor_status", window_get_monitor_status},
305 {"hook", LuaRegEvent},
306 {0, 0}
309 static int
310 window_tostring(lua_State *L)
312 char str[128];
313 struct win *w = check_window(L, 1);
314 snprintf(str, sizeof(str), "{window #%d: '%s'}", w->w_number, w->w_title);
315 lua_pushstring(L, str);
316 return 1;
319 static int
320 window_equality(lua_State *L)
322 struct win *w1 = check_window(L, 1), *w2 = check_window(L, 2);
323 lua_pushboolean(L, (w1 == w2 || (w1 && w2 && w1->w_number == w2->w_number)));
324 return 1;
327 static const luaL_reg window_metamethods[] = {
328 {"__tostring", window_tostring},
329 {"__eq", window_equality},
330 {0, 0}
333 static const struct Xet_reg window_setters[] = {
334 {"title", 0, 0, window_change_title/*absolute setter*/},
335 {0, 0}
338 static const struct Xet_reg window_getters[] = {
339 {"title", get_string, offsetof(struct win, w_title) + 8},
340 {"number", get_int, offsetof(struct win, w_number)},
341 {"dir", get_string, offsetof(struct win, w_dir)},
342 {"tty", get_string, offsetof(struct win, w_tty)},
343 {"pid", get_int, offsetof(struct win, w_pid)},
344 {"group", get_window, offsetof(struct win, w_group)},
345 {"bell", get_int, offsetof(struct win, w_bell)},
346 {0, 0}
350 /** }}} */
352 /** AclUser {{{ */
354 PUSH_TYPE(user, struct acluser)
356 CHECK_TYPE(user, struct acluser)
358 static int
359 get_user(lua_State *L, void *v)
361 push_user(L, (struct acluser **)v);
362 return 1;
365 static const luaL_reg user_methods[] = {
366 {0, 0}
369 static int
370 user_tostring(lua_State *L)
372 char str[128];
373 struct acluser *u = check_user(L, 1);
374 snprintf(str, sizeof(str), "{user '%s'}", u->u_name);
375 lua_pushstring(L, str);
376 return 1;
379 static const luaL_reg user_metamethods[] = {
380 {"__tostring", user_tostring},
381 {0, 0}
384 static const struct Xet_reg user_setters[] = {
385 {0, 0}
388 static const struct Xet_reg user_getters[] = {
389 {"name", get_string, offsetof(struct acluser, u_name)},
390 {"password", get_string, offsetof(struct acluser, u_password)},
391 {0, 0}
394 /** }}} */
396 /** Canvas {{{ */
398 PUSH_TYPE(canvas, struct canvas)
400 CHECK_TYPE(canvas, struct canvas)
402 static int
403 get_canvas(lua_State *L, void *v)
405 push_canvas(L, (struct canvas **)v);
406 return 1;
409 static int
410 canvas_select(lua_State *L)
412 struct canvas *c = check_canvas(L, 1);
413 if (!display || D_forecv == c)
414 return 0;
415 SetCanvasWindow(c, Layer2Window(c->c_layer));
416 D_forecv = c;
418 /* XXX: the following all is duplicated from process.c:DoAction.
419 * Should these be in some better place?
421 ResizeCanvas(&D_canvas);
422 RecreateCanvasChain();
423 RethinkDisplayViewports();
424 ResizeLayersToCanvases(); /* redisplays */
425 fore = D_fore = Layer2Window(D_forecv->c_layer);
426 flayer = D_forecv->c_layer;
427 #ifdef RXVT_OSC
428 if (D_xtermosc[2] || D_xtermosc[3])
430 Activate(-1);
431 break;
433 #endif
434 RefreshHStatus();
435 #ifdef RXVT_OSC
436 RefreshXtermOSC();
437 #endif
438 flayer = D_forecv->c_layer;
439 CV_CALL(D_forecv, LayRestore();LaySetCursor());
440 WindowChanged(0, 'F');
441 return 1;
444 static const luaL_reg canvas_methods[] = {
445 {"select", canvas_select},
446 {0, 0}
449 static const luaL_reg canvas_metamethods[] = {
450 {0, 0}
453 static const struct Xet_reg canvas_setters[] = {
454 {0, 0}
457 static int
458 canvas_get_window(lua_State *L)
460 struct canvas *c = check_canvas(L, 1);
461 struct win *win = Layer2Window(c->c_layer);
462 if (win)
463 push_window(L, &win);
464 else
465 lua_pushnil(L);
466 return 1;
469 static const struct Xet_reg canvas_getters[] = {
470 {"next", get_canvas, offsetof(struct canvas, c_next)},
471 {"xoff", get_int, offsetof(struct canvas, c_xoff)},
472 {"yoff", get_int, offsetof(struct canvas, c_yoff)},
473 {"xs", get_int, offsetof(struct canvas, c_xs)},
474 {"ys", get_int, offsetof(struct canvas, c_ys)},
475 {"xe", get_int, offsetof(struct canvas, c_xe)},
476 {"ye", get_int, offsetof(struct canvas, c_ye)},
477 {"window", 0, 0, canvas_get_window},
478 {0, 0}
481 /** }}} */
483 /** Layout {{{ */
485 PUSH_TYPE(layout, struct layout)
486 CHECK_TYPE(layout, struct layout)
488 static const struct Xet_reg layout_getters[] = {
489 {0,0}
492 static int
493 get_layout(lua_State *L, void *v)
495 push_layout(L, (struct layout **)v);
496 return 1;
499 /** }}} */
501 /** Display {{{ */
503 PUSH_TYPE(display, struct display)
505 CHECK_TYPE(display, struct display)
507 static int
508 display_get_canvases(lua_State *L)
510 struct display *d;
511 struct canvas *iter;
512 int count;
514 d = check_display(L, 1);
515 lua_newtable(L);
516 for (iter = d->d_cvlist, count = 0; iter; iter = iter->c_next, count++) {
517 lua_pushinteger(L, count);
518 push_canvas(L, &iter);
519 lua_settable(L, -3);
522 return 1;
525 static const luaL_reg display_methods[] = {
526 {"get_canvases", display_get_canvases},
527 {0, 0}
530 static int
531 display_tostring(lua_State *L)
533 char str[128];
534 struct display *d = check_display(L, 1);
535 snprintf(str, sizeof(str), "{display: tty = '%s', term = '%s'}", d->d_usertty, d->d_termname);
536 lua_pushstring(L, str);
537 return 1;
540 static const luaL_reg display_metamethods[] = {
541 {"__tostring", display_tostring},
542 {0, 0}
545 static const struct Xet_reg display_setters[] = {
546 {0, 0}
549 static const struct Xet_reg display_getters[] = {
550 {"tty", get_string, offsetof(struct display, d_usertty)},
551 {"term", get_string, offsetof(struct display, d_termname)},
552 {"fore", get_window, offsetof(struct display, d_fore)},
553 {"other", get_window, offsetof(struct display, d_other)},
554 {"width", get_int, offsetof(struct display, d_width)},
555 {"height", get_int, offsetof(struct display, d_height)},
556 {"user", get_user, offsetof(struct display, d_user)},
557 {"layout", get_layout, offsetof(struct display, d_layout)},
558 {0, 0}
561 /** }}} */
563 /** Screen {{{ */
565 static int
566 screen_get_windows(lua_State *L)
568 struct win *iter;
569 int count;
571 lua_newtable(L);
572 for (iter = windows, count = 0; iter; iter = iter->w_next, count++) {
573 lua_pushinteger(L, iter->w_number);
574 push_window(L, &iter);
575 lua_settable(L, -3);
578 return 1;
581 static int
582 screen_get_displays(lua_State *L)
584 struct display *iter;
585 int count;
587 lua_newtable(L);
588 for (iter = displays, count = 0; iter; iter = iter->d_next, count++) {
589 lua_pushinteger(L, count);
590 push_display(L, &iter);
591 lua_settable(L, -3);
594 return 1;
597 static int
598 screen_get_display(lua_State *L)
600 push_display(L, &display);
601 return 1;
604 static int
605 screen_exec_command(lua_State *L)
607 const char *command;
608 unsigned int len;
610 command = luaL_checklstring(L, 1, &len);
611 if (command)
612 RcLine((char *)command, len);
614 return 0;
617 static int
618 screen_append_msg(lua_State *L)
620 const char *msg, *color;
621 unsigned int len;
622 msg = luaL_checklstring(L, 1, &len);
623 if (lua_isnil(L, 2))
624 color = NULL;
625 else
626 color = luaL_checklstring(L, 2, &len);
627 AppendWinMsgRend(msg, color);
628 return 0;
631 void
632 script_input_fn(char *buf, int len, char *priv)
634 lua_State *L = (lua_State *)priv;
635 lua_pushstring(L, buf);
636 if (lua_pcall(L, 1, 0, 0) == LUA_ERRRUN)
638 if(lua_isstring(L, -1))
640 LuaShowErr(L);
645 static int
646 screen_input(lua_State *L)
648 char * prompt = NULL;
650 prompt = (char *)luaL_checkstring(L, 1);
651 Input(prompt, 100, INP_COOKED, script_input_fn, (char *)L, 0);
653 return 0;
656 static const luaL_reg screen_methods[] = {
657 {"windows", screen_get_windows},
658 {"displays", screen_get_displays},
659 {"display", screen_get_display},
660 {"command", screen_exec_command},
661 {"append_msg", screen_append_msg},
662 {"hook", LuaRegEvent},
663 {"unhook", LuaUnRegEvent},
664 {"input", screen_input},
665 {0, 0}
668 static const luaL_reg screen_metamethods[] = {
669 {0, 0}
672 static const struct Xet_reg screen_setters[] = {
673 {0, 0}
676 static const struct Xet_reg screen_getters[] = {
677 {0, 0}
680 /** }}} */
682 /** Public functions {{{ */
683 static lua_State *L;
684 int LuaInit(void)
686 L = luaL_newstate();
688 luaL_openlibs(L);
690 #define REGISTER(X) struct_register(L, #X , X ## _methods, X##_metamethods, X##_setters, X##_getters)
692 REGISTER(screen);
693 REGISTER(window);
694 REGISTER(display);
695 REGISTER(user);
696 REGISTER(canvas);
698 /* To store handler funcs */
699 luaL_getmetatable(L, "screen");
700 /* two kinds of info in this table:
701 * _funckey[func]->key
702 * _funckey[key]->refcnt */
703 lua_pushstring(L, "_funckey");
704 lua_newtable(L);
705 lua_rawset(L, -3);
706 /* two kinds of info in this table:
707 * _keyfunc[key]->func
708 * _keyfunc[func]->name */
709 lua_pushstring(L, "_keyfunc");
710 lua_newtable(L);
711 lua_rawset(L, -3);
712 lua_pop(L, 1);
714 return 0;
717 /* An error message on top of the stack. */
718 static void
719 LuaShowErr(lua_State *L)
721 struct display *d = display;
722 unsigned int len;
723 const char *message = luaL_checklstring(L, -1, &len);
724 LMsg(0, "%s", message ? message : "Unknown error");
725 lua_pop(L, 1);
726 display = d;
729 struct fn_def
731 void (*push_fn)(lua_State *, void*);
732 void *value;
735 static int
736 LuaCallProcess(const char *name, struct fn_def defs[])
738 int argc = 0;
740 lua_getfield(L, LUA_GLOBALSINDEX, name);
741 if (lua_isnil(L, -1))
743 lua_pop(L,1);
744 return 0;
746 for (argc = 0; defs[argc].push_fn; argc++)
747 defs[argc].push_fn(L, defs[argc].value);
748 if (lua_pcall(L, argc, 0, 0) == LUA_ERRRUN && lua_isstring(L, -1))
750 LuaShowErr(L);
751 return 0;
753 return 1;
756 int LuaSource(const char *file, int async)
758 if (!L)
759 return 0;
760 struct stat st;
761 if (stat(file, &st) == -1)
762 Msg(errno, "Error loading lua script file '%s'", file);
763 else
765 int len = strlen(file);
766 if (len < 4 || strncmp(file + len - 4, ".lua", 4) != 0)
767 return 0;
768 if (luaL_dofile(L, file) && lua_isstring(L, -1))
770 LuaShowErr(L);
772 return 1;
774 return 0;
777 int LuaFinit(void)
779 if (!L)
780 return 0;
781 lua_close(L);
782 L = (lua_State*)0;
783 return 0;
787 LuaProcessCaption(const char *caption, struct win *win, int len)
789 if (!L)
790 return 0;
791 struct fn_def params[] = {
792 {lua_pushstring, caption},
793 {push_window, &win},
794 {lua_pushinteger, len},
795 {NULL, NULL}
797 return LuaCallProcess("process_caption", params);
800 static void
801 push_stringarray(lua_State *L, char **args)
803 int i;
804 lua_newtable(L);
805 for (i = 1; args && *args; i++) {
806 lua_pushinteger(L, i);
807 lua_pushstring(L, *args++);
808 lua_settable(L, -3);
813 LuaPushParams(lua_State *L, const char *params, va_list va)
815 int num = 0;
816 while (*params)
818 switch (*params)
820 case 's':
821 lua_pushstring(L, va_arg(va, char *));
822 break;
823 case 'S':
824 push_stringarray(L, va_arg(va, char **));
825 break;
826 case 'i':
827 lua_pushinteger(L, va_arg(va, int));
829 params++;
830 num++;
832 return num;
835 int LuaCall(char *func, char **argv)
837 int argc;
838 if (!L)
839 return 0;
841 StackDump(L, "Before LuaCall\n");
842 lua_getfield(L, LUA_GLOBALSINDEX, func);
843 if (lua_isnil(L, -1))
845 lua_pop(L, 1);
846 lua_pushstring(L, "Could not find the script function\n");
847 LuaShowErr(L);
848 return 0;
850 for (argc = 0; *argv; argv++, argc++)
852 lua_pushstring(L, *argv);
854 if (lua_pcall(L, argc, 0, 0) == LUA_ERRRUN)
856 if(lua_isstring(L, -1))
858 StackDump(L, "After LuaCall\n");
859 LuaShowErr(L);
860 return 0;
863 return 1;
866 /*** Lua callback handler management {{{ */
869 LuaPushHTable(lua_State *L, int screen, const char * t)
871 lua_pushstring(L, t);
872 lua_rawget(L, screen);
873 /* FIXME: Do we need to balance the stack here? */
874 if (lua_isnil(L, -1))
875 luaL_error(L, "Fatal! Fail to get function registeration table!");
876 return lua_gettop(L);
879 void
880 LuaPushHandler(lua_State *L, lua_handler lh)
882 int keyfunc;
883 luaL_getmetatable(L, "screen");
884 keyfunc = LuaPushHTable(L, lua_gettop(L), "_keyfunc");
885 lua_rawgeti(L, keyfunc, lh);
886 lua_replace(L, -3);
887 lua_pop(L, 1);
891 LuaFuncKey(lua_State *L, int idx)
893 int key, funckey, sc;
894 luaL_getmetatable(L, "screen");
895 sc = lua_gettop(L);
896 funckey = LuaPushHTable(L, sc, "_funckey");
898 lua_pushvalue(L, idx);
899 lua_gettable(L, funckey);/*funckey[func] ==?*/
900 if (lua_isnil(L, -1))
902 /* Not found, alloc a new key */
904 /*funckey[key] = 1*/
905 lua_pushinteger(L, 1);
906 key = luaL_ref(L, funckey);
908 /*funckey[func]=key*/
909 lua_pushvalue(L, idx);
910 lua_pushinteger(L, key);
911 lua_settable(L, funckey);
913 int keyfunc = LuaPushHTable(L, sc, "_keyfunc");
914 /*keyfunc[key] = func*/
915 lua_pushinteger(L, key);
916 lua_pushvalue(L, idx);
917 lua_settable(L, keyfunc);
919 lua_pop(L, 1);
921 else
922 key = lua_tointeger(L, -1);/*key = funckey[func]*/
924 lua_pop(L, 3);
925 return key;
928 void
929 LuaHRef(lua_State *L, int key, int reg)
931 int funckey, keyfunc, cnt, sc, idx;
932 luaL_getmetatable(L, "screen");
933 sc = lua_gettop(L);
934 funckey = LuaPushHTable(L, sc, "_funckey");
935 keyfunc = LuaPushHTable(L, sc, "_keyfunc");
937 lua_rawgeti(L, keyfunc, key);
938 idx = lua_gettop(L);
940 lua_rawgeti(L, funckey, key);
941 cnt = lua_tointeger(L, -1);/*cnt = htable[key]*/
942 if (!reg && cnt <= 1)
944 /*release the last reference*/
945 luaL_unref(L, funckey, key);
946 lua_pushvalue(L, idx);
947 lua_pushnil(L);
948 lua_settable(L, funckey); /*htable[func]=key*/
950 else
952 lua_pushinteger(L, key);
953 lua_pushinteger(L, reg? cnt + 1 : cnt - 1);
954 lua_settable(L, funckey); /*htable[key] = cnt + 1*/
956 lua_pop(L, 3);
959 void
960 LuaHSetName(lua_State *L, int key, int name)
962 int keyfunc, sc;
963 luaL_getmetatable(L, "screen");
964 sc = lua_gettop(L);
965 keyfunc = LuaPushHTable(L, sc, "_keyfunc");
967 lua_rawgeti(L, keyfunc, key);
968 lua_pushvalue(L, name);
969 lua_rawset(L, keyfunc);
971 lua_pop(L, 2);
974 /* Do not hold the return value for long */
975 const char *
976 LuaHGetName(lua_State *L, lua_handler key)
978 int keyfunc, sc;
979 const char * name;
980 luaL_getmetatable(L, "screen");
981 sc = lua_gettop(L);
982 keyfunc = LuaPushHTable(L, sc, "_keyfunc");
984 lua_rawgeti(L, keyfunc, key);
985 lua_rawget(L, keyfunc);
986 name = lua_tostring(L, -1);
987 lua_pop(L, 3);
988 return name;
991 lua_handler
992 LuaCheckHandler(lua_State *L, int idx, int reg)
994 int name = 0, key, sc;
995 if (lua_isstring(L, idx))
997 const char * handler;
998 /* registered with func name.*/
999 handler = luaL_checkstring(L, idx);
1000 name = idx++;
1001 lua_getfield(L, LUA_GLOBALSINDEX, handler);
1002 if (!lua_isfunction(L, -1))
1003 luaL_error(L, "The specified handler %s in param #%d is not a function", handler, idx);
1005 else if (!lua_isfunction(L, idx))
1006 luaL_error(L, "Handler should be a function or the name of function");
1008 sc = lua_gettop(L);
1009 key = LuaFuncKey(L, idx );
1010 LuaHRef(L, key, reg);
1011 if (name)
1013 LuaHSetName(L, key, name);
1014 lua_pop(L, 1);
1016 return LuaAllocHandler(key);
1020 LuaHdlrComp(lua_handler h1, lua_handler h2)
1022 return h1 - h2;
1025 /* }}} **/
1027 static int
1028 LuaDispatch(void *handler, const char *params, va_list va)
1030 lua_handler lh = (lua_handler)handler;
1031 int argc, retvalue;
1033 StackDump(L, "before dispatch");
1035 LuaPushHandler(L, lh);
1036 if (lua_isnil(L, -1))
1038 lua_pop(L, 1);
1039 return 0;
1041 argc = LuaPushParams(L, params, va);
1043 if (lua_pcall(L, argc, 1, 0) == LUA_ERRRUN && lua_isstring(L, -1))
1045 StackDump(L, "After LuaDispatch\n");
1046 LuaShowErr(L);
1047 return 0;
1049 retvalue = lua_tonumber(L, -1);
1050 lua_pop(L, 1);
1051 return retvalue;
1054 int LuaForeWindowChanged(void)
1056 struct fn_def params[] = {
1057 {push_display, &display},
1058 {push_window, display ? &D_fore : &fore},
1059 {NULL, NULL}
1061 if (!L)
1062 return 0;
1063 return LuaCallProcess("fore_changed", params);
1066 #define SEVNAME_MAX 30
1067 static int
1068 LuaRegEvent(lua_State *L)
1070 /* signature: hook(obj, event, handler, priv);
1071 * or: hook(event, handler, priv)
1072 * returns: A ticket for later unregister. */
1073 int idx = 1, argc = lua_gettop(L);
1074 unsigned int priv = 31; /* Default privilege */
1075 lua_handler lh;
1077 char *obj = NULL;
1078 const char *objname = "global";
1080 static char evbuf[SEVNAME_MAX];
1081 const char *event;
1083 struct script_event *sev;
1085 StackDump(L, "Before RegEvent\n");
1087 /* Identify the object, if specified */
1088 if (luaL_getmetafield(L, 1, "_objname"))
1090 objname = luaL_checkstring(L, -1);
1091 lua_pop(L, 1);
1092 if (!strcmp("screen", objname))
1093 objname = "global";
1094 else
1095 obj = *(char **)lua_touserdata(L, 1);
1096 idx++;
1099 event = luaL_checkstring(L, idx++);
1100 snprintf(evbuf, SEVNAME_MAX, "%s_%s", objname, event);
1102 /* Check and get the handler */
1103 lh = LuaCheckHandler(L, idx++, 1);
1104 if (!lh)
1105 luaL_error(L, "Out of memory");
1107 StackDump(L, "In RegEvent\n");
1109 if (idx <= argc)
1110 priv = luaL_checkinteger(L, idx);
1112 sev = object_get_event(obj, evbuf);
1113 if (sev)
1115 struct listener *l;
1116 l = (struct listener *)malloc(sizeof(struct listener));
1117 if (!l)
1118 return luaL_error(L, "Out of memory");
1119 l->priv = priv;
1120 l->bd = &lua_binding;
1121 l->handler = (void *)lh;
1122 if (register_listener(sev, l))
1124 const char *fname = LuaHGetName(L, lh);
1125 free(l);
1126 if (fname)
1127 return luaL_error(L, "Handler %s has already been registered", fname);
1128 else
1129 return luaL_error(L, "Handler has already been registered");
1131 /* Return the handler for un-register */
1132 lua_pushlightuserdata(L, l);
1134 else
1135 return luaL_error(L, "Invalid event specified: %s for object %s", event, objname);
1137 StackDump(L, "After RegEvent\n");
1138 return 1;
1141 static int
1142 LuaUnRegEvent(lua_State *L)
1144 /* signature: unhook([obj], ticket)
1145 * returns: true of success, false otherwise */
1146 int idx = 1;
1147 struct listener *l;
1149 /* If the param is not as expected */
1150 if (!lua_islightuserdata(L, idx))
1152 /* Then it should be the userdata to be ignore, but if not ... */
1153 if (!lua_isuserdata(L, idx))
1154 luaL_checktype(L, idx, LUA_TLIGHTUSERDATA);
1155 idx++;
1156 luaL_checktype(L, idx, LUA_TLIGHTUSERDATA);
1159 l = (struct listener*)lua_touserdata(L, idx++);
1161 /* Validate the listener structure */
1162 if (!l || !l->handler)
1164 /* invalid */
1165 lua_pushboolean(L,0);
1167 else
1169 LuaHRef(L, (lua_handler)l->handler, 0);
1170 LuaFreeHandler(((lua_handler)&(l->handler)));
1171 unregister_listener(l);
1172 lua_pushboolean(L, 1);
1175 return 1;
1178 /** }}} */
1180 struct ScriptFuncs LuaFuncs =
1182 LuaForeWindowChanged,
1183 LuaProcessCaption
1186 struct binding lua_binding =
1188 "lua", /*name*/
1189 0, /*inited*/
1190 0, /*registered*/
1191 LuaInit,
1192 LuaFinit,
1193 LuaCall,
1194 LuaSource,
1195 LuaDispatch,
1196 LuaHdlrComp,
1197 0, /*b_next*/
1198 &LuaFuncs