%% LyX 1.5.4 created this file.  For more info, see http://www.lyx.org/.
%% Do not edit unless you really know what you are doing.
\documentclass[a4paper,twocolumn,ngerman]{article}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\setlength{\parskip}{\medskipamount}
\setlength{\parindent}{0pt}
\usepackage{url}
\usepackage{graphicx}

\makeatletter
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Textclass specific LaTeX commands.
\newenvironment{lyxcode}
{\begin{list}{}{
\setlength{\rightmargin}{\leftmargin}
\setlength{\listparindent}{0pt}% needed for AMS classes
\raggedright
\setlength{\itemsep}{0pt}
\setlength{\parsep}{0pt}
\normalfont\ttfamily}%
 \item[]}
{\end{list}}

\usepackage{babel}
\makeatother

\begin{document}

\title{Widgets zum Anfassen - GUI-Skripting mit Forth und GTK\texttt{+}}
\ifx\shorttitle\undefined\else
\shorttitle{Widgets zum Anfassen}
\fi

\author{Manfred Mahlow}

% (manfred.mahlow@forth-ev.de)

\maketitle
PC, Laptop, Notebook, PDA - grafische Oberflächen überall. Da kommt
früher oder später der Wunsch auf, schnell mal eine (einfache) grafische
Benutzerschnittstelle (GUI) für ein kleines Tool oder für die Anzeige
von Daten schreiben zu können, wie das z.B. mit der Skriptspache TCL/TK
möglich ist. Aber, es sollte eben mit Forth möglich sein, mit möglichst
kompakter \emph{forthiger} Syntax.

\begin{multicols}{2}

Das war der Ausgangspunkt als ich begann, mir Gedanken über GUI-Programmierung
mit Forth zu machen. Ein erstes Ergebnis, eine Programmierschnittstelle
(API) für das GTK\texttt{+}-Toolkit, habe ich auf der Jahrestagung
2008 der Forth-Gesellschaft vorgestellt.


\section*{Warum GTK\texttt{+} ?}

GTK\texttt{+} ist ein weit verbreitetes GUI-Toolkit, das für Linux
und Windows verfügbar ist. Es ist die Basis für den GNOME- und den
XFCE-Desktop, wird für Fenstermanager und viele Applikationen verwendet
und ist auch auf PDAs zu finden.

GTK\texttt{+} hat ein objektorientiertes Design, ist aber in C geschrieben
und kann relativ leicht in andere Programmiersprachen eingebunden
werden, so auch in Forth.


\section*{Eine GTK\texttt{+}-API für Forth}

Die Implementierung der GTK\texttt{+}-API orientiert sich an folgenden
Leitlinien:

\begin{enumerate}
\item Für eine erste Implementierung sollte ein möglichst kleines 32 Bit
Forth System für Linux verwendet werden, leicht zu verstehen und leicht
zu ändern.
\item Die Implementierung sollte objektorientiert erfolgen, mit möglichst
kompakter \emph{forthiger} Syntax.
\item Da das GTK\texttt{+}-Toolkit sehr umfassend ist, wird eine modulare
Struktur der API angestrebt.
\item GTK\texttt{+}-Basisfunktionen und GTK\texttt{+}-Klassen werden als
Quelltextmodule implementiert, die bei Bedarf geladen werden können.
\item Pro GTK\texttt{+}-Klasse wird nur eine kleine Teilmenge der Instanzvariablen
und Methoden implementiert, die für einfache Anwendungen ausreicht.
Weitere Instanzvariablen und Methoden können später hinzugefügt werden,
wenn sie für eine Applikation tatsächlich benötigt werden.
\item Klassen, Instanzvariablen und Methoden erhalten in Forth, soweit sinnvoll,
die gleichen Namen, wie in C. 
\item Das Klassen-Präfix von Methodennamen wird in Forth wegen der objektorientierten
Implementierung weggelassen.
\item Die GTK\texttt{+} Methoden \_get und \_set werden in Forth auf fetch
(@) und store (!) abgebildet. 
\end{enumerate}

\section*{Ein Forth für die GTK\texttt{+}-API}

Auf der Suche nach einem möglichst kleinen leicht zu verstehenden
und leicht zu ändernden 32 Bit Forth System für Linux bin ich auf
Reva Forth von Ron Aron gestoßen, das weitgehend meinen Vorstellungen
entsprach. 

