ncurses 5.6 - patch 20070526
authorThomas E. Dickey <dickey@invisible-island.net>
Sat, 26 May 2007 23:44:27 +0000 (23:44 +0000)
committerThomas E. Dickey <dickey@invisible-island.net>
Sat, 26 May 2007 23:44:27 +0000 (23:44 +0000)
+ modify keyname() to use "^X" form only if meta() has been called, or
  if keyname() is called without initializing curses, e.g., via
  initscr() or newterm() (prompted by LinuxBase #1604).
+ document some portability issues in man/curs_util.3x
+ add a shadow copy of TTY buffer to _nc_prescreen to fix applications
  broken by moving that data into SCREEN (cf: 20061230).

NEWS
dist.mk
man/curs_terminfo.3x
man/curs_util.3x
ncurses/base/MKkeyname.awk
ncurses/curses.priv.h
ncurses/tinfo/lib_data.c
ncurses/tinfo/lib_ttyflags.c
test/demo_panels.c

diff --git a/NEWS b/NEWS
index 91ba1efbced5e90f392b9b38e4e3785cb3dbc77b..52c219bc70cc56b71feb7f0b731fd1b7c84d79a0 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -25,7 +25,7 @@
 -- sale, use or other dealings in this Software without prior written        --
 -- authorization.                                                            --
 -------------------------------------------------------------------------------
--- $Id: NEWS,v 1.1127 2007/05/12 22:31:49 tom Exp $
+-- $Id: NEWS,v 1.1128 2007/05/26 21:46:41 tom Exp $
 -------------------------------------------------------------------------------
 
 This is a log of changes that ncurses has gone through since Zeyd started
@@ -45,6 +45,14 @@ See the AUTHORS file for the corresponding full names.
 Changes through 1.9.9e did not credit all contributions;
 it is not possible to add this information.
 
+20070526
+       + modify keyname() to use "^X" form only if meta() has been called, or
+         if keyname() is called without initializing curses, e.g., via
+         initscr() or newterm() (prompted by LinuxBase #1604).
+       + document some portability issues in man/curs_util.3x
+       + add a shadow copy of TTY buffer to _nc_prescreen to fix applications
+         broken by moving that data into SCREEN (cf: 20061230).
+
 20070512
        + add 'O' (wide-character panel test) in ncurses.c to demonstrate a
          problem reported by Sadrul H Chowdhury with repainting parts of
diff --git a/dist.mk b/dist.mk
index c141803ed2cb1bf5cfe9126347ca7cc010bb54f4..27a30590597349635167bb0a8a1a16e48f926925 100644 (file)
--- a/dist.mk
+++ b/dist.mk
@@ -25,7 +25,7 @@
 # use or other dealings in this Software without prior written               #
 # authorization.                                                             #
 ##############################################################################
-# $Id: dist.mk,v 1.593 2007/05/12 15:09:42 tom Exp $
+# $Id: dist.mk,v 1.594 2007/05/26 17:49:30 tom Exp $
 # Makefile for creating ncurses distributions.
 #
 # This only needs to be used directly as a makefile by developers, but
@@ -37,7 +37,7 @@ SHELL = /bin/sh
 # These define the major/minor/patch versions of ncurses.
 NCURSES_MAJOR = 5
 NCURSES_MINOR = 6
-NCURSES_PATCH = 20070512
+NCURSES_PATCH = 20070526
 
 # We don't append the patch to the version, since this only applies to releases
 VERSION = $(NCURSES_MAJOR).$(NCURSES_MINOR)
index fc2020b5463ab019ef2b6989891c579cf67cf3fc..5af0b8fbe27c6bfdfe8808cf28ff13b0a2dfebf4 100644 (file)
@@ -26,7 +26,7 @@
 .\" authorization.                                                           *
 .\"***************************************************************************
 .\"
-.\" $Id: curs_terminfo.3x,v 1.27 2007/03/11 00:15:07 tom Exp $
+.\" $Id: curs_terminfo.3x,v 1.28 2007/05/26 20:09:06 tom Exp $
 .TH curs_terminfo 3X ""
 .ds n 5
 .na
@@ -319,7 +319,7 @@ the SCREEN data allocated in either \fBinitscr\fR or \fBnewterm\fR.
 So though it is documented as a terminfo function,
 \fBmvcur\fR is really a curses function which is not well specified.
 .PP
-XSI states that the old location must be given.
+XSI states that the old location must be given for \fBmvcur\fP.
 This implementation allows the caller to use -1's for the old ordinates.
 In that case, the old location is unknown.
 .PP
index 73b599ec4dd377e6c7c7e59ed512ecb5c50a882a..4c8929abfce752bed172900ab494d051912a007a 100644 (file)
@@ -26,7 +26,7 @@
 .\" authorization.                                                           *
 .\"***************************************************************************
 .\"
-.\" $Id: curs_util.3x,v 1.23 2007/02/24 15:59:07 tom Exp $
+.\" $Id: curs_util.3x,v 1.25 2007/05/26 21:44:42 tom Exp $
 .TH curs_util 3X ""
 .na
 .hy 0
@@ -146,6 +146,29 @@ returns an error if the associated \fBfwrite\fP calls return an error.
 The XSI Curses standard, Issue 4 describes these functions.
 It states that \fBunctrl\fR and \fBwunctrl\fR will return a null pointer if
 unsuccessful, but does not define any error conditions.
+This implementation checks for three cases:
+.RS
+.TP 5
+-
+the parameter is a 7-bit US-ASCII code.
+This is the case that X/Open Curses documented.
+.TP 5
+-
+the parameter is in the range 128-159, i.e., a C1 control code.
+If \fBuse_legacy_coding\fP has been called with a \fB2\fP parameter,
+\fBunctrl\fP returns the parameter, i.e., a one-character string with
+the parameter as the first character.
+Otherwise, it returns ``~@'', ``~A'', etc., analogous to ``^@'', ``^A'', C0 controls.
+.IP
+X/Open Curses does not document whether \fBunctrl\fP can be called before
+initializing curses.
+This implementation permits that,
+and returns the ``~@'', etc., values in that case.
+.TP 5
+-
+parameter values outside the 0 to 255 range.
+\fBunctrl\fP returns a null pointer.
+.RE
 .PP
 The SVr4 documentation describes the action of \fBfilter\fR only in the vaguest
 terms.  The description here is adapted from the XSI Curses standard (which
@@ -157,13 +180,24 @@ showing C1 controls from the upper-128 codes with a `~' prefix rather than `^'.
 Other implementations have different conventions.
 For example, they may show both sets of control characters with `^',
 and strip the parameter to 7 bits.
-Or they may ignore C1 controls and treat all of the upper-1280 codes as
+Or they may ignore C1 controls and treat all of the upper-128 codes as
 printable.
 This implementation uses 8 bits but does not modify the string to reflect
 locale.
 The \fBuse_legacy_coding\fP function allows the caller to
 change the output of \fBunctrl\fP.
 .PP
+Likewise, the \fBmeta\fP function allows the caller to change the
+output of \fBkeyname\fP, i.e.,
+it determines whether to use the `M-' prefix
+for ``meta'' keys (codes in the range 128 to 255).
+Both \fBuse_legacy_coding\fP and \fBmeta\fP succeed only after
+curses is initialized. 
+X/Open Curses does not document the treatment of codes 128 to 159.
+When treating them as ``meta'' keys
+(or if \fBkeyname\fP is called before initializing curses),
+this implementation returns strings ``M-^@'', ``M-^A'', etc.
+.PP
 The \fBkeyname\fP function may return the names of user-defined
 string capabilities which are defined in the terminfo entry via the \fB-x\fP
 option of \fBtic\fP.
@@ -182,7 +216,8 @@ be conditioned using NCURSES_VERSION.
 \fBcurses\fR(3X),
 \fBcurs_initscr\fR(3X),
 \fBcurs_kernel\fR(3X),
-\fBcurs_scr_dump\fR(3X).
+\fBcurs_scr_dump\fR(3X),
+\fBlegacy_coding\fR(3X).
 .\"#
 .\"# The following sets edit modes for GNU EMACS
 .\"# Local Variables:
index b27eb75ab8b6ddbf0f954b375cde2ba62b3bfb7b..68903e434a4a4e8f78527ea821d4e34c21205411 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: MKkeyname.awk,v 1.32 2007/04/21 23:01:49 tom Exp $
+# $Id: MKkeyname.awk,v 1.33 2007/05/26 20:58:24 tom Exp $
 ##############################################################################
 # Copyright (c) 1999-2006,2007 Free Software Foundation, Inc.                #
 #                                                                            #
@@ -74,7 +74,7 @@ END {
        print "                         if (MyTable[c] == 0) {"
        print "                                 int cc = c;"
        print "                                 p = name;"
-       print "                                 if (cc >= 128) {"
+       print "                                 if (cc >= 128 && (SP == 0 || SP->_use_meta)) {"
        print "                                         strcpy(p, \"M-\");"
        print "                                         p += 2;"
        print "                                         cc -= 128;"
index 44e4528d2da74e6e0177ee016552ca582d519736..931b0fa51a0ee023ab0f400eba6378df35fd931a 100644 (file)
@@ -34,7 +34,7 @@
 
 
 /*
- * $Id: curses.priv.h,v 1.331 2007/05/12 18:10:46 tom Exp $
+ * $Id: curses.priv.h,v 1.332 2007/05/26 18:47:51 tom Exp $
  *
  *     curses.priv.h
  *
@@ -551,6 +551,7 @@ typedef struct {
        ripoff_t        rippedoff[N_RIPS];
        ripoff_t        *rsp;
        TPARM_STATE     tparm_state;
+       TTY             *saved_tty;     /* savetty/resetty information      */
 #if BROKEN_LINKER || USE_REENTRANT
        chtype          *real_acs_map;
 #endif
index aee05075eaac88b8ca8b5adc9848c8a12db769c0..63b8f644cdb89a4a6c5979872949cc75a6f661c0 100644 (file)
@@ -41,7 +41,7 @@
 
 #include <curses.priv.h>
 
-MODULE_ID("$Id: lib_data.c,v 1.25 2007/05/12 18:12:12 tom Exp $")
+MODULE_ID("$Id: lib_data.c,v 1.26 2007/05/26 18:48:07 tom Exp $")
 
 /*
  * OS/2's native linker complains if we don't initialize public data when
@@ -210,6 +210,7 @@ NCURSES_EXPORT_VAR(NCURSES_PRESCREEN) _nc_prescreen = {
        NUM_VARS_0s,            /* dynamic_var */
        NUM_VARS_0s,            /* static_vars */
     },
+    NULL,                      /* saved_tty */
 #if BROKEN_LINKER || USE_REENTRANT
     NULL,                      /* real_acs_map */
 #endif
index 66f08ec9fc1897772c522ffa8568d0727ceab7b0..4cbbf504a0c7e1c085d5de1783954bf0c338e393 100644 (file)
@@ -1,5 +1,5 @@
 /****************************************************************************
- * Copyright (c) 1998-2005,2006 Free Software Foundation, Inc.              *
+ * Copyright (c) 1998-2006,2007 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            *
 #include <curses.priv.h>
 #include <term.h>              /* cur_term */
 
-MODULE_ID("$Id: lib_ttyflags.c,v 1.14 2006/12/30 21:37:20 tom Exp $")
+MODULE_ID("$Id: lib_ttyflags.c,v 1.15 2007/05/26 18:54:25 tom Exp $")
 
 NCURSES_EXPORT(int)
 _nc_get_tty_mode(TTY * buf)
 {
     int result = OK;
 
-    if (cur_term == 0) {
+    if (buf == 0) {
        result = ERR;
     } else {
-       for (;;) {
-           if (GET_TTY(cur_term->Filedes, buf) != 0) {
-               if (errno == EINTR)
-                   continue;
-               result = ERR;
+       if (cur_term == 0) {
+           result = ERR;
+       } else {
+           for (;;) {
+               if (GET_TTY(cur_term->Filedes, buf) != 0) {
+                   if (errno == EINTR)
+                       continue;
+                   result = ERR;
+               }
+               break;
            }
-           break;
        }
-    }
 
-    if (result == ERR)
-       memset(buf, 0, sizeof(*buf));
+       if (result == ERR)
+           memset(buf, 0, sizeof(*buf));
 
-    TR(TRACE_BITS, ("_nc_get_tty_mode(%d): %s",
-                   cur_term->Filedes, _nc_trace_ttymode(buf)));
+       TR(TRACE_BITS, ("_nc_get_tty_mode(%d): %s",
+                       cur_term->Filedes, _nc_trace_ttymode(buf)));
+    }
     return (result);
 }
 
@@ -71,22 +75,26 @@ _nc_set_tty_mode(TTY * buf)
 {
     int result = OK;
 
-    if (cur_term == 0) {
+    if (buf == 0) {
        result = ERR;
     } else {
-       for (;;) {
-           if (SET_TTY(cur_term->Filedes, buf) != 0) {
-               if (errno == EINTR)
-                   continue;
-               if ((errno == ENOTTY) && (SP != 0))
-                   SP->_notty = TRUE;
-               result = ERR;
+       if (cur_term == 0) {
+           result = ERR;
+       } else {
+           for (;;) {
+               if (SET_TTY(cur_term->Filedes, buf) != 0) {
+                   if (errno == EINTR)
+                       continue;
+                   if ((errno == ENOTTY) && (SP != 0))
+                       SP->_notty = TRUE;
+                   result = ERR;
+               }
+               break;
            }
-           break;
        }
+       TR(TRACE_BITS, ("_nc_set_tty_mode(%d): %s",
+                       cur_term->Filedes, _nc_trace_ttymode(buf)));
     }
-    TR(TRACE_BITS, ("_nc_set_tty_mode(%d): %s",
-                   cur_term->Filedes, _nc_trace_ttymode(buf)));
     return (result);
 }
 
@@ -164,6 +172,22 @@ reset_shell_mode(void)
     returnCode(ERR);
 }
 
+static TTY *
+saved_tty(void)
+{
+    TTY *result = 0;
+
+    if (SP != 0) {
+       result = &(SP->_saved_tty);
+    } else {
+       if (_nc_prescreen.saved_tty == 0) {
+           _nc_prescreen.saved_tty = typeCalloc(TTY, 1);
+       }
+       result = _nc_prescreen.saved_tty;
+    }
+    return result;
+}
+
 /*
 **     savetty()  and  resetty()
 **
@@ -174,7 +198,7 @@ savetty(void)
 {
     T((T_CALLED("savetty()")));
 
-    returnCode(_nc_get_tty_mode(&(SP->_saved_tty)));
+    returnCode(_nc_get_tty_mode(saved_tty()));
 }
 
 NCURSES_EXPORT(int)
@@ -182,5 +206,5 @@ resetty(void)
 {
     T((T_CALLED("resetty()")));
 
-    returnCode(_nc_set_tty_mode(&(SP->_saved_tty)));
+    returnCode(_nc_set_tty_mode(saved_tty()));
 }
index fa6ab48d208abc47be0c39b2aba9c3a8135efec9..5723263cc572c8c8118292254560b18e1a916323 100755 (executable)
@@ -1,5 +1,5 @@
 /****************************************************************************
- * Copyright (c) 2003,2006 Free Software Foundation, Inc.                   *
+ * Copyright (c) 2007 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            *
@@ -26,7 +26,7 @@
  * authorization.                                                           *
  ****************************************************************************/
 /*
- * $Id: demo_panels.c,v 1.2 2006/04/01 19:08:03 tom Exp $
+ * $Id: demo_panels.c,v 1.5 2007/05/26 22:35:46 tom Exp $
  *
  * Demonstrate a variety of functions from the panel library.
  * Thomas Dickey - 2003/4/26
@@ -44,10 +44,376 @@ replace_panel                      -
 
 #include <panel.h>
 
+typedef void (*InitPanel) (void);
+typedef void (*FillPanel) (PANEL *);
+
+static bool use_colors;
+
+static NCURSES_CONST char *mod[] =
+{
+    "test ",
+    "TEST ",
+    "(**) ",
+    "*()* ",
+    "<--> ",
+    "LAST "
+};
+
+/*+-------------------------------------------------------------------------
+       saywhat(text)
+--------------------------------------------------------------------------*/
+static void
+saywhat(NCURSES_CONST char *text)
+{
+    wmove(stdscr, LINES - 1, 0);
+    wclrtoeol(stdscr);
+    if (text != 0 && *text != '\0') {
+       waddstr(stdscr, text);
+       waddstr(stdscr, "; ");
+    }
+    waddstr(stdscr, "press any key to continue");
+}                              /* end of saywhat */
+
+static PANEL *
+mkpanel(short color, int rows, int cols, int tly, int tlx)
+{
+    WINDOW *win;
+    PANEL *pan = 0;
+    char *userdata = malloc(3);
+
+    if ((win = newwin(rows, cols, tly, tlx)) != 0) {
+       if ((pan = new_panel(win)) == 0) {
+           delwin(win);
+       } else if (use_colors) {
+           short fg = (color == COLOR_BLUE) ? COLOR_WHITE : COLOR_BLACK;
+           short bg = color;
+
+           init_pair(color, fg, bg);
+           wbkgdset(win, (chtype) (COLOR_PAIR(color) | ' '));
+       } else {
+           wbkgdset(win, A_BOLD | ' ');
+       }
+    }
+    sprintf(userdata, "p%d", color % 8);
+    set_panel_userptr(pan, (NCURSES_CONST void *) userdata);
+    return pan;
+}
+
+/*+-------------------------------------------------------------------------
+       rmpanel(pan)
+--------------------------------------------------------------------------*/
+static void
+rmpanel(PANEL * pan)
+{
+    WINDOW *win = panel_window(pan);
+    del_panel(pan);
+    delwin(win);
+}                              /* end of rmpanel */
+
+/*+-------------------------------------------------------------------------
+       pflush()
+--------------------------------------------------------------------------*/
+static void
+pflush(void)
+{
+    update_panels();
+    doupdate();
+}                              /* end of pflush */
+
+/*+-------------------------------------------------------------------------
+       fill_panel(win)
+--------------------------------------------------------------------------*/
+static void
+init_panel(void)
+{
+    register int y, x;
+
+    for (y = 0; y < LINES - 1; y++) {
+       for (x = 0; x < COLS; x++)
+           wprintw(stdscr, "%d", (y + x) % 10);
+    }
+}
+
+static void
+fill_panel(PANEL * pan)
+{
+    WINDOW *win = panel_window(pan);
+    int num = ((const char *) panel_userptr(pan))[1];
+    int y, x;
+
+    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++) {
+           wmove(win, y, x);
+           waddch(win, UChar(num));
+       }
+    }
+}
+
+#if USE_WIDEC_SUPPORT
+static void
+make_fullwidth_digit(cchar_t *target, int digit)
+{
+    wchar_t source[2];
+
+    source[0] = digit + 0xff10;
+    source[1] = 0;
+    setcchar(target, source, A_NORMAL, 0, 0);
+}
+
+static void
+init_wide_panel(void)
+{
+    int digit;
+    cchar_t temp[10];
+
+    for (digit = 0; digit < 10; ++digit)
+       make_fullwidth_digit(&temp[digit], digit);
+
+    do {
+       int y, x;
+       getyx(stdscr, y, x);
+       digit = (y + x / 2) % 10;
+    } while (add_wch(&temp[digit]) != ERR);
+}
+
+static void
+fill_wide_panel(PANEL * pan)
+{
+    WINDOW *win = panel_window(pan);
+    int num = ((const char *) panel_userptr(pan))[1];
+    int y, x;
+
+    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++) {
+           wmove(win, y, x);
+           waddch(win, UChar(num));
+       }
+    }
+}
+#endif
+
+#define MAX_PANELS 5
+
+static void
+canned_panel(PANEL * px[MAX_PANELS + 1], NCURSES_CONST char *cmd)
+{
+    int which = cmd[1] - '0';
+
+    saywhat(cmd);
+    switch (*cmd) {
+    case 'h':
+       hide_panel(px[which]);
+       break;
+    case 's':
+       show_panel(px[which]);
+       break;
+    case 't':
+       top_panel(px[which]);
+       break;
+    case 'b':
+       bottom_panel(px[which]);
+       break;
+    case 'd':
+       rmpanel(px[which]);
+       break;
+    }
+    pflush();
+    wgetch(stdscr);
+}
+
+static void
+demo_panels(void (*myInit) (void), void (*myFill) (PANEL *))
+{
+    int itmp;
+    PANEL *px[MAX_PANELS + 1];
+
+    scrollok(stdscr, FALSE);   /* we don't want stdscr to scroll! */
+    refresh();
+
+    myInit();
+    for (itmp = 1; itmp <= MAX_PANELS; ++itmp)
+       px[itmp] = 0;
+
+    px[1] = mkpanel(COLOR_RED,
+                   LINES / 2 - 2,
+                   COLS / 8 + 1,
+                   0,
+                   0);
+
+    px[2] = mkpanel(COLOR_GREEN,
+                   LINES / 2 + 1,
+                   COLS / 7,
+                   LINES / 4,
+                   COLS / 10);
+
+    px[3] = mkpanel(COLOR_YELLOW,
+                   LINES / 4,
+                   COLS / 10,
+                   LINES / 2,
+                   COLS / 9);
+
+    px[4] = mkpanel(COLOR_BLUE,
+                   LINES / 2 - 2,
+                   COLS / 8,
+                   LINES / 2 - 2,
+                   COLS / 3);
+
+    px[5] = mkpanel(COLOR_MAGENTA,
+                   LINES / 2 - 2,
+                   COLS / 8,
+                   LINES / 2,
+                   COLS / 2 - 2);
+
+    myFill(px[1]);
+    myFill(px[2]);
+    myFill(px[3]);
+    myFill(px[4]);
+    myFill(px[5]);
+
+    hide_panel(px[4]);
+    hide_panel(px[5]);
+    pflush();
+    saywhat("");
+    wgetch(stdscr);
+
+    saywhat("h3 s1 s2 s4 s5");
+    move_panel(px[1], 0, 0);
+    hide_panel(px[3]);
+    show_panel(px[1]);
+    show_panel(px[2]);
+    show_panel(px[4]);
+    show_panel(px[5]);
+    pflush();
+    wgetch(stdscr);
+
+    canned_panel(px, "s1");
+    canned_panel(px, "s2");
+
+    saywhat("m2");
+    move_panel(px[2], LINES / 3 + 1, COLS / 8);
+    pflush();
+    wgetch(stdscr);
+
+    canned_panel(px, "s3");
+
+    saywhat("m3");
+    move_panel(px[3], LINES / 4 + 1, COLS / 15);
+    pflush();
+    wgetch(stdscr);
+
+    canned_panel(px, "b3");
+    canned_panel(px, "s4");
+    canned_panel(px, "s5");
+    canned_panel(px, "t3");
+    canned_panel(px, "t1");
+    canned_panel(px, "t2");
+    canned_panel(px, "t3");
+    canned_panel(px, "t4");
+
+    for (itmp = 0; itmp < 6; itmp++) {
+       WINDOW *w4 = panel_window(px[4]);
+       WINDOW *w5 = panel_window(px[5]);
+
+       saywhat("m4");
+       wmove(w4, LINES / 8, 1);
+       waddstr(w4, mod[itmp]);
+       move_panel(px[4], LINES / 6, itmp * (COLS / 8));
+       wmove(w5, LINES / 6, 1);
+       waddstr(w5, mod[itmp]);
+       pflush();
+       wgetch(stdscr);
+
+       saywhat("m5");
+       wmove(w4, LINES / 6, 1);
+       waddstr(w4, mod[itmp]);
+       move_panel(px[5], LINES / 3 - 1, (itmp * 10) + 6);
+       wmove(w5, LINES / 8, 1);
+       waddstr(w5, mod[itmp]);
+       pflush();
+       wgetch(stdscr);
+    }
+
+    saywhat("m4");
+    move_panel(px[4], LINES / 6, itmp * (COLS / 8));
+    pflush();
+    wgetch(stdscr);
+
+    canned_panel(px, "t5");
+    canned_panel(px, "t2");
+    canned_panel(px, "t1");
+    canned_panel(px, "d2");
+    canned_panel(px, "h3");
+    canned_panel(px, "d1");
+    canned_panel(px, "d4");
+    canned_panel(px, "d5");
+    canned_panel(px, "d3");
+
+    wgetch(stdscr);
+
+    erase();
+    endwin();
+}
+
+static void
+usage(void)
+{
+    static const char *const tbl[] =
+    {
+       "Usage: demo_panels [options]"
+       ,""
+       ,"Options:"
+       ,"  -m       do not use colors"
+#if USE_WIDEC_SUPPORT
+       ,"  -w       use wide-characters in panels and background"
+#endif
+    };
+    size_t n;
+    for (n = 0; n < SIZEOF(tbl); n++)
+       fprintf(stderr, "%s\n", tbl[n]);
+    ExitProgram(EXIT_FAILURE);
+}
+
 int
-main(int argc GCC_UNUSED, char *argv[]GCC_UNUSED)
+main(int argc, char *argv[])
 {
-    printf("Not implemented - demo for panel library\n");
+    int c;
+    bool monochrome = FALSE;
+    InitPanel myInit = init_panel;
+    FillPanel myFill = fill_panel;
+
+    while ((c = getopt(argc, argv, "mw")) != EOF) {
+       switch (c) {
+       case 'm':
+           monochrome = TRUE;
+           break;
+#if USE_WIDEC_SUPPORT
+       case 'w':
+           myInit = init_wide_panel;
+           myFill = fill_wide_panel;
+           break;
+#endif
+       default:
+           usage();
+       }
+    }
+
+    initscr();
+
+    use_colors = monochrome ? FALSE : has_colors();
+    if (use_colors)
+       start_color();
+
+    demo_panels(myInit, myFill);
+    endwin();
+
     return EXIT_SUCCESS;
 }
 #else