123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591 |
- \documentclass[10pt]{article}
- \usepackage{a4}
- \usepackage{epsfig}
- \usepackage{listings}
- \lstset{language=Delphi}%
- \lstset{basicstyle=\sffamily\small}%
- \lstset{commentstyle=\itshape}%
- \lstset{keywordstyle=\bfseries}%
- \lstset{blankstring=true}%
- \newif\ifpdf
- \ifx\pdfoutput\undefined
- \pdffalse
- \else
- \pdfoutput=1
- \pdftrue
- \fi
- \begin{document}
- \title{Programming GTK in Free Pascal}
- \author{Florian Kl\"ampfl\\and\\Micha\"el Van Canneyt}
- \date{July 2000}
- \maketitle
- \section{Introduction}
- The GTK library is a popular widget library for the X-Windows system.
- It is used as the basis for the GIMP graphical manipulation program
- and for the GNOME application framework. With its ports to Microsoft
- Windows and BeOS, it allows to program a graphical interface for any
- application in a platform independent way.
- GTK is implemented in C, but it is possible to access its functionality from
- Free Pascal. For this, its headers have been translated to Pascal,
- so a program written in Free Pascal can make use of the functionality
- offered by GTK and its companion libraries GDK and GLIB. In fact, there is
- an open source project (Lazarus) which makes use of GTK in order to build
- an open-source alternative to the visual classes offered by Inprise's
- Delphi.
- This article intends to present an introduction to programming GTK in
- Free Pascal. It by no means covers all of the functionality that GTK
- offers, as this would probably require a complete manual.
- The first section gives some general considerations on the GTK toolkit.
- \section{GTK is a C library}
- Since GTK is an external library, some import units describing the calls in
- the libraries are needed. Three libraries make up the GTK programming kit:
- \begin{description}
- \item[glib] this library contains some general programming tools, and
- defines platform independent types, which are used throughout the other
- libraries. To use this library, it is sufficient to include the
- \lstinline|glib| unit in your \lstinline|uses| clause.
- \item[gdk] encapsulates the Windowing system (X or Windows) underlying GTK.
- It contains routines to draw on the screen, and react to various mouse or
- keyboard events. To use these
- routines, the \lstinline|gdk| unit must be included in the \lstinline|uses|
- clause of a unit or program.
- \item[gtk] contains the widget library. This is a series of controls such
- as edit boxes, drop-down lists and many more, which are organised in an OOP
- structure. Since the library is written in C, there is no programming
- language support for this structure.
- All definitions of the gtk library are contained in the gtk unit, which
- must be included in the \lstinline|uses| clause of any program or unit that needs their
- functionality.
- \end{description}
- The GTK toolkit was programmed in C. This has some consequences for the
- Pascal interface, since some C constructs do not port easily to Pascal.
- When using the Pascal translation of the C headers, the following must be
- kept in mind:
- \begin{enumerate}
- \item Reserved words: Pascal reserved words in types, record element names
- etc. have been prepended with the word 'the'. For example \lstinline|label|
- becomes \lstinline|thelabel|.
- \item Functions and procedures have been kept with the same names.
- \item Types have been prepended with T, that is, the C type
- \lstinline|GtkWidget| has become \lstinline|TGtkWidget|.
- \item Pointers to types have been defined as the type name, prepended with a
- P. \lstinline|GtkWidget *| becomes \lstinline|PGtkWidget|.
- \item Records with bit-size elements: C allows to store parts of a record in
- individual bits; whereas in Pascal, the minimum size of an element in a
- record is a byte. To accommodate this, functions were defined to retrieve
- or set single bits from a record. The functions to retrieve a bit
- have the name of the record field. The procedure to set a bit has
- the name of the field prepended with 'set\_'.
- For example
- \begin{lstlisting}[language=c]{cpackedstruct}
- struct SomeStruct
- {
- gchar *title;
- guint visible : 1;
- guint resizeable : 1;
- };
- \end{lstlisting}
- translates to
- \begin{lstlisting}{ppackedstruct}
- TSomeStruct = record
- title : Pgchar;
- flag0 : word;
- end;
- function visible(var a: TGtkCListColumn): guint;
- procedure set_visible(var a: TGtkCListColumn; __visible: guint);
- function resizeable(var a: TGtkCListColumn): guint;
- procedure set_resizeable(var a: TGtkCListColumn;__resizeable: guint);
- \end{lstlisting}
- \item Macros. Many C macros have not been translated. The typecasting
- macros have been dropped, since they're useless under Pascal.
- Macros to access record members have been translated, but they are to be
- considered as {read-only}. So they can be used to retrieve a value, but
- not to store one. e.g.
- \begin{lstlisting}{macro}
- function GTK_WIDGET_FLAGS(wid : pgtkwidget) : longint;
- \end{lstlisting}
- can be used to retrieve the widget flags, but not to set them. so things like
- \begin{lstlisting}{invaliduseofmacro}
- GTK_WIDGET_FLAGS(wid):=GTK_WIDGET_FLAGS(wid) and someflag;
- \end{lstlisting}
- will not work, since this is a function, and NOT a macro as in C.
- \item Calling conventions: A C compiler uses another calling convention
- than the Free Pascal compiler. Since many GTK functions need a callback,
- these callback must use the C calling convention. This means that every
- function that is called by GTK code, should have the \lstinline|cdecl|
- modifier as a part of its declaration.
- \end{enumerate}
- Compiling a GTK application is no different than compiling any other Free
- Pascal application. The only thing that needs to be done is to tell the free
- Pascal compiler where the gtk, gdk and glib libraries are located on your
- system. This can be done with the \verb|-Fl| command-line switch. For
- example, supposing the gtk library is located in \verb|/usr/X11/lib|, the
- following command-line could be used to compile your application:
- \begin{verbatim}
- ppc386 -Fl/usr/X11/lib mygtkapp.pp
- \end{verbatim}
- This example supposes that the gtk unit is be in your unit search path. If
- it is not, you can add it with the \verb|-Fu| switch.
- \section{The bricks of a GTK application}
- The building-blocks of a a GTK application are the {\em widgets}.
- Widgets are the equivalent of Delphi's controls. And although GTK
- is not an object oriented library, the library defines a record
- \lstinline|TGtkWidget| which contains all settings common to all
- widgets; all widgets start with this record, and add their own
- specific data to it. This creates a tree-like structure with all
- the widgets present in the GTK library, to which your own widgets
- can be added.
- All functions that create a particular widget return a pointer
- to a \lstinline|TGtkWidget| record. It is not recommended to
- manipulate the contents of the widget record directly; GTK offers
- many functions to manipulate the members of the record, e.g.
- \lstinline|gtk_widget_set_parent| or \lstinline|gtk_widget_get_name|.
- To this set of functions, each new widget adds a few functions that are
- specific to this particular widget.
- Each widget has a specific function and a specific look; there are many
- widgets to choose from. A complete list of widgets is outside the scope of
- this article; the GTK reference manual offers an overview of available
- widgets. In general it can be said that most widgets one would expect
- are present in the GTK library: Edit fields, buttons, check-boxes, various
- lists, menus, combo-boxes, tree views, and some pre-defined dialogs.
- Any of these widgets is created with a \lstinline|gtk_WIDGET NAME_new| call.
- This call can accept arguments; The number and type of arguments depend
- on the widget.
- For example, to create a button that displays a text, the call is defined
- as follows:
- \begin{lstlisting}{}
- gtk_button_new_with_label(ALAbel : PChar)
- \end{lstlisting}
- All widgets can be destroyed with the \lstinline|gtk_widget_destroy| call,
- irrespective of their type.
- \section{Showing things on the screen}
- To show things on the screen, it is necessary to create a window. A window
- is created with the the \lstinline|gtk_window_new| call. This call accepts
- as an argument the type of window to be created.
- Creating a window creates it's structure in memory, but doesn't show it on
- screen. To show this window on the screen,a call to the
- \lstinline|gtk_widget_show| function is needed, as can been seen in
- example 1.
- \lstinputlisting{gtkex/ex1.pp}
- If the window contains widgets, the \lstinline|gtk_widget_show| function
- must be called for each widget.
- Looking at example 1, one notices 2 special calls: \lstinline|gtk_init| and
- \lstinline|gtk_main|. These calls should be present in any program that uses
- the GTK library.
- The first call initialises the GTK library. Among other things, it reads
- the command-line to see e.g. which display should be used.
- The second call is the heart of the GTK widget library: It starts the
- message loop of GTK. This call will not return, unless somewhere else
- in the program \lstinline|gtk_main_quit| is called. As long as the call
- doesn't return, GTK will wait for events such as mouse clicks, key-presses
- and so on. It will handle these events, but it will not notify you of any
- of these events except if you specifically ask for it.
- A window by itself is of course not very interesting. To make it more
- interesting, some elements should be added.
- Adding a widget to a parent is done with the \lstinline|gtk_container_add|
- call. This call places a widget in a container. A container is a widget
- which can contain other widgets; not all widgets are containers, however.
- Example 2 shows how to add a widget (a button) to a container (the window
- in this case). It also shows that the container has some specific
- properties, which can be manipulated as well (in this case, the border
- width). Since not each widget is a container, the window pointer must be
- typecasted to \lstinline|GTK_CONTAINER| in order to be accepted by the
- container handling calls.
- \lstinputlisting{gtkex/ex2.pp}
- Adding more than 1 widget to a container is not trivial in GTK. The reason
- for this is that GTK has not been designed to set widgets at a specific
- location in their parent widget. Instead, GTK asks that you 'pack' your
- objects in their parent widget. This means that if the parent widget is
- resized, it's child widgets are resized as well, depending on the packing
- options that were set.
- One of the reasons that the GTK library was set up this way, is that the
- size of a widget is not well-defined. For instance, the size of a button
- depends on whether it is the default widget of the window or not. Given
- that this is so, the placement of such a button is not well-defined either.
- The most common ways of packing widgets in a parent widget are the
- following:
- \begin{enumerate}
- \item using a vertical box.
- \item using a horizontal box.
- \item using a table.
- \end{enumerate}
- We'll discuss these ways in the subsequent. There are other ways, but these
- are probably the most important ones.
- \subsection{Using boxes}
- A horizontal or vertical box can be used to contain a row or column of
- widgets. Various options can be set to modify the spacing between the
- widgets, the alignment of the widgets in the box, or the behaviour of
- the box when the user resizes the parent widget. Boxes work only in
- one direction. The widgets inside a horizontal box always have the height of
- the box, and widgets in a vertical box always have the width of the vertical
- box.
- You can create a horizontal box with the \lstinline|gtk_hbox_new| call.
- It accepts 2 arguments: The first one is a boolean. It tells GTK whether the
- children should have the same space in the box. The second one is an
- integer, which tells GTK how much space to leave between the widgets in the
- box. Likewise, a vertical box can be created with the
- \lstinline|gtk_vbox_new| call. This call accepts the same arguments as the
- first box.
- Adding widgets to a box happens with the \lstinline|gtk_box_pack_start| or
- \lstinline|gtk_box_pack_end| calls. The former adds a widget at the start
- of the box, the latter adds a widget at the end of the box. Both functions
- accept the same arguments:
- \begin{lstlisting}{boxarguments}
- (Box : PGtkBox; Widget: PGtkWidget;
- expand gboolean; fill : gboolean;padding : guint);
- \end{lstlisting}
- The \lstinline|expand| argument tells the box whether it should take the
- size of it's parent widget, or whether it should resize itself so that it is
- just large enough to fit the widgets. The latter allows to justify the
- widgets in the box (but only if the box is {\em not} homogeneous.
- If the box should keep the size of it's parent, then the \lstinline|fill|
- argument decides what is done with the extra space available.
- If \lstinline|fill| is \lstinline|True| then the extra space is
- divided over the widgets. If \lstinline|fill| is \lstinline|False| then the
- extra space is put in between the widgets.
- The \lstinline|padding| adding tells the box to add extra space for this
- particular widget.
- The following program shows the use of a box:
- \lstinputlisting{gtkex/ex3.pp}
- What the program does is the following: It creates a window, which it splits
- up in two halves by means of the \lstinline|totalbox| widget. This is a
- vertical box, which will contain two other boxes: a vertical box and a
- horizontal box. Each of these two boxes is filled with buttons.
- The behaviour of the boxes can be seen when the window is resized.
- The effect of the various arguments to the pack calls can be seen by
- changing the arguments and recompiling the example.
- \subsection{Using tables}
- A table is used to set widgets in a grid inside the parent widget. It acts
- like a grid with cells, in which you can 'hang' your widgets. If the user
- resizes the parent widget, then the size of the grid cells changes, and
- the widgets will change their location and size, based on the size of the
- new grid cells.
- To create a table to manage a window's layout, the \lstinline|gtk_table_new|
- call is used. It accepts 3 arguments: the number of rows, the number of
- columns and a boolean which tells GTK whether the cells should always have
- the same size or not.
- To add a widget to a table, the \lstinline|gtk_table_attach| call is used.
- It is declared as
- \begin{lstlisting}{}
- gtk_table_attach(Table: PGtkTable;Widget: PGtkWidget;
- Left, right, top, bottom : guint;
- Xoptions,Yoptions : TGtkAttachOptions;
- Xpadding,Ypadding : Guint);
- \end{lstlisting}
- The first two options of this call are self-explanatory. The next four
- options, however, need some explanation. Contrary to what the name 'table'
- suggests, these do {\em not} specify the coordinates of cells; instead, they
- specify the grid lines that delimit the cells.
- \begin{figure}
- \caption{Placing widgets in a table.\label{fig:table}}
- \begin{center}
- \ifpdf
- \epsfig{file=table.pdf}
- \else
- \epsfig{file=table.eps}
- \fi
- \end{center}
- \end{figure}
- Figure \ref{fig:table} represents a table with 5 rows and 5 columns, with
- cells of the same size. The call to create this table could be:
- \begin{lstlisting}{}
- maintable:=gtk_table_new(5,5,TRUE);
- \end{lstlisting}
- To hang a widget in this table, so it starts in cell (2,1) and ends in cell
- (3,2), where the cells are counted starting with 0, it is necessary to tell
- GTK that the widget starts at horizontal grid line 2, and ends at horizontal
- grid line 4. Vertically, it starts at grid line 1, and ends at grid line 3.
- This means that the following call would place the widget at its correct
- location:
- \begin{lstlisting}{}
- gtk_table_attach(maintable,mybutton,
- 2,4,1,3,
- GTK_EXPAND OR GTK_FILL,GTK_EXPAND OR GTK_FILL,
- 0,0);
- \end{lstlisting}
- GTK delivers a shorter form of this call:
- \begin{lstlisting}{}
- gtk_table_attach_defaults(maintable,mybutton,2,4,1,3);
- \end{lstlisting}
- The parameter \lstinline|GTK_EXPAND or GTK_FILL| tells GTK that the widget
- should always take up the full space assigned to it.
- The following example program illustrates the use of a table in a gtk
- application:
- \lstinputlisting{gtkex/ex4.pp}
- The example creates a table with 6 rows and 6 columns. It places 3 buttons,
- each at a different location in the table, with different sizes. The first
- button has a width and height of 1 cell and is located at cell (1,1). The
- second has a width and height of two cells, and is located at cell (3,1).
- The last button is 4 cells wide and has a height of 1 cell, and is located
- at cell (1,4). When the window is resized, the cells are resized as well,
- and the buttons follow the size of the cells.
- {\em Remark:} because the table has homogeneous cells, the minimum width
- and height of the cells is determined by the first button (in this case).
- Since all cells must have the same size, this means that the minimum size
- of the window is 6 times the size of the first button (plus a border).
- \section{Reacting to user input}
- So far, the example programs did not react to button clicks or any other user
- action other than closing the window. To make a window respond to user
- actions, it is necessary to install signal callbacks or event handlers.
- The difference between signals and events is that signals come from the GTK
- toolkit. Events come from the underlying window system (X or Windows).
- For example, 'button\_pressed' is an event that is generated by the window
- system when the user clicks with his mouse. It is possible to react to
- this event.
- On the other hand, a button widget defines a signal 'clicked'.
- The 'clicked' event will occur when the user clicks on the button.
- So, many signals that are defined by GTK widgets are just a translation
- of events to something specific for that widget.
- Since calls to connect to a signal or to an event are the same, in what
- follows the discussion will be restricted to signals, but all that is
- said is also true for events.
- GTK has essentially 2 ways to install signal callbacks. The only difference
- between these calls is the arguments that the callback function accepts.
- The first way to install a callback is using the
- \lstinline|gtk_signal_connect| function. This function is declared as
- follows:
- \begin{lstlisting}{}
- TGtkSignalFunc = procedure ;cdecl;
- Function gtk_signal_connect(TheObject:PGtkObject;Name:Pgchar;
- Func:TGtkSignalFunc;Data:gpointer):guint;cdecl;
- \end{lstlisting}
- The first argument of this call (\lstinline|TheObject|) is the object
- (usually a widget) to which you want to assign an event handler. The second
- parameter, \lstinline|Name|, is the event you wish to catch with this
- callback (an example could be 'clicked' for a button). The third argument
- (\lstinline|Func|) is the function that should be called when the event occurs.
- The \lstinline|Data| argument is a pointer to arbitrary data. This pointer
- will be passed on to the callback function \lstinline|func| when the event
- occurs.
- The \lstinline|gtk_signal_connect| function returns an integer. This integer
- is the number of the callback for this event. It is possible to attach more
- than one callback to an event in GTK. When the event occurs, the callbacks
- will be executed in the order that they have been attached to the widget.
- The declaration of the \lstinline|TGtkSignalFunc| type requires that every
- callback function that is passed to GTK must be typecast. Since GTK defines
- only one function to set a signal handler, this is necessary, since
- callbacks can have different forms. This mechanism is error-prone, since
- in this manner it is possible to pass a function to GTK which has the wrong
- number of arguments.
- However, most callbacks must be of the form:
- \begin{lstlisting}{}
- Function (Widget : PGtkWidget; Data : GPointer) : guint;cdecl;
- \end{lstlisting}
- Such a callback function accepts 2 arguments: the first argument
- (\lstinline|Widget|) is the widget which caused the event
- (for example, the button which was clicked). The second argument is a
- pointer to arbitrary data. This is the pointer that was passed as
- \lstinline|Data| when the callback was installed.
- Signals are identified by their name. The GTK reference guide contains a
- complete list of supported signals.
- The first example shows how a handler for the 'destroy' signal of the
- window is installed. When the window-manager kills the window, this
- signal is sent. The \lstinline|gtk_main_quit| instructs GTK that it
- should stop processing X events and exit the \lstinline|gtk_main| call.
- A second method to connect a callback to a signal is using the
- \lstinline|gtk_signal_connect_object| call. This call is defined as
- follows:
- \begin{lstlisting}{}
- Function gtk_signal_connect_object(theobject:PGtkObject;
- name:Pgchar;
- func:TGtkSignalFunc;
- slot_object:PGtkObject):guint;cdecl
- \end{lstlisting}
- It is similar in function to the \lstinline|gtk_signal_connect| function,
- only it doesn't allow to pass arbitrary data to the signal handler. Instead,
- the handler must {\em always} be of the following form:
- \begin{lstlisting}{}
- Function (AnObject : PGtkObject);
- \end{lstlisting}
- The \lstinline|slot_object| pointer that was provided in the call to
- \lstinline|gtk_signal_connect_object| will be passed as the
- \lstinline|AnObject| argument to this function. Many GTK functions have the
- above form; this makes it possible to attach a GTK internal function to a
- signal.
- To illustrate this, the second example is modified so that clicking the button
- will also close the window:
- \lstinputlisting{gtkex/ex5.pp}
- In the example, the call to \lstinline|gtk_signal_connect_object| will
- connect the 'clicked' signal of the button to the
- \lstinline|gtk_widget_destroy| function of GTK, and passes the pointer to
- the window widget to it. When the user clicks the button, the
- \lstinline|gtk_widget_destroy| function will be called with as argument the
- pointer of the window object. As a result, the window widget will be
- destroyed, it's 'destroy' signal will be activated, and the
- \lstinline|gtk_main_quit| function will be called through the program's
- 'destroy' handler for the window.
- Since the signal handler connect call returns an integer by which it can
- be identified, it is possible to manipulate or even remove the handler
- once it has been installed.
- For instance it is possible to temporarily disable a signal handler with the
- \lstinline|gtk_signal_handler_block| call, and to enable it again with the
- \lstinline|gtk_signal_handler_unblock| call. An example of how to do this
- can be found in the following example:
- \lstinputlisting{gtkex/ex6.pp}
- There are other things that one can do with signal handlers, but a complete
- discussion of all possibilities is outside the scope of this article.
- Some widgets do not have their own window; i.e. they do not receive events
- from the underlying windowing system. An example of such a widget is a
- label. A label just draws it's text on it's parent widget, and nothing else.
- To be able to respond to certain events, an event-box must be used, and the
- window-less widget must be placed in it. An event-box can be created with
- the \lstinline|gtk_event_box_new| call. This call accepts no arguments.
- To this event-box, a window-less widget can be added. The event-bow will
- then capture events for the window-less widget. The following example shows
- how to use an event-box to detect when the mouse pointer is moved over a
- label:
- \lstinputlisting{gtkex/ex7.pp}
- If the mouse pointer is moved over the first label, the text of the second
- label is adapted accordingly. The example also shows the use of
- \lstinline|gtk_widget_show_all|, which shows a widget and all widgets
- contained in it.
- \section{A touch of style}
- The look of a GTK application is controlled through the use of styles. A
- style controls the colors in which a widget is drawn, in various states.
- As an example: a widget may be drawn differently depending on whether it
- has focus or not. How to draw the widget in each of this states is described
- in the style of the widget.
- GTK recognizes the following states of a widget:
- \begin{description}
- \item[NORMAL] The normal state of a widget. No mouse over it.
- \item[PRELIGHT] Is the state of a widget when the mouse is over it.
- \item[ACTIVE] Is the state of a widget when it is pressed or
- clicked.
- \item[INSENSITIVE] if the widgets is disabled ('grayed').
- \item[SELECTED] When the object is selected.
- The GTK unit has a constant for each of these states; it is the above name
- with \lstinline|GTK_STATE_| prefixed, so e.g. \lstinline|GTK_STATE_NORMAL|
- for the normal state.
- \end{description}
- Each widget class has a default style in which it is drawn. If you wish to
- change the way all these widgets look, you should change the default style
- of this class. If you want to change the way one particular widget looks,
- you should make a new style, and apply it to that particular widget. It is
- possible to make a copy of an existing style and modify the copy before
- applying it.
- It is also possible to change the default style of widgets. Changing the
- default style of widgets will have effect on all widgets created after the
- new style was set. Widgets created before that will be unaffected.
- The following example shows how to set the color of a label. It takes a
- copy of the standard label style, and modifies it so the foreground color
- becomes red. It then applies the modified style to the first label.
- The second label is unaffected by this change
- \lstinputlisting{gtkex/ex8.pp}
- The last example shows how to change the color of a button when the mouse
- moves over it.
- \lstinputlisting{gtkex/ex9.pp}
- \section{Carrying on}
- In the previous sections, some basic concepts of GTK have been introduced.
- However, GTK is a big toolkit and much more can be said about it. It is
- outside of the scope of the current article to describe all Widgets in the
- GTK library. The range of offered widgets is broad, and there probably is a
- widget for each conceivable task. If there is a missing widget, it is always
- possible to write a new widget.
- In principle, therefore, GTK is suitable to write large applications, also
- when writing in Free Pascal. However, the fact that it is written in C and
- it's interface is C oriented, justifies the writing of a small Pascal Object
- Oriented wrapper around it.
- The following arguments show the need for such a wrapper:
- \begin{enumerate}
- \item C has no object-oriented language constructs. This makes it necessary
- to do a lot of typecasts in GTK calls. Using Classes or Objects, this is no
- longer necessary, and will improve code readability substantially.
- \item C uses null-terminated strings. It can be useful to wrap calls that
- need a null-terminated string into one that accepts a normal string as an
- argument. Using ansistrings will make the conversion to null-terminated
- strings easier.
- \item The signal mechanism of GTK destroys the strong type checking of
- Pascal. When compiling the statement
- \begin{lstlisting}{}
- Button.OnClick:[email protected]
- \end{lstlisting}
- The compiler checks that the \lstinline|OnButtonClick| method can be
- assigned to the \lstinline|OnClick| event. Under GTK, it is possible
- to pass any function as a handler for a signal, as in
- \begin{lstlisting}{}
- gtk_signal_connect (PGTKOBJECT (window), 'destroy',
- GTK_SIGNAL_FUNC (@destroy), NULL);
- \end{lstlisting}
- This can lead to errors if the \lstinline|destroy| procedure accepts a
- different number of arguments, or other arguments than the ones that
- GTK provides. Therefore it would be a good idea to implement methods that
- would force type checking, e.g:
- \begin{lstlisting}{}
- Button.AddOnClick(@MyForm.OnButtonClick);
- \end{lstlisting}
- Such a statement would only compile if the \lstinline|OnButtonClick| would
- be of the right type.
- \end{enumerate}
- Additional benefits of making such a wrapper would be simpler code, and
- hence better readability. Both improve the maintainability of the code as well,
- which are all important factors when writing a large application.
- \end{document}
|