Aus Reva 6.0 habe ich dann cspForth abgeleitet, ein Testsystem für
OOP mit Forth. Es unterstützt - wie Reva 6.0 - das bedarfsabhängige
Laden von Quelltextmodulen, das Importieren von Funktionen aus Shared
Libraries sowie das Speichern des jeweiligen Systemzustands als ausführbare
Datei. 

Darüber hinaus hat cspForth zwei besondere Eigenschaften, durch die
es sich von den meisten anderen Forth Systemen unterscheidet:

\begin{enumerate}
\item cspForth unterstützt zwei Suchreihenfolgen, die bekannte Suchreihenfolge
für Vokabulare und Wortlisten und eine zusätzliche Suchreihenfolge
für Klassen, Objekte und Schnittstellen.
\item cspForth unterstützt Preludes. Ein Prelude ist ein Forth-Wort, das
einem anderen Forth-Wort so zugeordnet ist, dass es im Ausführungsmodus
oder im Compilermodus ausgeführt wird, bevor das Wort, dem es zugeordnet
ist, selbst ausgeführt oder compiliert wird.
\end{enumerate}
Diese beiden Eigenschaften sind die Basis für eine als Quelltextmodul
ladbare OOP-Erweiterung, die \emph{Context Switching Preludes} verwendet,
um Objekte mit den Instanzvariablen und Methoden ihrer Klasse zu verbinden:

\begin{itemize}
\item Einem Objekt wird seine Klasse als Prelude zugewiesen. Wenn diese
ausgeführt wird, erzeugt und aktiviert sie eine klassenspezifische
Suchreihenfolge, die den Zugriff auf die Instanzvariablen und Methoden
freigibt.
\item Die Instanzvariablen einer Klasse sind selbst wieder Objekte einer
Klasse, mit dem gerade beschriebenen Verhalten.
\item Die Methoden einer Klasse haben ein anderes Verhalten. Einer Methode
wird ein Prelude zugewiesen, das die klassenspezifische Suchreihenfolge,
in der die Methode gefunden wird, wieder deaktiviert (oder ändert).
\item Standard-Suchreihenfolge ist die Suchreihenfolge für Vokabulare und
Wortlisten.
\end{itemize}

\section*{Stand der Implementierung}

Die meisten einfachen Widget-Klassen des GTK\texttt{+}-Toolkits sind
bereits implementiert und zu fast jeder Klasse gibt es mindestens
ein Anwendungsbeispiel (siehe Abbildung \ref{fig:Beispiele-einfacher-GtkWidgets}).
Weitere Widget-Klassen werden nach und nach implementiert. Ein Tutorium
und Hilfetexte für die bereits implementierten Klassen sollen erstmal
Vorrang haben.


\section*{Von C nach Forth - Ein Beispiel}

Für das \emph{Hello World Beispiel} aus dem GTK\texttt{+}-Tutorium
ist im Listing~1 der Forth-Code dem C-Code gegenüber gestellt. Der
Forth-Code ist mit cspForth ausführbar und erzeugt das GUI der Abbildung~\ref{fig:HelloWorld}.
Der C-Code ist als Kommentar enthalten.

%
\begin{figure*}[tbh]
\begin{center}
\includegraphics{2008-02/Abbildung1sw}

\caption{\label{fig:HelloWorld} Der Hello-World--Dialog}
\end{center}
\end{figure*}


Der C-Code beginnt in Zeile 3 mit einer include-Anweisung, welche
die GTK+-Bibliotheken einbindet.

Auch in Forth werden die GTK\texttt{+}-Bibliotheken verwendet. Ihre
Funktionen werden durch Laden der benötigten GTK\texttt{+}-Klassen
importiert (Zeilen 5,6), die als Quelltextmodule implementiert sind.

Für das Beispiel werden die Klassen \emph{GtkWindow}, für das Hauptfenster
der Anwendung, und \emph{GtkButton}, für den Knopf, benötigt.

Zeile 7 legt fest, dass nachfolgende Definitionen zum Vokabular \emph{oop}
hinzugefügt werden. Das Vokabular \emph{gtk api} - es enthält die
Wörter der GTK\texttt{+}-Schnittstelle - wird in die Suchreihenfolge
aufgenommen und es wird die Zahlenbasis festgelegt.

GUI-Programme sind durch Ereignisse gesteuerte Programme. Wenn ein
(bekanntes) Ereignis eintritt, wird ein bestimmter Programmcode ausgeführt. 

