about summary refs log tree commit diff
path: root/Src/Modules/curses.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/Modules/curses.c')
-rw-r--r--Src/Modules/curses.c145
1 files changed, 124 insertions, 21 deletions
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),
 };