/* * Curses binding for Lua 5.1, 5.2 & 5.3. * * (c) Gary V. Vaughan 2013-2017 * (c) Reuben Thomas 2009-2012 * (c) Tiago Dionizio 2004-2007 * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*** Curses Window objects. The methods documented on this page are available on any Curses Window object, such as created by: stdscr = curses.initscr () window = curses.newwin (25, 80, 0, 0) @classmod curses.window */ #include #include "../teliva.h" #include "_helpers.c" #include "chstr.c" static const char *WINDOWMETA = "curses:window"; static void lc_newwin(lua_State *L, WINDOW *nw) { if (nw) { WINDOW **w = lua_newuserdata(L, sizeof(WINDOW*)); luaL_getmetatable(L, WINDOWMETA); lua_setmetatable(L, -2); *w = nw; } else { lua_pushliteral(L, "failed to create window"); lua_error(L); } } static WINDOW ** lc_getwin(lua_State *L, int offset) { WINDOW **w = (WINDOW**)luaL_checkudata(L, offset, WINDOWMETA); if (w == NULL) luaL_argerror(L, offset, "bad curses window"); return w; } static WINDOW * checkwin(lua_State *L, int offset) { WINDOW **w = lc_getwin(L, offset); if (*w == NULL) luaL_argerror(L, offset, "attempt to use closed curses window"); return *w; } /*** Unique string representation of a @{curses.window}. @function __tostring @treturn string unique string representation of the window object. */ static int W__tostring(lua_State *L) { WINDOW **w = lc_getwin(L, 1); char buff[34]; if (*w == NULL) strcpy(buff, "closed"); else sprintf(buff, "%p", lua_touserdata(L, 1)); lua_pushfstring(L, "curses window (%s)", buff); return 1; } /*** Free all the resources associated with a window. @function close @see delwin(3x) */ static int Wclose(lua_State *L) { WINDOW **w = lc_getwin(L, 1); if (*w != NULL && *w != stdscr) { delwin(*w); *w = NULL; } return 0; } /*** Move the position of a window. @function move_window @int y offset frow top of screen @int x offset from left of screen @treturn bool `true`, if successful @see mvwin(3x) */ static int Wmove_window(lua_State *L) { WINDOW *w = checkwin(L, 1); int y = checkint(L, 2); int x = checkint(L, 3); return pushokresult(mvwin(w, y, x)); } /*** Create a new subwindow. @function sub @treturn window a new absolutely positioned subwindow @int nlines number of window lines @int ncols number of window columns @int begin_y top line of window @int begin_x leftmost column of window @see subwin(3x) @see derive */ static int Wsub(lua_State *L) { WINDOW *orig = checkwin(L, 1); int nlines = checkint(L, 2); int ncols = checkint(L, 3); int begin_y = checkint(L, 4); int begin_x = checkint(L, 5); lc_newwin(L, subwin(orig, nlines, ncols, begin_y, begin_x)); return 1; } /*** Create a new derived window. @function derive @int nlines number of window lines @int ncols number of window columns @int begin_y top line of window @int begin_x leftmost column of window @treturn window a new relatively positioned subwindow @see derwin(3x) @see sub */ static int Wderive(lua_State *L) { WINDOW *orig = checkwin(L, 1); int nlines = checkint(L, 2); int ncols = checkint(L, 3); int begin_y = checkint(L, 4); int begin_x = checkint(L, 5); lc_newwin(L, derwin(orig, nlines, ncols, begin_y, begin_x)); return 1; } /*** Move the position of a derived window. @function move_derived @int par_y lines from top of parent window @int par_x columns from left of parent window @treturn bool `true`, if successful @see mvderwin(3x) */ static int Wmove_derived(lua_State *L) { WINDOW *w = checkwin(L, 1); int par_y = checkint(L, 2); int par_x = checkint(L, 3); return pushokresult(mvderwin(w, par_y, par_x)); } /*** Change the size of a window. @function resize @int height new number of lines @int width new number of columns @treturn bool `true`, if successful @fixme ncurses only? */ static int Wresize(lua_State *L) { WINDOW *w = checkwin(L, 1); int height = checkint(L, 2); int width = checkint(L, 3); int c = wresize(w, height, width); if (c == ERR) return 0; return pushokresult(true); } /*** Make a duplicate of a window. @function clone @treturn window a new duplicate of this window @see dupwin(3x) */ static int Wclone(lua_State *L) { WINDOW *w = checkwin(L, 1); lc_newwin(L, dupwin(w)); return 1; } /*** Mark ancestors of a window for refresh. @function syncup @see wsyncup(3x) */ static int Wsyncup(lua_State *L) { wsyncup(checkwin(L, 1)); return 0; } /*** Automatically mark ancestors of a changed window for refresh. @function syncok @bool bf @treturn bool `true`, if successful @fixme ncurses only */ static int Wsyncok(lua_State *L) { WINDOW *w = checkwin(L, 1); int bf = lua_toboolean(L, 2); return pushokresult(syncok(w, bf)); } /*** Mark cursor position of ancestors of a window for refresh. @function cursyncup @see wcursyncup(3x) */ static int Wcursyncup(lua_State *L) { wcursyncup(checkwin(L, 1)); return 0; } /*** Mark child windows for refresh. @function syncdown @see syncdown(3x) @see refresh */ static int Wsyncdown(lua_State *L) { wsyncdown(checkwin(L, 1)); return 0; } /*** Refresh the window terminal display from the virtual screen. @function refresh @treturn bool `true`, if successful @see wrefresh(3x) @see curses.doupdate @see noutrefresh */ static int Wrefresh(lua_State *L) { int result = wrefresh(checkwin(L, 1)); render_trusted_teliva_data(L); return pushokresult(result); } /*** Copy the window backing screen to the virtual screen. @function noutrefresh @treturn bool `true`, if successful @see wnoutrefresh(3x) @see curses.doupdate @see refresh */ static int Wnoutrefresh(lua_State *L) { return pushokresult(wnoutrefresh(checkwin(L, 1))); } /*** Mark a window as having corrupted display that needs fully redrawing. @function redrawwin @treturn bool `true`, if successful @see redrawwin(3x) @see redrawln */ static int Wredrawwin(lua_State *L) { return pushokresult(redrawwin(checkwin(L, 1))); } /*** Mark a range of lines in a window as corrupted and in need of redrawing. @function redrawln @int beg_line @int num_lines @treturn bool `true`, if successful @see wredrawln(3x) */ static int Wredrawln(lua_State *L) { WINDOW *w = checkwin(L, 1); int beg_line = checkint(L, 2); int num_lines = checkint(L, 3); return pushokresult(wredrawln(w, beg_line, num_lines)); } /*** Change the cursor position. @function move @int y @int x @treturn bool `true`, if successful @see wmove(3x) */ static int Wmove(lua_State *L) { WINDOW *w = checkwin(L, 1); int y = checkint(L, 2); int x = checkint(L, 3); return pushokresult(wmove(w, y, x)); } /*** Scroll the window up *n* lines. @function scrl @int n @treturn bool `true`, if successful @see wscrl(3x) */ static int Wscrl(lua_State *L) { WINDOW *w = checkwin(L, 1); int n = checkint(L, 2); return pushokresult(wscrl(w, n)); } /*** Set the changed state of a window since the last refresh. @function touch @param[opt] changed @treturn bool `true`, if successful @see touchwin(3x) */ static int Wtouch(lua_State *L) { WINDOW *w = checkwin(L, 1); int changed; if (lua_isnoneornil(L, 2)) changed = TRUE; else changed = lua_toboolean(L, 2); if (changed) return pushokresult(touchwin(w)); return pushokresult(untouchwin(w)); } /*** Mark a range of lines as changed since the last refresh. @function touchline @int y @int n @param[opt] changed @treturn bool `true`, if successful @see wtouchln(3x) */ static int Wtouchline(lua_State *L) { WINDOW *w = checkwin(L, 1); int y = checkint(L, 2); int n = checkint(L, 3); int changed; if (lua_isnoneornil(L, 4)) changed = TRUE; else changed = lua_toboolean(L, 4); return pushokresult(wtouchln(w, y, n, changed)); } /*** Has a particular window line changed since the last refresh? @function is_linetouched @int line @treturn bool `true`, if successful @see is_linetouched(3x) */ static int Wis_linetouched(lua_State *L) { WINDOW *w = checkwin(L, 1); int line = checkint(L, 2); return pushboolresult(is_linetouched(w, line)); } /*** Has a window changed since the last refresh? @function is_wintouched @treturn bool `true`, if successful @see is_wintouched(3x) */ static int Wis_wintouched(lua_State *L) { WINDOW *w = checkwin(L, 1); return pushboolresult(is_wintouched(w)); } /*** Fetch the cursor position. @function getyx @treturn int y coordinate of top line @treturn int x coordinate of left column @see getyx(3x) */ static int Wgetyx(lua_State *L) { WINDOW *w = checkwin(L, 1); int y, x; getyx(w, y, x); lua_pushinteger(L, y); lua_pushinteger(L, x); return 2; } /*** Fetch the parent-relative coordinates of a subwindow. @function getparyx @treturn int y coordinate of top line relative to parent window @treturn int x coordinate of left column relative to parent window @see getparyx(3x) */ static int Wgetparyx(lua_State *L) { WINDOW *w = checkwin(L, 1); int y, x; getparyx(w, y, x); lua_pushinteger(L, y); lua_pushinteger(L, x); return 2; } /*** Fetch the absolute top-left coordinates of a window. @function getbegyx @treturn int y coordinate of top line @treturn int x coordinate of left column @see getbegyx(3x) */ static int Wgetbegyx(lua_State *L) { WINDOW *w = checkwin(L, 1); int y, x; getbegyx(w, y, x); lua_pushinteger(L, y); lua_pushinteger(L, x); return 2; } /*** Fetch the absolute bottom-right coordinates of a window. @function getmaxyx @treturn int y coordinate of bottom line @treturn int x coordinate of right column @see getmaxyx(3x) */ static int Wgetmaxyx(lua_State *L) { WINDOW *w = checkwin(L, 1); int y, x; getmaxyx(w, y, x); --y; // set aside space for the menu bar lua_pushinteger(L, y); lua_pushinteger(L, x); return 2; } /*** Draw a border around a window. @function border @int[opt] ls @int[opt] rs @int[opt] ts @int[opt] bs @int[opt] tl @int[opt] tr @int[opt] bl @int[opt] br @treturn bool `true`, if successful @see wborder(3x) @usage win:border (curses.ACS_VLINE, curses.ACS_VLINE, curses.ACS_HLINE, curses.ACS_HLINE, curses.ACS_ULCORNER, curses.ACS_URCORNER, curses.ACS_LLCORNER, curses.ACS_LRCORNER) */ static int Wborder(lua_State *L) { WINDOW *w = checkwin(L, 1); chtype ls = optch(L, 2, 0); chtype rs = optch(L, 3, 0); chtype ts = optch(L, 4, 0); chtype bs = optch(L, 5, 0); chtype tl = optch(L, 6, 0); chtype tr = optch(L, 7, 0); chtype bl = optch(L, 8, 0); chtype br = optch(L, 9, 0); return pushokresult(wborder(w, ls, rs, ts, bs, tl, tr, bl, br)); } /*** Draw a box around a window. @function box @int verch @int horch @treturn bool `true`, if successful @see box(3x) @see border @usage win:box (curses.ACS_VLINE, curses.ACS_HLINE) */ static int Wbox(lua_State *L) { WINDOW *w = checkwin(L, 1); chtype verch = checkch(L, 2); chtype horch = checkch(L, 3); return pushokresult(box(w, verch, horch)); } /*** Draw a row of characters from the current cursor position. @function hline @int ch @int n @treturn bool `true`, if successful @see whline(3x) @see mvhline @see vline @usage _, width = win:getmaxyx () win:hline (curses.ACS_HLINE, width - curs_x) */ static int Whline(lua_State *L) { WINDOW *w = checkwin(L, 1); chtype ch = checkch(L, 2); int n = checkint(L, 3); return pushokresult(whline(w, ch, n)); } /*** Draw a column of characters from the current cursor position. @function vline @int ch @int n @treturn bool `true`, if successful @see wvline(3x) @see hline @see mvvline */ static int Wvline(lua_State *L) { WINDOW *w = checkwin(L, 1); chtype ch = checkch(L, 2); int n = checkint(L, 3); return pushokresult(wvline(w, ch, n)); } /*** Move the cursor, then draw a row of characters from the new cursor position. @function mvhline @int y @int x @int ch @int n @treturn bool `true`, if successful @see mvwhline(3x) */ static int Wmvhline(lua_State *L) { WINDOW *w = checkwin(L, 1); int y = checkint(L, 2); int x = checkint(L, 3); chtype ch = checkch(L, 4); int n = checkint(L, 5); return pushokresult(mvwhline(w, y, x, ch, n)); } /*** Move the cursor, then draw a column of characters from the new cursor position. @function mvvline @int y @int x @int ch @int n @treturn bool `true`, if successful @see mvwvline(3x) */ static int Wmvvline(lua_State *L) { WINDOW *w = checkwin(L, 1); int y = checkint(L, 2); int x = checkint(L, 3); chtype ch = checkch(L, 4); int n = checkint(L, 5); return pushokresult(mvwvline(w, y, x, ch, n)); } /*** Write blanks to every character position in the window. @function erase @treturn bool `true`, if successful @see werase(3x) */ static int Werase(lua_State *L) { return pushokresult(werase(checkwin(L, 1))); } /*** Call @{erase} and then @{clearok}. @function clear @treturn bool `true`, if successful @see wclear(3x) */ static int Wclear(lua_State *L) { return pushokresult(wclear(checkwin(L, 1))); } /*** Write blanks to every character position after the cursor. @function clrtobot @treturn bool `true`, if successful @see wclrtobot(3x) */ static int Wclrtobot(lua_State *L) { return pushokresult(wclrtobot(checkwin(L, 1))); } /*** Write blanks from the cursor to the end of the current line. @function clrtoeol @treturn bool `true`, if successful @see wclrtoeol(3x) */ static int Wclrtoeol(lua_State *L) { return pushokresult(wclrtoeol(checkwin(L, 1))); } /*** Advance the cursor after writing a character at the old position. @function addch @int ch @treturn bool `true`, if successful @see waddch(3x) */ static int Waddch(lua_State *L) { WINDOW *w = checkwin(L, 1); chtype ch = checkch(L, 2); return pushokresult(waddch(w, ch)); } /*** Call @{move}, then @{addch}. @function mvaddch @int y @int x @int ch @treturn bool `true`, if successful @see mvwaddch(3x) */ static int Wmvaddch(lua_State *L) { WINDOW *w = checkwin(L, 1); int y = checkint(L, 2); int x = checkint(L, 3); chtype ch = checkch(L, 4); return pushokresult(mvwaddch(w, y, x, ch)); } /*** Call @{addch} then @{refresh}. @function echoch @int ch @treturn bool `true`, if successful @see wechochar(3x) */ static int Wechoch(lua_State *L) { WINDOW *w = checkwin(L, 1); chtype ch = checkch(L, 2); return pushokresult(wechochar(w, ch)); } /*** Copy a @{curses.chstr} starting at the current cursor position. @function addchstr @int chstr cs @int[opt] n @treturn bool `true`, if successful @see waddchnstr(3x) */ static int Waddchstr(lua_State *L) { WINDOW *w = checkwin(L, 1); int n = optint(L, 3, -1); chstr *cs = checkchstr(L, 2); if (n < 0 || n > (int) cs->len) n = cs->len; return pushokresult(waddchnstr(w, cs->str, n)); } /*** Call @{move} then @{addchstr}. @function mvaddchstr @int y @int x @int[opt] n @treturn bool `true`, if successful @see mvwaddchnstr(3x) */ static int Wmvaddchstr(lua_State *L) { WINDOW *w = checkwin(L, 1); int y = checkint(L, 2); int x = checkint(L, 3); int n = optint(L, 5, -1); chstr *cs = checkchstr(L, 4); if (n < 0 || n > (int) cs->len) n = cs->len; return pushokresult(mvwaddchnstr(w, y, x, cs->str, n)); } /*** Copy a Lua string starting at the current cursor position. @function addstr @string str @int[opt] n @treturn bool `true`, if successful @see waddnstr(3x) */ static int Waddstr(lua_State *L) { WINDOW *w = checkwin(L, 1); const char *str = luaL_checkstring(L, 2); int n = optint(L, 3, -1); return pushokresult(waddnstr(w, str, n)); } /*** Call @{move} then @{addstr}. @function mvaddstr @int y @int x @string str @int[opt] n @treturn bool `true`, if successful @see mvwaddnstr(3x) */ static int Wmvaddstr(lua_State *L) { WINDOW *w = checkwin(L, 1); int y = checkint(L, 2); int x = checkint(L, 3); const char *str = luaL_checkstring(L, 4); int n = optint(L, 5, -1); return pushokresult(mvwaddnstr(w, y, x, str, n)); } /*** Set the background attributes for subsequently written characters. @function wbkgdset @int ch @see wbkgdset(3x) */ static int Wwbkgdset(lua_State *L) { WINDOW *w = checkwin(L, 1); chtype ch = checkch(L, 2); wbkgdset(w, ch); return 0; } /*** Call @{wbkgdset} and then set the background of every position accordingly. @function wbkgd @int ch @treturn bool `true`, if successful @see wbkgd(3x) */ static int Wwbkgd(lua_State *L) { WINDOW *w = checkwin(L, 1); chtype ch = checkch(L, 2); return pushokresult(wbkgd(w, ch)); } /*** Fetch the current background attribute for the window. @function getbkgd @treturn int current window background attribute @see getbkgd(3x) @see wbkgd */ static int Wgetbkgd(lua_State *L) { return pushintresult(getbkgd(checkwin(L, 1))); } /*** Set the flush on interrupt behaviour for the window. @function intrflush @bool bf @treturn bool `true`, if successful @see intrflush(3x) */ static int Wintrflush(lua_State *L) { WINDOW *w = checkwin(L, 1); int bf = lua_toboolean(L, 2); return pushokresult(intrflush(w, bf)); } /*** Set the single value keypad keys behaviour for the window. @function keypad @bool[opt] on @treturn bool `true`, if successful @see keypad(3x) */ static int Wkeypad(lua_State *L) { WINDOW *w = checkwin(L, 1); int bf = lua_isnoneornil(L, 2) ? 1 : lua_toboolean(L, 2); return pushokresult(keypad(w, bf)); } /*** Force 8-bit (or 7-bit) input characters for the window. @function meta @bool on `true` to force 8-bit input characters @treturn bool `true`, if successful @see meta(3x) */ static int Wmeta(lua_State *L) { WINDOW *w = checkwin(L, 1); int bf = lua_toboolean(L, 2); return pushokresult(meta(w, bf)); } /*** Force @{getch} to be non-blocking. @function nodelay @bool on @treturn bool `true`, if successful @see nodelay(3x) */ static int Wnodelay(lua_State *L) { WINDOW *w = checkwin(L, 1); int bf = lua_toboolean(L, 2); return pushokresult(nodelay(w, bf)); } /*** For differentiating user input from terminal control sequences. @function timeout @int delay milliseconds, `0` for blocking, `-1` for non-blocking @see wtimeout(3x) */ static int Wtimeout(lua_State *L) { WINDOW *w = checkwin(L, 1); int delay = checkint(L, 2); wtimeout(w, delay); return 0; } /*** Return input immediately from this window. @function notimeout @bool bf @treturn bool `true`, if successful @fixme ncurses only? */ static int Wnotimeout(lua_State *L) { WINDOW *w = checkwin(L, 1); int bf = lua_toboolean(L, 2); return pushokresult(notimeout(w, bf)); } /*** The next call to @{refresh} will clear and completely redraw the window. @function clearok @bool bf @treturn bool `true`, if successful @see clearok(3x) */ static int Wclearok(lua_State *L) { WINDOW *w = checkwin(L, 1); int bf = lua_toboolean(L, 2); return pushokresult(clearok(w, bf)); } /*** Use hardware character insert and delete on supporting terminals. @function idcok @bool bf @treturn bool `true`, if successful @see idcok(3x) */ static int Widcok(lua_State *L) { WINDOW *w = checkwin(L, 1); int bf = lua_toboolean(L, 2); idcok(w, bf); return 0; } /*** Use hardware line insert and delete on supporting terminals. @function idlok @bool bf @treturn bool `true`, if successful @see idlok(3x) */ static int Widlok(lua_State *L) { WINDOW *w = checkwin(L, 1); int bf = lua_toboolean(L, 2); return pushokresult(idlok(w, bf)); } /*** No need to force synchronisation of hardware cursor. @function leaveok @bool bf @treturn bool `true`, if successful @see leaveok(3x) */ static int Wleaveok(lua_State *L) { WINDOW *w = checkwin(L, 1); int bf = lua_toboolean(L, 2); return pushokresult(leaveok(w, bf)); } /*** Scroll up one line when the cursor writes to the last screen position. @function scrollok @bool bf @treturn bool `true`, if successful @see scrollok(3x) */ static int Wscrollok(lua_State *L) { WINDOW *w = checkwin(L, 1); int bf = lua_toboolean(L, 2); return pushokresult(scrollok(w, bf)); } /*** Automatically call @{refresh} whenever the window content is changed. @function immedok @bool bf @treturn bool `true`, if successful @see immedok(3x) */ static int Wimmedok(lua_State *L) { WINDOW *w = checkwin(L, 1); int bf = lua_toboolean(L, 2); immedok(w, bf); return 0; } /*** Set a software scrolling region for the window. @function wsetscrreg @int top top line of the scrolling region (line 0 is the first line) @int bot bottom line of the scrolling region @treturn bool `true`, if successful @see wsetscrreg(3x) */ static int Wwsetscrreg(lua_State *L) { WINDOW *w = checkwin(L, 1); int top = checkint(L, 2); int bot = checkint(L, 3); return pushokresult(wsetscrreg(w, top, bot)); } /*** Overlay this window on top of another non-destructively. @function overlay @tparam window dst destination window @treturn bool `true`, if successful @see overlay(3x) @see overwrite */ static int Woverlay(lua_State *L) { WINDOW *srcwin = checkwin(L, 1); WINDOW *dstwin = checkwin(L, 2); return pushokresult(overlay(srcwin, dstwin)); } /*** Destructively overwrite another window with this one. @function overwrite @tparam window dst destination window @treturn bool `true`, if successful @see overwrite(3x) */ static int Woverwrite(lua_State *L) { WINDOW *srcwin = checkwin(L, 1); WINDOW *dstwin = checkwin(L, 2); return pushokresult(overwrite(srcwin, dstwin)); } /*** Overlay a rectangle of this window over another. @function copywin @tparam window dst destination window @int st top row from this window @int sl left column from this window @int dt top row of rectangle @int dl left column of rectangle @int db bottom row of rectangle @int dr right column of rectangle @bool overlay if `true`, copy destructively like @{overlay} @treturn bool `true`, if successful @see copywin(3x) */ static int Wcopywin(lua_State *L) { WINDOW *srcwin = checkwin(L, 1); WINDOW *dstwin = checkwin(L, 2); int sminrow = checkint(L, 3); int smincol = checkint(L, 4); int dminrow = checkint(L, 5); int dmincol = checkint(L, 6); int dmaxrow = checkint(L, 7); int dmaxcol = checkint(L, 8); int woverlay = lua_toboolean(L, 9); return pushokresult(copywin(srcwin, dstwin, sminrow, smincol, dminrow, dmincol, dmaxrow, dmaxcol, woverlay)); } /*** Delete the character under the cursor. @function delch @treturn bool `true`, if successful @see wdelch(3x) */ static int Wdelch(lua_State *L) { return pushokresult(wdelch(checkwin(L, 1))); } /*** Call @{move} then @{delch}. @function mvdelch @int y @int x @treturn bool `true`, if successful @see mvwdelch(3x) */ static int Wmvdelch(lua_State *L) { WINDOW *w = checkwin(L, 1); int y = checkint(L, 2); int x = checkint(L, 3); return pushokresult(mvwdelch(w, y, x)); } /*** Move the lines below the cursor up, to delete the current line. @function deleteln @treturn bool `true`, if successful @see wdeleteln(3x) */ static int Wdeleteln(lua_State *L) { return pushokresult(wdeleteln(checkwin(L, 1))); } /*** Move the current line and those below down one line, leaving a new blank line. @function insertln @treturn bool `true`, if successful @see wdeleteln(3x) */ static int Winsertln(lua_State *L) { return pushokresult(winsertln(checkwin(L, 1))); } /*** Call @{deleteln} *n* times. @function winsdelln @int n @treturn bool `true`, if successful @see winsdelln(3x) */ static int Wwinsdelln(lua_State *L) { WINDOW *w = checkwin(L, 1); int n = checkint(L, 2); return pushokresult(winsdelln(w, n)); } /*** Read a character from the window input. @function getch @treturn int character read from input buffer @see wgetch(3x) @see curses.cbreak @see curses.echo @see keypad */ static int Wgetch(lua_State *L) { WINDOW *w = checkwin(L, 1); int y, x; getyx(w, y, x); render_trusted_teliva_data(L); /* Apps can draw what they want on screen, * but Teliva's UI is always visible when * asking the user to make a decision. */ if (x > COLS-2) x = COLS-2; if (y > LINES-1) y = LINES-1; /* http://gnats.netbsd.org/56664 */ mvaddstr(y, x, ""); int c = wgetch(w); /* audit log */ static char buffer[1024] = {0}; memset(buffer, '\0', 1024); if (isspace(c)) snprintf(buffer, 1020, "getch() => %s", character_name(c)); else snprintf(buffer, 1020, "getch() => %c", c); append_to_audit_log(L, buffer); if (c == ERR) return 0; /* standard menu hotkeys */ if (c == CTRL_U && editor_view_in_progress(L)) developer_mode(L); else if (c == CTRL_X || c == CTRL_U || c == CTRL_P) { /* always confirm; we're going to throw away data past this point */ /* draw a special menu just for this situation */ attron(A_BOLD|A_REVERSE); color_set(COLOR_PAIR_MENU, NULL); for (int x = 0; x < COLS; ++x) mvaddch(LINES-1, x, ' '); menu_column = 2; if (c == CTRL_X) draw_menu_item("^x", "exit"); else if (c == CTRL_U) draw_menu_item("^u", "edit app code"); else if (c == CTRL_P) draw_menu_item("^p", "modify app permissions"); draw_menu_item("anything else", "cancel"); color_set(COLOR_PAIR_ERROR, NULL); mvaddstr(LINES-1, menu_column+1, " Please confirm. App will restart, losing unsaved data. "); color_set(COLOR_PAIR_NORMAL, NULL); attroff(A_BOLD|A_REVERSE); int secondc; do /* just in case getch is currently non-blocking (nodelay) */ secondc = wgetch(w); while(secondc == ERR); if (c != secondc) return pushintresult(0); if (c == CTRL_X) { unlink("teliva_editor_state"); exit(0); } if (c == CTRL_U) developer_mode(L); if (c == CTRL_P) permissions_mode(L); } return pushintresult(c); } /*** Put back a character obtained from @{getch} @function ungetch @int ch @treturn OK or ERR @see mvwgetch(3x) @see getch */ static int Wungetch(lua_State *L) { int ch = checkint(L, 2); int result = ungetch(ch); if (result == ERR) return 0; return pushintresult(result); } /*** Call @{move} then @{getch} @function mvgetch @int y @int x @treturn int character read from input buffer @see mvwgetch(3x) @see getch */ static int Wmvgetch(lua_State *L) { WINDOW *w = checkwin(L, 1); int y = checkint(L, 2); int x = checkint(L, 3); int c; if (wmove(w, y, x) == ERR) return 0; c = wgetch(w); if (c == ERR) return 0; return pushintresult(c); } /*** Fetch the attributed character at the current cursor position. @function winch @treturn int attributed character read from input buffer @see winch(3x) */ static int Wwinch(lua_State *L) { WINDOW *w = checkwin(L, 1); return pushintresult(winch(w)); } /*** Call @{move} then @{winch} @function mvwinch @int y @int x @treturn int attributed character read from input buffer @see mvwinch(3x) */ static int Wmvwinch(lua_State *L) { WINDOW *w = checkwin(L, 1); int y = checkint(L, 2); int x = checkint(L, 3); return pushintresult(mvwinch(w, y, x)); } /*** Fetch attributed characters from cursor position up to rightmost window position. @function winchnstr @int n @treturn curses.chstr characters from cursor to end of line @see winchnstr(3x) @see winnstr */ static int Wwinchnstr(lua_State *L) { WINDOW *w = checkwin(L, 1); int n = checkint(L, 2); chstr *cs = chstr_new(L, n); if (winchnstr(w, cs->str, n) == ERR) return 0; return 1; } /*** Call @{move} then @{winchnstr}. @function mvwinchnstr @int y @int x @int n @treturn curses.chstr characters from cursor to end of line @see mvwinchnstr(3x) */ static int Wmvwinchnstr(lua_State *L) { WINDOW *w = checkwin(L, 1); int y = checkint(L, 2); int x = checkint(L, 3); int n = checkint(L, 4); chstr *cs = chstr_new(L, n); if (mvwinchnstr(w, y, x, cs->str, n) == ERR) return 0; return 1; } /*** Fetch a string from cursor position up to rightmost window position. @function winnstr @int n @treturn string string read from input buffer @see winnstr(3x) @see winchnstr */ static int Wwinnstr(lua_State *L) { WINDOW *w = checkwin(L, 1); int n = checkint(L, 2); char buf[LUAL_BUFFERSIZE]; char *ptr = buf; if (abs(n) >= LUAL_BUFFERSIZE) ptr = lua_newuserdata(L, (size_t) abs(n) + 1); n = winnstr(w, ptr, n); if (n == ERR) return 0; lua_pushlstring(L, ptr, n); return 1; } /*** Call @{move} then @{winnstr}. @function mvwinnstr @int y @int x @int n @treturn string string read from input buffer @see mvwinnstr(3x) */ static int Wmvwinnstr(lua_State *L) { WINDOW *w = checkwin(L, 1); int y = checkint(L, 2); int x = checkint(L, 3); int n = checkint(L, 4); char buf[LUAL_BUFFERSIZE]; char *ptr = buf; if (abs(n) >= LUAL_BUFFERSIZE) ptr = lua_newuserdata(L, (size_t) abs(n) + 1); n = mvwinnstr(w, y, x, ptr, n); if (n == ERR) return 0; lua_pushlstring(L, ptr, n); return 1; } /*** Insert an attributed character before the current cursor position. @function winsch @int ch @treturn bool `true`, if successful @see winsch(3x) */ static int Wwinsch(lua_State *L) { WINDOW *w = checkwin(L, 1); chtype ch = checkch(L, 2); return pushokresult(winsch(w, ch)); } /*** Call @{move} then @{winsch}. @function mvwinsch @int y @int x @int ch @treturn bool `true`, if successful @see mvwinsch(3x) */ static int Wmvwinsch(lua_State *L) { WINDOW *w = checkwin(L, 1); int y = checkint(L, 2); int x = checkint(L, 3); chtype ch = checkch(L, 4); return pushokresult(mvwinsch(w, y, x, ch)); } /*** Insert a string of characters before the current cursor position. @function winsstr @string str @treturn bool `true`, if successful @see winsstr(3x) */ static int Wwinsstr(lua_State *L) { WINDOW *w = checkwin(L, 1); const char *str = luaL_checkstring(L, 2); return pushokresult(winsnstr(w, str, lua_strlen(L, 2))); } /*** Call @{move} then @{winsstr}. @function mvwinsstr @int y @int x @string str @treturn bool `true`, if successful @see mvwinsstr(3x) */ static int Wmvwinsstr(lua_State *L) { WINDOW *w = checkwin(L, 1); int y = checkint(L, 2); int x = checkint(L, 3); const char *str = luaL_checkstring(L, 4); return pushokresult(mvwinsnstr(w, y, x, str, lua_strlen(L, 2))); } /*** Like @{winsstr}, but no more than *n* characters. @function winsnstr @string str @int n @treturn bool `true`, if successful @see winsnstr(3x) */ static int Wwinsnstr(lua_State *L) { WINDOW *w = checkwin(L, 1); const char *str = luaL_checkstring(L, 2); int n = checkint(L, 3); return pushokresult(winsnstr(w, str, n)); } /*** Call @{move} then @{winsnstr}. @function mvwinsnstr @int y @int x @string str @int n @treturn bool `true`, if successful @see mvwinsnstr(3x) */ static int Wmvwinsnstr(lua_State *L) { WINDOW *w = checkwin(L, 1); int y = checkint(L, 2); int x = checkint(L, 3); const char *str = luaL_checkstring(L, 4); int n = checkint(L, 5); return pushokresult(mvwinsnstr(w, y, x, str, n)); } /*** Return a new subpad window object. @function subpad @int nlines @int ncols @int begin_y @int begin_x @treturn window a new subpad window object @see subpad(3x) */ static int Wsubpad(lua_State *L) { WINDOW *orig = checkwin(L, 1); int nlines = checkint(L, 2); int ncols = checkint(L, 3); int begin_y = checkint(L, 4); int begin_x = checkint(L, 5); lc_newwin(L, subpad(orig, nlines, ncols, begin_y, begin_x)); return 1; } /*** Equivalent to @{refresh} for use with pad windows. @function prefresh @int st top row from this pad window @int sl left column from this pad window @int dt top row of rectangle @int dl left column of rectangle @int db bottom row of rectangle @int dr right column of rectangle @treturn bool `true`, if successful @see prefresh(3x) */ static int Wprefresh(lua_State *L) { WINDOW *p = checkwin(L, 1); int pminrow = checkint(L, 2); int pmincol = checkint(L, 3); int sminrow = checkint(L, 4); int smincol = checkint(L, 5); int smaxrow = checkint(L, 6); int smaxcol = checkint(L, 7); return pushokresult(prefresh(p, pminrow, pmincol, sminrow, smincol, smaxrow, smaxcol)); } /*** Equivalent to @{noutrefresh} for use with pad windows. @function pnoutrefresh @int st top row from this pad window @int sl left column from this pad window @int dt top row of rectangle @int dl left column of rectangle @int db bottom row of rectangle @int dr right column of rectangle @treturn bool `true`, if successful @see pnoutrefresh(3x) */ static int Wpnoutrefresh(lua_State *L) { WINDOW *p = checkwin(L, 1); int pminrow = checkint(L, 2); int pmincol = checkint(L, 3); int sminrow = checkint(L, 4); int smincol = checkint(L, 5); int smaxrow = checkint(L, 6); int smaxcol = checkint(L, 7); return pushokresult(pnoutrefresh(p, pminrow, pmincol, sminrow, smincol, smaxrow, smaxcol)); } /*** An efficient equivalent to @{addch} followed by @{refresh}. @function pechochar @int ch @treturn bool `true`, if successful @see pechochar(3x) */ static int Wpechochar(lua_State *L) { WINDOW *p = checkwin(L, 1); chtype ch = checkch(L, 2); return pushokresult(pechochar(p, ch)); } /*** Turn off the given attributes for subsequent writes to the window. @function attroff @int attrs @treturn bool `true`, if successful @see wattroff(3x) @see standend */ static int Wattroff(lua_State *L) { WINDOW *w = checkwin(L, 1); int attrs = checkint(L, 2); return pushokresult(wattroff(w, attrs)); } /*** Turn on the given attributes for subsequent writes to the window. @function attron @int attrs @treturn bool `true`, if successful @see wattron(3x) */ static int Wattron(lua_State *L) { WINDOW *w = checkwin(L, 1); int attrs = checkint(L, 2); return pushokresult(wattron(w, attrs)); } /*** Set the given attributes for subsequent writes to the window. @function attrset @int attrs @treturn bool `true`, if successful @see wattrset(3x) */ static int Wattrset(lua_State *L) { WINDOW *w = checkwin(L, 1); int attrs = checkint(L, 2); return pushokresult(wattrset(w, attrs)); } /*** Turn off all attributes for subsequent writes to the window. @function standend @treturn bool `true`, if successful @see wstandend(3x) */ static int Wstandend(lua_State *L) { return pushokresult(wstandend(checkwin(L, 1))); } /*** Set `A_STANDOUT` for subsequent writes to the window. @function standout @treturn bool `true`, if successful @see wstandout(3x) */ static int Wstandout(lua_State *L) { return pushokresult(wstandout(checkwin(L, 1))); } static const luaL_Reg curses_window_fns[] = { LCURSES_FUNC( W__tostring ), LCURSES_FUNC( Waddch ), LCURSES_FUNC( Waddchstr ), LCURSES_FUNC( Waddstr ), LCURSES_FUNC( Wattroff ), LCURSES_FUNC( Wattron ), LCURSES_FUNC( Wattrset ), LCURSES_FUNC( Wborder ), LCURSES_FUNC( Wbox ), LCURSES_FUNC( Wclear ), LCURSES_FUNC( Wclearok ), LCURSES_FUNC( Wclone ), LCURSES_FUNC( Wclose ), LCURSES_FUNC( Wclrtobot ), LCURSES_FUNC( Wclrtoeol ), LCURSES_FUNC( Wcopywin ), LCURSES_FUNC( Wcursyncup ), LCURSES_FUNC( Wdelch ), LCURSES_FUNC( Wdeleteln ), LCURSES_FUNC( Wderive ), LCURSES_FUNC( Wechoch ), LCURSES_FUNC( Werase ), LCURSES_FUNC( Wgetbegyx ), LCURSES_FUNC( Wgetbkgd ), LCURSES_FUNC( Wgetch ), LCURSES_FUNC( Wgetmaxyx ), LCURSES_FUNC( Wgetparyx ), /* no 'getstr' because there's no way to hook standard Teliva hotkeys into it */ LCURSES_FUNC( Wgetyx ), LCURSES_FUNC( Whline ), LCURSES_FUNC( Widcok ), LCURSES_FUNC( Widlok ), LCURSES_FUNC( Wimmedok ), LCURSES_FUNC( Winsertln ), LCURSES_FUNC( Wintrflush ), LCURSES_FUNC( Wis_linetouched ), LCURSES_FUNC( Wis_wintouched ), LCURSES_FUNC( Wkeypad ), LCURSES_FUNC( Wleaveok ), LCURSES_FUNC( Wmeta ), LCURSES_FUNC( Wmove ), LCURSES_FUNC( Wmove_derived ), LCURSES_FUNC( Wmove_window ), LCURSES_FUNC( Wmvaddch ), LCURSES_FUNC( Wmvaddchstr ), LCURSES_FUNC( Wmvaddstr ), LCURSES_FUNC( Wmvdelch ), LCURSES_FUNC( Wmvgetch ), /* no 'mvgetstr' because there's no way to hook standard Teliva hotkeys into it */ LCURSES_FUNC( Wmvhline ), LCURSES_FUNC( Wmvvline ), LCURSES_FUNC( Wmvwinch ), LCURSES_FUNC( Wmvwinchnstr ), LCURSES_FUNC( Wmvwinnstr ), LCURSES_FUNC( Wmvwinsch ), LCURSES_FUNC( Wmvwinsnstr ), LCURSES_FUNC( Wmvwinsstr ), LCURSES_FUNC( Wnodelay ), LCURSES_FUNC( Wnotimeout ), LCURSES_FUNC( Wnoutrefresh ), LCURSES_FUNC( Woverlay ), LCURSES_FUNC( Woverwrite ), LCURSES_FUNC( Wpechochar ), LCURSES_FUNC( Wpnoutrefresh ), LCURSES_FUNC( Wprefresh ), LCURSES_FUNC( Wredrawln ), LCURSES_FUNC( Wredrawwin ), LCURSES_FUNC( Wrefresh ), LCURSES_FUNC( Wresize ), LCURSES_FUNC( Wscrl ), LCURSES_FUNC( Wscrollok ), LCURSES_FUNC( Wstandend ), LCURSES_FUNC( Wstandout ), LCURSES_FUNC( Wsub ), LCURSES_FUNC( Wsubpad ), LCURSES_FUNC( Wsyncdown ), LCURSES_FUNC( Wsyncok ), LCURSES_FUNC( Wsyncup ), LCURSES_FUNC( Wtimeout ), LCURSES_FUNC( Wtouch ), LCURSES_FUNC( Wtouchline ), LCURSES_FUNC( Wungetch ), LCURSES_FUNC( Wvline ), LCURSES_FUNC( Wwbkgd ), LCURSES_FUNC( Wwbkgdset ), LCURSES_FUNC( Wwinch ), LCURSES_FUNC( Wwinchnstr ), LCURSES_FUNC( Wwinnstr ), LCURSES_FUNC( Wwinsch ), LCURSES_FUNC( Wwinsdelln ), LCURSES_FUNC( Wwinsnstr ), LCURSES_FUNC( Wwinsstr ), LCURSES_FUNC( Wwsetscrreg ), {"__gc", Wclose }, /* rough safety net */ {NULL, NULL} }; LUALIB_API int luaopen_curses_window(lua_State *L) { int t, mt; luaL_register(L, "curses.window", curses_window_fns); t = lua_gettop(L); luaL_newmetatable(L, WINDOWMETA); mt = lua_gettop(L); lua_pushvalue(L, mt); lua_setfield(L, mt, "__index"); /* mt.__index = mt */ lua_pushliteral(L, "CursesWindow"); lua_setfield(L, mt, "_type"); /* mt._type = "Curses Window" */ /* for k,v in pairs(t) do mt[k]=v end */ for (lua_pushnil(L); lua_next(L, t) != 0;) lua_setfield(L, mt, lua_tostring(L, -2)); lua_pop(L, 1); /* pop mt */ return 1; }