In GTK\texttt{+} ist dieser Mechanismus durch Signale und Signal-Handler
(ausführbarer Code) implementiert, die an GtkWidgets gebunden werden.
Trifft ein Signal ein, das mit einem Signal-Handler verknüpft wurde,
wird dieser von GTK\texttt{+} mit definierten Parametern aufgerufen.

Im betrachteten Beispiel soll auf die Ereignisse \emph{Anwendungsfenster
schließen} und \emph{Hello World Knopf gedrückt} reagiert werden.
Dazu müssen zwei Signal-Handler definiert werden.

In C werden sie als Funktionen des Typs static void definiert, in
Forth als normale Forth Wörter, die dann einem Callback-Handler zugewiesen
werden, der sie im Hintergrund (mit eigenem Stack) ausführt.

In Zeile 16 wird der Signal-Handler für den Knopf definiert und dem
Callback-Handler \emph{cb.hello} zugewiesen, der ihn mit zwei Parametern
und einer Stacktiefe von 20 im Hintergrund ausführen wird.

Ganz analog wird in Zeile 25 ein Callback-Handler \emph{cb.destroy}
definiert, der beim Schließen des Anwendungsfensters ausgeführt werden
soll. Er ruft dann die Funktion \emph{gtk~quit} auf (gtk\_main\_quit
in C).

In Zeile 29 beginnt die Hauptfunktion des C-Programms. Bevor das GTK\texttt{+}-Toolkit
verwendet werden kann, muss es initialisiert werden. In C erledigt
das die Funktion gtk\_init (Zeile 31). In Forth erfolgt die Initialisierung
im Hintergrund, wenn die GTK\texttt{+}-API (\emph{gtk api}) geladen
wird.

In C wird auf GtkWidgets über Zeiger zugegriffen (Zeile 32,33). In
Forth treten an die Stelle der Zeiger Objekte der jeweiligen Widget-Klasse.
Für das Hauptfenster des Beispiels wird ein Objekt der Klasse GtkWindow
erzeugt (Zeile 35) und für den Knopf ein Objekt der Klasse GtkButton
(Zeile 36).

In Analogie zur Struktur des C-Codes fassen wir auch den Forth-Code
zu einer Funktion (zu einem Wort) zusammen (Zeile 39).

In Zeile 47 wird das in Zeile 35 erzeugte Objekt \emph{window} initialisiert.
Die \emph{init}-Methode erzeugt ein \emph{GtkWindow} vom Typ GTK\_WINDOW\_TOPLEVEL
als Hauptfenster des Programms und weist dessen Adresse - in Forth
\emph{widget identifier (wid)} genannt - dem Objekt zu. 

In Zeile 48 werden das \emph{destroy}-Signal und der Callback-Handler
\emph{cb.destroy} an das Hauptfenster \emph{window} gebunden. Damit
wird festgelegt, das der Callback-Handler \emph{cb.destroy} (Zeile
25) ausgeführt wird, wenn das Fenster ein destroy-Signal erhält. GTK\texttt{+}
legt dann den \emph{widget identifier (wid)} des Fensters und einen
Datenzeiger (hier 0) auf den Stack des Callback-Handlers. Beide werden
hier vom Signal-Handler aber nicht verwendet. Die \emph{signal~connect}-Methode
übergibt einen Identifier auf dem Datenstack, der hier nicht gebraucht
wird.

Zeile 54 ist ein Beispiel für den Zugriff auf eine Instanzvariable
eines GtkWidgets. Die Breite des inneren Rands des Hauptfensters wird
auf 10 Pixel gesetzt.

Der entsprechende C-Code in Zeile 52 mag im Vergleich etwas verwirrend
sein, da auf das Hauptfenster vom Typ \emph{GtkWindow} mit einer Methode
der Klasse \emph{GtkContainer} zugegriffen wird. Das liegt daran,
dass die Instanzvariable \emph{border-width} nicht in der Klasse GtkWindow
sondern in der Klasse GtkContainer definiert ist.

Logisch erbt die Klasse GtkWindow von der Klasse GtkContainer. Da
sich diese Vererbung aber in C nicht direkt abbilden lässt, muss eine
Typumwandlung erfolgen und die Methodennamen müssen mit einem Klassen-Präfix
versehen werden.

In C muss ein Programmierer also immer die GTK\texttt{+}-Klassenhierarchie
beachten und die notwendigen Typumwandlungen und Methodenzuweisungen
selbst vornehmen.

