Modula-2 || Compiler & Tools || Library || Search Engine


Ulm's Modula-2 Library:
Windows


NAME

Windows - screen handling routines

SYNOPSIS

TYPE TermType = ARRAY[0..31] OF CHAR;
TYPE Device;
TYPE Terminfo;
TYPE Window;
TYPE WindowAttributes = (flushalways, flushoninput,
                         nodelay, echo, scroll, movecursor,
                         funckeys, timeout, mapkeys, readcr);
TYPE WindowAtSet = SET OF WindowAttributes;
TYPE WindowStatbuf =
        RECORD
           dev: Device;
           in, out: FILE;
           fkinfo: FKInfo;
           atinfo: AttrInfo;
           scr: Screen;
           terminfo: TermPtr;
        END;


VAR Done: BOOLEAN;

PROCEDURE OpenTerminfo(VAR tinfo: Terminfo; termtype: TermType);

(* operations on devices *) PROCEDURE OpenDevice(VAR dev: Device; devin, devout: FILE; tinfo: Terminfo); PROCEDURE OpenDeviceFile(VAR dev: Device; devname: ARRAY OF CHAR; tinfo: Terminfo); PROCEDURE Redraw(dev: Device); PROCEDURE DeviceChar(dev: Device; line, column: CARDINAL) : CHAR; PROCEDURE CloseDevice(VAR dev: Device); PROCEDURE SuspendDevice(dev: Device); PROCEDURE RestoreDevice(dev: Device);

(* operations on windows *) PROCEDURE CreateWindow(VAR win: Window; dev: Device); PROCEDURE CloseWindow(VAR win: Window); PROCEDURE GetWindowAttributes(win: Window; VAR atset: WindowAtSet); PROCEDURE SetWindowAttributes(win: Window; atset: WindowAtSet); PROCEDURE NewWindow(VAR win: Window; newwinof: Window; sx, sy, lns, cols: CARDINAL); PROCEDURE SubWindow(VAR win: Window; subwinof: Window; sx, sy, lns, cols: CARDINAL); PROCEDURE GetWindowSize(win: Window; VAR lines, columns: CARDINAL); PROCEDURE GetWindowStart(win: Window; VAR line, column: CARDINAL); PROCEDURE GetSupWin(win: Window; VAR supwin: Window); PROCEDURE IsSubWin(win: Window): BOOLEAN; PROCEDURE WindowStat(win: Window; VAR statbuf: WindowStatbuf); PROCEDURE SetWindowPos(win: Window; line, column: CARDINAL); PROCEDURE GetWindowPos(win: Window; VAR line, column: CARDINAL);

(* input/output on windows *) PROCEDURE WindowWrite(win: Window; ch: CHAR); PROCEDURE SetWindowDisplayMode(win: Window; atset: AttributeSet); PROCEDURE WindowRead(win: Window; VAR ch: CHAR); PROCEDURE IsFunctionKey(ch: CHAR) : BOOLEAN; PROCEDURE ToFunctionKey(ch: CHAR) : FunctionKey; PROCEDURE WindowChar(win: Window; line, column: CARDINAL) : CHAR; PROCEDURE WindowUnget(win: Window; ch: CHAR); PROCEDURE WindowClear(win: Window); PROCEDURE ScrollWindow(win: Window; count: INTEGER); PROCEDURE FlushWindow(win: Window);

(* coroutine-manager *) PROCEDURE StartWinProcess(win: Window; process: PROC); PROCEDURE TerminateWinProcess(win: Window); PROCEDURE RunProcesses; PROCEDURE Terminate;

DESCRIPTION

The basic objects of this module are windows. Each window is associated with a screen part on a terminal device. Each terminal device has a terminal type (e.g. "vt100"). Windows accesses the terminal capability database terminfo(4) and works for each terminal type described there.

Descriptions of terminal capabilities are referenced by Terminfo and can be opened using OpenTerminfo. If an empty string is given to termtype the environment variable TERM is taken instead.

In the beginning at least one device should be opened using OpenDevice or OpenDeviceFile. The given filepointers (typically StdIO.stdin and StdIO.stdout) must be associated with a terminal device. devout should be buffered. tinfo references the terminal type. Resulting parameter is dev which references the terminal device on further operations. CloseDevice restores the terminal settings (ioctl(2)), closes the associated filepointers, and deallocates the space used for dev. Redraw restores the screen contents. This is necessary if external effects have modified the terminal screen. DeviceChar returns the character at position line/column on device dev. The access of Windows to a device can be suspended by calling SuspendDevice (e.g. for shell escapes). This includes terminal resetting (ioctl(2)) and cursor positioning to the last line. RestoreDevice ends the suspension and redraws the screen.

Each window (except subwindows) has its own screen contents and cursor position which can differ from the actual contents on the terminal device. So write operations and cursor movements affect by default the window contents only. To update the screen part of a window on the terminal device FlushWindow is needed. Because windows may overlap it is possible to hide parts of a window by flushing another window. Some attributes belong to a window which can be read and set using GetWindowAttributes and SetWindowAttributes. They have following meaning:
flushalways causes every write operation to be followed by FlushWindow.
flushoninput requests WindowRead to call FlushWindow before reading.
nodelay causes WindowRead to return with Done set to FALSE if no input is available.
echo causes WindowRead to echo the input being read.
scroll enables scrolling on writing of ASCII.nl in the last line or after writing in the last column of the last line (automatic margin).
movecursor requests FlushWindow to position the cursor on the terminal device accordingly to the window cursor. If supported by the terminal the cursor is visible only if movecursor is set.
funckeys enables function keys on reading. Because this is local to a window typeahead of function keys should be avoided.
timeout is to be set in conjunction with funckeys and causes WindowRead not to hang on unfinished function key codes.
mapkeys requests even single character function key codes to be mapped (e.g. the ASCII bs character is mapped to backspace).
readcr requests WindowRead not to map ASCII.cr to ASCII.nl.

