gtk1.tex 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591
  1. \documentclass[10pt]{article}
  2. \usepackage{a4}
  3. \usepackage{epsfig}
  4. \usepackage{listings}
  5. \lstset{language=Delphi}%
  6. \lstset{basicstyle=\sffamily\small}%
  7. \lstset{commentstyle=\itshape}%
  8. \lstset{keywordstyle=\bfseries}%
  9. \lstset{blankstring=true}%
  10. \newif\ifpdf
  11. \ifx\pdfoutput\undefined
  12. \pdffalse
  13. \else
  14. \pdfoutput=1
  15. \pdftrue
  16. \fi
  17. \begin{document}
  18. \title{Programming GTK in Free Pascal}
  19. \author{Florian Kl\"ampfl\\and\\Micha\"el Van Canneyt}
  20. \date{July 2000}
  21. \maketitle
  22. \section{Introduction}
  23. The GTK library is a popular widget library for the X-Windows system.
  24. It is used as the basis for the GIMP graphical manipulation program
  25. and for the GNOME application framework. With its ports to Microsoft
  26. Windows and BeOS, it allows to program a graphical interface for any
  27. application in a platform independent way.
  28. GTK is implemented in C, but it is possible to access its functionality from
  29. Free Pascal. For this, its headers have been translated to Pascal,
  30. so a program written in Free Pascal can make use of the functionality
  31. offered by GTK and its companion libraries GDK and GLIB. In fact, there is
  32. an open source project (Lazarus) which makes use of GTK in order to build
  33. an open-source alternative to the visual classes offered by Inprise's
  34. Delphi.
  35. This article intends to present an introduction to programming GTK in
  36. Free Pascal. It by no means covers all of the functionality that GTK
  37. offers, as this would probably require a complete manual.
  38. The first section gives some general considerations on the GTK toolkit.
  39. \section{GTK is a C library}
  40. Since GTK is an external library, some import units describing the calls in
  41. the libraries are needed. Three libraries make up the GTK programming kit:
  42. \begin{description}
  43. \item[glib] this library contains some general programming tools, and
  44. defines platform independent types, which are used throughout the other
  45. libraries. To use this library, it is sufficient to include the
  46. \lstinline|glib| unit in your \lstinline|uses| clause.
  47. \item[gdk] encapsulates the Windowing system (X or Windows) underlying GTK.
  48. It contains routines to draw on the screen, and react to various mouse or
  49. keyboard events. To use these
  50. routines, the \lstinline|gdk| unit must be included in the \lstinline|uses|
  51. clause of a unit or program.
  52. \item[gtk] contains the widget library. This is a series of controls such
  53. as edit boxes, drop-down lists and many more, which are organised in an OOP
  54. structure. Since the library is written in C, there is no programming
  55. language support for this structure.
  56. All definitions of the gtk library are contained in the gtk unit, which
  57. must be included in the \lstinline|uses| clause of any program or unit that needs their
  58. functionality.
  59. \end{description}
  60. The GTK toolkit was programmed in C. This has some consequences for the
  61. Pascal interface, since some C constructs do not port easily to Pascal.
  62. When using the Pascal translation of the C headers, the following must be
  63. kept in mind:
  64. \begin{enumerate}
  65. \item Reserved words: Pascal reserved words in types, record element names
  66. etc. have been prepended with the word 'the'. For example \lstinline|label|
  67. becomes \lstinline|thelabel|.
  68. \item Functions and procedures have been kept with the same names.
  69. \item Types have been prepended with T, that is, the C type
  70. \lstinline|GtkWidget| has become \lstinline|TGtkWidget|.
  71. \item Pointers to types have been defined as the type name, prepended with a
  72. P. \lstinline|GtkWidget *| becomes \lstinline|PGtkWidget|.
  73. \item Records with bit-size elements: C allows to store parts of a record in
  74. individual bits; whereas in Pascal, the minimum size of an element in a
  75. record is a byte. To accommodate this, functions were defined to retrieve
  76. or set single bits from a record. The functions to retrieve a bit
  77. have the name of the record field. The procedure to set a bit has
  78. the name of the field prepended with 'set\_'.
  79. For example
  80. \begin{lstlisting}[language=c]{cpackedstruct}
  81. struct SomeStruct
  82. {
  83. gchar *title;
  84. guint visible : 1;
  85. guint resizeable : 1;
  86. };
  87. \end{lstlisting}
  88. translates to
  89. \begin{lstlisting}{ppackedstruct}
  90. TSomeStruct = record
  91. title : Pgchar;
  92. flag0 : word;
  93. end;
  94. function visible(var a: TGtkCListColumn): guint;
  95. procedure set_visible(var a: TGtkCListColumn; __visible: guint);
  96. function resizeable(var a: TGtkCListColumn): guint;
  97. procedure set_resizeable(var a: TGtkCListColumn;__resizeable: guint);
  98. \end{lstlisting}
  99. \item Macros. Many C macros have not been translated. The typecasting
  100. macros have been dropped, since they're useless under Pascal.
  101. Macros to access record members have been translated, but they are to be
  102. considered as {read-only}. So they can be used to retrieve a value, but
  103. not to store one. e.g.
  104. \begin{lstlisting}{macro}
  105. function GTK_WIDGET_FLAGS(wid : pgtkwidget) : longint;
  106. \end{lstlisting}
  107. can be used to retrieve the widget flags, but not to set them. so things like
  108. \begin{lstlisting}{invaliduseofmacro}
  109. GTK_WIDGET_FLAGS(wid):=GTK_WIDGET_FLAGS(wid) and someflag;
  110. \end{lstlisting}
  111. will not work, since this is a function, and NOT a macro as in C.
  112. \item Calling conventions: A C compiler uses another calling convention
  113. than the Free Pascal compiler. Since many GTK functions need a callback,
  114. these callback must use the C calling convention. This means that every
  115. function that is called by GTK code, should have the \lstinline|cdecl|
  116. modifier as a part of its declaration.
  117. \end{enumerate}
  118. Compiling a GTK application is no different than compiling any other Free
  119. Pascal application. The only thing that needs to be done is to tell the free
  120. Pascal compiler where the gtk, gdk and glib libraries are located on your
  121. system. This can be done with the \verb|-Fl| command-line switch. For
  122. example, supposing the gtk library is located in \verb|/usr/X11/lib|, the
  123. following command-line could be used to compile your application:
  124. \begin{verbatim}
  125. ppc386 -Fl/usr/X11/lib mygtkapp.pp
  126. \end{verbatim}
  127. This example supposes that the gtk unit is be in your unit search path. If
  128. it is not, you can add it with the \verb|-Fu| switch.
  129. \section{The bricks of a GTK application}
  130. The building-blocks of a a GTK application are the {\em widgets}.
  131. Widgets are the equivalent of Delphi's controls. And although GTK
  132. is not an object oriented library, the library defines a record
  133. \lstinline|TGtkWidget| which contains all settings common to all
  134. widgets; all widgets start with this record, and add their own
  135. specific data to it. This creates a tree-like structure with all
  136. the widgets present in the GTK library, to which your own widgets
  137. can be added.
  138. All functions that create a particular widget return a pointer
  139. to a \lstinline|TGtkWidget| record. It is not recommended to
  140. manipulate the contents of the widget record directly; GTK offers
  141. many functions to manipulate the members of the record, e.g.
  142. \lstinline|gtk_widget_set_parent| or \lstinline|gtk_widget_get_name|.
  143. To this set of functions, each new widget adds a few functions that are
  144. specific to this particular widget.
  145. Each widget has a specific function and a specific look; there are many
  146. widgets to choose from. A complete list of widgets is outside the scope of
  147. this article; the GTK reference manual offers an overview of available
  148. widgets. In general it can be said that most widgets one would expect
  149. are present in the GTK library: Edit fields, buttons, check-boxes, various
  150. lists, menus, combo-boxes, tree views, and some pre-defined dialogs.
  151. Any of these widgets is created with a \lstinline|gtk_WIDGET NAME_new| call.
  152. This call can accept arguments; The number and type of arguments depend
  153. on the widget.
  154. For example, to create a button that displays a text, the call is defined
  155. as follows:
  156. \begin{lstlisting}{}
  157. gtk_button_new_with_label(ALAbel : PChar)
  158. \end{lstlisting}
  159. All widgets can be destroyed with the \lstinline|gtk_widget_destroy| call,
  160. irrespective of their type.
  161. \section{Showing things on the screen}
  162. To show things on the screen, it is necessary to create a window. A window
  163. is created with the the \lstinline|gtk_window_new| call. This call accepts
  164. as an argument the type of window to be created.
  165. Creating a window creates it's structure in memory, but doesn't show it on
  166. screen. To show this window on the screen,a call to the
  167. \lstinline|gtk_widget_show| function is needed, as can been seen in
  168. example 1.
  169. \lstinputlisting{gtkex/ex1.pp}
  170. If the window contains widgets, the \lstinline|gtk_widget_show| function
  171. must be called for each widget.
  172. Looking at example 1, one notices 2 special calls: \lstinline|gtk_init| and
  173. \lstinline|gtk_main|. These calls should be present in any program that uses
  174. the GTK library.
  175. The first call initialises the GTK library. Among other things, it reads
  176. the command-line to see e.g. which display should be used.
  177. The second call is the heart of the GTK widget library: It starts the
  178. message loop of GTK. This call will not return, unless somewhere else
  179. in the program \lstinline|gtk_main_quit| is called. As long as the call
  180. doesn't return, GTK will wait for events such as mouse clicks, key-presses
  181. and so on. It will handle these events, but it will not notify you of any
  182. of these events except if you specifically ask for it.
  183. A window by itself is of course not very interesting. To make it more
  184. interesting, some elements should be added.
  185. Adding a widget to a parent is done with the \lstinline|gtk_container_add|
  186. call. This call places a widget in a container. A container is a widget
  187. which can contain other widgets; not all widgets are containers, however.
  188. Example 2 shows how to add a widget (a button) to a container (the window
  189. in this case). It also shows that the container has some specific
  190. properties, which can be manipulated as well (in this case, the border
  191. width). Since not each widget is a container, the window pointer must be
  192. typecasted to \lstinline|GTK_CONTAINER| in order to be accepted by the
  193. container handling calls.
  194. \lstinputlisting{gtkex/ex2.pp}
  195. Adding more than 1 widget to a container is not trivial in GTK. The reason
  196. for this is that GTK has not been designed to set widgets at a specific
  197. location in their parent widget. Instead, GTK asks that you 'pack' your
  198. objects in their parent widget. This means that if the parent widget is
  199. resized, it's child widgets are resized as well, depending on the packing
  200. options that were set.
  201. One of the reasons that the GTK library was set up this way, is that the
  202. size of a widget is not well-defined. For instance, the size of a button
  203. depends on whether it is the default widget of the window or not. Given
  204. that this is so, the placement of such a button is not well-defined either.
  205. The most common ways of packing widgets in a parent widget are the
  206. following:
  207. \begin{enumerate}
  208. \item using a vertical box.
  209. \item using a horizontal box.
  210. \item using a table.
  211. \end{enumerate}
  212. We'll discuss these ways in the subsequent. There are other ways, but these
  213. are probably the most important ones.
  214. \subsection{Using boxes}
  215. A horizontal or vertical box can be used to contain a row or column of
  216. widgets. Various options can be set to modify the spacing between the
  217. widgets, the alignment of the widgets in the box, or the behaviour of
  218. the box when the user resizes the parent widget. Boxes work only in
  219. one direction. The widgets inside a horizontal box always have the height of
  220. the box, and widgets in a vertical box always have the width of the vertical
  221. box.
  222. You can create a horizontal box with the \lstinline|gtk_hbox_new| call.
  223. It accepts 2 arguments: The first one is a boolean. It tells GTK whether the
  224. children should have the same space in the box. The second one is an
  225. integer, which tells GTK how much space to leave between the widgets in the
  226. box. Likewise, a vertical box can be created with the
  227. \lstinline|gtk_vbox_new| call. This call accepts the same arguments as the
  228. first box.
  229. Adding widgets to a box happens with the \lstinline|gtk_box_pack_start| or
  230. \lstinline|gtk_box_pack_end| calls. The former adds a widget at the start
  231. of the box, the latter adds a widget at the end of the box. Both functions
  232. accept the same arguments:
  233. \begin{lstlisting}{boxarguments}
  234. (Box : PGtkBox; Widget: PGtkWidget;
  235. expand gboolean; fill : gboolean;padding : guint);
  236. \end{lstlisting}
  237. The \lstinline|expand| argument tells the box whether it should take the
  238. size of it's parent widget, or whether it should resize itself so that it is
  239. just large enough to fit the widgets. The latter allows to justify the
  240. widgets in the box (but only if the box is {\em not} homogeneous.
  241. If the box should keep the size of it's parent, then the \lstinline|fill|
  242. argument decides what is done with the extra space available.
  243. If \lstinline|fill| is \lstinline|True| then the extra space is
  244. divided over the widgets. If \lstinline|fill| is \lstinline|False| then the
  245. extra space is put in between the widgets.
  246. The \lstinline|padding| adding tells the box to add extra space for this
  247. particular widget.
  248. The following program shows the use of a box:
  249. \lstinputlisting{gtkex/ex3.pp}
  250. What the program does is the following: It creates a window, which it splits
  251. up in two halves by means of the \lstinline|totalbox| widget. This is a
  252. vertical box, which will contain two other boxes: a vertical box and a
  253. horizontal box. Each of these two boxes is filled with buttons.
  254. The behaviour of the boxes can be seen when the window is resized.
  255. The effect of the various arguments to the pack calls can be seen by
  256. changing the arguments and recompiling the example.
  257. \subsection{Using tables}
  258. A table is used to set widgets in a grid inside the parent widget. It acts
  259. like a grid with cells, in which you can 'hang' your widgets. If the user
  260. resizes the parent widget, then the size of the grid cells changes, and
  261. the widgets will change their location and size, based on the size of the
  262. new grid cells.
  263. To create a table to manage a window's layout, the \lstinline|gtk_table_new|
  264. call is used. It accepts 3 arguments: the number of rows, the number of
  265. columns and a boolean which tells GTK whether the cells should always have
  266. the same size or not.
  267. To add a widget to a table, the \lstinline|gtk_table_attach| call is used.
  268. It is declared as
  269. \begin{lstlisting}{}
  270. gtk_table_attach(Table: PGtkTable;Widget: PGtkWidget;
  271. Left, right, top, bottom : guint;
  272. Xoptions,Yoptions : TGtkAttachOptions;
  273. Xpadding,Ypadding : Guint);
  274. \end{lstlisting}
  275. The first two options of this call are self-explanatory. The next four
  276. options, however, need some explanation. Contrary to what the name 'table'
  277. suggests, these do {\em not} specify the coordinates of cells; instead, they
  278. specify the grid lines that delimit the cells.
  279. \begin{figure}
  280. \caption{Placing widgets in a table.\label{fig:table}}
  281. \begin{center}
  282. \ifpdf
  283. \epsfig{file=table.pdf}
  284. \else
  285. \epsfig{file=table.eps}
  286. \fi
  287. \end{center}
  288. \end{figure}
  289. Figure \ref{fig:table} represents a table with 5 rows and 5 columns, with
  290. cells of the same size. The call to create this table could be:
  291. \begin{lstlisting}{}
  292. maintable:=gtk_table_new(5,5,TRUE);
  293. \end{lstlisting}
  294. To hang a widget in this table, so it starts in cell (2,1) and ends in cell
  295. (3,2), where the cells are counted starting with 0, it is necessary to tell
  296. GTK that the widget starts at horizontal grid line 2, and ends at horizontal
  297. grid line 4. Vertically, it starts at grid line 1, and ends at grid line 3.
  298. This means that the following call would place the widget at its correct
  299. location:
  300. \begin{lstlisting}{}
  301. gtk_table_attach(maintable,mybutton,
  302. 2,4,1,3,
  303. GTK_EXPAND OR GTK_FILL,GTK_EXPAND OR GTK_FILL,
  304. 0,0);
  305. \end{lstlisting}
  306. GTK delivers a shorter form of this call:
  307. \begin{lstlisting}{}
  308. gtk_table_attach_defaults(maintable,mybutton,2,4,1,3);
  309. \end{lstlisting}
  310. The parameter \lstinline|GTK_EXPAND or GTK_FILL| tells GTK that the widget
  311. should always take up the full space assigned to it.
  312. The following example program illustrates the use of a table in a gtk
  313. application:
  314. \lstinputlisting{gtkex/ex4.pp}
  315. The example creates a table with 6 rows and 6 columns. It places 3 buttons,
  316. each at a different location in the table, with different sizes. The first
  317. button has a width and height of 1 cell and is located at cell (1,1). The
  318. second has a width and height of two cells, and is located at cell (3,1).
  319. The last button is 4 cells wide and has a height of 1 cell, and is located
  320. at cell (1,4). When the window is resized, the cells are resized as well,
  321. and the buttons follow the size of the cells.
  322. {\em Remark:} because the table has homogeneous cells, the minimum width
  323. and height of the cells is determined by the first button (in this case).
  324. Since all cells must have the same size, this means that the minimum size
  325. of the window is 6 times the size of the first button (plus a border).
  326. \section{Reacting to user input}
  327. So far, the example programs did not react to button clicks or any other user
  328. action other than closing the window. To make a window respond to user
  329. actions, it is necessary to install signal callbacks or event handlers.
  330. The difference between signals and events is that signals come from the GTK
  331. toolkit. Events come from the underlying window system (X or Windows).
  332. For example, 'button\_pressed' is an event that is generated by the window
  333. system when the user clicks with his mouse. It is possible to react to
  334. this event.
  335. On the other hand, a button widget defines a signal 'clicked'.
  336. The 'clicked' event will occur when the user clicks on the button.
  337. So, many signals that are defined by GTK widgets are just a translation
  338. of events to something specific for that widget.
  339. Since calls to connect to a signal or to an event are the same, in what
  340. follows the discussion will be restricted to signals, but all that is
  341. said is also true for events.
  342. GTK has essentially 2 ways to install signal callbacks. The only difference
  343. between these calls is the arguments that the callback function accepts.
  344. The first way to install a callback is using the
  345. \lstinline|gtk_signal_connect| function. This function is declared as
  346. follows:
  347. \begin{lstlisting}{}
  348. TGtkSignalFunc = procedure ;cdecl;
  349. Function gtk_signal_connect(TheObject:PGtkObject;Name:Pgchar;
  350. Func:TGtkSignalFunc;Data:gpointer):guint;cdecl;
  351. \end{lstlisting}
  352. The first argument of this call (\lstinline|TheObject|) is the object
  353. (usually a widget) to which you want to assign an event handler. The second
  354. parameter, \lstinline|Name|, is the event you wish to catch with this
  355. callback (an example could be 'clicked' for a button). The third argument
  356. (\lstinline|Func|) is the function that should be called when the event occurs.
  357. The \lstinline|Data| argument is a pointer to arbitrary data. This pointer
  358. will be passed on to the callback function \lstinline|func| when the event
  359. occurs.
  360. The \lstinline|gtk_signal_connect| function returns an integer. This integer
  361. is the number of the callback for this event. It is possible to attach more
  362. than one callback to an event in GTK. When the event occurs, the callbacks
  363. will be executed in the order that they have been attached to the widget.
  364. The declaration of the \lstinline|TGtkSignalFunc| type requires that every
  365. callback function that is passed to GTK must be typecast. Since GTK defines
  366. only one function to set a signal handler, this is necessary, since
  367. callbacks can have different forms. This mechanism is error-prone, since
  368. in this manner it is possible to pass a function to GTK which has the wrong
  369. number of arguments.
  370. However, most callbacks must be of the form:
  371. \begin{lstlisting}{}
  372. Function (Widget : PGtkWidget; Data : GPointer) : guint;cdecl;
  373. \end{lstlisting}
  374. Such a callback function accepts 2 arguments: the first argument
  375. (\lstinline|Widget|) is the widget which caused the event
  376. (for example, the button which was clicked). The second argument is a
  377. pointer to arbitrary data. This is the pointer that was passed as
  378. \lstinline|Data| when the callback was installed.
  379. Signals are identified by their name. The GTK reference guide contains a
  380. complete list of supported signals.
  381. The first example shows how a handler for the 'destroy' signal of the
  382. window is installed. When the window-manager kills the window, this
  383. signal is sent. The \lstinline|gtk_main_quit| instructs GTK that it
  384. should stop processing X events and exit the \lstinline|gtk_main| call.
  385. A second method to connect a callback to a signal is using the
  386. \lstinline|gtk_signal_connect_object| call. This call is defined as
  387. follows:
  388. \begin{lstlisting}{}
  389. Function gtk_signal_connect_object(theobject:PGtkObject;
  390. name:Pgchar;
  391. func:TGtkSignalFunc;
  392. slot_object:PGtkObject):guint;cdecl
  393. \end{lstlisting}
  394. It is similar in function to the \lstinline|gtk_signal_connect| function,
  395. only it doesn't allow to pass arbitrary data to the signal handler. Instead,
  396. the handler must {\em always} be of the following form:
  397. \begin{lstlisting}{}
  398. Function (AnObject : PGtkObject);
  399. \end{lstlisting}
  400. The \lstinline|slot_object| pointer that was provided in the call to
  401. \lstinline|gtk_signal_connect_object| will be passed as the
  402. \lstinline|AnObject| argument to this function. Many GTK functions have the
  403. above form; this makes it possible to attach a GTK internal function to a
  404. signal.
  405. To illustrate this, the second example is modified so that clicking the button
  406. will also close the window:
  407. \lstinputlisting{gtkex/ex5.pp}
  408. In the example, the call to \lstinline|gtk_signal_connect_object| will
  409. connect the 'clicked' signal of the button to the
  410. \lstinline|gtk_widget_destroy| function of GTK, and passes the pointer to
  411. the window widget to it. When the user clicks the button, the
  412. \lstinline|gtk_widget_destroy| function will be called with as argument the
  413. pointer of the window object. As a result, the window widget will be
  414. destroyed, it's 'destroy' signal will be activated, and the
  415. \lstinline|gtk_main_quit| function will be called through the program's
  416. 'destroy' handler for the window.
  417. Since the signal handler connect call returns an integer by which it can
  418. be identified, it is possible to manipulate or even remove the handler
  419. once it has been installed.
  420. For instance it is possible to temporarily disable a signal handler with the
  421. \lstinline|gtk_signal_handler_block| call, and to enable it again with the
  422. \lstinline|gtk_signal_handler_unblock| call. An example of how to do this
  423. can be found in the following example:
  424. \lstinputlisting{gtkex/ex6.pp}
  425. There are other things that one can do with signal handlers, but a complete
  426. discussion of all possibilities is outside the scope of this article.
  427. Some widgets do not have their own window; i.e. they do not receive events
  428. from the underlying windowing system. An example of such a widget is a
  429. label. A label just draws it's text on it's parent widget, and nothing else.
  430. To be able to respond to certain events, an event-box must be used, and the
  431. window-less widget must be placed in it. An event-box can be created with
  432. the \lstinline|gtk_event_box_new| call. This call accepts no arguments.
  433. To this event-box, a window-less widget can be added. The event-bow will
  434. then capture events for the window-less widget. The following example shows
  435. how to use an event-box to detect when the mouse pointer is moved over a
  436. label:
  437. \lstinputlisting{gtkex/ex7.pp}
  438. If the mouse pointer is moved over the first label, the text of the second
  439. label is adapted accordingly. The example also shows the use of
  440. \lstinline|gtk_widget_show_all|, which shows a widget and all widgets
  441. contained in it.
  442. \section{A touch of style}
  443. The look of a GTK application is controlled through the use of styles. A
  444. style controls the colors in which a widget is drawn, in various states.
  445. As an example: a widget may be drawn differently depending on whether it
  446. has focus or not. How to draw the widget in each of this states is described
  447. in the style of the widget.
  448. GTK recognizes the following states of a widget:
  449. \begin{description}
  450. \item[NORMAL] The normal state of a widget. No mouse over it.
  451. \item[PRELIGHT] Is the state of a widget when the mouse is over it.
  452. \item[ACTIVE] Is the state of a widget when it is pressed or
  453. clicked.
  454. \item[INSENSITIVE] if the widgets is disabled ('grayed').
  455. \item[SELECTED] When the object is selected.
  456. The GTK unit has a constant for each of these states; it is the above name
  457. with \lstinline|GTK_STATE_| prefixed, so e.g. \lstinline|GTK_STATE_NORMAL|
  458. for the normal state.
  459. \end{description}
  460. Each widget class has a default style in which it is drawn. If you wish to
  461. change the way all these widgets look, you should change the default style
  462. of this class. If you want to change the way one particular widget looks,
  463. you should make a new style, and apply it to that particular widget. It is
  464. possible to make a copy of an existing style and modify the copy before
  465. applying it.
  466. It is also possible to change the default style of widgets. Changing the
  467. default style of widgets will have effect on all widgets created after the
  468. new style was set. Widgets created before that will be unaffected.
  469. The following example shows how to set the color of a label. It takes a
  470. copy of the standard label style, and modifies it so the foreground color
  471. becomes red. It then applies the modified style to the first label.
  472. The second label is unaffected by this change
  473. \lstinputlisting{gtkex/ex8.pp}
  474. The last example shows how to change the color of a button when the mouse
  475. moves over it.
  476. \lstinputlisting{gtkex/ex9.pp}
  477. \section{Carrying on}
  478. In the previous sections, some basic concepts of GTK have been introduced.
  479. However, GTK is a big toolkit and much more can be said about it. It is
  480. outside of the scope of the current article to describe all Widgets in the
  481. GTK library. The range of offered widgets is broad, and there probably is a
  482. widget for each conceivable task. If there is a missing widget, it is always
  483. possible to write a new widget.
  484. In principle, therefore, GTK is suitable to write large applications, also
  485. when writing in Free Pascal. However, the fact that it is written in C and
  486. it's interface is C oriented, justifies the writing of a small Pascal Object
  487. Oriented wrapper around it.
  488. The following arguments show the need for such a wrapper:
  489. \begin{enumerate}
  490. \item C has no object-oriented language constructs. This makes it necessary
  491. to do a lot of typecasts in GTK calls. Using Classes or Objects, this is no
  492. longer necessary, and will improve code readability substantially.
  493. \item C uses null-terminated strings. It can be useful to wrap calls that
  494. need a null-terminated string into one that accepts a normal string as an
  495. argument. Using ansistrings will make the conversion to null-terminated
  496. strings easier.
  497. \item The signal mechanism of GTK destroys the strong type checking of
  498. Pascal. When compiling the statement
  499. \begin{lstlisting}{}
  500. Button.OnClick:[email protected]
  501. \end{lstlisting}
  502. The compiler checks that the \lstinline|OnButtonClick| method can be
  503. assigned to the \lstinline|OnClick| event. Under GTK, it is possible
  504. to pass any function as a handler for a signal, as in
  505. \begin{lstlisting}{}
  506. gtk_signal_connect (PGTKOBJECT (window), 'destroy',
  507. GTK_SIGNAL_FUNC (@destroy), NULL);
  508. \end{lstlisting}
  509. This can lead to errors if the \lstinline|destroy| procedure accepts a
  510. different number of arguments, or other arguments than the ones that
  511. GTK provides. Therefore it would be a good idea to implement methods that
  512. would force type checking, e.g:
  513. \begin{lstlisting}{}
  514. Button.AddOnClick(@MyForm.OnButtonClick);
  515. \end{lstlisting}
  516. Such a statement would only compile if the \lstinline|OnButtonClick| would
  517. be of the right type.
  518. \end{enumerate}
  519. Additional benefits of making such a wrapper would be simpler code, and
  520. hence better readability. Both improve the maintainability of the code as well,
  521. which are all important factors when writing a large application.
  522. \end{document}