In Forth ist das einfacher. Die GTK\texttt{+}-Klassenhierarchie wurde
hier bereits bei der objektorientierten Implementierung der API berücksichtigt.
So erbt z.B. die Klasse GtkWindow auch alle Instanzvariablen und Methoden
der Klasse GtkContainer. 

In Zeile 63 wird das in Zeile 36 erzeugte Objekt \emph{button} initialisiert.
Die \emph{init}-Methode erzeugt einen \emph{GtkButton} mit der Beschriftung
\emph{Hallo World}, weist dessen Adresse - in Forth \emph{widget identifier
(wid)} genannt - dem Objekt zu und übergibt sie außerdem auf dem Stack.
Die Phrase \emph{window add} findet die Adresse auf dem Stack und
packt den adressierten GtkButton in das Hauptfenster.

In der Zeile 64 werden das \emph{clicked}-Signal und der Callback-Handler
\emph{cb.hello} an den GtkButton gebunden. So wird festgelegt, das
der Callback-Handler \emph{cb.hello} (Zeile 16) ausgeführt wird, wenn
der GtkButton mit der Maus oder mit der Eingabetaste aktviert wird.
GTK\texttt{+} übergibt dann den \emph{widget identifier (wid)} des
GtkButton und einen Datenzeiger (hier 0) an den Callback-Handler.
Beide werden hier vom Signal-Handler aber nicht verwendet.

Alle GtkWidgets sind nun erzeugt aber noch nicht zu sehen. Sie werden
durch den Code in Zeile 70 sichtbar gemacht.

Die Methode \emph{show all} ist in der Klasse \emph{GtkWidget} definiert.
Sie macht das angegebene Widget und alle darin enthaltenen Widgets
sichtbar. In Forth erbt die Klasse GtkWindow diese Methode von der
Klasse GtkWidget. In C muss wieder eine Typumwandlung erfolgen und
dem Methodennamen muss das Klassen-Präfix vorangestellt werden(Zeile
68).

Mit den Zeilen 74 bis 76 wird der C-Code abgeschlossen. gtk\_main
ist die GTK\texttt{+}-Hauptschleife, die auf Ereignisse wartet und
dann den zugeordneten Code ausführt. Sie wird erst dann verlassen,
wenn die Funktion gtk\_main\_quit ausgeführt wird. Das geschieht durch
den in Zeile 20 definierten Signal-Handler destroy, der ausgeführt
wird, wenn das Hauptfenster geschlossen wird. Das C-Programm gibt
dann die Kontrolle an die aufrufende Ebene zurück.

Der entsprechend Forth-Code folgt in den Zeilen 78 u. 79, allerdings
mit abweichender Funktion:

Wenn der cspForth-Prozess, der den Forth-Code ausführt, in einem Terminal
gestartet wurde, muss keine GTK\texttt{+}-Hauptschleife aufgerufen
werden, weil die Ereignisverarbeitung dann im Hintergrund erfolgt,
während auf die Eingabe einer Kommandozeile gewartet wird. 

Wird der cspForth-Prozess nicht in einem Terminal gestartet, z.B.
weil der Forth-Code per \emph{Drag and Drop} direkt an cspForth übergeben
wird, erfolgt keine Ereignisverarbeitung im Hintergrund. Dann muss
auch in Forth explizit eine GTK\texttt{+}-Hauptschleife gestartet
werden. Der Code in Zeile 78 stellt das sicher.

In Zeile 81 wird nun das gerade definierte Forth-Wort main ausgeführt.
Es erzeugt und initialisiert die Widgets und stellt, wie gerade beschrieben,
die Ereignisverarbeitung sicher. 

Die nachfolgende Phrase \emph{oop ??} ist nur relevant, wenn der cspForth-Prozess
in einem Terminal gestartet wurde. Sie zeigt dann das Vokabular \emph{oop}
und den aktuellen Systemzustand im Terminal an (siehe Abbildung \ref{fig:Listing-1 geladen})
und wir können interaktiv auf die GtkWidgets zugreifen - Widgets zum
Anfassen.

%
\begin{figure*}[tbh]
\begin{minipage}[b]{0.5\textwidth}
\begin{center}
\includegraphics[scale=0.45]{2008-02/Abbildung2sw}

\caption{\label{fig:Listing-1 geladen}Status nach dem Laden von Listing 1}
\end{center}
\end{minipage}
%\end{figure*}
%
%\begin{figure*}[tbh]
\begin{minipage}[b]{0.5\textwidth}
\begin{center}
\includegraphics[scale=0.45]{2008-02/Abbildung3sw}

