about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog14
-rw-r--r--Doc/Zsh/mod_curses.yo41
-rw-r--r--Src/Modules/curses.c134
-rw-r--r--Src/Modules/curses_keys.awk2
4 files changed, 164 insertions, 27 deletions
diff --git a/ChangeLog b/ChangeLog
index 0bab7396d..49ca72d62 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,12 +1,18 @@
+2007-10-28  Peter Stephenson  <p.w.stephenson@ntlworld.com>
+
+	* 24025: Doc/Zsh/mod_curses.yo, Src/Modules/curses.c,
+	Src/Modules/curses_keys.awk: new zcurses subcommands
+	"clear" and "position"; "stdscr" window; numerous other tweaks.
+
 2007-10-26  Peter Stephenson  <p.w.stephenson@ntlworld.com>
 
 	* unposted: Src/curses.c: zcurses input oops.
 	
 	* 24024: configure.ac, Doc/Zsh/mod_curses.yo,
-	Src/Modules/curses.c:  add "zcurses input" for single character
-	raw input without echoing.  Test for wget_wch for wide
-	character input.  Add handling for keypad() mode by
-	scanning header.
+	Src/Modules/curses.c, Src/Modules/curses_keys.awk:  add "zcurses
+	input" for single character raw input without echoing.  Test for
+	wget_wch for wide character input.  Add handling for keypad()
+	mode by scanning header.
 
 2007-10-26  Clint Adams  <clint@zsh.org>
 
