summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog3
-rw-r--r--Doc/Zsh/mod_curses.yo19
-rw-r--r--Src/Modules/curses.c145
3 files changed, 143 insertions, 24 deletions
diff --git a/ChangeLog b/ChangeLog
index 684ce15f6..fb09814a3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,8 @@
 2007-10-28  Peter Stephenson  <p.w.stephenson@ntlworld.com>
 
+	* 24027: Doc/Zsh/mod_curses.yo, Src/Modules/curses.c:
+	add "touch", subwindows, optimized "refresh".
+
 	* 24026: Doc/Zsh/mod_curses.yo, Src/Modules/curses.c:
 	handle default/default colorpair and handle color
 	default separately if use_default_colors() is available.
diff --git a/Doc/Zsh/mod_curses.yo b/Doc/Zsh/mod_curses.yo
index 9cd521d19..b53238288 100644
--- a/Doc/Zsh/mod_curses.yo
+++ b/Doc/Zsh/mod_curses.yo
@@ -11,12 +11,13 @@ findex(zcurses)
 cindex(windows, curses)
 xitem(tt(zcurses) tt(init))
 xitem(tt(zcurses) tt(end))
-xitem(tt(zcurses) tt(addwin) var(targetwin) var(nlines) var(ncols) var(begin_y) var(begin_x) )
+xitem(tt(zcurses) tt(addwin) var(targetwin) var(nlines) var(ncols) var(begin_y) var(begin_x) [ var(parentwin) ] )
 xitem(tt(zcurses) tt(delwin) var(targetwin) )
-xitem(tt(zcurses) tt(refresh) [ var(targetwin) ] )
+xitem(tt(zcurses) tt(refresh) [ var(targetwin) ... ] )
+xitem(tt(zcurses) tt(touch) 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(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) )(
@@ -35,6 +36,13 @@ to the name of a window that is not currently assigned.  Note
 in particular the curses convention that vertical values appear
 before horizontal values.
 
+If tt(addwin) is given an existing window as the final argument, the new
+window is created as a subwindow of var(parentwin).  This differs from an
+ordinary new window in that the memory of the window contents is shared
+with the parent's memory.  Subwindows must be deleted before their parent.
+Note that the coordinates of subwindows are relative to the screen, not
+the parent, as with other windows
+
 Use tt(delwin) to delete a window created with tt(addwin).  Note
 that tt(end) does em(not) implicitly delete windows, and that
 tt(delwin) does not erase the screen image of the window.
@@ -47,6 +55,11 @@ 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.
+If multiple windows are given, the screen is updated once at the end.
+
+The tt(touch) command marks the var(targetwin)s listed as changed.
+This is necessary before tt(refresh)ing windows if a window that
+was in front of another window (which may be tt(stdscr)) is deleted.
 
 tt(move) moves the cursor position in var(targetwin) to new coordinates
 var(new_y) and var(new_x).
diff --git a/Src/Modules/curses.c b/Src/Modules/curses.c
index e82576133..0f9647fb9 100644
--- a/Src/Modules/curses.c
+++ b/Src/Modules/curses.c
@@ -59,11 +59,15 @@ enum zc_win_flags {
     ZCWF_SCROLL = 0x0002
 };
 
-typedef struct zc_win {
+typedef struct zc_win *ZCWin;
+
+struct zc_win {
     WINDOW *win;
     char *name;
     int flags;
-} *ZCWin;
+    LinkList children;
+    ZCWin parent;
+};
 
 struct zcurses_namenumberpair {
     char *name;
@@ -211,6 +215,9 @@ zcurses_free_window(ZCWin w)
     if (w->name)
 	zsfree(w->name);
 
+    if (w->children)
+	freelinklist(w->children, (FreeFunc)NULL);
+
     zfree(w, sizeof(struct zc_win));
 
     return 0;
@@ -410,11 +417,37 @@ zccmd_addwin(const char *nam, char **args)
 	return 1;
 
     w->name = ztrdup(args[0]);
-    w->win = newwin(nlines, ncols, begin_y, begin_x);
+    if (args[5]) {
+	LinkNode node;
+	ZCWin worig;
+
+	node = zcurses_validate_window(args[5], ZCURSES_USED);
+	if (node == NULL) {
+	    zwarnnam(nam, "%s: %s", zcurses_strerror(zc_errno), args[0],
+		     0);
+	    zsfree(w->name);
+	    zfree(w, sizeof(struct zc_win));
+	    return 1;
+	}
+
+	worig = (ZCWin)getdata(node);
+
+	w->win = subwin(worig->win, nlines, ncols, begin_y, begin_x);
+	if (w->win) {
+	    w->parent = worig;
+	    if (!worig->children)
+		worig->children = znewlinklist();
+	    zinsertlinknode(worig->children, lastnode(worig->children),
+			    (void *)w);
+	}
+    } else {
+	w->win = newwin(nlines, ncols, begin_y, begin_x);
+    }
 
     if (w->win == NULL) {
+	zwarnnam(nam, "failed to create window `%s'", w->name);
 	zsfree(w->name);
-	free(w);
+	zfree(w, sizeof(struct zc_win));
 	return 1;
     }
 
@@ -428,6 +461,7 @@ zccmd_delwin(const char *nam, char **args)
 {
     LinkNode node;
     ZCWin w;
+    int ret = 0;
 
     node = zcurses_validate_window(args[0], ZCURSES_USED);
     if (node == NULL) {
@@ -445,39 +479,84 @@ zccmd_delwin(const char *nam, char **args)
 	zwarnnam(nam, "window `%s' can't be deleted", args[0]);
 	return 1;
     }
-    if (delwin(w->win)!=OK)
+
+    if (w->children && firstnode(w->children)) {
+	zwarnnam(nam, "window `%s' has subwindows, delete those first",
+		 w->name);
 	return 1;
+    }
+
+    if (delwin(w->win)!=OK) {
+	/*
+	 * Not sure what to do here, but we are probably stuffed,
+	 * so delete the window locally anyway.
+	 */
+	ret = 1;
+    }
+
+    if (w->parent) {
+	/* Remove from parent's list of children */
+	LinkList wpc = w->parent->children;
+	LinkNode pcnode;
+	for (pcnode = firstnode(wpc); pcnode; incnode(pcnode)) {
+	    ZCWin child = (ZCWin)getdata(pcnode);
+	    if (child == w) {
+		remnode(wpc, pcnode);
+		break;
+	    }
+	}
+	DPUTS(pcnode == NULL, "BUG: child node not found in parent's children");
+	/*
+	 * We need to touch the parent to get the parent to refresh
+	 * properly.
+	 */
+	touchwin(w->parent->win);
+    }
+    else
+	touchwin(stdscr);
 
     if (w->name)
 	zsfree(w->name);
 
     zfree((ZCWin)remnode(zcurses_windows, node), sizeof(struct zc_win));
 
-    return 0;
+    return ret;
 }
 
 
 static int
 zccmd_refresh(const char *nam, char **args)
 {
-    if (args[0]) {
-	LinkNode node;
-	ZCWin w;
+    WINDOW *win;
+    int ret = 0;
 
-	node = zcurses_validate_window(args[0], ZCURSES_USED);
-	if (node == NULL) {
-	    zwarnnam(nam, "%s: %s", zcurses_strerror(zc_errno), args[0],
-		     0);
-	    return 1;
-	}
+    if (args[0]) {
+	for (; *args; 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],
+			 0);
+		return 1;
+	    }
 
-	w = (ZCWin)getdata(node);
+	    w = (ZCWin)getdata(node);
 
-	return (wrefresh(w->win)!=OK) ? 1 : 0;
+	    if (w->parent) {
+		/* This is what the manual says you have to do. */
+		touchwin(w->parent->win);
+	    }
+	    win = w->win;
+	    if (wnoutrefresh(win) != OK)
+		ret = 1;
+	}
+	return (doupdate() != OK || ret);
     }
     else
     {
-	return (wrefresh(curscr) != OK) ? 1 : 0;
+	return (wrefresh(stdscr) != OK) ? 1 : 0;
     }
 }
 
