Unterabschnitte

Erste Schritte mit der libCUI

''Hallo CUI world!''

Um nicht mit der guten alten Tradition von Programmierbüchern zu brechen, soll auch diese Einführung mit dem obligatorischen ''Hallo World'' Programm beginnen:

#include <cui.h>

void quit(void)
{
   WindowEnd();
}

int main(void)
{
   WindowStart(TRUE, TRUE);
   atexit(quit);

   MessageBox(WindowGetDesktop(),
              "Hallo World\n"
              "This is my first libcui program!",
              "Message",
              MB_OK);

   return 0;
}

Zunächst wird die Datei ''cui.h'' eingebunden, die alle Funktionsprototypen, Datentypen und Konstanten der libCUI bekannt macht. In der ''main''-Routine wird dann über den Funktionsaufruf ''WindowStart'' in den curses-Modus gewechselt, wobei die beiden Parameter sowohl den Farbmodus, als auch die Mauseingabe aktivieren.

   void WindowStart(int color, int mouse);

Anschließend wird über ''atexit'' eine Exit-Routine angemeldet, die in jedem Fall dafür sorgt, dass der curses-Modus auch wieder korret über ''WindowEnd'' beendet wird und alle von der libCUI verwalteten Datenstrukturen freigegeben werden. Zu guter letzt wird über ''MessageBox'' ein Meldungsfenster angezeigt, das eine zweizeilige Meldung ausgibt.

Das Programm mogelt sich zugegebenermaßen um die eigentliche Fensterprogrammierung herum, indem die fertige Dialogklasse ''MessageBox'' verwendet wird um Text auszugeben. Zu einem späteren Zeitpunkt wird darauf jedoch noch wesentlich ausführlicher eingegangen.

übersetzen von libCUI Anwendungen

Damit ein libCUI-Programm lauffähig ist, muss es mit der Biblithek bei der übersetzung verknüpft (gelinkt) werden. Dies funktioniert sebstverständlich nur dann, wenn sich die Entwicklungsdateien (headers and libraries) der libCUI auf dem Build-System befinden.

Das Linken kann auf zwei Arten erfolgen: dynamisch und statisch. Bei der dynamischen Verknüpfung werden lediglich Verweise auf eine gemeinsame Bibliotheksdatei in dem erzeugten Programm hinterlegt. Diese müssen später vom Programm-Loader des Betriebsystems aufgelöst werden, bevor das Programm zur Ausführung kommen kann. Der Vorteil dabei ist, dass alle Programme eine gemeinsame Bibliothek verwenden und damit Resourcen schonen. Zudem kommen bei einem Update der Bibliothek alle Programme zugleich in den Genuss von Fehlerkorrekturen, solange sich das Interface der Bibliothek nicht verändert hat.

Beim statischen Linken wird der verwendete Code der Bibliothek in das Programm übernommen, wodurch deutlich größere Binärdateien erzeugt werden. Diese haben dann aber den Vorteil, dass sie von konzeptionellen Änderungen der Bibliothek unabhängig sind und auch auf Systemen funktionieren, auf denen die libCUI nicht als gemeinsame Datei vorliegt. Zum momentanen Zeitpunkt wird zum statischen Linken geraten, da sich die libCUI noch in einem recht frühen Entwicklungsstadium befindet.

Dynamisches Linken

gcc -Wall -Wstrict-prototypes -o hallo.o hallo.c
gcc -o hallo hallo.o -lcui

Hier wird in zwei Schritten zunächst die Datei hallo.c übersetzt und anschließend mit der Bibliothek libCUI zu einem ausführbaren Programm verlinkt. Bei nur einer Code-Datei kann dies auch in einem einzelnen Schritt erfolgen:

gcc -Wall -Wstrict-prototypes -o hallo hallo.c -lcui

Statisches Linken

gcc -Wall -Wstrict-prototypes -o hallo.o hallo.c
gcc -o hallo hallo.o /usr/lib/libcui.a -lcurses

Hier wird in zwei Schritten zunächst die Datei hallo.c übersetzt und anschließend mit der Bibliothek libCUI zu einem ausführbaren Programm verlinkt. Dabei wird die statische Bibliotheksdatei ''/usr/lib/libcui.a'' einfach in die Liste der zu verlinkenden Module aufgenommen wodurch sie vom Linker fest eingebunden. Zu beachten ist jetzt allerdings, dass zur Auflösung der curses-Funktionen, die curses-Library ebenfalls angegeben werden muss.

Bei nur einer Code-Datei kann das auch in einem einzelnen Schritt erfolgen:

gcc -Wall -Wstrict-prototypes -o hallo hallo.c /usr/lib/libcui.a \
    -lcurses

Das Ergebnis

Egal ob nun statisch oder dynamisch gelinkt wurde, sollte sich nach dem obigen Beispiel eine Datei ''hallo'' im aktuellen Verzeichnis befinden, die sich mit

eis # ./hallo

ausführen lässt. Das Ergebnis ist ein Programm, dass die Meldung ''Hallo World'', ''This is my first libcui program!'' in einem Meldungsfenster vor einem (blauen) Hintergrund ausgibt. Das Meldungsfenster besitzt eine Schaltfäche über die das Fenster entweder mit der Leertaste oder der Enter-Taste geschlossen werden kann. Falls die Konsole die Maus unterstützt, kann das Fenster auch mit diesem Eingabegerät geschlossen werden. Zudem lässt sich die MessageBox durch Ziehen der Maus auf dem Fensterrahmen im sichtbaren Bereich verschieben.

Wird die Größe des Konsolenfensters geändert, wird das Meldungsfenster in der Fenstermitte zentriert.

Image halloworld1

Allgemeine Hinweise

Koordinatensysteme

Vergleichbar mit gängigen Fenstersystemen wird bei Koordinatenangaben innerhalb der libCUI eine x, y-Reihenfolge eingehalten. Demgegenüber nennt die curses- Bibliothek die y-Koordinate zuerst, also y, x. Dies mag zu einiger Verwirrung führen, denn immer wenn mit curses-Routinen zur Textausgabe gearbeitet wird, ist dieser Unterschied zu beachten.

Um die Programmierung in dieser Hinsicht zu erleichtern wird die libCUI zu einem späteren Zeitpunkt Makro-Definitionen erhalten, die die Curses-Routinen so erscheinen lassen, als seien sie innerhalb der libCUI definiert. Dabei werden die Koordinaten entsprechend getauscht werden.

Mausunterstützung

Damit die Maus auf der Textkonsole funktioniert, muss die zugrundeliegende curses- Bibliothek mit Mausunterstützung (z.B. für den gpm-Mouse Daemon) übersetzt worden sein. Dies ist oftmals nicht der Fall. In Terminal-Fenstern unter X11 (KDE- / Gnome- Terminal), sowie im ssh Client PuTTY ist die Mausunterstützung i.d.R enthalten. Allerdings ist es dem Autor nicht gelungen, auch die Mouse-Move Ereignisse sichtbar zu machen. Diese Eigenschaft muss in den Tiefen der terminfo-Dateien verborgen sein. Sachdienliche Hinweise sind stets willkommen... :-)
Holger Bruenjes 2016-12-12