\caption{\label{fig:Klassenhierarchie-des-Hauptfensters}Klassenhierarchie
des Hauptfensters}
\end{center}
\end{minipage}
\end{figure*}


In Forth ist ein GtkWidget ein Objekt. Im interaktiven Modus aktiviert
ein Objekt seine klassenspezifische Suchreihenfolge (seine Klasenhierarchie)
und übergibt seinen Identifier (oid) auf dem Datenstack. Mit der Methode
??? kann man sich beide anzeigen lassen (Abbildung \ref{fig:Klassenhierarchie-des-Hauptfensters}).



Man kann also sehen, über welche Instanzvariablen und Methoden auf
ein Objekt zugegriffen werden kann und man kann das auch tun!

\emph{Hinweis: Mit dem Wort .. kann man einen Klassenkontext wieder
verlassen.}

Also fröhliches Experimentieren, aber vorher besser die cspForth README-Datei
lesen.

Es gibt auch eine kontextsensitive Hilfefunktion. Mit h <name> kann
man sich den Glossary-Eintrag für das Worte <name> anzeigen lassen,
vorausgesetzt, ein Glossary-Eintrag wurde bereits geschrieben, was
noch nicht für alle Wörter der GTK\texttt{+}-API der Fall ist.

Zur Jahrestagung 2008 der Forth-Gesellschaft hatte ich einen Entwicklungsschnappschuss
zusammengestellt, mit dem man in die GTK\texttt{+}-Programmierung
mit Forth einsteigen kann. Das cspForth System mit der GTK\texttt{+}-API
kann vom Wiki der Forth-Gesellschaft heruntergeladen werden. Kommentare,
Anregungen, Kritik aber auch Mitarbeit sind sehr willkommen.

Das Beispiel mag den Eindruck vermittelt haben, dass man für die GUI-Programmierung
mit Forth auch mit C vertraut sein muss. Das ist aber nicht generell
der Fall. Soweit alle benötigten GTK\texttt{+}-Klassen in Forth bereits
implementiert sind, muss man sich mit C nicht befassen. Nur wenn man
die API erweitern will oder C-Beispiele übernehmen möchte, muss man
sich mit dem Zusammenhang von C und Forth befassen.

Entfernt man den C-Code aus Listing 1 bleibt das sehr überschaubare
Listing 2 über.


\section*{Wie soll es weitergehen?}

Im Wiki der Forthgesellschaft werde ich ein Projekt für die GTK\texttt{+}-Programmierung
mit Forth einrichten. Dort werde ich ein Tutorium, weitere Beispiele
und dann und wann einen neuen Entwicklungsschnappschuss veröffentlichen.

Weiter wäre es interessant, die GTK\texttt{+}-API auch für andere
Forth Systeme zu implementieren, z.B. für ein in C implementiertes
Forth, das nicht nur auf PC-Systemen läuft (der cspForth-Kern ist
in Assembler geschrieben und damit nicht so einfach auf andere Prozessoren
zu portieren). Ich denke dabei an PDAs, wie z.B. das Nokia N810. Wer
hat daran Interesse?



