gtk2.tex 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  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{September 2000}
  21. \maketitle
  22. \section{Introduction}
  23. In this second article on programming the GTK toolkit, a more advanced use
  24. of the GTK library is presented. Techniques to create a new GTK widget
  25. are discussed by creating two custom widgets.
  26. The first widget is realized by combining existing GTK widgets to create
  27. a new widget, a GTKFileEdit component, modeled after the TFileEdit component
  28. found in the RXLib library for Delphi.
  29. The second widget is..
  30. \section{Preliminaries}
  31. Whatever the method used when creating new GTK widgets, it is necessary to
  32. split the functionality of the widget in 2 parts.
  33. The first part is the functionality that is common to all instances of the
  34. new widget. This part is by far the most important
  35. one, and is implemented in the 'class record'.
  36. The second part concerns the particular instance of the widget that is
  37. created. It is the actual object created by the user. This part of the
  38. widget is implemented in the 'Object record'.
  39. Creating a new widget consists of defining 2 records that contain the
  40. data for the class as a whole, and one for the individual instances of
  41. the objects.
  42. Then some standard methods must be implemented in order to integrate
  43. the new widget in the GTK library. Implementing some methods for the
  44. user to manipulate the properties of the new widget finishes then
  45. the creation of a new widget.
  46. Since GTK is implemented in C, the programmer must obey some rules in order
  47. to preserve the object-oriented aspect of the GTK library. More precisely,
  48. when defining the class and object structures, care must be taken to specify
  49. the parent object as the first element in the newly created structure. This
  50. will allow typecasting of the widget to its parent objects.
  51. Taking a look at the \lstinline|TGtkContainer| widget, we see that the declaration
  52. of the object record starts with the delaration of its parent widget
  53. \lstinline|TGtkWidget|:
  54. \begin{lstlisting}{}
  55. TGtkContainer = record
  56. widget : TGtkWidget;
  57. focus_child : PGtkWidget;
  58. flag0 : longint;
  59. resize_widgets : PGSList;
  60. end;
  61. \end{lstlisting}
  62. The same is true for the \lstinline|TGtkContainerClass| record:
  63. \begin{lstlisting}{}
  64. TGtkContainerClass = record
  65. parent_class : TGtkWidgetClass;
  66. n_child_args : guint;
  67. // ...
  68. end;
  69. \end{lstlisting}
  70. For both the components that will be made, such records will be made.
  71. \section{A filename edit component}
  72. The \lstinline|TGTKFileEdit| component presented here is composed out of three
  73. other components; first of all a single line edit control, in which the
  74. user can type a filename if he wishes. The second is a button. The button
  75. is always placed on the right edge of the edit control, and has the same
  76. height. The third component is an image component, which is used to display
  77. an image on the button\footnote{In GTK a button does not necessarily contains a
  78. caption, it is an empty placeholder, which can be filled with whatever
  79. you want, in this case an image. To have the button display a caption,
  80. a label is placed in it.}
  81. Since the edit and button component must be kept together, we use a
  82. \lstinline|TGtkHBox| as the 'Parent' component, and this component will be
  83. used to keep the edit and button control. There is no need to consider the
  84. image component, since it will be placed inside the button.
  85. Having decided that, the structure of the record for the instance of the
  86. component is more or less determined:
  87. \begin{lstlisting}{}
  88. Type
  89. PGtkFileEdit = ^TGtkFileEdit;
  90. TGtkFileEdit = Record
  91. Box : TGtkHBox;
  92. Edit : PGtkEntry;
  93. Button : PGtkButton;
  94. Image : PGtkPixmap;
  95. Dialog : PGtkFileSelection;
  96. end;
  97. \end{lstlisting}
  98. The first field of the record contains the parent record, as required
  99. by the OOP structure of GTK. The other fields are used to contain references
  100. to the other controls used. The \lstinline|Dialog| field will be filled with the
  101. reference to the file selection dialog which is created when the user clicks
  102. the button, at all other times it will contain a \lstinline|nil| pointer.
  103. Remark that the first field is a record, and all other fields are pointers.
  104. Since the fields of the record are 'Public' the user can access the button
  105. and edit components, and set or read their properties, and set additional
  106. signals. (e.g. a 'change' signal for the edit component)
  107. The class record for the {TGTKFileEdit} component should contain as a first
  108. field the parent class record, in this case \lstinline|TgtkHBoxClass|. Furthermore
  109. in the class record the default bitmap that will be displayed on the button
  110. will be stored. For this two fields are needed; one to keep the bitmap
  111. (\lstinline|DefaultPixmap|, and
  112. another one to keep a bitmask that is used to determine the transparant
  113. pixels in the bitmap (\lstinline|DefaultBitMap|):
  114. \begin{lstlisting}{}
  115. PGtkFileEditClass = ^TGtkFileEditClass;
  116. TGtkFileEditClass = Record
  117. Parent_Class : TgtkHBoxClass;
  118. DefaultPixmap : PGdkPixmap;
  119. DefaultBitMap : PGdkBitmap;
  120. end;
  121. \end{lstlisting}
  122. As usual, a pointer type is defined which points to the record. The fields
  123. of the class record will be filled in by the initialization code for our
  124. component, as will be shown below.
  125. To register the component with the GTK library, a function must be
  126. implemented which returns the type of the widget:
  127. The \lstinline|GtkFileEdit\_get\_type| function.
  128. When this function is called for the first time, it will register
  129. the new class with GTK, which will in turn supply a unique ID for the
  130. new component. This ID is returned and also stored, and will be returned
  131. the next times when the \lstinline|\_get\_type| function is called.
  132. Registering a new type with GTK is done by filling a \lstinline|TGtkTypeInfo|
  133. record with information on the new type, and passing it on to GTK with
  134. \lstinline|gtk\_type\_unique|:
  135. \begin{lstlisting}{}
  136. Function GtkFileEdit_get_type : Guint;cdecl;
  137. Const
  138. GtkFileEditInfo : TGtkTypeInfo =
  139. (type_name : 'GtkFileEdit';
  140. object_size : SizeOf(TGtkFileEdit);
  141. class_size : SizeOf(TGtkFileEditClass);
  142. class_init_func : TGtkClassInitFunc(@GtkFileEditClassInit);
  143. object_init_func : TGtkObjectInitFunc(@GtkFileEditInit);
  144. reserved_1 : Nil;
  145. reserved_2 : Nil;
  146. base_class_init_func : Nil
  147. );
  148. begin
  149. if (GtkFileEditType=0) then
  150. GtkFileEditType:=gtk_type_unique(gtk_hbox_get_type,@GtkFileEditInfo);
  151. Result:=GtkFileEditType;
  152. end;
  153. \end{lstlisting}
  154. The fields of the \lstinline|TGtkTypeInfo| record are filled with the following
  155. information:
  156. \begin{description}
  157. \item[type\_name] Contains the name of the type that must be registered.
  158. \item[object\_size] The size of the object record. GTK itself will allocate
  159. the memory when an new instance of the object is created, so it must know the
  160. size of the object.
  161. \item[class\_size] The size of the class object. Only one instance of this
  162. record will be created (by GTK)
  163. \item[class\_init\_func] The address of a function that will initialize the
  164. class record. This function accepts as a single arument a pointer to the
  165. class record to be initialized. This function will normally be called only
  166. once.
  167. \item[object\_init\_func] The address of a function that will initialize
  168. an instance of the object. The function must accept as a single argument
  169. a pointer to an instance of the object. This instance will be created by
  170. GTK. This function is called for each instance of the object.
  171. \end{description}
  172. The other three fields of the record are unfortunately not documented, so
  173. they are left blank.
  174. The component is registered by passing along a suitably filled
  175. \lstinline|TGtkTypeInfo| record together with the type of the parent class
  176. (acquired with it's \lstinline|gtk\_hbox\_get\_type| function) to the
  177. \lstinline|gtk\_type\_unique| function. this function will return a numeric ID for
  178. the \lstinline|GtkFileEdit| class.
  179. If a \lstinline|class\_init\_func| was specified when registering the new type,
  180. then GTK will call this method; it should initialize any class-specific
  181. data in the class record. In the case of the \lstinline|GTKFileEdit|, the bitmap
  182. which is used to fill the button is loaded:
  183. \begin{lstlisting}{}
  184. Procedure GtkFileEditClassInit (CObj : PGtkFileEditClass);cdecl;
  185. begin
  186. With Cobj^ do
  187. DefaultPixMap:=gdk_pixmap_create_from_xpm(Nil,@DefaultBitmap,
  188. Nil,'fileopen.xpm');
  189. end;
  190. \end{lstlisting}
  191. The \lstinline|gdk_pixmap_create_from_xpm| does 2 things: It loads a bitmap
  192. from the \textsf{fileopen.xpm} file and returns a PGdkPixmap pointer.
  193. At the same time it returns a pointer to a bitmask which designates the
  194. transparant regions of the bitmap.
  195. The result of this function is stored in the class record, so the bitmap
  196. is available when a new instance of the class is created.
  197. \end{document}