]> ncurses.scripts.mit.edu Git - ncurses.git/blobdiff - test/ncurses.c
ncurses 5.0
[ncurses.git] / test / ncurses.c
index faef03dcf5011df9adf501c8f012477b1035389d..aa24a4261809fb36b84f6589125c9ab6f745ed1c 100644 (file)
@@ -1,3 +1,30 @@
+/****************************************************************************
+ * Copyright (c) 1998,1999 Free Software Foundation, Inc.                   *
+ *                                                                          *
+ * Permission is hereby granted, free of charge, to any person obtaining a  *
+ * copy of this software and associated documentation files (the            *
+ * "Software"), to deal in the Software without restriction, including      *
+ * without limitation the rights to use, copy, modify, merge, publish,      *
+ * distribute, distribute with modifications, sublicense, and/or sell       *
+ * copies of the Software, and to permit persons to whom the Software is    *
+ * furnished to do so, subject to the following conditions:                 *
+ *                                                                          *
+ * The above copyright notice and this permission notice shall be included  *
+ * in all copies or substantial portions of the Software.                   *
+ *                                                                          *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
+ *                                                                          *
+ * Except as contained in this notice, the name(s) of the above copyright   *
+ * holders shall not be used in advertising or otherwise to promote the     *
+ * sale, use or other dealings in this Software without prior written       *
+ * authorization.                                                           *
+ ****************************************************************************/
 /****************************************************************************
 
 NAME
@@ -10,11 +37,9 @@ DESCRIPTION
    An interactive test module for the ncurses library.
 
 AUTHOR
-   This software is Copyright (C) 1993 by Eric S. Raymond, all rights reserved.
-It is issued with ncurses under the same terms and conditions as the ncurses
-library source.
+   Author: Eric S. Raymond <esr@snark.thyrsus.com> 1993
 
-$Id: ncurses.c,v 1.91 1997/05/10 18:19:48 tom Exp $
+$Id: ncurses.c,v 1.120 1999/10/23 20:01:30 tom Exp $
 
 ***************************************************************************/
 
@@ -26,8 +51,12 @@ $Id: ncurses.c,v 1.91 1997/05/10 18:19:48 tom Exp $
 #include <assert.h>
 #include <signal.h>
 
+#if HAVE_LOCALE_H
+#include <locale.h>
+#endif
+
 #if HAVE_GETTIMEOFDAY
-#if HAVE_SYS_TIME_H && ! SYSTEM_LOOKS_LIKE_SCO
+#if HAVE_SYS_TIME_H && HAVE_SYS_TIME_SELECT
 #include <sys/time.h>
 #endif
 #if HAVE_SYS_SELECT_H
@@ -86,7 +115,6 @@ extern int _nc_tracing;
 #define CTRL(x)                ((x) & 0x1f)
 #endif
 
-#define SIZEOF(table)  (sizeof(table)/sizeof(table[0]))
 #define QUIT           CTRL('Q')
 #define ESCAPE         CTRL('[')
 #define BLANK          ' '             /* this is the background character */
@@ -157,6 +185,53 @@ static void ShellOut(bool message)
        refresh();
 }
 
+#ifdef NCURSES_MOUSE_VERSION
+static const char *mouse_decode(MEVENT const *ep)
+{
+       static char buf[80];
+
+       (void) sprintf(buf, "id %2d  at (%2d, %2d, %2d) state %4lx = {",
+                      ep->id, ep->x, ep->y, ep->z, ep->bstate);
+
+#define SHOW(m, s) if ((ep->bstate & m)==m) {strcat(buf,s); strcat(buf, ", ");}
+       SHOW(BUTTON1_RELEASED,          "release-1")
+       SHOW(BUTTON1_PRESSED,           "press-1")
+       SHOW(BUTTON1_CLICKED,           "click-1")
+       SHOW(BUTTON1_DOUBLE_CLICKED,    "doubleclick-1")
+       SHOW(BUTTON1_TRIPLE_CLICKED,    "tripleclick-1")
+       SHOW(BUTTON1_RESERVED_EVENT,    "reserved-1")
+       SHOW(BUTTON2_RELEASED,          "release-2")
+       SHOW(BUTTON2_PRESSED,           "press-2")
+       SHOW(BUTTON2_CLICKED,           "click-2")
+       SHOW(BUTTON2_DOUBLE_CLICKED,    "doubleclick-2")
+       SHOW(BUTTON2_TRIPLE_CLICKED,    "tripleclick-2")
+       SHOW(BUTTON2_RESERVED_EVENT,    "reserved-2")
+       SHOW(BUTTON3_RELEASED,          "release-3")
+       SHOW(BUTTON3_PRESSED,           "press-3")
+       SHOW(BUTTON3_CLICKED,           "click-3")
+       SHOW(BUTTON3_DOUBLE_CLICKED,    "doubleclick-3")
+       SHOW(BUTTON3_TRIPLE_CLICKED,    "tripleclick-3")
+       SHOW(BUTTON3_RESERVED_EVENT,    "reserved-3")
+       SHOW(BUTTON4_RELEASED,          "release-4")
+       SHOW(BUTTON4_PRESSED,           "press-4")
+       SHOW(BUTTON4_CLICKED,           "click-4")
+       SHOW(BUTTON4_DOUBLE_CLICKED,    "doubleclick-4")
+       SHOW(BUTTON4_TRIPLE_CLICKED,    "tripleclick-4")
+       SHOW(BUTTON4_RESERVED_EVENT,    "reserved-4")
+       SHOW(BUTTON_CTRL,               "ctrl")
+       SHOW(BUTTON_SHIFT,              "shift")
+       SHOW(BUTTON_ALT,                "alt")
+       SHOW(ALL_MOUSE_EVENTS,          "all-events")
+       SHOW(REPORT_MOUSE_POSITION,     "position")
+#undef SHOW
+
+       if (buf[strlen(buf)-1] == ' ')
+               buf[strlen(buf)-2] = '\0';
+       (void) strcat(buf, "}");
+       return(buf);
+}
+#endif /* NCURSES_MOUSE_VERSION */
+
 /****************************************************************************
  *
  * Character input test
@@ -203,7 +278,7 @@ int y, x;
                MEVENT  event;
 
                getmouse(&event);
-               printw("KEY_MOUSE, %s\n", _tracemouse(&event));
+               printw("KEY_MOUSE, %s\n", mouse_decode(&event));
            }
            else
 #endif /* NCURSES_MOUSE_VERSION */