diff --git a/Doc/Zsh/mod_curses.yo b/Doc/Zsh/mod_curses.yo
index 266cdea29..81513c5fc 100644
--- a/Doc/Zsh/mod_curses.yo
+++ b/Doc/Zsh/mod_curses.yo
@@ -15,6 +15,8 @@ xitem(tt(zcurses) tt(addwin) var(targetwin) var(nlines) var(ncols) var(begin_y)
 xitem(tt(zcurses) tt(delwin) var(targetwin) )
 xitem(tt(zcurses) tt(refresh) [ var(targetwin) ] )
 xitem(tt(zcurses) tt(move) var(targetwin) var(new_y) var(new_x) )
+xitem(tt(zcurses) tt(clear) var(targetwin) [ tt(redraw) | tt(eol) | tt(bot) ])
+xitem(tt(location) var(targetwin) var(array))
 xitem(tt(zcurses) tt(char) var(targetwin) var(character) )
 xitem(tt(zcurses) tt(string) var(targetwin) var(string) )
 xitem(tt(zcurses) tt(border) var(targetwin) var(border) )(
@@ -29,19 +31,46 @@ the terminal to be in an unwanted state.
 With tt(addwin), create a window with var(nlines) lines and var(ncols) columns.
 Its upper left corner will be placed at row var(begin_y) and column
 var(begin_x) of the screen.  var(targetwin) is a string and refers
-to the name of a window that is not currently assigned.
+to the name of a window that is not currently assigned.  Note
+in particular the curses convention that vertical values appear
+before horizontal values.
 
 Use tt(delwin) to delete a window created with tt(addwin).  Note
-that tt(end) does em(not) implicitly delete windows.
+that tt(end) does em(not) implicitly delete windows, and that
+tt(delwin) does not erase the screen image of the window.
 
-The tt(refresh) command will refresh window var(targetwin); this is necessary to
-make any pending changes (such as characters you have prepared for output
-with tt(char)) visible on the screen.  If no argument is given,
-all windows are refreshed; this is necessary after deleting a window.
+The window corresponding to the full visible screen is called
+tt(stdscr); it always exists after `tt(zcurses init)' and cannot
+be delete with tt(delwin).
+
+The tt(refresh) command will refresh window var(targetwin); this is
+necessary to make any pending changes (such as characters you have
+prepared for output with tt(char)) visible on the screen.  tt(refresh)
+without an argument causes the screen to be cleared and redrawn.
 
 tt(move) moves the cursor position in var(targetwin) to new coordinates
 var(new_y) and var(new_x).
 
+tt(clear) erases the contents of var(targetwin).  One (and no more than one)
+of three options may be specified.  With the option tt(redraw),
+in addition the next tt(refresh) of var(targetwin) will cause the screen to be
+cleared and repainted.  With the option tt(eol), var(targetwin) is only
+cleared to the end of the current cursor line.  With the option
+tt(bot), var(targetwin) is cleared to the end of the window, i.e
+everything to the right and below the cursor is cleared.
+
+tt(location) writes various positions associated with var(targetwin)
+into the array named var(array).
+These are, in order:
+startsitem()
+sitem()(The y and x coordinates of the cursor relative to the top left
+of var(targetwin))
+sitem()(The y and x coordinates of the top left of var(targetwin) on the
+screen)
+sitem()(The y and x coordinates of the bottom right of var(targetwin)
+on the screen.)
+endsitem()
+
 Outputting characters and strings are achieved by tt(char) and tt(string)
 respectively.
 
diff --git a/Src/Modules/curses.c b/Src/Modules/curses.c
index 0ea43f1c1..92d906aee 100644
--- a/Src/Modules/curses.c
+++ b/Src/Modules/curses.c
@@ -53,8 +53,10 @@
 #include <stdio.h>
 
 enum zc_win_flags {
+    /* Window is permanent (probably "stdscr") */
+    ZCWF_PERMANENT = 0x0001,
     /* Scrolling enabled */
-    ZCWF_SCROLL = 0x0001
+    ZCWF_SCROLL = 0x0002
 };
 
 typedef struct zc_win {
@@ -82,13 +84,12 @@ struct zcurses_subcommand {
     int maxargs;
 };
 
-static WINDOW *win_zero;
 static struct ttyinfo saved_tty_state;
 static struct ttyinfo curses_tty_state;
 static LinkList zcurses_windows;
 static HashTable zcurses_colorpairs = NULL;
 
-#define ZCURSES_ERANGE 1
+#define ZCURSES_EINVALID 1
 #define ZCURSES_EDEFINED 2
 #define ZCURSES_EUNDEFINED 3
 
@@ -151,11 +152,12 @@ zcurses_strerror(int err)
 {
     static const char *errs[] = {
 	"unknown error",
-	"window number out of range",
+	"window name invalid",
 	"window already defined",
+	"window undefined",
 	NULL };
 
-    return errs[(err < 1 || err > 2) ? 0 : err];
+    return errs[(err < 1 || err > 3) ? 0 : err];
 }
 
 static LinkNode
@@ -177,7 +179,7 @@ zcurses_validate_window(char *win, int criteria)
     LinkNode target;
 
     if (win==NULL || strlen(win) < 1) {
-	zc_errno = ZCURSES_ERANGE;
+	zc_errno = ZCURSES_EINVALID;
 	return NULL;
     }
 
@@ -200,7 +202,7 @@ zcurses_validate_window(char *win, int criteria)
 static int
 zcurses_free_window(ZCWin w)
 {
-    if (delwin(w->win)!=OK)
+    if (!(w->flags & ZCWF_PERMANENT) && delwin(w->win)!=OK)
 	return 1;
 
     if (w->name)
@@ -317,9 +319,23 @@ freecolorpairnode(HashNode hn)
 static int
 zccmd_init(const char *nam, char **args)
 {
-    if (!win_zero) {
+    LinkNode stdscr_win = zcurses_getwindowbyname("stdscr");
+
+    if (!stdscr_win) {
+	ZCWin w = (ZCWin)zshcalloc(sizeof(struct zc_win));
+	if (!w)
+	    return 1;
+
 	gettyinfo(&saved_tty_state);
-	win_zero = initscr();
+	w->name = ztrdup("stdscr");
+	w->win = initscr();
+	if (w->win == NULL) {
+	    zsfree(w->name);
+	    zfree(w, sizeof(struct zc_win));
+	    return 1;
+	}
+	w->flags = ZCWF_PERMANENT;
+	zinsertlinknode(zcurses_windows, lastnode(zcurses_windows), (void *)w);
 	if (start_color() != ERR) {
 	    if(!zc_color_phase)
 		zc_color_phase = 1;
@@ -410,6 +426,10 @@ zccmd_delwin(const char *nam, char **args)
 	zwarnnam(nam, "record for window `%s' is corrupt", args[0]);
 	return 1;
     }
+    if (w->flags & ZCWF_PERMANENT) {
+	zwarnnam(nam, "window `%s' can't be deleted", args[0]);
+	return 1;
+    }
     if (delwin(w->win)!=OK)
 	return 1;
 
@@ -421,6 +441,7 @@ zccmd_delwin(const char *nam, char **args)
     return 0;
 }
 