\begin{thebibliography}{1}
\bibitem{key-16}GTK\texttt{+} Dokumentation. \url{http://www.gtk.org}

\bibitem{key-17}Matthias Warkus: GNOME 2.0 - Das Entwickler-Handbuch.
Galileo Press GmbH, 2003

\end{thebibliography}
\end{multicols}
% \onecolumn

%
\begin{figure*}[tbh]
\begin{center}
\includegraphics[scale=0.45]{2008-02/Beispiele-sw}

\caption{\label{fig:Beispiele-einfacher-GtkWidgets}Beispiele implementierter
GtkWidgets}
\end{center}
\end{figure*}


% \appendix

\subsection*{Listing 1:}

\begin{lyxcode}
~1~~~\textbackslash{}~Listing~1:~GTK+-Beispiel~\char`\"{}Hello~World\char`\"{}~in~C~und~Forth

~2

~3~~~\textbackslash{}~\#include~<gtk/gtkh>

~4

~5~~~needs~GtkWindow

~6~~~needs~GtkButton

~7~~~oop~definitions~gtk~api~decimal

~8

~9

10

11~~~\textbackslash{}~static~void~hello(~GtkWidget~{*}widget,~gpointer~data~)

12~~~\textbackslash{}~\{

13~~~\textbackslash{}~g\_print~(\char`\"{}Hello~World\textbackslash{}n\char`\"{});

14~~~\textbackslash{}~\}

15

16~~~::~(~wid~data~-{}-~)~.\char`\"{}~Hello~World\char`\"{}~cr~;~~2~20~cb~cb.hello

17

18

19

20~~~\textbackslash{}~static~void~destroy(~GtkWidget~{*}widget,~gpointer~data~)

21~~~\textbackslash{}~\{

22~~~\textbackslash{}~gtk\_main\_quit~();

23~~~\textbackslash{}~\}

24

25~~~::~(~wid~data~-{}-~)~gtk~quit~;~~2~20~cb~cb.destroy

26

27

28

29~~~\textbackslash{}~int~main(~int~argc,~char~{*}argv{[}]~)

30~~~\textbackslash{}~\{

31~~~\textbackslash{}~gtk\_init~(\&argc,~\&argv);

32~~~\textbackslash{}~GtkWindow~{*}window;

33~~~\textbackslash{}~GtkButton~{*}button;

34

35~~~GtkWindow~new~window

36~~~GtkButton~new~button

38

39~~~:~main~(~-{}-~)

40~

41

42

43~~~\textbackslash{}~window~=~gtk\_window\_new~(GTK\_WINDOW\_TOPLEVEL);

44~~~\textbackslash{}~g\_signal\_connect~(G\_OBJECT~(window),~\char`\"{}destroy\char`\"{},

45~~~\textbackslash{}~G\_CALLBACK~(destroy),~NULL);

46

47~~~~~GTK\_WINDOW\_TOPLEVEL~window~init

48~~~~~\char`\"{}~destroy\char`\"{}~cb.destroy~0~window~signal~connect~drop

49

50

51~

52~~~\textbackslash{}~gtk\_container\_set\_border\_width~(GTK\_CONTAINER~(window),~10);

53

54~~~~~10~window~border-width~!

55

56

57

58~~~\textbackslash{}~button~=~gtk\_button\_new\_with\_label~(\char`\"{}Hello~World\char`\"{});

59~~~\textbackslash{}~gtk\_container\_add~(GTK\_CONTAINER~(window),~button);

60~~~\textbackslash{}~g\_signal\_connect~(G\_OBJECT~(button),~\char`\"{}clicked\char`\"{},

61~~~\textbackslash{}~G\_CALLBACK~(hello),~NULL);

62

63~~~~~\char`\"{}~Hello~World~\char`\"{}~button~init~window~add

64~~~~~\char`\"{}~clicked\char`\"{}~cb.hello~0~button~signal~connect~drop

65

66

67

68~~~\textbackslash{}~gtk\_widget\_show\_all~(window);

69

70~~~~~window~show~all

71

72

73

74~~~\textbackslash{}~gtk\_main~();

75~~~\textbackslash{}~return~0;

76~~~\textbackslash{}~\}

77

78~~~~~term?~0if~gtk~main~bye~then

79~~~;

80

81~~~main~~oop~??


\end{lyxcode}

\subsection*{Listing 2:}

\begin{lyxcode}
~1~~~\textbackslash{}~Listing~2:~~Gtk+-Beispiel~\char`\"{}Hello~World\char`\"{}~in~Forth

~2

~3~~~needs~GtkWindow

~4~~~needs~GtkButton

~5~~~

~6~~~oop~definitions~~gtk~api~~decimal

~7

~8~~~::~(~wid~data~-{}-~)~.\char`\"{}~Hello~World\char`\"{}~cr~;~~2~20~cb~cb.hello

~9

10~~~::~(~wid~data~-{}-~)~gtk~quit~;~~2~20~cb~cb.destroy

11

12~~~GtkWindow~new~window

13~~~GtkButton~new~button

14

15~~~:~main~(~-{}-~)

16~~~~~~~GTK\_WINDOW\_TOPLEVEL~window~init

17~~~~~~~\char`\"{}~destroy\char`\"{}~cb.destroy~0~window~signal~connect~drop

18~~~~~~~10~window~border-width~!

19~~~~~~~\char`\"{}~~Hello~World~\char`\"{}~button~init~~window~add

20~~~~~~~\char`\"{}~clicked\char`\"{}~cb.hello~0~button~signal~connect~drop

21~~~~~~~window~show~all

22~~~~~~~term?~0if~~gtk~main~bye~~then

23~~~;

24

25~~~main~~oop~??~


\end{lyxcode}


\end{document}