@@ -890,6 +969,29 @@ zccmd_position(const char *nam, char **args)
 }
 
 
+static int
+zccmd_touch(const char *nam, char **args)
+{
+    LinkNode node;
+    ZCWin w;
+    int ret = 0;
+
+    for (; *args; args++) {
+	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 (touchwin(w->win) != OK)
+	    ret = 1;
+    }
+
+    return ret;
+}
+
+
 /*********************
   Main builtin handler
  *********************/
@@ -904,9 +1006,9 @@ bin_zcurses(char *nam, char **args, Options ops, UNUSED(int func))
 
     struct zcurses_subcommand scs[] = {
 	{"init", zccmd_init, 0, 0},
-	{"addwin", zccmd_addwin, 5, 5},
+	{"addwin", zccmd_addwin, 5, 6},
 	{"delwin", zccmd_delwin, 1, 1},
-	{"refresh", zccmd_refresh, 0, 1},
+	{"refresh", zccmd_refresh, 0, -1},
 	{"move", zccmd_move, 3, 3},
 	{"clear", zccmd_clear, 1, 2},
 	{"position", zccmd_position, 2, 2},
@@ -917,6 +1019,7 @@ bin_zcurses(char *nam, char **args, Options ops, UNUSED(int func))
 	{"attr", zccmd_attr, 2, -1},
 	{"scroll", zccmd_scroll, 2, 2},
 	{"input", zccmd_input, 1, 3},
+	{"touch", zccmd_touch, 1, -1},
 	{NULL, (zccmd_t)0, 0, 0}
     };
 
@@ -954,7 +1057,7 @@ bin_zcurses(char *nam, char **args, Options ops, UNUSED(int func))
 
 
 static struct builtin bintab[] = {
-    BUILTIN("zcurses", 0, bin_zcurses, 1, 6, 0, "", NULL),
+    BUILTIN("zcurses", 0, bin_zcurses, 1, -1, 0, "", NULL),
 };