Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

PATCH: curses tweaks, maybe

I had a short play with zcurses.  Well, it started off as a short play.
By the way, I have

We need to free up the linked list data element after use, on zcurses -d.

Also, a refresh() is needed after deleting a window, otherwise nothing
works when you add a new one.  It's not clear where this should be,
however.  If the intent is that the user can stack up commands before
refreshing we would need that as a user command, but we might well
need to ensure that it got called anyway before things got too hopefully
messed up (e.g. it would probably need to be called just before, or
presumably in place of, a wrefresh() for a new window).  So this will do
for now.

Also, something very screwy was happening with stty onlcr on my terminal,
which keeps being turned off when running the updated test function,

curses_test() {
  zmodload zsh/curses
  zcurses -a $win 10 10 10 10
  zcurses -b $win
  zcurses -m $win 1 1
  zcurses -c $win B
  zcurses -c $win l
  zcurses -c $win a
  zcurses -c $win h
  zcurses -r $win
  sleep 5
  zcurses -d $win

I think I've tracked it down to this: if zsh/curses gets loaded here,
onclr is turned off; if zsh/curses was already loaded then it's OK.
Presumably the difference is that from the command line zsh is doing it's
sanity checks (but I don't quite understand why they don't happen after the
above).  This is from initscr().  The functions nonl() / nl() seem to
control this in curses, but they docs suggest the setting isn't changed
automatically, which seems to be wrong.

Perhaps to be safe we should be requiring all use of curses to be between
commands such as zcurses -i and zcurses -e, as below?  After all, it's
reasonable to suppose this doesn't fit in with normal shell line-by-line
character handling.  This fixes Bart's gripe about clearing the screen.

Even with this code I only got it to work by both saving the terminal state
from before zcurses -i, and when I restore it on zcurses -e ensuring that
shttyinfo is the same---this seems a bit hairy.  (I had a panic attack that
shttyinfo.winsize would be screwed up, too, but
settyinfo() doesn't alter that.)

The test now becomes:

curses_test() {
  zmodload zsh/curses
  zcurses -i
  zcurses -a $win 10 10 10 10
  zcurses -b $win
  zcurses -m $win 1 1
  zcurses -c $win B
  zcurses -c $win l
  zcurses -c $win a
  zcurses -c $win h
  zcurses -r $win
  sleep 5
  zcurses -d $win
  zcurses -e

This seemed to work.   Probably zcurses -e, if it stays, should do more
work, such as deleting any remaining windows.  (That could fix up the
refresh() issue mentioned at the top in the case where we delete all

zcurses -i could be implicit, but it's nice to be clear.  Maybe it should
return an error if win_zero is already set, or allow nested -i/-e pairs, or

I'm not sure how convinced I am by all of this.

Index: Doc/Zsh/mod_curses.yo
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/mod_curses.yo,v
retrieving revision 1.4
diff -u -r1.4 mod_curses.yo
--- Doc/Zsh/mod_curses.yo	15 Oct 2007 16:49:50 -0000	1.4
+++ Doc/Zsh/mod_curses.yo	15 Oct 2007 18:28:15 -0000
@@ -6,6 +6,8 @@
 cindex(windows, curses)
+xitem(tt(zcurses) tt(-i))
+xitem(tt(zcurses) tt(-e))
 xitem(tt(zcurses) tt(-a) var(targetwin) var(nlines) var(ncols) var(begin_y) var(begin_x) )
 xitem(tt(zcurses) tt(-d) var(targetwin) )
 xitem(tt(zcurses) tt(-r) var(targetwin) )
@@ -13,7 +15,10 @@
 xitem(tt(zcurses) tt(-c) var(targetwin) var(character) )
 xitem(tt(zcurses) tt(-s) var(targetwin) var(string) )
 item(tt(zcurses) tt(-b) var(targetwin) var(border) )(
-Manipulate curses windows.
+Manipulate curses windows.  All uses of this command should be
+bracketed by `tt(zcurses -i)' to initialise use of curses, and
+`tt(zcurses -e)' to end it; omitting `tt(zcurses -e)' can cause
+the terminal to be in an unwanted state.
 With tt(-a), 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
Index: Src/Modules/curses.c
RCS file: /cvsroot/zsh/zsh/Src/Modules/curses.c,v
retrieving revision 1.8
diff -u -r1.8 curses.c
--- Src/Modules/curses.c	15 Oct 2007 16:57:48 -0000	1.8
+++ Src/Modules/curses.c	15 Oct 2007 18:28:15 -0000
@@ -44,8 +44,9 @@
     char *name;
 } *ZCWin;
-WINDOW *win_zero;
-LinkList zcurses_windows;
+static WINDOW *win_zero;
+static struct ttyinfo saved_tty_state;
+static LinkList zcurses_windows;
@@ -125,6 +126,15 @@
 static int
 bin_zcurses(char *nam, char **args, Options ops, UNUSED(int func))
+    /* Initialise curses */
+    if (OPT_ISSET(ops,'i')) {
+	if (!win_zero) {
+	    gettyinfo(&saved_tty_state);
+	    win_zero = initscr();
+	}
+	return 0;
+    }
     if (OPT_ISSET(ops,'a')) {
 	int nlines, ncols, begin_y, begin_x;
         ZCWin w;
@@ -179,7 +189,8 @@
 	if (w->name)
-        remnode(zcurses_windows, node);
+        zfree((ZCWin)remnode(zcurses_windows, node), sizeof(struct zc_win));
+	refresh();
 	return 0;
@@ -325,6 +336,24 @@
 	return 0;
+    /* Finish using curses */
+    if (OPT_ISSET(ops,'e')) {
+	if (win_zero) {
+	    endwin();
+	    /* TODO: do we free win_zero?  Manual doesn't say. */
+	    win_zero = NULL;
+	    /* Restore TTY as it was before zcurses -i */
+	    settyinfo(&saved_tty_state);
+	    /*
+	     * TODO: should I need the following?  Without it
+	     * the screen stays messed up.  Presumably we are
+	     * doing stuff with shttyinfo when we shouldn't really be.
+	     */
+	    gettyinfo(&shttyinfo);
+	}
+	return 0;
+    }
     return 0;
@@ -333,7 +362,7 @@
 static struct builtin bintab[] = {
-    BUILTIN("zcurses", 0, bin_zcurses, 0, 5, 0, "ab:cd:mr:rs", NULL),
+    BUILTIN("zcurses", 0, bin_zcurses, 0, 5, 0, "ab:cd:eimr:rs", NULL),
 static struct features module_features = {
@@ -371,7 +400,6 @@
 boot_(Module m)
     zcurses_windows = znewlinklist();
-    win_zero=initscr();
     return 0;
@@ -380,7 +408,6 @@
 cleanup_(Module m)
-    endwin();
     freelinklist(zcurses_windows, (FreeFunc) zcurses_free_window);
     return setfeatureenables(m, &module_features, NULL);

Peter Stephenson <pws@xxxxxxx>                  Software Engineer
CSR PLC, Churchill House, Cambridge Business Park, Cowley Road
Cambridge, CB4 0WZ, UK                          Tel: +44 (0)1223 692070

Messages sorted by: Reverse Date, Date, Thread, Author