The first window of a device dev is to be created using CreateWindow. The number of lines and columns result from the associated terminal type and can be retrieved using GetWindowSize.

Further windows can be created using SubWindow and NewWindow. They are positioned relative (with offsets sx (line offset) and sy) to subwinof or newwinof, respectively, and have a size (lns and cols) which must fit into subwinof or newwinof, respectively. The window attributes of subwinof or newwinof, respectively, are inherited to win. Subwindows have no screen contents of their own but serve as mapping rule and update unit. Like other windows they have their own cursor and their own attributes. The flushoninput attribute has a special meaning for subwindows and causes subwinof to be updated on reading, too. Windows created by NewWin behave like windows created by CreateWindow, i.e. if more than one screen fitting window is needed, CreateWindow can be called again.

Some procedures retrieve informations about windows. GetWindowSize returns the number of lines and columns. GetWindowStart returns the relative offset to the terminal screen in case of windows created by NewWindow or CreateWindow or the relative offset to subwinof in case of subwindows. GetSupWin returns the super-window, i.e. subwinof of subwindows. IsSubWin allows to distinguish between subwindows and other windows. WindowStat returns a record containing further informations associated with win. The components of the record are system dependant, e.g. terminfo is possibly a termcap reference on Berkeley systems.

Cursor positioning is possible using SetWindowPos. Line and column numbers start from 0. GetWindowPos returns the current cursor position.

WindowWrite writes ch at the current cursor position of the window. Besides visible characters only few characters are permitted. Back spaces, newlines, and carriage returns are translated into cursor movements, i.e. back spaces don't erase the window. Visible characters cause the cursor to be moved (with an automatic margin at the end of each window line). If scroll is not set, no scrolling takes place after having reached the end of the last line of the window and nothing can be written without moving the cursor first. WindowClear fills win with blanks. ScrollWindow scrolls win upward (count > 0) or downward (count < 0) ABS(count) lines.

SetWindowDisplayMode sets the set of display modes for win. The type AttributeSet is to be imported from Attributes. The display mode is effective for the given window until SetWindowDisplayMode is called again. Unlike window attributes, display modes are not inherited to subwindows. Combinations of several display modes (cardinality of atset > 1) do not work well for every terminal. Terminals needing extra characters to store the display modes are not supported. Note that WindowClear does not affect the display modes; e.g. reverse display mode followed by WindowClear causes the complete window to be set into reverse video.

WindowRead reads one character into ch from the terminal associated with win. If flushoninput is set FlushWindow is called for win, or if win is a subwindow for the window ordered above. If the cursor on the terminal is to be left at the window cursor position (and is to be made more visible if possible) movecursor should be set together with flushoninput. On nodelay, WindowRead returns immediately if no input is available. Characters being read are written to the current cursor position if echo is set. If function keys are enabled IsFunctionKey can be used to distinguish between normal characters and function keys. ToFunctionKey converts a character returned by WindowRead to a function key (type FunctionKey is imported from module FunctionKeys). ToFunctionKey returns nokey if ch is not a function key. Function keys are not echoed and cannot be given as argument to WindowWrite. WindowUnget causes WindowRead to return ch on next call for this window.

WindowChar returns the character at the given window position.

FlushWindow updates win on the associated terminal device in an optimized way. If movecursor is set for win the (visible) cursor on the terminal is left at the corresponding window cursor position. Else the cursor is invisible (if possible).

The coroutine-manager allows to serve more than one terminal concurrently. StartWinProcess connects a coroutine procedure proc to win. Coroutine procedures must not share a window nor a terminal device. After having set up all coroutine procedures with StartWinProcess RunProcesses transfers to the first of them. The only way that a coroutine gets suspended is to call WindowRead with nodelay set. WindowRead then transfers to the next coroutine if no input is available. A coroutine must not return but has to call Terminate for final suspension. TerminateWinProcess allows to kill other coroutines. If all coroutines are terminated RunProcesses returns. The stack for each coroutine is limited (currently 32768 bytes), so big arrays should be allocated using Storage and not as local variables.

SEE ALSO

Attributes set of available attributes and some associated low-level operations
FtdWin formatted i/o to and from windows
FunctionKeys set of available function keys and some associated low-level operations
MainWin a less sophisticated interface which offers one main window
Menus menus on base of Windows
Screen low-level screen operations which are used by Windows
TermInfo low-level interface to the terminfo database
W formatted i/o in Printf style to and from windows

BUGS

Windows is very slow if devout is unbuffered. So OpenDeviceFile should be used instead of OpenDevice.

No character will be written at the last column of the last line of a device. This is necessary because some terminals scroll in this case one line forward.


Edited by: borchert, last change: 2003/12/10, revision: 1.4, converted to HTML: 2003/12/10

Modula-2 || Compiler & Tools || Library || Search Engine