1 | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> |
---|
2 | <HTML> |
---|
3 | <HEAD> |
---|
4 | <META NAME="GENERATOR" CONTENT="SGML-Tools 1.0.9"> |
---|
5 | <TITLE>GTK v1.2 Tutorial: Getting Started</TITLE> |
---|
6 | <LINK HREF="gtk_tut-3.html" REL=next> |
---|
7 | <LINK HREF="gtk_tut-1.html" REL=previous> |
---|
8 | <LINK HREF="gtk_tut.html#toc2" REL=contents> |
---|
9 | </HEAD> |
---|
10 | <BODY BGCOLOR="#FFFFFF"> |
---|
11 | <A HREF="gtk_tut-3.html">Next</A> |
---|
12 | <A HREF="gtk_tut-1.html">Previous</A> |
---|
13 | <A HREF="gtk_tut.html#toc2">Contents</A> |
---|
14 | <HR NOSHADE> |
---|
15 | <H2><A NAME="s2">2. Getting Started</A></H2> |
---|
16 | |
---|
17 | <P>The first thing to do, of course, is download the GTK source and |
---|
18 | install it. You can always get the latest version from ftp.gtk.org in |
---|
19 | /pub/gtk. You can also view other sources of GTK information on |
---|
20 | <A HREF="http://www.gtk.org/">http://www.gtk.org/</A>. GTK |
---|
21 | uses GNU autoconf for configuration. Once untar'd, type ./configure |
---|
22 | --help to see a list of options. |
---|
23 | <P>The GTK source distribution also contains the complete source to all |
---|
24 | of the examples used in this tutorial, along with Makefiles to aid |
---|
25 | compilation. |
---|
26 | <P>To begin our introduction to GTK, we'll start with the simplest |
---|
27 | program possible. This program will create a 200x200 pixel window and |
---|
28 | has no way of exiting except to be killed by using the shell. |
---|
29 | <P> |
---|
30 | <BLOCKQUOTE><CODE> |
---|
31 | <PRE> |
---|
32 | /* example-start base base.c */ |
---|
33 | |
---|
34 | #include <gtk/gtk.h> |
---|
35 | |
---|
36 | int main( int argc, |
---|
37 | char *argv[] ) |
---|
38 | { |
---|
39 | GtkWidget *window; |
---|
40 | |
---|
41 | gtk_init (&argc, &argv); |
---|
42 | |
---|
43 | window = gtk_window_new (GTK_WINDOW_TOPLEVEL); |
---|
44 | gtk_widget_show (window); |
---|
45 | |
---|
46 | gtk_main (); |
---|
47 | |
---|
48 | return(0); |
---|
49 | } |
---|
50 | /* example-end */ |
---|
51 | </PRE> |
---|
52 | </CODE></BLOCKQUOTE> |
---|
53 | <P>You can compile the above program with gcc using: |
---|
54 | <BLOCKQUOTE><CODE> |
---|
55 | <PRE> |
---|
56 | gcc base.c -o base `gtk-config --cflags --libs` |
---|
57 | </PRE> |
---|
58 | </CODE></BLOCKQUOTE> |
---|
59 | <P>The meaning of the unusual compilation options is explained below in |
---|
60 | <A HREF="#sec_compiling">Compiling Hello World</A>. |
---|
61 | <P>All programs will of course include gtk/gtk.h which declares the |
---|
62 | variables, functions, structures, etc. that will be used in your GTK |
---|
63 | application. |
---|
64 | <P>The next line: |
---|
65 | <P> |
---|
66 | <BLOCKQUOTE><CODE> |
---|
67 | <PRE> |
---|
68 | gtk_init (&argc, &argv); |
---|
69 | </PRE> |
---|
70 | </CODE></BLOCKQUOTE> |
---|
71 | <P>calls the function gtk_init(gint *argc, gchar ***argv) which will be |
---|
72 | called in all GTK applications. This sets up a few things for us such |
---|
73 | as the default visual and color map and then proceeds to call |
---|
74 | gdk_init(gint *argc, gchar ***argv). This function initializes the |
---|
75 | library for use, sets up default signal handlers, and checks the |
---|
76 | arguments passed to your application on the command line, looking for |
---|
77 | one of the following: |
---|
78 | <P> |
---|
79 | <UL> |
---|
80 | <LI> <CODE>--gtk-module</CODE></LI> |
---|
81 | <LI> <CODE>--g-fatal-warnings</CODE></LI> |
---|
82 | <LI> <CODE>--gtk-debug</CODE></LI> |
---|
83 | <LI> <CODE>--gtk-no-debug</CODE></LI> |
---|
84 | <LI> <CODE>--gdk-debug</CODE></LI> |
---|
85 | <LI> <CODE>--gdk-no-debug</CODE></LI> |
---|
86 | <LI> <CODE>--display</CODE></LI> |
---|
87 | <LI> <CODE>--sync</CODE></LI> |
---|
88 | <LI> <CODE>--no-xshm</CODE></LI> |
---|
89 | <LI> <CODE>--name</CODE></LI> |
---|
90 | <LI> <CODE>--class</CODE></LI> |
---|
91 | </UL> |
---|
92 | <P>It removes these from the argument list, leaving anything it does not |
---|
93 | recognize for your application to parse or ignore. This creates a set |
---|
94 | of standard arguments accepted by all GTK applications. |
---|
95 | <P>The next two lines of code create and display a window. |
---|
96 | <P> |
---|
97 | <BLOCKQUOTE><CODE> |
---|
98 | <PRE> |
---|
99 | window = gtk_window_new (GTK_WINDOW_TOPLEVEL); |
---|
100 | gtk_widget_show (window); |
---|
101 | </PRE> |
---|
102 | </CODE></BLOCKQUOTE> |
---|
103 | <P>The <CODE>GTK_WINDOW_TOPLEVEL</CODE> argument specifies that we want the |
---|
104 | window to undergo window manager decoration and placement. Rather than |
---|
105 | create a window of 0x0 size, a window without children is set to |
---|
106 | 200x200 by default so you can still manipulate it. |
---|
107 | <P>The gtk_widget_show() function lets GTK know that we are done setting |
---|
108 | the attributes of this widget, and that it can display it. |
---|
109 | <P>The last line enters the GTK main processing loop. |
---|
110 | <P> |
---|
111 | <BLOCKQUOTE><CODE> |
---|
112 | <PRE> |
---|
113 | gtk_main (); |
---|
114 | </PRE> |
---|
115 | </CODE></BLOCKQUOTE> |
---|
116 | <P>gtk_main() is another call you will see in every GTK application. |
---|
117 | When control reaches this point, GTK will sleep waiting for X events |
---|
118 | (such as button or key presses), timeouts, or file IO notifications to |
---|
119 | occur. In our simple example, however, events are ignored. |
---|
120 | <P> |
---|
121 | <H2><A NAME="ss2.1">2.1 Hello World in GTK</A> |
---|
122 | </H2> |
---|
123 | |
---|
124 | <P>Now for a program with a widget (a button). It's the classic |
---|
125 | hello world a la GTK. |
---|
126 | <P> |
---|
127 | <BLOCKQUOTE><CODE> |
---|
128 | <PRE> |
---|
129 | /* example-start helloworld helloworld.c */ |
---|
130 | |
---|
131 | #include <gtk/gtk.h> |
---|
132 | |
---|
133 | /* This is a callback function. The data arguments are ignored |
---|
134 | * in this example. More on callbacks below. */ |
---|
135 | void hello( GtkWidget *widget, |
---|
136 | gpointer data ) |
---|
137 | { |
---|
138 | g_print ("Hello World\n"); |
---|
139 | } |
---|
140 | |
---|
141 | gint delete_event( GtkWidget *widget, |
---|
142 | GdkEvent *event, |
---|
143 | gpointer data ) |
---|
144 | { |
---|
145 | /* If you return FALSE in the "delete_event" signal handler, |
---|
146 | * GTK will emit the "destroy" signal. Returning TRUE means |
---|
147 | * you don't want the window to be destroyed. |
---|
148 | * This is useful for popping up 'are you sure you want to quit?' |
---|
149 | * type dialogs. */ |
---|
150 | |
---|
151 | g_print ("delete event occurred\n"); |
---|
152 | |
---|
153 | /* Change TRUE to FALSE and the main window will be destroyed with |
---|
154 | * a "delete_event". */ |
---|
155 | |
---|
156 | return(TRUE); |
---|
157 | } |
---|
158 | |
---|
159 | /* Another callback */ |
---|
160 | void destroy( GtkWidget *widget, |
---|
161 | gpointer data ) |
---|
162 | { |
---|
163 | gtk_main_quit(); |
---|
164 | } |
---|
165 | |
---|
166 | int main( int argc, |
---|
167 | char *argv[] ) |
---|
168 | { |
---|
169 | /* GtkWidget is the storage type for widgets */ |
---|
170 | GtkWidget *window; |
---|
171 | GtkWidget *button; |
---|
172 | |
---|
173 | /* This is called in all GTK applications. Arguments are parsed |
---|
174 | * from the command line and are returned to the application. */ |
---|
175 | gtk_init(&argc, &argv); |
---|
176 | |
---|
177 | /* create a new window */ |
---|
178 | window = gtk_window_new (GTK_WINDOW_TOPLEVEL); |
---|
179 | |
---|
180 | /* When the window is given the "delete_event" signal (this is given |
---|
181 | * by the window manager, usually by the "close" option, or on the |
---|
182 | * titlebar), we ask it to call the delete_event () function |
---|
183 | * as defined above. The data passed to the callback |
---|
184 | * function is NULL and is ignored in the callback function. */ |
---|
185 | gtk_signal_connect (GTK_OBJECT (window), "delete_event", |
---|
186 | GTK_SIGNAL_FUNC (delete_event), NULL); |
---|
187 | |
---|
188 | /* Here we connect the "destroy" event to a signal handler. |
---|
189 | * This event occurs when we call gtk_widget_destroy() on the window, |
---|
190 | * or if we return FALSE in the "delete_event" callback. */ |
---|
191 | gtk_signal_connect (GTK_OBJECT (window), "destroy", |
---|
192 | GTK_SIGNAL_FUNC (destroy), NULL); |
---|
193 | |
---|
194 | /* Sets the border width of the window. */ |
---|
195 | gtk_container_set_border_width (GTK_CONTAINER (window), 10); |
---|
196 | |
---|
197 | /* Creates a new button with the label "Hello World". */ |
---|
198 | button = gtk_button_new_with_label ("Hello World"); |
---|
199 | |
---|
200 | /* When the button receives the "clicked" signal, it will call the |
---|
201 | * function hello() passing it NULL as its argument. The hello() |
---|
202 | * function is defined above. */ |
---|
203 | gtk_signal_connect (GTK_OBJECT (button), "clicked", |
---|
204 | GTK_SIGNAL_FUNC (hello), NULL); |
---|
205 | |
---|
206 | /* This will cause the window to be destroyed by calling |
---|
207 | * gtk_widget_destroy(window) when "clicked". Again, the destroy |
---|
208 | * signal could come from here, or the window manager. */ |
---|
209 | gtk_signal_connect_object (GTK_OBJECT (button), "clicked", |
---|
210 | GTK_SIGNAL_FUNC (gtk_widget_destroy), |
---|
211 | GTK_OBJECT (window)); |
---|
212 | |
---|
213 | /* This packs the button into the window (a gtk container). */ |
---|
214 | gtk_container_add (GTK_CONTAINER (window), button); |
---|
215 | |
---|
216 | /* The final step is to display this newly created widget. */ |
---|
217 | gtk_widget_show (button); |
---|
218 | |
---|
219 | /* and the window */ |
---|
220 | gtk_widget_show (window); |
---|
221 | |
---|
222 | /* All GTK applications must have a gtk_main(). Control ends here |
---|
223 | * and waits for an event to occur (like a key press or |
---|
224 | * mouse event). */ |
---|
225 | gtk_main (); |
---|
226 | |
---|
227 | return(0); |
---|
228 | } |
---|
229 | /* example-end */ |
---|
230 | </PRE> |
---|
231 | </CODE></BLOCKQUOTE> |
---|
232 | <P> |
---|
233 | <H2><A NAME="sec_compiling"></A> <A NAME="ss2.2">2.2 Compiling Hello World </A> |
---|
234 | </H2> |
---|
235 | |
---|
236 | <P>To compile use: |
---|
237 | <P> |
---|
238 | <BLOCKQUOTE><CODE> |
---|
239 | <PRE> |
---|
240 | gcc -Wall -g helloworld.c -o helloworld `gtk-config --cflags` \ |
---|
241 | `gtk-config --libs` |
---|
242 | </PRE> |
---|
243 | </CODE></BLOCKQUOTE> |
---|
244 | <P>This uses the program <CODE>gtk-config</CODE>, which comes with GTK. This |
---|
245 | program "knows" what compiler switches are needed to compile programs |
---|
246 | that use GTK. <CODE>gtk-config --cflags</CODE> will output a list of include |
---|
247 | directories for the compiler to look in, and <CODE>gtk-config --libs</CODE> |
---|
248 | will output the list of libraries for the compiler to link with and |
---|
249 | the directories to find them in. In the above example they could have |
---|
250 | been combined into a single instance, such as |
---|
251 | <CODE>`gtk-config --cflags --libs`</CODE>. |
---|
252 | <P>Note that the type of single quote used in the compile command above |
---|
253 | is significant. |
---|
254 | <P>The libraries that are usually linked in are: |
---|
255 | <UL> |
---|
256 | <LI>The GTK library (-lgtk), the widget library, based on top of GDK.</LI> |
---|
257 | <LI>The GDK library (-lgdk), the Xlib wrapper.</LI> |
---|
258 | <LI>The gmodule library (-lgmodule), which is used to load run time |
---|
259 | extensions.</LI> |
---|
260 | <LI>The GLib library (-lglib), containing miscellaneous functions; |
---|
261 | only g_print() is used in this particular example. GTK is built on top |
---|
262 | of glib so you will always require this library. See the section on |
---|
263 | <A HREF="gtk_tut-20.html#sec_glib">GLib</A> for details.</LI> |
---|
264 | <LI>The Xlib library (-lX11) which is used by GDK.</LI> |
---|
265 | <LI>The Xext library (-lXext). This contains code for shared memory |
---|
266 | pixmaps and other X extensions.</LI> |
---|
267 | <LI>The math library (-lm). This is used by GTK for various purposes.</LI> |
---|
268 | </UL> |
---|
269 | <P> |
---|
270 | <H2><A NAME="ss2.3">2.3 Theory of Signals and Callbacks</A> |
---|
271 | </H2> |
---|
272 | |
---|
273 | <P>Before we look in detail at <EM>helloworld</EM>, we'll discuss signals |
---|
274 | and callbacks. GTK is an event driven toolkit, which means it will |
---|
275 | sleep in gtk_main until an event occurs and control is passed to the |
---|
276 | appropriate function. |
---|
277 | <P>This passing of control is done using the idea of "signals". (Note |
---|
278 | that these signals are not the same as the Unix system signals, and |
---|
279 | are not implemented using them, although the terminology is almost |
---|
280 | identical.) When an event occurs, such as the press of a mouse button, |
---|
281 | the appropriate signal will be "emitted" by the widget that was |
---|
282 | pressed. This is how GTK does most of its useful work. There are |
---|
283 | signals that all widgets inherit, such as "destroy", and there are |
---|
284 | signals that are widget specific, such as "toggled" on a toggle |
---|
285 | button. |
---|
286 | <P>To make a button perform an action, we set up a signal handler to |
---|
287 | catch these signals and call the appropriate function. This is done by |
---|
288 | using a function such as: |
---|
289 | <P> |
---|
290 | <BLOCKQUOTE><CODE> |
---|
291 | <PRE> |
---|
292 | gint gtk_signal_connect( GtkObject *object, |
---|
293 | gchar *name, |
---|
294 | GtkSignalFunc func, |
---|
295 | gpointer func_data ); |
---|
296 | </PRE> |
---|
297 | </CODE></BLOCKQUOTE> |
---|
298 | <P>where the first argument is the widget which will be emitting the |
---|
299 | signal, and the second the name of the signal you wish to catch. The |
---|
300 | third is the function you wish to be called when it is caught, and the |
---|
301 | fourth, the data you wish to have passed to this function. |
---|
302 | <P>The function specified in the third argument is called a "callback |
---|
303 | function", and should generally be of the form |
---|
304 | <P> |
---|
305 | <BLOCKQUOTE><CODE> |
---|
306 | <PRE> |
---|
307 | void callback_func( GtkWidget *widget, |
---|
308 | gpointer callback_data ); |
---|
309 | </PRE> |
---|
310 | </CODE></BLOCKQUOTE> |
---|
311 | <P>where the first argument will be a pointer to the widget that emitted |
---|
312 | the signal, and the second a pointer to the data given as the last |
---|
313 | argument to the gtk_signal_connect() function as shown above. |
---|
314 | <P>Note that the above form for a signal callback function declaration is |
---|
315 | only a general guide, as some widget specific signals generate |
---|
316 | different calling parameters. For example, the CList "select_row" |
---|
317 | signal provides both row and column parameters. |
---|
318 | <P>Another call used in the <EM>helloworld</EM> example, is: |
---|
319 | <P> |
---|
320 | <BLOCKQUOTE><CODE> |
---|
321 | <PRE> |
---|
322 | gint gtk_signal_connect_object( GtkObject *object, |
---|
323 | gchar *name, |
---|
324 | GtkSignalFunc func, |
---|
325 | GtkObject *slot_object ); |
---|
326 | </PRE> |
---|
327 | </CODE></BLOCKQUOTE> |
---|
328 | <P>gtk_signal_connect_object() is the same as gtk_signal_connect() except |
---|
329 | that the callback function only uses one argument, a pointer to a GTK |
---|
330 | object. So when using this function to connect signals, the callback |
---|
331 | should be of the form |
---|
332 | <P> |
---|
333 | <BLOCKQUOTE><CODE> |
---|
334 | <PRE> |
---|
335 | void callback_func( GtkObject *object ); |
---|
336 | </PRE> |
---|
337 | </CODE></BLOCKQUOTE> |
---|
338 | <P>where the object is usually a widget. We usually don't setup callbacks |
---|
339 | for gtk_signal_connect_object however. They are usually used to call a |
---|
340 | GTK function that accepts a single widget or object as an argument, as |
---|
341 | is the case in our <EM>helloworld</EM> example. |
---|
342 | <P>The purpose of having two functions to connect signals is simply to |
---|
343 | allow the callbacks to have a different number of arguments. Many |
---|
344 | functions in the GTK library accept only a single GtkWidget pointer as |
---|
345 | an argument, so you want to use the gtk_signal_connect_object() for |
---|
346 | these, whereas for your functions, you may need to have additional |
---|
347 | data supplied to the callbacks. |
---|
348 | <P> |
---|
349 | <H2><A NAME="ss2.4">2.4 Events</A> |
---|
350 | </H2> |
---|
351 | |
---|
352 | <P>In addition to the signal mechanism described above, there is a set |
---|
353 | of <EM>events</EM> that reflect the X event mechanism. Callbacks may |
---|
354 | also be attached to these events. These events are: |
---|
355 | <P> |
---|
356 | <UL> |
---|
357 | <LI> event</LI> |
---|
358 | <LI> button_press_event</LI> |
---|
359 | <LI> button_release_event</LI> |
---|
360 | <LI> motion_notify_event</LI> |
---|
361 | <LI> delete_event</LI> |
---|
362 | <LI> destroy_event</LI> |
---|
363 | <LI> expose_event</LI> |
---|
364 | <LI> key_press_event</LI> |
---|
365 | <LI> key_release_event</LI> |
---|
366 | <LI> enter_notify_event</LI> |
---|
367 | <LI> leave_notify_event</LI> |
---|
368 | <LI> configure_event</LI> |
---|
369 | <LI> focus_in_event</LI> |
---|
370 | <LI> focus_out_event</LI> |
---|
371 | <LI> map_event</LI> |
---|
372 | <LI> unmap_event</LI> |
---|
373 | <LI> property_notify_event</LI> |
---|
374 | <LI> selection_clear_event</LI> |
---|
375 | <LI> selection_request_event</LI> |
---|
376 | <LI> selection_notify_event</LI> |
---|
377 | <LI> proximity_in_event</LI> |
---|
378 | <LI> proximity_out_event</LI> |
---|
379 | <LI> drag_begin_event</LI> |
---|
380 | <LI> drag_request_event</LI> |
---|
381 | <LI> drag_end_event</LI> |
---|
382 | <LI> drop_enter_event</LI> |
---|
383 | <LI> drop_leave_event</LI> |
---|
384 | <LI> drop_data_available_event</LI> |
---|
385 | <LI> other_event</LI> |
---|
386 | </UL> |
---|
387 | <P>In order to connect a callback function to one of these events, you |
---|
388 | use the function gtk_signal_connect, as described above, using one of |
---|
389 | the above event names as the <CODE>name</CODE> parameter. The callback |
---|
390 | function for events has a slightly different form than that for |
---|
391 | signals: |
---|
392 | <P> |
---|
393 | <BLOCKQUOTE><CODE> |
---|
394 | <PRE> |
---|
395 | void callback_func( GtkWidget *widget, |
---|
396 | GdkEvent *event, |
---|
397 | gpointer callback_data ); |
---|
398 | </PRE> |
---|
399 | </CODE></BLOCKQUOTE> |
---|
400 | <P>GdkEvent is a C <CODE>union</CODE> structure whose type will depend upon which |
---|
401 | of the above events has occurred. In order for us to tell which event |
---|
402 | has been issued each of the possible alternatives has a <CODE>type</CODE> |
---|
403 | parameter which reflects the event being issued. The other components |
---|
404 | of the event structure will depend upon the type of the |
---|
405 | event. Possible values for the type are: |
---|
406 | <P> |
---|
407 | <BLOCKQUOTE><CODE> |
---|
408 | <PRE> |
---|
409 | GDK_NOTHING |
---|
410 | GDK_DELETE |
---|
411 | GDK_DESTROY |
---|
412 | GDK_EXPOSE |
---|
413 | GDK_MOTION_NOTIFY |
---|
414 | GDK_BUTTON_PRESS |
---|
415 | GDK_2BUTTON_PRESS |
---|
416 | GDK_3BUTTON_PRESS |
---|
417 | GDK_BUTTON_RELEASE |
---|
418 | GDK_KEY_PRESS |
---|
419 | GDK_KEY_RELEASE |
---|
420 | GDK_ENTER_NOTIFY |
---|
421 | GDK_LEAVE_NOTIFY |
---|
422 | GDK_FOCUS_CHANGE |
---|
423 | GDK_CONFIGURE |
---|
424 | GDK_MAP |
---|
425 | GDK_UNMAP |
---|
426 | GDK_PROPERTY_NOTIFY |
---|
427 | GDK_SELECTION_CLEAR |
---|
428 | GDK_SELECTION_REQUEST |
---|
429 | GDK_SELECTION_NOTIFY |
---|
430 | GDK_PROXIMITY_IN |
---|
431 | GDK_PROXIMITY_OUT |
---|
432 | GDK_DRAG_BEGIN |
---|
433 | GDK_DRAG_REQUEST |
---|
434 | GDK_DROP_ENTER |
---|
435 | GDK_DROP_LEAVE |
---|
436 | GDK_DROP_DATA_AVAIL |
---|
437 | GDK_CLIENT_EVENT |
---|
438 | GDK_VISIBILITY_NOTIFY |
---|
439 | GDK_NO_EXPOSE |
---|
440 | GDK_OTHER_EVENT /* Deprecated, use filters instead */ |
---|
441 | </PRE> |
---|
442 | </CODE></BLOCKQUOTE> |
---|
443 | <P>So, to connect a callback function to one of these events we would use |
---|
444 | something like: |
---|
445 | <P> |
---|
446 | <BLOCKQUOTE><CODE> |
---|
447 | <PRE> |
---|
448 | gtk_signal_connect( GTK_OBJECT(button), "button_press_event", |
---|
449 | GTK_SIGNAL_FUNC(button_press_callback), |
---|
450 | NULL); |
---|
451 | </PRE> |
---|
452 | </CODE></BLOCKQUOTE> |
---|
453 | <P>This assumes that <CODE>button</CODE> is a Button widget. Now, when the |
---|
454 | mouse is over the button and a mouse button is pressed, the function |
---|
455 | <CODE>button_press_callback</CODE> will be called. This function may be |
---|
456 | declared as: |
---|
457 | <P> |
---|
458 | <BLOCKQUOTE><CODE> |
---|
459 | <PRE> |
---|
460 | static gint button_press_callback( GtkWidget *widget, |
---|
461 | GdkEventButton *event, |
---|
462 | gpointer data ); |
---|
463 | </PRE> |
---|
464 | </CODE></BLOCKQUOTE> |
---|
465 | <P>Note that we can declare the second argument as type |
---|
466 | <CODE>GdkEventButton</CODE> as we know what type of event will occur for this |
---|
467 | function to be called. |
---|
468 | <P>The value returned from this function indicates whether the event |
---|
469 | should be propagated further by the GTK event handling |
---|
470 | mechanism. Returning TRUE indicates that the event has been handled, |
---|
471 | and that it should not propagate further. Returning FALSE continues |
---|
472 | the normal event handling. See the section on |
---|
473 | <A HREF="gtk_tut-18.html#sec_Adv_Events_and_Signals">Advanced Event and Signal Handling</A> for more details on this |
---|
474 | propagation process. |
---|
475 | <P>For details on the GdkEvent data types, see the appendix entitled |
---|
476 | <A HREF="gtk_tut-29.html#sec_GDK_Event_Types">GDK Event Types</A>. |
---|
477 | <P> |
---|
478 | <H2><A NAME="ss2.5">2.5 Stepping Through Hello World</A> |
---|
479 | </H2> |
---|
480 | |
---|
481 | <P>Now that we know the theory behind this, let's clarify by walking |
---|
482 | through the example <EM>helloworld</EM> program. |
---|
483 | <P>Here is the callback function that will be called when the button is |
---|
484 | "clicked". We ignore both the widget and the data in this example, but |
---|
485 | it is not hard to do things with them. The next example will use the |
---|
486 | data argument to tell us which button was pressed. |
---|
487 | <P> |
---|
488 | <BLOCKQUOTE><CODE> |
---|
489 | <PRE> |
---|
490 | void hello( GtkWidget *widget, |
---|
491 | gpointer data ) |
---|
492 | { |
---|
493 | g_print ("Hello World\n"); |
---|
494 | } |
---|
495 | </PRE> |
---|
496 | </CODE></BLOCKQUOTE> |
---|
497 | <P>The next callback is a bit special. The "delete_event" occurs when the |
---|
498 | window manager sends this event to the application. We have a choice |
---|
499 | here as to what to do about these events. We can ignore them, make |
---|
500 | some sort of response, or simply quit the application. |
---|
501 | <P>The value you return in this callback lets GTK know what action to |
---|
502 | take. By returning TRUE, we let it know that we don't want to have |
---|
503 | the "destroy" signal emitted, keeping our application running. By |
---|
504 | returning FALSE, we ask that "destroy" be emitted, which in turn will |
---|
505 | call our "destroy" signal handler. |
---|
506 | <P> |
---|
507 | <BLOCKQUOTE><CODE> |
---|
508 | <PRE> |
---|
509 | gint delete_event( GtkWidget *widget, |
---|
510 | GdkEvent *event, |
---|
511 | gpointer data ) |
---|
512 | { |
---|
513 | g_print ("delete event occurred\n"); |
---|
514 | |
---|
515 | return (TRUE); |
---|
516 | } |
---|
517 | </PRE> |
---|
518 | </CODE></BLOCKQUOTE> |
---|
519 | <P>Here is another callback function which causes the program to quit by |
---|
520 | calling gtk_main_quit(). This function tells GTK that it is to exit |
---|
521 | from gtk_main when control is returned to it. |
---|
522 | <P> |
---|
523 | <BLOCKQUOTE><CODE> |
---|
524 | <PRE> |
---|
525 | void destroy( GtkWidget *widget, |
---|
526 | gpointer data ) |
---|
527 | { |
---|
528 | gtk_main_quit (); |
---|
529 | } |
---|
530 | </PRE> |
---|
531 | </CODE></BLOCKQUOTE> |
---|
532 | <P>I assume you know about the main() function... yes, as with other |
---|
533 | applications, all GTK applications will also have one of these. |
---|
534 | <P> |
---|
535 | <BLOCKQUOTE><CODE> |
---|
536 | <PRE> |
---|
537 | int main( int argc, |
---|
538 | char *argv[] ) |
---|
539 | { |
---|
540 | </PRE> |
---|
541 | </CODE></BLOCKQUOTE> |
---|
542 | <P>This next part declares pointers to a structure of type |
---|
543 | GtkWidget. These are used below to create a window and a button. |
---|
544 | <P> |
---|
545 | <BLOCKQUOTE><CODE> |
---|
546 | <PRE> |
---|
547 | GtkWidget *window; |
---|
548 | GtkWidget *button; |
---|
549 | </PRE> |
---|
550 | </CODE></BLOCKQUOTE> |
---|
551 | <P>Here is our gtk_init again. As before, this initializes the toolkit, |
---|
552 | and parses the arguments found on the command line. Any argument it |
---|
553 | recognizes from the command line, it removes from the list, and |
---|
554 | modifies argc and argv to make it look like they never existed, |
---|
555 | allowing your application to parse the remaining arguments. |
---|
556 | <P> |
---|
557 | <BLOCKQUOTE><CODE> |
---|
558 | <PRE> |
---|
559 | gtk_init (&argc, &argv); |
---|
560 | </PRE> |
---|
561 | </CODE></BLOCKQUOTE> |
---|
562 | <P>Create a new window. This is fairly straightforward. Memory is |
---|
563 | allocated for the GtkWidget *window structure so it now points to a |
---|
564 | valid structure. It sets up a new window, but it is not displayed |
---|
565 | until we call gtk_widget_show(window) near the end of our program. |
---|
566 | <P> |
---|
567 | <BLOCKQUOTE><CODE> |
---|
568 | <PRE> |
---|
569 | window = gtk_window_new (GTK_WINDOW_TOPLEVEL); |
---|
570 | </PRE> |
---|
571 | </CODE></BLOCKQUOTE> |
---|
572 | <P>Here are two examples of connecting a signal handler to an object, in |
---|
573 | this case, the window. Here, the "delete_event" and "destroy" signals |
---|
574 | are caught. The first is emitted when we use the window manager to |
---|
575 | kill the window, or when we use the gtk_widget_destroy() call passing |
---|
576 | in the window widget as the object to destroy. The second is emitted |
---|
577 | when, in the "delete_event" handler, we return FALSE. |
---|
578 | <P>The <CODE>GTK_OBJECT</CODE> and <CODE>GTK_SIGNAL_FUNC</CODE> are macros that perform |
---|
579 | type casting and checking for us, as well as aid the readability of |
---|
580 | the code. |
---|
581 | <P> |
---|
582 | <BLOCKQUOTE><CODE> |
---|
583 | <PRE> |
---|
584 | gtk_signal_connect (GTK_OBJECT (window), "delete_event", |
---|
585 | GTK_SIGNAL_FUNC (delete_event), NULL); |
---|
586 | gtk_signal_connect (GTK_OBJECT (window), "destroy", |
---|
587 | GTK_SIGNAL_FUNC (destroy), NULL); |
---|
588 | </PRE> |
---|
589 | </CODE></BLOCKQUOTE> |
---|
590 | <P>This next function is used to set an attribute of a container object. |
---|
591 | This just sets the window so it has a blank area along the inside of |
---|
592 | it 10 pixels wide where no widgets will go. There are other similar |
---|
593 | functions which we will look at in the section on |
---|
594 | <A HREF="gtk_tut-16.html#sec_setting_widget_attributes">Setting Widget Attributes</A><P>And again, <CODE>GTK_CONTAINER</CODE> is a macro to perform type casting. |
---|
595 | <P> |
---|
596 | <BLOCKQUOTE><CODE> |
---|
597 | <PRE> |
---|
598 | gtk_container_set_border_width (GTK_CONTAINER (window), 10); |
---|
599 | </PRE> |
---|
600 | </CODE></BLOCKQUOTE> |
---|
601 | <P>This call creates a new button. It allocates space for a new GtkWidget |
---|
602 | structure in memory, initializes it, and makes the button pointer |
---|
603 | point to it. It will have the label "Hello World" on it when |
---|
604 | displayed. |
---|
605 | <P> |
---|
606 | <BLOCKQUOTE><CODE> |
---|
607 | <PRE> |
---|
608 | button = gtk_button_new_with_label ("Hello World"); |
---|
609 | </PRE> |
---|
610 | </CODE></BLOCKQUOTE> |
---|
611 | <P>Here, we take this button, and make it do something useful. We attach |
---|
612 | a signal handler to it so when it emits the "clicked" signal, our |
---|
613 | hello() function is called. The data is ignored, so we simply pass in |
---|
614 | NULL to the hello() callback function. Obviously, the "clicked" signal |
---|
615 | is emitted when we click the button with our mouse pointer. |
---|
616 | <P> |
---|
617 | <BLOCKQUOTE><CODE> |
---|
618 | <PRE> |
---|
619 | gtk_signal_connect (GTK_OBJECT (button), "clicked", |
---|
620 | GTK_SIGNAL_FUNC (hello), NULL); |
---|
621 | </PRE> |
---|
622 | </CODE></BLOCKQUOTE> |
---|
623 | <P>We are also going to use this button to exit our program. This will |
---|
624 | illustrate how the "destroy" signal may come from either the window |
---|
625 | manager, or our program. When the button is "clicked", same as above, |
---|
626 | it calls the first hello() callback function, and then this one in the |
---|
627 | order they are set up. You may have as many callback functions as you |
---|
628 | need, and all will be executed in the order you connected |
---|
629 | them. Because the gtk_widget_destroy() function accepts only a |
---|
630 | GtkWidget *widget as an argument, we use the |
---|
631 | gtk_signal_connect_object() function here instead of straight |
---|
632 | gtk_signal_connect(). |
---|
633 | <P> |
---|
634 | <BLOCKQUOTE><CODE> |
---|
635 | <PRE> |
---|
636 | gtk_signal_connect_object (GTK_OBJECT (button), "clicked", |
---|
637 | GTK_SIGNAL_FUNC (gtk_widget_destroy), |
---|
638 | GTK_OBJECT (window)); |
---|
639 | </PRE> |
---|
640 | </CODE></BLOCKQUOTE> |
---|
641 | <P>This is a packing call, which will be explained in depth later on in |
---|
642 | <A HREF="gtk_tut-4.html#sec_packing_widgets">Packing Widgets</A>. But it is |
---|
643 | fairly easy to understand. It simply tells GTK that the button is to |
---|
644 | be placed in the window where it will be displayed. Note that a GTK |
---|
645 | container can only contain one widget. There are other widgets, that |
---|
646 | are described later, which are designed to layout multiple widgets in |
---|
647 | various ways. |
---|
648 | <P> |
---|
649 | <BLOCKQUOTE><CODE> |
---|
650 | <PRE> |
---|
651 | gtk_container_add (GTK_CONTAINER (window), button); |
---|
652 | </PRE> |
---|
653 | </CODE></BLOCKQUOTE> |
---|
654 | <P>Now we have everything set up the way we want it to be. With all the |
---|
655 | signal handlers in place, and the button placed in the window where it |
---|
656 | should be, we ask GTK to "show" the widgets on the screen. The window |
---|
657 | widget is shown last so the whole window will pop up at once rather |
---|
658 | than seeing the window pop up, and then the button form inside of |
---|
659 | it. Although with such a simple example, you'd never notice. |
---|
660 | <P> |
---|
661 | <BLOCKQUOTE><CODE> |
---|
662 | <PRE> |
---|
663 | gtk_widget_show (button); |
---|
664 | |
---|
665 | gtk_widget_show (window); |
---|
666 | </PRE> |
---|
667 | </CODE></BLOCKQUOTE> |
---|
668 | <P>And of course, we call gtk_main() which waits for events to come from |
---|
669 | the X server and will call on the widgets to emit signals when these |
---|
670 | events come. |
---|
671 | <P> |
---|
672 | <BLOCKQUOTE><CODE> |
---|
673 | <PRE> |
---|
674 | gtk_main (); |
---|
675 | </PRE> |
---|
676 | </CODE></BLOCKQUOTE> |
---|
677 | <P>And the final return. Control returns here after gtk_quit() is called. |
---|
678 | <P> |
---|
679 | <BLOCKQUOTE><CODE> |
---|
680 | <PRE> |
---|
681 | return (0); |
---|
682 | </PRE> |
---|
683 | </CODE></BLOCKQUOTE> |
---|
684 | <P>Now, when we click the mouse button on a GTK button, the widget emits |
---|
685 | a "clicked" signal. In order for us to use this information, our |
---|
686 | program sets up a signal handler to catch that signal, which |
---|
687 | dispatches the function of our choice. In our example, when the button |
---|
688 | we created is "clicked", the hello() function is called with a NULL |
---|
689 | argument, and then the next handler for this signal is called. This |
---|
690 | calls the gtk_widget_destroy() function, passing it the window widget |
---|
691 | as its argument, destroying the window widget. This causes the window |
---|
692 | to emit the "destroy" signal, which is caught, and calls our destroy() |
---|
693 | callback function, which simply exits GTK. |
---|
694 | <P>Another course of events is to use the window manager to kill the |
---|
695 | window, which will cause the "delete_event" to be emitted. This will |
---|
696 | call our "delete_event" handler. If we return TRUE here, the window |
---|
697 | will be left as is and nothing will happen. Returning FALSE will cause |
---|
698 | GTK to emit the "destroy" signal which of course calls the "destroy" |
---|
699 | callback, exiting GTK. |
---|
700 | <P> |
---|
701 | <HR NOSHADE> |
---|
702 | <A HREF="gtk_tut-3.html">Next</A> |
---|
703 | <A HREF="gtk_tut-1.html">Previous</A> |
---|
704 | <A HREF="gtk_tut.html#toc2">Contents</A> |
---|
705 | </BODY> |
---|
706 | </HTML> |
---|