@@ -274,10 +349,13 @@ int y, x;
     endwin();
 }
 
-static int show_attr(int row, chtype attr, const char *name, bool once, const char *capname)
+static int show_attr(int row, int skip, chtype attr, const char *name, bool once)
 {
+    int ncv = tigetnum("ncv");
+
     mvprintw(row, 8, "%s mode:", name);
     mvprintw(row, 24, "|");
+    if (skip) printw("%*s", skip, " ");
     if (once)
        attron(attr);
     else
@@ -285,38 +363,125 @@ static int show_attr(int row, chtype attr, const char *name, bool once, const ch
     addstr("abcde fghij klmno pqrst uvwxy z");
     if (once)
        attroff(attr);
+    if (skip) printw("%*s", skip, " ");
     printw("|");
-    if (capname != 0 && tigetstr(capname) == 0)
-       printw(" (N/A)");
+    if (attr != A_NORMAL) {
+       if (!(termattrs() & attr)) {
+           printw(" (N/A)");
+       } else if (ncv > 0 && (getbkgd(stdscr) & A_COLOR)) {
+           static const attr_t table[] = {
+               A_STANDOUT,
+               A_UNDERLINE,
+               A_REVERSE,
+               A_BLINK,
+               A_DIM,
+               A_BOLD,
+               A_INVIS,
+               A_PROTECT,
+               A_ALTCHARSET
+           };
+           unsigned n;
+           bool found = FALSE;
+           for (n = 0; n < sizeof(table)/sizeof(table[0]); n++) {
+               if ((table[n] & attr) != 0
+                && ((1 << n) & ncv) != 0) {
+                   found = TRUE;
+                   break;
+               }
+           }
+           if (found)
+               printw(" (NCV)");
+       }
+    }
     return row + 2;
 }
 
+static bool attr_getc(int *skip, int *fg, int *bg)
+{
+    int ch = Getchar();
+
+    if (isdigit(ch)) {
+       *skip = (ch - '0');
+       return TRUE;
+    } else if (ch == CTRL('L')) {
+       touchwin(stdscr);
+       touchwin(curscr);
+       return TRUE;
+    } else if (has_colors()) {
+       switch (ch) {
+       case 'f': *fg = (*fg + 1); break;
+       case 'F': *fg = (*fg - 1); break;
+       case 'b': *bg = (*bg + 1); break;
+       case 'B': *bg = (*bg - 1); break;
+       default:
+           return FALSE;
+       }
+       if (*fg >= COLORS) *fg = 0;
+       if (*fg <  0)      *fg = COLORS - 1;
+       if (*bg >= COLORS) *bg = 0;
+       if (*bg <  0)      *bg = COLORS - 1;
+       return TRUE;
+    }
+    return FALSE;
+}
+
 static void attr_test(void)
 /* test text attributes */
 {
-    int row = 2;
-    refresh();
+    int n;
+    int skip = tigetnum("xmc");
+    int fg = COLOR_BLACK;      /* color pair 0 is special */
+    int bg = COLOR_BLACK;
+    bool *pairs = (bool *)calloc(COLOR_PAIRS, sizeof(bool));
+    pairs[0] = TRUE;
+
+    if (skip < 0)
+       skip = 0;
+
+    n = skip;  /* make it easy */
+
+    do {
+       int row = 2;
+       int normal = A_NORMAL | BLANK;
+
+       if (has_colors()) {
+           int pair = (fg * COLORS) + bg;
+           if (!pairs[pair]) {
+               init_pair(pair, fg, bg);
+               pairs[pair] = TRUE;
+           }
+           normal |= COLOR_PAIR(pair);
+       }
+       bkgdset(normal);
+       erase();
 
-    mvaddstr(0, 20, "Character attribute test display");
+       mvaddstr(0, 20, "Character attribute test display");
 
-    row = show_attr(row, A_STANDOUT,  "STANDOUT",  TRUE, "smso");
-    row = show_attr(row, A_REVERSE,   "REVERSE",   TRUE, "rev");
-    row = show_attr(row, A_BOLD,      "BOLD",      TRUE, "bold");
-    row = show_attr(row, A_UNDERLINE, "UNDERLINE", TRUE, "smul");
-    row = show_attr(row, A_DIM,       "DIM",       TRUE, "dim");
-    row = show_attr(row, A_BLINK,     "BLINK",     TRUE, "blink");
-    row = show_attr(row, A_PROTECT,   "PROTECT",   TRUE, "prot");
-    row = show_attr(row, A_INVIS,     "INVISIBLE", TRUE, "invis");
-    row = show_attr(row, A_NORMAL,    "NORMAL",    FALSE,0);
+       row = show_attr(row, n, A_STANDOUT,  "STANDOUT",  TRUE);
+       row = show_attr(row, n, A_REVERSE,   "REVERSE",   TRUE);
+       row = show_attr(row, n, A_BOLD,      "BOLD",      TRUE);
+       row = show_attr(row, n, A_UNDERLINE, "UNDERLINE", TRUE);
+       row = show_attr(row, n, A_DIM,       "DIM",       TRUE);
+       row = show_attr(row, n, A_BLINK,     "BLINK",     TRUE);
+       row = show_attr(row, n, A_PROTECT,   "PROTECT",   TRUE);
+       row = show_attr(row, n, A_INVIS,     "INVISIBLE", TRUE);
+       row = show_attr(row, n, A_NORMAL,    "NORMAL",    FALSE);
 
-    mvprintw(row, 8,
+       mvprintw(row, 8,
             "This terminal does %shave the magic-cookie glitch",
             tigetnum("xmc") > -1 ? "" : "not ");
+       mvprintw(row+1, 8,
+            "Enter a digit to set gaps on each side of displayed attributes");
+       mvprintw(row+2, 8,
+            "^L = repaint");
+       if (has_colors())
+           printw(".  f/F/b/F toggle colors (now %d/%d)", fg, bg);
 
-    refresh();
-
-    Pause();
+        refresh();
+    } while (attr_getc(&n, &fg, &bg));
 
+    free((char *)pairs);
+    bkgdset(A_NORMAL | BLANK);
     erase();
     endwin();
 }
@@ -327,7 +492,7 @@ static void attr_test(void)
  *
  ****************************************************************************/
 
-static NCURSES_CONST char *colors[] =
+static NCURSES_CONST char *color_names[] =
 {
     "black",
     "red",
@@ -339,46 +504,52 @@ static NCURSES_CONST char *colors[] =
     "white"
 };
 
+static void show_color_name(int y, int x, int color)
+{
+    if (COLORS > 8)
+       mvprintw(y, x, "%02d   ", color);
+    else
+       mvaddstr(y, x, color_names[color]);
+}
+
 static void color_test(void)
 /* generate a color test pattern */
 {
     int i;
+    int base, top, width;
+    NCURSES_CONST char *hello;
 
     refresh();
     (void) printw("There are %d color pairs\n", COLOR_PAIRS);
 
-    (void) mvprintw(1, 0,
-        "%dx%d matrix of foreground/background colors, bright *off*\n",
-        COLORS, COLORS);
-    for (i = 0; i < COLORS; i++)
-       mvaddstr(2, (i+1) * 8, colors[i]);
-    for (i = 0; i < COLORS; i++)
-       mvaddstr(3 + i, 0, colors[i]);
-    for (i = 1; i < COLOR_PAIRS; i++)
-    {
-       init_pair(i, i % COLORS, i / COLORS);
-       attron((attr_t)COLOR_PAIR(i));
-       mvaddstr(3 + (i / COLORS), (i % COLORS + 1) * 8, "Hello");
-       attrset(A_NORMAL);
-    }
+    width = (COLORS > 8) ? 4 : 8;
+    hello = (COLORS > 8) ? "Test" : "Hello";
 
-    (void) mvprintw(COLORS + 4, 0,
-          "%dx%d matrix of foreground/background colors, bright *on*\n",
-          COLORS, COLORS);
-    for (i = 0; i < COLORS; i++)
-       mvaddstr(5 + COLORS, (i+1) * 8, colors[i]);
-    for (i = 0; i < COLORS; i++)
-       mvaddstr(6 + COLORS + i, 0, colors[i]);
-    for (i = 1; i < COLOR_PAIRS; i++)
+    for (base = 0; base < 2; base++)
     {
-       init_pair(i, i % COLORS, i / COLORS);
-       attron((attr_t)(COLOR_PAIR(i) | A_BOLD));
-       mvaddstr(6 + COLORS + (i / COLORS), (i % COLORS + 1) * 8, "Hello");
-       attrset(A_NORMAL);
+       top = (COLORS > 8) ? 0 : base * (COLORS+3);
+       clrtobot();
+       (void) mvprintw(top + 1, 0,
+               "%dx%d matrix of foreground/background colors, bright *%s*\n",
+               COLORS, COLORS,
+               base ? "on" : "off");
+       for (i = 0; i < COLORS; i++)
+           show_color_name(top + 2, (i+1) * width, i);
+       for (i = 0; i < COLORS; i++)
+           show_color_name(top + 3 + i, 0, i);
+       for (i = 1; i < COLOR_PAIRS; i++)
+       {
+           init_pair(i, i % COLORS, i / COLORS);
+           attron((attr_t)COLOR_PAIR(i));
+           if (base)
+               attron((attr_t)A_BOLD);
+           mvaddstr(top + 3 + (i / COLORS), (i % COLORS + 1) * width, hello);
+           attrset(A_NORMAL);
+       }
+       if ((COLORS > 8) || base)
+           Pause();
     }
 
-    Pause();
-
     erase();
     endwin();
 }
@@ -432,8 +603,8 @@ static void color_edit(void)
         {
            mvprintw(2 + i, 0, "%c %-8s:",
                     (i == current ? '>' : ' '),
-                    (i < (int) SIZEOF(colors)
-                       ? colors[i] : ""));
+                    (i < (int) SIZEOF(color_names)
+                       ? color_names[i] : ""));
            attrset(COLOR_PAIR(i));
            addstr("        ");
            attrset(A_NORMAL);
@@ -519,7 +690,7 @@ static void color_edit(void)
     P("currently selected will be reverse-video highlighted.");
     P("");
     P("To change a field, enter the digits of the new value; they are echoed");
-    P("echoed.  Finish by typing `='; the change will take effect instantly.");
+    P("as entered.  Finish by typing `='.  The change will take effect instantly.");
     P("To increment or decrement a value, use the same procedure, but finish");
     P("with a `+' or `-'.");
     P("");
@@ -1136,6 +1307,11 @@ static void acs_and_scroll(void)
                neww->next->last = neww;
            }
            current = neww;
+           /* SVr4 curses sets the keypad on all newly-created windows to
+            * false.  Someone reported that PDCurses makes new windows inherit
+            * this flag.  Remove the following 'keypad()' call to test this
+            */
+           keypad(current->wind, TRUE);
            current->do_keypad = HaveKeypad(current);
            current->do_scroll = HaveScroll(current);
            break;
@@ -1212,6 +1388,7 @@ static void acs_and_scroll(void)
            if (current)
            {
                pair *tmp, ul, lr;
+               int mx, my;
 
                move(0, 0); clrtoeol();
                addstr("Use arrows to move cursor, anything else to mark new corner");
@@ -1233,15 +1410,16 @@ static void acs_and_scroll(void)
                wnoutrefresh(stdscr);
 
                /* strictly cosmetic hack for the test */
-               if (current->wind->_maxy > tmp->y - ul.y)
+               getmaxyx(current->wind, my, mx);
+               if (my > tmp->y - ul.y)
                {
                  getyx(current->wind, lr.y, lr.x);
                  wmove(current->wind, tmp->y - ul.y + 1, 0);
                  wclrtobot(current->wind);
                  wmove(current->wind, lr.y, lr.x);
                }
-               if (current->wind->_maxx > tmp->x - ul.x)
-                 for (i = 0; i < current->wind->_maxy; i++)
+               if (mx > tmp->x - ul.x)
+                 for (i = 0; i < my; i++)
                  {
                    wmove(current->wind, i, tmp->x - ul.x + 1);
                    wclrtoeol(current->wind);
@@ -1314,7 +1492,7 @@ static void acs_and_scroll(void)
        usescr = (current ? current->wind : stdscr);
        wrefresh(usescr);
     } while
-       ((c = wGetchar(usescr))
+       ((c = wGetchar(usescr)) != QUIT
         && !((c == ESCAPE) && (usescr->_use_keypad))
         && (c != ERR));
 
@@ -1338,17 +1516,6 @@ static void acs_and_scroll(void)
  ****************************************************************************/
 
 #if USE_LIBPANEL
-static PANEL *p1;
-static PANEL *p2;
-static PANEL *p3;
-static PANEL *p4;
-static PANEL *p5;
-static WINDOW *w1;
-static WINDOW *w2;
-static WINDOW *w3;
-static WINDOW *w4;
-static WINDOW *w5;
-
 static unsigned long nap_msec = 1;
 
 static NCURSES_CONST char *mod[] =
@@ -1397,17 +1564,24 @@ saywhat(NCURSES_CONST char *text)
        mkpanel(rows,cols,tly,tlx) - alloc a win and panel and associate them
 --------------------------------------------------------------------------*/
 static PANEL *
-mkpanel(int rows, int cols, int tly, int tlx)
-{
-WINDOW *win = newwin(rows,cols,tly,tlx);
-PANEL *pan;
-
-       if(!win)
-               return((PANEL *)0);
-       if((pan = new_panel(win)))
-               return(pan);
-       delwin(win);
-       return((PANEL *)0);
+mkpanel(int color, int rows, int cols, int tly, int tlx)
+{
+WINDOW *win;
+PANEL *pan = 0;
+
+       if ((win = newwin(rows, cols, tly, tlx)) != 0) {
+               if ((pan = new_panel(win)) == 0) {
+                       delwin(win);
+               } else if (has_colors()) {
+                       int fg = (color == COLOR_BLUE) ? COLOR_WHITE : COLOR_BLACK;
+                       int bg = color;
+                       init_pair(color, fg, bg);
+                       wbkgdset(win, COLOR_PAIR(color) | ' ');
+               } else {
+                       wbkgdset(win, A_BOLD | ' ');
+               }
+       }
+       return pan;
 }      /* end of mkpanel */
 
 /*+-------------------------------------------------------------------------
@@ -1441,9 +1615,10 @@ WINDOW *win = panel_window(pan);
 int num = ((const char *)panel_userptr(pan))[1];
 int y,x;
 
-       box(win, 0, 0);
        wmove(win,1,1);
        wprintw(win,"-pan%c-", num);
+       wclrtoeol(win);
+       box(win, 0, 0);
        for(y = 2; y < getmaxy(win) - 1; y++)
        {
                for(x = 1; x < getmaxx(win) - 1; x++)
@@ -1457,7 +1632,7 @@ int y,x;
 static void demo_panels(void)
 {
 int itmp;
-register y,x;
+register int y,x;
 
        refresh();
 
@@ -1468,24 +1643,25 @@ register y,x;
        }
        for(y = 0; y < 5; y++)
        {
-               p1 = mkpanel(LINES/2 - 2, COLS/8 + 1, 0, 0);
-               w1 = panel_window(p1);
+               PANEL *p1;
+               PANEL *p2;
+               PANEL *p3;
+               PANEL *p4;
+               PANEL *p5;
+
+               p1 = mkpanel(COLOR_RED, LINES/2 - 2, COLS/8 + 1, 0, 0);
                set_panel_userptr(p1,"p1");
 
-               p2 = mkpanel(LINES/2 + 1, COLS/7, LINES/4, COLS/10);
-               w2 = panel_window(p2);
+               p2 = mkpanel(COLOR_GREEN, LINES/2 + 1, COLS/7, LINES/4, COLS/10);
                set_panel_userptr(p2,"p2");
 
-               p3 = mkpanel(LINES/4, COLS/10, LINES/2, COLS/9);
-               w3 = panel_window(p3);
+               p3 = mkpanel(COLOR_YELLOW, LINES/4, COLS/10, LINES/2, COLS/9);
                set_panel_userptr(p3,"p3");
 
-               p4 = mkpanel(LINES/2 - 2, COLS/8, LINES/2 - 2, COLS/3);
-               w4 = panel_window(p4);
+               p4 = mkpanel(COLOR_BLUE, LINES/2 - 2, COLS/8, LINES/2 - 2, COLS/3);
                set_panel_userptr(p4,"p4");
 
-               p5 = mkpanel(LINES/2 - 2, COLS/8, LINES/2, COLS/2 - 2);
-               w5 = panel_window(p5);
+               p5 = mkpanel(COLOR_MAGENTA, LINES/2 - 2, COLS/8, LINES/2, COLS/2 - 2);
                set_panel_userptr(p5,"p5");
 
                fill_panel(p1);
@@ -1576,6 +1752,9 @@ register y,x;
 
                for(itmp = 0; itmp < 6; itmp++)
                {
+                       WINDOW *w4 = panel_window(p4);
+                       WINDOW *w5 = panel_window(p5);
+
                        saywhat("m4; press any key to continue");
                        wmove(w4, LINES/8, 1);
                        waddstr(w4,mod[itmp]);
@@ -1584,6 +1763,7 @@ register y,x;
                        waddstr(w5,mod[itmp]);
                        pflush();
                        wait_a_while(nap_msec);
+
                        saywhat("m5; press any key to continue");
                        wmove(w4, LINES/6, 1);
                        waddstr(w4,mod[itmp]);
@@ -1869,8 +2049,8 @@ static void panner(WINDOW *pad,
            int length  = (portx - top_x - 1);
            float ratio = ((float) length) / ((float) pxmax);
 
-           lowend  = top_x + (basex * ratio);
-           highend = top_x + ((basex + length) * ratio);
+           lowend  = (int)(top_x + (basex * ratio));
+           highend = (int)(top_x + ((basex + length) * ratio));
 
            do_h_line(porty - 1, top_x, ACS_HLINE, lowend);
            if (highend < portx) {
@@ -1886,8 +2066,8 @@ static void panner(WINDOW *pad,
            int length  = (porty - top_y - 1);
            float ratio = ((float) length) / ((float) pymax);
 
-           lowend  = top_y + (basey * ratio);
-           highend = top_y + ((basey + length) * ratio);
+           lowend  = (int)(top_y + (basey * ratio));
+           highend = (int)(top_y + ((basey + length) * ratio));
 
            do_v_line(top_y, portx - 1, ACS_VLINE, lowend);
                if (highend < porty) {
@@ -1938,7 +2118,6 @@ int padgetch(WINDOW *win)
 {
     int        c;
 
-    while(1)
     switch(c = wGetchar(win))
     {
     case '!': ShellOut(FALSE); return KEY_REFRESH;
@@ -2024,10 +2203,8 @@ static void flushinp_test(WINDOW *win)
     WINDOW *subWin;
     wclear (win);
 
-    w  = win->_maxx;
-    h  = win->_maxy;
-    bx = win->_begx;
-    by = win->_begy;
+    getmaxyx(win, h,  w);
+    getbegyx(win, by, bx);
     sw = w / 3;
     sh = h / 3;
     if((subWin = subwin(win, sh, sw, by + h - sh - 2, bx + w - sw - 2)) == 0)
@@ -2048,7 +2225,14 @@ static void flushinp_test(WINDOW *win)
     mvwaddstr(subWin, 2, 1, "This is a subwindow");
     wrefresh(win);
 
-    nocbreak();
+    /*
+     * This used to set 'nocbreak()'.  However, Alexander Lukyanov says that
+     * it only happened to "work" on SVr4 because that implementation does not
+     * emulate nocbreak+noecho mode, whereas ncurses does.  To get the desired
+     * test behavior, we're using 'cbreak()', which will allow a single
+     * character to return without needing a newline. - T.Dickey 1997/10/11.
+     */
+    cbreak();
     mvwaddstr(win, 0, 1, "This is a test of the flushinp() call.");
 
     mvwaddstr(win, 2, 1, "Type random keys for 5 seconds.");
@@ -2113,14 +2297,25 @@ static int menu_virtualize(int c)
 {
     if (c == '\n' || c == KEY_EXIT)
        return(MAX_COMMAND + 1);
+    else if (c == 'u')
+       return(REQ_SCR_ULINE);
+    else if (c == 'd')
+       return(REQ_SCR_DLINE);
+    else if (c == 'b' || c == KEY_NPAGE)
+       return(REQ_SCR_UPAGE);
+    else if (c == 'f' || c == KEY_PPAGE)
+       return(REQ_SCR_DPAGE);
     else if (c == 'n' || c == KEY_DOWN)
        return(REQ_NEXT_ITEM);
     else if (c == 'p' || c == KEY_UP)
        return(REQ_PREV_ITEM);
     else if (c == ' ')
        return(REQ_TOGGLE_ITEM);
-    else
+    else {
+       if (c != KEY_MOUSE)
+           beep();
        return(c);
+    }
 }
 
 static const char *animals[] =
@@ -2135,13 +2330,17 @@ static void menu_test(void)
     ITEM       *items[SIZEOF(animals)];
     ITEM       **ip = items;
     const char **ap;
-    int                mrows, mcols;
+    int                mrows, mcols, c;
     WINDOW     *menuwin;
 
+#ifdef NCURSES_MOUSE_VERSION
+    mousemask(ALL_MOUSE_EVENTS, (mmask_t *)0);
+#endif
     mvaddstr(0, 0, "This is the menu test:");
     mvaddstr(2, 0, "  Use up and down arrow to move the select bar.");
     mvaddstr(3, 0, "  'n' and 'p' act like arrows.");
-    mvaddstr(4, 0, "  Press return to exit.");
+    mvaddstr(4, 0, "  'b' and 'f' scroll up/down (page), 'u' and 'd' (line).");
+    mvaddstr(5, 0, "  Press return to exit.");
     refresh();
 
     for (ap = animals; *ap; ap++)
@@ -2150,6 +2349,7 @@ static void menu_test(void)
 
     m = new_menu(items);
 
+    set_menu_format(m, (SIZEOF(animals)+1)/2, 1);
     scale_menu(m, &mrows, &mcols);
 
     menuwin = newwin(mrows + 2, mcols +  2, MENU_Y, MENU_X);
@@ -2161,8 +2361,11 @@ static void menu_test(void)
 
     post_menu(m);
 
-    while (menu_driver(m, menu_virtualize(wGetchar(menuwin))) != E_UNKNOWN_COMMAND)
+    while ((c = menu_driver(m, menu_virtualize(wGetchar(menuwin)))) != E_UNKNOWN_COMMAND) {
+       if (c == E_REQUEST_DENIED)
+           beep();
        continue;
+    }
 
     (void) mvprintw(LINES - 2, 0,
                     "You chose: %s\n", item_name(current_item(m)));
@@ -2175,6 +2378,9 @@ static void menu_test(void)
     free_menu(m);
     for (ip = items; *ip; ip++)
        free_item(*ip);
+#ifdef NCURSES_MOUSE_VERSION
+    mousemask(0, (mmask_t *)0);
+#endif
 }
 
 #ifdef TRACE
@@ -2209,7 +2415,7 @@ static char *tracetrace(int tlevel)
        size_t need = 12;
        for (n = 0; t_tbl[n].name != 0; n++)
            need += strlen(t_tbl[n].name) + 2;
-       buf = malloc(need);
+       buf = (char *)malloc(need);
     }
     sprintf(buf, "0x%02x = {", tlevel);
     if (tlevel == 0) {
@@ -2353,12 +2559,14 @@ static FIELD *make_label(int frow, int fcol, NCURSES_CONST char *label)
     return(f);
 }
 
-static FIELD *make_field(int frow, int fcol, int rows, int cols)
+static FIELD *make_field(int frow, int fcol, int rows, int cols, bool secure)
 {
-    FIELD      *f = new_field(rows, cols, frow, fcol, 0, 0);
+    FIELD      *f = new_field(rows, cols, frow, fcol, 0, secure ? 1 : 0);
 
-    if (f)
+    if (f) {
        set_field_back(f, A_UNDERLINE);
+       set_field_userptr(f, (void *)0);
+    }
     return(f);
 }
 
@@ -2393,101 +2601,142 @@ static void erase_form(FORM *f)
     delwin(w);
 }
 
-static int form_virtualize(WINDOW *w)
+static int edit_secure(FIELD *me, int c)
 {
+    int rows, cols, frow, fcol, nbuf;
+
+    if (field_info(me, &rows, &cols, &frow, &fcol, (int *)0, &nbuf) == E_OK
+     && nbuf > 0) {
+       char temp[80];
+       long len;
+
+       strcpy(temp, field_buffer(me, 1));
+       len = (long)(char *) field_userptr(me);
+       if (c <= KEY_MAX) {
+           if (isgraph(c)) {
+               temp[len++] = c;
+               temp[len] = 0;
+               set_field_buffer(me, 1, temp);
+               c = '*';
+           } else {
+               c = 0;
+           }
+       } else {
+           switch (c) {
+           case REQ_BEG_FIELD:
+           case REQ_CLR_EOF:
+           case REQ_CLR_EOL:
+           case REQ_DEL_LINE:
+           case REQ_DEL_WORD:
+           case REQ_DOWN_CHAR:
+           case REQ_END_FIELD:
+           case REQ_INS_CHAR:
+           case REQ_INS_LINE:
+           case REQ_LEFT_CHAR:
+           case REQ_NEW_LINE:
+           case REQ_NEXT_WORD:
+           case REQ_PREV_WORD:
+           case REQ_RIGHT_CHAR:
+           case REQ_UP_CHAR:
+               c = 0;          /* we don't want to do inline editing */
+               break;
+           case REQ_CLR_FIELD:
+               if (len) {
+                   temp[0] = 0;
+                   set_field_buffer(me, 1, temp);
+               }
+               break;
+           case REQ_DEL_CHAR:
+           case REQ_DEL_PREV:
+               if (len) {
+                   temp[--len] = 0;
+                   set_field_buffer(me, 1, temp);
+               }
+               break;
+           }
+       }
+       set_field_userptr(me, (void *)len);
+     }
+     return c;
+}
+
+static int form_virtualize(FORM *f, WINDOW *w)
+{
+    static const struct {
+       int code;
+       int result;
+    } lookup[] = {
+       { CTRL('A'),     REQ_NEXT_CHOICE },
+       { CTRL('B'),     REQ_PREV_WORD },
+       { CTRL('C'),     REQ_CLR_EOL },
+       { CTRL('D'),     REQ_DOWN_FIELD },
+       { CTRL('E'),     REQ_END_FIELD },
+       { CTRL('F'),     REQ_NEXT_PAGE },
+       { CTRL('G'),     REQ_DEL_WORD },
+       { CTRL('H'),     REQ_DEL_PREV },
+       { CTRL('I'),     REQ_INS_CHAR },
+       { CTRL('K'),     REQ_CLR_EOF },
+       { CTRL('L'),     REQ_LEFT_FIELD },
+       { CTRL('M'),     REQ_NEW_LINE },
+       { CTRL('N'),     REQ_NEXT_FIELD },
+       { CTRL('O'),     REQ_INS_LINE },
+       { CTRL('P'),     REQ_PREV_FIELD },
+       { CTRL('R'),     REQ_RIGHT_FIELD },
+       { CTRL('S'),     REQ_BEG_FIELD },
+       { CTRL('U'),     REQ_UP_FIELD },
+       { CTRL('V'),     REQ_DEL_CHAR },
+       { CTRL('W'),     REQ_NEXT_WORD },
+       { CTRL('X'),     REQ_CLR_FIELD },
+       { CTRL('Y'),     REQ_DEL_LINE },
+       { CTRL('Z'),     REQ_PREV_CHOICE },
+       { ESCAPE,        MAX_FORM_COMMAND + 1 },
+       { KEY_BACKSPACE, REQ_DEL_PREV },
+       { KEY_DOWN,      REQ_DOWN_CHAR },
+       { KEY_END,       REQ_LAST_FIELD },
+       { KEY_HOME,      REQ_FIRST_FIELD },
+       { KEY_LEFT,      REQ_LEFT_CHAR },
+       { KEY_LL,        REQ_LAST_FIELD },
+       { KEY_NEXT,      REQ_NEXT_FIELD },
+       { KEY_NPAGE,     REQ_NEXT_PAGE },
+       { KEY_PPAGE,     REQ_PREV_PAGE },
+       { KEY_PREVIOUS,  REQ_PREV_FIELD },
+       { KEY_RIGHT,     REQ_RIGHT_CHAR },
+       { KEY_UP,        REQ_UP_CHAR },
+       { QUIT,          MAX_FORM_COMMAND + 1 }
+    };
+
     static int mode = REQ_INS_MODE;
     int                c = wGetchar(w);
+    unsigned   n;
+    FIELD *me = current_field(f);
 
-    switch(c)
-    {
-    case QUIT:
-    case ESCAPE:
-       return(MAX_FORM_COMMAND + 1);
-
-    /* demo doesn't use these three, leave them in anyway as sample code */
-    case KEY_NPAGE:
-    case CTRL('F'):
-       return(REQ_NEXT_PAGE);
-    case KEY_PPAGE:
-       return(REQ_PREV_PAGE);
-
-    case KEY_NEXT:
-    case CTRL('N'):
-       return(REQ_NEXT_FIELD);
-    case KEY_PREVIOUS:
-    case CTRL('P'):
-       return(REQ_PREV_FIELD);
-
-    case KEY_HOME:
-       return(REQ_FIRST_FIELD);
-    case KEY_END:
-    case KEY_LL:
-       return(REQ_LAST_FIELD);
-
-    case CTRL('L'):
-       return(REQ_LEFT_FIELD);
-    case CTRL('R'):
-       return(REQ_RIGHT_FIELD);
-    case CTRL('U'):
-       return(REQ_UP_FIELD);
-    case CTRL('D'):
-       return(REQ_DOWN_FIELD);
-
-    case CTRL('W'):
-       return(REQ_NEXT_WORD);
-    case CTRL('B'):
-       return(REQ_PREV_WORD);
-    case CTRL('S'):
-       return(REQ_BEG_FIELD);
-    case CTRL('E'):
-       return(REQ_END_FIELD);
-
-    case KEY_LEFT:
-       return(REQ_LEFT_CHAR);
-    case KEY_RIGHT:
-       return(REQ_RIGHT_CHAR);
-    case KEY_UP:
-       return(REQ_UP_CHAR);
-    case KEY_DOWN:
-       return(REQ_DOWN_CHAR);
-
-    case CTRL('M'):
-       return(REQ_NEW_LINE);
-    case CTRL('I'):
-       return(REQ_INS_CHAR);
-    case CTRL('O'):
-       return(REQ_INS_LINE);
-    case CTRL('V'):
-       return(REQ_DEL_CHAR);
-
-    case CTRL('H'):
-    case KEY_BACKSPACE:
-       return(REQ_DEL_PREV);
-    case CTRL('Y'):
-       return(REQ_DEL_LINE);
-    case CTRL('G'):
-       return(REQ_DEL_WORD);
-
-    case CTRL('C'):
-       return(REQ_CLR_EOL);
-    case CTRL('K'):
-       return(REQ_CLR_EOF);
-    case CTRL('X'):
-       return(REQ_CLR_FIELD);
-    case CTRL('A'):
-       return(REQ_NEXT_CHOICE);
-    case CTRL('Z'):
-       return(REQ_PREV_CHOICE);
-
-    case CTRL(']'):
+    if (c == CTRL(']')) {
        if (mode == REQ_INS_MODE)
-           return(mode = REQ_OVL_MODE);
+           mode = REQ_OVL_MODE;
        else
-           return(mode = REQ_INS_MODE);
+           mode = REQ_INS_MODE;
+       c = mode;
+    } else {
+       for (n = 0; n < sizeof(lookup)/sizeof(lookup[0]); n++) {
+           if (lookup[n].code == c) {
+               c = lookup[n].result;
+               break;
+           }
+       }
+    }
 
-    default:
-       return(c);
+    /*
+     * Force the field that the user is typing into to be in reverse video,
+     * while the other fields are shown underlined.
+     */
+    if (c <= KEY_MAX) {
+       c = edit_secure(me, c);
+       set_field_back(me, A_REVERSE);
+    } else if (c <= MAX_FORM_COMMAND) {
+       c = edit_secure(me, c);
+       set_field_back(me, A_UNDERLINE);
     }
+    return c;
 }
 
 static int my_form_driver(FORM *form, int c)
@@ -2506,10 +2755,9 @@ static void demo_forms(void)
 {
     WINDOW     *w;
     FORM       *form;
-    FIELD      *f[10];
+    FIELD      *f[12], *secure;
     int                finished = 0, c;
-
-    mvaddstr(10, 57, "Forms Entry Test");
+    unsigned   n = 0;
 
     move(18, 0);
     addstr("Defined form-traversal keys:   ^Q/ESC- exit form\n");
@@ -2523,19 +2771,25 @@ static void demo_forms(void)
     addstr("^G   -- delete current word    ^C  -- clear to end of line\n");
     addstr("^K   -- clear to end of field  ^X  -- clear field\n");
     addstr("Arrow keys move within a field as you would expect.");
+
+    mvaddstr(4, 57, "Forms Entry Test");
+
     refresh();
 
     /* describe the form */
-    f[0] = make_label(0, 15, "Sample Form");
-    f[1] = make_label(2, 0, "Last Name");
-    f[2] = make_field(3, 0, 1, 18);
-    f[3] = make_label(2, 20, "First Name");
-    f[4] = make_field(3, 20, 1, 12);
-    f[5] = make_label(2, 34, "Middle Name");
-    f[6] = make_field(3, 34, 1, 12);
-    f[7] = make_label(5, 0, "Comments");
-    f[8] = make_field(6, 0, 4, 46);
-    f[9] = (FIELD *)0;
+    f[n++] = make_label(0, 15, "Sample Form");
+    f[n++] = make_label(2, 0, "Last Name");
+    f[n++] = make_field(3, 0, 1, 18, FALSE);
+    f[n++] = make_label(2, 20, "First Name");
+    f[n++] = make_field(3, 20, 1, 12, FALSE);
+    f[n++] = make_label(2, 34, "Middle Name");
+    f[n++] = make_field(3, 34, 1, 12, FALSE);
+    f[n++] = make_label(5, 0, "Comments");
+    f[n++] = make_field(6, 0, 4, 46, FALSE);
+    f[n++] = make_label(5, 20, "Password:");
+    secure =
+    f[n++] = make_field(5, 30, 1, 9, TRUE);
+    f[n++] = (FIELD *)0;
 
     form = new_form(f);
 
@@ -2545,9 +2799,12 @@ static void demo_forms(void)
     raw();
     while (!finished)
     {
-       switch(form_driver(form, c = form_virtualize(w)))
+       switch(form_driver(form, c = form_virtualize(form, w)))
        {
        case E_OK:
+           mvaddstr(5, 57, field_buffer(secure, 1));
+           clrtoeol();
+           refresh();
            break;
        case E_UNKNOWN_COMMAND:
            finished = my_form_driver(form, c);
@@ -2576,11 +2833,13 @@ static void demo_forms(void)
 static void fillwin(WINDOW *win, char ch)
 {
     int y, x;
+    int y1, x1;
 
-    for (y = 0; y <= win->_maxy; y++)
+    getmaxyx(win, y1, x1);
+    for (y = 0; y < y1; y++)
     {
        wmove(win, y, 0);
-       for (x = 0; x <= win->_maxx; x++)
+       for (x = 0; x < x1; x++)
            waddch(win, ch);
     }
 }
@@ -2588,12 +2847,14 @@ static void fillwin(WINDOW *win, char ch)
 static void crosswin(WINDOW *win, char ch)
 {
     int y, x;
+    int y1, x1;
 
-    for (y = 0; y <= win->_maxy; y++)
+    getmaxyx(win, y1, x1);
+    for (y = 0; y < y1; y++)
     {
-       for (x = 0; x <= win->_maxx; x++)
-           if (((x > win->_maxx / 3) && (x <= 2 * win->_maxx / 3))
-                       || (((y > win->_maxy / 3) && (y <= 2 * win->_maxy / 3))))
+       for (x = 0; x < x1; x++)
+           if (((x > (x1 - 1) / 3) && (x <= (2 * (x1 - 1)) / 3))
+           || (((y > (y1 - 1) / 3) && (y <= (2 * (y1 - 1)) / 3))))
            {
                wmove(win, y, x);
                waddch(win, ch);
@@ -2609,6 +2870,7 @@ static void overlap_test(void)
     WINDOW *win1 = newwin(9, 20, 3, 3);
     WINDOW *win2 = newwin(9, 20, 9, 16);
 
+    raw();
     refresh();
     move(0, 0);
     printw("This test shows the behavior of wnoutrefresh() with respect to\n");
@@ -2771,10 +3033,6 @@ do_single_test(const char c)
 #endif
 
     case '?':
-       (void) puts("This is the ncurses capability tester.");
-       (void) puts("You may select a test from the main menu by typing the");
-       (void) puts("key letter of the choice (the letter to left of the =)");
-       (void) puts("at the > prompt.  The commands `x' or `q' will exit.");
        break;
 
     default:
@@ -2853,6 +3111,10 @@ main(int argc, char *argv[])
     int                command, c;
     int                my_e_param = 1;
 
+#if HAVE_LOCALE_H
+    setlocale(LC_CTYPE, "");
+#endif
+
     while ((c = getopt(argc, argv, "e:fhs:t:")) != EOF) {
        switch (c) {
        case 'e':
@@ -2871,9 +3133,11 @@ main(int argc, char *argv[])
        case 'h':
            ripoffline(1, rip_header);
            break;
+#if USE_LIBPANEL
        case 's':
            nap_msec = atol(optarg);
            break;
+#endif
 #ifdef TRACE
        case 't':
            save_trace = atoi(optarg);
@@ -2922,7 +3186,16 @@ main(int argc, char *argv[])
      */
     endwin();
 
+#if HAVE_CURSES_VERSION
+    (void) printf("Welcome to %s.  Press ? for help.\n", curses_version());
+#elif defined(NCURSES_VERSION_MAJOR) && defined(NCURSES_VERSION_MINOR) && defined(NCURSES_VERSION_PATCH)
+    (void) printf("Welcome to ncurses %d.%d.%d.  Press ? for help.\n",
+               NCURSES_VERSION_MAJOR,
+               NCURSES_VERSION_MINOR,
+               NCURSES_VERSION_PATCH);
+#else
     (void) puts("Welcome to ncurses.  Press ? for help.");
+#endif
 
     do {
        (void) puts("This is the ncurses main menu");
@@ -2989,6 +3262,12 @@ main(int argc, char *argv[])
                clear();
                refresh();
                endwin();
+               if (command == '?') {
+                       (void) puts("This is the ncurses capability tester.");
+                       (void) puts("You may select a test from the main menu by typing the");
+                       (void) puts("key letter of the choice (the letter to left of the =)");
+                       (void) puts("at the > prompt.  The commands `x' or `q' will exit.");
+               }
                continue;
        }
     } while