Curses

Die C-Bibliothek Curses beziehungsweise ihre neuere Version NCurses bietet die Möglichkeit, textbasierte Benutzeroberflächen zu erzeugen. Curses wird daher in vielen Shell-Programmen verwendet, darunter aptitude, cmus, mc, usw.

Curses starten und beenden

Um Curses zu starten, muss zunächst die Funktion initscr() aufgerufen werden. Diese Funktion erzeugt einen leeres Fenster und weist ihm den Namen stdscr (“standard screen”) zu. Damit das neue Fenster angezeigt wird, muss anschließend die Funktion refresh() aufgerufen werden, so dass das Shell-Fenster aktualisiert wird und die Änderungen sichtbar werden.

Mit der refresh()-Anweisung werden in Curses zwei Teilfunktionen aufgerufen: Zunächst werden mittels der ersten Funktion wnoutrefresh() nur die veränderten Teile eines Curses-Fensters in einem “virtuellen” Fenster aktualisiert. Anschließend wird dieses mittels der zweiten Funktion douptate() auf den Bildschirm übertragen. Somit wird immer nur der Teil des Fensters aktualisiert, der tatsächlich verändert wurde; dies ist wesentlich effizienter, als wenn ständig das gesamte Shell-Fenster aktualisiert werden müsste.

Um ein Curses-Programm wieder zu beenden, verwendet man die Funktion endwin(). Diese löscht den Bildschirm und stellt automatisch die vorgefundenen Shell-Einstellungen wieder her. Da endwin() insgesamt zahlreiche Aufräumarbeiten übernimmt, sollte Curses stets mit dieser Funktion beendet werden.

Ein minimales Curses-Programm, das nur kurz einen leeren Bildschirm erzeugt, auf diesem “Hallo Welt” ausgibt und sich nach kurzer Zeit selbst beendet, kann folgendermaßen aussehen:

// Datei: curses-beispiel-1.c

#include <ncurses.h>

int main(void)
{
    initscr();
    printw("Hallo Welt!");
    refresh();
    napms(3000);
    endwin();
    return 0;
}

In diesem Beispiel wurde zudem die Curses-Funktion napms() verwendet, die eine weitere Ausführung des Programms um die angegebene Anzahl in Millisekunden verzögert.

Ausgeben und Einlesen von Text

Zur Ausgabe von Text gibt es in Curses im Wesentlichen drei Funktionen:

  • Mittels addch(c) kann ein einzelnes Zeichen auf dem Bildschirm ausgegeben werden.
  • Mittels addstr(*str) kann eine ganze Zeichenkette auf dem Bildschirm ausgegeben werden. (Dabei wird intern die Funktion addch() aufgerufen, bis die Zeichenkette abgearbeitet ist.)
  • Mittels printw() kann Text in der gleichen Weise in einem Curses-Fenster ausgegeben werden, wie dies mittels der Funktion printf() auf dem Standard-Ausgang der Fall ist.

Damit der Text an der richtigen Stelle im Curses-Fenster erscheint, kann man mittels der Funktion move() den Cursor an eine bestimmte Stelle bewegen. Als erstes Argument wird dabei die Zeilennummer y, als zweites die Spaltennummer x angegeben, also move(y,x).[1] Da Curses, wie in C üblich, bei der Nummerierung mit Null beginnt, entspricht move(0,0) einem Bewegen des Cursors in die obere linke Ecke; die erlauben Maximalwerte für die Zeilen- und Spaltennummer in move() sind entsprechend um 1 kleiner als die Zeilen- und Spaltenanzahl des Fensters. Diese beiden Werte können mittels der Funktion getmaxyx(stdscr, maxrow, maxcol) bestimmt werden, wobei maxrow und maxcol im Voraus als int deklariert werden müssen:[2]

// Datei: curses-beispiel-2.c

#include <ncurses.h>

int maxrow, maxcol;


int main(void)
    {
    initscr();

    // Größe des Curses-Fensters bestimmen:
    getmaxyx(stdscr, maxrow, maxcol);

    // Größe des Curses-Fensters ausgeben:
    move(0,0);
    printw("Das Fenster hat %d Zeilen und %d Spalten.", maxrow, maxcol);
    refresh();

    napms(3000);
    endwin();
    return 0;
    }

