\chapter{GUI-Dienste}
\label{gui}

Durch die immer gr"o"sere Leistungsf"ahigkeit der Hardware, insbesondere was
die Verf"ugbarkeit von Arbeitsspeicher und Prozessorleistung angeht, sind die
M"oglichkeiten zur Implementierung grafischer Benutzerschnittstellen ({\em
graphical user interface - GUI}) in den 
letzten Jahren stark gestiegen \cite{Man93}.
Spezialisierte Bibliotheken machen die grafischen Leistungen der in modernen 
Arbeitsplatzrechnern benutzten Fensterbetriebssysteme (z.B. {\sf Motif}, {\sf
Windows}, {\sf Presentation Manager}) auf einer h"oheren Abstraktionsebene 
f"ur den Anwendungsprogrammierer zug"anglich.
Dadurch wird die Komplexit"at der GUI-Programmierung und somit der
Gesamtaufwand f"ur die Anwendungsentwicklung reduziert.

Problematisch ist allerdings, da"s die Schnittstellen dieser Bibliotheken nicht 
immer zur Anwendungsprogrammiersprache passen \cite{Dea88}, da sie meist 
nur f"ur eine bestimmte
Sprache angeboten werden. Der Programmierer mu"s dann im Extremfall nicht
nur eine zus"atzliche Sprache beherrschen, sondern sich auch um deren
Einbindung in die Anwendungsprogrammiersprache k"ummern, was die Komplexit"at
der Aufgabe abermals steigert. Durch das im letzten Kapitel vorgestellte 
generische Gateway wird dem Anwendungsprogrammierer jedoch dieser zus"atzliche 
Aufwand abgenommen.  Er bekommt dar"uberhinaus die M"oglichkeit, die 
Vorz"uge einer interaktiven persistenten Umgebung f"ur die GUI-Programmierung 
zu nutzen. Auf diese Vorz"uge m"u"ste er eventuell verzichten, wenn 
seine Entscheidung f"ur eine Applikationsprogrammiersprache von der 
Verf"ugbarkeit von GUI-Bibliotheken abhinge.

In diesem Kapitel wird am Beispiel der Einbindung der
GUI-Klassenbibliothek {\sf StarView$^{TM}$}\cite{StarView93} eine
Anwendung des C++-Gateway-Generators beschrieben. Dabei zeigt sich, da"s die
Nutzung dieser Bibliothek von Tycoon aus eine Qualit"atsverbesserung
aus zwei unterschiedlichen Sichten mit sich bringt:
einerseits aus der Sicht des Klienten (in diesem Fall der 
Tycoon-Umgebung), dadurch, da"s
damit eine plattform"ubergreifende einheitliche GUI-Programmierschnittstelle zur
Verf"ugung steht. Andererseits aus der Sicht der GUI-Programmierung, denn
die Nutzung dieser Bibliothek von Tycoon aus ist durch interaktive
"Ubersetzung und Auswertung, Persistenz und {\em multi threading} flexibler
als deren direkte Verwendung in C++-Anwendungen. 

        
                \section{Konzepte von {\sf StarView}}

