by Zeyd M. ben-Halim and Eric S. Raymond
(version 1.9, 1 May 1995)
panels
Library
The curses 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. Curses uses terminfo, which is a database format that can describe the capabilities of thousands of different terminals.
Historically, the first ancestor of curses was the routines written to provide screen-handling for the game rogue; these used the already- existing termcap database facility for describing terminal capabilities. These routines were abstracted into a documented library and first released with the early BSD UNIX versions.
System III UNIX from Bell Labs featured a rewritten and much-improved curses 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&T System V releases, curses evolved to use more facilities and offer more capabilities, going far beyond BSD curses in power and flexibility.
This document describes ncurses, a freeware implementation of the System V curses API. It includes the following System V curses features:
The ncurses package was originated by Pavel Curtis. The primary maintainer of the package is Zeyd ben-Halim <zmbenhal@netcom.com>. Eric S. Raymond <esr@snark.thyrsus.com> wrote many of the new features in versions after 1.8.1 and coauthored this introduction.
This document also describes the 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).
Finally, this document describes the menu extension library, also cloned from System V, which provides easy construction and sequences of menus.
#include <curses.h>at the top of the program source. The screen package uses the Standard I/O library, so <curses.h> includes <stdio.h>. <curses.h> also includes <termios.h>, <termio.h>, or <sgtty.h> depending on your system. It is redundant (but harmless) for the programmer to do these includes, too. In linking with curses you need to have -lncurses in your LDFLAGS or on the command line. There is no need for any other libraries.
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.
To make the section of physical screen corresponding to a window reflect the contents of the window structure, the routine refresh() (or wrefresh() if the window is not stdscr) is called.
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.
Many functions are defined to use stdscr as a default screen. For example, to add a character to stdscr, one calls addch() with the desired character as argument. To write to a different window. use the routine waddch() (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.
In order to move the current (y, x) coordinates from one point to another, the routines move() and wmove() 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
move(y, x); addch(ch);can be replaced by
mvaddch(y, x, ch);and
wmove(win, y, x); waddch(win, ch);can be replaced by
mvwaddch(win, y, x, ch);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.
type name description ------------------------------------------------------------------ int LINES number of lines on the terminal int COLS number of columns on the terminalThe curses.h also introduces some #define constants and types of general usefulness:
Here is a sample program to motivate the discussion:
#include#include 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); }
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 scrollok(). If you want the cursor to be left in place after the last change, use leaveok(). If this isn't done, refresh() will move the cursor to the window's current (y, x) coordinates after updating it.
You can create new windows of your own using the functions newwin(), derwin(), and subwin(). The routine delwin() will allow you to get rid of old windows. All the options described above can be applied to any window.
The other output functions, such as addstr() and printw(), all call addch() to add characters to the window.
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 refresh(). In order to optimize finding changes, refresh() assumes that any part of the window not changed since the last refresh() 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 touchwin() is provided to make it look like the entire window has been changed, thus making refresh() check the whole subsection of the terminal for changes.
If you call wrefresh() with curscr as its argument, it will make the screen look like curscr thinks it looks like. This is useful for implementing a command which would redraw the screen in case it get messed up.
When you need to accept line-oriented input in a window, the functions wgetstr and friends are available. There is even a wscanw function that can do scanf(3)-style multi-field parsing on window input. These pseudo-line-oriented functions turn on echoing while they execute.
The example code above uses the call keypad(stdscr, TRUE) to enable support for function-key mapping. With this feature, the getch() code watches the input stream for character sequences that correspond to arrow and function keys. These sequences are returned as pseudo-character values. The #define values returned are listed in the ncurses.h The mapping from sequences to #define values is determined by key_ capabilities in the terminal's terminfo entry.
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, ncurses.h will map them to a recognizable (though ugly) set of ASCII defaults.
Highlights are encoded, internally, as high bits of the pseudo-character type (chtype) that ncurses.h uses to represent the contents of a screen cell. See the ncurses.h header file for a complete list of highlight mask values (look for the prefix A_).
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 addch call, or any other output call that takes a chtype argument.
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 attron, attroff, and attrset; 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 init_pair values.
Once you've done an init_pair that creates color-pair N, you can use COLOR_PAIR(N) as a highlight that invokes that particular color combination. Note that COLOR_PAIR(N), for constant N, is itself a compile-time constant and can be used in initializers.
The value of term can be given as NULL, which will cause the value of TERM in the environment to be used. The errret pointer can also be given as NULL, meaning no error code is wanted. If errret is defaulted, and something goes wrong, setupterm 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.
After the call to setupterm, the global variable cur_term is set to point to the current structure of terminal capabilities. By calling setupterm for each terminal, and saving and restoring cur_term, it is possible for a program to use two or more terminals at once. Setupterm also stores the names section of the terminal description in the global character array ttytype[]. Subsequent calls to setupterm will overwrite this array, so you'll have to save it yourself if need be.
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 ncurses library is not yet an exception to this rule.
There is a freeware panels library included in the ncurses distribution that does a pretty good job of strengthening the overlapping-windows facilities.
Try to avoid using the global variables LINES and COLS. Use getmaxyx() on the stdscr 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.
To leave ncurses mode, call endwin() 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 ncurses mode, simply call refresh() or doupdate(). This will repaint the screen.
There is a boolean function, isendwin(), which code can use to test whether ncurses screen mode is active. It returns TRUE in the interval between an endwin() call and the following refresh(), FALSE otherwise.
Here is some sample code for shellout:
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 */
The easiest way to code your SIGWINCH handler is to have it do an endwin, followed by an initscr and a screen repaint you code yourself. The initscr will pick up the new screen size from the xterm's environment.
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 stdscr will be set to the last one allocated. You will switch between screens with the set_term call. Note that you will also have to call def_shell_mode and def_prog_mode on each tty yourself.
panels
Librarywnoutrefresh()
calls followd by a doupdate()
, 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. 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.
The panel
library first appeared in AT&T System V. The
version documented here is the freeware panel
code distributed
with ncurses
.
#include ≶panel.h&tg;and must be linked explicitly with the panels library using an
-lpanel
argument. Note that they must also link the
ncurses library with -lcurses
. Most modern linkers
are two-pass and will accept either order, but it is still good practice
to put -lpanel
first and -lcurses
second.
refresh()
) that displays all panels in the
deck in the proper order to resolve overlaps. The standard window,
stdscr
, is considered below all panels. Details on the panels functions are available in the man pages. We'll just hit the highlights here.
You create a panel from a window by calling new_panel()
on a
window pointer. It then becomes the top of the deck. The panel's window
is available as the value of pnel_windo()
called with the
panel pointer as argument.
You can delete a panel (removing it from the deck) with del_panel
.
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
replace_window
. 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.
To move a panel's window, use move_panel()
. The
mvwin()
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.
Two functions (top_panel()
, bottom_panel()
) 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.
The function update_panels()
does all the
wnoutrefresh()
calls needed to prepare for
doupdate()
(which you must call yourself, afterwards).
wnoutrefresh()
or wrefresh()
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.
The stsdcr
window is a special case. It is considered below all
panels. Because changes to panels may obscure parts of stdscr
,
though, you should call update_panels()
before
doupdate()
even when you only change stdscr
.
Note that wgetch
automatically calls wrefresh
.
Therefore, before requesting input from a panel window, you need to be sure
that the panel is totally unobscured.
There is presently no way to display changes to one obscured panel without repainting all panels.
hide_panel
for this. You can un-hide a panel with
show_panel()
. The predicate function panel_hidden
tests whether or not a panel is hidden.
The panel_update
code ignores hidden panels. You cannot do
top_panel()
or bottom_panel
on a hiddlen panel().
Other panels operations are applicable.
panel_above()
and panel_below
. Handed a panel
pointer, they return the panel above or below that panel. Handed
NULL
, they return the bottom-most or top-most panel.
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 set_panel_userptr()
and panel_userptr
for
details.
menu
library is a curses
extension that supports easy programming of menu hierarchies with a
uniform but flexible interface.
The menu
library first appeared in AT&T System V. The
version documented here is the freeware menu
code distributed
with ncurses
.
#include ≶menu.h&tg;and must be linked explicitly with the menus library using an
-lmenu
argument. Note that they must also link the
ncurses library with -lcurses
. Most modern linkers
are two-pass and will accept either order, but it is still good practice
to put -lmenu
first and -lcurses
second.
The menu can then by posted, 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.
A menu may also be unposted (that is, undisplayed), and finally freed to make the storage associated with it and its items available for re-use.
The general flow of control of a menu program looks like this:
curses
.
new_item()
.
new_menu()
.
menu_post()
.
menu_unpost()
.
free_menu()
.
free_item()
.
curses
.
mitem_opts(3x)
to see how to change the default).
Both types always have a current item.
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 item_value()
predicate function. Your menu-processing code can use the function
set_item_value()
to flag the items in the select set.
Menu items can be made un-selectable using set_item_opts()
or item_opts_off()
with the O_SELECTABLE
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.
set_menu_format()
allows you to set the
maximum size of the viewport or menu page that will be used
to display menu items. You can retrieve any format associated with a
menu with menu_format()
. The default format is rows=16,
columns=1. 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.
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.
You can scroll it with requests to the menu driver, which will be described in the section on menu input handling.
Each menu has a mark string used to visually tag selected items;
see the menu_mark(3x)
manual page for details. The mark
string length also influences the menu page size.
The function scale_menu()
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 menu_attribs(3x)
manual page.
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.
The inner window or subwindow is where the current menu page is displayed.
By default, both windows are stdscr
. You can set them with the
functions in menu_win(3x)
.
When you call menu_post()
, you write the menu to its
subwindow. When you call menu_unpost()
, you erase the
subwindow, However, neither of these actually modifies the screen. To
do that, call wrefresh()
or some equivalent.
menu_driver()
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 menu_driver()
. The menu command codes are
fully documented in menu_driver(3x)
.
The simplest group of command codes is REQ_NEXT_ITEM
,
REQ_PREV_ITEM
, REQ_FIRST_ITEM
,
REQ_LAST_ITEM
, REQ_UP_ITEM
,
REQ_DOWN_ITEM
, REQ_LEFT_ITEM
,
REQ_RIGHT_ITEM
. These change the currently selected
item. These requests may cause scrolling of the menu page if it only
partially displayed.
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 REQ_SCR_DLINE
,
REQ_SCR_ULINE
, REQ_SCR_DPAGE
, and
REQ_SCR_UPAGE
.
The REQ_TOGGLE_ITEM
selects or deselects the current item.
It is for use in multi-valued menus; if you use it with O_ONEVALUE
on, you'll get an error return (E_REQUEST_DENIED
).
Each menu has an associated pattern buffer. The
menu_driver()
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 menu_driver()
returns
E_NO_MATCH
.
Some requests change the pattern buffer directly:
REQ_CLEAR_PATTERN
, REQ_BACK_PATTERN
,
REQ_NEXT_MATCH
, REQ_PREV_MATCH
. The latter
two are useful when pattern buffer input matches more than one item
in a multi-valued menu.
Each successful scroll or item navigation request clears the pattern
buffer. It is also possible to set the pattern buffer explicitly
with set_menu_pattern()
.
Finally, menu driver requests above the constant MAX_COMMAND
are considered application-specific commands. The menu_driver()
code ignores them and returns E_UNKNOWN_COMMAND
.
menu_opts(3x) for
details.
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
mitem_current(3x)
.
If your application needs to change the menu subwindow cursor for
any reason, pos_menu_cursor()
will restore it to the
correct location for continuing menu driver processing.
It is possible to set hooks to be called at menu initialization and
wrapup time, and whenever the selected item changes. See
menu_hook(3x)
.
Each item, and each menu, has an associated user pointer on which you
can hang application data. See mitem_userptr(3x)
and
menu_userptr(3x)
.