Die Kombination von move() mit einer der Print-Anweisungen kommt in Curses-Anwendungen sehr häufig vor; daher gibt es zu den drei Ausgabefunktionen addch(), addstr() und printw() auch die kombinierten Funktionen mvaddch(), mvaddstr() und mvprintw(). Diesen wird beim Aufruf zunächst die gewünschte Position des Cursor angegeben, die übrigen Argumente sind mit den Basisfunktionen identisch. Beispielsweise sind die folgenden beiden Aufrufe identisch:

// Text in Zeile 0, Spalte 3 ausgeben:
move(0,3)
addstr("Hallo Curses!")

// Kurzschreibweise:
mvaddstr(0, 3, "Hallo Curses!")

Zur Eingabe von Text gibt es in Curses ebenfalls drei grundlegende Funktionen:

  • Mittels getch(c) kann ein einzelnes Zeichen vom Bildschirm eingelesen werden; das Zeichen wird dabei automatisch eingelesen, ohne dass die Enter-Taste gedrückt werden muss.
  • Mittels getstr(*str) und getnstr(*str, n) kann eine ganze Zeichenkette vom Curses-Fenster eingelesen werden, wie es mit gets() von der Standard-Eingabe der Fall ist. Die Funktion getnstr() beschränkt die Anzahl an eingelesenen Zeichen dabei auf n Stück, so dass sichergestellt werden kann, dass das Array, in dem die Zeichenkette abgelegt werden soll, ausreichend groß ist.
  • Mittels scanw() kann Text in der gleichen Weise von einem Curses-Fenster eingelesen werden, wie dies mittels der Funktion scanf() aus dem Standard-Eingang der Fall ist.

Als Standard geben alle Eingabefunktionen die vom Benutzer eingegebenen Zeichen unmittelbar auf dem Bildschirm aus, auch ohne dass dazu die refresh()-Funktion aufgerufen werden müsste; zusätzlich stoppt das Programm, bis die Eingabe vom Benutzer erfolgt ist. Ist dies nicht gewünscht, so müssen diese Einstellung, wie im folgenden Abschnitt beschrieben, deaktiviert werden.

Modifizierung der Ein- und Ausgabe

In Curses gibt es folgende Funktionen, die das Verhalten des Programms hinsichtlich Eingabe und Ausgabe anzupassen:

  • raw() und cbreak():

    Normalerweise speichert die Shell die Eingabe des Benutzers in einem Puffer, bis ein Neues-Zeile-Zeichen oder ein Carriage-Return-Zeichen (Enter-Taste) erscheint. Die meisten interaktiven Programme benötigen die eingegebenen Zeichen allerdings unmittelbar. Die beiden Funktionen raw() und cbreak() deaktivieren beide das Puffern von eingegebenen Zeichen, wobei sie sich in einem Detail unterscheiden: Eingegebene Zeichen wie Ctrl z (“Suspend”) oder Ctrl c (“Interrupt”), die von der Shell normalerweise als Kontrollsequenzen interpretiert werden, werden auch bei der Verwendung von cbreak() zunächst von der Shell ausgewertet. Bei Verwendung von raw() werden auch diese Zeichen direkt ans Programm weitergeleitet und dort interpretiert.

  • echo() und noecho():

    Diese beiden Funktionen beeinflussen, ob vom Benutzer eingegebene Zeichen unmittelbar auf dem Bildschirm erscheinen sollen oder nicht. Diese Funktionen sind insbesondere in Verbindung mit der Curses-Funktion getch() von Bedeutung, um beispielsweise in interaktiven Programmen die unnötige Wiedergabe der vom Benutzer gedrückten Tasten auf dem Bildschirm zu vermeiden. Meist wird noecho() zu Beginn des Programms aufgerufen, und der Echo-Modus nur im Bedarfsfall (beispielsweise beim zeichenweise Einlesen von Text) aktiviert.

  • keypad():

    Diese Funktion sollte von jedem interaktiven Curses-Programm aufgerufen werden, denn sie ermöglicht die Verwendung der Funktions- und Pfeiltasten. Um beispielsweise die Funktion für den Standard-Bildschirm stdscr zu aktivieren, gibt man keypad(stdscr, TRUE); ein.[3]

  • curs_set():

    Diese Funktion kann verwendet werden, um den Cursor unsichtbar oder wieder sichtbar zu machen. Mit curs_set(0); wird der Cursor unsichtbar, mit curs_set(1); wieder sichtbar.

  • halfdelay(n):

    Mit dieser nur in Ausnahmefällen verwendeten Funktion kann festgelegt werden, dass beim dem Einlesen eines Zeichens mittels getch() oder einer Zeichenkette maximal n Zehntel Sekunden gewartet wird. Wird in dieser Zeit kein Text eingegeben, so fährt das Programm fort. Dies kann beispielsweise für eine Timeout-Funktion bei einer Passwort-Eingabe verwendet werden.

  • nodelay():

    Diese Funktion wird von den meisten interaktiven Curses-Programm zu Beginn aufgerufen, denn sie verhindert, dass das Programm bei der Verwendung der Funktion getch() anhält. Anstelle dessen liefert getch() kontinuierlich den Wert ERR (entspricht dem Wert -1) zurück, sofern der Benutzer keine Taste gedrückt hat.