{\sf StarView} ist eine  C++-Klassenbibliothek, die es erlaubt, bei der 
Anwendungsentwicklung von der Gestaltung der grafischen Benutzeroberfl"ache des 
jeweiligen Fenstersystems zu abstrahieren, um dadurch die Portabilit"at von
GUI-Anwendungen zu erh"ohen.
Kennzeichnend f"ur grafische Benutzeroberfl"achen ist einerseits 
das Erscheinungsbild und die Funktionalit"at der Fenster 
und Interaktionselemente ({\em look}) und andererseits das Verhalten des
Systems ({\em feel}) auf Interaktionen des Anwenders.
Die Klassenhierarchie dieser Bibliothek ist so gestaltet,
da"s das {\em look and feel} des jeweilig zugrundeliegenden Fenstersystems 
weitgehend beibehalten wird und nur bei den Eigenschaften und Funktionen
Anpassungen vorgenommen werden, bei denen sich die Fenstersysteme graduell 
unterscheiden. Es wird also eine Mischung aus dem {\em Schnittmengenansatz}
und dem {\em Obermengenansatz} verfolgt \cite{Mues94}, da nicht alle
nichtvorhandene Funktionalit"at eines Fenstersystems durch {\sf StarView}
nachgebildet wird\footnote{
Ein Beispiel hierf"ur ist die M"oglichkeit der Ikonifizierung von Fenstern in
manchen Systemen, die auf dem {\sf Apple Macintosh} nicht existiert und in der 
{\sf StarView}-Implementation f"ur dieses System auch nicht nachgebildet wird.
}
Diese Mischform wirft allerdings die Frage nach dem Grad der Portabilit"at von
{\sf StarView}-Anwendungen auf, da GUI-Anwendungen nur dann portabel sind, wenn 
der Programmierer darauf geachtet hat, nur Funktionalit"at zu benutzen, die auf
allen unterst"utzten Systemen verf"ugbar ist. 

Einen Eindruck von Aufbau und Umfang der Bibliothek soll
Abbildung \ref{sv-classes} verschaffen.

\begin{figure}
\leavevmode
\def\epsfsize#1#2{0.8\textwidth}
\centerline{\epsffile{sv-classes.epsf}}
\caption{\label{sv-classes} Klassenhierarchie von {\sf StarView}}
\end{figure}


        \subsection{Typische GUI-Elemente}

Aus der Vielzahl der angebotenen Klassen sollen in diesem Abschnitt exemplarisch
die Eigenschaften der wichtigsten GUI-Elemente beschrieben werden. 

\begin{description}
\item [Fenster:] Sie dienen der Pr"asentation der Anwendungsdaten und der
Entgegennahme der Eingaben des Benutzers\footnote{
Au"serhalb von Fenstern sind keine Eingaben m"oglich.} 
durch die im Ausgabebereich des jeweiligen Fensters dargestellten 
Interaktionselemente. Nur Fenster, die den {\em focus} besitzen, k"onnen
Eingaben entgegennehmen. 
Sie stehen "uber eine Vater-Sohn-Beziehung (festgelegt bei der Erzeugung,
dynamisch rekonfigurierbar) zueinander in einem Abh"angigkeitsverh"altnis. 
Systemfenster ({\em class SystemWindow}) sind unabh"angig von ihrem 
Vater-Fenster verschiebbar, w"ahrend alle anderen Fenster nur relativ zum 
Vater-Fenster
positioniert werden k"onnen. Arbeitsfenster k"onnen vom Benutzer geschlossen
und dadurch als Piktogramm ({\em icon}) auf dem Bildschirmhintergrund
dargestellt werden. 

\item [Interaktionselemente (controls):] Dies sind die vom Anwender durch 
Maus und Tastatur
manipulierbaren Schnittstellenelemente. Sie umfassen Kn"opfe, Auswahllisten,
Eingabefelder, Men"us etc. Mit diesen Elementen k"onnen Funktionen verkn"upft
werden, die bei bestimmten Benutzerinteraktionen (z.B. Maus-Klick auf einen
Knopf) aufgerufen werden.

\item [Dialoge:] Durch Dialoge werden Interaktionselemente zusammengefa"st, um 
umfangreiche
Benutzereingaben zu unterst"utzen. Sie steuern den Focus-Wechsel zwischen
Interaktionselementen und erm"oglichen dadurch ihre geordnete Bearbeitung.
Es wird zwischen {\em modalen} und {\em nichtmodalen} Dialogen unterschieden,
wobei modale Dialoge im Gegensatz zu den nichtmodalen beendet werden m"ussen,
bevor in der Anwendung fortgeschritten werden kann.

