about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSebastian Gniazdowski <psprint3@fastmail.com>2017-03-05 11:25:38 -0800
committerBarton E. Schaefer <schaefer@zsh.org>2017-03-05 11:25:38 -0800
commit23275fc8db671cecb5b6491a06455b27fbabd59b (patch)
tree181ca07d3819a151622d274bf25fc87396f1b269
parent8522e996ecc88697344dcc4814367ec7e32e7deb (diff)
downloadzsh-23275fc8db671cecb5b6491a06455b27fbabd59b.tar.gz
zsh-23275fc8db671cecb5b6491a06455b27fbabd59b.tar.xz
zsh-23275fc8db671cecb5b6491a06455b27fbabd59b.zip
40726: add "zcurses resize" for sane terminal size change
-rw-r--r--ChangeLog5
-rw-r--r--Doc/Zsh/mod_curses.yo18
-rw-r--r--Src/Modules/curses.c69
-rw-r--r--configure.ac2
4 files changed, 92 insertions, 2 deletions
diff --git a/ChangeLog b/ChangeLog
index 40972a0b9..2b10f6d79 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2017-03-05  Barton E. Schaefer  <schaefer@zsh.org>
+
+	* Sebastian: 40726: Doc/Zsh/mod_curses.yo, Src/Modules/curses.c,
+	configure.ac: add "zcurses resize" for sane terminal size change
+
 2017-03-04  Barton E. Schaefer  <schaefer@zsh.org>
 
 	* Sebastian: 40781: Src/params.c, Test/A06assign.ztst: optimize
diff --git a/Doc/Zsh/mod_curses.yo b/Doc/Zsh/mod_curses.yo
index 72dc4094a..6e4831abe 100644
--- a/Doc/Zsh/mod_curses.yo
+++ b/Doc/Zsh/mod_curses.yo
@@ -27,7 +27,8 @@ xitem(tt(zcurses) tt(scroll) var(targetwin) [ tt(on) | tt(off) | [tt(+)|tt(-)]va
 xitem(tt(zcurses) tt(input) var(targetwin) [ var(param) [ var(kparam) [ var(mparam) ] ] ])
 xitem(tt(zcurses) tt(mouse) [ tt(delay) var(num) | [tt(+)|tt(-)]tt(motion) ])
 xitem(tt(zcurses) tt(timeout) var(targetwin) var(intval))
-item(tt(zcurses) tt(querychar) var(targetwin) [ var(param) ])(
+xitem(tt(zcurses) tt(querychar) var(targetwin) [ var(param) ])
+item(tt(zcurses) tt(resize) var(height) var(width) [ tt(endwin) | tt(nosave) | tt(endwin_nosave) ])(
 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
@@ -211,6 +212,21 @@ second is the color pair in the usual var(fg_col)tt(/)var(bg_col)
 notation, or tt(0) if color is not supported.  Any attributes other than
 color that apply to the character, as set with the subcommand tt(attr),
 appear as additional elements.
+
+The subcommand tt(resize) resizes tt(stdscr) and all windows to given
+dimensions (windows that stick out from the new dimensions are resized
+down). The underlying curses extension (tt(resize_term call)) can be
+unavailable. To verify, zeroes can be used for var(height) and
+var(width). If the result of the subcommand is tt(0), resize_term is
+available (tt(2) otherwise). Tests show that resizing can be normally
+accomplished by calling tt(zcurses end) and tt(zcurses refresh). The
+tt(resize) subcommand is provided for versatility. Multiple system
+configurations have been checked and tt(zcurses end) and tt(zcurses
+refresh) are still needed for correct terminal state after resize. To
+invoke them with tt(resize), use var(endwin) argument.  Using
+var(nosave) argument will cause new terminal state to not be saved
+internally by tt(zcurses). This is also provided for versatility and
+should normally be not needed.
 )
 enditem()
 
diff --git a/Src/Modules/curses.c b/Src/Modules/curses.c
index d9c19bdb1..a60dfcbf8 100644
--- a/Src/Modules/curses.c
+++ b/Src/Modules/curses.c
@@ -1490,6 +1490,74 @@ zccmd_touch(const char *nam, char **args)
     return ret;
 }
 
+static int
+zccmd_resize(const char *nam, char **args)
+{
+#ifdef HAVE_RESIZE_TERM
+    int y, x, do_endwin=0, do_save=1;
+    LinkNode stdscr_win = zcurses_getwindowbyname("stdscr");
+
+    if (stdscr_win) {
+        y = atoi(args[0]);
+        x = atoi(args[1]);
+        if (args[2]) {
+            if (0 == strcmp(args[2], "endwin")) {
+                do_endwin=1;
+            } else if (0 == strcmp(args[2], "endwin_nosave")) {
+                do_endwin=1;
+                do_save=0;
+            } else if (0 == strcmp(args[2], "nosave")) {
+                do_save=0;
+            } else {
+                zwarnnam(nam, "`resize' expects `endwin', `nosave' or `endwin_nosave' for third argument, if given");
+            }
+        }
+
+        if (y == 0 && x == 0 && args[2] == NULL) {
+            // Special case to just test that curses has resize_term. #ifdef
+            // HAVE_RESIZE_TERM will result in return value 2 if resize_term
+            // is not available.
+            return 0;
+        } else {
+            // Without this call some window moves are innacurate. Tested on
+            // OS X ncurses 5.4, Homebrew ncursesw 6.0-2, Arch Linux ncursesw
+            // 6.0, Ubuntu 14.04 ncurses 5.9, FreeBSD ncursesw.so.8
+            //
+            // On the other hand, the whole resize goal can be (from tests)
+            // accomplished by calling endwin and refresh. But to secure any
+            // future problems, resize_term is provided, and it is featured
+            // with endwin, so that users have multiple options.
+            if (do_endwin) {
+                endwin();
+            }
+
+            if( resize_term( y, x ) == OK ) {
+                // Things work without this, but we need to get out from
+                // endwin (i.e. call refresh), and in theory store new
+                // curses state (the resize might have changed it), which
+                // should be presented to terminal only after refresh.
+                if (do_endwin || do_save) {
+                    ZCWin w;
+                    w = (ZCWin)getdata(stdscr_win);
+                    wnoutrefresh(w->win);
+                    doupdate();
+                }
+
+                if (do_save) {
+                    gettyinfo(&curses_tty_state);
+                }
+                return 0;
+            } else {
+                return 1;
+            }
+        }
+    } else {
+        return 1;
+    }
+#else
+    return 2;
+#endif
+}
 
 /*********************
   Main builtin handler
@@ -1523,6 +1591,7 @@ bin_zcurses(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
 	{"mouse", zccmd_mouse, 0, -1},
 	{"querychar", zccmd_querychar, 1, 2},
 	{"touch", zccmd_touch, 1, -1},
+	{"resize", zccmd_resize, 2, 3},
 	{NULL, (zccmd_t)0, 0, 0}
     };
 
diff --git a/configure.ac b/configure.ac
index 0551a69f0..911cc4547 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1309,7 +1309,7 @@ AC_CHECK_FUNCS(strftime strptime mktime timelocal \
 	       putenv getenv setenv unsetenv xw\
 	       brk sbrk \
 	       pathconf sysconf \
-	       tgetent tigetflag tigetnum tigetstr setupterm initscr \
+	       tgetent tigetflag tigetnum tigetstr setupterm initscr resize_term \
 	       getcchar setcchar waddwstr wget_wch win_wch use_default_colors \
 	       pcre_compile pcre_study pcre_exec \
 	       nl_langinfo \