Mit Hilfe von nodelay(stdscr, TRUE) kann beispielsweise eine mainloop() programmiert werden, die einzelne von der Tastatur aus eingegebene Zeichen über eine switch-Anweisung mit bestimmten Anweisungen verknüpft:[4]

// Datei: curses-beispiel-3.c

#include <ncurses.h>

int main()
{
    int c;
    int quit = FALSE;

    initscr();
    cbreak();
    noecho();
    keypad(stdscr, TRUE);
    nodelay(stdscr, TRUE);

    mvprintw(0,0, "Bitte Taste eingeben oder Programm mit \'q\' beenden.");

    while( !quit )
    {
        c = getch();
        switch(c)
        {
            case ERR:
                napms(10);
                break;
            case 'q':
                quit = TRUE;
                break;

            default:
                mvprintw(3, 0, "ASCII-Code des Zeichens: %3d;", c);
                mvprintw(3, 30, "Zeichen wird dargestellt als: \'%c\'.", c);
                break;
        }

        refresh();
    }

    endwin();
    return 0;
}

Im obigen Beispielprogramm wird zunächst Curses gestartet und das Bildschirm-Verhalten angepasst. Anschließend wird mittels der while-Schleife kontinuierlich eine Tastatureingabe vom Benutzer abgefragt:

  • Wird keine Taste gedrückt (Rückgabewert: ERR), so wartet das Programm durch Aufruf von napms(10) zehn Millisekunden lang, bis es mit der Ausführung fortfährt. Ohne eine derartige Verzögerung würde das Programm die Schleife kontinuierlich mit maximaler Geschwindigkeit abarbeiten und somit ständig maximale CPU-Last verursachen; mit “nur” zehn Millisekunden Pause reduziert sich die CPU-Auslastung auf circa 1\%.
  • Wird eine beliebige Taste außer q gedrückt, so wird der ASCII-Wert des Zeichens und das Zeichen selbst ausgegeben. Die Darstellung funktioniert nur bei alphabetischen und numerischen Zeichen wie gewohnt, bei Funktions- und Sondertasten kann zumindest der ASCII-Wert des eingegebenen Zeichens abgefragt werden.
  • Entspricht das eingegebene Zeichen dem Zeichen q (beziehungsweise dem ASCII-Wert 113), so wird die Variable quit auf TRUE gesetzt. Damit ist die Negation !quit gleich FALSE, und die Schleife wird nicht fortgesetzt.

Schließlich wird das Curses-Programm mittels endwin() beendet.

Editor-Funktionen

Die Curses-Bibliothek stellt, da sie auf textbasierte Programme ausgerichtet ist, einige Funktionen bereit, die das Eingeben von Text ziemlich komfortabel gestalten.

Um einzelne Zeichen oder Zeilen einzugeben oder zu löschen, gibt es in Curses folgende Funktionen:

  • insch()

    Mit insch(c) kann ein einzelnes Zeichen an der Stelle des Cursors eingefügt werden; der Rest der Zeile wird dabei automatisch um eine Zeichenbreite nach rechts verschoben.

  • delch()

    Mit delch() wird das Zeichen an der Stelle des Cursors gelöscht; der Rest der Zeile wird dabei automatisch um eine Zeichenbreite nach links verschoben.

  • insertln()

    Mit insertln() kann eine neue Zeile an der Stelle des Cursors eingefügt werden; alle folgenden Zeilen werden dabei automatisch um eine Zeile nach unten verschoben.

  • deleteln()

    Mit deleteln() wird die Zeile an der Stelle des Cursors gelöscht; alle folgenden Zeilen werden dabei automatisch um eine Zeile nach oben verschoben.