\item [Datenaustausch:] Der Transfer von Daten zwischen Anwendungen, bzw.
fenster"ubergreifend innerhalb einer Anwendung wird durch standardisierte 
Verfahren unterst"utzt.
Diese umfassen das Klemmbrett ({\em clipboard}) sowie das {\em drag and drop
protocol}. Das Klemmbrett dient als Zwischenspeicher f"ur Daten, von denen
Kopien (evtl. f"ur andere Anwendungen) angefordert werden k"onnen. {\em Drag and 
drop} ist ein verwandtes Verfahren, wobei der Benutzer Datenkopien durch
gleichzeitiges Dr"ucken einer Maustaste und Bewegung des Mauszeigers auf
ein Ziel anfordern kann. Loslassen der Maustaste beendet diesen Vorgang. 
\end{description}

        \subsection{Ereignisbearbeitung}

Bei Auftreten bestimmter Ereignisse werden von {\sf StarView}
benutzerdefinierte Funktionen ({\em event handler}) aufgerufen. 
Damit erh"alt der Benutzer die M"oglichkeit, programmtechnisch auf Ereignisse
zu reagieren und die Anwendung entsprechend zu steuern. Die Assoziation 
eines {\em event handler} mit einem Ereignis erfolgt in C++ entweder
durch "uberschreiben virtueller Funktionen oder durch einen speziellen, von 
{\sf StarView} zur Verf"ugung gestellten Mechanismus. Die Ereignisverarbeitung
mit Aufruf der jeweilig mit einem bestimmten Ereignis assoziierten
Funktion/Methode erfolgt durch das Fenstersystem selbst. In 
Abbildung~\ref{callback} auf Seite~\pageref{callback} wurde der Vorgang der 
Ereignisbearbeitung in Zusammenhang mit 
dem Tycoon {\em Callback}-Mechanismus veranschaulicht.


                \section{Durchf"uhrung der Anbindung}

In diesem Abschnitt wird der Einsatz des Gateway-Generators zur Anbindung
der {\sf StarView}-Bibliothek beispielhaft demonstriert. 
Konkretisiert auf diesen Anwendungsfall wird das Anbindungsszenario 
anhand von Abbildung \ref{sv-gateway} veranschaulicht.
\begin{figure}
\leavevmode
\def\epsfsize#1#2{0.9\textwidth}
\centerline{\epsffile{sv-gateway.epsf}}
\caption{\label{sv-gateway} Anbindungsszenario f"ur {\sf StarView}}
\end{figure}

Die Durchf"uhrung der Anbindung verl"auft dabei in drei Phasen:

\subsubsection{1. Erstellung der GDL-Schnittstellenbeschreibungen}

Die Klassendeklarationen von {\sf StarView} liegen in Form mehrerer 
{\em Header}-Dateien vor. Diese bilden die Grundlage zur Erstellung
der erforderlichen GDL-Spezifikationen zur Schnittstellengenerierung, wie
in Abschnitt \ref{sprachkonzepte} auf Seite \pageref{sprachkonzepte}ff 
beschrieben. Die Aufteilung der Klassen auf GDL-Dateien ist prinzipiell
frei w"ahlbar. Zu beachten ist jedoch, da"s wechselseitig rekursiv
definierte Klassen in derselben GDL-Spezifikation definiert werden, da Module 
in \TL\ nicht rekursiv definiert sein k"onnen. Ferner ist die M"oglichkeit von
Namenskonflikten je gr"o"ser, desto mehr Klassen in derselben Datei
spezifiziert werden, da Klassen in GDL keinen Namensraum darstellen. 
Ein Beispiel f"ur eine typische GDL-Spezifikation:
\newpage

\begin{samepage}
\begin{xple}
\kw{gateway} ''C++'' scrollBar :ScrollBar
\kw{import} window control resId range 
\kw{export}
   \kw{enum} ScrollType\{SCROLL\_DONTKNOW, SCROLL\_LINEUP, 
                 SCROLL\_LINEDOWN, SCROLL\_PAGEUP, SCROLL\_PAGEDOWN\}
 
  \kw{class} ScrollBar$=>$T : \kw{public} Control
  \{
      \kw{constructor} ScrollBar$=>$new(Window* pParent)
 
      \kw{virtual} void    Scroll()
      ...
      Range           ChangeRange(\kw{const} Range\& rRange$=>$r)
      Range           GetRange() \kw{const}
      ...
      ScrollType      GetType() \kw{const}
  \}
\kw{end}
\end{xple}
\end{samepage}

\subsubsection{2. Generierung}

Die Generierung der \TL-Module und -Schnittstellen sowie der
C++-Module erfolgt aufgrund des gro"sen Umfanges der Bibliothek
werkzeugunterst"utzt: 
Eingabedateien f"ur das {\sf Unix}-Werkzeug {\em make} werden aus den 
Import-Listen der GDL-Spezifikationen automatisch erzeugt. Eine 
GDL-Spezifikation kann erst dann "ubersetzt werden, wenn alle von ihr 
importierten Spezifikationen bereits "ubersetzt sind.

Vor der "Ubersetzung der generierten \TL-Module ist eine statische Beschreibung
der Bibliothek (\TL-Konstrukt {\em library}) zu erstellen, die 
Sichtbarkeitsbeziehungen
der beteiligten Module und Schnittstellen untereinander beschreibt. Auch diese 
kann aus den Import-Listen der GDL-Spezifikationen automatisch erzeugt werden.

Aus obiger GDL-Spezifikation wird folgende \TL-Schnittstelle generiert:

\begin{xple}
\kw{interface} ScrollBar
\kw{import} optional :Window link range resId window control
\kw{export} 
  ScrollType $<:$Int
  SCROLL\_DONTKNOW, SCROLL\_LINEUP, ... (* etc. *) SCROLL\_DRAG :ScrollType
  T $<:$control.T
  new(parent :optional.T(window.T)) :T
  scroll(self :T) :\kw{Ok}
  setScroll(self :T  scroll() :T) :\kw{Ok}
  getScroll(self :T) :\kw{Fun}() :T
  ...
  changeRange(self :T r :range.T) :range.T
  getRange(self :T) :range.T
  ...
  getType(self :T) :ScrollType
  deleteT(self :T) :\kw{Ok}
\kw{end}
\end{xple}

Zu dieser Schnittstelle geh"ort folgende Implementation:

\begin{xple}
\kw{module} scrollBar
\kw{import} optional :Window link range resId window control word cCallback
	    gdlObject
\kw{export} 
  \kw{let} lib = ''svenv/svenv'' (* wird vom Laufzeitsystem benutzt *) 
  
  \kw{Let} ScrollType = Int
  \kw{let} SCROLL\_DONTKNOW = 0  \kw{let} SCROLL\_LINEUP = 1 ... (* etc. *)

  \kw{Let} T = control.T 
  \kw{let} new = bind(:\kw{Fun}(parent :word.T) :T lib ''scrollBar\_new'' ''ww'')
  \kw{let} new(parent :optional.T(window.T)) :T =
    \kw{if} optional.null(parent) \kw{then} new(word.nil)
    \kw{else} new(optional.value(parent))
    \kw{end}
  \kw{let} scroll = (* Bindung an die Default-Implementation *) 
    bind(:\kw{Fun}(self :T) :\kw{Ok} lib ''scrollBar\_Scroll'' ''wv'')
  \kw{let} setScroll(self :T scroll() :\kw{Ok}) :\kw{Ok} = 
    gdlObject.setHandler(self ''scroll'' cCallback.new(scroll ''v''))
    (* Tr"agt den Callback in die globale Callback-Tabelle ein. *)
  \kw{let} getScroll(self :T) :\kw{Fun}() :\kw{Ok} = 
    cCallback.get(:\kw{Fun}() :\kw{Ok} gdlObject.getHandler(self ''scroll''))
    (* Extrahiert die Funktion, die in der Callback-Tabelle unter dem Namen
       ''scroll'' und dem Objekt 'self' gefunden wurde. *)
  ...
  \kw{let} changeRange = 
    bind(:\kw{Fun}(self :T r :range.T) :range.T lib ''scrollBar\_ChangeRange'' ''www'')
  \kw{let} getRange = bind(:\kw{Fun}(self :T) :range.T lib ''scrollBar\_GetRange'' ''ww'')
  ...
  \kw{let} getType = bind(:\kw{Fun}(self :T) :ScrollType lib ''scrollBar\_GetType'' ''wi'')
  \kw{let} deleteT = bind(:\kw{Fun}(self :T) :\kw{Ok} lib ''scrollBar\_deleteT'' ''wv'')
  
  (* benutzte "Parameter"ubergabemodi:
       Format   C-Typ   TL-Typ
       -------------------------------------------
       w        void*   32-Bit-Wort
       i          long    Int
       v         void    Ok (nur als R"uckgabewert)
   *)
\kw{end}
\end{xple}

Die in der Implementation benutzten C-Funktionen werden folgenderma"sen
generiert:
\begin{xple}
/* scrollBar.cxx */ 
 
\kw{class} TyScrollBar : \kw{public} ScrollBar
\{
\kw{public}:
  TyScrollBar(Window* pParent) : ScrollBar(pParent) \{\};

  \kw{typedef} \kw{void} (*scrollFunc)();
  ... /* folgen Typdefinitionen f"ur Funktionspointer der geerbten virtuellen 
           Funktionen */

  \kw{virtual} \kw{void} Scroll() 
  \{ 
    scrollFunc scroll;
    scroll = (scrollFunc) gdlobj\_getHandler(\kw{this}, ''scroll'');
    /* Aufsuchen der Callback-Funktion aus der globalen Callback-Tabelle */
    \kw{if} (scroll) \kw{return} (*scroll)();
    \kw{else return} ScrollBar::Scroll(); 
  \};
  ... /* folgen Redefinitionen f"ur alle geerbten virtuellen Funktionen */
\};
\kw{extern} ''C'' TyScrollBar* scrollBar\_new(Window* pParent) \{ 
  \kw{return new} TyScrollBar(pParent); 
\}
\kw{extern} ''C'' \kw{void} scrollBar\_Scroll(ScrollBar* self) \{
  self$->$ScrollBar::Scroll();
\}
...
\kw{extern} ''C'' Range* scrollBar\_ChangeRange(ScrollBar* self, Range* rRange) \{ 
  \kw{return new} Range(self$->$ChangeRange(*rRange)); 
\}
\kw{extern} ''C'' Range* scrollBar\_GetRange(ScrollBar* self) \{ 
  \kw{return new} Range(self$->$GetRange()); 
\}
...
\kw{extern} ''C'' ScrollType scrollBar\_GetType(ScrollBar* self) \{ 
  \kw{return} self$->$GetType(); 
\}
\kw{extern} ''C'' \kw{void} scrollBar\_deleteT(ScrollBar* self) \{ 
  \kw{delete} self; 
\}
\end{xple}

\subsubsection{3. "Ubersetzung}

Die "ubersetzten C++-Module werden in einer {\em shared dynamic link library}
(DLL) zusammengefa"st. Aus den der {\em bind}-Primitive "ubergebenen Parametern 
(Funktionsname, Bibliotheksname, Parameterformate) kann das Laufzeitsystem
entsprechende Aufrufe an die DLL erzeugen, ohne da"s es selbst
ge"andert werden mu"s. Schlie"slich werden die \TL-Module anhand der
Bibliotheksspezifikation ({\sl library}-Konstrukt) "ubersetzt.

"Anderungen an GDL-Spezifikationen erfordern einen erneuten Durchlauf dieser
Phasen. Eine erneute "Ubersetzung der abh"angigen \TL-Schnittstellen und
-Module ist nur dann notwendig, wenn sich die Klassenhierarchie "andert.
Alle anderen "Anderungen, z.B. die Erweiterung von Signaturen, machen, im 
Gegensatz zu "`normalen"' \TL-Modulen, keine
Neu"ubersetzung der abh"angigen Module notwendig, da exportierte Funktionen 
lediglich ihre Parameter an den externen Diensterbringer weiterleiten und
niemals \TL-Funktionen aufrufen. Die Modulverwaltung unterscheidet jedoch nicht
zwischen Modulen, die externe Funktionalit"at benutzen und solchen, die dies
nicht tun, so da"s eine Neu"ubersetzung gem"a"s den normalen
Abh"angigkeitsregeln trotzdem vorgenommen wird.


\subsubsection{Multi-Threading}

GUI-Anwendungen verlaufen "ublicherweise nach folgendem Schema:
\begin{itemize}
\item Festlegung der statischen Struktur der grafischen Interaktionselemente
(Men"us, Dialog, Arbeitsfenster etc.),
\item Definition der {\em event handler},
\item Start der Ereignisverarbeitung.
\end{itemize}
Nach dem Starten der Ereignisverarbeitung sind, trotz der M"oglichkeit zur
inkrementellen "Ubersetzung, Programm"anderungen nicht durchf"uhrbar, ohne
die Anwendung zu verlassen, da sich "Anderungen nur bei gestarteter
Ereignisverarbeitung auswirken.

Durch die M"oglichkeit in Tycoon, mehrere Kontrollfl"usse 
({\em threads of control}) auf demselben Zustand operieren zu lassen 
\cite{MaSc94}, l"a"st sich dieser Nachteil ausgleichen. Die Ereignisverwaltung
({\em event loop}) wird dazu in einem eigenst"andigen {\em thread} gestartet,
dem {\em event loop thread}. 
In einem parallel zum {\em event loop thread} laufenden {\em thread} (z.B.
dem \TL\ {\em top level}) kann dann
durch inkrementelle "Ubersetzung die Applikation dynamisch modifiziert werden,
wobei die Auswirkungen dieser "Anderungen sofort sichtbar und testbar sind.
%## Beispielsitzung

Diese Funktionalit"at macht die interaktive Erzeugung von 
Benutzerschnittstellen potentiell komfortabler als bei herk"ommlichen 
Werkzeugen ({\em interface builder}, z.B. {\sf SUN's} {\em Developer's 
Graphical User Interface Design Editor} \cite{Sun92} oder dem {\em Design 
Editor} von {\sf Star Division} \cite{StarView93}), da
auch die Funktionalit"at der {\em event handler} iterativ entwickelt und
getestet werden kann. Diese Eigenschaft ist deshalb so wertvoll, weil der
weitaus gr"o"ste Teil des Programmcodes von Anwendungen mit grafischer
Benutzerschnittstelle eine Reaktion auf Ereignisse darstellt. 
Zu einer kompletten {\em visuellen Programmierumgebung}
wie z.B. {\sf VisualBASIC} \cite{MD93} fehlt jedoch noch grafische 
Unterst"utzung zur direkten Manipulation von GUI-Elementen, z.B. zur
Erzeugung und Positionierung von Kn"opfen, Men"us und Dialogen. 

Gegenstand zuk"unftiger Projekte k"onnte der Aufbau
einer visuellen Entwicklungsumgebung f"ur Prototypen datenintensiver
Anwendungen sein, aufbauend auf vorhandenen Diensten 
({\sf StarView}-Gateway, {\em persistent threads}). 
Dabei w"are zu erforschen, inwieweit sich diese Form der
(semi-)\-visuellen Programmierung f"ur das {\em prototyping} von Anwendungen 
eignet und wie sie in das bisherige Spektrum der Werkzeuge f"ur Sprachen
der vierten Generation (z.b. {\sf INGRES~4GL} \cite{ingres}) einzuordnen ist.


