Files
oldlinux-files/study/sabre/Mirrored/ncurses-intro.html
2024-02-19 00:25:23 -05:00

1035 lines
46 KiB
HTML

<TITLE>mitem_attribs(3x)</TITLE>
<HTML>
<HEAD>
<TITLE>Writing Programs with NCURSES</TITLE>
<link rev="made" href="mailto:esr@snark.thyrsus.com">
</HEAD>
<BODY>
<H1>Writing Programs with NCURSES</H1>
<BLOCKQUOTE>
by Zeyd M. ben-Halim and Eric S. Raymond<BR>
(version 1.9, 1 May 1995)
</BLOCKQUOTE>
<H1>Contents</H1>
<UL>
<LI> <A HREF="#introduction">Introduction</A>
<LI> <A HREF="#overview">An Overview of Curses</A>
<UL>
<LI> <A HREF="#terminology">Terminology</A>
<LI> <A HREF="#compiling">Compiling Programs using Curses</A>
<LI> <A HREF="#updating">Updating the Screen</A>
<LI> <A HREF="#stdscr">Standard Windows and Function Naming Conventions</A>
<LI> <A HREF="#variables">Variables</A>
</UL>
<LI> <A HREF="#using">Using the Library</A>
<UL>
<LI> <A HREF="#starting">Starting up</A>
<LI> <A HREF="#output">Output</A>
<LI> <A HREF="#input">Input</A>
<LI> <A HREF="#formschars">Using Forms Characters</A>
<LI> <A HREF="#attributes">Character Attributes and Color</A>
<LI> <A HREF="#finishing">Finishing Up</A>
</UL>
<LI> <A HREF="#functions">Function Descriptions</A>
<UL>
<LI> <A HREF="#init">Initialization and Wrapup</A>
<LI> <A HREF="#flush">Causing Output to the Terminal</A>
<LI> <A HREF="#lowlevel">Low-Level Capability Access</A>
<LI> <A HREF="#debugging">Debugging</A>
</UL>
<LI> <A HREF="#hints">Hints, Tips, and Tricks</A>
<UL>
<LI> <A HREF="#caution">Some Notes of Caution</A>
<LI> <A HREF="#leaving">Temporarily Leaving ncurses Mode</A>
<LI> <A HREF="#xterm">Using <TT>ncurses</TT> under <TT>xterm</TT></A>
<LI> <A HREF="#screens">Handling Multiple Terminal Screens</A>
<LI> <A HREF="#testing">Testing for Terminal Capabilities</A>
<LI> <A HREF="#tuning">Tuning for Speed</A>
<LI> <A HREF="#special">Special Features of <TT>ncurses</TT></A>
</UL>
<LI> <A HREF="#panels">The <CODE>panels</CODE> Library</A>
<UL>
<LI> <A HREF="#pcompile">Compiling With the panels Library</A>
<LI> <A HREF="#poverview">Overview of panels</A>
<LI> <A HREF="#pstsdcr">Panels, Input, and the Standard Screen</A>
<LI> <A HREF="#hiding">Hiding Panels</A>
<LI> <A HREF="#pmisc">Miscellaneous Other Facilities</A>
</UL>
<LI> <A HREF="#menu">The Menu Library</A>
<LI> <A HREF="#mcompile">Compiling With the menu Library</A>
<LI> <A HREF="#moverview">Overview of Menus</A>
<LI> <A HREF="#select">Selecting items</A>
<LI> <A HREF="#mdisplay">Menu Display</A>
<LI> <A HREF="#mwindows">Menu Windows</A>
<LI> <A HREF="#minput">Processing Menu Input</A>
<LI> <A HREF="#mmisc">Miscellaneous Other Features</A>
</UL>
<HR>
<H1><A NAME="introduction">Introduction</A></H1>
This document is an introduction to programming with <TT>curses</TT>. It is
not an exhaustive reference for the curses Application Programming Interface
(API); that role is filled by the <TT>curses</TT> manual pages. Rather, it
is intended to help C programmers ease into using the package. <P>
The <TT>curses</TT> package is a subroutine library which presents a high level
screen model to the programmer, hiding differences between terminal types and
doing automatic optimization of output to change one screenfull of text into
another. <TT>Curses</TT> uses terminfo, which is a database format that can
describe the capabilities of thousands of different terminals. <P>
Historically, the first ancestor of <TT>curses</TT> was the routines written to
provide screen-handling for the game <TT>rogue</TT>; these used the already-
existing <TT>termcap</TT> database facility for describing terminal
capabilities. These routines were abstracted into a documented library and
first released with the early BSD UNIX versions. <P>
System III UNIX from Bell Labs featured a rewritten and much-improved
<TT>curses</TT> library. It introduced the terminfo format. Terminfo is based
on Berkeley's termcap database, but contains a number of improvements and
extensions. Parameterized capabilities strings were introduced, making it
possible to describe multiple video attributes, and colors and to handle far
more unusual terminals than possible with termcap. In the later AT&amp;T
System V releases, <TT>curses</TT> evolved to use more facilities and offer
more capabilities, going far beyond BSD curses in power and flexibility.<P>
This document describes <TT>ncurses</TT>, a freeware implementation of the
System V <TT>curses</TT> API. It includes the following System V curses
features: <P>
<UL>
<LI> Support for multiple screen highlights (BSD curses could only
handle one `standout' highlight, usually reverse-video). <P>
<LI> Support for line- and box-drawing using forms characters. <P>
<LI> Recognition of function keys on input. <P>
<LI> Color support. <P>
<LI> Support for pads (windows of larger than screen size on which the
screen or a subwindow defines a viewport). <P>
</UL>
Also, this package makes use of the insert and delete line and character
features of terminals so equipped, and determines how to optimally use these
features with no help from the programmer. It allows arbitrary combinations of
video attributes to be displayed, even on terminals that leave ``magic
cookies'' on the screen to mark changes in attributes. <P>
The <TT>ncurses</TT> package was originated by Pavel Curtis. The primary
maintainer of the package is Zeyd ben-Halim &lt;zmbenhal@netcom.com&gt;.
Eric S. Raymond &lt;esr@snark.thyrsus.com&gt; wrote many of the new
features in versions after 1.8.1 and coauthored this introduction. <P>
This document also describes the <A HREF="panels"></A> extension library,
similarly modeled on the SVr4 panels facility. This library allows you to
associate backing store with each of a stack or deck of overlapping windows,
and provides operations for moving windows around in the stack that change
their visibility in the natural way (handling window overlaps). <P>
Finally, this document describes the <A HREF="#menus">menu</A> extension
library, also cloned from System V, which provides easy construction and
sequences of menus. <P>
<H1><A NAME="overview">An Overview of Curses</A></H1>
<H2><A NAME="terminology">Terminology</A></H2>
In this document, the following terminology is used with reasonable
consistency:
<DL>
<DT> window
<DD>
A data structure describing a sub-rectangle of the screen (possibly the
entire screen). You can write to a window as though it were a miniature
screen, scrolling independently of other windows on the physical screen.
<DT> screens
<DD>
A subset of windows which are as large as the terminal screen, i.e., they start
at the upper left hand corner and encompass the lower right hand corner. One
of these, <TT>stdscr</TT>, is automatically provided for the programmer.
<DT> terminal screen
<DD>
The package's idea of what the terminal display currently looks like, i.e.,
what the user sees now. This is a special screen.
</DL>
<H2><A NAME="compiling">Compiling Programs using Curses</A></H2>
In order to use the library, it is necessary to have certain types and
variables defined. Therefore, the programmer must have a line:
<PRE>
#include <TT>&lt;curses.h&gt;</TT>
</PRE>
at the top of the program source. The screen package uses the Standard I/O
library, so <TT>&lt;curses.h&gt;</TT> includes
<TT>&lt;stdio.h&gt;</TT>. <TT>&lt;curses.h&gt;</TT> also includes
<TT>&lt;termios.h&gt;</TT>, <TT>&lt;termio.h&gt;</TT>, or
<TT>&lt;sgtty.h&gt;</TT> depending on your system. It is redundant (but
harmless) for the programmer to do these includes, too. In linking with
<TT>curses</TT> you need to have <TT>-lncurses</TT> in your LDFLAGS or on the
command line. There is no need for any other libraries.
<H2><A NAME="updating">Updating the Screen</A></H2>
In order to update the screen optimally, it is necessary for the routines to
know what the screen currently looks like and what the programmer wants it to
look like next. For this purpose, a data type (structure) named WINDOW is
defined which describes a window image to the routines, including its starting
position on the screen (the (y, x) coordinates of the upper left hand corner)
and its size. One of these (called <TT>curscr</TT>, for current screen) is a
screen image of what the terminal currently looks like. Another screen (called
<TT>stdscr</TT>, for standard screen) is provided by default to make changes
on. <P>
A window is a purely internal representation. It is used to build and store a
potential image of a portion of the terminal. It doesn't bear any necessary
relation to what is really on the terminal screen; it's more like a
scratchpad or write buffer. <P>
To make the section of physical screen corresponding to a window reflect the
contents of the window structure, the routine <TT>refresh()</TT> (or
<TT>wrefresh()</TT> if the window is not <TT>stdscr</TT>) is called. <P>
A given physical screen section may be within the scope of any number of
overlapping windows. Also, changes can be made to windows in any order,
without regard to motion efficiency. Then, at will, the programmer can
effectively say ``make it look like this,'' and let the package implementation
determine the most efficient way to repaint the screen. <P>
<H2><A NAME="stdscr">Standard Windows and Function Naming Conventions</A></H2>
As hinted above, the routines can use several windows, but two are
automatically given: <TT>curscr</TT>, which knows what the terminal looks like,
and <TT>stdscr</TT>, which is what the pro- grammer wants the terminal to look
like next. The user should never actually access <TT>curscr</TT> directly.
Changes should be made to through the API, and then the routine
<TT>refresh()</TT> (or <TT>wrefresh()</TT>) called. <P>
Many functions are defined to use <TT>stdscr</TT> as a default screen. For
example, to add a character to <TT>stdscr</TT>, one calls <TT>addch()</TT> with
the desired character as argument. To write to a different window. use the
routine <TT>waddch()</TT> (for `w'indow-specific addch()) is provided. This
convention of prepending function names with a `w' when they are to be
applied to specific windows is consistent. The only routines which do not
follow it are those for which a window must always be specified. <P>
In order to move the current (y, x) coordinates from one point to another, the
routines <TT>move()</TT> and <TT>wmove()</TT> are provided. However, it is
often desirable to first move and then perform some I/O operation. In order to
avoid clumsiness, most I/O routines can be preceded by the prefix 'mv' and
the desired (y, x) coordinates prepended to the arguments to the function. For
example, the calls
<PRE>
move(y, x);
addch(ch);
</PRE>
can be replaced by
<PRE>
mvaddch(y, x, ch);
</PRE>
and
<PRE>
wmove(win, y, x);
waddch(win, ch);
</PRE>
can be replaced by
<PRE>
mvwaddch(win, y, x, ch);
</PRE>
Note that the window description pointer (win) comes before the added (y, x)
coordinates. If a function requires a window pointer, it is always the first
parameter passed. <P>
<H2><A NAME="variables">Variables</A></H2>
The <TT>curses</TT> library sets some variables describing the terminal
capabilities.
<PRE>
type name description
------------------------------------------------------------------
int LINES number of lines on the terminal
int COLS number of columns on the terminal
</PRE>
The <TT>curses.h</TT> also introduces some <TT>#define</TT> constants and types
of general usefulness:
<DL>
<DT> <TT>bool</TT>
<DD> boolean type, actually a `char' (e.g., <TT>bool doneit;</TT>)
<DT> <TT>TRUE</TT>
<DD> boolean `true' flag (1).
<DT> <TT>FALSE</TT>
<DD> boolean `false' flag (0).
<DT> <TT>ERR</TT>
<DD> error flag returned by routines on a fail (-1).
<DT> <TT>OK</TT>
<DD> error flag returned by routines when things go right.
</DL>
<H1><A NAME="using">Using the Library</A></H1>
Now we describe how to actually use the screen package. In it, we assume all
updating, reading, etc. is applied to <TT>stdscr</TT>. These instructions will
work on any window, providing you change the function names and parameters as
mentioned above. <P>
Here is a sample program to motivate the discussion: <P>
<PRE>
#include <curses.h>
#include <signal.h>
static void finish(int sig);
main(int argc, char *argv[])
{
/* initialize your non-curses data structures here */
(void) signal(SIGINT, finish); /* arrange interrupts to terminate */
(void) initscr(); /* initialize the curses library */
keypad(stdscr, TRUE); /* enable keyboard mapping */
(void) nonl(); /* tell curses not to do NL->CR/NL on output */
(void) cbreak(); /* take input chars one at a time, no wait for \n */
(void) noecho(); /* don't echo input */
if (has_colors())
{
start_color();
/*
* Simple color assignment, often all we need.
*/
init_pair(COLOR_BLACK, COLOR_BLACK, COLOR_BLACK);
init_pair(COLOR_GREEN, COLOR_GREEN, COLOR_BLACK);
init_pair(COLOR_RED, COLOR_RED, COLOR_BLACK);
init_pair(COLOR_CYAN, COLOR_CYAN, COLOR_BLACK);
init_pair(COLOR_WHITE, COLOR_WHITE, COLOR_BLACK);
init_pair(COLOR_MAGENTA, COLOR_MAGENTA, COLOR_BLACK);
init_pair(COLOR_BLUE, COLOR_BLUE, COLOR_BLACK);
init_pair(COLOR_YELLOW, COLOR_YELLOW, COLOR_BLACK);
}
for (;;)
{
int c = getch(); /* refresh, accept single keystroke of input */
/* process the command keystroke */
}
finish(0); /* we're done */
}
static void finish(int sig)
{
endwin();
/* do your non-curses wrapup here */
exit(0);
}
</PRE>
<H2><A NAME="starting">Starting up</A></H2>
In order to use the screen package, the routines must know about terminal
characteristics, and the space for <TT>curscr</TT> and <TT>stdscr</TT> must be
allocated. These function <TT>initscr()</TT> does both these things. Since it
must allocate space for the windows, it can overflow memory when attempting to
do so. On the rare occasions this happens, <TT>initscr()</TT> will terminate
the program with an error message. <TT>initscr()</TT> must always be called
before any of the routines which affect windows are used. If it is not, the
program will core dump as soon as either <TT>curscr</TT> or <TT>stdscr</TT> are
referenced. However, it is usually best to wait to call it until after you are
sure you will need it, like after checking for startup errors. Terminal status
changing routines like <TT>nl()</TT> and <TT>cbreak()</TT> should be called
after <TT>initscr()</TT>. <P>
Once the screen windows have been allocated, you can set them up for
your program. If you want to, say, allow a screen to scroll, use
<TT>scrollok()</TT>. If you want the cursor to be left in place after
the last change, use <TT>leaveok()</TT>. If this isn't done,
<TT>refresh()</TT> will move the cursor to the window's current (y, x)
coordinates after updating it. <P>
You can create new windows of your own using the functions <TT>newwin()</TT>,
<TT>derwin()</TT>, and <TT>subwin()</TT>. The routine <TT>delwin()</TT> will
allow you to get rid of old windows. All the options described above can be
applied to any window. <P>
<H2><A NAME="output">Output</A></H2>
Now that we have set things up, we will want to actually update the terminal.
The basic functions used to change what will go on a window are
<TT>addch()</TT> and <TT>move()</TT>. <TT>addch()</TT> adds a character at the
current (y, x) coordinates. <TT>move()</TT> changes the current (y, x)
coordinates to whatever you want them to be. It returns <TT>ERR</TT> if you
try to move off the window. As mentioned above, you can combine the two into
<TT>mvaddch()</TT> to do both things at once. <P>
The other output functions, such as <TT>addstr()</TT> and <TT>printw()</TT>,
all call <TT>addch()</TT> to add characters to the window. <P>
After you have put on the window what you want there, when you want the portion
of the terminal covered by the window to be made to look like it, you must call
<TT>refresh()</TT>. In order to optimize finding changes, <TT>refresh()</TT>
assumes that any part of the window not changed since the last
<TT>refresh()</TT> of that window has not been changed on the terminal, i.e.,
that you have not refreshed a portion of the terminal with an overlapping
window. If this is not the case, the routine <TT>touchwin()</TT> is provided
to make it look like the entire window has been changed, thus making
<TT>refresh()</TT> check the whole subsection of the terminal for changes. <P>
If you call <TT>wrefresh()</TT> with <TT>curscr</TT> as its argument, it will
make the screen look like <TT>curscr</TT> thinks it looks like. This is useful
for implementing a command which would redraw the screen in case it get messed
up. <P>
<H2><A NAME="input">Input</A></H2>
The complementary function to <TT>addch()</TT> is <TT>getch()</TT> which, if
echo is set, will call <TT>addch()</TT> to echo the character. Since the
screen package needs to know what is on the terminal at all times, if
characters are to be echoed, the tty must be in raw or cbreak mode. Since
initially the terminal has echoing enabled and is in ordinary ``cooked'' mode,
one or the other has to changed before calling <TT>getch()</TT>; otherwise,
the program's output will be unpredictable. <P>
When you need to accept line-oriented input in a window, the functions
<TT>wgetstr</TT> and friends are available. There is even a <TT>wscanw</TT>
function that can do <TT>scanf</TT>(3)-style multi-field parsing on window
input. These pseudo-line-oriented functions turn on echoing while they
execute. <P>
The example code above uses the call <TT>keypad(stdscr, TRUE)</TT> to enable
support for function-key mapping. With this feature, the <TT>getch()</TT> code
watches the input stream for character sequences that correspond to arrow and
function keys. These sequences are returned as pseudo-character values. The
<TT>#define</TT> values returned are listed in the <TT>ncurses.h</TT> The
mapping from sequences to <TT>#define</TT> values is determined by
<TT>key_</TT> capabilities in the terminal's terminfo entry. <P>
<H2><A NAME="formschars">Using Forms Characters</A></H2>
The <TT>addch</TT> function (and some others, including <TT>box</TT> and
<TT>border</TT>) can accept some pseudo-character arguments which are specially
defined by <TT>ncurses</TT>. These are <TT>#define</TT> values set up in
the <TT>ncurses.h</TT> header; see there for a complete list (look for
the prefix <TT>ACS_</TT>). <P>
The most useful of the ACS defines are the forms-drawing characters. You can
use these to draw boxes and simple graphs on the screen. If the terminal
does not have such characters, <TT>ncurses.h</TT> will map them to a
recognizable (though ugly) set of ASCII defaults. <P>
<H2><A NAME="attributes">Character Attributes and Color</A></H2>
The <TT>ncurses</TT> package supports screen highlights including standout,
reverse-video, underline, and blink. It also supports color, which is treated
as another kind of highlight. <P>
Highlights are encoded, internally, as high bits of the pseudo-character type
(<TT>chtype</TT>) that <TT>ncurses.h</TT> uses to represent the contents of a
screen cell. See the <TT>ncurses.h</TT> header file for a complete list of
highlight mask values (look for the prefix <TT>A_</TT>).<P>
There are two ways to make highlights. One is to logical-or the value of the
highlights you want into the character argument of an <TT>addch</TT> call,
or any other output call that takes a <TT>chtype</TT> argument. <P>
The other is to set the current-highlight value. This is logical-or'ed with
any highlight you specify the first way. You do this with the functions
<TT>attron</TT>, <TT>attroff</TT>, and <TT>attrset</TT>; see the manual
pages for details.
Color is a special kind of highlight. The package actually thinks in terms
of color pairs, combinations of foreground and background colors. The sample
code above sets up eight color pairs, all of the guaranteed-available colors
on black. Note that each color pair is, in effect, given the name of its
foreground color. Any other range of eight non-conflicting values could
have been used as the first arguments of the <TT>init_pair</TT> values. <P>
Once you've done an <TT>init_pair</TT> that creates color-pair N, you can
use <TT>COLOR_PAIR(N)</TT> as a highlight that invokes that particular
color combination. Note that <TT>COLOR_PAIR(N)</TT>, for constant N,
is itself a compile-time constant and can be used in initializers. <P>
<H2><A NAME="finishing">Finishing Up</A></H2>
In order to clean up after the <TT>ncurses</TT> routines, the routine
<TT>endwin()</TT> is provided. It restores tty modes to what they were when
<TT>initscr()</TT> was first called, and moves the cursor down to the
lower-left corner. Thus, anytime after the call to initscr, <TT>endwin()</TT>
should be called before exiting. <P>
<H1><A NAME="functions">Function Descriptions</A></H1>
We describe the detailed behavior of some important curses functions here, as a
supplement to the manual page descriptions.
<H2><A NAME="init">Initialization and Wrapup</A></H2>
<DL>
<DT> <TT>initscr()</TT>
<DD> The first function called should almost always be
<TT>initscr</TT>. This will determine the terminal type and
initialize curses data structures. <TT>initscr</TT> also arranges that
the first call to <TT>refresh</TT> will clear the screen. If an error
occurs a message is writen to standard error and the program
exits. Otherwise it returns a pointer to stdscr. A few functions may be
called before initscr (<TT>slk_init</TT>, <TT>filter</TT>,
<TT>ripofflines</TT>, <TT>use_env</TT>, and, if you are using multiple
terminals, <TT>newterm</TT>.)
<DT> <TT>endwin()</TT>
<DD> Your program should always call <TT>endwin</TT> before exiting or
shelling out of the program. This function will restore tty modes,
move the cursor to the lower left corner of the screen, reset the
terminal into the proper nonvisual mode. Calling <TT>refresh()</TT>
or <TT>doupdate()</TT> after a temporary escape from the program will
restore the ncurses screen from before the escape.
<DT> <TT>newterm(type, ofp, ifp)</TT>
<DD> A program which outputs to more than one terminal should use
<TT>newterm</TT> instead of <TT>initscr</TT>. <TT>newterm</TT> should
be called once for each terminal. It returns a variable of type
<TT>SCREEN *</TT> which should be saved as a reference to that
terminal. The arguments are the type of the terminal (a string) and
<TT>FILE</TT> pointers for the output and input of the terminal. If
type is NULL then the environment variable <TT>$TERM</TT> is used.
<TT>endwin</TT> should called once at wrapup time for each terminal
opened using this function.
<DT> <TT>set_term(new)</TT>
<DD> This function is used to switch to a different terminal previously
opened by <TT>newterm</TT>. The screen reference for the new terminal
is passed as the parameter. The previous terminal is returned by the
function. All other calls affect only the current terminal.
<DT> <TT>delscreen(sp)</TT>
<DD> The inverse of <TT>newterm</TT>; deallocates the data structures
associated with a given <TT>SCREEN</TT> reference.
</DL>
<H2><A NAME="flush">Causing Output to the Terminal</A></H2>
<DL>
<DT> <TT>refresh()</TT> and <TT>wrefresh(win)</TT>
<DD> These functions must be called to actually get any output on
the terminal, as other routines merely manipulate data
structures. <TT>wrefresh</TT> copies the named window to the physi-
cal terminal screen, taking into account what is already
there in order to do optimizations. <TT>refresh</TT> does a
refresh of <TT>stdscr</TT>. Unless <TT>leaveok</TT> has been
enabled, the physical cursor of the terminal is left at the
location of the window's cursor.
<DT> <TT>doupdate()</TT> and <TT>wnoutrefresh(win)</TT>
<DD> These two functions allow multiple updates with more efficiency
than wrefresh. To use them, it is important to understand how curses
works. In addition to all the window structures, curses keeps two
data structures representing the terminal screen: a physical screen,
describing what is actually on the screen, and a virtual screen,
describing what the programmer wants to have on the screen. wrefresh
works by first copying the named window to the virtual screen
(<TT>wnoutrefresh</TT>), and then calling the routine to update the
screen (<TT>doupdate</TT>). If the programmer wishes to output
several windows at once, a series of calls to wre- fresh will result
in alternating calls to <TT>wnoutrefresh</TT> and <TT>doupdate</TT>,
causing several bursts of output to the screen. By calling
<TT>wnoutrefresh</TT> for each window, it is then possible to call
<TT>doupdate once</TT>, resulting in only one burst of output, with
probably fewer total characters transmitted.
</DL>
<H2><A NAME="init">Low-Level Capability Access</A></H2>
<DL>
<DT> <TT>setupterm(term, filenum, errret)</TT>
This routine is called to initialize a terminal's description, without setting
up the curses screen structures or changing the tty-driver mode bits.
<TT>term</TT> is the character string representing the name of the terminal
being used. <TT>filenum</TT> is the UNIX file descriptor of the ter- minal to
be used for output. <TT>errret</TT> is a pointer to an integer, in which a
success or failure indication is returned. The values returned can be 1 (all
is well), 0 (no such terminal), or -1 (some problem locating the terminfo
database). <P>
The value of <TT>term</TT> can be given as NULL, which will cause the value of
<TT>TERM</TT> in the environment to be used. The <TT>errret</TT> pointer can
also be given as NULL, meaning no error code is wanted. If <TT>errret</TT> is
defaulted, and something goes wrong, <TT>setupterm</TT> will print an
appropriate error message and exit, rather than returning. Thus, a simple
program can call setupterm(0, 1, 0) and not worry about initialization
errors. <P>
After the call to <TT>setupterm</TT>, the global variable <TT>cur_term</TT> is
set to point to the current structure of terminal capabilities. By calling
<TT>setupterm</TT> for each terminal, and saving and restoring
<TT>cur_term</TT>, it is possible for a program to use two or more terminals at
once. <TT>Setupterm</TT> also stores the names section of the terminal
description in the global character array <TT>ttytype[]</TT>. Subsequent calls
to <TT>setupterm</TT> will overwrite this array, so you'll have to save it
yourself if need be. <P>
<DD>
</DL>
<H2><A NAME="debugging">Debugging</A></H2>
<DL>
<DT> <TT>_tracef()</TT>
<DD>
NOTE: THIS FUNCTION IS NOT PART OF THE STANDARD CURSES API!
This function can be used to output your own debugging information. It is only
available only if you link with -lncurses_g. It can be used the same way as
<TT>printf</TT>, only it outputs a newline after the end of arguments.
The output goes to a file called <TT>trace</TT> in the current directory.
</DL>
<H1><A NAME="hints">Hints, Tips, and Tricks</A></H1>
The <TT>ncurses</TT> manual pages are a complete reference for this library.
In the remainder of this document, we discuss various useful methods that
may not be obvious from the manual page descriptions. <P>
<H2><A NAME="caution">Some Notes of Caution</A></H2>
Bear in mind that <TT>refresh()</TT> is a synonym for
<TT>wrefresh(stdscr)</TT>,
and don't try to mix use of <TT>stdscr</TT> with use of windows declared
by <TT>newwin</TT>; a <TT>refresh()</TT> call will blow them off the
screen. The right way to handle this is to use <TT>subwin</TT>, or
not touch <TT>stdscr</TT> at all and tile your screen with declared
windows which you then <TT>wnoutrefresh</TT> somewhere in your program
event loop, with a single <TT>doupdate</TT> call to trigger actual
repainting. <P>
You are much less likely to run into problems if you design your screen
layouts to use tiled rather than overlapping windows. Historically,
curses support for overlapping windows has been weak, fragile, and poorly
documented. The <TT>ncurses</TT> library is not yet an exception to this
rule. <P>
There is a freeware panels library included in the <TT>ncurses</TT>
distribution that does a pretty good job of strengthening the
overlapping-windows facilities. <P>
Try to avoid using the global variables LINES and COLS. Use
<TT>getmaxyx()</TT> on the <TT>stdscr</TT> context instead. Reason:
your code may be ported to run in an environment with window resizes,
in which case several screens could be open with different sizes. <P>
<H2><A NAME="leaving">Temporarily Leaving <TT>ncurses</TT> Mode</A></H2>
Sometimes you will want to write a program that spends most of its time in
screen mode, but occasionally returns to ordinary `cooked' mode. A common
reason for this is to support shell-out. This behavior is simple to arrange
in <TT>ncurses</TT>. <P>
To leave <TT>ncurses</TT> mode, call <TT>endwin()</TT> as you would if you
were intending to terminate the program. This will take the screen back to
cooked mode; you can do your shell-out. When you want to return to
<TT>ncurses</TT> mode, simply call <TT>refresh()</TT> or <TT>doupdate()</TT>.
This will repaint the screen. <P>
There is a boolean function, <TT>isendwin()</TT>, which code can use to
test whether <TT>ncurses</TT> screen mode is active. It returns <TT>TRUE</TT>
in the interval between an <TT>endwin()</TT> call and the following
<TT>refresh()</TT>, <TT>FALSE</TT> otherwise. <P>
Here is some sample code for shellout:
<PRE>
addstr("Shelling out...");
def_prog_mode(); /* save current tty modes */
endwin(); /* restore original tty modes */
system("sh"); /* run shell */
addstr("returned.\n"); /* prepare return message */
refresh(); /* restore save modes, repaint screen */
</PRE>
<H2><A NAME="xterm">Using <TT>ncurses</TT> Under <TT>xterm</TT></A></H2>
A resize operation in X sends SIGWINCH to the application running under xterm.
The <TT>ncurses</TT> library does not catch this signal, because it cannot in
general know how you want the screen re-painted. You will have to write the
SIGWINCH handler yourself. <P>
The easiest way to code your SIGWINCH handler is to have it do an
<TT>endwin</TT>, followed by an <TT>initscr</TT> and a screen repaint you code
yourself. The <TT>initscr</TT> will pick up the new screen size from the
xterm's environment.
<H2><A NAME="screens">Handling Multiple Terminal Screens</A></H2>
The <TT>initscr()</TT> function actually calls a function named
<TT>newterm()</TT> to do most of its work. If you are writing a program that
opens multiple terminals, use <TT>newterm()</TT> directly. <P>
For each call, you will have to specify a terminal type and a pair of file
pointers; each call will return a screen reference, and <TT>stdscr</TT> will be
set to the last one allocated. You will switch between screens with the
<TT>set_term</TT> call. Note that you will also have to call
<TT>def_shell_mode</TT> and <TT>def_prog_mode</TT> on each tty yourself. <P>
<H2><A NAME="testing">Testing for Terminal Capabilities</A></H2>
Sometimes you may want to write programs that test for the presence of various
capabilities before deciding whether to go into <TT>ncurses</TT> mode. An easy
way to do this is to call <TT>setupterm()</TT>, then use the functions
<TT>tigetflag()</TT>, <TT>tigetnum()</TT>, and <TT>tigetstr()</TT> to do your
testing. <P>
<H2><A NAME="tuning">Tuning for Speed</A></H2>
Use the <TT>addchstr()</TT> family of functions for fast
screen-painting of text when you know the text doesn't contain any
control characters. Try to make attribute changes infrequent on your
screens. Don't use the <TT>immedok()</TT> option! <P>
<H2><A NAME="special">Special Features of <TT>ncurses</TT></A></H2>
When running on PC-clones, <TT>ncurses</TT> has enhanced support for the
IBM high-half and ROM characters. A new highlight, <TT>A_PCCHARSET</TT>,
enables display of the PC ROM graphics 0-31 that are normally interpreted
as control characters.
<H1><A NAME="panels">The <CODE>panels</CODE> Library</A></H1>
The <TT>ncurses</TT> library by itself provides good support for screen
displays in which the windows are tiled (non-overlapping). In the more
general case that windows may overlap, you have to use a series of
<CODE>wnoutrefresh()</CODE> calls followd by a <CODE>doupdate()</CODE>, and be
careful about the order you do the window refreshes in. It has to be
bottom-upwards, otherwise parts of windows that should be obscured will
show through. <P>
When your interface design is such that windows may dive deeper into the
visibility stack or pop to the top at runtime, the resulting book-keeping
can be tedious and difficult to get right. Hence the panels library. <P>
The <CODE>panel</CODE> library first appeared in AT&amp;T System V. The
version documented here is the freeware <CODE>panel</CODE> code distributed
with <CODE>ncurses</CODE>.
<H2><A NAME="pcompile">Compiling With the panels Library</A></H2>
Your panels-using modules must import the panels library declarations with
<PRE>
#include <TT>&lg;panel.h&tg;</TT>
</PRE>
and must be linked explicitly with the panels library using an
<CODE>-lpanel</CODE> argument. Note that they must also link the
<TT>ncurses</TT> library with <CODE>-lcurses</CODE>. Most modern linkers
are two-pass and will accept either order, but it is still good practice
to put <CODE>-lpanel</CODE> first and <CODE>-lcurses</CODE> second.
<H2><A NAME="poverview">Overview of panels</A></H2>
A panel object is a window that is implicitly treated as part of a
<DFN>deck</DFN> including all other panel objects. The deck has an implicit
bottom-to-top visibility order. The panels library includes an update
function (analogous to <CODE>refresh()</CODE>) that displays all panels in the
deck in the proper order to resolve overlaps. The standard window,
<CODE>stdscr</CODE>, is considered below all panels. <P>
Details on the panels functions are available in the man pages. We'll just
hit the highlights here. <P>
You create a panel from a window by calling <CODE>new_panel()</CODE> on a
window pointer. It then becomes the top of the deck. The panel's window
is available as the value of <CODE>pnel_windo()</CODE> called with the
panel pointer as argument.<P>
You can delete a panel (removing it from the deck) with <CODE>del_panel</CODE>.
This will not deallocate the associated window; you have to do that yourself.
You can replace a panel's window with a different window by calling
<CODE>replace_window</CODE>. The new window may be of different size;
the panel code will re-compute all overlaps. This operation doesn't
change the panel's position in the deck. <P>
To move a panel's window, use <CODE>move_panel()</CODE>. The
<CODE>mvwin()</CODE> function on the panel's window isn't sufficient because it
doesn't update the panels library's representation of where the windows are.
This operation leaves the panel's depth, contents, and size unchanged. <P>
Two functions (<CODE>top_panel()</CODE>, <CODE>bottom_panel()</CODE>) are
provided for rearranging the deck. The first pops its argument window to the
top of the deck; the second sends it to the bottom. Either operation leaves
the panel's screen location, contents, and size unchanged. <P>
The function <CODE>update_panels()</CODE> does all the
<CODE>wnoutrefresh()</CODE> calls needed to prepare for
<CODE>doupdate()</CODE> (which you must call yourself, afterwards). <P>
<H2><A HREF="pstsdcr">Panels, Input, and the Standard Screen</A></H2>
You shouldn't mix <CODE>wnoutrefresh()</CODE> or <CODE>wrefresh()</CODE>
operations with panels code; this will work only if the argument window
is either in the top panel or un-obscured by any other panels. <P>
The <CODE>stsdcr</CODE> window is a special case. It is considered below all
panels. Because changes to panels may obscure parts of <CODE>stdscr</CODE>,
though, you should call <CODE>update_panels()</CODE> before
<CODE>doupdate()</CODE> even when you only change <CODE>stdscr</CODE>. <P>
Note that <CODE>wgetch</CODE> automatically calls <CODE>wrefresh</CODE>.
Therefore, before requesting input from a panel window, you need to be sure
that the panel is totally unobscured. <P>
There is presently no way to display changes to one obscured panel without
repainting all panels. <P>
<H2><A NAME="hiding">Hiding Panels</A></H2>
It's possible to remove a panel from the deck temporarily; use
<CODE>hide_panel</CODE> for this. You can un-hide a panel with
<CODE>show_panel()</CODE>. The predicate function <CODE>panel_hidden</CODE>
tests whether or not a panel is hidden. <P>
The <CODE>panel_update</CODE> code ignores hidden panels. You cannot do
<CODE>top_panel()</CODE> or <CODE>bottom_panel</CODE> on a hiddlen panel().
Other panels operations are applicable. <P>
<H2><A NAME="pmisc">Miscellaneous Other Facilities</A></H2>
It's possible to navigate the deck using the functions
<CODE>panel_above()</CODE> and <CODE>panel_below</CODE>. Handed a panel
pointer, they return the panel above or below that panel. Handed
<CODE>NULL</CODE>, they return the bottom-most or top-most panel. <P>
Every panel has an associated user pointer, not used by the panel code, to
whicch you can attach application data. See the man page documentation
of <CODE>set_panel_userptr()</CODE> and <CODE>panel_userptr</CODE> for
details. <P>
<H1><A HREF="menus">The Menu Library</A></H1>
A menu is a screen display that assists the user to choose some subset
of a given set of items. The <CODE>menu</CODE> library is a curses
extension that supports easy programming of menu hierarchies with a
uniform but flexible interface.
The <CODE>menu</CODE> library first appeared in AT&amp;T System V. The
version documented here is the freeware <CODE>menu</CODE> code distributed
with <CODE>ncurses</CODE>.
<H2><A NAME="mcompile">Compiling With the menu Library</A></H2>
Your menu-using modules must import the menu library declarations with
<PRE>
#include <TT>&lg;menu.h&tg;</TT>
</PRE>
and must be linked explicitly with the menus library using an
<CODE>-lmenu</CODE> argument. Note that they must also link the
<TT>ncurses</TT> library with <CODE>-lcurses</CODE>. Most modern linkers
are two-pass and will accept either order, but it is still good practice
to put <CODE>-lmenu</CODE> first and <CODE>-lcurses</CODE> second.
<H2><A NAME="moverview">Overview of Menus</A></H2>
The menus created by this library consist of collections of
<DFN>items</DFN> including a name string part and a description string
part. To make menus, you create groups of these items and connect
them with menu frame objects. <P>
The menu can then by <DFN>posted</DFN>, that is written to an
associated window. Actually, each menu has two associated windows; a
containing window in which the programmer can scribble titles or
borders, and a subwindow in which the menu items proper are displayed.
If this subwindow is too small to display all the items, it will be a
scrollable viewport on the collection of items. <P>
A menu may also be <DFN>unposted</DFN> (that is, undisplayed), and finally
freed to make the storage associated with it and its items available for
re-use. <P>
The general flow of control of a menu program looks like this:
<OL>
<LI> Initialize <CODE>curses</CODE>.
<LI> Create the menu items, using <CODE>new_item()</CODE>.
<LI> Create the menu using <CODE>new_menu()</CODE>.
<LI> Post the menu using <CODE>menu_post()</CODE>.
<LI> Refresh the screen.
<LI> Process user requests via an input loop.
<LI> Unpost the menu using <CODE>menu_unpost()</CODE>.
<LI> Free the menu, using <CODE>free_menu()</CODE>.
<LI> Free the items using <CODE>free_item()</CODE>.
<LI> Terminate <CODE>curses</CODE>.
</OL>
<H2><A NAME="select">Selecting items</A></H2>
Menus may be multi-valued or (the default) single-valued (see the manual
page <CODE>mitem_opts(3x)</CODE> to see how to change the default).
Both types always have a <DFN>current item</DFN>. <P>
From a single-valued menu you can read the selected value simply by looking
at the current item. From a multi-valued menu, you get the selected set
by looping through the items applying the <CODE>item_value()</CODE>
predicate function. Your menu-processing code can use the function
<CODE>set_item_value()</CODE> to flag the items in the select set. <P>
Menu items can be made un-selectable using <CODE>set_item_opts()</CODE>
or <CODE>item_opts_off()</CODE> with the <CODE>O_SELECTABLE</CODE>
argument. This is the only option so far defined for menus, but it
is good practice to code as though other option bits might be on. <P>
<H2><A NAME="mdisplay">Menu Display</A></H2>
The menu library calculates a minimum display size for your window, based
on the following variables: <P>
<UL>
<LI> The number and maximum length of the menu items
<LI> Whether the O_ROWMAJOR option is enabled
<LI> Whether display of descriptions is enabled
<LI> Whatever menu format may have been set by the programmer
<LI> The length of the menu mark string used for highlighting selected items
</UL>
The function <CODE>set_menu_format()</CODE> allows you to set the
maximum size of the viewport or <DFN>menu page</DFN> that will be used
to display menu items. You can retrieve any format associated with a
menu with <CODE>menu_format()</CODE>. The default format is rows=16,
columns=1. <P>
The actual menu page may be smaller than the format size. This depends
on the item number and size and whether O_ROWMAJOR is on. This option
(on by default) causes menu items to be displayed in a `raster-scan'
pattern, so that if more than one item will fit horizontally the first
couple of items are side-by-side in the top row. The alternative is
column-major display, which tries to put the first several items in
the first column. <P>
As mentioned above, a menu format not large enough to allow all items to fit
on-screen will result in a menu display that is vertically scrollable. <P>
You can scroll it with requests to the menu driver, which will be described
in the section on <A HREF="#minput">menu input handling</A>. <P>
Each menu has a <DFN>mark string</DFN> used to visually tag selected items;
see the <CODE>menu_mark(3x)</CODE> manual page for details. The mark
string length also influences the menu page size. <P>
The function <CODE>scale_menu()</CODE> returns the minimum display size
that the menu code computes from all these factors.
There are other menu display attributes including a select attribute,
an attribute for selectable items, an attribute for unselectable items,
and a pad character used to separate item name text from description
text. These have reasonable defaults which the library allows you to
change (see the <CODE>menu_attribs(3x)</CODE>manual page. <P>
<H2><A NAME="mwindows">Menu Windows</A></H2>
Each menu has, as mentioned previously, a pair of associated windows.
Both these windows are painted when the menu is posted and erased when
the menu is unposted. <P>
The outer or frame window is not otherwise touched by the menu routines.
It exists so the programmer can associate a title, a border, or
perhaps help text with the menu and have it properly refreshed or erased
at post/unpost time. <P>
The inner window or <DFN>subwindow</DFN> is where the current menu page is
displayed. <P>
By default, both windows are <CODE>stdscr</CODE>. You can set them with the
functions in <CODE>menu_win(3x)</CODE>. <P>
When you call <CODE>menu_post()</CODE>, you write the menu to its
subwindow. When you call <CODE>menu_unpost()</CODE>, you erase the
subwindow, However, neither of these actually modifies the screen. To
do that, call <CODE>wrefresh()</CODE> or some equivalent. <P>
<H2><A NAME="minput">Processing Menu Input</A></H2>
The main loop of your menu-processing code should call
<CODE>menu_driver()</CODE> repeatedly. The first argument of this routine
is a menu pointer; the second is a menu command code. You should write an
input-fetching routine that maps input characters to menu command codes, and
pass its output to <CODE>menu_driver()</CODE>. The menu command codes are
fully documented in <CODE>menu_driver(3x)</CODE>. <P>
The simplest group of command codes is <CODE>REQ_NEXT_ITEM</CODE>,
<CODE>REQ_PREV_ITEM</CODE>, <CODE>REQ_FIRST_ITEM</CODE>,
<CODE>REQ_LAST_ITEM</CODE>, <CODE>REQ_UP_ITEM</CODE>,
<CODE>REQ_DOWN_ITEM</CODE>, <CODE>REQ_LEFT_ITEM</CODE>,
<CODE>REQ_RIGHT_ITEM</CODE>. These change the currently selected
item. These requests may cause scrolling of the menu page if it only
partially displayed. <P>
There are explicit requests for scrolling which also change the
current item (because the select location does not change, but the
item there does). These are <CODE>REQ_SCR_DLINE</CODE>,
<CODE>REQ_SCR_ULINE</CODE>, <CODE>REQ_SCR_DPAGE</CODE>, and
<CODE>REQ_SCR_UPAGE</CODE>. <P>
The <CODE>REQ_TOGGLE_ITEM</CODE> selects or deselects the current item.
It is for use in multi-valued menus; if you use it with <CODE>O_ONEVALUE</CODE>
on, you'll get an error return (<CODE>E_REQUEST_DENIED</CODE>). <P>
Each menu has an associated pattern buffer. The
<CODE>menu_driver()</CODE> logic tries to accumulate printable ASCII
characters passed in in that buffer; when it matches a prefix of an
item name, that item (or the next matching item) is selected. If
apopending a character yields no new match, that character is deleted
from the pattern buffer, and <CODE>menu_driver()</CODE> returns
<CODE>E_NO_MATCH</CODE>. <P>
Some requests change the pattern buffer directly:
<CODE>REQ_CLEAR_PATTERN</CODE>, <CODE>REQ_BACK_PATTERN</CODE>,
<CODE>REQ_NEXT_MATCH</CODE>, <CODE>REQ_PREV_MATCH</CODE>. The latter
two are useful when pattern buffer input matches more than one item
in a multi-valued menu. <P>
Each successful scroll or item navigation request clears the pattern
buffer. It is also possible to set the pattern buffer explicitly
with <CODE>set_menu_pattern()</CODE>. <P>
Finally, menu driver requests above the constant <CODE>MAX_COMMAND</CODE>
are considered application-specific commands. The <CODE>menu_driver()</CODE>
code ignores them and returns <CODE>E_UNKNOWN_COMMAND</CODE>.
<H2><A NAME="mmisc">Miscellaneous Other Features</A></H2>
Various menu options can affect the processing and visual appearance
and input processing of menus. See <CODE>menu_opts(3x) for
details.</CODE> <P>
It is possible to change the current item from application code; this
is useful if you want to write your own navigation requests. It is
also possible to explicitly set the top row of the menu display. See
<CODE>mitem_current(3x)</CODE>.
If your application needs to change the menu subwindow cursor for
any reason, <CODE>pos_menu_cursor()</CODE> will restore it to the
correct location for continuing menu driver processing. <P>
It is possible to set hooks to be called at menu initialization and
wrapup time, and whenever the selected item changes. See
<CODE>menu_hook(3x)</CODE>. <P>
Each item, and each menu, has an associated user pointer on which you
can hang application data. See <CODE>mitem_userptr(3x)</CODE> and
<CODE>menu_userptr(3x)</CODE>. <P>
<HR>
<ADDRESS>Eric S. Raymond &lt;esr@snark.thyrsus.com&gt;</ADDRESS> </BODY>
</HTML>