Möchte man an der gleichen Stelle am Bildschirm aufeinander folgende Textstellen mit unterschiedlicher Länge ausgeben, so werden durch refresh(); nur die jeweils neu darzustellenden Zeichen auf dem Bildschirm aktualisiert; wird an der gleichen Startpositiion zunächst eine lange und danach eine kurze Textstelle ausgegeben, so bleibt bei der Ausgabe der kurzen Textstelle ein Rest der langen Textstelle bestehen.

Um den Bildschirm zu säubern, gibt es daher in Curses folgende Funktionen:

  • clrtoeol()

    Mit clrtoeol() werden alle Zeichen von der Cursor-Position aus bis zum Ende der Zeile gelöscht (“clear to end of line”).

  • clrtobot()

    Mit clrtobot() werden alle Zeilen von der Cursor-Position aus bis zum Ende des Fensters gelöscht (“clear to bottom of window”).

  • erase() und clear()

    Mit erase() und clear() werden alle Zeichen auf dem gesamten Fenster gelöscht. Beide Funktionen sind nahezu identisch, clear() ist allerdings etwas “gründlicher” und bewirkt, dass das Fenster beim nächsten Aufruf von refresh() komplett neu ausgegeben wird.

Attribute und Farben

Text kann in Curses auf den meisten Shells auch farbig oder fettgedruckt dargestellt werden. Eine solche Modifizierung wird mittels der folgenden Funktionen vorgenommen werden:

  • attron(attr)

    Mit dieser Funktion wird das angegebene Attribut attr aktiviert.

  • attroff(attr)

    Mit dieser Funktion wird das angegebene Attribut attr deaktiviert.

  • attrset(attr)

    Mit dieser Funktion wird das angegebene Attribut attr aktiviert; alle sonstigen Attribute werden deaktiviert.

Die obigen Funktionen wirken sich auf die weitere Darstellung aller Zeichenketten aus. Um den ausgegebenen Text wieder in “normaler” Form darzustellen, kann attrset(A_NORMAL) verwendet werden. Eine Übersicht aller Textattribute ist in der folgenden Tabelle zusammengestellt.

A_NORMAL Normaler Text
A_BOLD Text in Fettschrift und mit erhöhter Helligkeit
A_DIM Text mit verringerter Helligkeit (wird nicht von jeder Shell unterstützt)
A_REVERSE Text mit vertauschter Vorder- und Hintergrundfarbe
A_UNDERLINE Unterstrichener Text
A_BLINK Blinkender Text (wird nicht von jeder Shell unterstützt)
A_STANDOUT Hervorgehobener Text (entspricht meist A_REVERSE)

Um mehrere Attribute miteinander zu kombinieren, können diese entweder nacheinander mittels attron() aktiviert werden, oder in einer einzigen attrset()-Anweisung durch ein binäres Oder verbunden werden; beispielsweise wird durch attrset(A_UNDERLINE | A_BOLD); Text künftig unterstrichen und in Fettdruck ausgegeben.

Farbiger Text

Um Text farbig auszugeben, sollte zunächst geprüft werden, ob eine farbige Darstellung von der Shell unterstützt wird. Dazu gibt es in Curses die Funktion has_colors(), die entweder TRUE oder FALSE als Ergebnis liefert. Ist farbiger Text auf der Shell möglich, so kann in Curses die Farbunterstützung mittels der Funktion start_color() freigeschaltet werden; dabei werden zugleich die in der folgenden Tabelle angegebenen Farbnamen als symbolische Konstanten definiert.

Nummer Name Farbe
0 COLOR_BLACK Schwarz
1 COLOR_RED Rot
2 COLOR_GREEN Grün
3 COLOR_YELLOW Gelb
4 COLOR_BLUE Blau
5 COLOR_MAGENTA Magenta
6 COLOR_CYAN Cyan
7 COLOR_WHITE Weiss

