* PATCH: subwindows, touching, better refreshing
@ 2007-10-28 19:30 Peter Stephenson
2007-10-28 20:26 ` Peter Stephenson
0 siblings, 1 reply; 2+ messages in thread
From: Peter Stephenson @ 2007-10-28 19:30 UTC (permalink / raw)
To: Zsh hackers list
These changes were inspired by trying to get the function below to
work. I mistakenly thought that using a subwindow meant I could
have the main window automatically restored when the subwindow
is deleted, but it's actually the opposite: a subwindow shares the
same memory whereas a new window doesn't. By the time I'd realised that
I'd added tracking of parents and children.
The key to getting windows removed is to touch the windows behind them.
There's no easy way to automate this, so I've simply added a "touch"
subcommand. (I have, however, tried to help by adding some touchwin()s
where they seem inevitable.) Also, I've optimized "refresh" so that you
can give it a list and the update only happens at the end.
Use the function keys to move round a rectangle. You get a warning
and a second's delay if you hit the edge (input timeouts won't be hard
since curses does the hard work and they're on my list). Any other key
exits.
curses_bang() {
# Arrow keys to move, anything else to exit.
zmodload zsh/curses
local REPLY key
integer h=$(( LINES - 10 )) w=$((COLUMNS - 20))
integer x=1 y=1
bang() {
zcurses addwin bang 1 5 $(( y + 5 )) $(( x + 10 ))
zcurses attr bang red/green bold
zcurses string bang 'BANG!'
zcurses refresh bang
sleep 1
zcurses delwin bang
zcurses touch main
zcurses refresh stdscr main
}
{
zcurses init
zcurses addwin main $(( LINES - 10 )) $(( COLUMNS - 20 )) 5 10
zcurses border main
zcurses move main $y $x
zcurses refresh main
while true; do
zcurses input main REPLY key
case $key in
(UP)
if (( y == 1 )); then
bang
else
zcurses string main "^"
(( y-- ))
zcurses move main $y $x
zcurses refresh main
fi
;;
(DOWN)
if (( y == h - 2 )); then
bang
else
zcurses string main "v"
(( y++ ))
zcurses move main $y $x
zcurses refresh main
fi
;;
(LEFT)
if (( x == 1 )); then
bang
else
zcurses string main "<"
(( x-- ))
zcurses move main $y $x
zcurses refresh main
fi
;;
(RIGHT)
if (( x == w - 2 )); then
bang
else
zcurses string main ">"
(( x++ ))
zcurses move main $y $x
zcurses refresh main
fi
;;
("")
break
;;
esac
done
} always {
zcurses delwin main
zcurses end
}
}
Index: Doc/Zsh/mod_curses.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/mod_curses.yo,v
retrieving revision 1.15
diff -u -r1.15 mod_curses.yo
--- Doc/Zsh/mod_curses.yo 28 Oct 2007 00:21:54 -0000 1.15
+++ Doc/Zsh/mod_curses.yo 28 Oct 2007 19:28:48 -0000
@@ -11,12 +11,13 @@
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 @@
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 @@
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).
Index: Src/Modules/curses.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Modules/curses.c,v
retrieving revision 1.27
diff -u -r1.27 curses.c
--- Src/Modules/curses.c 28 Oct 2007 00:21:55 -0000 1.27
+++ Src/Modules/curses.c 28 Oct 2007 19:28:48 -0000
@@ -59,11 +59,15 @@
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 @@
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 @@
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 @@
{
LinkNode node;
ZCWin w;
+ int ret = 0;
node = zcurses_validate_window(args[0], ZCURSES_USED);
if (node == NULL) {
@@ -445,39 +479,84 @@
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 @@
}
+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 @@
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 @@
{"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 @@
static struct builtin bintab[] = {
- BUILTIN("zcurses", 0, bin_zcurses, 1, 6, 0, "", NULL),
+ BUILTIN("zcurses", 0, bin_zcurses, 1, -1, 0, "", NULL),
};
--
Peter Stephenson <p.w.stephenson@ntlworld.com>
Web page now at http://homepage.ntlworld.com/p.w.stephenson/
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: PATCH: subwindows, touching, better refreshing
2007-10-28 19:30 PATCH: subwindows, touching, better refreshing Peter Stephenson
@ 2007-10-28 20:26 ` Peter Stephenson
0 siblings, 0 replies; 2+ messages in thread
From: Peter Stephenson @ 2007-10-28 20:26 UTC (permalink / raw)
To: Zsh hackers list
On Sun, 28 Oct 2007 19:30:39 +0000
Peter Stephenson <p.w.stephenson@ntlworld.com> wrote:
> Use the function keys to move round a rectangle. You get a warning
> and a second's delay if you hit the edge (input timeouts won't be hard
> since curses does the hard work and they're on my list).
They weren't, except I kept getting the function wrong.
curses_bang() {
# Arrow keys to move, anything else to exit.
zmodload zsh/curses
local REPLY key newkey
integer h=$(( LINES - 10 )) w=$((COLUMNS - 20))
integer x=1 y=1
bang() {
zcurses addwin bang 1 5 $(( y + 5 )) $(( x + 10 ))
zcurses attr bang red/green bold
zcurses string bang 'BANG!'
zcurses refresh bang
zcurses timeout bang 1000
zcurses input bang REPLY key
zcurses delwin bang
zcurses touch main
zcurses refresh stdscr main
}
{
zcurses init
zcurses addwin main $(( LINES - 10 )) $(( COLUMNS - 20 )) 5 10
zcurses border main
zcurses move main $y $x
zcurses refresh main
while true; do
if [[ -z $key ]]; then
zcurses input main REPLY key
fi
newkey=$key
key=
case $newkey in
(UP)
if (( y == 1 )); then
bang
else
zcurses string main "^"
(( y-- ))
zcurses move main $y $x
zcurses refresh main
fi
;;
(DOWN)
if (( y == h - 2 )); then
bang
else
zcurses string main "v"
(( y++ ))
zcurses move main $y $x
zcurses refresh main
fi
;;
(LEFT)
if (( x == 1 )); then
bang
else
zcurses string main "<"
(( x-- ))
zcurses move main $y $x
zcurses refresh main
fi
;;
(RIGHT)
if (( x == w - 2 )); then
bang
else
zcurses string main ">"
(( x++ ))
zcurses move main $y $x
zcurses refresh main
fi
;;
("")
break
;;
esac
done
} always {
zcurses delwin main
zcurses end
}
}
Index: Doc/Zsh/mod_curses.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/mod_curses.yo,v
retrieving revision 1.16
diff -u -r1.16 mod_curses.yo
--- Doc/Zsh/mod_curses.yo 28 Oct 2007 19:52:40 -0000 1.16
+++ Doc/Zsh/mod_curses.yo 28 Oct 2007 20:23:35 -0000
@@ -23,7 +23,8 @@
xitem(tt(zcurses) tt(border) var(targetwin) var(border) )(
xitem(tt(zcurses) tt(attr) var(targetwin) [ var({+/-}attribute) | var(fg_col)tt(/)var(bg_col) ] [...])
xitem(tt(zcurses) tt(scroll) [ tt(on) | tt(off) | {+/-}var(lines) ])
-item(tt(input) var(targetwin) [ var(param) [ var(kpparm) ] ])(
+xitem(tt(zcurses) tt(input) var(targetwin) [ var(param) [ var(kpparm) ] ])
+item(tt(zcurses) tt(timeout) var(targetwin) var(intval))(
Manipulate curses windows. All uses of this command should be
bracketed by `tt(zcurses init)' to initialise use of curses, and
`tt(zcurses end)' to end it; omitting `tt(zcurses end)' can cause
@@ -125,6 +126,14 @@
var(param) as before. On a succesful return only one of var(param) or
var(kpparm) contains a non-empty string; the other is set to an empty
string.
+
+tt(timeout) specifies a timeout value for input from var(targetwin).
+If var(intval) is negative, `tt(zcurses input)' waits indefinitely for
+a character to be typed; this is the default. If var(intval) is zero,
+`tt(zcurses input)' returns immediately; if there is typeahead it is
+returned, else no input is done and status 1 is returned. If var(intval)
+is positive, `tt(zcurses input)' waits var(intval) milliseconds for
+input and if there is none at the end of that period returns status 1.
)
enditem()
Index: Src/Modules/curses.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Modules/curses.c,v
retrieving revision 1.28
diff -u -r1.28 curses.c
--- Src/Modules/curses.c 28 Oct 2007 19:52:41 -0000 1.28
+++ Src/Modules/curses.c 28 Oct 2007 20:23:35 -0000
@@ -562,7 +562,7 @@
static int
-zccmd_move(const char *nam, char **args)
+zccmd_move(const char *nam, char **args)
{
int y, x;
LinkNode node;
@@ -936,6 +936,33 @@
static int
+zccmd_timeout(const char *nam, char **args)
+{
+ LinkNode node;
+ ZCWin w;
+ int to;
+ char *eptr;
+
+ 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);
+
+ to = (int)zstrtol(args[1], &eptr, 10);
+ if (*eptr) {
+ zwarnnam(nam, "timeout requires an integer: %s", args[1]);
+ return 1;
+ }
+
+ wtimeout(w->win, to);
+ return 0;
+}
+
+
+static int
zccmd_position(const char *nam, char **args)
{
LinkNode node;
@@ -1019,6 +1046,7 @@
{"attr", zccmd_attr, 2, -1},
{"scroll", zccmd_scroll, 2, 2},
{"input", zccmd_input, 1, 3},
+ {"timeout", zccmd_timeout, 2, 2},
{"touch", zccmd_touch, 1, -1},
{NULL, (zccmd_t)0, 0, 0}
};
--
Peter Stephenson <p.w.stephenson@ntlworld.com>
Web page now at http://homepage.ntlworld.com/p.w.stephenson/
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2007-10-28 20:27 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-10-28 19:30 PATCH: subwindows, touching, better refreshing Peter Stephenson
2007-10-28 20:26 ` Peter Stephenson
Code repositories for project(s) associated with this public inbox
https://git.vuxu.org/mirror/zsh/
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).