+
 static int
 zccmd_refresh(const char *nam, char **args)
 {
@@ -441,7 +462,7 @@ zccmd_refresh(const char *nam, char **args)
     }
     else
     {
-	return (refresh() != OK) ? 1 : 0;
+	return (wrefresh(curscr) != OK) ? 1 : 0;
     }
 }
 
@@ -472,6 +493,35 @@ zccmd_move(const char *nam, char **args)
 
 
 static int
+zccmd_clear(const char *nam, char **args)
+{
+    LinkNode node;
+    ZCWin w;
+
+    node = zcurses_validate_window(args[0], ZCURSES_USED);
+    if (node == NULL) {
+	zwarnnam(nam, "%s: %s", zcurses_strerror(zc_errno), args[0]);
+	return 1;
+    }
+
+    w = (ZCWin)getdata(node);
+
+    if (!args[1]) {
+	return werase(w->win) != OK;
+    } else if (!strcmp(args[1], "redraw")) {
+	return wclear(w->win) != OK;
+    } else if (!strcmp(args[1], "eol")) {
+	return wclrtoeol(w->win) != OK;
+    } else if (!strmp(args[1], "bot")) {
+	return wclrtobot(w->win) != OK;
+    } else {
+	zwarnnam(nam, "`clear' expects `redraw', `eol' or `bot'");
+	return 1;
+    }
+}
+
+
+static int
 zccmd_char(const char *nam, char **args)
 {
     LinkNode node;
@@ -574,7 +624,9 @@ zccmd_border(const char *nam, char **args)
 static int
 zccmd_endwin(const char *nam, char **args)
 {
-    if (win_zero) {
+    LinkNode stdscr_win = zcurses_getwindowbyname("stdscr");
+
+    if (stdscr_win) {
 	endwin();
 	/* Restore TTY as it was before zcurses -i */
 	settyinfo(&saved_tty_state);
@@ -727,6 +779,7 @@ zccmd_input(const char *nam, char **args)
 	break;
 
     case KEY_CODE_YES:
+	*instr = '\0';
 	keypadnum = (int)wi;
 	break;
 
@@ -736,8 +789,11 @@ zccmd_input(const char *nam, char **args)
     }
 #else
     ci = wgetch(w->win);
+    if (ci == ERR)
+	return 1;
     if (ci >= 256) {
 	keypadnum = ci;
+	*instr = '\0';
     } else {
 	if (imeta(ci)) {
 	    instr[0] = Meta;
@@ -753,16 +809,17 @@ zccmd_input(const char *nam, char **args)
 	var = args[1];
     else
 	var = "REPLY";
-    if (!setsparam(var, ztrdup(keypadnum > 0 ? "" : instr)))
+    if (!setsparam(var, ztrdup(instr)))
 	return 1;
-    if (args[2]) {
+    if (args[1] && args[2]) {
 	if (keypadnum > 0) {
 	    const struct zcurses_namenumberpair *nnptr;
 	    char fbuf[DIGBUFSIZE+1];
 
 	    for (nnptr = keypad_names; nnptr->name; nnptr++) {
 		if (keypadnum == nnptr->number) {
-		    setsparam(args[2], ztrdup(nnptr->name));
+		    if (!setsparam(args[2], ztrdup(nnptr->name)))
+			return 1;
 		    return 0;
 		}
 	    }
@@ -773,15 +830,51 @@ zccmd_input(const char *nam, char **args)
 		/* print raw number */
 		sprintf(fbuf, "%d", keypadnum);
 	    }
-	    setsparam(args[2], ztrdup(fbuf));
+	    if (!setsparam(args[2], ztrdup(fbuf)))
+		return 1;
 	} else {
-	    setsparam(args[2], ztrdup(""));
+	    if (!setsparam(args[2], ztrdup("")))
+		return 1;
 	}
     }
     return 0;
 }
 
 
+static int
+zccmd_position(const char *nam, char **args)
+{
+    LinkNode node;
+    ZCWin w;
+    int i, intarr[6];
+    char **array, dbuf[DIGBUFSIZE];
+
+    node = zcurses_validate_window(args[0], ZCURSES_USED);
+    if (node == NULL) {
+	zwarnnam(nam, "%s: %s", zcurses_strerror(zc_errno), args[0]);
+	return 1;
+    }
+
+    w = (ZCWin)getdata(node);
+
+    /* Look no pointers:  these are macros. */
+    if (getyx(w->win, intarr[0], intarr[1]) == ERR ||
+	getbegyx(w->win, intarr[2], intarr[3]) == ERR ||
+	getmaxyx(w->win, intarr[4], intarr[5]) == ERR)
+	return 1;
+
+    array = (char **)zalloc(7*sizeof(char *));
+    for (i = 0; i < 6; i++) {
+	sprintf(dbuf, "%d", intarr[i]);
+	array[i] = ztrdup(dbuf);
+    }
+    array[6] = NULL;
+
+    setaparam(args[1], array);
+    return 0;
+}
+
+
 /*********************
   Main builtin handler
  *********************/
@@ -800,6 +893,8 @@ bin_zcurses(char *nam, char **args, Options ops, UNUSED(int func))
 	{"delwin", zccmd_delwin, 1, 1},
 	{"refresh", zccmd_refresh, 0, 1},
 	{"move", zccmd_move, 3, 3},
+	{"clear", zccmd_clear, 1, 2},
+	{"position", zccmd_position, 2, 2},
 	{"char", zccmd_char, 2, 2},
 	{"string", zccmd_string, 2, 2},
 	{"border", zccmd_border, 1, 1},
@@ -832,6 +927,13 @@ bin_zcurses(char *nam, char **args, Options ops, UNUSED(int func))
 	return 1;
     }
 
+    if (zcsc->cmd != zccmd_init && zcsc->cmd != zccmd_endwin &&
+	!zcurses_getwindowbyname("stdscr")) {
+	zwarnnam(nam, "command `%s' can't be used before `zcurses init'",
+		 zcsc->name);
+	return 1;
+    }
+
     return zcsc->cmd(nam, args+1);
 }
 
diff --git a/Src/Modules/curses_keys.awk b/Src/Modules/curses_keys.awk
index 55a786521..ffb182c35 100644
--- a/Src/Modules/curses_keys.awk
+++ b/Src/Modules/curses_keys.awk
@@ -5,7 +5,7 @@ BEGIN {nkeydefs = 0}
     keytail = substr($0, keyindex, 80)
     split(keytail, tmp)
     keynam = substr(tmp[1], 5, 30)
-    if (keynam != "MIN" && keynam != "MAX") {
+    if (keynam != "MIN" && keynam != "MAX" && keynam != "CODE_YES") {
 	name[nkeydefs++] = keynam
     }
 }