Aus diesen üblicherweise 8 Farben können mittels init_pair() anschließend so genannte “Farb-Paare” definiert werden. In einem solchen Paar besteht aus einer Farbnummer für den Vordergrund (der Schriftfarbe) und einer Farbnummer für den Hintergrund, wobei anstelle der Nummern auch die oben aufgelisteten symbolischen Konstanten verwendet werden können. Beispielsweise wird mit init_pair(1, COLOR_YELLOW, COLOR_BLUE) ein Farben-Paar mit der Nummer 1 definiert, bei dessen Verwendung Text in gelber Farbe auf blauem Hintergrund ausgegeben wird.

Jedes so definierte Farbenpaar kann mittels attron() beziehungsweise attrset() als Text-Attribut aktiviert werden:

if ( has_colors() == FALSE )
    printw("Kein farbiger Text moeglich!");
else
    start_color();

init_pair(1, COLOR_YELLOW, COLOR_BLUE );
attrset( COLOR_PAIR(1) );

printw("Farbiger Text, sofern moeglich!");

Neben der Angabe von COLOR_PAIR(n), die für das Farben-Paar mit der Nummer n steht, können ebenfalls weitere Attribute mittels eines binärem Oders angegeben werden. Wird ein Farbenpaar mit dem Attribut A_BOLD kombiniert, so erscheint der Text nicht nur fettgedruckt, sondern auch in einer etwas helleren Farbe; aus Schwarz wird als Vordergrundfarbe beispielsweise Grau. Bei einer gezielten Verwendung kann damit das Farbspektrum etwas erweitert werden.

Es ist auch möglich dem Hintergrund ein Farben-Paar zuzuweisen; damit ändert sich das Aussehen des Curses-Fensters, auch wenn kein Text ausgegeben wird. Die Attribute für den Hintergrund werden mit der Funktion bkdg() gesetzt. Wird neben einem Farbenpaar und einem binärem Oder zusätzlich ein beliebiges Zeichen angegeben, so wird der Hintergrund standardmäßig mit diesem Zeichen bedruckt:

bkgd( COLOR_PAIR(1) | '+' );

In diesem Fall würde mit den obigen Definitionen das Curses-Fenster blau erscheinen und an allen Stellen ohne Text mit gelben +-Zeichen aufgefüllt werden.

Fenster und Unterfenster

In vielen interaktiven Programmen kann man zwischen verschiedenen Ansichtsfenstern wechseln, um beispielsweise eine Datei aus einem Filebrowser-Fenster auszuwählen oder eine Hilfe-Seite zu betrachten. Für eine bessere Übersichtlichkeit im Quellcode und eine bessere Effizienz ist es empfehlenswert, für jeden derartigen Zweck ein eigenes Fenster zu verwenden, das bei einem Wechsel nicht neu geschrieben, sondern nur wieder aktualisiert werden muss.

Ein neues Fenster wird mittels der Funktion newwin() erstellt. Als Rückgabewert liefert diese Funktion entweder einen Zeiger auf ein WINDOW-Objekt, oder NULL, falls beim Erstellen des Fensters ein Fehler aufgetreten ist. Als Argumente für newwin() werden die Anzahl an Zeilen und Spalten sowie die Startposition der oberen linken Ecke des Fensters angegeben:

int nrows = 5;
int ncols = 20;
int starty = 3;
int startx = 5;

mywin = newwin(nrows, ncols, starty, startx);
wrefresh(mywin);

Ein neues Fenster darf nicht größer sein als das Standard-Fenster stdscr, und muss mindestens eine Zeile und eine Spalte beinhalten. Gibt man allerdings newwin(0,0,0,0); ein, so wird ein neues Fenster erzeugt, das genauso groß ist wie das Fenster stdscr. Damit das neue Fenster auf dem Bildschirm sichtbar wird, muss die Funktion wrefresh() mit dem entsprechenden Namen des Fensters aufgerufen werden. Bei Bedarf müssen zudem die Funktionen keypad() und nodelay für das jeweilige Fenster aufgerufen werden.

Die Funktionen move(), addch, addstr(), printw(), getch(), getstr() lassen sich auf ein existierende Fenster werden, wenn an ihren Funktionsname vorne ein w angehängt und als erstes Argument ein Zeiger auf das zu bearbeitende Fenster übergeben wird, also beispielsweise waddstr(mywin, "Text").

Bei der Verwendung von mehreren sich überlappenden Fenstern ist nicht sichergestellt, dass der Text von Curses wie erwartet dargestellt wird. Es wird daher dringend empfohlen, entweder neue Fenster mit voller Fenstergröße zu erzeugen, oder das Standard-Fenster nicht zu benutzen und dafür mehrere nicht überlappende Fenster zu verwenden. Das Fenster, das zuletzt mit einem Aufruf von wrefresh() aktualisiert wurde, wird als “oberstes” angezeigt und verdeckt gegebenenfalls andere Fenster.

Um ein Fenster wieder zu schließen, wird die Funktion delwin() verwendet, wobei als Argument wiederum ein Zeiger auf ein Fenster übergeben wird, also beispielsweise delwin(mywin). Das Fenster, das nach dem Löschen aktiv angezeigt werden soll, muss dabei mittels wrefresh() aktualisiert werden. Gegebenenfalls muss es dazu erst mittels touchwin(win_name) zur vollständigen Aktualisierung vorgemerkt werden, falls ansonsten keine Änderungen vorgenommen wurden.

Unterfenster erstellen

Neben Fenstern können in Curses auch so genannte Unterfenster erstellt werden. Diese können dazu verwendet werden, um einen Teil des Hauptfensters leichter ansteuern oder mit anderen Farb- und Textattributen versehen zu können. Der Inhalt eines Unterfensters hingegen stimmt mit dem Inhalt des Hauptfensters an der jeweiligen Stelle überein.

Ein neues Unterfenster kann, ebenso wie mit newwin() ein neues Fenster erstellt wird, mittels subwin() erzeugt werden, wobei als erstes Argument der Name des übergeordneten Fensters und als weitere Argumente die Anzahl an Zeilen und Spalten sowie die Startposition der oberen linken Ecke angegeben werden:

// Neues Unterfenster erstellen:
my_subwin = subwin(mywin, nrows, ncols, starty, startx);

// Alternativ auch möglich:
my_subwin = derwin(mywin, nrows, ncols, starty, startx);

Die zweite Möglichkeit ein Unterfenster zu erstellen bietet die Funktion derwin(), wobei in diesem Fall die Werte starty und startx relativ zum übergeordneten Fenster (und nicht relativ zum Hauptfenster stdscr) angegeben werden.

Alle Funktionen, die auf ein “richtiges” Fenster angewendet werden können, lassen sich auch auf ein Unterfenster anwenden. Unterfenster haben einen eigenen Cursor und eigene Text- und Farbattribute; sie können selbst wiederum Ausgangspunkt für neue Unterfenster sein.

Mittels delwin(subwindow_name) wird ein Unterfenster wieder geschlossen. Bevor ein (Haupt-)Fenster geschlossen wird, sollten zuerst auf diese Weise alle Unterfenster geschlossen werden, um Speicherlecks zu vermeiden (die Hauptfenster haben keine Informationen darüber, ob sie Unterfenster beinhalten und können diese somit nicht automatisch löschen). Der Inhalt des Subfensters, der dem Inhalt des Hauptfensters entspricht, bleibt beim Löschen erhalten.[5]

Pads

Neben normalen Fenstern gibt es in Curses auch so genannte “Pads”. Während die Funktionen für Pads weitgehend mit den für normale Fenster identisch sind, ist ihre Größe nicht auf die Größe des Hauptfensters beschränkt; die maximale Größe eines Pads ist allerdings auf 32767 Zeilen beziehungsweise Spalten beschränkt.

Ein neues Pad wird folgendermaßen erzeugt:

int nrows = 1000;
int ncols = 1000;
WINDOW *mypad;

// Neues Pad erstellen:
mypad = newpad(nrows, ncols);

Mittels den für Fenster üblichen Ausgabefunktionen, beispielsweise waddstr(), kann Text auf einem Pad angezeigt werden. Damit die Änderungen auf dem Bildschirm sichtbar werden, kann allerdings nicht wrefresh() verwendet werden, da zusätzlich angegeben werden muss, von welcher Stelle aus das Pad angezeigt werden soll: Üblicherweise ist ein Pad größer als der Bildschirm, es kann somit nur ein Ausschnitt des Pads angezeigt werden. Dies wird bei der Funktion prefresh() berücksichtigt:

prefresh(padname, pad_ymin, pad_xmin, ymin, xmin, ymax, xmax);

Hierbei bezeichnen pad_ymin und pad_xmin die Koordinaten der oberen linken Ecke innerhalb des Pads, von der aus der Inhalt angezeigt werden soll. Die übrigen Argumente geben die Koordinaten des Bereichs an, in dem das Pad relativ zum Hauptfenster angezeigt werden soll.

Subpads

Ebenso wie Fenster ein oder mehrere Unterfenster haben können, können Pads auch ein oder mehrere Subpads beinhalten. Ebenso wie bei den Unterfenstern ist der Inhalt eines Subpads mit dem Hauptpad identisch, das Subpad kann allerdings beispielsweise eigene Attribute und Farben aufweisen.

Ein neues Subpad kann mittels subpad() erzeugt werden:[6]

int nrows = 1000;
int ncols = 1000;
int subrows = 50;
int subrows = 50;
WINDOW *mypad, *my_subpad;

// Neues Pad erstellen:
mypad = newpad(nrows, ncols);

// Neues Subpad erstellen:
// Allgemeine Syntax: subpad(nrows, ncols, starty, startx)
my_subpad = subpad(mypad, 0, 0, 10, 10);

Bei der Verwendung von Pads und Subpads ist zu beachten, dass diese nicht innerhalb des Hauptfensters verschoben werden dürfen; die mvwin()-Funktion kann somit nicht auf Pads angewendet werden. Ebenso sind die scroll()-Funktionen für Pads nicht definiert.

Mittels delwin(padname) kann ein (Unter-)Pad wieder gelöscht werden. Auch hierbei sollten zunächst alle Subpads und erst zuletzt das Hauptpad gelöscht werden, um Speicherlecks zu vermeiden.

Debugging von Curses-Programmen

Curses-Programme nutzen die Shell als Ein- und Ausgabefenster; sie lassen sich daher nicht innerhalb der gleichen Shell aufrufen und mit dem gdb-Debugger analysieren. Folgender Trick schafft hier Abhilfe:

  • Man öffnet ein zweites Shell-Fenster und gibt dort tty ein, um sich die Nummer dieser Shell anzeigen zu lassen; das Ergebnis lautet beispielsweise /dev/pts/23. Anschließend gibt man in diesem Fenster sleep 1000000000000000000000 ein, um alle weiteren Eingaben an diese Shell für eine lange Zeit zu ignorieren. (Bei Bedarf kann der Schlafmodus mittels Strg C abgebrochen werden.)

  • Im ersten Shell-Fenster kann man dann im Projektverzeichnis wie gewohnt gdb programmname eingeben, um den Debugger zu starten. Als erste Debugger-Anweisung wird dann der Eingabe-und-Ausgabe-Port des zu debuggenden Programms auf den Bezeichner des zweiten Shell-Fensters festgelegt:

    tty /dev/pts/23
    

    Nun kann run eingeben werden, um das Programm im Debugger ablaufen zu lassen. Die Ausgabe des Programms erfolgt dabei im zweitem Shell-Fenster.


Anmerkungen:

[1]Eine “Spalte” in Curses der Breite eines Textzeichens; die meisten Fenster haben daher mehr Spalten als Zeilen.
[2]Für die Größe des Hauptfensters stdscr sind in Curses auch die Makros LINES und COLS definiert, die vom Compiler durch die beim Programmstart vorliegenden Werte ersetzt werden.
[3]Die Konstanten TRUE und OK beziehungsweise FALSE sind in der Datei ncurses.h als 1 beziehungsweise 0 definiert.
[4]Mit nodelay(stdscr, FALSE) kann das ursprüngliche Verhalten von getch() wieder hergestellt werden.
[5]Umgekehrt wird allerdings durch Funktionen wie wclear() der Inhalt beim Löschen des Inhalts eines Fensters automatisch auch der Inhalt aller Unterfenster gelöscht.
[6]Ein Pad kann ein Subpad, aber kein Unterfenster beinhalten. Man kann innerhalb eines Pads also mittels subpad() ein Subpad erzeugen, jedoch nicht mittels subwin() ein Unterfenster.