]> Pileus Git - ~andy/gtk/blob - docs/tutorial/gtk-tut.sgml
minor fixes
[~andy/gtk] / docs / tutorial / gtk-tut.sgml
1 <!doctype book PUBLIC "-//OASIS//DTD DocBook V3.1//EN" [
2 <!notation PNG system "PNG">
3 <!entity % local.notation.class "| PNG">
4 ]>
5 <book id="gtk-tut">
6
7 <bookinfo>
8     <date>December 7, 2002</date>
9     <title>GTK+ 2.0 Tutorial</title>
10     <authorgroup>
11       <author>
12         <firstname>Tony</firstname>
13         <surname>Gale</surname>
14       </author>
15       <author>
16         <firstname>Ian</firstname>
17         <surname>Main</surname>
18       </author>
19       <author>
20         <firstname>&amp; the GTK team</firstname>
21       </author>
22     </authorgroup>
23     <abstract>
24       <para>This is a tutorial on how to use GTK (the GIMP Toolkit) through its C
25             interface.</para>
26     </abstract>
27   </bookinfo>
28
29 <toc></toc>
30
31 <!-- ***************************************************************** -->
32 <chapter id="ch-TutorialDownload">
33 <title>Tutorial Availability</title>
34
35 <para>A copy of this tutorial in SGML and HTML is distributed with each
36 source code release of GTK+. For binary distributions, please check with
37 your vendor.</para>
38
39 <para>A copy is available online for reference at <ulink 
40 url="http://www.gtk.org/tutorial/">http://www.gtk.org/tutorial</ulink>.</para>
41
42 <para>A packaged verion of this tutorial is available from
43 <ulink url="ftp://ftp.gtk.org/pub/gtk/tutorial/">
44 ftp://ftp.gtk.org/pub/gtk/tutorial</ulink> which contains the tutorial in
45 various different formats. This
46 package is primary for those people wanting to have the tutorial
47 available for offline reference and for printing.</para>
48
49 </chapter>
50
51 <!-- ***************************************************************** -->
52 <chapter id="ch-Introduction">
53 <title>Introduction</title>
54
55 <para>GTK (GIMP Toolkit) is a library for creating graphical user
56 interfaces. It is licensed using the LGPL license, so you can develop
57 open software, free software, or even commercial non-free software
58 using GTK without having to spend anything for licenses or royalties.</para>
59
60 <para>It's called the GIMP toolkit because it was originally written for
61 developing the GNU Image Manipulation Program (GIMP), but GTK has
62 now been used in a large number of software projects, including the
63 GNU Network Object Model Environment (GNOME) project. GTK is built on
64 top of GDK (GIMP Drawing Kit) which is basically a wrapper around the
65 low-level functions for accessing the underlying windowing functions
66 (Xlib in the case of the X windows system), and gdk-pixbuf, a library for
67 client-side image manipulation.
68 </para>
69 <para>The primary authors of GTK are:</para>
70
71 <itemizedlist>
72 <listitem><simpara> Peter Mattis <ulink url="mailto:petm@xcf.berkeley.edu">
73 petm@xcf.berkeley.edu</ulink></simpara>
74 </listitem>
75 <listitem><simpara> Spencer Kimball <ulink url="mailto:spencer@xcf.berkeley.edu">
76 spencer@xcf.berkeley.edu</ulink></simpara>
77 </listitem>
78 <listitem><simpara> Josh MacDonald <ulink url="mailto:jmacd@xcf.berkeley.edu">
79 jmacd@xcf.berkeley.edu</ulink></simpara>
80 </listitem>
81 </itemizedlist>
82
83 <para>GTK is currently maintained by:</para>
84
85 <itemizedlist>
86 <listitem><simpara> Owen Taylor <ulink url="mailto:otaylor@redhat.com">
87 otaylor@redhat.com</ulink></simpara>
88 </listitem>
89 <listitem><simpara> Tim Janik <ulink url="mailto:timj@gtk.org">
90 timj@gtk.org</ulink></simpara>
91 </listitem>
92 </itemizedlist>
93
94 <para>GTK is essentially an object oriented application programmers
95 interface (API). Although written completely in C, it is implemented
96 using the idea of classes and callback functions (pointers to
97 functions).</para>
98
99 <para>There is also a third component called GLib which contains a few
100 replacements for some standard calls, as well as some additional
101 functions for handling linked lists, etc. The replacement functions
102 are used to increase GTK's portability, as some of the functions
103 implemented here are not available or are nonstandard on other Unixes
104 such as g_strerror(). Some also contain enhancements to the libc
105 versions, such as g_malloc() that has enhanced debugging utilities.</para>
106
107 <para>In version 2.0, GLib has picked up the type system which forms the
108 foundation for GTK's class hierarchy, the signal system which is used
109 throughout GTK, a thread API which abstracts the different native thread APIs 
110 of the various platforms and a facility for loading modules.
111 </para>
112
113 <para>As the last component, GTK uses the Pango library for internationalized
114 text output.
115 </para>
116
117 <para>This tutorial describes the C interface to GTK. There are GTK
118 bindings for many other languages including C++, Guile, Perl, Python,
119 TOM, Ada95, Objective C, Free Pascal, Eiffel, Java and C#. If you intend to
120 use another language's bindings to GTK, look at that binding's
121 documentation first. In some cases that documentation may describe
122 some important conventions (which you should know first) and then
123 refer you back to this tutorial. There are also some cross-platform
124 APIs (such as wxWindows and V) which use GTK as one of their target
125 platforms; again, consult their documentation first.</para>
126
127 <para>If you're developing your GTK application in C++, a few extra notes
128 are in order. There's a C++ binding to GTK called GTK--, which
129 provides a more C++-like interface to GTK; you should probably look
130 into this instead. If you don't like that approach for whatever
131 reason, there are two alternatives for using GTK. First, you can use
132 only the C subset of C++ when interfacing with GTK and then use the C
133 interface as described in this tutorial. Second, you can use GTK and
134 C++ together by declaring all callbacks as static functions in C++
135 classes, and again calling GTK using its C interface. If you choose
136 this last approach, you can include as the callback's data value a
137 pointer to the object to be manipulated (the so-called "this" value).
138 Selecting between these options is simply a matter of preference,
139 since in all three approaches you get C++ and GTK. None of these
140 approaches requires the use of a specialized preprocessor, so no
141 matter what you choose you can use standard C++ with GTK.</para>
142
143 <para>This tutorial is an attempt to document as much as possible of GTK,
144 but it is by no means complete. This tutorial assumes a good
145 understanding of C, and how to create C programs. It would be a great
146 benefit for the reader to have previous X programming experience, but
147 it shouldn't be necessary. If you are learning GTK as your first
148 widget set, please comment on how you found this tutorial, and what
149 you had trouble with. There are also C++, Objective C, ADA, Guile and
150 other language bindings available, but I don't follow these.</para>
151
152 <para>This document is a "work in progress". Please look for updates on
153 <ulink url="http://www.gtk.org/">http://www.gtk.org/</ulink>.</para>
154
155 <para>I would very much like to hear of any problems you have learning GTK
156 from this document, and would appreciate input as to how it may be
157 improved. Please see the section on <link linkend="ch-Contributing">Contributing
158 </link> for further information.</para>
159
160 </chapter>
161
162 <!-- ***************************************************************** -->
163 <chapter id="ch-GettingStarted">
164 <title>Getting Started</title>
165
166 <para>The first thing to do, of course, is download the GTK source and
167 install it. You can always get the latest version from <ulink 
168 url="ftp://ftp.gtk.org/pub/gtk">ftp.gtk.org</ulink>. You can also view 
169 other sources of GTK information on
170 <ulink url="http://www.gtk.org/">http://www.gtk.org/</ulink>. GTK
171 uses GNU autoconf for configuration. Once untar'd, type 
172 <literal>./configure --help</literal> to see a list of options.</para>
173
174 <para>The GTK source distribution also contains the complete source to all
175 of the examples used in this tutorial, along with Makefiles to aid
176 compilation.</para>
177
178 <para>To begin our introduction to GTK, we'll start with the simplest
179 program possible. This program will create a 200x200 pixel window and
180 has no way of exiting except to be killed by using the shell.</para>
181
182 <para>
183 <inlinemediaobject>
184 <imageobject>
185 <imagedata fileref="images/base.png" format="png">
186 </imageobject>
187 </inlinemediaobject>
188 </para>
189
190 <programlisting role="C">
191 <!-- example-start base base.c -->
192
193 #include &lt;gtk/gtk.h&gt;
194
195 int main( int   argc,
196           char *argv[] )
197 {
198     GtkWidget *window;
199     
200     gtk_init (&amp;argc, &amp;argv);
201     
202     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
203     gtk_widget_show  (window);
204     
205     gtk_main ();
206     
207     return 0;
208 }
209 <!-- example-end -->
210 </programlisting>
211
212 <para>You can compile the above program with gcc using:</para>
213 <para><literallayout>
214 <literal>gcc base.c -o base `pkg-config --cflags --libs gtk+-2.0`</literal>
215 </literallayout></para>
216
217 <para>The meaning of the unusual compilation options is explained below in
218 <link linkend="sec-Compiling">Compiling Hello World</link>.</para>
219
220 <para>All programs will of course include <filename>gtk/gtk.h</filename> which 
221 declares the variables, functions, structures, etc. that will be used in your GTK
222 application.</para>
223
224 <para>The next line:</para>
225
226 <programlisting role="C">
227 gtk_init (&amp;argc, &amp;argv);
228 </programlisting>
229
230 <para>calls the function gtk_init(gint *argc, gchar ***argv) which will be called 
231 in all GTK applications. This sets up a few things for us such as the default visual 
232 and color map and then proceeds to call gdk_init(gint *argc, gchar ***argv). 
233 This function initializes the library for use, sets up default signal handlers, and 
234 checks the arguments passed to your application on the command line, looking for
235 one of the following:</para>
236
237 <itemizedlist spacing=Compact>
238 <listitem><simpara> <literal>--gtk-module</literal></simpara>
239 </listitem>
240 <listitem><simpara> <literal>--g-fatal-warnings</literal></simpara>
241 </listitem>
242 <listitem><simpara> <literal>--gtk-debug</literal></simpara>
243 </listitem>
244 <listitem><simpara> <literal>--gtk-no-debug</literal></simpara>
245 </listitem>
246 <listitem><simpara> <literal>--gdk-debug</literal></simpara>
247 </listitem>
248 <listitem><simpara> <literal>--gdk-no-debug</literal></simpara>
249 </listitem>
250 <listitem><simpara> <literal>--display</literal></simpara>
251 </listitem>
252 <listitem><simpara> <literal>--sync</literal></simpara>
253 </listitem>
254 <listitem><simpara> <literal>--name</literal></simpara>
255 </listitem>
256 <listitem><simpara> <literal>--class</literal></simpara>
257 </listitem>
258 </itemizedlist>
259
260 <para>It removes these from the argument list, leaving anything it does not
261 recognize for your application to parse or ignore. This creates a set
262 of standard arguments accepted by all GTK applications.</para>
263
264 <para>The next two lines of code create and display a window.</para>
265
266 <programlisting role="C">
267   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
268   gtk_widget_show (window);
269 </programlisting>
270
271 <para>The <literal>GTK_WINDOW_TOPLEVEL</literal> argument specifies that we want the
272 window to undergo window manager decoration and placement. Rather than
273 create a window of 0x0 size, a window without children is set to
274 200x200 by default so you can still manipulate it.</para>
275
276 <para>The gtk_widget_show() function lets GTK know that we are done setting
277 the attributes of this widget, and that it can display it.</para>
278
279 <para>The last line enters the GTK main processing loop.</para>
280
281 <programlisting role="C">
282   gtk_main ();
283 </programlisting>
284
285 <para>gtk_main() is another call you will see in every GTK application.
286 When control reaches this point, GTK will sleep waiting for X events
287 (such as button or key presses), timeouts, or file IO notifications to
288 occur. In our simple example, however, events are ignored.</para>
289
290 <!-- ----------------------------------------------------------------- -->
291 <sect1 id="sec-HelloWorld">
292 <title>Hello World in GTK</title>
293
294 <para>Now for a program with a widget (a button). It's the classic
295 hello world a la GTK.</para>
296
297 <para>
298 <inlinemediaobject>
299 <imageobject>
300 <imagedata fileref="images/helloworld.png" format="png">
301 </imageobject>
302 </inlinemediaobject>
303 </para>
304
305 <programlisting role="C">
306 <!-- example-start helloworld helloworld.c -->
307
308 #include &lt;gtk/gtk.h&gt;
309
310 /* This is a callback function. The data arguments are ignored
311  * in this example. More on callbacks below. */
312 void hello( GtkWidget *widget,
313             gpointer   data )
314 {
315     g_print ("Hello World\n");
316 }
317
318 gint delete_event( GtkWidget *widget,
319                    GdkEvent  *event,
320                    gpointer   data )
321 {
322     /* If you return FALSE in the "delete_event" signal handler,
323      * GTK will emit the "destroy" signal. Returning TRUE means
324      * you don't want the window to be destroyed.
325      * This is useful for popping up 'are you sure you want to quit?'
326      * type dialogs. */
327
328     g_print ("delete event occurred\n");
329
330     /* Change TRUE to FALSE and the main window will be destroyed with
331      * a "delete_event". */
332
333     return TRUE;
334 }
335
336 /* Another callback */
337 void destroy( GtkWidget *widget,
338               gpointer   data )
339 {
340     gtk_main_quit ();
341 }
342
343 int main( int   argc,
344           char *argv[] )
345 {
346     /* GtkWidget is the storage type for widgets */
347     GtkWidget *window;
348     GtkWidget *button;
349     
350     /* This is called in all GTK applications. Arguments are parsed
351      * from the command line and are returned to the application. */
352     gtk_init (&amp;argc, &amp;argv);
353     
354     /* create a new window */
355     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
356     
357     /* When the window is given the "delete_event" signal (this is given
358      * by the window manager, usually by the "close" option, or on the
359      * titlebar), we ask it to call the delete_event () function
360      * as defined above. The data passed to the callback
361      * function is NULL and is ignored in the callback function. */
362     g_signal_connect (G_OBJECT (window), "delete_event",
363                       G_CALLBACK (delete_event), NULL);
364     
365     /* Here we connect the "destroy" event to a signal handler.  
366      * This event occurs when we call gtk_widget_destroy() on the window,
367      * or if we return FALSE in the "delete_event" callback. */
368     g_signal_connect (G_OBJECT (window), "destroy",
369                       G_CALLBACK (destroy), NULL);
370     
371     /* Sets the border width of the window. */
372     gtk_container_set_border_width (GTK_CONTAINER (window), 10);
373     
374     /* Creates a new button with the label "Hello World". */
375     button = gtk_button_new_with_label ("Hello World");
376     
377     /* When the button receives the "clicked" signal, it will call the
378      * function hello() passing it NULL as its argument.  The hello()
379      * function is defined above. */
380     g_signal_connect (G_OBJECT (button), "clicked",
381                       G_CALLBACK (hello), NULL);
382     
383     /* This will cause the window to be destroyed by calling
384      * gtk_widget_destroy(window) when "clicked".  Again, the destroy
385      * signal could come from here, or the window manager. */
386     g_signal_connect_swapped (G_OBJECT (button), "clicked",
387                               G_CALLBACK (gtk_widget_destroy),
388                               G_OBJECT (window));
389     
390     /* This packs the button into the window (a gtk container). */
391     gtk_container_add (GTK_CONTAINER (window), button);
392     
393     /* The final step is to display this newly created widget. */
394     gtk_widget_show (button);
395     
396     /* and the window */
397     gtk_widget_show (window);
398     
399     /* All GTK applications must have a gtk_main(). Control ends here
400      * and waits for an event to occur (like a key press or
401      * mouse event). */
402     gtk_main ();
403     
404     return 0;
405 }
406 <!-- example-end -->
407 </programlisting>
408
409 </sect1>
410
411 <!-- ----------------------------------------------------------------- -->
412 <sect1 id="sec-Compiling">
413 <title>Compiling Hello World</title>
414
415 <para>To compile use:</para>
416
417 <para><literallayout>
418 <literal>gcc -Wall -g helloworld.c -o helloworld `pkg-config --cflags gtk+-2.0` \</literal>
419 <literal>    `pkg-config --libs gtk+-2.0`</literal>
420 </literallayout></para>
421
422 <para>This uses the program <literal>pkg-config</literal>, which can be obtained from
423 <ulink url="http://www.freedesktop.org">www.freedesktop.org</ulink>. This program 
424 reads the <filename>.pc</filename> which comes with GTK to determine what 
425 compiler switches are needed to compile programs that use GTK. 
426 <literal>pkg-config --cflags gtk+-2.0</literal> will output a list of include
427 directories for the compiler to look in, and 
428 <literal>pkg-config --libs gtk+-2.0</literal>
429 will output the list of libraries for the compiler to link with and
430 the directories to find them in. In the above example they could have
431 been combined into a single instance, such as
432 <literal>pkg-config --cflags --libs gtk+-2.0</literal>.</para>
433
434 <para>Note that the type of single quote used in the compile command above
435 is significant.</para>
436
437 <para>The libraries that are usually linked in are:</para>
438
439 <itemizedlist>
440 <listitem><simpara>The GTK library (<literal>-lgtk</literal>), the widget library, 
441 based on top of GDK.</simpara>
442 </listitem>
443
444 <listitem><simpara>The GDK library (<literal>-lgdk</literal>), the Xlib wrapper.</simpara>
445 </listitem>
446
447 <listitem><simpara>The gdk-pixbuf library (<literal>-lgdk_pixbuf</literal>), the image 
448 manipulation library.</simpara>
449 </listitem>
450
451 <listitem><simpara>The Pango library (<literal>-lpango</literal>) for internationalized 
452 text.</simpara>
453 </listitem>
454
455 <listitem><simpara>The gobject library (<literal>-lgobject</literal>), containing the
456 type system on which GTK is based.</simpara>
457 </listitem>
458
459 <listitem><simpara>The gmodule library (<literal>-lgmodule</literal>), which is used 
460 to load run time extensions.</simpara>
461 </listitem>
462
463 <listitem><simpara>The GLib library (<literal>-lglib</literal>), containing miscellaneous
464 functions; only g_print() is used in this particular example. GTK is built on top
465 of GLib so you will always require this library. See the section on
466 <link linkend="ch-glib">GLib</link> for details.</simpara>
467 </listitem>
468
469 <listitem><simpara>The Xlib library (<literal>-lX11</literal>) which is used by GDK.</simpara>
470 </listitem>
471
472 <listitem><simpara>The Xext library (<literal>-lXext</literal>). This contains code 
473 for shared memory pixmaps and other X extensions.</simpara>
474 </listitem>
475
476 <listitem><simpara>The math library (<literal>-lm</literal>). This is used by GTK 
477 for various purposes.</simpara>
478 </listitem>
479 </itemizedlist>
480
481 </sect1>
482
483 <!-- ----------------------------------------------------------------- -->
484 <sect1 id="sec-TheoryOfSignalsAndCallbacks">
485 <title>Theory of Signals and Callbacks</title>
486
487 <note>
488 <para>In version 2.0, the signal system has been moved from GTK to GLib, therefore the
489 functions and types explained in this section have a "g_" prefix rather than a "gtk_" 
490 prefix. We won't go into details about the extensions which the GLib 2.0 signal system
491 has relative to the GTK 1.2 signal system.</para>
492 </note>
493
494 <para>Before we look in detail at <emphasis>helloworld</emphasis>, we'll discuss signals
495 and callbacks. GTK is an event driven toolkit, which means it will
496 sleep in gtk_main() until an event occurs and control is passed to the
497 appropriate function.</para>
498
499 <para>This passing of control is done using the idea of "signals". (Note
500 that these signals are not the same as the Unix system signals, and
501 are not implemented using them, although the terminology is almost
502 identical.) When an event occurs, such as the press of a mouse button,
503 the appropriate signal will be "emitted" by the widget that was
504 pressed.  This is how GTK does most of its useful work. There are
505 signals that all widgets inherit, such as "destroy", and there are
506 signals that are widget specific, such as "toggled" on a toggle
507 button.</para>
508
509 <para>To make a button perform an action, we set up a signal handler to
510 catch these signals and call the appropriate function. This is done by
511 using a function such as:</para>
512
513 <programlisting role="C">
514 gulong g_signal_connect( gpointer      *object,
515                          const gchar   *name,
516                          GCallback     func,
517                          gpointer      func_data );
518 </programlisting>
519
520 <para>where the first argument is the widget which will be emitting the
521 signal, and the second the name of the signal you wish to catch. The
522 third is the function you wish to be called when it is caught, and the
523 fourth, the data you wish to have passed to this function.</para>
524
525 <para>The function specified in the third argument is called a "callback
526 function", and should generally be of the form</para>
527
528 <programlisting role="C">
529 void callback_func( GtkWidget *widget,
530                     gpointer   callback_data );
531 </programlisting>
532
533 <para>where the first argument will be a pointer to the widget that emitted
534 the signal, and the second a pointer to the data given as the last
535 argument to the g_signal_connect() function as shown above.</para>
536
537 <para>Note that the above form for a signal callback function declaration is
538 only a general guide, as some widget specific signals generate
539 different calling parameters.</para>
540
541 <para>Another call used in the <emphasis>helloworld</emphasis> example, is:</para>
542
543 <programlisting role="C">
544 gulong g_signal_connect_swapped( gpointer     *object,
545                                  const gchar  *name,
546                                  GCallback    func,
547                                  gpointer     *slot_object );
548 </programlisting>
549
550 <para>g_signal_connect_swapped() is the same as g_signal_connect() except
551 that the callback function only uses one argument, a pointer to a GTK
552 object. So when using this function to connect signals, the callback
553 should be of the form</para>
554
555 <programlisting role="C">
556 void callback_func( GtkObject *object );
557 </programlisting>
558
559 <para>where the object is usually a widget. We usually don't setup callbacks
560 for g_signal_connect_swapped() however. They are usually used to call a
561 GTK function that accepts a single widget or object as an argument, as
562 is the case in our <emphasis>helloworld</emphasis> example.</para>
563
564 <para>The purpose of having two functions to connect signals is simply to
565 allow the callbacks to have a different number of arguments. Many
566 functions in the GTK library accept only a single GtkWidget pointer as
567 an argument, so you want to use the g_signal_connect_swapped() for
568 these, whereas for your functions, you may need to have additional
569 data supplied to the callbacks.</para>
570
571 </sect1>
572
573 <!-- ----------------------------------------------------------------- -->
574 <sect1 id="sec-Events">
575 <title>Events</title>
576
577 <para>In addition to the signal mechanism described above, there is a set
578 of <emphasis>events</emphasis> that reflect the X event mechanism. Callbacks may
579 also be attached to these events. These events are:</para>
580
581 <itemizedlist spacing=Compact>
582 <listitem><simpara> event</simpara>
583 </listitem>
584 <listitem><simpara> button_press_event</simpara>
585 </listitem>
586 <listitem><simpara> button_release_event</simpara>
587 </listitem>
588 <listitem><simpara> scroll_event</simpara>
589 </listitem>
590 <listitem><simpara> motion_notify_event</simpara>
591 </listitem>
592 <listitem><simpara> delete_event</simpara>
593 </listitem>
594 <listitem><simpara> destroy_event</simpara>
595 </listitem>
596 <listitem><simpara> expose_event</simpara>
597 </listitem>
598 <listitem><simpara> key_press_event</simpara>
599 </listitem>
600 <listitem><simpara> key_release_event</simpara>
601 </listitem>
602 <listitem><simpara> enter_notify_event</simpara>
603 </listitem>
604 <listitem><simpara> leave_notify_event</simpara>
605 </listitem>
606 <listitem><simpara> configure_event</simpara>
607 </listitem>
608 <listitem><simpara> focus_in_event</simpara>
609 </listitem>
610 <listitem><simpara> focus_out_event</simpara>
611 </listitem>
612 <listitem><simpara> map_event</simpara>
613 </listitem>
614 <listitem><simpara> unmap_event</simpara>
615 </listitem>
616 <listitem><simpara> property_notify_event</simpara>
617 </listitem>
618 <listitem><simpara> selection_clear_event</simpara>
619 </listitem>
620 <listitem><simpara> selection_request_event</simpara>
621 </listitem>
622 <listitem><simpara> selection_notify_event</simpara>
623 </listitem>
624 <listitem><simpara> proximity_in_event</simpara>
625 </listitem>
626 <listitem><simpara> proximity_out_event</simpara>
627 </listitem>
628 <listitem><simpara> visibility_notify_event</simpara>
629 </listitem>
630 <listitem><simpara> client_event</simpara>
631 </listitem>
632 <listitem><simpara> no_expose_event</simpara>
633 </listitem>
634 <listitem><simpara> window_state_event</simpara>
635 </listitem>
636 </itemizedlist>
637
638 <para>In order to connect a callback function to one of these events you
639 use the function g_signal_connect(), as described above, using one of
640 the above event names as the <literal>name</literal> parameter. The callback
641 function for events has a slightly different form than that for
642 signals:</para>
643
644 <programlisting role="C">
645 gint callback_func( GtkWidget *widget,
646                     GdkEvent  *event,
647                     gpointer   callback_data );
648 </programlisting>
649
650 <para>GdkEvent is a C <literal>union</literal> structure whose type will depend upon 
651 which of the above events has occurred. In order for us to tell which event
652 has been issued each of the possible alternatives has a <literal>type</literal>
653 member that reflects the event being issued. The other components
654 of the event structure will depend upon the type of the
655 event. Possible values for the type are:</para>
656
657 <programlisting role="C">
658   GDK_NOTHING
659   GDK_DELETE
660   GDK_DESTROY
661   GDK_EXPOSE
662   GDK_MOTION_NOTIFY
663   GDK_BUTTON_PRESS
664   GDK_2BUTTON_PRESS
665   GDK_3BUTTON_PRESS
666   GDK_BUTTON_RELEASE
667   GDK_KEY_PRESS
668   GDK_KEY_RELEASE
669   GDK_ENTER_NOTIFY
670   GDK_LEAVE_NOTIFY
671   GDK_FOCUS_CHANGE
672   GDK_CONFIGURE
673   GDK_MAP
674   GDK_UNMAP
675   GDK_PROPERTY_NOTIFY
676   GDK_SELECTION_CLEAR
677   GDK_SELECTION_REQUEST
678   GDK_SELECTION_NOTIFY
679   GDK_PROXIMITY_IN
680   GDK_PROXIMITY_OUT
681   GDK_DRAG_ENTER
682   GDK_DRAG_LEAVE
683   GDK_DRAG_MOTION
684   GDK_DRAG_STATUS
685   GDK_DROP_START
686   GDK_DROP_FINISHED
687   GDK_CLIENT_EVENT
688   GDK_VISIBILITY_NOTIFY
689   GDK_NO_EXPOSE
690   GDK_SCROLL
691   GDK_WINDOW_STATE
692   GDK_SETTING
693 </programlisting>
694
695 <para>So, to connect a callback function to one of these events we would use
696 something like:</para>
697
698 <programlisting role="C">
699 g_signal_connect (G_OBJECT (button), "button_press_event",
700                   G_CALLBACK (button_press_callback), NULL);
701 </programlisting>
702
703 <para>This assumes that <literal>button</literal> is a Button widget. Now, when the
704 mouse is over the button and a mouse button is pressed, the function
705 button_press_callback() will be called. This function may be declared as:</para>
706
707 <programlisting role="C">
708 static gint button_press_callback( GtkWidget      *widget, 
709                                    GdkEventButton *event,
710                                    gpointer        data );
711 </programlisting>
712
713 <para>Note that we can declare the second argument as type
714 <literal>GdkEventButton</literal> as we know what type of event will occur for this
715 function to be called.</para>
716
717 <para>The value returned from this function indicates whether the event
718 should be propagated further by the GTK event handling
719 mechanism. Returning TRUE indicates that the event has been handled,
720 and that it should not propagate further. Returning FALSE continues
721 the normal event handling.  See the section on
722 <link linkend="ch-AdvancedEventsAndSignals">Advanced Event and Signal Handling</link> 
723 for more details on this propagation process.</para>
724
725 <para>For details on the GdkEvent data types, see the appendix entitled
726 <link linkend="app-GDKEventTypes">GDK Event Types</link>.</para>
727
728 <para>The GDK selection and drag-and-drop APIs also emit a number of events which
729 are reflected in GTK by the signals. See <link 
730 linkend="sec-SignalsOnSourceWidgets">Signals on the source widget</link> and <link 
731 linkend="sec-SignalsOnDestWidgets">Signals on the destination widget</link>
732 for details on the signatures of the callback functions for these signals:</para>
733
734 <itemizedlist spacing=Compact>
735 <listitem><simpara> selection_received</simpara>
736 </listitem>
737 <listitem><simpara> selection_get</simpara>
738 </listitem>
739 <listitem><simpara> drag_begin_event</simpara>
740 </listitem>
741 <listitem><simpara> drag_end_event</simpara>
742 </listitem>
743 <listitem><simpara> drag_data_delete</simpara>
744 </listitem>
745 <listitem><simpara> drag_motion</simpara>
746 </listitem>
747 <listitem><simpara> drag_drop</simpara>
748 </listitem>
749 <listitem><simpara> drag_data_get</simpara>
750 </listitem>
751 <listitem><simpara> drag_data_received</simpara>
752 </listitem>
753 </itemizedlist>
754
755 </sect1>
756
757 <!-- ----------------------------------------------------------------- -->
758 <sect1 id="sec-SteppingThroughHelloWorld">
759 <title>Stepping Through Hello World</title>
760
761 <para>Now that we know the theory behind this, let's clarify by walking
762 through the example <emphasis>helloworld</emphasis> program.</para>
763
764 <para>Here is the callback function that will be called when the button is
765 "clicked". We ignore both the widget and the data in this example, but
766 it is not hard to do things with them. The next example will use the
767 data argument to tell us which button was pressed.</para>
768
769 <programlisting role="C">
770 void hello( GtkWidget *widget,
771             gpointer   data )
772 {
773     g_print ("Hello World\n");
774 }
775 </programlisting>
776
777 <para>The next callback is a bit special. The "delete_event" occurs when the
778 window manager sends this event to the application. We have a choice
779 here as to what to do about these events. We can ignore them, make
780 some sort of response, or simply quit the application.</para>
781
782 <para>The value you return in this callback lets GTK know what action to
783 take.  By returning TRUE, we let it know that we don't want to have
784 the "destroy" signal emitted, keeping our application running. By
785 returning FALSE, we ask that "destroy" be emitted, which in turn will
786 call our "destroy" signal handler.</para>
787
788
789 <programlisting role="C">
790 gint delete_event( GtkWidget *widget,
791                    GdkEvent  *event,
792                    gpointer   data )
793 {
794     g_print ("delete event occurred\n");
795
796     return TRUE; 
797 }
798 </programlisting>
799
800 <para>Here is another callback function which causes the program to quit by
801 calling gtk_main_quit(). This function tells GTK that it is to exit
802 from gtk_main when control is returned to it.</para>
803
804 <programlisting role="C">
805 void destroy( GtkWidget *widget,
806               gpointer   data )
807 {
808     gtk_main_quit ();
809 }
810 </programlisting>
811
812 <para>I assume you know about the main() function... yes, as with other
813 applications, all GTK applications will also have one of these.</para>
814
815 <programlisting role="C">
816 int main( int   argc,
817           char *argv[] )
818 {
819 </programlisting>
820
821 <para>This next part declares pointers to a structure of type
822 GtkWidget. These are used below to create a window and a button.</para>
823
824 <programlisting role="C">
825     GtkWidget *window;
826     GtkWidget *button;
827 </programlisting>
828
829 <para>Here is our gtk_init() again. As before, this initializes the toolkit,
830 and parses the arguments found on the command line. Any argument it
831 recognizes from the command line, it removes from the list, and
832 modifies argc and argv to make it look like they never existed,
833 allowing your application to parse the remaining arguments.</para>
834
835 <programlisting role="C">
836     gtk_init (&amp;argc, &amp;argv);
837 </programlisting>
838
839 <para>Create a new window. This is fairly straightforward. Memory is
840 allocated for the GtkWidget *window structure so it now points to a
841 valid structure. It sets up a new window, but it is not displayed
842 until we call gtk_widget_show(window) near the end of our program.</para>
843
844 <programlisting role="C">
845     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
846 </programlisting>
847
848 <para>Here are two examples of connecting a signal handler to an object, in
849 this case, the window. Here, the "delete_event" and "destroy" signals
850 are caught. The first is emitted when we use the window manager to
851 kill the window, or when we use the gtk_widget_destroy() call passing
852 in the window widget as the object to destroy. The second is emitted
853 when, in the "delete_event" handler, we return FALSE.
854  
855 The <literal>G_OBJECT</literal> and <literal>G_CALLBACK</literal> are macros 
856 that perform type casting and checking for us, as well as aid the readability of
857 the code.</para>
858
859 <programlisting role="C">
860     g_signal_connect (G_OBJECT (window), "delete_event",
861                       G_CALLBACK (delete_event), NULL);
862     g_signal_connect (G_OBJECT (window), "destroy",
863                       G_CALLBACK (destroy), NULL);
864 </programlisting>
865
866 <para>This next function is used to set an attribute of a container object.
867 This just sets the window so it has a blank area along the inside of
868 it 10 pixels wide where no widgets will go. There are other similar
869 functions which we will look at in the section on
870 <link linkend="ch-SettingWidgetAttributes">Setting Widget Attributes</link></para>
871
872 <para>And again, <literal>GTK_CONTAINER</literal> is a macro to perform type casting.</para>
873
874 <programlisting role="C">
875     gtk_container_set_border_width (GTK_CONTAINER (window), 10);
876 </programlisting>
877
878 <para>This call creates a new button. It allocates space for a new GtkWidget
879 structure in memory, initializes it, and makes the button pointer
880 point to it. It will have the label "Hello World" on it when
881 displayed.</para>
882
883 <programlisting role="C">
884     button = gtk_button_new_with_label ("Hello World");
885 </programlisting>
886
887 <para>Here, we take this button, and make it do something useful. We attach
888 a signal handler to it so when it emits the "clicked" signal, our
889 hello() function is called. The data is ignored, so we simply pass in
890 NULL to the hello() callback function. Obviously, the "clicked" signal
891 is emitted when we click the button with our mouse pointer.</para>
892
893 <programlisting role="C">
894     g_signal_connect (G_OBJECT (button), "clicked",
895                       G_CALLBACK (hello), NULL);
896 </programlisting>
897
898 <para>We are also going to use this button to exit our program. This will
899 illustrate how the "destroy" signal may come from either the window
900 manager, or our program. When the button is "clicked", same as above,
901 it calls the first hello() callback function, and then this one in the
902 order they are set up. You may have as many callback functions as you
903 need, and all will be executed in the order you connected
904 them. Because the gtk_widget_destroy() function accepts only a
905 GtkWidget *widget as an argument, we use the g_signal_connect_swapped() 
906 function here instead of straight g_signal_connect().</para>
907
908 <programlisting role="C">
909     g_signal_connect_swapped (G_OBJECT (button), "clicked",
910                               G_CALLBACK (gtk_widget_destroy),
911                               G_OBJECT (window));
912 </programlisting>
913
914 <para>This is a packing call, which will be explained in depth later on in
915 <link linkend="ch-PackingWidgets">Packing Widgets</link>. But it is
916 fairly easy to understand. It simply tells GTK that the button is to
917 be placed in the window where it will be displayed. Note that a GTK
918 container can only contain one widget. There are other widgets, that
919 are described later, which are designed to layout multiple widgets in
920 various ways.
921  </para>
922
923 <programlisting role="C">
924     gtk_container_add (GTK_CONTAINER (window), button);
925 </programlisting>
926
927 <para>Now we have everything set up the way we want it to be. With all the
928 signal handlers in place, and the button placed in the window where it
929 should be, we ask GTK to "show" the widgets on the screen. The window
930 widget is shown last so the whole window will pop up at once rather
931 than seeing the window pop up, and then the button form inside of
932 it. Although with such a simple example, you'd never notice.</para>
933
934 <programlisting role="C">
935     gtk_widget_show (button);
936
937     gtk_widget_show (window);
938 </programlisting>
939
940 <para>And of course, we call gtk_main() which waits for events to come from
941 the X server and will call on the widgets to emit signals when these
942 events come.</para>
943
944 <programlisting role="C">
945     gtk_main ();
946 </programlisting>
947
948 <para>And the final return. Control returns here after gtk_quit() is called.</para>
949
950 <programlisting role="C">
951     return 0;
952 </programlisting>
953
954 <para>Now, when we click the mouse button on a GTK button, the widget emits
955 a "clicked" signal. In order for us to use this information, our
956 program sets up a signal handler to catch that signal, which
957 dispatches the function of our choice. In our example, when the button
958 we created is "clicked", the hello() function is called with a NULL
959 argument, and then the next handler for this signal is called. This
960 calls the gtk_widget_destroy() function, passing it the window widget
961 as its argument, destroying the window widget. This causes the window
962 to emit the "destroy" signal, which is caught, and calls our destroy()
963 callback function, which simply exits GTK.</para>
964
965 <para>Another course of events is to use the window manager to kill the
966 window, which will cause the "delete_event" to be emitted. This will
967 call our "delete_event" handler. If we return TRUE here, the window
968 will be left as is and nothing will happen. Returning FALSE will cause
969 GTK to emit the "destroy" signal which of course calls the "destroy"
970 callback, exiting GTK.</para>
971
972 </sect1>
973 </chapter>
974
975 <!-- ***************************************************************** -->
976 <chapter id="ch-MovingOn">
977 <title>Moving On</title>
978
979 <!-- ----------------------------------------------------------------- -->
980 <sect1 id="sec-DataTypes">
981 <title>Data Types</title>
982
983 <para>There are a few things you probably noticed in the previous examples
984 that need explaining. The gint, gchar, etc. that you see are typedefs
985 to int and char, respectively, that are part of the GLib system. This
986 is done to get around that nasty dependency on the size of simple data
987 types when doing calculations.</para>
988
989 <para>A good example is "gint32" which will be typedef'd to a 32 bit integer
990 for any given platform, whether it be the 64 bit alpha, or the 32 bit
991 i386. The typedefs are very straightforward and intuitive. They are
992 all defined in <filename>glib/glib.h</filename> (which gets included from 
993 <filename>gtk.h</filename>).</para>
994
995 <para>You'll also notice GTK's ability to use GtkWidget when the function
996 calls for a GtkObject. GTK is an object oriented design, and a widget
997 is an object.</para>
998
999 </sect1>
1000
1001 <!-- ----------------------------------------------------------------- -->
1002 <sect1 id="sec-MoreOnSignalHandlers">
1003 <title>More on Signal Handlers</title>
1004
1005 <para>Lets take another look at the g_signal_connect() declaration.</para>
1006
1007 <programlisting role="C">
1008 gulong g_signal_connect( gpointer object,
1009                          const gchar *name,
1010                          GCallback func,
1011                          gpointer func_data );
1012 </programlisting>
1013
1014 <para>Notice the gulong return value? This is a tag that identifies your
1015 callback function. As stated above, you may have as many callbacks per
1016 signal and per object as you need, and each will be executed in turn,
1017 in the order they were attached.</para>
1018
1019 <para>This tag allows you to remove this callback from the list by using:</para>
1020
1021 <programlisting role="C">
1022 void g_signal_handler_disconnect( gpointer object,
1023                                   gulong   id );
1024 </programlisting>
1025
1026 <para>So, by passing in the widget you wish to remove the handler from, and
1027 the tag returned by one of the signal_connect functions, you can
1028 disconnect a signal handler.</para>
1029
1030 <para>You can also temporarily disable signal handlers with the
1031 g_signal_handler_block() and g_signal_handler_unblock() family of
1032 functions.</para>
1033
1034 <programlisting role="C">
1035 void g_signal_handler_block( gpointer object,
1036                              gulong   id );
1037
1038 void g_signal_handlers_block_by_func( gpointer  object,
1039                                       GCallback func,
1040                                       gpointer  data );
1041
1042 void g_signal_handler_unblock( gpointer object,
1043                                gulong   id );
1044
1045 void g_signal_handlers_unblock_by_func( gpointer  object,
1046                                         GCallback func,
1047                                         gpointer  data );
1048 </programlisting>
1049
1050 </sect1>
1051
1052 <!-- ----------------------------------------------------------------- -->
1053 <sect1 id="sec-AnUpgradedHelloWorld">
1054 <title>An Upgraded Hello World</title>
1055
1056 <para>Let's take a look at a slightly improved <emphasis>helloworld</emphasis> with
1057 better examples of callbacks. This will also introduce us to our next
1058 topic, packing widgets.</para>
1059
1060 <para>
1061 <inlinemediaobject>
1062 <imageobject>
1063 <imagedata fileref="images/helloworld2.png" format="png">
1064 </imageobject>
1065 </inlinemediaobject>
1066 </para>
1067
1068 <programlisting role="C">
1069 <!-- example-start helloworld2 helloworld2.c -->
1070
1071 #include &lt;gtk/gtk.h&gt;
1072
1073 /* Our new improved callback.  The data passed to this function
1074  * is printed to stdout. */
1075 void callback( GtkWidget *widget,
1076                gpointer   data )
1077 {
1078     g_print ("Hello again - %s was pressed\n", (gchar *) data);
1079 }
1080
1081 /* another callback */
1082 gint delete_event( GtkWidget *widget,
1083                    GdkEvent  *event,
1084                    gpointer   data )
1085 {
1086     gtk_main_quit ();
1087     return FALSE;
1088 }
1089
1090 int main( int   argc,
1091           char *argv[] )
1092 {
1093     /* GtkWidget is the storage type for widgets */
1094     GtkWidget *window;
1095     GtkWidget *button;
1096     GtkWidget *box1;
1097
1098     /* This is called in all GTK applications. Arguments are parsed
1099      * from the command line and are returned to the application. */
1100     gtk_init (&amp;argc, &amp;argv);
1101
1102     /* Create a new window */
1103     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1104
1105     /* This is a new call, which just sets the title of our
1106      * new window to "Hello Buttons!" */
1107     gtk_window_set_title (GTK_WINDOW (window), "Hello Buttons!");
1108
1109     /* Here we just set a handler for delete_event that immediately
1110      * exits GTK. */
1111     g_signal_connect (G_OBJECT (window), "delete_event",
1112                       G_CALLBACK (delete_event), NULL);
1113
1114     /* Sets the border width of the window. */
1115     gtk_container_set_border_width (GTK_CONTAINER (window), 10);
1116
1117     /* We create a box to pack widgets into.  This is described in detail
1118      * in the "packing" section. The box is not really visible, it
1119      * is just used as a tool to arrange widgets. */
1120     box1 = gtk_hbox_new (FALSE, 0);
1121
1122     /* Put the box into the main window. */
1123     gtk_container_add (GTK_CONTAINER (window), box1);
1124
1125     /* Creates a new button with the label "Button 1". */
1126     button = gtk_button_new_with_label ("Button 1");
1127     
1128     /* Now when the button is clicked, we call the "callback" function
1129      * with a pointer to "button 1" as its argument */
1130     g_signal_connect (G_OBJECT (button), "clicked",
1131                       G_CALLBACK (callback), (gpointer) "button 1");
1132
1133     /* Instead of gtk_container_add, we pack this button into the invisible
1134      * box, which has been packed into the window. */
1135     gtk_box_pack_start (GTK_BOX(box1), button, TRUE, TRUE, 0);
1136
1137     /* Always remember this step, this tells GTK that our preparation for
1138      * this button is complete, and it can now be displayed. */
1139     gtk_widget_show (button);
1140
1141     /* Do these same steps again to create a second button */
1142     button = gtk_button_new_with_label ("Button 2");
1143
1144     /* Call the same callback function with a different argument,
1145      * passing a pointer to "button 2" instead. */
1146     g_signal_connect (G_OBJECT (button), "clicked",
1147                       G_CALLBACK (callback), (gpointer) "button 2");
1148
1149     gtk_box_pack_start(GTK_BOX (box1), button, TRUE, TRUE, 0);
1150
1151     /* The order in which we show the buttons is not really important, but I
1152      * recommend showing the window last, so it all pops up at once. */
1153     gtk_widget_show (button);
1154
1155     gtk_widget_show (box1);
1156
1157     gtk_widget_show (window);
1158     
1159     /* Rest in gtk_main and wait for the fun to begin! */
1160     gtk_main ();
1161
1162     return 0;
1163 }
1164 <!-- example-end -->
1165 </programlisting>
1166
1167 <para>Compile this program using the same linking arguments as our first
1168 example.  You'll notice this time there is no easy way to exit the
1169 program, you have to use your window manager or command line to kill
1170 it. A good exercise for the reader would be to insert a third "Quit"
1171 button that will exit the program. You may also wish to play with the
1172 options to gtk_box_pack_start() while reading the next section.  Try
1173 resizing the window, and observe the behavior.</para>
1174
1175 </sect1>
1176 </chapter>
1177
1178 <!-- ***************************************************************** -->
1179 <chapter id="ch-PackingWidgets">
1180 <title>Packing Widgets</title>
1181
1182 <para>When creating an application, you'll want to put more than one widget
1183 inside a window. Our first <emphasis>helloworld</emphasis> example only used one
1184 widget so we could simply use a gtk_container_add() call to "pack" the
1185 widget into the window. But when you want to put more than one widget
1186 into a window, how do you control where that widget is positioned?
1187 This is where packing comes in.</para>
1188
1189 <!-- ----------------------------------------------------------------- -->
1190 <sect1 id="sec-TheoryOfPackingBoxes">
1191 <title>Theory of Packing Boxes</title>
1192
1193 <para>Most packing is done by creating boxes. These
1194 are invisible widget containers that we can pack our widgets into
1195 which come in two forms, a horizontal box, and a vertical box. When
1196 packing widgets into a horizontal box, the objects are inserted
1197 horizontally from left to right or right to left depending on the call
1198 used. In a vertical box, widgets are packed from top to bottom or vice
1199 versa. You may use any combination of boxes inside or beside other
1200 boxes to create the desired effect.</para>
1201
1202 <para>To create a new horizontal box, we use a call to gtk_hbox_new(), and
1203 for vertical boxes, gtk_vbox_new(). The gtk_box_pack_start() and
1204 gtk_box_pack_end() functions are used to place objects inside of these
1205 containers. The gtk_box_pack_start() function will start at the top
1206 and work its way down in a vbox, and pack left to right in an hbox.
1207 gtk_box_pack_end() will do the opposite, packing from bottom to top in
1208 a vbox, and right to left in an hbox. Using these functions allows us
1209 to right justify or left justify our widgets and may be mixed in any
1210 way to achieve the desired effect. We will use gtk_box_pack_start() in
1211 most of our examples. An object may be another container or a
1212 widget. In fact, many widgets are actually containers themselves,
1213 including the button, but we usually only use a label inside a button.</para>
1214
1215 <para>By using these calls, GTK knows where you want to place your widgets
1216 so it can do automatic resizing and other nifty things. There are also
1217 a number of options as to how your widgets should be packed. As you
1218 can imagine, this method gives us a quite a bit of flexibility when
1219 placing and creating widgets.</para>
1220
1221 </sect1>
1222
1223 <!-- ----------------------------------------------------------------- -->
1224 <sect1 id="sec-DetailsOfBoxes">
1225 <title>Details of Boxes</title>
1226
1227 <para>Because of this flexibility, packing boxes in GTK can be confusing at
1228 first. There are a lot of options, and it's not immediately obvious how
1229 they all fit together. In the end, however, there are basically five
1230 different styles.</para>
1231
1232 <para>
1233 <inlinemediaobject>
1234 <imageobject>
1235 <imagedata fileref="images/packbox1.png" format="png">
1236 </imageobject>
1237 </inlinemediaobject>
1238 </para>
1239
1240 <para>Each line contains one horizontal box (hbox) with several buttons. The
1241 call to gtk_box_pack is shorthand for the call to pack each of the
1242 buttons into the hbox. Each of the buttons is packed into the hbox the
1243 same way (i.e., same arguments to the gtk_box_pack_start() function).</para>
1244
1245 <para>This is the declaration of the gtk_box_pack_start() function.</para>
1246
1247 <programlisting role="C">
1248 void gtk_box_pack_start( GtkBox    *box,
1249                          GtkWidget *child,
1250                          gboolean   expand,
1251                          gboolean   fill,
1252                          guint      padding );
1253 </programlisting>
1254
1255 <para>The first argument is the box you are packing the object into, the
1256 second is the object. The objects will all be buttons for now, so
1257 we'll be packing buttons into boxes.</para>
1258
1259 <para>The expand argument to gtk_box_pack_start() and gtk_box_pack_end()
1260 controls whether the widgets are laid out in the box to fill in all
1261 the extra space in the box so the box is expanded to fill the area
1262 allotted to it (TRUE); or the box is shrunk to just fit the widgets
1263 (FALSE). Setting expand to FALSE will allow you to do right and left
1264 justification of your widgets.  Otherwise, they will all expand to fit
1265 into the box, and the same effect could be achieved by using only one
1266 of gtk_box_pack_start() or gtk_box_pack_end().</para>
1267
1268 <para>The fill argument to the gtk_box_pack functions control whether the
1269 extra space is allocated to the objects themselves (TRUE), or as extra
1270 padding in the box around these objects (FALSE). It only has an effect
1271 if the expand argument is also TRUE.</para>
1272
1273 <para>When creating a new box, the function looks like this:</para>
1274
1275 <programlisting role="C">
1276 GtkWidget *gtk_hbox_new ( gboolean homogeneous,
1277                           gint     spacing );
1278 </programlisting>
1279
1280 <para>The homogeneous argument to gtk_hbox_new() (and the same for
1281 gtk_vbox_new()) controls whether each object in the box has the same
1282 size (i.e., the same width in an hbox, or the same height in a
1283 vbox). If it is set, the gtk_box_pack() routines function essentially
1284 as if the <literal>expand</literal> argument was always turned on.</para>
1285
1286 <para>What's the difference between spacing (set when the box is created)
1287 and padding (set when elements are packed)? Spacing is added between
1288 objects, and padding is added on either side of an object. The
1289 following figure should make it clearer:</para>
1290
1291 <para>
1292 <inlinemediaobject>
1293 <imageobject>
1294 <imagedata fileref="images/packbox2.png" format="png">
1295 </imageobject>
1296 </inlinemediaobject>
1297 </para>
1298
1299 <para>Here is the code used to create the above images. I've commented it
1300 fairly heavily so I hope you won't have any problems following
1301 it. Compile it yourself and play with it.</para>
1302
1303 </sect1>
1304
1305 <!-- ----------------------------------------------------------------- -->
1306 <sect1 id="sec-PackingDemonstrationProgram">
1307 <title>Packing Demonstration Program</title>
1308
1309 <programlisting role="C">
1310 /* example-start packbox packbox.c */
1311
1312 #include &lt;stdio.h&gt;
1313 #include &lt;stdlib.h&gt;
1314 #include "gtk/gtk.h"
1315
1316 gint delete_event( GtkWidget *widget,
1317                    GdkEvent  *event,
1318                    gpointer   data )
1319 {
1320     gtk_main_quit ();
1321     return FALSE;
1322 }
1323
1324 /* Make a new hbox filled with button-labels. Arguments for the 
1325  * variables we're interested are passed in to this function. 
1326  * We do not show the box, but do show everything inside. */
1327 GtkWidget *make_box( gboolean homogeneous,
1328                      gint     spacing,
1329                      gboolean expand,
1330                      gboolean fill,
1331                      guint    padding ) 
1332 {
1333     GtkWidget *box;
1334     GtkWidget *button;
1335     char padstr[80];
1336     
1337     /* Create a new hbox with the appropriate homogeneous
1338      * and spacing settings */
1339     box = gtk_hbox_new (homogeneous, spacing);
1340     
1341     /* Create a series of buttons with the appropriate settings */
1342     button = gtk_button_new_with_label ("gtk_box_pack");
1343     gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
1344     gtk_widget_show (button);
1345     
1346     button = gtk_button_new_with_label ("(box,");
1347     gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
1348     gtk_widget_show (button);
1349     
1350     button = gtk_button_new_with_label ("button,");
1351     gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
1352     gtk_widget_show (button);
1353     
1354     /* Create a button with the label depending on the value of
1355      * expand. */
1356     if (expand == TRUE)
1357             button = gtk_button_new_with_label ("TRUE,");
1358     else
1359             button = gtk_button_new_with_label ("FALSE,");
1360     
1361     gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
1362     gtk_widget_show (button);
1363     
1364     /* This is the same as the button creation for "expand"
1365      * above, but uses the shorthand form. */
1366     button = gtk_button_new_with_label (fill ? "TRUE," : "FALSE,");
1367     gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
1368     gtk_widget_show (button);
1369     
1370     sprintf (padstr, "%d);", padding);
1371     
1372     button = gtk_button_new_with_label (padstr);
1373     gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
1374     gtk_widget_show (button);
1375     
1376     return box;
1377 }
1378
1379 int main( int   argc,
1380           char *argv[]) 
1381 {
1382     GtkWidget *window;
1383     GtkWidget *button;
1384     GtkWidget *box1;
1385     GtkWidget *box2;
1386     GtkWidget *separator;
1387     GtkWidget *label;
1388     GtkWidget *quitbox;
1389     int which;
1390     
1391     /* Our init, don't forget this! :) */
1392     gtk_init (&amp;argc, &amp;argv);
1393     
1394     if (argc != 2) {
1395         fprintf (stderr, "usage: packbox num, where num is 1, 2, or 3.\n");
1396         /* This just does cleanup in GTK and exits with an exit status of 1. */
1397         exit (1);
1398     }
1399     
1400     which = atoi (argv[1]);
1401
1402     /* Create our window */
1403     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1404
1405     /* You should always remember to connect the delete_event signal
1406      * to the main window. This is very important for proper intuitive
1407      * behavior */
1408     g_signal_connect (G_OBJECT (window), "delete_event",
1409                       G_CALLBACK (delete_event), NULL);
1410     gtk_container_set_border_width (GTK_CONTAINER (window), 10);
1411     
1412     /* We create a vertical box (vbox) to pack the horizontal boxes into.
1413      * This allows us to stack the horizontal boxes filled with buttons one
1414      * on top of the other in this vbox. */
1415     box1 = gtk_vbox_new (FALSE, 0);
1416     
1417     /* which example to show. These correspond to the pictures above. */
1418     switch (which) {
1419     case 1:
1420         /* create a new label. */
1421         label = gtk_label_new ("gtk_hbox_new (FALSE, 0);");
1422         
1423         /* Align the label to the left side.  We'll discuss this function and 
1424          * others in the section on Widget Attributes. */
1425         gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
1426
1427         /* Pack the label into the vertical box (vbox box1).  Remember that 
1428          * widgets added to a vbox will be packed one on top of the other in
1429          * order. */
1430         gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
1431         
1432         /* Show the label */
1433         gtk_widget_show (label);
1434         
1435         /* Call our make box function - homogeneous = FALSE, spacing = 0,
1436          * expand = FALSE, fill = FALSE, padding = 0 */
1437         box2 = make_box (FALSE, 0, FALSE, FALSE, 0);
1438         gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1439         gtk_widget_show (box2);
1440
1441         /* Call our make box function - homogeneous = FALSE, spacing = 0,
1442          * expand = TRUE, fill = FALSE, padding = 0 */
1443         box2 = make_box (FALSE, 0, TRUE, FALSE, 0);
1444         gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1445         gtk_widget_show (box2);
1446         
1447         /* Args are: homogeneous, spacing, expand, fill, padding */
1448         box2 = make_box (FALSE, 0, TRUE, TRUE, 0);
1449         gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1450         gtk_widget_show (box2);
1451         
1452         /* Creates a separator, we'll learn more about these later, 
1453          * but they are quite simple. */
1454         separator = gtk_hseparator_new ();
1455         
1456         /* Pack the separator into the vbox. Remember each of these
1457          * widgets is being packed into a vbox, so they'll be stacked
1458          * vertically. */
1459         gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1460         gtk_widget_show (separator);
1461         
1462         /* Create another new label, and show it. */
1463         label = gtk_label_new ("gtk_hbox_new (TRUE, 0);");
1464         gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
1465         gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
1466         gtk_widget_show (label);
1467         
1468         /* Args are: homogeneous, spacing, expand, fill, padding */
1469         box2 = make_box (TRUE, 0, TRUE, FALSE, 0);
1470         gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1471         gtk_widget_show (box2);
1472         
1473         /* Args are: homogeneous, spacing, expand, fill, padding */
1474         box2 = make_box (TRUE, 0, TRUE, TRUE, 0);
1475         gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1476         gtk_widget_show (box2);
1477         
1478         /* Another new separator. */
1479         separator = gtk_hseparator_new ();
1480         /* The last 3 arguments to gtk_box_pack_start are:
1481          * expand, fill, padding. */
1482         gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1483         gtk_widget_show (separator);
1484         
1485         break;
1486
1487     case 2:
1488
1489         /* Create a new label, remember box1 is a vbox as created 
1490          * near the beginning of main() */
1491         label = gtk_label_new ("gtk_hbox_new (FALSE, 10);");
1492         gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
1493         gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
1494         gtk_widget_show (label);
1495         
1496         /* Args are: homogeneous, spacing, expand, fill, padding */
1497         box2 = make_box (FALSE, 10, TRUE, FALSE, 0);
1498         gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1499         gtk_widget_show (box2);
1500         
1501         /* Args are: homogeneous, spacing, expand, fill, padding */
1502         box2 = make_box (FALSE, 10, TRUE, TRUE, 0);
1503         gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1504         gtk_widget_show (box2);
1505         
1506         separator = gtk_hseparator_new ();
1507         /* The last 3 arguments to gtk_box_pack_start are:
1508          * expand, fill, padding. */
1509         gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1510         gtk_widget_show (separator);
1511         
1512         label = gtk_label_new ("gtk_hbox_new (FALSE, 0);");
1513         gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
1514         gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
1515         gtk_widget_show (label);
1516         
1517         /* Args are: homogeneous, spacing, expand, fill, padding */
1518         box2 = make_box (FALSE, 0, TRUE, FALSE, 10);
1519         gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1520         gtk_widget_show (box2);
1521         
1522         /* Args are: homogeneous, spacing, expand, fill, padding */
1523         box2 = make_box (FALSE, 0, TRUE, TRUE, 10);
1524         gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1525         gtk_widget_show (box2);
1526         
1527         separator = gtk_hseparator_new ();
1528         /* The last 3 arguments to gtk_box_pack_start are: expand, fill, padding. */
1529         gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1530         gtk_widget_show (separator);
1531         break;
1532     
1533     case 3:
1534
1535         /* This demonstrates the ability to use gtk_box_pack_end() to
1536          * right justify widgets. First, we create a new box as before. */
1537         box2 = make_box (FALSE, 0, FALSE, FALSE, 0);
1538
1539         /* Create the label that will be put at the end. */
1540         label = gtk_label_new ("end");
1541         /* Pack it using gtk_box_pack_end(), so it is put on the right
1542          * side of the hbox created in the make_box() call. */
1543         gtk_box_pack_end (GTK_BOX (box2), label, FALSE, FALSE, 0);
1544         /* Show the label. */
1545         gtk_widget_show (label);
1546         
1547         /* Pack box2 into box1 (the vbox remember ? :) */
1548         gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1549         gtk_widget_show (box2);
1550         
1551         /* A separator for the bottom. */
1552         separator = gtk_hseparator_new ();
1553         /* This explicitly sets the separator to 400 pixels wide by 5 pixels
1554          * high. This is so the hbox we created will also be 400 pixels wide,
1555          * and the "end" label will be separated from the other labels in the
1556          * hbox. Otherwise, all the widgets in the hbox would be packed as
1557          * close together as possible. */
1558         gtk_widget_set_size_request (separator, 400, 5);
1559         /* pack the separator into the vbox (box1) created near the start 
1560          * of main() */
1561         gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1562         gtk_widget_show (separator);    
1563     }
1564     
1565     /* Create another new hbox.. remember we can use as many as we need! */
1566     quitbox = gtk_hbox_new (FALSE, 0);
1567     
1568     /* Our quit button. */
1569     button = gtk_button_new_with_label ("Quit");
1570     
1571     /* Setup the signal to terminate the program when the button is clicked */
1572     g_signal_connect_swapped (G_OBJECT (button), "clicked",
1573                               G_CALLBACK (gtk_main_quit),
1574                               G_OBJECT (window));
1575     /* Pack the button into the quitbox.
1576      * The last 3 arguments to gtk_box_pack_start are:
1577      * expand, fill, padding. */
1578     gtk_box_pack_start (GTK_BOX (quitbox), button, TRUE, FALSE, 0);
1579     /* pack the quitbox into the vbox (box1) */
1580     gtk_box_pack_start (GTK_BOX (box1), quitbox, FALSE, FALSE, 0);
1581     
1582     /* Pack the vbox (box1) which now contains all our widgets, into the
1583      * main window. */
1584     gtk_container_add (GTK_CONTAINER (window), box1);
1585     
1586     /* And show everything left */
1587     gtk_widget_show (button);
1588     gtk_widget_show (quitbox);
1589     
1590     gtk_widget_show (box1);
1591     /* Showing the window last so everything pops up at once. */
1592     gtk_widget_show (window);
1593     
1594     /* And of course, our main function. */
1595     gtk_main ();
1596
1597     /* Control returns here when gtk_main_quit() is called, but not when 
1598      * exit() is used. */
1599     
1600     return 0;
1601 }
1602 <!-- example-end -->
1603 </programlisting>
1604
1605 </sect1>
1606
1607 <!-- ----------------------------------------------------------------- -->
1608 <sect1 id="sec-PackingUsingTables">
1609 <title>Packing Using Tables</title>
1610
1611 <para>Let's take a look at another way of packing - Tables. These can be
1612 extremely useful in certain situations.</para>
1613
1614 <para>Using tables, we create a grid that we can place widgets in. The
1615 widgets may take up as many spaces as we specify.</para>
1616
1617 <para>The first thing to look at, of course, is the gtk_table_new() function:</para>
1618
1619 <programlisting role="C">
1620 GtkWidget *gtk_table_new( guint    rows,
1621                           guint    columns,
1622                           gboolean homogeneous );
1623 </programlisting>
1624
1625 <para>The first argument is the number of rows to make in the table, while
1626 the second, obviously, is the number of columns.</para>
1627
1628 <para>The homogeneous argument has to do with how the table's boxes are
1629 sized. If homogeneous is TRUE, the table boxes are resized to the size
1630 of the largest widget in the table. If homogeneous is FALSE, the size
1631 of a table boxes is dictated by the tallest widget in its same row,
1632 and the widest widget in its column.</para>
1633
1634 <para>The rows and columns are laid out from 0 to n, where n was the number
1635 specified in the call to gtk_table_new. So, if you specify rows = 2
1636 and columns = 2, the layout would look something like this:</para>
1637
1638 <programlisting role="C">
1639  0          1          2
1640 0+----------+----------+
1641  |          |          |
1642 1+----------+----------+
1643  |          |          |
1644 2+----------+----------+
1645 </programlisting>
1646
1647 <para>Note that the coordinate system starts in the upper left hand corner.
1648 To place a widget into a box, use the following function:</para>
1649
1650 <programlisting role="C">
1651 void gtk_table_attach( GtkTable         *table,
1652                        GtkWidget        *child,
1653                        guint            left_attach,
1654                        guint            right_attach,
1655                        guint            top_attach,
1656                        guint            bottom_attach,
1657                        GtkAttachOptions xoptions,
1658                        GtkAttachOptions yoptions,
1659                        guint            xpadding,
1660                        guint            ypadding );
1661 </programlisting>
1662
1663 <para>The first argument ("table") is the table you've created and the
1664 second ("child") the widget you wish to place in the table.</para>
1665
1666 <para>The left and right attach arguments specify where to place the widget,
1667 and how many boxes to use. If you want a button in the lower right
1668 table entry of our 2x2 table, and want it to fill that entry <emphasis>only</emphasis>,
1669 left_attach would be = 1, right_attach = 2, top_attach = 1,
1670 bottom_attach = 2.</para>
1671
1672 <para>Now, if you wanted a widget to take up the whole top row of our 2x2
1673 table, you'd use left_attach = 0, right_attach = 2, top_attach = 0,
1674 bottom_attach = 1.</para>
1675
1676 <para>The xoptions and yoptions are used to specify packing options and may
1677 be bitwise OR'ed together to allow multiple options.</para>
1678
1679 <para>These options are:</para>
1680
1681 <variablelist>
1682 <varlistentry>
1683 <term><literal>GTK_FILL</literal></term>
1684 <listitem><para>If the table box is larger than the widget, and
1685 <literal>GTK_FILL</literal> is specified, the widget will expand to use all the room
1686 available.</para>
1687 </listitem>
1688 </varlistentry>
1689
1690 <varlistentry>
1691 <term><literal>GTK_SHRINK</literal></term>
1692 <listitem><para>If the table widget was allocated less space
1693 then was requested (usually by the user resizing the window), then the
1694 widgets would normally just be pushed off the bottom of the window and
1695 disappear. If <literal>GTK_SHRINK</literal> is specified, the widgets will shrink
1696 with the table.</para>
1697 </listitem>
1698 </varlistentry>
1699
1700 <varlistentry>
1701 <term><literal>GTK_EXPAND</literal></term>
1702 <listitem><para>This will cause the table to expand to use up
1703 any remaining space in the window.</para>
1704 </listitem>
1705 </varlistentry>
1706 </variablelist>
1707
1708 <para>Padding is just like in boxes, creating a clear area around the widget
1709 specified in pixels.</para>
1710
1711 <para>gtk_table_attach() has a <emphasis>lot</emphasis> of options.  
1712 So, there's a shortcut:</para>
1713
1714 <programlisting role="C">
1715 void gtk_table_attach_defaults( GtkTable  *table,
1716                                 GtkWidget *widget,
1717                                 guint      left_attach,
1718                                 guint      right_attach,
1719                                 guint      top_attach,
1720                                 guint      bottom_attach );
1721 </programlisting>
1722
1723 <para>The X and Y options default to <literal>GTK_FILL | GTK_EXPAND</literal>, 
1724 and X and Y padding are set to 0. The rest of the arguments are identical to the
1725 previous function.</para>
1726
1727 <para>We also have gtk_table_set_row_spacing() and
1728 gtk_table_set_col_spacing(). These places spacing between the rows at
1729 the specified row or column.</para>
1730
1731 <programlisting role="C">
1732 void gtk_table_set_row_spacing( GtkTable *table,
1733                                 guint     row,
1734                                 guint     spacing );
1735 </programlisting>
1736
1737 <para>and</para>
1738
1739 <programlisting role="C">
1740 void gtk_table_set_col_spacing ( GtkTable *table,
1741                                  guint     column,
1742                                  guint     spacing );
1743 </programlisting>
1744
1745 <para>Note that for columns, the space goes to the right of the column, and
1746 for rows, the space goes below the row.</para>
1747
1748 <para>You can also set a consistent spacing of all rows and/or columns with:</para>
1749
1750 <programlisting role="C">
1751 void gtk_table_set_row_spacings( GtkTable *table,
1752                                  guint    spacing );
1753 </programlisting>
1754
1755 <para>And,</para>
1756
1757 <programlisting role="C">
1758 void gtk_table_set_col_spacings( GtkTable *table,
1759                                  guint     spacing );
1760 </programlisting>
1761
1762 <para>Note that with these calls, the last row and last column do not get
1763 any spacing.</para>
1764
1765 </sect1>
1766
1767 <!-- ----------------------------------------------------------------- -->
1768 <sect1 id="sec-TablePackingExamples">
1769 <title>Table Packing Example</title>
1770
1771 <para>Here we make a window with three buttons in a 2x2 table.
1772 The first two buttons will be placed in the upper row.
1773 A third, quit button, is placed in the lower row, spanning both columns.
1774 Which means it should look something like this:</para>
1775
1776 <para>
1777 <inlinemediaobject>
1778 <imageobject>
1779 <imagedata fileref="images/table.png" format="png">
1780 </imageobject>
1781 </inlinemediaobject>
1782 </para>
1783
1784 <para>Here's the source code:</para>
1785
1786 <programlisting role="C">
1787 <!-- example-start table table.c -->
1788
1789 #include &lt;gtk/gtk.h&gt;
1790
1791 /* Our callback.
1792  * The data passed to this function is printed to stdout */
1793 void callback( GtkWidget *widget,
1794                gpointer   data )
1795 {
1796     g_print ("Hello again - %s was pressed\n", (char *) data);
1797 }
1798
1799 /* This callback quits the program */
1800 gint delete_event( GtkWidget *widget,
1801                    GdkEvent  *event,
1802                    gpointer   data )
1803 {
1804     gtk_main_quit ();
1805     return FALSE;
1806 }
1807
1808 int main( int   argc,
1809           char *argv[] )
1810 {
1811     GtkWidget *window;
1812     GtkWidget *button;
1813     GtkWidget *table;
1814
1815     gtk_init (&amp;argc, &amp;argv);
1816
1817     /* Create a new window */
1818     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1819
1820     /* Set the window title */
1821     gtk_window_set_title (GTK_WINDOW (window), "Table");
1822
1823     /* Set a handler for delete_event that immediately
1824      * exits GTK. */
1825     g_signal_connect (G_OBJECT (window), "delete_event",
1826                       G_CALLBACK (delete_event), NULL);
1827
1828     /* Sets the border width of the window. */
1829     gtk_container_set_border_width (GTK_CONTAINER (window), 20);
1830
1831     /* Create a 2x2 table */
1832     table = gtk_table_new (2, 2, TRUE);
1833
1834     /* Put the table in the main window */
1835     gtk_container_add (GTK_CONTAINER (window), table);
1836
1837     /* Create first button */
1838     button = gtk_button_new_with_label ("button 1");
1839
1840     /* When the button is clicked, we call the "callback" function
1841      * with a pointer to "button 1" as its argument */
1842     g_signal_connect (G_OBJECT (button), "clicked",
1843                       G_CALLBACK (callback), (gpointer) "button 1");
1844
1845
1846     /* Insert button 1 into the upper left quadrant of the table */
1847     gtk_table_attach_defaults (GTK_TABLE (table), button, 0, 1, 0, 1);
1848
1849     gtk_widget_show (button);
1850
1851     /* Create second button */
1852
1853     button = gtk_button_new_with_label ("button 2");
1854
1855     /* When the button is clicked, we call the "callback" function
1856      * with a pointer to "button 2" as its argument */
1857     g_signal_connect (G_OBJECT (button), "clicked",
1858                       G_CALLBACK (callback), (gpointer) "button 2");
1859     /* Insert button 2 into the upper right quadrant of the table */
1860     gtk_table_attach_defaults (GTK_TABLE (table), button, 1, 2, 0, 1);
1861
1862     gtk_widget_show (button);
1863
1864     /* Create "Quit" button */
1865     button = gtk_button_new_with_label ("Quit");
1866
1867     /* When the button is clicked, we call the "delete_event" function
1868      * and the program exits */
1869     g_signal_connect (G_OBJECT (button), "clicked",
1870                       G_CALLBACK (delete_event), NULL);
1871
1872     /* Insert the quit button into the both 
1873      * lower quadrants of the table */
1874     gtk_table_attach_defaults (GTK_TABLE (table), button, 0, 2, 1, 2);
1875
1876     gtk_widget_show (button);
1877
1878     gtk_widget_show (table);
1879     gtk_widget_show (window);
1880
1881     gtk_main ();
1882
1883     return 0;
1884 }
1885 <!-- example-end -->
1886 </programlisting>
1887
1888 </sect1>
1889 </chapter>
1890
1891 <!-- ***************************************************************** -->
1892 <chapter id="ch-WidgetOverview">
1893 <title>Widget Overview</title>
1894
1895 <para>The general steps to creating a widget in GTK are:</para>
1896 <orderedlist>
1897 <listitem><simpara> gtk_*_new() - one of various functions to create a new widget.
1898 These are all detailed in this section.</simpara>
1899 </listitem>
1900
1901 <listitem><simpara> Connect all signals and events we wish to use to the
1902 appropriate handlers.</simpara>
1903 </listitem>
1904
1905 <listitem><simpara> Set the attributes of the widget.</simpara>
1906 </listitem>
1907
1908 <listitem><simpara> Pack the widget into a container using the appropriate call
1909 such as gtk_container_add() or gtk_box_pack_start().</simpara>
1910 </listitem>
1911
1912 <listitem><simpara> gtk_widget_show() the widget.</simpara>
1913 </listitem>
1914 </orderedlist>
1915
1916 <para>gtk_widget_show() lets GTK know that we are done setting the
1917 attributes of the widget, and it is ready to be displayed. You may
1918 also use gtk_widget_hide to make it disappear again. The order in
1919 which you show the widgets is not important, but I suggest showing the
1920 window last so the whole window pops up at once rather than seeing the
1921 individual widgets come up on the screen as they're formed. The
1922 children of a widget (a window is a widget too) will not be displayed
1923 until the window itself is shown using the gtk_widget_show() function.</para>
1924
1925 <!-- ----------------------------------------------------------------- -->
1926 <sect1 id="sec-Casting">
1927 <title>Casting</title>
1928
1929 <para>You'll notice as you go on that GTK uses a type casting system. This
1930 is always done using macros that both test the ability to cast the
1931 given item, and perform the cast. Some common ones you will see are:</para>
1932
1933 <programlisting role="C">
1934   G_OBJECT (object)
1935   GTK_WIDGET (widget)
1936   GTK_OBJECT (object)
1937   GTK_SIGNAL_FUNC (function)
1938   GTK_CONTAINER (container)
1939   GTK_WINDOW (window)
1940   GTK_BOX (box)
1941 </programlisting>
1942
1943 <para>These are all used to cast arguments in functions. You'll see them in the
1944 examples, and can usually tell when to use them simply by looking at the
1945 function's declaration.</para>
1946
1947 <para>As you can see below in the class hierarchy, all GtkWidgets are
1948 derived from the GObject base class. This means you can use a widget
1949 in any place the function asks for an object - simply use the
1950 <literal>G_OBJECT()</literal> macro.</para>
1951
1952 <para>For example:</para>
1953
1954 <programlisting role="C">
1955 g_signal_connect( G_OBJECT (button), "clicked",
1956                   G_CALLBACK (callback_function), callback_data);
1957 </programlisting>
1958
1959 <para>This casts the button into an object, and provides a cast for the
1960 function pointer to the callback.</para>
1961
1962 <para>Many widgets are also containers. If you look in the class hierarchy
1963 below, you'll notice that many widgets derive from the Container
1964 class. Any one of these widgets may be used with the
1965 <literal>GTK_CONTAINER</literal> macro to pass them to functions that ask for
1966 containers.</para>
1967
1968 <para>Unfortunately, these macros are not extensively covered in the
1969 tutorial, but I recommend taking a look through the GTK header
1970 files or the GTK API reference manual. It can be very educational. In fact, 
1971 it's not difficult to learn how a widget works just by looking at the 
1972 function declarations.</para>
1973
1974 </sect1>
1975
1976 <!-- ----------------------------------------------------------------- -->
1977 <sect1 id="sec-WidgetHierarchy">
1978 <title>Widget Hierarchy</title>
1979
1980 <para>For your reference, here is the class hierarchy tree used to implement 
1981 widgets. (Deprecated widgets and auxiliary classes have been omitted.)</para>
1982
1983 <programlisting role="C">
1984 GObject
1985  |  
1986  GtkObject
1987   +GtkWidget
1988   | +GtkMisc
1989   | | +GtkLabel
1990   | | | `GtkAccelLabel
1991   | | +GtkArrow
1992   | | `GtkImage
1993   | +GtkContainer
1994   | | +GtkBin
1995   | | | +GtkAlignment
1996   | | | +GtkFrame
1997   | | | | `GtkAspectFrame
1998   | | | +GtkButton
1999   | | | | +GtkToggleButton
2000   | | | | | `GtkCheckButton
2001   | | | | |   `GtkRadioButton
2002   | | | | `GtkOptionMenu
2003   | | | +GtkItem
2004   | | | | +GtkMenuItem
2005   | | | |   +GtkCheckMenuItem
2006   | | | |   | `GtkRadioMenuItem
2007   | | | |   +GtkImageMenuItem
2008   | | | |   +GtkSeparatorMenuItem
2009   | | | |   `GtkTearoffMenuItem
2010   | | | +GtkWindow
2011   | | | | +GtkDialog
2012   | | | | | +GtkColorSelectionDialog
2013   | | | | | +GtkFileSelection
2014   | | | | | +GtkFontSelectionDialog
2015   | | | | | +GtkInputDialog
2016   | | | | | `GtkMessageDialog
2017   | | | | `GtkPlug
2018   | | | +GtkEventBox
2019   | | | +GtkHandleBox
2020   | | | +GtkScrolledWindow
2021   | | | `GtkViewport
2022   | | +GtkBox
2023   | | | +GtkButtonBox
2024   | | | | +GtkHButtonBox
2025   | | | | `GtkVButtonBox
2026   | | | +GtkVBox
2027   | | | | +GtkColorSelection
2028   | | | | +GtkFontSelection
2029   | | | | `GtkGammaCurve
2030   | | | `GtkHBox
2031   | | |   +GtkCombo
2032   | | |   `GtkStatusbar
2033   | | +GtkFixed
2034   | | +GtkPaned
2035   | | | +GtkHPaned
2036   | | | `GtkVPaned
2037   | | +GtkLayout
2038   | | +GtkMenuShell
2039   | | | +GtkMenuBar
2040   | | | `GtkMenu
2041   | | +GtkNotebook
2042   | | +GtkSocket
2043   | | +GtkTable
2044   | | +GtkTextView
2045   | | +GtkToolbar
2046   | | `GtkTreeView
2047   | +GtkCalendar
2048   | +GtkDrawingArea
2049   | | `GtkCurve
2050   | +GtkEditable
2051   | | +GtkEntry
2052   | |   `GtkSpinButton
2053   | +GtkRuler
2054   | | +GtkHRuler
2055   | | `GtkVRuler
2056   | +GtkRange
2057   | | +GtkScale
2058   | | | +GtkHScale
2059   | | | `GtkVScale
2060   | | `GtkScrollbar
2061   | |   +GtkHScrollbar
2062   | |   `GtkVScrollbar
2063   | +GtkSeparator
2064   | | +GtkHSeparator
2065   | | `GtkVSeparator
2066   | +GtkInvisible
2067   | +GtkPreview
2068   | `GtkProgressBar
2069   +GtkAdjustment
2070   +GtkCellRenderer
2071   | +GtkCellRendererPixbuf
2072   | +GtkCellRendererText
2073   | +GtkCellRendererToggle
2074   +GtkItemFactory
2075   +GtkTooltips
2076   `GtkTreeViewColumn
2077 </programlisting>
2078
2079 </sect1>
2080
2081 <!-- ----------------------------------------------------------------- -->
2082 <sect1 id="sec-WidgetsWithoutWindows">
2083 <title>Widgets Without Windows</title>
2084
2085 <para>The following widgets do not have an associated window. If you want to
2086 capture events, you'll have to use the EventBox. See the section on
2087 the <link linkend="sec-EventBox">EventBox</link> widget.</para>
2088
2089 <programlisting role="C">
2090 GtkAlignment
2091 GtkArrow
2092 GtkBin
2093 GtkBox
2094 GtkButton
2095 GtkCheckButton
2096 GtkFixed
2097 GtkImage
2098 GtkLabel
2099 GtkMenuItem
2100 GtkNotebook
2101 GtkPaned
2102 GtkRadioButton
2103 GtkRange
2104 GtkScrolledWindow
2105 GtkSeparator
2106 GtkTable
2107 GtkToolbar
2108 GtkAspectFrame
2109 GtkFrame
2110 GtkVBox
2111 GtkHBox
2112 GtkVSeparator
2113 GtkHSeparator
2114 </programlisting>
2115
2116 <para>We'll further our exploration of GTK by examining each widget in turn,
2117 creating a few simple functions to display them. Another good source
2118 is the <literal>testgtk</literal> program that comes with GTK. It can be found in
2119 <filename>tests/testgtk.c</filename>.</para>
2120
2121 </sect1>
2122 </chapter>
2123
2124 <!-- ***************************************************************** -->
2125 <chapter id="ch-ButtonWidget">
2126 <title>The Button Widget</title>
2127
2128 <!-- ----------------------------------------------------------------- -->
2129 <sect1 id="sec-NormalButtons">
2130 <title>Normal Buttons</title>
2131
2132 <para>We've almost seen all there is to see of the button widget. It's
2133 pretty simple. There is however more than one way to create a button. You can
2134 use the gtk_button_new_with_label() or gtk_button_new_with_mnemonic() to create 
2135 a button with a label, use gtk_button_new_from_stock() to create a button
2136 containing the image and text from a stock item or use gtk_button_new() to
2137 create a blank button. It's then up to you to pack a label or pixmap into 
2138 this new button. To do this, create a new box, and then pack your objects into 
2139 this box using the usual gtk_box_pack_start(), and then use gtk_container_add() 
2140 to pack the box into the button.</para>
2141
2142 <para>Here's an example of using gtk_button_new() to create a button with a
2143 image and a label in it. I've broken up the code to create a box from the rest 
2144 so you can use it in your programs. There are further examples of using images 
2145 later in the tutorial.</para>
2146
2147 <para>
2148 <inlinemediaobject>
2149 <imageobject>
2150 <imagedata fileref="images/buttons.png" format="png">
2151 </imageobject>
2152 </inlinemediaobject>
2153 </para>
2154
2155 <programlisting role="C">
2156 <!-- example-start buttons buttons.c -->
2157
2158 #include &lt;stdlib.h&gt;
2159 #include &lt;gtk/gtk.h&gt;
2160
2161 /* Create a new hbox with an image and a label packed into it
2162  * and return the box. */
2163
2164 GtkWidget *xpm_label_box( gchar     *xpm_filename,
2165                           gchar     *label_text )
2166 {
2167     GtkWidget *box;
2168     GtkWidget *label;
2169     GtkWidget *image;
2170
2171     /* Create box for image and label */
2172     box = gtk_hbox_new (FALSE, 0);
2173     gtk_container_set_border_width (GTK_CONTAINER (box), 2);
2174
2175     /* Now on to the image stuff */
2176     image = gtk_image_new_from_file (xpm_filename);
2177
2178     /* Create a label for the button */
2179     label = gtk_label_new (label_text);
2180
2181     /* Pack the image and label into the box */
2182     gtk_box_pack_start (GTK_BOX (box), image, FALSE, FALSE, 3);
2183     gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 3);
2184
2185     gtk_widget_show (image);
2186     gtk_widget_show (label);
2187
2188     return box;
2189 }
2190
2191 /* Our usual callback function */
2192 void callback( GtkWidget *widget,
2193                gpointer   data )
2194 {
2195     g_print ("Hello again - %s was pressed\n", (char *) data);
2196 }
2197
2198 int main( int   argc,
2199           char *argv[] )
2200 {
2201     /* GtkWidget is the storage type for widgets */
2202     GtkWidget *window;
2203     GtkWidget *button;
2204     GtkWidget *box;
2205
2206     gtk_init (&amp;argc, &amp;argv);
2207
2208     /* Create a new window */
2209     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2210
2211     gtk_window_set_title (GTK_WINDOW (window), "Pixmap'd Buttons!");
2212
2213     /* It's a good idea to do this for all windows. */
2214     g_signal_connect (G_OBJECT (window), "destroy",
2215                       G_CALLBACK (gtk_main_quit), NULL);
2216
2217     g_signal_connect (G_OBJECT (window), "delete_event",
2218                       G_CALLBACK (gtk_main_quit), NULL);
2219
2220     /* Sets the border width of the window. */
2221     gtk_container_set_border_width (GTK_CONTAINER (window), 10);
2222
2223     /* Create a new button */
2224     button = gtk_button_new ();
2225
2226     /* Connect the "clicked" signal of the button to our callback */
2227     g_signal_connect (G_OBJECT (button), "clicked",
2228                       G_CALLBACK (callback), (gpointer) "cool button");
2229
2230     /* This calls our box creating function */
2231     box = xpm_label_box ("info.xpm", "cool button");
2232
2233     /* Pack and show all our widgets */
2234     gtk_widget_show (box);
2235
2236     gtk_container_add (GTK_CONTAINER (button), box);
2237
2238     gtk_widget_show (button);
2239
2240     gtk_container_add (GTK_CONTAINER (window), button);
2241
2242     gtk_widget_show (window);
2243
2244     /* Rest in gtk_main and wait for the fun to begin! */
2245     gtk_main ();
2246
2247     return 0;
2248 }
2249 <!-- example-end -->
2250 </programlisting>
2251
2252 <para>The xpm_label_box() function could be used to pack images and labels into
2253 any widget that can be a container.</para>
2254
2255 <para>The Button widget has the following signals:</para>
2256
2257 <itemizedlist>
2258 <listitem><simpara><literal>pressed</literal> - emitted when pointer button is pressed within
2259 Button widget</simpara>
2260 </listitem>
2261 <listitem><simpara><literal>released</literal> - emitted when pointer button is released within
2262 Button widget</simpara>
2263 </listitem>
2264 <listitem><simpara><literal>clicked</literal> - emitted when pointer button is pressed and then
2265 released within Button widget</simpara>
2266 </listitem>
2267 <listitem><simpara><literal>enter</literal> - emitted when pointer enters Button widget</simpara>
2268 </listitem>
2269 <listitem><simpara><literal>leave</literal> - emitted when pointer leaves Button widget</simpara>
2270 </listitem>
2271 </itemizedlist>
2272
2273 </sect1>
2274
2275 <!-- ----------------------------------------------------------------- -->
2276 <sect1 id="sec-ToggleButtons">
2277 <title>Toggle Buttons</title>
2278
2279 <para>Toggle buttons are derived from normal buttons and are very similar,
2280 except they will always be in one of two states, alternated by a
2281 click. They may be depressed, and when you click again, they will pop
2282 back up. Click again, and they will pop back down.</para>
2283
2284 <para>Toggle buttons are the basis for check buttons and radio buttons, as
2285 such, many of the calls used for toggle buttons are inherited by radio
2286 and check buttons. I will point these out when we come to them.</para>
2287
2288 <para>Creating a new toggle button:</para>
2289
2290 <programlisting role="C">
2291 GtkWidget *gtk_toggle_button_new( void );
2292
2293 GtkWidget *gtk_toggle_button_new_with_label( const gchar *label );
2294
2295 GtkWidget *gtk_toggle_button_new_with_mnemonic( const gchar *label );
2296 </programlisting>
2297
2298 <para>As you can imagine, these work identically to the normal button widget
2299 calls. The first creates a blank toggle button, and the last two, a
2300 button with a label widget already packed into it. The _mnemonic() variant
2301 additionally parses the label for '_'-prefixed mnemonic characters.</para>
2302
2303 <para>To retrieve the state of the toggle widget, including radio and check
2304 buttons, we use a construct as shown in our example below. This tests
2305 the state of the toggle button, by accessing the <literal>active</literal> field of the
2306 toggle widget's structure, after first using the
2307 <literal>GTK_TOGGLE_BUTTON</literal> macro to cast the widget pointer into a toggle
2308 widget pointer. The signal of interest to us emitted by toggle
2309 buttons (the toggle button, check button, and radio button widgets) is
2310 the "toggled" signal. To check the state of these buttons, set up a
2311 signal handler to catch the toggled signal, and access the structure
2312 to determine its state. The callback will look something like:</para>
2313
2314 <programlisting role="C">
2315 void toggle_button_callback (GtkWidget *widget, gpointer data)
2316 {
2317     if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) 
2318     {
2319         /* If control reaches here, the toggle button is down */
2320     
2321     } else {
2322     
2323         /* If control reaches here, the toggle button is up */
2324     }
2325 }
2326 </programlisting>
2327
2328 <para>To force the state of a toggle button, and its children, the radio and
2329 check buttons, use this function:</para>
2330
2331 <programlisting role="C">
2332 void gtk_toggle_button_set_active( GtkToggleButton *toggle_button,
2333                                    gboolean        is_active );
2334 </programlisting>
2335
2336 <para>The above call can be used to set the state of the toggle button, and
2337 its children the radio and check buttons. Passing in your created
2338 button as the first argument, and a TRUE or FALSE for the second state
2339 argument to specify whether it should be down (depressed) or up
2340 (released). Default is up, or FALSE.</para>
2341
2342 <para>Note that when you use the gtk_toggle_button_set_active() function, and
2343 the state is actually changed, it causes the "clicked" and "toggled"
2344 signals to be emitted from the button.</para>
2345
2346 <programlisting role="C">
2347 gboolean gtk_toggle_button_get_active   (GtkToggleButton *toggle_button);
2348 </programlisting>
2349
2350 <para>This returns the current state of the toggle button as a boolean
2351 TRUE/FALSE value.</para>
2352
2353 </sect1>
2354
2355 <!-- ----------------------------------------------------------------- -->
2356 <sect1 id="sec-CheckButtons">
2357 <title>Check Buttons</title>
2358
2359 <para>Check buttons inherit many properties and functions from the the
2360 toggle buttons above, but look a little different. Rather than being
2361 buttons with text inside them, they are small squares with the text to
2362 the right of them. These are often used for toggling options on and
2363 off in applications.</para>
2364
2365 <para>The creation functions are similar to those of the normal button.</para>
2366
2367 <programlisting role="C">
2368 GtkWidget *gtk_check_button_new( void );
2369
2370 GtkWidget *gtk_check_button_new_with_label ( const gchar *label );
2371
2372 GtkWidget *gtk_check_button_new_with_mnemonic ( const gchar *label );
2373 </programlisting>
2374
2375 <para>The gtk_check_button_new_with_label() function creates a check button 
2376 with a label beside it.</para>
2377
2378 <para>Checking the state of the check button is identical to that of the
2379 toggle button.</para>
2380
2381 </sect1>
2382
2383 <!-- ----------------------------------------------------------------- -->
2384 <sect1 id="sec-RadioButtons">
2385 <title>Radio Buttons</title>
2386
2387 <para>Radio buttons are similar to check buttons except they are grouped so
2388 that only one may be selected/depressed at a time. This is good for
2389 places in your application where you need to select from a short list
2390 of options.</para>
2391
2392 <para>Creating a new radio button is done with one of these calls:</para>
2393
2394 <programlisting role="C">
2395 GtkWidget *gtk_radio_button_new( GSList *group );
2396
2397 GtkWidget *gtk_radio_button_new_from_widget( GtkRadioButton *group );
2398
2399 GtkWidget *gtk_radio_button_new_with_label( GSList *group,
2400                                             const gchar  *label );
2401
2402 GtkWidget* gtk_radio_button_new_with_label_from_widget( GtkRadioButton *group,
2403                                                         const gchar    *label );
2404
2405 GtkWidget *gtk_radio_button_new_with_mnemonic( GSList *group,
2406                                                const gchar  *label );
2407
2408 GtkWidget *gtk_radio_button_new_with_mnemonic_from_widget( GtkRadioButton *group,
2409                                                            const gchar  *label );
2410
2411 </programlisting>
2412
2413 <para>You'll notice the extra argument to these calls. They require a group
2414 to perform their duty properly. The first call to gtk_radio_button_new() or 
2415 gtk_radio_button_new_with_label() should pass NULL as the first argument. 
2416 Then create a group using:</para>
2417
2418 <programlisting role="C">
2419 GSList *gtk_radio_button_get_group( GtkRadioButton *radio_button );
2420 </programlisting>
2421
2422 <para>The important thing to remember is that gtk_radio_button_get_group() must be
2423 called for each new button added to the group, with the previous button passed 
2424 in as an argument. The result is then passed into the next call to 
2425 gtk_radio_button_new() or gtk_radio_button_new_with_label(). This allows a
2426 chain of buttons to be established. The example below should make this clear.</para>
2427
2428 <para>You can shorten this slightly by using the following syntax, which
2429 removes the need for a variable to hold the list of buttons:</para>
2430
2431 <programlisting role="C">
2432      button2 = gtk_radio_button_new_with_label(
2433                  gtk_radio_button_get_group (GTK_RADIO_BUTTON (button1)),
2434                  "button2");
2435 </programlisting>
2436
2437 <para>
2438 The _from_widget() variants of the creation functions allow you to shorten this
2439 further, by omitting the gtk_radio_button_get_group() call. This form is used 
2440 in the example to create the third button:
2441 </para>
2442
2443 <programlisting role="C">
2444      button2 = gtk_radio_button_new_with_label_from_widget(
2445                  GTK_RADIO_BUTTON (button1), 
2446                  "button2");
2447 </programlisting>
2448
2449 <para>It is also a good idea to explicitly set which button should be the
2450 default depressed button with:</para>
2451
2452 <programlisting role="C">
2453 void gtk_toggle_button_set_active( GtkToggleButton *toggle_button,
2454                                    gboolean        state );
2455 </programlisting>
2456
2457 <para>This is described in the section on toggle buttons, and works in
2458 exactly the same way.  Once the radio buttons are grouped together,
2459 only one of the group may be active at a time. If the user clicks on
2460 one radio button, and then on another, the first radio button will
2461 first emit a "toggled" signal (to report becoming inactive), and then
2462 the second will emit its "toggled" signal (to report becoming active).</para>
2463
2464 <para>The following example creates a radio button group with three buttons.</para>
2465
2466 <para>
2467 <inlinemediaobject>
2468 <imageobject>
2469 <imagedata fileref="images/radiobuttons.png" format="png">
2470 </imageobject>
2471 </inlinemediaobject>
2472 </para>
2473
2474 <programlisting role="C">
2475 <!-- example-start radiobuttons radiobuttons.c -->
2476
2477 #include &lt;glib.h&gt;
2478 #include &lt;gtk/gtk.h&gt;
2479
2480 gint close_application( GtkWidget *widget,
2481                         GdkEvent  *event,
2482                         gpointer   data )
2483 {
2484   gtk_main_quit ();
2485   return FALSE;
2486 }
2487
2488 int main( int   argc,
2489           char *argv[] )
2490 {
2491     GtkWidget *window = NULL;
2492     GtkWidget *box1;
2493     GtkWidget *box2;
2494     GtkWidget *button;
2495     GtkWidget *separator;
2496     GSList *group;
2497   
2498     gtk_init (&amp;argc, &amp;argv);    
2499       
2500     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2501   
2502     g_signal_connect (G_OBJECT (window), "delete_event",
2503                       G_CALLBACK (close_application),
2504                       NULL);
2505
2506     gtk_window_set_title (GTK_WINDOW (window), "radio buttons");
2507     gtk_container_set_border_width (GTK_CONTAINER (window), 0);
2508
2509     box1 = gtk_vbox_new (FALSE, 0);
2510     gtk_container_add (GTK_CONTAINER (window), box1);
2511     gtk_widget_show (box1);
2512
2513     box2 = gtk_vbox_new (FALSE, 10);
2514     gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
2515     gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
2516     gtk_widget_show (box2);
2517
2518     button = gtk_radio_button_new_with_label (NULL, "button1");
2519     gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
2520     gtk_widget_show (button);
2521
2522     group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (button));
2523     button = gtk_radio_button_new_with_label (group, "button2");
2524     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
2525     gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
2526     gtk_widget_show (button);
2527
2528     button = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON (button),
2529                                                           "button3");
2530     gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
2531     gtk_widget_show (button);
2532
2533     separator = gtk_hseparator_new ();
2534     gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
2535     gtk_widget_show (separator);
2536
2537     box2 = gtk_vbox_new (FALSE, 10);
2538     gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
2539     gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
2540     gtk_widget_show (box2);
2541
2542     button = gtk_button_new_with_label ("close");
2543     g_signal_connect_swapped (G_OBJECT (button), "clicked",
2544                               G_CALLBACK (close_application),
2545                               G_OBJECT (window));
2546     gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
2547     GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
2548     gtk_widget_grab_default (button);
2549     gtk_widget_show (button);
2550     gtk_widget_show (window);
2551      
2552     gtk_main ();
2553
2554     return 0;
2555 }
2556 <!-- example-end -->
2557 </programlisting>
2558
2559 </sect1>
2560 </chapter>
2561
2562 <!-- ***************************************************************** -->
2563 <chapter id="ch-Adjustments">
2564 <title>Adjustments</title>
2565
2566 <para>GTK has various widgets that can be visually adjusted by the user
2567 using the mouse or the keyboard, such as the range widgets, described
2568 in the <link linkend="ch-RangeWidgets">Range Widgets</link>
2569 section. There are also a few widgets that display some adjustable
2570 portion of a larger area of data, such as the text widget and the
2571 viewport widget.</para>
2572
2573 <para>Obviously, an application needs to be able to react to changes the
2574 user makes in range widgets. One way to do this would be to have each
2575 widget emit its own type of signal when its adjustment changes, and
2576 either pass the new value to the signal handler, or require it to look
2577 inside the widget's data structure in order to ascertain the value.
2578 But you may also want to connect the adjustments of several widgets
2579 together, so that adjusting one adjusts the others. The most obvious
2580 example of this is connecting a scrollbar to a panning viewport or a
2581 scrolling text area. If each widget has its own way of setting or
2582 getting the adjustment value, then the programmer may have to write
2583 their own signal handlers to translate between the output of one
2584 widget's signal and the "input" of another's adjustment setting
2585 function.</para>
2586
2587 <para>GTK solves this problem using the Adjustment object, which is not a
2588 widget but a way for widgets to store and pass adjustment information
2589 in an abstract and flexible form. The most obvious use of Adjustment
2590 is to store the configuration parameters and values of range widgets,
2591 such as scrollbars and scale controls. However, since Adjustments are
2592 derived from Object, they have some special powers beyond those of
2593 normal data structures. Most importantly, they can emit signals, just
2594 like widgets, and these signals can be used not only to allow your
2595 program to react to user input on adjustable widgets, but also to
2596 propagate adjustment values transparently between adjustable widgets.</para>
2597
2598 <para>You will see how adjustments fit in when you see the other widgets
2599 that incorporate them:
2600 <link linkend="sec-ProgressBars">Progress Bars</link>,
2601 <link linkend="sec-Viewports">Viewports</link>,
2602 <link linkend="sec-ScrolledWindows">Scrolled Windows</link>, and others.</para>
2603
2604 <!-- ----------------------------------------------------------------- -->
2605 <sect1 id="sec-CreatingAnAdjustment">
2606 <title>Creating an Adjustment</title>
2607
2608 <para>Many of the widgets which use adjustment objects do so automatically,
2609 but some cases will be shown in later examples where you may need to
2610 create one yourself. You create an adjustment using:</para>
2611
2612 <programlisting role="C">
2613 GtkObject *gtk_adjustment_new( gdouble value,
2614                                gdouble lower,
2615                                gdouble upper,
2616                                gdouble step_increment,
2617                                gdouble page_increment,
2618                                gdouble page_size );
2619 </programlisting>
2620
2621 <para>The <literal>value</literal> argument is the initial value you want to give to the
2622 adjustment, usually corresponding to the topmost or leftmost position
2623 of an adjustable widget. The <literal>lower</literal> argument specifies the lowest
2624 value which the adjustment can hold. The <literal>step_increment</literal> argument
2625 specifies the "smaller" of the two increments by which the user can
2626 change the value, while the <literal>page_increment</literal> is the "larger" one.
2627 The <literal>page_size</literal> argument usually corresponds somehow to the visible
2628 area of a panning widget. The <literal>upper</literal> argument is used to represent
2629 the bottom most or right most coordinate in a panning widget's
2630 child. Therefore it is <emphasis>not</emphasis> always the largest number that
2631 <literal>value</literal> can take, since the <literal>page_size</literal> of such widgets is
2632 usually non-zero.</para>
2633
2634 </sect1>
2635
2636 <!-- ----------------------------------------------------------------- -->
2637 <sect1 id="sec-UsingAdjustments">
2638 <title>Using Adjustments the Easy Way</title>
2639
2640 <para>The adjustable widgets can be roughly divided into those which use and
2641 require specific units for these values and those which treat them as
2642 arbitrary numbers. The group which treats the values as arbitrary
2643 numbers includes the range widgets (scrollbars and scales, the
2644 progress bar widget, and the spin button widget). These widgets are
2645 all the widgets which are typically "adjusted" directly by the user
2646 with the mouse or keyboard. They will treat the <literal>lower</literal> and
2647 <literal>upper</literal> values of an adjustment as a range within which the user
2648 can manipulate the adjustment's <literal>value</literal>. By default, they will only
2649 modify the <literal>value</literal> of an adjustment.</para>
2650
2651 <para>The other group includes the text widget, the viewport widget, the
2652 compound list widget, and the scrolled window widget. All of these
2653 widgets use pixel values for their adjustments. These are also all
2654 widgets which are typically "adjusted" indirectly using scrollbars.
2655 While all widgets which use adjustments can either create their own
2656 adjustments or use ones you supply, you'll generally want to let this
2657 particular category of widgets create its own adjustments. Usually,
2658 they will eventually override all the values except the <literal>value</literal>
2659 itself in whatever adjustments you give them, but the results are, in
2660 general, undefined (meaning, you'll have to read the source code to
2661 find out, and it may be different from widget to widget).</para>
2662
2663 <para>Now, you're probably thinking, since text widgets and viewports insist
2664 on setting everything except the <literal>value</literal> of their adjustments,
2665 while scrollbars will <emphasis>only</emphasis> touch the adjustment's 
2666 <literal>value</literal>, if you <emphasis>share</emphasis> an adjustment
2667 object between a scrollbar and a text widget, manipulating the scrollbar will 
2668 automagically adjust the viewport widget?  Of course it will! Just like this:</para>
2669
2670 <programlisting role="C">
2671   /* creates its own adjustments */
2672   viewport = gtk_viewport_new (NULL, NULL);
2673   /* uses the newly-created adjustment for the scrollbar as well */
2674   vscrollbar = gtk_vscrollbar_new (gtk_viewport_get_vadjustment (viewport));
2675 </programlisting>
2676
2677 </sect1>
2678
2679 <!-- ----------------------------------------------------------------- -->
2680 <sect1 id="sec-AdjustmentInternals">
2681 <title>Adjustment Internals</title>
2682
2683 <para>Ok, you say, that's nice, but what if I want to create my own handlers
2684 to respond when the user adjusts a range widget or a spin button, and
2685 how do I get at the value of the adjustment in these handlers?  To
2686 answer these questions and more, let's start by taking a look at
2687 <literal>struct _GtkAdjustment</literal> itself:</para>
2688
2689 <programlisting role="C">
2690 struct _GtkAdjustment
2691 {
2692   GtkObject parent_instance;
2693   
2694   gdouble lower;
2695   gdouble upper;
2696   gdouble value;
2697   gdouble step_increment;
2698   gdouble page_increment;
2699   gdouble page_size;
2700 };
2701 </programlisting>
2702
2703 <para>If you don't like to poke directly at struct internals like a 
2704 <emphasis>real</emphasis> C programmer, you can use the following accessor to
2705 inspect the <literal>value</literal> of an adjustment:</para>
2706
2707 <programlisting role="C">
2708 gdouble gtk_adjustment_get_value( GtkAdjustment *adjustment);
2709 </programlisting>
2710
2711 <para>Since, when you set the <literal>value</literal> of an Adjustment, you generally
2712 want the change to be reflected by every widget that uses this
2713 adjustment, GTK provides this convenience function to do this:</para>
2714
2715 <programlisting role="C">
2716 void gtk_adjustment_set_value( GtkAdjustment *adjustment,
2717                                gdouble       value );
2718 </programlisting>
2719
2720 <para>As mentioned earlier, Adjustment is a subclass of Object just
2721 like all the various widgets, and thus it is able to emit signals.
2722 This is, of course, why updates happen automagically when you share an
2723 adjustment object between a scrollbar and another adjustable widget;
2724 all adjustable widgets connect signal handlers to their adjustment's
2725 <literal>value_changed</literal> signal, as can your program. Here's the definition
2726 of this signal in <literal>struct _GtkAdjustmentClass</literal>:</para>
2727
2728 <programlisting role="C">
2729   void (* value_changed) (GtkAdjustment *adjustment);
2730 </programlisting>
2731
2732 <para>The various widgets that use the Adjustment object will emit this
2733 signal on an adjustment whenever they change its value. This happens
2734 both when user input causes the slider to move on a range widget, as
2735 well as when the program explicitly changes the value with
2736 gtk_adjustment_set_value(). So, for example, if you have a scale
2737 widget, and you want to change the rotation of a picture whenever its
2738 value changes, you would create a callback like this:</para>
2739
2740 <programlisting role="C">
2741 void cb_rotate_picture (GtkAdjustment *adj, GtkWidget *picture)
2742 {
2743   set_picture_rotation (picture, gtk_adjustment_get_value (adj));
2744 ...
2745 </programlisting>
2746
2747 <para>and connect it to the scale widget's adjustment like this:</para>
2748
2749 <programlisting role="C">
2750 g_signal_connect (G_OBJECT (adj), "value_changed",
2751                   G_CALLBACK (cb_rotate_picture), (gpointer) picture);
2752 </programlisting>
2753
2754 <para>What about when a widget reconfigures the <literal>upper</literal> or <literal>lower</literal>
2755 fields of its adjustment, such as when a user adds more text to a text
2756 widget?  In this case, it emits the <literal>changed</literal> signal, which looks
2757 like this:</para>
2758
2759 <programlisting role="C">
2760   void (* changed) (GtkAdjustment *adjustment);
2761 </programlisting>
2762
2763 <para>Range widgets typically connect a handler to this signal, which
2764 changes their appearance to reflect the change - for example, the size
2765 of the slider in a scrollbar will grow or shrink in inverse proportion
2766 to the difference between the <literal>lower</literal> and <literal>upper</literal> values of its
2767 adjustment.</para>
2768
2769 <para>You probably won't ever need to attach a handler to this signal,
2770 unless you're writing a new type of range widget.  However, if you
2771 change any of the values in a Adjustment directly, you should emit
2772 this signal on it to reconfigure whatever widgets are using it, like
2773 this:</para>
2774
2775 <programlisting role="C">
2776 g_signal_emit_by_name (G_OBJECT (adjustment), "changed");
2777 </programlisting>
2778
2779 <para>Now go forth and adjust!</para>
2780
2781 </sect1>
2782 </chapter>
2783
2784 <!-- ***************************************************************** -->
2785 <chapter id="ch-RangeWidgets">
2786 <title>Range Widgets</title>
2787
2788 <para>The category of range widgets includes the ubiquitous scrollbar widget
2789 and the less common scale widget. Though these two types of widgets
2790 are generally used for different purposes, they are quite similar in
2791 function and implementation. All range widgets share a set of common
2792 graphic elements, each of which has its own X window and receives
2793 events. They all contain a "trough" and a "slider" (what is sometimes
2794 called a "thumbwheel" in other GUI environments). Dragging the slider
2795 with the pointer moves it back and forth within the trough, while
2796 clicking in the trough advances the slider towards the location of the
2797 click, either completely, or by a designated amount, depending on
2798 which mouse button is used.</para>
2799
2800 <para>As mentioned in <link linkend="ch-Adjustments">Adjustments</link> above,
2801 all range widgets are associated with an adjustment object, from which
2802 they calculate the length of the slider and its position within the
2803 trough. When the user manipulates the slider, the range widget will
2804 change the value of the adjustment.</para>
2805
2806 <!-- ----------------------------------------------------------------- -->
2807 <sect1 id="sec-ScrollbarWidgets">
2808 <title>Scrollbar Widgets</title>
2809
2810 <para>These are your standard, run-of-the-mill scrollbars. These should be
2811 used only for scrolling some other widget, such as a list, a text box,
2812 or a viewport (and it's generally easier to use the scrolled window
2813 widget in most cases).  For other purposes, you should use scale
2814 widgets, as they are friendlier and more featureful.</para>
2815
2816 <para>There are separate types for horizontal and vertical scrollbars.
2817 There really isn't much to say about these. You create them with the
2818 following functions:</para>
2819
2820 <programlisting role="C">
2821 GtkWidget *gtk_hscrollbar_new( GtkAdjustment *adjustment );
2822
2823 GtkWidget *gtk_vscrollbar_new( GtkAdjustment *adjustment );
2824 </programlisting>
2825
2826 <para>and that's about it (if you don't believe me, look in the header
2827 files!).  The <literal>adjustment</literal> argument can either be a pointer to an
2828 existing Adjustment, or NULL, in which case one will be created for
2829 you. Specifying NULL might actually be useful in this case, if you
2830 wish to pass the newly-created adjustment to the constructor function
2831 of some other widget which will configure it for you, such as a text
2832 widget.</para>
2833
2834 </sect1>
2835
2836 <!-- ----------------------------------------------------------------- -->
2837 <sect1 id="sec-ScaleWidgets">
2838 <title>Scale Widgets</title>
2839
2840 <para>Scale widgets are used to allow the user to visually select and
2841 manipulate a value within a specific range. You might want to use a
2842 scale widget, for example, to adjust the magnification level on a
2843 zoomed preview of a picture, or to control the brightness of a color,
2844 or to specify the number of minutes of inactivity before a screensaver
2845 takes over the screen.</para>
2846
2847 <!-- ----------------------------------------------------------------- -->
2848 <sect2>
2849 <title>Creating a Scale Widget</title>
2850
2851 <para>As with scrollbars, there are separate widget types for horizontal and
2852 vertical scale widgets. (Most programmers seem to favour horizontal
2853 scale widgets.) Since they work essentially the same way, there's no
2854 need to treat them separately here. The following functions create vertical and 
2855 horizontal scale widgets, respectively:</para>
2856
2857 <programlisting role="C">
2858 GtkWidget *gtk_vscale_new( GtkAdjustment *adjustment );
2859
2860 GtkWidget *gtk_vscale_new_with_range( gdouble min,
2861                                       gdouble max,
2862                                       gdouble step );
2863
2864 GtkWidget *gtk_hscale_new( GtkAdjustment *adjustment );
2865
2866 GtkWidget *gtk_hscale_new_with_range( gdouble min,
2867                                       gdouble max,
2868                                       gdouble step );
2869 </programlisting>
2870
2871 <para>The <literal>adjustment</literal> argument can either be an adjustment which has
2872 already been created with gtk_adjustment_new(), or NULL, in
2873 which case, an anonymous Adjustment is created with all of its
2874 values set to <literal>0.0</literal> (which isn't very useful in this case). 
2875 In order to avoid confusing yourself, you probably want to create your
2876 adjustment with a <literal>page_size</literal> of <literal>0.0</literal> so 
2877 that its <literal>upper</literal> value actually corresponds to the highest 
2878 value the user can select. The _new_with_range() variants take care of creating
2879 a suitable adjustment. (If you're <emphasis>already</emphasis> thoroughly
2880 confused, read the section on <link linkend="ch-Adjustments">Adjustments</link> 
2881 again for an explanation of what exactly adjustments do and how to create and 
2882 manipulate them.)</para>
2883
2884 </sect2>
2885
2886 <!-- ----------------------------------------------------------------- -->
2887 <sect2>
2888 <title>Functions and Signals (well, functions, at least)</title>
2889
2890 <para>Scale widgets can display their current value as a number beside the
2891 trough. The default behaviour is to show the value, but you can change
2892 this with this function:</para>
2893
2894 <programlisting role="C">
2895 void gtk_scale_set_draw_value( GtkScale *scale,
2896                                gboolean draw_value );
2897 </programlisting>
2898
2899 <para>As you might have guessed, <literal>draw_value</literal> is either <literal>TRUE</literal> or
2900 <literal>FALSE</literal>, with predictable consequences for either one.</para>
2901
2902 <para>The value displayed by a scale widget is rounded to one decimal point
2903 by default, as is the <literal>value</literal> field in its Adjustment. You can
2904 change this with:</para>
2905
2906 <programlisting role="C">
2907 void gtk_scale_set_digits( GtkScale *scale,
2908                             gint     digits );
2909 </programlisting>
2910
2911 <para>where <literal>digits</literal> is the number of decimal places you want. You can
2912 set <literal>digits</literal> to anything you like, but no more than 13 decimal
2913 places will actually be drawn on screen.</para>
2914
2915 <para>Finally, the value can be drawn in different positions
2916 relative to the trough:</para>
2917
2918 <programlisting role="C">
2919 void gtk_scale_set_value_pos( GtkScale        *scale,
2920                               GtkPositionType  pos );
2921 </programlisting>
2922
2923 <para>The argument <literal>pos</literal> is of type <literal>GtkPositionType</literal>,
2924 which can take one of the following values:</para>
2925
2926 <programlisting role="C">
2927   GTK_POS_LEFT
2928   GTK_POS_RIGHT
2929   GTK_POS_TOP
2930   GTK_POS_BOTTOM
2931 </programlisting>
2932
2933 <para>If you position the value on the "side" of the trough (e.g., on the
2934 top or bottom of a horizontal scale widget), then it will follow the
2935 slider up and down the trough.</para>
2936
2937 <para>All the preceding functions are defined in
2938 <literal>&lt;gtk/gtkscale.h&gt;</literal>. The header files for all GTK widgets
2939 are automatically included when you include
2940 <literal>&lt;gtk/gtk.h&gt;</literal>. But you should look over the header files
2941 of all widgets that interest you, in order to learn more about their functions
2942 and features.</para>
2943
2944 </sect2>
2945 </sect1>
2946
2947 <!-- ----------------------------------------------------------------- -->
2948 <sect1 id="sec-CommonRangeFunctions">
2949 <title>Common Range Functions</title>
2950
2951 <para>The Range widget class is fairly complicated internally, but, like
2952 all the "base class" widgets, most of its complexity is only
2953 interesting if you want to hack on it. Also, almost all of the
2954 functions and signals it defines are only really used in writing
2955 derived widgets. There are, however, a few useful functions that are
2956 defined in <literal>&lt;gtk/gtkrange.h&gt;</literal> and will work on all range
2957 widgets.</para>
2958
2959 <!-- ----------------------------------------------------------------- -->
2960 <sect2>
2961 <title>Setting the Update Policy</title>
2962
2963 <para>The "update policy" of a range widget defines at what points during
2964 user interaction it will change the <literal>value</literal> field of its
2965 Adjustment and emit the "value_changed" signal on this
2966 Adjustment. The update policies, defined in
2967 <literal>&lt;gtk/gtkenums.h&gt;</literal> as type <literal>enum GtkUpdateType</literal>,
2968 are:</para>
2969
2970 <variablelist>
2971 <varlistentry>
2972 <term><literal>GTK_UPDATE_CONTINUOUS</literal></term>
2973 <listitem><para>This is the default. The
2974 "value_changed" signal is emitted continuously, i.e., whenever the
2975 slider is moved by even the tiniest amount.</para>
2976 </listitem>
2977 </varlistentry>
2978 <varlistentry>
2979 <term><literal>GTK_UPDATE_DISCONTINUOUS</literal></term>
2980 <listitem><para>The "value_changed" signal is
2981 only emitted once the slider has stopped moving and the user has
2982 released the mouse button.</para>
2983 </listitem>
2984 </varlistentry>
2985 <varlistentry>
2986 <term><literal>GTK_UPDATE_DELAYED</literal></term>
2987 <listitem><para>The "value_changed" signal is emitted
2988 when the user releases the mouse button, or if the slider stops moving
2989 for a short period of time.</para>
2990 </listitem>
2991 </varlistentry>
2992 </variablelist>
2993
2994 <para>The update policy of a range widget can be set by casting it using the
2995 <literal>GTK_RANGE(widget)</literal> macro and passing it to this function:</para>
2996
2997 <programlisting role="C">
2998 void gtk_range_set_update_policy( GtkRange      *range,
2999                                   GtkUpdateType  policy);
3000 </programlisting>
3001
3002 </sect2>
3003
3004 <!-- ----------------------------------------------------------------- -->
3005 <sect2>
3006 <title>Getting and Setting Adjustments</title>
3007
3008 <para>Getting and setting the adjustment for a range widget "on the fly" is
3009 done, predictably, with:</para>
3010
3011 <programlisting role="C">
3012 GtkAdjustment* gtk_range_get_adjustment( GtkRange *range );
3013
3014 void gtk_range_set_adjustment( GtkRange      *range,
3015                                GtkAdjustment *adjustment );
3016 </programlisting>
3017
3018 <para><literal>gtk_range_get_adjustment()</literal> returns a pointer to the adjustment to
3019 which <literal>range</literal> is connected.</para>
3020
3021 <para><literal>gtk_range_set_adjustment()</literal> does absolutely nothing if you pass it
3022 the adjustment that <literal>range</literal> is already using, regardless of whether
3023 you changed any of its fields or not. If you pass it a new
3024 Adjustment, it will unreference the old one if it exists (possibly
3025 destroying it), connect the appropriate signals to the new one, and
3026 call the private function <literal>gtk_range_adjustment_changed()</literal>, which
3027 will (or at least, is supposed to...) recalculate the size and/or
3028 position of the slider and redraw if necessary. As mentioned in the
3029 section on adjustments, if you wish to reuse the same Adjustment,
3030 when you modify its values directly, you should emit the "changed"
3031 signal on it, like this:</para>
3032
3033 <programlisting role="C">
3034 g_signal_emit_by_name (G_OBJECT (adjustment), "changed");
3035 </programlisting>
3036
3037 </sect2>
3038 </sect1>
3039
3040 <!-- ----------------------------------------------------------------- -->
3041 <sect1 id="sec-KeyAndMouseBindings">
3042 <title>Key and Mouse bindings</title>
3043
3044 <para>All of the GTK range widgets react to mouse clicks in more or less
3045 the same way. Clicking button-1 in the trough will cause its
3046 adjustment's <literal>page_increment</literal> to be added or subtracted from its
3047 <literal>value</literal>, and the slider to be moved accordingly. Clicking mouse
3048 button-2 in the trough will jump the slider to the point at which the
3049 button was clicked. Clicking button-3 in the trough of a range or any button on 
3050 a scrollbar's arrows will cause its adjustment's value to change by
3051 <literal>step_increment</literal> at a time.</para>
3052
3053 <para>Scrollbars are not focusable, thus have no key bindings. The key bindings
3054 for the other range widgets (which are, of course, only active when the widget 
3055 has focus) are do <emphasis>not</emphasis> differentiate between horizontal and 
3056 vertical range widgets.</para>
3057
3058 <para>All range widgets can be operated with the left, right, up and down arrow
3059 keys, as well as with the <literal>Page Up</literal> and <literal>Page Down</literal> 
3060 keys. The arrows move the slider up and down by <literal>step_increment</literal>, while
3061 <literal>Page Up</literal> and <literal>Page Down</literal> move it by 
3062 <literal>page_increment</literal>.</para>
3063
3064 <para>The user can also move the slider all the way to one end or the other
3065 of the trough using the keyboard. This is done with the <literal>Home</literal> 
3066 and <literal>End</literal> keys.</para>
3067
3068 </sect1>
3069
3070 <!-- ----------------------------------------------------------------- -->
3071 <sect1 id="sec-RangeWidgetsExample">
3072 <title>Example</title>
3073
3074 <para>This example is a somewhat modified version of the "range controls"
3075 test from <filename>testgtk.c</filename>. It basically puts up a window with three
3076 range widgets all connected to the same adjustment, and a couple of
3077 controls for adjusting some of the parameters mentioned above and in
3078 the section on adjustments, so you can see how they affect the way
3079 these widgets work for the user.</para>
3080
3081 <para>
3082 <inlinemediaobject>
3083 <imageobject>
3084 <imagedata fileref="images/rangewidgets.png" format="png">
3085 </imageobject>
3086 </inlinemediaobject>
3087 </para>
3088
3089 <programlisting role="C">
3090 <!-- example-start rangewidgets rangewidgets.c -->
3091
3092 #include &lt;gtk/gtk.h&gt;
3093
3094 GtkWidget *hscale, *vscale;
3095
3096 void cb_pos_menu_select( GtkWidget       *item,
3097                          GtkPositionType  pos )
3098 {
3099     /* Set the value position on both scale widgets */
3100     gtk_scale_set_value_pos (GTK_SCALE (hscale), pos);
3101     gtk_scale_set_value_pos (GTK_SCALE (vscale), pos);
3102 }
3103
3104 void cb_update_menu_select( GtkWidget     *item,
3105                             GtkUpdateType  policy )
3106 {
3107     /* Set the update policy for both scale widgets */
3108     gtk_range_set_update_policy (GTK_RANGE (hscale), policy);
3109     gtk_range_set_update_policy (GTK_RANGE (vscale), policy);
3110 }
3111
3112 void cb_digits_scale( GtkAdjustment *adj )
3113 {
3114     /* Set the number of decimal places to which adj->value is rounded */
3115     gtk_scale_set_digits (GTK_SCALE (hscale), (gint) adj->value);
3116     gtk_scale_set_digits (GTK_SCALE (vscale), (gint) adj->value);
3117 }
3118
3119 void cb_page_size( GtkAdjustment *get,
3120                    GtkAdjustment *set )
3121 {
3122     /* Set the page size and page increment size of the sample
3123      * adjustment to the value specified by the "Page Size" scale */
3124     set->page_size = get->value;
3125     set->page_increment = get->value;
3126
3127     /* This sets the adjustment and makes it emit the "changed" signal to 
3128        reconfigure all the widgets that are attached to this signal.  */
3129     gtk_adjustment_set_value (set, CLAMP (set->value,
3130                                           set->lower,
3131                                           (set->upper - set->page_size)));
3132 }
3133
3134 void cb_draw_value( GtkToggleButton *button )
3135 {
3136     /* Turn the value display on the scale widgets off or on depending
3137      *  on the state of the checkbutton */
3138     gtk_scale_set_draw_value (GTK_SCALE (hscale), button->active);
3139     gtk_scale_set_draw_value (GTK_SCALE (vscale), button->active);  
3140 }
3141
3142 /* Convenience functions */
3143
3144 GtkWidget *make_menu_item (gchar     *name,
3145                            GCallback  callback,
3146                            gpointer   data)
3147 {
3148     GtkWidget *item;
3149   
3150     item = gtk_menu_item_new_with_label (name);
3151     g_signal_connect (G_OBJECT (item), "activate",
3152                       callback, (gpointer) data);
3153     gtk_widget_show (item);
3154
3155     return item;
3156 }
3157
3158 void scale_set_default_values( GtkScale *scale )
3159 {
3160     gtk_range_set_update_policy (GTK_RANGE (scale),
3161                                  GTK_UPDATE_CONTINUOUS);
3162     gtk_scale_set_digits (scale, 1);
3163     gtk_scale_set_value_pos (scale, GTK_POS_TOP);
3164     gtk_scale_set_draw_value (scale, TRUE);
3165 }
3166
3167 /* makes the sample window */
3168
3169 void create_range_controls( void )
3170 {
3171     GtkWidget *window;
3172     GtkWidget *box1, *box2, *box3;
3173     GtkWidget *button;
3174     GtkWidget *scrollbar;
3175     GtkWidget *separator;
3176     GtkWidget *opt, *menu, *item;
3177     GtkWidget *label;
3178     GtkWidget *scale;
3179     GtkObject *adj1, *adj2;
3180
3181     /* Standard window-creating stuff */
3182     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3183     g_signal_connect (G_OBJECT (window), "destroy",
3184                       G_CALLBACK (gtk_main_quit),
3185                       NULL);
3186     gtk_window_set_title (GTK_WINDOW (window), "range controls");
3187
3188     box1 = gtk_vbox_new (FALSE, 0);
3189     gtk_container_add (GTK_CONTAINER (window), box1);
3190     gtk_widget_show (box1);
3191
3192     box2 = gtk_hbox_new (FALSE, 10);
3193     gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
3194     gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
3195     gtk_widget_show (box2);
3196
3197     /* value, lower, upper, step_increment, page_increment, page_size */
3198     /* Note that the page_size value only makes a difference for
3199      * scrollbar widgets, and the highest value you'll get is actually
3200      * (upper - page_size). */
3201     adj1 = gtk_adjustment_new (0.0, 0.0, 101.0, 0.1, 1.0, 1.0);
3202   
3203     vscale = gtk_vscale_new (GTK_ADJUSTMENT (adj1));
3204     scale_set_default_values (GTK_SCALE (vscale));
3205     gtk_box_pack_start (GTK_BOX (box2), vscale, TRUE, TRUE, 0);
3206     gtk_widget_show (vscale);
3207
3208     box3 = gtk_vbox_new (FALSE, 10);
3209     gtk_box_pack_start (GTK_BOX (box2), box3, TRUE, TRUE, 0);
3210     gtk_widget_show (box3);
3211
3212     /* Reuse the same adjustment */
3213     hscale = gtk_hscale_new (GTK_ADJUSTMENT (adj1));
3214     gtk_widget_set_size_request (GTK_WIDGET (hscale), 200, -1);
3215     scale_set_default_values (GTK_SCALE (hscale));
3216     gtk_box_pack_start (GTK_BOX (box3), hscale, TRUE, TRUE, 0);
3217     gtk_widget_show (hscale);
3218
3219     /* Reuse the same adjustment again */
3220     scrollbar = gtk_hscrollbar_new (GTK_ADJUSTMENT (adj1));
3221     /* Notice how this causes the scales to always be updated
3222      * continuously when the scrollbar is moved */
3223     gtk_range_set_update_policy (GTK_RANGE (scrollbar), 
3224                                  GTK_UPDATE_CONTINUOUS);
3225     gtk_box_pack_start (GTK_BOX (box3), scrollbar, TRUE, TRUE, 0);
3226     gtk_widget_show (scrollbar);
3227
3228     box2 = gtk_hbox_new (FALSE, 10);
3229     gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
3230     gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
3231     gtk_widget_show (box2);
3232
3233     /* A checkbutton to control whether the value is displayed or not */
3234     button = gtk_check_button_new_with_label("Display value on scale widgets");
3235     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3236     g_signal_connect (G_OBJECT (button), "toggled",
3237                       G_CALLBACK (cb_draw_value), NULL);
3238     gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
3239     gtk_widget_show (button);
3240   
3241     box2 = gtk_hbox_new (FALSE, 10);
3242     gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
3243
3244     /* An option menu to change the position of the value */
3245     label = gtk_label_new ("Scale Value Position:");
3246     gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0);
3247     gtk_widget_show (label);
3248   
3249     opt = gtk_option_menu_new ();
3250     menu = gtk_menu_new ();
3251
3252     item = make_menu_item ("Top",
3253                            G_CALLBACK (cb_pos_menu_select),
3254                            GINT_TO_POINTER (GTK_POS_TOP));
3255     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3256   
3257     item = make_menu_item ("Bottom", G_CALLBACK (cb_pos_menu_select), 
3258                            GINT_TO_POINTER (GTK_POS_BOTTOM));
3259     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3260   
3261     item = make_menu_item ("Left", G_CALLBACK (cb_pos_menu_select),
3262                            GINT_TO_POINTER (GTK_POS_LEFT));
3263     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3264   
3265     item = make_menu_item ("Right", G_CALLBACK (cb_pos_menu_select),
3266                            GINT_TO_POINTER (GTK_POS_RIGHT));
3267     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3268   
3269     gtk_option_menu_set_menu (GTK_OPTION_MENU (opt), menu);
3270     gtk_box_pack_start (GTK_BOX (box2), opt, TRUE, TRUE, 0);
3271     gtk_widget_show (opt);
3272
3273     gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
3274     gtk_widget_show (box2);
3275
3276     box2 = gtk_hbox_new (FALSE, 10);
3277     gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
3278
3279     /* Yet another option menu, this time for the update policy of the
3280      * scale widgets */
3281     label = gtk_label_new ("Scale Update Policy:");
3282     gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0);
3283     gtk_widget_show (label);
3284   
3285     opt = gtk_option_menu_new ();
3286     menu = gtk_menu_new ();
3287   
3288     item = make_menu_item ("Continuous",
3289                            G_CALLBACK (cb_update_menu_select),
3290                            GINT_TO_POINTER (GTK_UPDATE_CONTINUOUS));
3291     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3292   
3293     item = make_menu_item ("Discontinuous",
3294                            G_CALLBACK (cb_update_menu_select),
3295                            GINT_TO_POINTER (GTK_UPDATE_DISCONTINUOUS));
3296     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3297   
3298     item = make_menu_item ("Delayed",
3299                            G_CALLBACK (cb_update_menu_select),
3300                            GINT_TO_POINTER (GTK_UPDATE_DELAYED));
3301     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3302   
3303     gtk_option_menu_set_menu (GTK_OPTION_MENU (opt), menu);
3304     gtk_box_pack_start (GTK_BOX (box2), opt, TRUE, TRUE, 0);
3305     gtk_widget_show (opt);
3306   
3307     gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
3308     gtk_widget_show (box2);
3309
3310     box2 = gtk_hbox_new (FALSE, 10);
3311     gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
3312   
3313     /* An HScale widget for adjusting the number of digits on the
3314      * sample scales. */
3315     label = gtk_label_new ("Scale Digits:");
3316     gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0);
3317     gtk_widget_show (label);
3318
3319     adj2 = gtk_adjustment_new (1.0, 0.0, 5.0, 1.0, 1.0, 0.0);
3320     g_signal_connect (G_OBJECT (adj2), "value_changed",
3321                       G_CALLBACK (cb_digits_scale), NULL);
3322     scale = gtk_hscale_new (GTK_ADJUSTMENT (adj2));
3323     gtk_scale_set_digits (GTK_SCALE (scale), 0);
3324     gtk_box_pack_start (GTK_BOX (box2), scale, TRUE, TRUE, 0);
3325     gtk_widget_show (scale);
3326
3327     gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
3328     gtk_widget_show (box2);
3329   
3330     box2 = gtk_hbox_new (FALSE, 10);
3331     gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
3332   
3333     /* And, one last HScale widget for adjusting the page size of the
3334      * scrollbar. */
3335     label = gtk_label_new ("Scrollbar Page Size:");
3336     gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0);
3337     gtk_widget_show (label);
3338
3339     adj2 = gtk_adjustment_new (1.0, 1.0, 101.0, 1.0, 1.0, 0.0);
3340     g_signal_connect (G_OBJECT (adj2), "value_changed",
3341                       G_CALLBACK (cb_page_size), (gpointer) adj1);
3342     scale = gtk_hscale_new (GTK_ADJUSTMENT (adj2));
3343     gtk_scale_set_digits (GTK_SCALE (scale), 0);
3344     gtk_box_pack_start (GTK_BOX (box2), scale, TRUE, TRUE, 0);
3345     gtk_widget_show (scale);
3346
3347     gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
3348     gtk_widget_show (box2);
3349
3350     separator = gtk_hseparator_new ();
3351     gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
3352     gtk_widget_show (separator);
3353
3354     box2 = gtk_vbox_new (FALSE, 10);
3355     gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
3356     gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
3357     gtk_widget_show (box2);
3358
3359     button = gtk_button_new_with_label ("Quit");
3360     g_signal_connect_swapped (G_OBJECT (button), "clicked",
3361                               G_CALLBACK (gtk_main_quit),
3362                               NULL);
3363     gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
3364     GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
3365     gtk_widget_grab_default (button);
3366     gtk_widget_show (button);
3367
3368     gtk_widget_show (window);
3369 }
3370
3371 int main( int   argc,
3372           char *argv[] )
3373 {
3374     gtk_init (&amp;argc, &amp;argv);
3375
3376     create_range_controls ();
3377
3378     gtk_main ();
3379
3380     return 0;
3381 }
3382
3383 <!-- example-end -->
3384 </programlisting>
3385
3386 <para>You will notice that the program does not call g_signal_connect()
3387 for the "delete_event", but only for the "destroy" signal. This will
3388 still perform the desired function, because an unhandled
3389 "delete_event" will result in a "destroy" signal being given to the
3390 window.</para>
3391
3392 </sect1>
3393 </chapter>
3394
3395 <!-- ***************************************************************** -->
3396 <chapter id="ch-MiscWidgets">
3397 <title>Miscellaneous Widgets</title>
3398
3399 <!-- ----------------------------------------------------------------- -->
3400 <sect1 id="sec-Labels">
3401 <title>Labels</title>
3402
3403 <para>Labels are used a lot in GTK, and are relatively simple. Labels emit
3404 no signals as they do not have an associated X window. If you need to
3405 catch signals, or do clipping, place it inside a <link linkend="sec-EventBox">
3406 EventBox</link> widget or a Button widget.</para>
3407
3408 <para>To create a new label, use:</para>
3409
3410 <programlisting role="C">
3411 GtkWidget *gtk_label_new( const char *str );
3412
3413 GtkWidget *gtk_label_new_with_mnemonic( const char *str );
3414 </programlisting>
3415
3416 <para>The sole argument is the string you wish the label to display.</para>
3417
3418 <para>To change the label's text after creation, use the function:</para>
3419
3420 <programlisting role="C">
3421 void gtk_label_set_text( GtkLabel   *label,
3422                          const char *str );
3423 </programlisting>
3424
3425 <para>The first argument is the label you created previously (cast
3426 using the <literal>GTK_LABEL()</literal> macro), and the second is the new string.</para>
3427
3428 <para>The space needed for the new string will be automatically adjusted if
3429 needed. You can produce multi-line labels by putting line breaks in
3430 the label string.</para>
3431
3432 <para>To retrieve the current string, use:</para>
3433
3434 <programlisting role="C">
3435 const gchar* gtk_label_get_text( GtkLabel  *label );                    
3436 </programlisting>
3437
3438 <para>Do not free the returned string, as it is used internally by GTK.</para>
3439
3440 <para>The label text can be justified using:</para>
3441
3442 <programlisting role="C">
3443 void gtk_label_set_justify( GtkLabel         *label,
3444                             GtkJustification  jtype );
3445 </programlisting>
3446
3447 <para>Values for <literal>jtype</literal> are:</para>
3448 <programlisting role="C">
3449   GTK_JUSTIFY_LEFT
3450   GTK_JUSTIFY_RIGHT
3451   GTK_JUSTIFY_CENTER (the default)
3452   GTK_JUSTIFY_FILL
3453 </programlisting>
3454
3455 <para>The label widget is also capable of line wrapping the text
3456 automatically. This can be activated using:</para>
3457
3458 <programlisting role="C">
3459 void gtk_label_set_line_wrap (GtkLabel *label,
3460                               gboolean  wrap);
3461 </programlisting>
3462
3463 <para>The <literal>wrap</literal> argument takes a TRUE or FALSE value.</para>
3464
3465 <para>If you want your label underlined, then you can set a pattern on the
3466 label:</para>
3467
3468 <programlisting role="C">
3469 void       gtk_label_set_pattern   (GtkLabel          *label,
3470                                     const gchar       *pattern);
3471 </programlisting>
3472
3473 <para>The pattern argument indicates how the underlining should look. It
3474 consists of a string of underscore and space characters. An underscore
3475 indicates that the corresponding character in the label should be
3476 underlined. For example, the string <literal>"__     __"</literal> would underline the
3477 first two characters and eight and ninth characters.</para>
3478
3479 <note><para>If you simply want to have an underlined accelerator ("mnemonic") 
3480 in your label, you should use gtk_label_new_with_mnemonic() or 
3481 gtk_label_set_text_with_mnemonic(), not gtk_label_set_pattern().</para>
3482 </note>
3483
3484 <para>Below is a short example to illustrate these functions. This example
3485 makes use of the Frame widget to better demonstrate the label
3486 styles. You can ignore this for now as the <link linkend="sec-Frames">Frame</link> 
3487 widget is explained later on.</para>
3488
3489 <para>In GTK+ 2.0, label texts can contain markup for font and other text attribute 
3490 changes, and labels may be selectable (for copy-and-paste). These advanced features
3491 won't be explained here.</para>
3492
3493 <para>
3494 <inlinemediaobject>
3495 <imageobject>
3496 <imagedata fileref="images/label.png" format="png">
3497 </imageobject>
3498 </inlinemediaobject>
3499 </para>
3500
3501 <programlisting role="C">
3502 <!-- example-start label label.c -->
3503
3504 #include &lt;gtk/gtk.h&gt;
3505
3506 int main( int   argc,
3507           char *argv[] )
3508 {
3509   static GtkWidget *window = NULL;
3510   GtkWidget *hbox;
3511   GtkWidget *vbox;
3512   GtkWidget *frame;
3513   GtkWidget *label;
3514
3515   /* Initialise GTK */
3516   gtk_init (&amp;argc, &amp;argv);
3517
3518   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3519   g_signal_connect (G_OBJECT (window), "destroy",
3520                     G_CALLBACK (gtk_main_quit),
3521                     NULL);
3522
3523   gtk_window_set_title (GTK_WINDOW (window), "Label");
3524   vbox = gtk_vbox_new (FALSE, 5);
3525   hbox = gtk_hbox_new (FALSE, 5);
3526   gtk_container_add (GTK_CONTAINER (window), hbox);
3527   gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
3528   gtk_container_set_border_width (GTK_CONTAINER (window), 5);
3529   
3530   frame = gtk_frame_new ("Normal Label");
3531   label = gtk_label_new ("This is a Normal label");
3532   gtk_container_add (GTK_CONTAINER (frame), label);
3533   gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3534   
3535   frame = gtk_frame_new ("Multi-line Label");
3536   label = gtk_label_new ("This is a Multi-line label.\nSecond line\n" \
3537                          "Third line");
3538   gtk_container_add (GTK_CONTAINER (frame), label);
3539   gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3540   
3541   frame = gtk_frame_new ("Left Justified Label");
3542   label = gtk_label_new ("This is a Left-Justified\n" \
3543                          "Multi-line label.\nThird      line");
3544   gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
3545   gtk_container_add (GTK_CONTAINER (frame), label);
3546   gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3547   
3548   frame = gtk_frame_new ("Right Justified Label");
3549   label = gtk_label_new ("This is a Right-Justified\nMulti-line label.\n" \
3550                          "Fourth line, (j/k)");
3551   gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_RIGHT);
3552   gtk_container_add (GTK_CONTAINER (frame), label);
3553   gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3554
3555   vbox = gtk_vbox_new (FALSE, 5);
3556   gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
3557   frame = gtk_frame_new ("Line wrapped label");
3558   label = gtk_label_new ("This is an example of a line-wrapped label.  It " \
3559                          "should not be taking up the entire             " /* big space to test spacing */\
3560                          "width allocated to it, but automatically " \
3561                          "wraps the words to fit.  " \
3562                          "The time has come, for all good men, to come to " \
3563                          "the aid of their party.  " \
3564                          "The sixth sheik's six sheep's sick.\n" \
3565                          "     It supports multiple paragraphs correctly, " \
3566                          "and  correctly   adds "\
3567                          "many          extra  spaces. ");
3568   gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
3569   gtk_container_add (GTK_CONTAINER (frame), label);
3570   gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3571   
3572   frame = gtk_frame_new ("Filled, wrapped label");
3573   label = gtk_label_new ("This is an example of a line-wrapped, filled label.  " \
3574                          "It should be taking "\
3575                          "up the entire              width allocated to it.  " \
3576                          "Here is a sentence to prove "\
3577                          "my point.  Here is another sentence. "\
3578                          "Here comes the sun, do de do de do.\n"\
3579                          "    This is a new paragraph.\n"\
3580                          "    This is another newer, longer, better " \
3581                          "paragraph.  It is coming to an end, "\
3582                          "unfortunately.");
3583   gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_FILL);
3584   gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
3585   gtk_container_add (GTK_CONTAINER (frame), label);
3586   gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3587   
3588   frame = gtk_frame_new ("Underlined label");
3589   label = gtk_label_new ("This label is underlined!\n"
3590                          "This one is underlined in quite a funky fashion");
3591   gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
3592   gtk_label_set_pattern (GTK_LABEL (label),
3593                          "_________________________ _ _________ _ ______     __ _______ ___");
3594   gtk_container_add (GTK_CONTAINER (frame), label);
3595   gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3596   
3597   gtk_widget_show_all (window);
3598
3599   gtk_main ();
3600   
3601   return 0;
3602 }
3603 <!-- example-end -->
3604 </programlisting>
3605
3606 </sect1>
3607
3608 <!-- ----------------------------------------------------------------- -->
3609 <sect1 id="sec-Arrows">
3610 <title>Arrows</title>
3611
3612 <para>The Arrow widget draws an arrowhead, facing in a number of possible
3613 directions and having a number of possible styles. It can be very
3614 useful when placed on a button in many applications. Like the Label
3615 widget, it emits no signals.</para>
3616
3617 <para>There are only two functions for manipulating an Arrow widget:</para>
3618
3619 <programlisting role="C">
3620 GtkWidget *gtk_arrow_new( GtkArrowType   arrow_type,
3621                           GtkShadowType  shadow_type );
3622
3623 void gtk_arrow_set( GtkArrow      *arrow,
3624                     GtkArrowType   arrow_type,
3625                     GtkShadowType  shadow_type );
3626 </programlisting>
3627
3628 <para>The first creates a new arrow widget with the indicated type and
3629 appearance. The second allows these values to be altered
3630 retrospectively. The <literal>arrow_type</literal> argument may take one of the
3631 following values:</para>
3632
3633 <programlisting role="C">
3634   GTK_ARROW_UP
3635   GTK_ARROW_DOWN
3636   GTK_ARROW_LEFT
3637   GTK_ARROW_RIGHT
3638 </programlisting>
3639
3640 <para>These values obviously indicate the direction in which the arrow will
3641 point. The <literal>shadow_type</literal> argument may take one of these values:</para>
3642
3643 <programlisting role="C">
3644   GTK_SHADOW_IN
3645   GTK_SHADOW_OUT (the default)
3646   GTK_SHADOW_ETCHED_IN
3647   GTK_SHADOW_ETCHED_OUT
3648 </programlisting>
3649
3650 <para>Here's a brief example to illustrate their use.</para>
3651
3652 <para>
3653 <inlinemediaobject>
3654 <imageobject>
3655 <imagedata fileref="images/arrow.png" format="png">
3656 </imageobject>
3657 </inlinemediaobject>
3658 </para>
3659
3660 <programlisting role="C">
3661 <!-- example-start arrow arrow.c -->
3662
3663 #include &lt;gtk/gtk.h&gt;
3664
3665 /* Create an Arrow widget with the specified parameters
3666  * and pack it into a button */
3667 GtkWidget *create_arrow_button( GtkArrowType  arrow_type,
3668                                 GtkShadowType shadow_type )
3669 {
3670   GtkWidget *button;
3671   GtkWidget *arrow;
3672
3673   button = gtk_button_new ();
3674   arrow = gtk_arrow_new (arrow_type, shadow_type);
3675
3676   gtk_container_add (GTK_CONTAINER (button), arrow);
3677   
3678   gtk_widget_show (button);
3679   gtk_widget_show (arrow);
3680
3681   return button;
3682 }
3683
3684 int main( int   argc,
3685           char *argv[] )
3686 {
3687   /* GtkWidget is the storage type for widgets */
3688   GtkWidget *window;
3689   GtkWidget *button;
3690   GtkWidget *box;
3691
3692   /* Initialize the toolkit */
3693   gtk_init (&amp;argc, &amp;argv);
3694
3695   /* Create a new window */
3696   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3697
3698   gtk_window_set_title (GTK_WINDOW (window), "Arrow Buttons");
3699
3700   /* It's a good idea to do this for all windows. */
3701   g_signal_connect (G_OBJECT (window), "destroy",
3702                     G_CALLBACK (gtk_main_quit), NULL);
3703
3704   /* Sets the border width of the window. */
3705   gtk_container_set_border_width (GTK_CONTAINER (window), 10);
3706
3707   /* Create a box to hold the arrows/buttons */
3708   box = gtk_hbox_new (FALSE, 0);
3709   gtk_container_set_border_width (GTK_CONTAINER (box), 2);
3710   gtk_container_add (GTK_CONTAINER (window), box);
3711
3712   /* Pack and show all our widgets */
3713   gtk_widget_show (box);
3714
3715   button = create_arrow_button (GTK_ARROW_UP, GTK_SHADOW_IN);
3716   gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 3);
3717
3718   button = create_arrow_button (GTK_ARROW_DOWN, GTK_SHADOW_OUT);
3719   gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 3);
3720   
3721   button = create_arrow_button (GTK_ARROW_LEFT, GTK_SHADOW_ETCHED_IN);
3722   gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 3);
3723   
3724   button = create_arrow_button (GTK_ARROW_RIGHT, GTK_SHADOW_ETCHED_OUT);
3725   gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 3);
3726   
3727   gtk_widget_show (window);
3728   
3729   /* Rest in gtk_main and wait for the fun to begin! */
3730   gtk_main ();
3731   
3732   return 0;
3733 }
3734 <!-- example-end -->
3735 </programlisting>
3736
3737 </sect1>
3738
3739 <!-- ----------------------------------------------------------------- -->
3740 <sect1 id="sec-TheTooltipsObject">
3741 <title>The Tooltips Object</title>
3742
3743 <para>These are the little text strings that pop up when you leave your
3744 pointer over a button or other widget for a few seconds. They are easy
3745 to use, so I will just explain them without giving an example. If you
3746 want to see some code, take a look at the <filename>testgtk.c</filename> program
3747 distributed with GTK.</para>
3748
3749 <para>Widgets that do not receive events (widgets that do not have their
3750 own window) will not work with tooltips.</para>
3751
3752 <para>The first call you will use creates a new tooltip. You only need to do
3753 this once for a set of tooltips as the <literal>GtkTooltips</literal> object this
3754 function returns can be used to create multiple tooltips.</para>
3755
3756 <programlisting role="C">
3757 GtkTooltips *gtk_tooltips_new( void );
3758 </programlisting>
3759
3760 <para>Once you have created a new tooltip, and the widget you wish to use it
3761 on, simply use this call to set it:</para>
3762
3763 <programlisting role="C">
3764 void gtk_tooltips_set_tip( GtkTooltips *tooltips,
3765                            GtkWidget   *widget,
3766                            const gchar *tip_text,
3767                            const gchar *tip_private );
3768 </programlisting>
3769
3770 <para>The first argument is the tooltip you've already created, followed by
3771 the widget you wish to have this tooltip pop up for, and the text you
3772 wish it to say. The last argument is a text string that can be used as
3773 an identifier when using GtkTipsQuery to implement context sensitive
3774 help. For now, you can set it to NULL.</para>
3775
3776 <!-- TODO: sort out what how to do the context sensitive help -->
3777
3778 <para>Here's a short example:</para>
3779
3780 <programlisting role="C">
3781 GtkTooltips *tooltips;
3782 GtkWidget *button;
3783 .
3784 .
3785 .
3786 tooltips = gtk_tooltips_new ();
3787 button = gtk_button_new_with_label ("button 1");
3788 .
3789 .
3790 .
3791 gtk_tooltips_set_tip (tooltips, button, "This is button 1", NULL);
3792 </programlisting>
3793
3794 <para>There are other calls that can be used with tooltips. I will just list
3795 them with a brief description of what they do.</para>
3796
3797 <programlisting role="C">
3798 void gtk_tooltips_enable( GtkTooltips *tooltips );
3799 </programlisting>
3800
3801 <para>Enable a disabled set of tooltips.</para>
3802
3803 <programlisting role="C">
3804 void gtk_tooltips_disable( GtkTooltips *tooltips );
3805 </programlisting>
3806
3807 <para>Disable an enabled set of tooltips.</para>
3808
3809 <para>And that's all the functions associated with tooltips. More than
3810 you'll ever want to know :-)</para>
3811
3812 </sect1>
3813
3814 <!-- ----------------------------------------------------------------- -->
3815 <sect1 id="sec-ProgressBars">
3816 <title>Progress Bars</title>
3817
3818 <para>Progress bars are used to show the status of an operation. They are
3819 pretty easy to use, as you will see with the code below. But first
3820 lets start out with the calls to create a new progress bar.</para>
3821
3822 <programlisting role="C">
3823 GtkWidget *gtk_progress_bar_new( void );
3824 </programlisting>
3825
3826 <para>Now that the progress bar has been created we can use it.</para>
3827
3828 <programlisting role="C">
3829 void gtk_progress_bar_set_fraction ( GtkProgressBar *pbar,
3830                                      gdouble        fraction );
3831 </programlisting>
3832
3833 <para>The first argument is the progress bar you wish to operate on, and the
3834 second argument is the amount "completed", meaning the amount the
3835 progress bar has been filled from 0-100%. This is passed to the
3836 function as a real number ranging from 0 to 1.</para>
3837
3838 <para>GTK v1.2 has added new functionality to the progress bar that enables
3839 it to display its value in different ways, and to inform the user of
3840 its current value and its range.</para>
3841
3842 <para>A progress bar may be set to one of a number of orientations using the
3843 function</para>
3844
3845 <programlisting role="C">
3846 void gtk_progress_bar_set_orientation( GtkProgressBar *pbar,
3847                                        GtkProgressBarOrientation orientation );
3848 </programlisting>
3849
3850 <para>The <literal>orientation</literal> argument may take one of the following
3851 values to indicate the direction in which the progress bar moves:</para>
3852
3853 <programlisting role="C">
3854   GTK_PROGRESS_LEFT_TO_RIGHT
3855   GTK_PROGRESS_RIGHT_TO_LEFT
3856   GTK_PROGRESS_BOTTOM_TO_TOP
3857   GTK_PROGRESS_TOP_TO_BOTTOM
3858 </programlisting>
3859
3860 <para>As well as indicating the amount of progress that has occured, the
3861 progress bar may be set to just indicate that there is some activity. 
3862 This can be useful in situations where progress cannot be measured against 
3863 a value range. The following function indicates that some progress has been 
3864 made.</para>
3865
3866 <programlisting role="C">
3867 void gtk_progress_bar_pulse ( GtkProgressBar *progress );
3868 </programlisting>
3869
3870 <para>The step size of the activity indicator is set using the following 
3871 function.</para>
3872
3873 <programlisting role="C">
3874 void gtk_progress_bar_set_pulse_step( GtkProgressBar *pbar,
3875                                       gdouble         fraction );
3876 </programlisting>
3877
3878 <para>When not in activity mode, the progress bar can also display a
3879 configurable text string within its trough, using the following
3880 function.</para>
3881
3882 <programlisting role="C">
3883 void gtk_progress_bar_set_text( GtkProgressBar *progress,
3884                                 const gchar    *text );
3885 </programlisting>
3886
3887 <note><para>Note that gtk_progress_set_text() doesn't support the printf()-like formatting
3888 of the GTK+ 1.2 Progressbar.</para></note>
3889
3890 <para>You can turn off the display of the string by calling gtk_progess_bar_set_text()
3891 again with NULL as second argument.</para>
3892
3893 <para>The current text setting of a progressbar can be retrieved with the 
3894 following function. Do not free the returned string.</para>
3895
3896 <programlisting role="C">
3897 const gchar *gtk_progress_bar_get_text( GtkProgressBar *pbar );
3898 </programlisting>
3899
3900 <para>Progress Bars are usually used with timeouts or other such functions
3901 (see section on <link linkend="ch-Timeouts">Timeouts, I/O and Idle Functions</link>) 
3902 to give the illusion of multitasking. All will employ the
3903 gtk_progress_bar_set_fraction() or gtk_progress_bar_pulse() functions in the 
3904 same manner.</para>
3905
3906 <para>Here is an example of the progress bar, updated using timeouts. This
3907 code also shows you how to reset the Progress Bar.</para>
3908
3909 <para>
3910 <inlinemediaobject>
3911 <imageobject>
3912 <imagedata fileref="images/progressbar.png" format="png">
3913 </imageobject>
3914 </inlinemediaobject>
3915 </para>
3916
3917 <programlisting role="C">
3918 <!-- example-start progressbar progressbar.c -->
3919
3920 #include &lt;gtk/gtk.h&gt;
3921
3922 typedef struct _ProgressData {
3923   GtkWidget *window;
3924   GtkWidget *pbar;
3925   int timer;
3926   gboolean activity_mode;
3927 } ProgressData;
3928
3929 /* Update the value of the progress bar so that we get
3930  * some movement */
3931 gint progress_timeout( gpointer data )
3932 {
3933   ProgressData *pdata = (ProgressData *)data;
3934   gdouble new_val;
3935   
3936   if (pdata-&gt;activity_mode) 
3937     gtk_progress_bar_pulse (GTK_PROGRESS_BAR (pdata-&gt;pbar));
3938   else 
3939     {
3940       /* Calculate the value of the progress bar using the
3941        * value range set in the adjustment object */
3942       
3943       new_val = gtk_progress_bar_get_fraction (GTK_PROGRESS_BAR (pdata-&gt;pbar)) + 0.01;
3944       
3945       if (new_val &gt; 1.0)
3946         new_val = 0.0;
3947       
3948       /* Set the new value */
3949       gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (pdata-&gt;pbar), new_val);
3950     }
3951   
3952   /* As this is a timeout function, return TRUE so that it
3953    * continues to get called */
3954   return TRUE;
3955
3956
3957 /* Callback that toggles the text display within the progress bar trough */
3958 void toggle_show_text( GtkWidget    *widget,
3959                        ProgressData *pdata )
3960 {
3961   const gchar *text;
3962   
3963   text = gtk_progress_bar_get_text (GTK_PROGRESS_BAR (pdata-&gt;pbar));
3964   if (text &amp;&amp; *text)
3965     gtk_progress_bar_set_text (GTK_PROGRESS_BAR (pdata-&gt;pbar), "");
3966   else 
3967     gtk_progress_bar_set_text (GTK_PROGRESS_BAR (pdata-&gt;pbar), "some text");
3968 }
3969
3970 /* Callback that toggles the activity mode of the progress bar */
3971 void toggle_activity_mode( GtkWidget    *widget,
3972                            ProgressData *pdata )
3973 {
3974   pdata-&gt;activity_mode = !pdata-&gt;activity_mode;
3975   if (pdata-&gt;activity_mode) 
3976       gtk_progress_bar_pulse (GTK_PROGRESS_BAR (pdata-&gt;pbar));
3977   else
3978       gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (pdata-&gt;pbar), 0.0);
3979 }
3980
3981  
3982 /* Callback that toggles the orientation of the progress bar */
3983 void toggle_orientation( GtkWidget    *widget,
3984                          ProgressData *pdata )
3985 {
3986   switch (gtk_progress_bar_get_orientation (GTK_PROGRESS_BAR (pdata-&gt;pbar))) {
3987   case GTK_PROGRESS_LEFT_TO_RIGHT:
3988     gtk_progress_bar_set_orientation (GTK_PROGRESS_BAR (pdata-&gt;pbar), 
3989                                       GTK_PROGRESS_RIGHT_TO_LEFT);
3990     break;
3991   case GTK_PROGRESS_RIGHT_TO_LEFT:
3992     gtk_progress_bar_set_orientation (GTK_PROGRESS_BAR (pdata-&gt;pbar), 
3993                                       GTK_PROGRESS_LEFT_TO_RIGHT);
3994     break;
3995   default:
3996     // do nothing       
3997   }
3998 }
3999
4000  
4001 /* Clean up allocated memory and remove the timer */
4002 void destroy_progress( GtkWidget     *widget,
4003                        ProgressData *pdata)
4004 {
4005     gtk_timeout_remove (pdata-&gt;timer);
4006     pdata-&gt;timer = 0;
4007     pdata-&gt;window = NULL;
4008     g_free (pdata);
4009     gtk_main_quit ();
4010 }
4011
4012 int main( int   argc,
4013           char *argv[])
4014 {
4015     ProgressData *pdata;
4016     GtkWidget *align;
4017     GtkWidget *separator;
4018     GtkWidget *table;
4019     GtkWidget *button;
4020     GtkWidget *check;
4021     GtkWidget *vbox;
4022
4023     gtk_init (&amp;argc, &amp;argv);
4024
4025     /* Allocate memory for the data that is passed to the callbacks */
4026     pdata = g_malloc (sizeof (ProgressData));
4027   
4028     pdata-&gt;window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
4029     gtk_window_set_resizable (GTK_WINDOW (pdata-&gt;window), TRUE);
4030
4031     g_signal_connect (G_OBJECT (pdata-&gt;window), "destroy",
4032                       G_CALLBACK (destroy_progress),
4033                       (gpointer) pdata);
4034     gtk_window_set_title (GTK_WINDOW (pdata-&gt;window), "GtkProgressBar");
4035     gtk_container_set_border_width (GTK_CONTAINER (pdata-&gt;window), 0);
4036
4037     vbox = gtk_vbox_new (FALSE, 5);
4038     gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
4039     gtk_container_add (GTK_CONTAINER (pdata-&gt;window), vbox);
4040     gtk_widget_show (vbox);
4041   
4042     /* Create a centering alignment object */
4043     align = gtk_alignment_new (0.5, 0.5, 0, 0);
4044     gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 5);
4045     gtk_widget_show (align);
4046
4047     /* Create the GtkProgressBar */
4048     pdata-&gt;pbar = gtk_progress_bar_new ();
4049
4050     gtk_container_add (GTK_CONTAINER (align), pdata-&gt;pbar);
4051     gtk_widget_show (pdata-&gt;pbar);
4052
4053     /* Add a timer callback to update the value of the progress bar */
4054     pdata-&gt;timer = gtk_timeout_add (100, progress_timeout, pdata);
4055
4056     separator = gtk_hseparator_new ();
4057     gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, 0);
4058     gtk_widget_show (separator);
4059
4060     /* rows, columns, homogeneous */
4061     table = gtk_table_new (2, 3, FALSE);
4062     gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0);
4063     gtk_widget_show (table);
4064
4065     /* Add a check button to select displaying of the trough text */
4066     check = gtk_check_button_new_with_label ("Show text");
4067     gtk_table_attach (GTK_TABLE (table), check, 0, 1, 0, 1,
4068                       GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
4069                       5, 5);
4070     g_signal_connect (G_OBJECT (check), "clicked",
4071                       G_CALLBACK (toggle_show_text),
4072                       (gpointer) pdata);
4073     gtk_widget_show (check);
4074
4075     /* Add a check button to toggle activity mode */
4076     check = gtk_check_button_new_with_label ("Activity mode");
4077     gtk_table_attach (GTK_TABLE (table), check, 0, 1, 1, 2,
4078                       GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
4079                       5, 5);
4080     g_signal_connect (G_OBJECT (check), "clicked",
4081                       G_CALLBACK (toggle_activity_mode),
4082                       (gpointer) pdata);
4083     gtk_widget_show (check);
4084
4085     /* Add a check button to toggle orientation */
4086     check = gtk_check_button_new_with_label ("Right to Left");
4087     gtk_table_attach (GTK_TABLE (table), check, 0, 1, 2, 3,
4088                       GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
4089                       5, 5);
4090     g_signal_connect (G_OBJECT (check), "clicked",
4091                       G_CALLBACK (toggle_orientation),
4092                       (gpointer) pdata);
4093     gtk_widget_show (check);
4094
4095     /* Add a button to exit the program */
4096     button = gtk_button_new_with_label ("close");
4097     g_signal_connect_swapped (G_OBJECT (button), "clicked",
4098                               G_CALLBACK (gtk_widget_destroy),
4099                               G_OBJECT (pdata-&gt;window));
4100     gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
4101
4102     /* This makes it so the button is the default. */
4103     GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
4104
4105     /* This grabs this button to be the default button. Simply hitting
4106      * the "Enter" key will cause this button to activate. */
4107     gtk_widget_grab_default (button);
4108     gtk_widget_show (button);
4109
4110     gtk_widget_show (pdata-&gt;window);
4111
4112     gtk_main ();
4113     
4114     return 0;
4115 }
4116 <!-- example-end -->
4117 </programlisting>
4118
4119 </sect1>
4120
4121 <!-- ----------------------------------------------------------------- -->
4122 <sect1 id="sec-Dialogs">
4123 <title>Dialogs</title>
4124
4125 <para>The Dialog widget is very simple, and is actually just a window with a
4126 few things pre-packed into it for you. The structure for a Dialog is:</para>
4127
4128 <programlisting role="C">
4129 struct GtkDialog
4130 {
4131       GtkWindow window;
4132     
4133       GtkWidget *vbox;
4134       GtkWidget *action_area;
4135 };
4136 </programlisting>
4137
4138 <para>So you see, it simply creates a window, and then packs a vbox into the
4139 top, which contains a separator and then an hbox called the
4140 "action_area".</para>
4141
4142 <para>The Dialog widget can be used for pop-up messages to the user, and
4143 other similar tasks. There are two functions to create a new Dialog.</para>
4144
4145 <programlisting role="C">
4146 GtkWidget *gtk_dialog_new( void );
4147
4148 GtkWidget *gtk_dialog_new_with_buttons( const gchar    *title,
4149                                         GtkWindow      *parent,
4150                                         GtkDialogFlags  flags, 
4151                                         const gchar    *first_button_text,
4152                                         ... );
4153 </programlisting>
4154
4155 <para>The first function will create an empty dialog, and it is now up to you to use
4156  it. You could pack a button in the action_area by doing something like this:</para>
4157
4158 <programlisting role="C">
4159     button = ...
4160     gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area),
4161                         button, TRUE, TRUE, 0);
4162     gtk_widget_show (button);
4163 </programlisting>
4164
4165 <para>And you could add to the vbox area by packing, for instance, a label 
4166 in it, try something like this:</para>
4167
4168 <programlisting role="C">
4169     label = gtk_label_new ("Dialogs are groovy");
4170     gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox),
4171                         label, TRUE, TRUE, 0);
4172     gtk_widget_show (label);
4173 </programlisting>
4174
4175 <para>As an example in using the dialog box, you could put two buttons in
4176 the action_area, a Cancel button and an Ok button, and a label in the
4177 vbox area, asking the user a question or giving an error etc. Then
4178 you could attach a different signal to each of the buttons and perform
4179 the operation the user selects.</para>
4180
4181 <para>If the simple functionality provided by the default vertical and
4182 horizontal boxes in the two areas doesn't give you enough control for
4183 your application, then you can simply pack another layout widget into
4184 the boxes provided. For example, you could pack a table into the
4185 vertical box.</para>
4186
4187 <para>The more complicated _new_with_buttons() variant allows to set one or
4188 more of the following flags.</para>
4189
4190 <variablelist>
4191 <varlistentry>
4192 <term><literal>GTK_DIALOG_MODAL</literal></term>
4193 <listitem><para>make the dialog modal.
4194 </para></listitem>
4195 </varlistentry>
4196 <varlistentry>
4197 <term><literal>GTK_DIALOG_DESTROY_WITH_PARENT</literal></term>
4198 <listitem><para>ensures that the dialog window is destroyed together with the specified
4199 parent.</para></listitem>
4200 </varlistentry>
4201 <varlistentry>
4202 <term><literal>GTK_DIALOG_NO_SEPARATOR</literal></term>
4203 <listitem><para>omits the separator between the vbox and the action_area.
4204 </para></listitem>
4205 </varlistentry>
4206 </variablelist>
4207 </sect1>
4208
4209 <!-- ----------------------------------------------------------------- -->
4210 <sect1 id="sec-Rulers">
4211 <title>Rulers</title>
4212
4213 <para>Ruler widgets are used to indicate the location of the mouse pointer
4214 in a given window. A window can have a vertical ruler spanning across
4215 the width and a horizontal ruler spanning down the height. A small
4216 triangular indicator on the ruler shows the exact location of the
4217 pointer relative to the ruler.</para>
4218
4219 <para>A ruler must first be created. Horizontal and vertical rulers are
4220 created using</para>
4221
4222 <programlisting role="C">
4223 GtkWidget *gtk_hruler_new( void );    /* horizontal ruler */
4224
4225 GtkWidget *gtk_vruler_new( void );    /* vertical ruler   */
4226 </programlisting>
4227
4228 <para>Once a ruler is created, we can define the unit of measurement. Units
4229 of measure for rulers can be<literal>GTK_PIXELS</literal>, <literal>GTK_INCHES</literal> or
4230 <literal>GTK_CENTIMETERS</literal>. This is set using</para>
4231
4232 <programlisting role="C">
4233 void gtk_ruler_set_metric( GtkRuler      *ruler,
4234                            GtkMetricType  metric );
4235 </programlisting>
4236
4237 <para>The default measure is <literal>GTK_PIXELS</literal>.</para>
4238
4239 <programlisting role="C">
4240     gtk_ruler_set_metric( GTK_RULER(ruler), GTK_PIXELS );
4241 </programlisting>
4242
4243 <para>Other important characteristics of a ruler are how to mark the units
4244 of scale and where the position indicator is initially placed. These
4245 are set for a ruler using</para>
4246
4247 <programlisting role="C">
4248 void gtk_ruler_set_range( GtkRuler *ruler,
4249                           gdouble   lower,
4250                           gdouble   upper,
4251                           gdouble   position,
4252                           gdouble   max_size );
4253 </programlisting>
4254
4255 <para>The lower and upper arguments define the extent of the ruler, and
4256 max_size is the largest possible number that will be displayed.
4257 Position defines the initial position of the pointer indicator within
4258 the ruler.</para>
4259
4260 <para>A vertical ruler can span an 800 pixel wide window thus</para>
4261
4262 <programlisting role="C">
4263     gtk_ruler_set_range( GTK_RULER(vruler), 0, 800, 0, 800);
4264 </programlisting>
4265
4266 <para>The markings displayed on the ruler will be from 0 to 800, with a
4267 number for every 100 pixels. If instead we wanted the ruler to range
4268 from 7 to 16, we would code</para>
4269
4270 <programlisting role="C">
4271     gtk_ruler_set_range( GTK_RULER(vruler), 7, 16, 0, 20);
4272 </programlisting>
4273
4274 <para>The indicator on the ruler is a small triangular mark that indicates
4275 the position of the pointer relative to the ruler. If the ruler is
4276 used to follow the mouse pointer, the motion_notify_event signal
4277 should be connected to the motion_notify_event method of the ruler.
4278 To follow all mouse movements within a window area, we would use</para>
4279
4280 <programlisting role="C">
4281 #define EVENT_METHOD(i, x) GTK_WIDGET_GET_CLASS(i)->x
4282
4283     g_signal_connect_swapped (G_OBJECT (area), "motion_notify_event",
4284            G_CALLBACK (EVENT_METHOD (ruler, motion_notify_event)),
4285            G_OBJECT (ruler));
4286 </programlisting>
4287
4288 <para>The following example creates a drawing area with a horizontal ruler
4289 above it and a vertical ruler to the left of it. The size of the
4290 drawing area is 600 pixels wide by 400 pixels high. The horizontal
4291 ruler spans from 7 to 13 with a mark every 100 pixels, while the
4292 vertical ruler spans from 0 to 400 with a mark every 100 pixels.
4293 Placement of the drawing area and the rulers is done using a table.</para>
4294
4295 <para>
4296 <inlinemediaobject>
4297 <imageobject>
4298 <imagedata fileref="images/rulers.png" format="png">
4299 </imageobject>
4300 </inlinemediaobject>
4301 </para>
4302
4303 <programlisting role="C">
4304 <!-- example-start rulers rulers.c -->
4305
4306 #include &lt;gtk/gtk.h&gt;
4307
4308 #define EVENT_METHOD(i, x) GTK_WIDGET_GET_CLASS(i)-&gt;x
4309
4310 #define XSIZE  600
4311 #define YSIZE  400
4312
4313 /* This routine gets control when the close button is clicked */
4314 gint close_application( GtkWidget *widget,
4315                         GdkEvent  *event,
4316                         gpointer   data )
4317 {
4318     gtk_main_quit ();
4319     return FALSE;
4320 }
4321
4322 /* The main routine */
4323 int main( int   argc,
4324           char *argv[] ) {
4325     GtkWidget *window, *table, *area, *hrule, *vrule;
4326
4327     /* Initialize GTK and create the main window */
4328     gtk_init (&amp;argc, &amp;argv);
4329
4330     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
4331     g_signal_connect (G_OBJECT (window), "delete_event",
4332                       G_CALLBACK (close_application), NULL);
4333     gtk_container_set_border_width (GTK_CONTAINER (window), 10);
4334
4335     /* Create a table for placing the ruler and the drawing area */
4336     table = gtk_table_new (3, 2, FALSE);
4337     gtk_container_add (GTK_CONTAINER (window), table);
4338
4339     area = gtk_drawing_area_new ();
4340     gtk_widget_set_size_request (GTK_WIDGET (area), XSIZE, YSIZE);
4341     gtk_table_attach (GTK_TABLE (table), area, 1, 2, 1, 2,
4342                       GTK_EXPAND|GTK_FILL, GTK_FILL, 0, 0);
4343     gtk_widget_set_events (area, GDK_POINTER_MOTION_MASK |
4344                                  GDK_POINTER_MOTION_HINT_MASK);
4345
4346     /* The horizontal ruler goes on top. As the mouse moves across the
4347      * drawing area, a motion_notify_event is passed to the
4348      * appropriate event handler for the ruler. */
4349     hrule = gtk_hruler_new ();
4350     gtk_ruler_set_metric (GTK_RULER (hrule), GTK_PIXELS);
4351     gtk_ruler_set_range (GTK_RULER (hrule), 7, 13, 0, 20);
4352     g_signal_connect_swapped (G_OBJECT (area), "motion_notify_event",
4353                               G_CALLBACK (EVENT_METHOD (hrule, motion_notify_event)),
4354                               G_OBJECT (hrule));
4355     gtk_table_attach (GTK_TABLE (table), hrule, 1, 2, 0, 1,
4356                       GTK_EXPAND|GTK_SHRINK|GTK_FILL, GTK_FILL, 0, 0);
4357     
4358     /* The vertical ruler goes on the left. As the mouse moves across
4359      * the drawing area, a motion_notify_event is passed to the
4360      * appropriate event handler for the ruler. */
4361     vrule = gtk_vruler_new ();
4362     gtk_ruler_set_metric (GTK_RULER (vrule), GTK_PIXELS);
4363     gtk_ruler_set_range (GTK_RULER (vrule), 0, YSIZE, 10, YSIZE );
4364     g_signal_connect_swapped (G_OBJECT (area), "motion_notify_event",
4365                               G_CALLBACK (EVENT_METHOD (vrule, motion_notify_event)),
4366                               G_OBJECT (vrule));
4367     gtk_table_attach (GTK_TABLE (table), vrule, 0, 1, 1, 2,
4368                       GTK_FILL, GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0);
4369
4370     /* Now show everything */
4371     gtk_widget_show (area);
4372     gtk_widget_show (hrule);
4373     gtk_widget_show (vrule);
4374     gtk_widget_show (table);
4375     gtk_widget_show (window);
4376     gtk_main ();
4377
4378     return 0;
4379 }
4380 <!-- example-end -->
4381 </programlisting>
4382
4383 </sect1>
4384
4385 <!-- ----------------------------------------------------------------- -->
4386 <sect1 id="sec-Statusbars">
4387 <title>Statusbars</title>
4388
4389 <para>Statusbars are simple widgets used to display a text message. They
4390 keep a stack of the messages pushed onto them, so that popping the
4391 current message will re-display the previous text message.</para>
4392
4393 <para>In order to allow different parts of an application to use the same
4394 statusbar to display messages, the statusbar widget issues Context
4395 Identifiers which are used to identify different "users". The message
4396 on top of the stack is the one displayed, no matter what context it is
4397 in. Messages are stacked in last-in-first-out order, not context
4398 identifier order.</para>
4399
4400 <para>A statusbar is created with a call to:</para>
4401
4402 <programlisting role="C">
4403 GtkWidget *gtk_statusbar_new( void );
4404 </programlisting>
4405
4406 <para>A new Context Identifier is requested using a call to the following 
4407 function with a short textual description of the context:</para>
4408
4409 <programlisting role="C">
4410 guint gtk_statusbar_get_context_id( GtkStatusbar *statusbar,
4411                                     const gchar  *context_description );
4412 </programlisting>
4413
4414 <para>There are three functions that can operate on statusbars:</para>
4415
4416 <programlisting role="C">
4417 guint gtk_statusbar_push( GtkStatusbar *statusbar,
4418                           guint         context_id,
4419                           const gchar  *text );
4420
4421 void gtk_statusbar_pop( GtkStatusbar *statusbar)
4422                         guint         context_id );
4423
4424 void gtk_statusbar_remove( GtkStatusbar *statusbar,
4425                            guint         context_id,
4426                            guint         message_id ); 
4427 </programlisting>
4428
4429 <para>The first, gtk_statusbar_push(), is used to add a new message to the
4430 statusbar.  It returns a Message Identifier, which can be passed later
4431 to the function gtk_statusbar_remove to remove the message with the
4432 given Message and Context Identifiers from the statusbar's stack.</para>
4433
4434 <para>The function gtk_statusbar_pop() removes the message highest in the
4435 stack with the given Context Identifier.</para>
4436
4437 <para>In addition to messages, statusbars may also display a resize grip, which 
4438 can be dragged with the mouse to resize the toplevel window containing the statusbar,
4439 similar to dragging the window frame. The following functions control the display
4440 of the resize grip.</para>
4441
4442 <programlisting role="C">
4443 void     gtk_statusbar_set_has_resize_grip( GtkStatusbar *statusbar,
4444                                             gboolean      setting );
4445
4446 gboolean gtk_statusbar_get_has_resize_grip( GtkStatusbar *statusbar );
4447 </programlisting>
4448
4449 <para>The following example creates a statusbar and two buttons, one for
4450 pushing items onto the statusbar, and one for popping the last item
4451 back off.</para>
4452
4453 <para>
4454 <inlinemediaobject>
4455 <imageobject>
4456 <imagedata fileref="images/statusbar.png" format="png">
4457 </imageobject>
4458 </inlinemediaobject>
4459 </para>
4460
4461 <programlisting role="C">
4462 <!-- example-start statusbar statusbar.c -->
4463
4464 #include &lt;stdlib.h&gt;
4465 #include &lt;gtk/gtk.h&gt;
4466 #include &lt;glib.h&gt;
4467
4468 GtkWidget *status_bar;
4469
4470 void push_item( GtkWidget *widget,
4471                 gpointer   data )
4472 {
4473   static int count = 1;
4474   char buff[20];
4475
4476   g_snprintf (buff, 20, "Item %d", count++);
4477   gtk_statusbar_push (GTK_STATUSBAR (status_bar), GPOINTER_TO_INT (data), buff);
4478
4479   return;
4480 }
4481
4482 void pop_item( GtkWidget *widget,
4483                gpointer   data )
4484 {
4485   gtk_statusbar_pop (GTK_STATUSBAR (status_bar), GPOINTER_TO_INT (data));
4486   return;
4487 }
4488
4489 int main( int   argc,
4490           char *argv[] )
4491 {
4492
4493     GtkWidget *window;
4494     GtkWidget *vbox;
4495     GtkWidget *button;
4496
4497     gint context_id;
4498
4499     gtk_init (&amp;argc, &amp;argv);
4500
4501     /* create a new window */
4502     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
4503     gtk_widget_set_size_request (GTK_WIDGET (window), 200, 100);
4504     gtk_window_set_title (GTK_WINDOW (window), "GTK Statusbar Example");
4505     g_signal_connect (G_OBJECT (window), "delete_event",
4506                       G_CALLBACK (exit), NULL);
4507  
4508     vbox = gtk_vbox_new (FALSE, 1);
4509     gtk_container_add (GTK_CONTAINER (window), vbox);
4510     gtk_widget_show (vbox);
4511           
4512     status_bar = gtk_statusbar_new ();      
4513     gtk_box_pack_start (GTK_BOX (vbox), status_bar, TRUE, TRUE, 0);
4514     gtk_widget_show (status_bar);
4515
4516     context_id = gtk_statusbar_get_context_id(
4517                           GTK_STATUSBAR (status_bar), "Statusbar example");
4518
4519     button = gtk_button_new_with_label ("push item");
4520     g_signal_connect (G_OBJECT (button), "clicked",
4521                       G_CALLBACK (push_item), GINT_TO_POINTER (context_id));
4522     gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 2);
4523     gtk_widget_show (button);              
4524
4525     button = gtk_button_new_with_label ("pop last item");
4526     g_signal_connect (G_OBJECT (button), "clicked",
4527                       G_CALLBACK (pop_item), GINT_TO_POINTER (context_id));
4528     gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 2);
4529     gtk_widget_show (button);
4530
4531     /* always display the window as the last step so it all splashes on
4532      * the screen at once. */
4533     gtk_widget_show (window);
4534
4535     gtk_main ();
4536
4537     return 0;
4538 }
4539 <!-- example-end -->
4540 </programlisting>
4541
4542 </sect1>
4543
4544 <!-- ----------------------------------------------------------------- -->
4545 <sect1 id="sec-TextEntries">
4546 <title>Text Entries</title>
4547
4548 <para>The Entry widget allows text to be typed and displayed in a single line
4549 text box. The text may be set with function calls that allow new text
4550 to replace, prepend or append the current contents of the Entry widget.</para>
4551
4552 <para>Create a new Entry widget with the following function.</para>
4553
4554 <programlisting role="C">
4555 GtkWidget *gtk_entry_new( void );
4556 </programlisting>
4557
4558 <para>The next function alters the text which is currently
4559 within the Entry widget.</para>
4560
4561 <programlisting role="C">
4562 void gtk_entry_set_text( GtkEntry    *entry,
4563                          const gchar *text );
4564 </programlisting>
4565
4566 <para>The function gtk_entry_set_text() sets the contents of the Entry widget,
4567 replacing the current contents. Note that the class Entry implements the Editable
4568 interface (yes, gobject supports Java-like interfaces) which contains some more
4569 functions for manipulating the contents.
4570  </para>
4571
4572 <para>The contents of the Entry can be retrieved by using a call to the
4573 following function. This is useful in the callback functions described below.</para>
4574
4575 <programlisting role="C">
4576 const gchar *gtk_entry_get_text( GtkEntry *entry );
4577 </programlisting>
4578
4579 <para>The value returned by this function is used internally, and must not
4580 be freed using either free() or g_free().</para>
4581
4582 <para>If we don't want the contents of the Entry to be changed by someone typing
4583 into it, we can change its editable state.</para>
4584
4585 <programlisting role="C">
4586 void gtk_editable_set_editable( GtkEditable *entry,
4587                                 gboolean     editable );
4588 </programlisting>
4589
4590 <para>The function above allows us to toggle the editable state of the
4591 Entry widget by passing in a TRUE or FALSE value for the <literal>editable</literal>
4592 argument.</para>
4593
4594 <para>If we are using the Entry where we don't want the text entered to be
4595 visible, for example when a password is being entered, we can use the
4596 following function, which also takes a boolean flag.</para>
4597
4598 <programlisting role="C">
4599 void gtk_entry_set_visibility( GtkEntry *entry,
4600                                gboolean  visible );
4601 </programlisting>
4602
4603 <para>A region of the text may be set as selected by using the following
4604 function. This would most often be used after setting some default
4605 text in an Entry, making it easy for the user to remove it.</para>
4606
4607 <programlisting role="C">
4608 void gtk_editable_select_region( GtkEditable *entry,
4609                                  gint         start,
4610                                  gint         end );
4611 </programlisting>
4612
4613 <para>If we want to catch when the user has entered text, we can connect to
4614 the <literal>activate</literal> or <literal>changed</literal> signal. Activate is raised when the
4615 user hits the enter key within the Entry widget. Changed is raised
4616 when the text changes at all, e.g., for every character entered or
4617 removed.</para>
4618
4619 <para>The following code is an example of using an Entry widget.</para>
4620
4621 <para>
4622 <inlinemediaobject>
4623 <imageobject>
4624 <imagedata fileref="images/entry.png" format="png">
4625 </imageobject>
4626 </inlinemediaobject>
4627 </para>
4628
4629 <programlisting role="C">
4630 <!-- example-start entry entry.c -->
4631
4632 #include &lt;stdio.h&gt;
4633 #include &lt;stdlib.h&gt;
4634 #include &lt;gtk/gtk.h&gt;
4635
4636 void enter_callback( GtkWidget *widget,
4637                      GtkWidget *entry )
4638 {
4639   const gchar *entry_text;
4640   entry_text = gtk_entry_get_text (GTK_ENTRY (entry));
4641   printf("Entry contents: %s\n", entry_text);
4642 }
4643
4644 void entry_toggle_editable( GtkWidget *checkbutton,
4645                             GtkWidget *entry )
4646 {
4647   gtk_editable_set_editable (GTK_EDITABLE (entry),
4648                              GTK_TOGGLE_BUTTON (checkbutton)-&gt;active);
4649 }
4650
4651 void entry_toggle_visibility( GtkWidget *checkbutton,
4652                               GtkWidget *entry )
4653 {
4654   gtk_entry_set_visibility (GTK_ENTRY (entry),
4655                             GTK_TOGGLE_BUTTON (checkbutton)-&gt;active);
4656 }
4657
4658 int main( int   argc,
4659           char *argv[] )
4660 {
4661
4662     GtkWidget *window;
4663     GtkWidget *vbox, *hbox;
4664     GtkWidget *entry;
4665     GtkWidget *button;
4666     GtkWidget *check;
4667     gint tmp_pos;
4668
4669     gtk_init (&amp;argc, &amp;argv);
4670
4671     /* create a new window */
4672     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
4673     gtk_widget_set_size_request (GTK_WIDGET (window), 200, 100);
4674     gtk_window_set_title (GTK_WINDOW (window), "GTK Entry");
4675     g_signal_connect (G_OBJECT (window), "destroy",
4676                       G_CALLBACK (gtk_main_quit), NULL);
4677     g_signal_connect_swapped (G_OBJECT (window), "delete_event",
4678                               G_CALLBACK (gtk_widget_destroy), 
4679                               G_OBJECT (window));
4680
4681     vbox = gtk_vbox_new (FALSE, 0);
4682     gtk_container_add (GTK_CONTAINER (window), vbox);
4683     gtk_widget_show (vbox);
4684
4685     entry = gtk_entry_new ();
4686     gtk_entry_set_max_length (GTK_ENTRY (entry), 50);
4687     g_signal_connect (G_OBJECT (entry), "activate",
4688                       G_CALLBACK (enter_callback),
4689                       (gpointer) entry);
4690     gtk_entry_set_text (GTK_ENTRY (entry), "hello");
4691     tmp_pos = GTK_ENTRY (entry)-&gt;text_length;
4692     gtk_editable_insert_text (GTK_EDITABLE (entry), " world", -1, &amp;tmp_pos);
4693     gtk_editable_select_region (GTK_EDITABLE (entry),
4694                                 0, GTK_ENTRY (entry)-&gt;text_length);
4695     gtk_box_pack_start (GTK_BOX (vbox), entry, TRUE, TRUE, 0);
4696     gtk_widget_show (entry);
4697
4698     hbox = gtk_hbox_new (FALSE, 0);
4699     gtk_container_add (GTK_CONTAINER (vbox), hbox);
4700     gtk_widget_show (hbox);
4701                                   
4702     check = gtk_check_button_new_with_label ("Editable");
4703     gtk_box_pack_start (GTK_BOX (hbox), check, TRUE, TRUE, 0);
4704     g_signal_connect (G_OBJECT (check), "toggled",
4705                       G_CALLBACK (entry_toggle_editable), (gpointer) entry);
4706     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), TRUE);
4707     gtk_widget_show (check);
4708     
4709     check = gtk_check_button_new_with_label ("Visible");
4710     gtk_box_pack_start (GTK_BOX (hbox), check, TRUE, TRUE, 0);
4711     g_signal_connect (G_OBJECT (check), "toggled",
4712                       G_CALLBACK (entry_toggle_visibility), (gpointer) entry);
4713     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), TRUE);
4714     gtk_widget_show (check);
4715                                    
4716     button = gtk_button_new_from_stock (GTK_STOCK_CLOSE);
4717     g_signal_connect_swapped (G_OBJECT (button), "clicked",
4718                               G_CALLBACK (gtk_widget_destroy),
4719                               G_OBJECT (window));
4720     gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);
4721     GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
4722     gtk_widget_grab_default (button);
4723     gtk_widget_show (button);
4724     
4725     gtk_widget_show (window);
4726
4727     gtk_main();
4728
4729     return 0;
4730 }
4731 <!-- example-end -->
4732 </programlisting>
4733
4734 </sect1>
4735
4736 <!-- ----------------------------------------------------------------- -->
4737 <sect1 id="sec-SpinButtons">
4738 <title>Spin Buttons</title>
4739
4740 <para>The Spin Button widget is generally used to allow the user to select a
4741 value from a range of numeric values. It consists of a text
4742 entry box with up and down arrow buttons attached to the
4743 side. Selecting one of the buttons causes the value to "spin" up and
4744 down the range of possible values. The entry box may also be edited
4745 directly to enter a specific value.</para>
4746
4747 <para>The Spin Button allows the value to have zero or a number of decimal
4748 places and to be incremented/decremented in configurable steps. The
4749 action of holding down one of the buttons optionally results in an
4750 acceleration of change in the value according to how long it is
4751 depressed.</para>
4752
4753 <para>The Spin Button uses an <link linkend="ch-Adjustments">Adjustment</link>
4754 object to hold information about the range of values that the spin
4755 button can take. This makes for a powerful Spin Button widget.</para>
4756
4757 <para>Recall that an adjustment widget is created with the following
4758 function, which illustrates the information that it holds:</para>
4759
4760 <programlisting role="C">
4761 GtkObject *gtk_adjustment_new( gdouble value,
4762                                gdouble lower,
4763                                gdouble upper,
4764                                gdouble step_increment,
4765                                gdouble page_increment,
4766                                gdouble page_size );
4767 </programlisting>
4768
4769 <para>These attributes of an Adjustment are used by the Spin Button in the
4770 following way:</para>
4771
4772 <itemizedlist>
4773 <listitem><simpara> <literal>value</literal>: initial value for the Spin Button</simpara>
4774 </listitem>
4775 <listitem><simpara> <literal>lower</literal>: lower range value</simpara>
4776 </listitem>
4777 <listitem><simpara> <literal>upper</literal>: upper range value</simpara>
4778 </listitem>
4779 <listitem><simpara> <literal>step_increment</literal>: value to increment/decrement when pressing
4780 mouse button 1 on a button</simpara>
4781 </listitem>
4782 <listitem><simpara> <literal>page_increment</literal>: value to increment/decrement when pressing
4783 mouse button 2 on a button</simpara>
4784 </listitem>
4785 <listitem><simpara> <literal>page_size</literal>: unused</simpara>
4786 </listitem>
4787 </itemizedlist>
4788
4789 <para>Additionally, mouse button 3 can be used to jump directly to the
4790 <literal>upper</literal> or <literal>lower</literal> values when used to select one of the
4791 buttons. Lets look at how to create a Spin Button:</para>
4792
4793 <programlisting role="C">
4794 GtkWidget *gtk_spin_button_new( GtkAdjustment *adjustment,
4795                                 gdouble         climb_rate,
4796                                 guint          digits );
4797 </programlisting>
4798
4799 <para>The <literal>climb_rate</literal> argument take a value between 0.0 and 1.0 and
4800 indicates the amount of acceleration that the Spin Button has. The
4801 <literal>digits</literal> argument specifies the number of decimal places to which
4802 the value will be displayed.</para>
4803
4804 <para>A Spin Button can be reconfigured after creation using the following
4805 function:</para>
4806
4807 <programlisting role="C">
4808 void gtk_spin_button_configure( GtkSpinButton *spin_button,
4809                                 GtkAdjustment *adjustment,
4810                                 gdouble        climb_rate,
4811                                 guint          digits );
4812 </programlisting>
4813
4814 <para>The <literal>spin_button</literal> argument specifies the Spin Button widget that is
4815 to be reconfigured. The other arguments are as specified above.</para>
4816
4817 <para>The adjustment can be set and retrieved independantly using the
4818 following two functions:</para>
4819
4820 <programlisting role="C">
4821 void gtk_spin_button_set_adjustment( GtkSpinButton  *spin_button,
4822                                      GtkAdjustment  *adjustment );
4823
4824 GtkAdjustment *gtk_spin_button_get_adjustment( GtkSpinButton *spin_button );
4825 </programlisting>
4826
4827 <para>The number of decimal places can also be altered using:</para>
4828
4829 <programlisting role="C">
4830 void gtk_spin_button_set_digits( GtkSpinButton *spin_button,
4831                                  guint          digits) ;
4832 </programlisting>
4833
4834 <para>The value that a Spin Button is currently displaying can be changed
4835 using the following function:</para>
4836
4837 <programlisting role="C">
4838 void gtk_spin_button_set_value( GtkSpinButton *spin_button,
4839                                 gdouble        value );
4840 </programlisting>
4841
4842 <para>The current value of a Spin Button can be retrieved as either a
4843 floating point or integer value with the following functions:</para>
4844
4845 <programlisting role="C">
4846 gdouble gtk_spin_button_get_value ( GtkSpinButton *spin_button );
4847
4848 gint gtk_spin_button_get_value_as_int( GtkSpinButton *spin_button );
4849 </programlisting>
4850
4851 <para>If you want to alter the value of a Spin Button relative to its current
4852 value, then the following function can be used:</para>
4853
4854 <programlisting role="C">
4855 void gtk_spin_button_spin( GtkSpinButton *spin_button,
4856                            GtkSpinType    direction,
4857                            gdouble        increment );
4858 </programlisting>
4859
4860 <para>The <literal>direction</literal> parameter can take one of the following values:</para>
4861
4862 <programlisting role="C">
4863   GTK_SPIN_STEP_FORWARD
4864   GTK_SPIN_STEP_BACKWARD
4865   GTK_SPIN_PAGE_FORWARD
4866   GTK_SPIN_PAGE_BACKWARD
4867   GTK_SPIN_HOME
4868   GTK_SPIN_END
4869   GTK_SPIN_USER_DEFINED
4870 </programlisting>
4871
4872 <para>This function packs in quite a bit of functionality, which I will
4873 attempt to clearly explain. Many of these settings use values from the
4874 Adjustment object that is associated with a Spin Button.</para>
4875
4876 <para><literal>GTK_SPIN_STEP_FORWARD</literal> and <literal>GTK_SPIN_STEP_BACKWARD</literal> change the
4877 value of the Spin Button by the amount specified by <literal>increment</literal>,
4878 unless <literal>increment</literal> is equal to 0, in which case the value is
4879 changed by the value of <literal>step_increment</literal> in theAdjustment.</para>
4880
4881 <para><literal>GTK_SPIN_PAGE_FORWARD</literal> and <literal>GTK_SPIN_PAGE_BACKWARD</literal> simply
4882 alter the value of the Spin Button by <literal>increment</literal>.</para>
4883
4884 <para><literal>GTK_SPIN_HOME</literal> sets the value of the Spin Button to the bottom of
4885 the Adjustments range.</para>
4886
4887 <para><literal>GTK_SPIN_END</literal> sets the value of the Spin Button to the top of the
4888 Adjustments range.</para>
4889
4890 <para><literal>GTK_SPIN_USER_DEFINED</literal> simply alters the value of the Spin Button
4891 by the specified amount.</para>
4892
4893 <para>We move away from functions for setting and retreving the range attributes
4894 of the Spin Button now, and move onto functions that effect the
4895 appearance and behaviour of the Spin Button widget itself.</para>
4896
4897 <para>The first of these functions is used to constrain the text box of the
4898 Spin Button such that it may only contain a numeric value. This
4899 prevents a user from typing anything other than numeric values into
4900 the text box of a Spin Button:</para>
4901
4902 <programlisting role="C">
4903 void gtk_spin_button_set_numeric( GtkSpinButton *spin_button,
4904                                   gboolean       numeric );
4905 </programlisting>
4906
4907 <para>You can set whether a Spin Button will wrap around between the upper
4908 and lower range values with the following function:</para>
4909
4910 <programlisting role="C">
4911 void gtk_spin_button_set_wrap( GtkSpinButton *spin_button,
4912                                gboolean       wrap );
4913 </programlisting>
4914
4915 <para>You can set a Spin Button to round the value to the nearest
4916 <literal>step_increment</literal>, which is set within the Adjustment object used
4917 with the Spin Button. This is accomplished with the following
4918 function:</para>
4919
4920 <programlisting role="C">
4921 void gtk_spin_button_set_snap_to_ticks( GtkSpinButton  *spin_button,
4922                                         gboolean        snap_to_ticks );
4923 </programlisting>
4924
4925 <para>The update policy of a Spin Button can be changed with the following
4926 function:</para>
4927
4928 <programlisting role="C">
4929 void gtk_spin_button_set_update_policy( GtkSpinButton  *spin_button,
4930                                     GtkSpinButtonUpdatePolicy policy );
4931 </programlisting>
4932
4933 <para>The possible values of <literal>policy</literal> are either <literal>GTK_UPDATE_ALWAYS</literal> or
4934 <literal>GTK_UPDATE_IF_VALID</literal>.</para>
4935
4936 <para>These policies affect the behavior of a Spin Button when parsing
4937 inserted text and syncing its value with the values of the
4938 Adjustment.</para>
4939
4940 <para>In the case of <literal>GTK_UPDATE_IF_VALID</literal> the Spin Button only value
4941 gets changed if the text input is a numeric value that is within the
4942 range specified by the Adjustment. Otherwise the text is reset to the
4943 current value.</para>
4944
4945 <para>In case of <literal>GTK_UPDATE_ALWAYS</literal> we ignore errors while converting
4946 text into a numeric value.</para>
4947
4948 <para>Finally, you can explicitly request that a Spin Button update itself:</para>
4949
4950 <programlisting role="C">
4951 void gtk_spin_button_update( GtkSpinButton  *spin_button );
4952 </programlisting>
4953
4954 <para>It's example time again.</para>
4955
4956 <para>
4957 <inlinemediaobject>
4958 <imageobject>
4959 <imagedata fileref="images/spinbutton.png" format="png">
4960 </imageobject>
4961 </inlinemediaobject>
4962 </para>
4963
4964 <programlisting role="C">
4965 <!-- example-start spinbutton spinbutton.c -->
4966
4967 #include &lt;stdio.h&gt;
4968 #include &lt;gtk/gtk.h&gt;
4969
4970 static GtkWidget *spinner1;
4971
4972 void toggle_snap( GtkWidget     *widget,
4973                   GtkSpinButton *spin )
4974 {
4975   gtk_spin_button_set_snap_to_ticks (spin, GTK_TOGGLE_BUTTON (widget)-&gt;active);
4976 }
4977
4978 void toggle_numeric( GtkWidget *widget,
4979                      GtkSpinButton *spin )
4980 {
4981   gtk_spin_button_set_numeric (spin, GTK_TOGGLE_BUTTON (widget)-&gt;active);
4982 }
4983
4984 void change_digits( GtkWidget *widget,
4985                     GtkSpinButton *spin )
4986 {
4987   gtk_spin_button_set_digits (GTK_SPIN_BUTTON (spinner1),
4988                               gtk_spin_button_get_value_as_int (spin));
4989 }
4990
4991 void get_value( GtkWidget *widget,
4992                 gpointer data )
4993 {
4994   gchar buf[32];
4995   GtkLabel *label;
4996   GtkSpinButton *spin;
4997
4998   spin = GTK_SPIN_BUTTON (spinner1);
4999   label = GTK_LABEL (g_object_get_data (G_OBJECT (widget), "user_data"));
5000   if (GPOINTER_TO_INT (data) == 1)
5001     sprintf (buf, "%d", gtk_spin_button_get_value_as_int (spin));
5002   else
5003     sprintf (buf, "%0.*f", spin-&gt;digits,
5004              gtk_spin_button_get_value (spin));
5005   gtk_label_set_text (label, buf);
5006 }
5007
5008
5009 int main( int   argc,
5010           char *argv[] )
5011 {
5012   GtkWidget *window;
5013   GtkWidget *frame;
5014   GtkWidget *hbox;
5015   GtkWidget *main_vbox;
5016   GtkWidget *vbox;
5017   GtkWidget *vbox2;
5018   GtkWidget *spinner2;
5019   GtkWidget *spinner;
5020   GtkWidget *button;
5021   GtkWidget *label;
5022   GtkWidget *val_label;
5023   GtkAdjustment *adj;
5024
5025   /* Initialise GTK */
5026   gtk_init (&amp;argc, &amp;argv);
5027
5028   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
5029
5030   g_signal_connect (G_OBJECT (window), "destroy",
5031                     G_CALLBACK (gtk_main_quit),
5032                     NULL);
5033
5034   gtk_window_set_title (GTK_WINDOW (window), "Spin Button");
5035
5036   main_vbox = gtk_vbox_new (FALSE, 5);
5037   gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 10);
5038   gtk_container_add (GTK_CONTAINER (window), main_vbox);
5039   
5040   frame = gtk_frame_new ("Not accelerated");
5041   gtk_box_pack_start (GTK_BOX (main_vbox), frame, TRUE, TRUE, 0);
5042   
5043   vbox = gtk_vbox_new (FALSE, 0);
5044   gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
5045   gtk_container_add (GTK_CONTAINER (frame), vbox);
5046   
5047   /* Day, month, year spinners */
5048   
5049   hbox = gtk_hbox_new (FALSE, 0);
5050   gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 5);
5051   
5052   vbox2 = gtk_vbox_new (FALSE, 0);
5053   gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
5054   
5055   label = gtk_label_new ("Day :");
5056   gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
5057   gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, TRUE, 0);
5058   
5059   adj = (GtkAdjustment *) gtk_adjustment_new (1.0, 1.0, 31.0, 1.0,
5060                                               5.0, 0.0);
5061   spinner = gtk_spin_button_new (adj, 0, 0);
5062   gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner), TRUE);
5063   gtk_box_pack_start (GTK_BOX (vbox2), spinner, FALSE, TRUE, 0);
5064   
5065   vbox2 = gtk_vbox_new (FALSE, 0);
5066   gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
5067   
5068   label = gtk_label_new ("Month :");
5069   gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
5070   gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, TRUE, 0);
5071   
5072   adj = (GtkAdjustment *) gtk_adjustment_new (1.0, 1.0, 12.0, 1.0,
5073                                               5.0, 0.0);
5074   spinner = gtk_spin_button_new (adj, 0, 0);
5075   gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner), TRUE);
5076   gtk_box_pack_start (GTK_BOX (vbox2), spinner, FALSE, TRUE, 0);
5077   
5078   vbox2 = gtk_vbox_new (FALSE, 0);
5079   gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
5080   
5081   label = gtk_label_new ("Year :");
5082   gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
5083   gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, TRUE, 0);
5084   
5085   adj = (GtkAdjustment *) gtk_adjustment_new (1998.0, 0.0, 2100.0,
5086                                               1.0, 100.0, 0.0);
5087   spinner = gtk_spin_button_new (adj, 0, 0);
5088   gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner), FALSE);
5089   gtk_widget_set_size_request (spinner, 55, -1);
5090   gtk_box_pack_start (GTK_BOX (vbox2), spinner, FALSE, TRUE, 0);
5091   
5092   frame = gtk_frame_new ("Accelerated");
5093   gtk_box_pack_start (GTK_BOX (main_vbox), frame, TRUE, TRUE, 0);
5094   
5095   vbox = gtk_vbox_new (FALSE, 0);
5096   gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
5097   gtk_container_add (GTK_CONTAINER (frame), vbox);
5098   
5099   hbox = gtk_hbox_new (FALSE, 0);
5100   gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 5);
5101   
5102   vbox2 = gtk_vbox_new (FALSE, 0);
5103   gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
5104   
5105   label = gtk_label_new ("Value :");
5106   gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
5107   gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, TRUE, 0);
5108   
5109   adj = (GtkAdjustment *) gtk_adjustment_new (0.0, -10000.0, 10000.0,
5110                                               0.5, 100.0, 0.0);
5111   spinner1 = gtk_spin_button_new (adj, 1.0, 2);
5112   gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner1), TRUE);
5113   gtk_widget_set_size_request (spinner1, 100, -1);
5114   gtk_box_pack_start (GTK_BOX (vbox2), spinner1, FALSE, TRUE, 0);
5115   
5116   vbox2 = gtk_vbox_new (FALSE, 0);
5117   gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
5118   
5119   label = gtk_label_new ("Digits :");
5120   gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
5121   gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, TRUE, 0);
5122   
5123   adj = (GtkAdjustment *) gtk_adjustment_new (2, 1, 5, 1, 1, 0);
5124   spinner2 = gtk_spin_button_new (adj, 0.0, 0);
5125   gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner2), TRUE);
5126   g_signal_connect (G_OBJECT (adj), "value_changed",
5127                     G_CALLBACK (change_digits),
5128                     (gpointer) spinner2);
5129   gtk_box_pack_start (GTK_BOX (vbox2), spinner2, FALSE, TRUE, 0);
5130   
5131   hbox = gtk_hbox_new (FALSE, 0);
5132   gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 5);
5133   
5134   button = gtk_check_button_new_with_label ("Snap to 0.5-ticks");
5135   g_signal_connect (G_OBJECT (button), "clicked",
5136                     G_CALLBACK (toggle_snap),
5137                     (gpointer) spinner1);
5138   gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);
5139   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
5140   
5141   button = gtk_check_button_new_with_label ("Numeric only input mode");
5142   g_signal_connect (G_OBJECT (button), "clicked",
5143                     G_CALLBACK (toggle_numeric),
5144                     (gpointer) spinner1);
5145   gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);
5146   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
5147   
5148   val_label = gtk_label_new ("");
5149   
5150   hbox = gtk_hbox_new (FALSE, 0);
5151   gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 5);
5152   button = gtk_button_new_with_label ("Value as Int");
5153   g_object_set_data (G_OBJECT (button), "user_data", val_label);
5154   g_signal_connect (G_OBJECT (button), "clicked",
5155                     G_CALLBACK (get_value),
5156                     GINT_TO_POINTER (1));
5157   gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 5);
5158   
5159   button = gtk_button_new_with_label ("Value as Float");
5160   g_object_set_data (G_OBJECT (button), "user_data", val_label);
5161   g_signal_connect (G_OBJECT (button), "clicked",
5162                     G_CALLBACK (get_value),
5163                     GINT_TO_POINTER (2));
5164   gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 5);
5165   
5166   gtk_box_pack_start (GTK_BOX (vbox), val_label, TRUE, TRUE, 0);
5167   gtk_label_set_text (GTK_LABEL (val_label), "0");
5168   
5169   hbox = gtk_hbox_new (FALSE, 0);
5170   gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, TRUE, 0);
5171   
5172   button = gtk_button_new_with_label ("Close");
5173   g_signal_connect_swapped (G_OBJECT (button), "clicked",
5174                             G_CALLBACK (gtk_widget_destroy),
5175                             G_OBJECT (window));
5176   gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 5);
5177
5178   gtk_widget_show_all (window);
5179
5180   /* Enter the event loop */
5181   gtk_main ();
5182     
5183   return 0;
5184 }
5185
5186 <!-- example-end -->
5187 </programlisting>
5188
5189 </sect1>
5190
5191 <!-- ----------------------------------------------------------------- -->
5192 <sect1 id="sec-ComboBox">
5193 <title>Combo Box</title>
5194
5195 <para>The combo box is another fairly simple widget that is really just a
5196 collection of other widgets. From the user's point of view, the widget
5197 consists of a text entry box and a pull down menu from which the user
5198 can select one of a set of predefined entries. Alternatively, the user
5199 can type a different option directly into the text box.</para>
5200
5201 <para>The following extract from the structure that defines a Combo Box
5202 identifies several of the components:</para>
5203
5204 <programlisting role="C">
5205 struct _GtkCombo { 
5206         GtkHBox hbox; 
5207         GtkWidget *entry; 
5208         GtkWidget *button;
5209         GtkWidget *popup; 
5210         GtkWidget *popwin; 
5211         GtkWidget *list;
5212         ...  };
5213 </programlisting>
5214
5215 <para>As you can see, the Combo Box has two principal parts that you really
5216 care about: an entry and a list.</para>
5217
5218 <para>First off, to create a combo box, use:</para>
5219
5220 <programlisting role="C">
5221 GtkWidget *gtk_combo_new( void );
5222 </programlisting>
5223
5224 <para>Now, if you want to set the string in the entry section of the combo
5225 box, this is done by manipulating the <literal>entry</literal> widget directly:</para>
5226
5227 <programlisting role="C">
5228     gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (combo)->entry), "My String.");
5229 </programlisting>
5230
5231 <para>To set the values in the popdown list, one uses the function:</para>
5232
5233 <programlisting role="C">
5234 void gtk_combo_set_popdown_strings( GtkCombo *combo,
5235                                     GList    *strings );
5236 </programlisting>
5237
5238 <para>Before you can do this, you have to assemble a GList of the strings
5239 that you want. GList is a linked list implementation that is part of
5240 <link linkend="ch-GLib">GLib</link>, a library supporting GTK. For the
5241 moment, the quick and dirty explanation is that you need to set up a
5242 GList pointer, set it equal to NULL, then append strings to it with</para>
5243
5244 <programlisting role="C">
5245 GList *g_list_append( GList *glist, 
5246                       gpointer data );
5247 </programlisting>
5248
5249 <para>It is important that you set the initial GList pointer to NULL. The
5250 value returned from the g_list_append() function must be used as the new
5251 pointer to the GList.</para>
5252
5253 <para>Here's a typical code segment for creating a set of options:</para>
5254
5255 <programlisting role="C">
5256     GList *glist = NULL;
5257
5258     glist = g_list_append (glist, "String 1");
5259     glist = g_list_append (glist, "String 2");
5260     glist = g_list_append (glist, "String 3"); 
5261     glist = g_list_append (glist, "String 4");
5262
5263     gtk_combo_set_popdown_strings (GTK_COMBO (combo), glist);
5264     
5265     /* can free glist now, combo takes a copy */
5266 </programlisting>
5267
5268 <para>The combo widget makes a copy of the strings passed to it in the glist
5269 structure. As a result, you need to make sure you free the memory used
5270 by the list if that is appropriate for your application.</para>
5271
5272 <para>At this point you have a working combo box that has been set up.
5273 There are a few aspects of its behavior that you can change. These
5274 are accomplished with the functions: </para>
5275
5276 <programlisting role="C">
5277 void gtk_combo_set_use_arrows( GtkCombo *combo,
5278                                gboolean  val );
5279
5280 void gtk_combo_set_use_arrows_always( GtkCombo *combo,
5281                                       gboolean  val );
5282
5283 void gtk_combo_set_case_sensitive( GtkCombo *combo,
5284                                    gboolean  val );
5285 </programlisting>
5286
5287 <para>gtk_combo_set_use_arrows() lets the user change the value in the
5288 entry using the up/down arrow keys. This doesn't bring up the list, but
5289 rather replaces the current text in the entry with the next list entry
5290 (up or down, as your key choice indicates). It does this by searching
5291 in the list for the item corresponding to the current value in the
5292 entry and selecting the previous/next item accordingly. Usually in an
5293 entry the arrow keys are used to change focus (you can do that anyway
5294 using TAB). Note that when the current item is the last of the list
5295 and you press arrow-down it changes the focus (the same applies with
5296 the first item and arrow-up).</para>
5297
5298 <para>If the current value in the entry is not in the list, then the
5299 function of gtk_combo_set_use_arrows() is disabled.</para>
5300
5301 <para>gtk_combo_set_use_arrows_always() similarly allows the use the
5302 the up/down arrow keys to cycle through the choices in the dropdown
5303 list, except that it wraps around the values in the list, completely
5304 disabling the use of the up and down arrow keys for changing focus.</para>
5305
5306 <para>gtk_combo_set_case_sensitive() toggles whether or not GTK
5307 searches for entries in a case sensitive manner. This is used when the
5308 Combo widget is asked to find a value from the list using the current
5309 entry in the text box. This completion can be performed in either a
5310 case sensitive or insensitive manner, depending upon the use of this
5311 function. The Combo widget can also simply complete the current entry
5312 if the user presses the key combination MOD-1 and "Tab". MOD-1 is
5313 often mapped to the "Alt" key, by the <literal>xmodmap</literal> utility. Note,
5314 however that some window managers also use this key combination, which
5315 will override its use within GTK.</para>
5316
5317 <para>Now that we have a combo box, tailored to look and act how we want it,
5318 all that remains is being able to get data from the combo box. This is
5319 relatively straightforward. The majority of the time, all you are
5320 going to care about getting data from is the entry. The entry is
5321 accessed simply by <literal>GTK_ENTRY (GTK_COMBO (combo)->entry)</literal>. The
5322 two principal things that you are going to want to do with it are
5323 connect to the activate signal, which indicates that the user has
5324 pressed the Return or Enter key, and read the text. The first is
5325 accomplished using something like:</para>
5326
5327 <programlisting role="C">
5328     g_signal_connect (G_OBJECT (GTK_COMBO (combo)->entry), "activate",
5329                       G_CALLBACK (my_callback_function), (gpointer) my_data);
5330 </programlisting>
5331
5332 <para>Getting the text at any arbitrary time is accomplished by simply using
5333 the entry function:</para>
5334
5335 <programlisting role="C">
5336 gchar *gtk_entry_get_text( GtkEntry *entry );
5337 </programlisting>
5338
5339 <para>Such as:</para>
5340
5341 <programlisting role="C">
5342     gchar *string;
5343
5344     string = gtk_entry_get_text (GTK_ENTRY (GTK_COMBO (combo)->entry));
5345 </programlisting>
5346
5347 <para>That's about all there is to it. There is a function</para>
5348
5349 <programlisting role="C">
5350 void gtk_combo_disable_activate( GtkCombo *combo );
5351 </programlisting>
5352
5353 <para>that will disable the activate signal on the entry widget in the combo
5354 box. Personally, I can't think of why you'd want to use it, but it
5355 does exist.</para>
5356
5357 <!-- There is also a function to set the string on a particular item, void
5358 gtk_combo_set_item_string(GtkCombo *combo, GtkItem *item, const gchar
5359 *item_value), but this requires that you have a pointer to the
5360 appropriate Item. Frankly, I have no idea how to do that.
5361 -->
5362
5363 </sect1>
5364
5365 <!-- ----------------------------------------------------------------- -->
5366 <sect1 id="sec-Calendar">
5367 <title>Calendar</title>
5368
5369 <para>The Calendar widget is an effective way to display and retrieve
5370 monthly date related information. It is a very simple widget to create
5371 and work with.</para>
5372
5373 <para>Creating a GtkCalendar widget is a simple as: </para>
5374
5375 <programlisting role="C">
5376 GtkWidget *gtk_calendar_new( void );
5377 </programlisting>
5378
5379 <para>There might be times where you need to change a lot of information
5380 within this widget and the following functions allow you to make
5381 multiple change to a Calendar widget without the user seeing multiple
5382 on-screen updates.</para>
5383
5384 <programlisting role="C">
5385 void gtk_calendar_freeze( GtkCalendar *Calendar );
5386
5387 void gtk_calendar_thaw( GtkCalendar *Calendar );
5388 </programlisting>
5389
5390 <para>They work just like the freeze/thaw functions of every other
5391 widget.</para>
5392
5393 <para>The Calendar widget has a few options that allow you to change the way
5394 the widget both looks and operates by using the function</para>
5395
5396 <programlisting role="C">
5397 void gtk_calendar_display_options( GtkCalendar               *calendar,
5398                                    GtkCalendarDisplayOptions  flags );
5399 </programlisting>
5400
5401 <para>The <literal>flags</literal> argument can be formed by combining either of the
5402 following five options using the logical bitwise OR (|) operation:</para>
5403
5404 <variablelist>
5405 <varlistentry>
5406 <term><literal>GTK_CALENDAR_SHOW_HEADING</literal></term>
5407 <listitem><para>this option specifies that the month and year should be shown 
5408 when drawing the calendar.</para>
5409 </listitem>
5410 </varlistentry>
5411 <varlistentry>
5412 <term><literal>GTK_CALENDAR_SHOW_DAY_NAMES</literal></term>
5413 <listitem><para>this option specifies that the three letter descriptions should 
5414 be displayed for each day (eg Mon,Tue, etc.).</para>
5415 </listitem>
5416 </varlistentry>
5417 <varlistentry>
5418 <term><literal>GTK_CALENDAR_NO_MONTH_CHANGE</literal></term>
5419 <listitem><para>this option states that the user
5420 should not and can not change the currently displayed month. This can
5421 be good if you only need to display a particular month such as if you
5422 are displaying 12 calendar widgets for every month in a particular
5423 year.</para>
5424 </listitem>
5425 </varlistentry>
5426 <varlistentry>
5427 <term><literal>GTK_CALENDAR_SHOW_WEEK_NUMBERS</literal></term>
5428 <listitem><para>this option specifies that the
5429 number for each week should be displayed down the left side of the
5430 calendar. (eg. Jan 1 = Week 1,Dec 31 = Week 52).</para>
5431 </listitem>
5432 </varlistentry>
5433 <varlistentry>
5434 <term><literal>GTK_CALENDAR_WEEK_START_MONDAY</literal></term>
5435 <listitem><para>this option states that the
5436 calander week will start on Monday instead of Sunday which is the
5437 default. This only affects the order in which days are displayed from
5438 left to right.</para>
5439 </listitem>
5440 </varlistentry>
5441 </variablelist>
5442
5443 <para>The following functions are used to set the the currently displayed
5444 date:</para>
5445
5446 <programlisting role="C">
5447 gint gtk_calendar_select_month( GtkCalendar *calendar, 
5448                                 guint        month,
5449                                 guint        year );
5450
5451 void gtk_calendar_select_day( GtkCalendar *calendar,
5452                               guint        day );
5453 </programlisting>
5454
5455 <para>The return value from <literal>gtk_calendar_select_month()</literal> is a boolean
5456 value indicating whether the selection was successful.</para>
5457
5458 <para>With <literal>gtk_calendar_select_day()</literal> the specified day number is
5459 selected within the current month, if that is possible. A
5460 <literal>day</literal> value of 0 will deselect any current selection.</para>
5461
5462 <para>In addition to having a day selected, any number of days in the month
5463 may be "marked". A marked day is highlighted within the calendar
5464 display. The following functions are provided to manipulate marked
5465 days:</para>
5466
5467 <programlisting role="C">
5468 gint gtk_calendar_mark_day( GtkCalendar *calendar,
5469                             guint        day);
5470
5471 gint gtk_calendar_unmark_day( GtkCalendar *calendar,
5472                               guint        day);
5473
5474 void gtk_calendar_clear_marks( GtkCalendar *calendar);
5475 </programlisting>
5476
5477 <para>The currently marked days are stored within an array within the
5478 GtkCalendar structure. This array is 31 elements long so to test
5479 whether a particular day is currently marked, you need to access the
5480 corresponding element of the array (don't forget in C that array
5481 elements are numbered 0 to n-1). For example:</para>
5482
5483 <programlisting role="C">
5484     GtkCalendar *calendar;
5485     calendar = gtk_calendar_new ();
5486
5487     ...
5488
5489     /* Is day 7 marked? */
5490     if (calendar->marked_date[7-1])
5491        /* day is marked */
5492 </programlisting>
5493
5494 <para>Note that marks are persistent across month and year changes.</para>
5495
5496 <para>The final Calendar widget function is used to retrieve the currently
5497 selected date, month and/or year.</para>
5498
5499 <programlisting role="C">
5500 void gtk_calendar_get_date( GtkCalendar *calendar, 
5501                             guint       *year,
5502                             guint       *month,
5503                             guint       *day );
5504 </programlisting>
5505
5506 <para>This function requires you to pass the addresses of <literal>guint</literal>
5507 variables, into which the result will be placed. Passing <literal>NULL</literal> as
5508 a value will result in the corresponding value not being returned.</para>
5509
5510 <para>The Calendar widget can generate a number of signals indicating date
5511 selection and change. The names of these signals are self explanatory,
5512 and are:</para>
5513
5514 <itemizedlist>
5515 <listitem><simpara> <literal>month_changed</literal></simpara>
5516 </listitem>
5517 <listitem><simpara> <literal>day_selected</literal></simpara>
5518 </listitem>
5519 <listitem><simpara> <literal>day_selected_double_click</literal></simpara>
5520 </listitem>
5521 <listitem><simpara> <literal>prev_month</literal></simpara>
5522 </listitem>
5523 <listitem><simpara> <literal>next_month</literal></simpara>
5524 </listitem>
5525 <listitem><simpara> <literal>prev_year</literal></simpara>
5526 </listitem>
5527 <listitem><simpara> <literal>next_year</literal></simpara>
5528 </listitem>
5529 </itemizedlist>
5530
5531 <para>That just leaves us with the need to put all of this together into
5532 example code.</para>
5533
5534 <para>
5535 <inlinemediaobject>
5536 <imageobject>
5537 <imagedata fileref="images/calendar.png" format="png">
5538 </imageobject>
5539 </inlinemediaobject>
5540 </para>
5541
5542 <programlisting role="C">
5543 <!-- example-start calendar calendar.c -->
5544 /*
5545  * Copyright (C) 1998 Cesar Miquel, Shawn T. Amundson, Mattias Grönlund
5546  * Copyright (C) 2000 Tony Gale
5547  *
5548  * This program is free software; you can redistribute it and/or modify
5549  * it under the terms of the GNU General Public License as published by
5550  * the Free Software Foundation; either version 2 of the License, or
5551  * (at your option) any later version.
5552  *
5553  * This program is distributed in the hope that it will be useful,
5554  * but WITHOUT ANY WARRANTY; without even the implied warranty of
5555  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
5556  * GNU General Public License for more details.
5557  *
5558  * You should have received a copy of the GNU General Public License
5559  * along with this program; if not, write to the Free Software
5560  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
5561  */
5562
5563 #include &lt;stdio.h&gt;
5564 #include &lt;string.h&gt;
5565 #include &lt;gtk/gtk.h&gt;
5566
5567 #define DEF_PAD 10
5568 #define DEF_PAD_SMALL 5
5569
5570 #define TM_YEAR_BASE 1900
5571
5572 typedef struct _CalendarData {
5573   GtkWidget *flag_checkboxes[5];
5574   gboolean  settings[5];
5575   GtkWidget *font_dialog;
5576   GtkWidget *window;
5577   GtkWidget *prev2_sig;
5578   GtkWidget *prev_sig;
5579   GtkWidget *last_sig;
5580   GtkWidget *month;
5581 } CalendarData;
5582
5583 enum {
5584   calendar_show_header,
5585   calendar_show_days,
5586   calendar_month_change, 
5587   calendar_show_week,
5588   calendar_monday_first
5589 };
5590
5591 /*
5592  * GtkCalendar
5593  */
5594
5595 void calendar_date_to_string (CalendarData *data,
5596                               char         *buffer,
5597                               gint          buff_len)
5598 {
5599   GDate *date;
5600   guint year, month, day;
5601
5602   gtk_calendar_get_date (GTK_CALENDAR (data-&gt;window),
5603                          &amp;year, &amp;month, &amp;day);
5604   date = g_date_new_dmy (day, month + 1, year);
5605   g_date_strftime (buffer, buff_len - 1, "%x", date);
5606
5607   g_date_free (date);
5608 }
5609
5610 void calendar_set_signal_strings (char         *sig_str,
5611                                   CalendarData *data)
5612 {
5613   const gchar *prev_sig;
5614
5615   prev_sig = gtk_label_get_text (GTK_LABEL (data-&gt;prev_sig));
5616   gtk_label_set_text (GTK_LABEL (data-&gt;prev2_sig), prev_sig);
5617
5618   prev_sig = gtk_label_get_text (GTK_LABEL (data-&gt;last_sig));
5619   gtk_label_set_text (GTK_LABEL (data-&gt;prev_sig), prev_sig);
5620   gtk_label_set_text (GTK_LABEL (data-&gt;last_sig), sig_str);
5621 }
5622
5623 void calendar_month_changed (GtkWidget    *widget,
5624                              CalendarData *data)
5625 {
5626   char buffer[256] = "month_changed: ";
5627
5628   calendar_date_to_string (data, buffer + 15, 256 - 15);
5629   calendar_set_signal_strings (buffer, data);
5630 }
5631
5632 void calendar_day_selected (GtkWidget    *widget,
5633                             CalendarData *data)
5634 {
5635   char buffer[256] = "day_selected: ";
5636
5637   calendar_date_to_string (data, buffer + 14, 256 - 14);
5638   calendar_set_signal_strings (buffer, data);
5639 }
5640
5641 void calendar_day_selected_double_click (GtkWidget    *widget,
5642                                          CalendarData *data)
5643 {
5644   char buffer[256] = "day_selected_double_click: ";
5645   guint day;
5646
5647   calendar_date_to_string (data, buffer + 27, 256 - 27);
5648   calendar_set_signal_strings (buffer, data);
5649
5650   gtk_calendar_get_date (GTK_CALENDAR (data-&gt;window),
5651                          NULL, NULL, &amp;day);
5652
5653   if (GTK_CALENDAR (data-&gt;window)-&gt;marked_date[day-1] == 0) {
5654     gtk_calendar_mark_day (GTK_CALENDAR (data-&gt;window), day);
5655   } else { 
5656     gtk_calendar_unmark_day (GTK_CALENDAR (data-&gt;window), day);
5657   }
5658 }
5659
5660 void calendar_prev_month (GtkWidget    *widget,
5661                           CalendarData *data)
5662 {
5663   char buffer[256] = "prev_month: ";
5664
5665   calendar_date_to_string (data, buffer + 12, 256 - 12);
5666   calendar_set_signal_strings (buffer, data);
5667 }
5668
5669 void calendar_next_month (GtkWidget    *widget,
5670                           CalendarData *data)
5671 {
5672   char buffer[256] = "next_month: ";
5673
5674   calendar_date_to_string (data, buffer + 12, 256 - 12);
5675   calendar_set_signal_strings (buffer, data);
5676 }
5677
5678 void calendar_prev_year (GtkWidget    *widget,
5679                          CalendarData *data)
5680 {
5681   char buffer[256] = "prev_year: ";
5682
5683   calendar_date_to_string (data, buffer + 11, 256 - 11);
5684   calendar_set_signal_strings (buffer, data);
5685 }
5686
5687 void calendar_next_year (GtkWidget    *widget,
5688                          CalendarData *data)
5689 {
5690   char buffer[256] = "next_year: ";
5691
5692   calendar_date_to_string (data, buffer + 11, 256 - 11);
5693   calendar_set_signal_strings (buffer, data);
5694 }
5695
5696
5697 void calendar_set_flags (CalendarData *calendar)
5698 {
5699   gint i;
5700   gint options = 0;
5701   for (i = 0;i &lt; 5; i++) 
5702     if (calendar-&gt;settings[i])
5703       {
5704         options = options + (1 &lt;&lt; i);
5705       }
5706   if (calendar-&gt;window)
5707     gtk_calendar_display_options (GTK_CALENDAR (calendar-&gt;window), options);
5708 }
5709
5710 void calendar_toggle_flag (GtkWidget    *toggle,
5711                            CalendarData *calendar)
5712 {
5713   gint i;
5714   gint j;
5715   j = 0;
5716   for (i = 0; i &lt; 5; i++)
5717     if (calendar-&gt;flag_checkboxes[i] == toggle)
5718       j = i;
5719
5720   calendar-&gt;settings[j] = !calendar-&gt;settings[j];
5721   calendar_set_flags (calendar);
5722   
5723 }
5724
5725 void calendar_font_selection_ok (GtkWidget    *button,
5726                                  CalendarData *calendar)
5727 {
5728   GtkRcStyle *style;
5729   char *font_name;
5730
5731   if (calendar-&gt;window)
5732     {
5733       font_name = gtk_font_selection_dialog_get_font_name (GTK_FONT_SELECTION_DIALOG (calendar-&gt;font_dialog));
5734       if (font_name) 
5735         {
5736           style = gtk_rc_style_new ();
5737           pango_font_description_free (style-&gt;font_desc);
5738           style-&gt;font_desc = pango_font_description_from_string (font_name);
5739           gtk_widget_modify_style (calendar-&gt;window, style);
5740           g_free (font_name);
5741         }
5742     }
5743
5744   gtk_widget_destroy (calendar-&gt;font_dialog);
5745 }
5746
5747 void calendar_select_font (GtkWidget    *button,
5748                            CalendarData *calendar)
5749 {
5750   GtkWidget *window;
5751
5752   if (!calendar-&gt;font_dialog) {
5753     window = gtk_font_selection_dialog_new ("Font Selection Dialog");
5754     g_return_if_fail (GTK_IS_FONT_SELECTION_DIALOG (window));
5755     calendar-&gt;font_dialog = window;
5756     
5757     gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_MOUSE);
5758     
5759     g_signal_connect (window, "destroy",
5760                       G_CALLBACK (gtk_widget_destroyed),
5761                       &amp;calendar-&gt;font_dialog);
5762     
5763     g_signal_connect (GTK_FONT_SELECTION_DIALOG (window)-&gt;ok_button,
5764                       "clicked", G_CALLBACK (calendar_font_selection_ok),
5765                       calendar);
5766     g_signal_connect_swapped (GTK_FONT_SELECTION_DIALOG (window)-&gt;cancel_button,
5767                              "clicked", G_CALLBACK (gtk_widget_destroy), 
5768                              calendar-&gt;font_dialog);
5769   }
5770   window = calendar-&gt;font_dialog;
5771   if (!GTK_WIDGET_VISIBLE (window))
5772     gtk_widget_show (window);
5773   else
5774     gtk_widget_destroy (window);
5775
5776 }
5777
5778 void create_calendar ()
5779 {
5780   GtkWidget *window;
5781   GtkWidget *vbox, *vbox2, *vbox3;
5782   GtkWidget *hbox;
5783   GtkWidget *hbbox;
5784   GtkWidget *calendar;
5785   GtkWidget *toggle;
5786   GtkWidget *button;
5787   GtkWidget *frame;
5788   GtkWidget *separator;
5789   GtkWidget *label;
5790   GtkWidget *bbox;
5791   static CalendarData calendar_data;
5792   gint i;
5793   
5794   struct {
5795     char *label;
5796   } flags[] =
5797     {
5798       { "Show Heading" },
5799       { "Show Day Names" },
5800       { "No Month Change" },
5801       { "Show Week Numbers" },
5802       { "Week Start Monday" }
5803     };
5804
5805   
5806   calendar_data.window = NULL;
5807   calendar_data.font_dialog = NULL;
5808
5809   for (i = 0; i &lt; 5; i++) {
5810     calendar_data.settings[i] = 0;
5811   }
5812
5813   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
5814   gtk_window_set_title (GTK_WINDOW (window), "GtkCalendar Example");
5815   gtk_container_set_border_width (GTK_CONTAINER (window), 5);
5816   g_signal_connect (window, "destroy",
5817                     G_CALLBACK (gtk_main_quit),
5818                     NULL);
5819   g_signal_connect (window, "delete-event",
5820                     G_CALLBACK (gtk_false),
5821                     NULL);
5822   gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
5823
5824   vbox = gtk_vbox_new (FALSE, DEF_PAD);
5825   gtk_container_add (GTK_CONTAINER (window), vbox);
5826
5827   /*
5828    * The top part of the window, Calendar, flags and fontsel.
5829    */
5830
5831   hbox = gtk_hbox_new (FALSE, DEF_PAD);
5832   gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, DEF_PAD);
5833   hbbox = gtk_hbutton_box_new ();
5834   gtk_box_pack_start (GTK_BOX (hbox), hbbox, FALSE, FALSE, DEF_PAD);
5835   gtk_button_box_set_layout (GTK_BUTTON_BOX (hbbox), GTK_BUTTONBOX_SPREAD);
5836   gtk_box_set_spacing (GTK_BOX (hbbox), 5);
5837
5838   /* Calendar widget */
5839   frame = gtk_frame_new ("Calendar");
5840   gtk_box_pack_start(GTK_BOX (hbbox), frame, FALSE, TRUE, DEF_PAD);
5841   calendar=gtk_calendar_new ();
5842   calendar_data.window = calendar;
5843   calendar_set_flags (&amp;calendar_data);
5844   gtk_calendar_mark_day (GTK_CALENDAR (calendar), 19);  
5845   gtk_container_add (GTK_CONTAINER (frame), calendar);
5846   g_signal_connect (calendar, "month_changed", 
5847                     G_CALLBACK (calendar_month_changed),
5848                     &amp;calendar_data);
5849   g_signal_connect (calendar, "day_selected", 
5850                     G_CALLBACK (calendar_day_selected),
5851                     &amp;calendar_data);
5852   g_signal_connect (calendar, "day_selected_double_click", 
5853                     G_CALLBACK (calendar_day_selected_double_click),
5854                     &amp;calendar_data);
5855   g_signal_connect (calendar, "prev_month", 
5856                     G_CALLBACK (calendar_prev_month),
5857                     &amp;calendar_data);
5858   g_signal_connect (calendar, "next_month", 
5859                     G_CALLBACK (calendar_next_month),
5860                     &amp;calendar_data);
5861   g_signal_connect (calendar, "prev_year", 
5862                     G_CALLBACK (calendar_prev_year),
5863                     &amp;calendar_data);
5864   g_signal_connect (calendar, "next_year", 
5865                     G_CALLBACK (calendar_next_year),
5866                     &amp;calendar_data);
5867
5868
5869   separator = gtk_vseparator_new ();
5870   gtk_box_pack_start (GTK_BOX (hbox), separator, FALSE, TRUE, 0);
5871
5872   vbox2 = gtk_vbox_new (FALSE, DEF_PAD);
5873   gtk_box_pack_start (GTK_BOX (hbox), vbox2, FALSE, FALSE, DEF_PAD);
5874   
5875   /* Build the Right frame with the flags in */ 
5876
5877   frame = gtk_frame_new ("Flags");
5878   gtk_box_pack_start (GTK_BOX (vbox2), frame, TRUE, TRUE, DEF_PAD);
5879   vbox3 = gtk_vbox_new (TRUE, DEF_PAD_SMALL);
5880   gtk_container_add (GTK_CONTAINER (frame), vbox3);
5881
5882   for (i = 0; i &lt; 5; i++)
5883     {
5884       toggle = gtk_check_button_new_with_label (flags[i].label);
5885       g_signal_connect (toggle,
5886                         "toggled",
5887                         G_CALLBACK (calendar_toggle_flag),
5888                         &amp;calendar_data);
5889       gtk_box_pack_start (GTK_BOX (vbox3), toggle, TRUE, TRUE, 0);
5890       calendar_data.flag_checkboxes[i] = toggle;
5891     }
5892   /* Build the right font-button */ 
5893   button = gtk_button_new_with_label ("Font...");
5894   g_signal_connect (button,
5895                     "clicked",
5896                     G_CALLBACK (calendar_select_font),
5897                     &amp;calendar_data);
5898   gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0);
5899
5900   /*
5901    *  Build the Signal-event part.
5902    */
5903
5904   frame = gtk_frame_new ("Signal events");
5905   gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, DEF_PAD);
5906
5907   vbox2 = gtk_vbox_new (TRUE, DEF_PAD_SMALL);
5908   gtk_container_add (GTK_CONTAINER (frame), vbox2);
5909   
5910   hbox = gtk_hbox_new (FALSE, 3);
5911   gtk_box_pack_start (GTK_BOX (vbox2), hbox, FALSE, TRUE, 0);
5912   label = gtk_label_new ("Signal:");
5913   gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
5914   calendar_data.last_sig = gtk_label_new ("");
5915   gtk_box_pack_start (GTK_BOX (hbox), calendar_data.last_sig, FALSE, TRUE, 0);
5916
5917   hbox = gtk_hbox_new (FALSE, 3);
5918   gtk_box_pack_start (GTK_BOX (vbox2), hbox, FALSE, TRUE, 0);
5919   label = gtk_label_new ("Previous signal:");
5920   gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
5921   calendar_data.prev_sig = gtk_label_new ("");
5922   gtk_box_pack_start (GTK_BOX (hbox), calendar_data.prev_sig, FALSE, TRUE, 0);
5923
5924   hbox = gtk_hbox_new (FALSE, 3);
5925   gtk_box_pack_start (GTK_BOX (vbox2), hbox, FALSE, TRUE, 0);
5926   label = gtk_label_new ("Second previous signal:");
5927   gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
5928   calendar_data.prev2_sig = gtk_label_new ("");
5929   gtk_box_pack_start (GTK_BOX (hbox), calendar_data.prev2_sig, FALSE, TRUE, 0);
5930
5931   bbox = gtk_hbutton_box_new ();
5932   gtk_box_pack_start (GTK_BOX (vbox), bbox, FALSE, FALSE, 0);
5933   gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END);
5934
5935   button = gtk_button_new_with_label ("Close");
5936   g_signal_connect (button, "clicked", 
5937                     G_CALLBACK (gtk_main_quit), 
5938                     NULL);
5939   gtk_container_add (GTK_CONTAINER (bbox), button);
5940   GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
5941   gtk_widget_grab_default (button);
5942
5943   gtk_widget_show_all (window);
5944 }
5945
5946
5947 int main (int   argc,
5948           char *argv[])
5949 {
5950   gtk_init (&amp;argc, &amp;argv);
5951
5952   create_calendar ();
5953
5954   gtk_main ();
5955
5956   return 0;
5957 }
5958 <!-- example-end -->
5959 </programlisting>
5960
5961 </sect1>
5962
5963 <!-- ----------------------------------------------------------------- -->
5964 <sect1 id="sec-ColorSelection">
5965 <title>Color Selection</title>
5966
5967 <para>The color selection widget is, not surprisingly, a widget for
5968 interactive selection of colors. This composite widget lets the user
5969 select a color by manipulating RGB (Red, Green, Blue) and HSV (Hue,
5970 Saturation, Value) triples.  This is done either by adjusting single
5971 values with sliders or entries, or by picking the desired color from a
5972 hue-saturation wheel/value bar.  Optionally, the opacity of the color
5973 can also be set.</para>
5974
5975 <para>The color selection widget currently emits only one signal,
5976 "color_changed", which is emitted whenever the current color in the
5977 widget changes, either when the user changes it or if it's set
5978 explicitly through gtk_color_selection_set_color().</para>
5979
5980 <para>Lets have a look at what the color selection widget has to offer
5981 us. The widget comes in two flavours: GtkColorSelection and
5982 GtkColorSelectionDialog.</para>
5983
5984 <programlisting role="C">
5985 GtkWidget *gtk_color_selection_new( void );
5986 </programlisting>
5987         
5988 <para>You'll probably not be using this constructor directly. It creates an
5989 orphan ColorSelection widget which you'll have to parent
5990 yourself. The ColorSelection widget inherits from the VBox
5991 widget.</para>
5992
5993 <programlisting role="C">
5994 GtkWidget *gtk_color_selection_dialog_new( const gchar *title );
5995 </programlisting>
5996
5997 <para>This is the most common color selection constructor. It creates a
5998 ColorSelectionDialog. It consists of a Frame containing a
5999 ColorSelection widget, an HSeparator and an HBox with three buttons,
6000 "Ok", "Cancel" and "Help". You can reach these buttons by accessing
6001 the "ok_button", "cancel_button" and "help_button" widgets in the
6002 ColorSelectionDialog structure,
6003 (i.e., <literal>GTK_COLOR_SELECTION_DIALOG (colorseldialog)->ok_button</literal>)).</para>
6004
6005 <programlisting role="C">
6006 void gtk_color_selection_set_has_opacity_control( GtkColorSelection *colorsel,
6007                                                   gboolean           has_opacity );
6008 </programlisting>
6009
6010 <para>The color selection widget supports adjusting the opacity of a color
6011 (also known as the alpha channel). This is disabled by
6012 default. Calling this function with has_opacity set to TRUE enables
6013 opacity. Likewise, has_opacity set to FALSE will disable opacity.</para>
6014
6015 <programlisting role="C">
6016 void gtk_color_selection_set_current_color( GtkColorSelection *colorsel,
6017                                             GdkColor          *color );
6018
6019 void gtk_color_selection_set_current_alpha( GtkColorSelection *colorsel,
6020                                             guint16            alpha );
6021 </programlisting>
6022
6023 <para>You can set the current color explicitly by calling 
6024 gtk_color_selection_set_current_color() with a pointer to a GdkColor. 
6025 Setting the opacity (alpha channel) is done with 
6026 gtk_color_selection_set_current_alpha(). The alpha value should be between
6027 0 (fully transparent) and 65636 (fully opaque).
6028 </para>
6029
6030 <programlisting role="C">
6031 void gtk_color_selection_get_current_color( GtkColorSelection *colorsel,
6032                                             GdkColor *color );
6033
6034 void gtk_color_selection_get_current_alpha( GtkColorSelection *colorsel,
6035                                             guint16           *alpha );
6036 </programlisting>
6037
6038 <para>When you need to query the current color, typically when you've
6039 received a "color_changed" signal, you use these functions.</para>
6040
6041 <para><!-- Need to do a whole section on DnD - TRG
6042 Drag and drop
6043 -------------</para>
6044
6045 <para>The color sample areas (right under the hue-saturation wheel) supports
6046 drag and drop. The type of drag and drop is "application/x-color". The
6047 message data consists of an array of 4 (or 5 if opacity is enabled)
6048 gdouble values, where the value at position 0 is 0.0 (opacity on) or
6049 1.0 (opacity off) followed by the red, green and blue values at
6050 positions 1,2 and 3 respectively.  If opacity is enabled, the opacity
6051 is passed in the value at position 4.
6052 --></para>
6053
6054 <para>Here's a simple example demonstrating the use of the
6055 ColorSelectionDialog. The program displays a window containing a
6056 drawing area. Clicking on it opens a color selection dialog, and
6057 changing the color in the color selection dialog changes the
6058 background color.</para>
6059
6060 <para>
6061 <inlinemediaobject>
6062 <imageobject>
6063 <imagedata fileref="images/colorsel.png" format="png">
6064 </imageobject>
6065 </inlinemediaobject>
6066 </para>
6067
6068 <programlisting role="C">
6069 <!-- example-start colorsel colorsel.c -->
6070
6071 #include &lt;glib.h&gt;
6072 #include &lt;gdk/gdk.h&gt;
6073 #include &lt;gtk/gtk.h&gt;
6074
6075 GtkWidget *colorseldlg = NULL;
6076 GtkWidget *drawingarea = NULL;
6077 GdkColor color;
6078
6079 /* Color changed handler */
6080
6081 void color_changed_cb( GtkWidget         *widget,
6082                        GtkColorSelection *colorsel )
6083 {
6084   GdkColor ncolor;
6085
6086   gtk_color_selection_get_current_color (colorsel, &amp;ncolor);
6087   gtk_widget_modify_bg (drawingarea, GTK_STATE_NORMAL, &amp;ncolor);       
6088 }
6089
6090 /* Drawingarea event handler */
6091
6092 gint area_event( GtkWidget *widget,
6093                  GdkEvent  *event,
6094                  gpointer   client_data )
6095 {
6096   gint handled = FALSE;
6097   gint response;
6098   GtkColorSelection *colorsel;
6099
6100   /* Check if we've received a button pressed event */
6101
6102   if (event-&gt;type == GDK_BUTTON_PRESS)
6103     {
6104       handled = TRUE;
6105
6106        /* Create color selection dialog */
6107       if (colorseldlg == NULL)
6108         colorseldlg = gtk_color_selection_dialog_new ("Select background color");
6109
6110       /* Get the ColorSelection widget */
6111       colorsel = GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (colorseldlg)-&gt;colorsel);
6112
6113       gtk_color_selection_set_previous_color (colorsel, &amp;color);
6114       gtk_color_selection_set_current_color (colorsel, &amp;color);
6115       gtk_color_selection_set_has_palette (colorsel, TRUE);
6116
6117       /* Connect to the "color_changed" signal, set the client-data
6118        * to the colorsel widget */
6119       g_signal_connect (G_OBJECT (colorsel), "color_changed",
6120                         G_CALLBACK (color_changed_cb), (gpointer) colorsel);
6121
6122       /* Show the dialog */
6123       response = gtk_dialog_run (GTK_DIALOG (colorseldlg));
6124
6125       if (response == GTK_RESPONSE_OK)
6126         gtk_color_selection_get_current_color (colorsel, &amp;color);
6127       else 
6128         gtk_widget_modify_bg (drawingarea, GTK_STATE_NORMAL, &amp;color);
6129
6130       gtk_widget_hide (colorseldlg);
6131     }
6132
6133   return handled;
6134 }
6135
6136 /* Close down and exit handler */
6137
6138 gint destroy_window( GtkWidget *widget,
6139                      GdkEvent  *event,
6140                      gpointer   client_data )
6141 {
6142   gtk_main_quit ();
6143   return TRUE;
6144 }
6145
6146 /* Main */
6147
6148 gint main( gint   argc,
6149            gchar *argv[] )
6150 {
6151   GtkWidget *window;
6152
6153   /* Initialize the toolkit, remove gtk-related commandline stuff */
6154
6155   gtk_init (&amp;argc, &amp;argv);
6156
6157   /* Create toplevel window, set title and policies */
6158
6159   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6160   gtk_window_set_title (GTK_WINDOW (window), "Color selection test");
6161   gtk_window_set_policy (GTK_WINDOW (window), TRUE, TRUE, TRUE);
6162
6163   /* Attach to the "delete" and "destroy" events so we can exit */
6164
6165   g_signal_connect (GTK_OBJECT (window), "delete_event",
6166                     GTK_SIGNAL_FUNC (destroy_window), (gpointer) window);
6167   
6168   /* Create drawingarea, set size and catch button events */
6169
6170   drawingarea = gtk_drawing_area_new ();
6171
6172   color.red = 0;
6173   color.blue = 65535;
6174   color.green = 0;
6175   gtk_widget_modify_bg (drawingarea, GTK_STATE_NORMAL, &amp;color);       
6176
6177   gtk_widget_set_size_request (GTK_WIDGET (drawingarea), 200, 200);
6178
6179   gtk_widget_set_events (drawingarea, GDK_BUTTON_PRESS_MASK);
6180
6181   g_signal_connect (GTK_OBJECT (drawingarea), "event", 
6182                     GTK_SIGNAL_FUNC (area_event), (gpointer) drawingarea);
6183   
6184   /* Add drawingarea to window, then show them both */
6185
6186   gtk_container_add (GTK_CONTAINER (window), drawingarea);
6187
6188   gtk_widget_show (drawingarea);
6189   gtk_widget_show (window);
6190   
6191   /* Enter the gtk main loop (this never returns) */
6192
6193   gtk_main ();
6194
6195   /* Satisfy grumpy compilers */
6196
6197   return 0;
6198 }
6199 <!-- example-end -->
6200 </programlisting>
6201
6202 </sect1>
6203
6204 <!-- ----------------------------------------------------------------- -->
6205 <sect1 id="sec-FileSelections">
6206 <title>File Selections</title>
6207
6208 <para>The file selection widget is a quick and simple way to display a File
6209 dialog box. It comes complete with Ok, Cancel, and Help buttons, a
6210 great way to cut down on programming time.</para>
6211
6212 <para>To create a new file selection box use:</para>
6213
6214 <programlisting role="C">
6215 GtkWidget *gtk_file_selection_new( const gchar *title );
6216 </programlisting>
6217
6218 <para>To set the filename, for example to bring up a specific directory, or
6219 give a default filename, use this function:</para>
6220
6221 <programlisting role="C">
6222 void gtk_file_selection_set_filename( GtkFileSelection *filesel,
6223                                       const gchar      *filename );
6224 </programlisting>
6225
6226 <para>To grab the text that the user has entered or clicked on, use this 
6227 function:</para>
6228
6229 <programlisting role="C">
6230 gchar *gtk_file_selection_get_filename( GtkFileSelection *filesel );
6231 </programlisting>
6232
6233 <para>There are also pointers to the widgets contained within the file 
6234 selection widget. These are:</para>
6235
6236 <programlisting role="C">
6237   dir_list
6238   file_list
6239   selection_entry
6240   selection_text
6241   main_vbox
6242   ok_button
6243   cancel_button
6244   help_button
6245 </programlisting>
6246  
6247 <para>Most likely you will want to use the ok_button, cancel_button, and
6248 help_button pointers in signaling their use.</para>
6249
6250 <para>Included here is an example stolen from <filename>testgtk.c</filename>,
6251 modified to run on its own. As you will see, there is nothing much to creating a file
6252 selection widget. While in this example the Help button appears on the
6253 screen, it does nothing as there is not a signal attached to it.</para>
6254
6255 <para>
6256 <inlinemediaobject>
6257 <imageobject>
6258 <imagedata fileref="images/filesel.png" format="png">
6259 </imageobject>
6260 </inlinemediaobject>
6261 </para>
6262
6263 <programlisting role="C">
6264 <!-- example-start filesel filesel.c -->
6265
6266 #include &lt;gtk/gtk.h&gt;
6267
6268 /* Get the selected filename and print it to the console */
6269 void file_ok_sel( GtkWidget        *w,
6270                   GtkFileSelection *fs )
6271 {
6272     g_print ("%s\n", gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs)));
6273 }
6274
6275 int main( int   argc,
6276           char *argv[] )
6277 {
6278     GtkWidget *filew;
6279     
6280     gtk_init (&amp;argc, &amp;argv);
6281     
6282     /* Create a new file selection widget */
6283     filew = gtk_file_selection_new ("File selection");
6284     
6285     g_signal_connect (G_OBJECT (filew), "destroy",
6286                       G_CALLBACK (gtk_main_quit), NULL);
6287     /* Connect the ok_button to file_ok_sel function */
6288     g_signal_connect (G_OBJECT (GTK_FILE_SELECTION (filew)-&gt;ok_button),
6289                       "clicked", G_CALLBACK (file_ok_sel), (gpointer) filew);
6290     
6291     /* Connect the cancel_button to destroy the widget */
6292     g_signal_connect_swapped (G_OBJECT (GTK_FILE_SELECTION (filew)-&gt;cancel_button),
6293                               "clicked", G_CALLBACK (gtk_widget_destroy),
6294                               G_OBJECT (filew));
6295     
6296     /* Lets set the filename, as if this were a save dialog, and we are giving
6297      a default filename */
6298     gtk_file_selection_set_filename (GTK_FILE_SELECTION(filew), 
6299                                      "penguin.png");
6300     
6301     gtk_widget_show (filew);
6302     gtk_main ();
6303     return 0;
6304 }
6305 <!-- example-end -->
6306 </programlisting>
6307
6308 </sect1>
6309 </chapter>
6310
6311 <!-- ***************************************************************** -->
6312 <chapter id="ch-ContainerWidgets">
6313 <title>Container Widgets</title>
6314
6315 <!-- ----------------------------------------------------------------- -->   
6316 <sect1 id="sec-EventBox">
6317 <title>The EventBox</title>
6318
6319 <para>Some GTK widgets don't have associated X windows, so they just draw on
6320 their parents. Because of this, they cannot receive events and if they
6321 are incorrectly sized, they don't clip so you can get messy
6322 overwriting, etc. If you require more from these widgets, the EventBox
6323 is for you.</para>
6324
6325 <para>At first glance, the EventBox widget might appear to be totally
6326 useless. It draws nothing on the screen and responds to no
6327 events. However, it does serve a function - it provides an X window
6328 for its child widget. This is important as many GTK widgets do not
6329 have an associated X window. Not having an X window saves memory and
6330 improves performance, but also has some drawbacks. A widget without an
6331 X window cannot receive events, and does not perform any clipping on
6332 its contents. Although the name <emphasis>EventBox</emphasis> emphasizes the
6333 event-handling function, the widget can also be used for clipping.
6334 (and more, see the example below).</para>
6335
6336 <para>To create a new EventBox widget, use:</para>
6337
6338 <programlisting role="C">
6339 GtkWidget *gtk_event_box_new( void );
6340 </programlisting>
6341
6342 <para>A child widget can then be added to this EventBox:</para>
6343
6344 <programlisting role="C">
6345     gtk_container_add (GTK_CONTAINER (event_box), child_widget);
6346 </programlisting>
6347
6348 <para>The following example demonstrates both uses of an EventBox - a label
6349 is created that is clipped to a small box, and set up so that a
6350 mouse-click on the label causes the program to exit. Resizing the
6351 window reveals varying amounts of the label.</para>
6352
6353 <para>
6354 <inlinemediaobject>
6355 <imageobject>
6356 <imagedata fileref="images/eventbox.png" format="png">
6357 </imageobject>
6358 </inlinemediaobject>
6359 </para>
6360
6361 <programlisting role="C">
6362 <!-- example-start eventbox eventbox.c -->
6363
6364 #include &lt;stdlib.h&gt;
6365 #include &lt;gtk/gtk.h&gt;
6366
6367 int main( int argc,
6368           char *argv[] )
6369 {
6370     GtkWidget *window;
6371     GtkWidget *event_box;
6372     GtkWidget *label;
6373     
6374     gtk_init (&amp;argc, &amp;argv);
6375     
6376     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6377     
6378     gtk_window_set_title (GTK_WINDOW (window), "Event Box");
6379     
6380     g_signal_connect (G_OBJECT (window), "destroy",
6381                       G_CALLBACK (exit), NULL);
6382     
6383     gtk_container_set_border_width (GTK_CONTAINER (window), 10);
6384     
6385     /* Create an EventBox and add it to our toplevel window */
6386     
6387     event_box = gtk_event_box_new ();
6388     gtk_container_add (GTK_CONTAINER (window), event_box);
6389     gtk_widget_show (event_box);
6390     
6391     /* Create a long label */
6392     
6393     label = gtk_label_new ("Click here to quit, quit, quit, quit, quit");
6394     gtk_container_add (GTK_CONTAINER (event_box), label);
6395     gtk_widget_show (label);
6396     
6397     /* Clip it short. */
6398     gtk_widget_set_size_request (label, 110, 20);
6399     
6400     /* And bind an action to it */
6401     gtk_widget_set_events (event_box, GDK_BUTTON_PRESS_MASK);
6402     g_signal_connect (G_OBJECT (event_box), "button_press_event",
6403                       G_CALLBACK (exit), NULL);
6404     
6405     /* Yet one more thing you need an X window for ... */
6406     
6407     gtk_widget_realize (event_box);
6408     gdk_window_set_cursor (event_box-&gt;window, gdk_cursor_new (GDK_HAND1));
6409     
6410     gtk_widget_show (window);
6411     
6412     gtk_main ();
6413     
6414     return 0;
6415 }
6416 <!-- example-end -->
6417 </programlisting>
6418
6419 </sect1>
6420
6421 <!-- ----------------------------------------------------------------- -->   
6422 <sect1 id="sec-TheAlignmentWidget">
6423 <title>The Alignment widget</title>
6424
6425 <para>The alignment widget allows you to place a widget within its window at
6426 a position and size relative to the size of the Alignment widget
6427 itself. For example, it can be very useful for centering a widget
6428 within the window.</para>
6429
6430 <para>There are only two functions associated with the Alignment widget:</para>
6431
6432 <programlisting role="C">
6433 GtkWidget* gtk_alignment_new( gfloat xalign,
6434                               gfloat yalign,
6435                               gfloat xscale,
6436                               gfloat yscale );
6437
6438 void gtk_alignment_set( GtkAlignment *alignment,
6439                         gfloat        xalign,
6440                         gfloat        yalign,
6441                         gfloat        xscale,
6442                         gfloat        yscale );
6443 </programlisting>
6444
6445 <para>The first function creates a new Alignment widget with the specified
6446 parameters. The second function allows the alignment parameters of an
6447 exisiting Alignment widget to be altered.</para>
6448
6449 <para>All four alignment parameters are floating point numbers which can
6450 range from 0.0 to 1.0. The <literal>xalign</literal> and <literal>yalign</literal> arguments
6451 affect the position of the widget placed within the Alignment
6452 widget. The <literal>xscale</literal> and <literal>yscale</literal> arguments effect the amount of
6453 space allocated to the widget.</para>
6454
6455 <para>A child widget can be added to this Alignment widget using:</para>
6456
6457 <programlisting role="C">
6458     gtk_container_add (GTK_CONTAINER (alignment), child_widget);
6459 </programlisting>
6460
6461 <para>For an example of using an Alignment widget, refer to the example for
6462 the <link linkend="sec-ProgressBars">Progress Bar</link> widget.</para>
6463
6464 </sect1>
6465
6466 <!-- ----------------------------------------------------------------- -->
6467 <sect1 id="sec-FixedContainer">
6468 <title>Fixed Container</title>
6469
6470 <para>The Fixed container allows you to place widgets at a fixed position
6471 within it's window, relative to it's upper left hand corner. The
6472 position of the widgets can be changed dynamically.</para>
6473
6474 <para>There are only a few functions associated with the fixed widget:</para>
6475
6476 <programlisting role="C">
6477 GtkWidget* gtk_fixed_new( void );
6478
6479 void gtk_fixed_put( GtkFixed  *fixed,
6480                     GtkWidget *widget,
6481                     gint       x,
6482                     gint       y );
6483
6484 void gtk_fixed_move( GtkFixed  *fixed,
6485                      GtkWidget *widget,
6486                      gint       x,
6487                      gint       y );
6488 </programlisting>
6489
6490 <para>The function gtk_fixed_new() allows you to create a new Fixed
6491 container.</para>
6492
6493 <para>gtk_fixed_put() places <literal>widget</literal> in the container <literal>fixed</literal> at
6494 the position specified by <literal>x</literal> and <literal>y</literal>.</para>
6495
6496 <para>gtk_fixed_move() allows the specified widget to be moved to a new
6497 position.</para>
6498
6499 <programlisting role="C">
6500 void gtk_fixed_set_has_window( GtkFixed  *fixed,
6501                                gboolean   has_window );
6502
6503 gboolean gtk_fixed_get_has_window( GtkFixed *fixed );
6504 </programlisting>
6505
6506 <para>Normally, Fixed widgets don't have their own X window. Since this is
6507 different from the behaviour of Fixed widgets in earlier releases of GTK, 
6508 the function gtk_fixed_set_has_window() allows the creation of Fixed widgets 
6509 <emphasis>with</emphasis> their own window. It has to be called before
6510 realizing the widget.</para>
6511
6512 <para>The following example illustrates how to use the Fixed Container.</para>
6513
6514 <para>
6515 <inlinemediaobject>
6516 <imageobject>
6517 <imagedata fileref="images/fixed.png" format="png">
6518 </imageobject>
6519 </inlinemediaobject>
6520 </para>
6521
6522 <programlisting role="C">
6523 <!-- example-start fixed fixed.c -->
6524
6525 #include &lt;gtk/gtk.h&gt;
6526
6527 /* I'm going to be lazy and use some global variables to
6528  * store the position of the widget within the fixed
6529  * container */
6530 gint x = 50;
6531 gint y = 50;
6532
6533 /* This callback function moves the button to a new position
6534  * in the Fixed container. */
6535 void move_button( GtkWidget *widget,
6536                   GtkWidget *fixed )
6537 {
6538   x = (x + 30) % 300;
6539   y = (y + 50) % 300;
6540   gtk_fixed_move (GTK_FIXED (fixed), widget, x, y); 
6541 }
6542
6543 int main( int   argc,
6544           char *argv[] )
6545 {
6546   /* GtkWidget is the storage type for widgets */
6547   GtkWidget *window;
6548   GtkWidget *fixed;
6549   GtkWidget *button;
6550   gint i;
6551
6552   /* Initialise GTK */
6553   gtk_init (&amp;argc, &amp;argv);
6554     
6555   /* Create a new window */
6556   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6557   gtk_window_set_title (GTK_WINDOW (window), "Fixed Container");
6558
6559   /* Here we connect the "destroy" event to a signal handler */ 
6560   g_signal_connect (G_OBJECT (window), "destroy",
6561                     G_CALLBACK (gtk_main_quit), NULL);
6562  
6563   /* Sets the border width of the window. */
6564   gtk_container_set_border_width (GTK_CONTAINER (window), 10);
6565
6566   /* Create a Fixed Container */
6567   fixed = gtk_fixed_new ();
6568   gtk_container_add (GTK_CONTAINER (window), fixed);
6569   gtk_widget_show (fixed);
6570   
6571   for (i = 1 ; i &lt;= 3 ; i++) {
6572     /* Creates a new button with the label "Press me" */
6573     button = gtk_button_new_with_label ("Press me");
6574   
6575     /* When the button receives the "clicked" signal, it will call the
6576      * function move_button() passing it the Fixed Container as its
6577      * argument. */
6578     g_signal_connect (G_OBJECT (button), "clicked",
6579                       G_CALLBACK (move_button), (gpointer) fixed);
6580   
6581     /* This packs the button into the fixed containers window. */
6582     gtk_fixed_put (GTK_FIXED (fixed), button, i*50, i*50);
6583   
6584     /* The final step is to display this newly created widget. */
6585     gtk_widget_show (button);
6586   }
6587
6588   /* Display the window */
6589   gtk_widget_show (window);
6590     
6591   /* Enter the event loop */
6592   gtk_main ();
6593     
6594   return 0;
6595 }
6596 <!-- example-end -->
6597 </programlisting>
6598
6599 </sect1>
6600
6601 <!-- ----------------------------------------------------------------- -->
6602 <sect1 id="sec-LayoutContainer">
6603 <title>Layout Container</title>
6604
6605 <para>The Layout container is similar to the Fixed container except that it
6606 implements an infinite (where infinity is less than 2^32) scrolling
6607 area. The X window system has a limitation where windows can be at
6608 most 32767 pixels wide or tall. The Layout container gets around this
6609 limitation by doing some exotic stuff using window and bit gravities,
6610 so that you can have smooth scrolling even when you have many child
6611 widgets in your scrolling area.</para>
6612
6613 <para>A Layout container is created using:</para>
6614
6615 <programlisting role="C">
6616 GtkWidget *gtk_layout_new( GtkAdjustment *hadjustment,
6617                            GtkAdjustment *vadjustment );
6618 </programlisting>
6619
6620 <para>As you can see, you can optionally specify the Adjustment objects that
6621 the Layout widget will use for its scrolling.</para>
6622
6623 <para>You can add and move widgets in the Layout container using the
6624 following two functions:</para>
6625
6626 <programlisting role="C">
6627 void gtk_layout_put( GtkLayout *layout,
6628                      GtkWidget *widget,
6629                      gint       x,
6630                      gint       y );
6631
6632 void gtk_layout_move( GtkLayout *layout,
6633                       GtkWidget *widget,
6634                       gint       x,
6635                       gint       y );
6636 </programlisting>
6637
6638 <para>The size of the Layout container can be set using the next function:</para>
6639
6640 <programlisting role="C">
6641 void gtk_layout_set_size( GtkLayout *layout,
6642                           guint      width,
6643                           guint      height );
6644 </programlisting>
6645
6646 <para>The final four functions for use with Layout widgets are for
6647 manipulating the horizontal and vertical adjustment widgets:</para>
6648
6649 <programlisting role="C">
6650 GtkAdjustment* gtk_layout_get_hadjustment( GtkLayout *layout );
6651
6652 GtkAdjustment* gtk_layout_get_vadjustment( GtkLayout *layout );
6653
6654 void gtk_layout_set_hadjustment( GtkLayout     *layout,
6655                                  GtkAdjustment *adjustment );
6656
6657 void gtk_layout_set_vadjustment( GtkLayout     *layout,
6658                                  GtkAdjustment *adjustment);
6659 </programlisting>
6660
6661 </sect1>
6662
6663 <!-- ----------------------------------------------------------------- -->
6664 <sect1 id="sec-Frames">
6665 <title>Frames</title>
6666
6667 <para>Frames can be used to enclose one or a group of widgets with a box
6668 which can optionally be labelled. The position of the label and the
6669 style of the box can be altered to suit.</para>
6670
6671 <para>A Frame can be created with the following function:</para>
6672
6673 <programlisting role="C">
6674 GtkWidget *gtk_frame_new( const gchar *label );
6675 </programlisting>
6676
6677 <para>The label is by default placed in the upper left hand corner of the
6678 frame. A value of NULL for the <literal>label</literal> argument will result in no
6679 label being displayed. The text of the label can be changed using the
6680 next function.</para>
6681
6682 <programlisting role="C">
6683 void gtk_frame_set_label( GtkFrame    *frame,
6684                           const gchar *label );
6685 </programlisting>
6686
6687 <para>The position of the label can be changed using this function:</para>
6688
6689 <programlisting role="C">
6690 void gtk_frame_set_label_align( GtkFrame *frame,
6691                                 gfloat    xalign,
6692                                 gfloat    yalign );
6693 </programlisting>
6694
6695 <para><literal>xalign</literal> and <literal>yalign</literal> take values between 0.0 and 1.0. <literal>xalign</literal>
6696 indicates the position of the label along the top horizontal of the
6697 frame. <literal>yalign</literal> is not currently used. The default value of xalign
6698 is 0.0 which places the label at the left hand end of the frame.</para>
6699
6700 <para>The next function alters the style of the box that is used to outline
6701 the frame.</para>
6702
6703 <programlisting role="C">
6704 void gtk_frame_set_shadow_type( GtkFrame      *frame,
6705                                 GtkShadowType  type);
6706 </programlisting>
6707
6708 <para>The <literal>type</literal> argument can take one of the following values:</para>
6709 <programlisting role="C">
6710   GTK_SHADOW_NONE
6711   GTK_SHADOW_IN
6712   GTK_SHADOW_OUT
6713   GTK_SHADOW_ETCHED_IN (the default)
6714   GTK_SHADOW_ETCHED_OUT
6715 </programlisting>
6716
6717 <para>The following code example illustrates the use of the Frame widget.</para>
6718
6719 <para>
6720 <inlinemediaobject>
6721 <imageobject>
6722 <imagedata fileref="images/frame.png" format="png">
6723 </imageobject>
6724 </inlinemediaobject>
6725 </para>
6726
6727 <programlisting role="C">
6728 <!-- example-start frame frame.c -->
6729
6730 #include &lt;gtk/gtk.h&gt;
6731
6732 int main( int   argc,
6733           char *argv[] )
6734 {
6735   /* GtkWidget is the storage type for widgets */
6736   GtkWidget *window;
6737   GtkWidget *frame;
6738
6739   /* Initialise GTK */
6740   gtk_init (&amp;argc, &amp;argv);
6741     
6742   /* Create a new window */
6743   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6744   gtk_window_set_title (GTK_WINDOW (window), "Frame Example");
6745
6746   /* Here we connect the "destroy" event to a signal handler */ 
6747   g_signal_connect (G_OBJECT (window), "destroy",
6748                     G_CALLBACK (gtk_main_quit), NULL);
6749
6750   gtk_widget_set_size_request (window, 300, 300);
6751   /* Sets the border width of the window. */
6752   gtk_container_set_border_width (GTK_CONTAINER (window), 10);
6753
6754   /* Create a Frame */
6755   frame = gtk_frame_new (NULL);
6756   gtk_container_add (GTK_CONTAINER (window), frame);
6757
6758   /* Set the frame's label */
6759   gtk_frame_set_label (GTK_FRAME (frame), "GTK Frame Widget");
6760
6761   /* Align the label at the right of the frame */
6762   gtk_frame_set_label_align (GTK_FRAME (frame), 1.0, 0.0);
6763
6764   /* Set the style of the frame */
6765   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_OUT);
6766
6767   gtk_widget_show (frame);
6768   
6769   /* Display the window */
6770   gtk_widget_show (window);
6771     
6772   /* Enter the event loop */
6773   gtk_main ();
6774     
6775   return 0;
6776 }
6777 <!-- example-end -->
6778 </programlisting>
6779 </sect1>
6780
6781 <!-- ----------------------------------------------------------------- -->   
6782 <sect1 id="sec-AspectFrames">
6783 <title>Aspect Frames</title>
6784
6785 <para>The aspect frame widget is like a frame widget, except that it also
6786 enforces the aspect ratio (that is, the ratio of the width to the
6787 height) of the child widget to have a certain value, adding extra
6788 space if necessary. This is useful, for instance, if you want to
6789 preview a larger image. The size of the preview should vary when the
6790 user resizes the window, but the aspect ratio needs to always match
6791 the original image.</para>
6792   
6793 <para>To create a new aspect frame use:</para>
6794
6795 <programlisting role="C">
6796 GtkWidget *gtk_aspect_frame_new( const gchar *label,
6797                                  gfloat       xalign,
6798                                  gfloat       yalign,
6799                                  gfloat       ratio,
6800                                  gboolean     obey_child);
6801 </programlisting>
6802    
6803 <para><literal>xalign</literal> and <literal>yalign</literal> specify alignment as with Alignment
6804 widgets. If <literal>obey_child</literal> is TRUE, the aspect ratio of a child
6805 widget will match the aspect ratio of the ideal size it requests.
6806 Otherwise, it is given by <literal>ratio</literal>.</para>
6807    
6808 <para>To change the options of an existing aspect frame, you can use:</para>
6809
6810 <programlisting role="C">
6811 void gtk_aspect_frame_set( GtkAspectFrame *aspect_frame,
6812                            gfloat          xalign,
6813                            gfloat          yalign,
6814                            gfloat          ratio,
6815                            gboolean        obey_child);
6816 </programlisting>
6817    
6818 <para>As an example, the following program uses an AspectFrame to present a
6819 drawing area whose aspect ratio will always be 2:1, no matter how the
6820 user resizes the top-level window.</para>
6821
6822 <para>
6823 <inlinemediaobject>
6824 <imageobject>
6825 <imagedata fileref="images/aspectframe.png" format="png">
6826 </imageobject>
6827 </inlinemediaobject>
6828 </para>
6829
6830 <programlisting role="C">
6831 <!-- example-start aspectframe aspectframe.c -->
6832
6833 #include &lt;gtk/gtk.h&gt;
6834    
6835 int main( int argc,
6836           char *argv[] )
6837 {
6838     GtkWidget *window;
6839     GtkWidget *aspect_frame;
6840     GtkWidget *drawing_area;
6841     gtk_init (&amp;argc, &amp;argv);
6842    
6843     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6844     gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
6845     g_signal_connect (G_OBJECT (window), "destroy",
6846                       G_CALLBACK (gtk_main_quit), NULL);
6847     gtk_container_set_border_width (GTK_CONTAINER (window), 10);
6848    
6849     /* Create an aspect_frame and add it to our toplevel window */
6850    
6851     aspect_frame = gtk_aspect_frame_new ("2x1", /* label */
6852                                          0.5, /* center x */
6853                                          0.5, /* center y */
6854                                          2, /* xsize/ysize = 2 */
6855                                          FALSE /* ignore child's aspect */);
6856    
6857     gtk_container_add (GTK_CONTAINER (window), aspect_frame);
6858     gtk_widget_show (aspect_frame);
6859    
6860     /* Now add a child widget to the aspect frame */
6861    
6862     drawing_area = gtk_drawing_area_new ();
6863    
6864     /* Ask for a 200x200 window, but the AspectFrame will give us a 200x100
6865      * window since we are forcing a 2x1 aspect ratio */
6866     gtk_widget_set_size_request (drawing_area, 200, 200);
6867     gtk_container_add (GTK_CONTAINER (aspect_frame), drawing_area);
6868     gtk_widget_show (drawing_area);
6869    
6870     gtk_widget_show (window);
6871     gtk_main ();
6872     return 0;
6873 }
6874 <!-- example-end -->
6875 </programlisting>
6876
6877 </sect1>
6878
6879 <!-- ----------------------------------------------------------------- -->   
6880 <sect1 id="sec-PanedWindowWidgets">
6881 <title>Paned Window Widgets</title>
6882
6883 <para>The paned window widgets are useful when you want to divide an area
6884 into two parts, with the relative size of the two parts controlled by
6885 the user. A groove is drawn between the two portions with a handle
6886 that the user can drag to change the ratio. The division can either be
6887 horizontal (HPaned) or vertical (VPaned).</para>
6888    
6889 <para>To create a new paned window, call one of:</para>
6890
6891 <programlisting role="C">
6892 GtkWidget *gtk_hpaned_new (void);
6893
6894 GtkWidget *gtk_vpaned_new (void);
6895 </programlisting>
6896
6897 <para>After creating the paned window widget, you need to add child widgets
6898 to its two halves. To do this, use the functions:</para>
6899
6900 <programlisting role="C">
6901 void gtk_paned_add1 (GtkPaned *paned, GtkWidget *child);
6902
6903 void gtk_paned_add2 (GtkPaned *paned, GtkWidget *child);
6904 </programlisting>
6905
6906 <para><literal>gtk_paned_add1()</literal> adds the child widget to the left or top half of
6907 the paned window. <literal>gtk_paned_add2()</literal> adds the child widget to the
6908 right or bottom half of the paned window.</para>
6909
6910 <para>As an example, we will create part of the user interface of an
6911 imaginary email program. A window is divided into two portions
6912 vertically, with the top portion being a list of email messages and
6913 the bottom portion the text of the email message. Most of the program
6914 is pretty straightforward. A couple of points to note: text can't be
6915 added to a Text widget until it is realized. This could be done by
6916 calling gtk_widget_realize(), but as a demonstration of an
6917 alternate technique, we connect a handler to the "realize" signal to
6918 add the text. Also, we need to add the <literal>GTK_SHRINK</literal> option to some
6919 of the items in the table containing the text window and its
6920 scrollbars, so that when the bottom portion is made smaller, the
6921 correct portions shrink instead of being pushed off the bottom of the
6922 window.</para>
6923
6924 <para>
6925 <inlinemediaobject>
6926 <imageobject>
6927 <imagedata fileref="images/paned.png" format="png">
6928 </imageobject>
6929 </inlinemediaobject>
6930 </para>
6931
6932 <programlisting role="C">
6933 <!-- example-start paned paned.c -->
6934
6935 #include &lt;stdio.h&gt;
6936 #include &lt;gtk/gtk.h&gt;
6937    
6938 /* Create the list of "messages" */
6939 GtkWidget *create_list( void )
6940 {
6941
6942     GtkWidget *scrolled_window;
6943     GtkWidget *tree_view;
6944     GtkListStore *model;
6945     GtkTreeIter iter;
6946     GtkCellRenderer *cell;
6947     GtkTreeViewColumn *column;
6948
6949     int i;
6950    
6951     /* Create a new scrolled window, with scrollbars only if needed */
6952     scrolled_window = gtk_scrolled_window_new (NULL, NULL);
6953     gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
6954                                     GTK_POLICY_AUTOMATIC, 
6955                                     GTK_POLICY_AUTOMATIC);
6956    
6957     model = gtk_list_store_new (1, G_TYPE_STRING);
6958     tree_view = gtk_tree_view_new ();
6959     gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled_window), 
6960                                            tree_view);
6961     gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view), GTK_TREE_MODEL (model));
6962     gtk_widget_show (tree_view);
6963    
6964     /* Add some messages to the window */
6965     for (i = 0; i &lt; 10; i++) {
6966         gchar *msg = g_strdup_printf ("Message #%d", i);
6967         gtk_list_store_append (GTK_LIST_STORE (model), &amp;iter);
6968         gtk_list_store_set (GTK_LIST_STORE (model), 
6969                             &amp;iter,
6970                             0, msg,
6971                             -1);
6972         g_free (msg);
6973     }
6974    
6975     cell = gtk_cell_renderer_text_new ();
6976
6977     column = gtk_tree_view_column_new_with_attributes ("Messages",
6978                                                        cell,
6979                                                        "text", 0,
6980                                                        NULL);
6981   
6982     gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view),
6983                                  GTK_TREE_VIEW_COLUMN (column));
6984
6985     return scrolled_window;
6986 }
6987    
6988 /* Add some text to our text widget - this is a callback that is invoked
6989 when our window is realized. We could also force our window to be
6990 realized with gtk_widget_realize, but it would have to be part of
6991 a hierarchy first */
6992
6993 void insert_text (GtkTextBuffer *buffer)
6994 {
6995    GtkTextIter iter;
6996  
6997    gtk_text_buffer_get_iter_at_offset (buffer, &amp;iter, 0);
6998
6999    gtk_text_buffer_insert (buffer, &amp;iter,   
7000     "From: pathfinder@nasa.gov\n"
7001     "To: mom@nasa.gov\n"
7002     "Subject: Made it!\n"
7003     "\n"
7004     "We just got in this morning. The weather has been\n"
7005     "great - clear but cold, and there are lots of fun sights.\n"
7006     "Sojourner says hi. See you soon.\n"
7007     " -Path\n", -1);
7008 }
7009    
7010 /* Create a scrolled text area that displays a "message" */
7011 GtkWidget *create_text( void )
7012 {
7013    GtkWidget *scrolled_window;
7014    GtkWidget *view;
7015    GtkTextBuffer *buffer;
7016
7017    view = gtk_text_view_new ();
7018    buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
7019
7020    scrolled_window = gtk_scrolled_window_new (NULL, NULL);
7021    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
7022                                    GTK_POLICY_AUTOMATIC,
7023                                    GTK_POLICY_AUTOMATIC);
7024
7025    gtk_container_add (GTK_CONTAINER (scrolled_window), view);
7026    insert_text (buffer);
7027
7028    gtk_widget_show_all (scrolled_window);
7029
7030    return scrolled_window;
7031 }
7032    
7033 int main( int   argc,
7034           char *argv[] )
7035 {
7036     GtkWidget *window;
7037     GtkWidget *vpaned;
7038     GtkWidget *list;
7039     GtkWidget *text;
7040
7041     gtk_init (&amp;argc, &amp;argv);
7042    
7043     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
7044     gtk_window_set_title (GTK_WINDOW (window), "Paned Windows");
7045     g_signal_connect (G_OBJECT (window), "destroy",
7046                       G_CALLBACK (gtk_main_quit), NULL);
7047     gtk_container_set_border_width (GTK_CONTAINER (window), 10);
7048     gtk_widget_set_size_request (GTK_WIDGET (window), 450, 400);
7049
7050     /* create a vpaned widget and add it to our toplevel window */
7051    
7052     vpaned = gtk_vpaned_new ();
7053     gtk_container_add (GTK_CONTAINER (window), vpaned);
7054     gtk_widget_show (vpaned);
7055    
7056     /* Now create the contents of the two halves of the window */
7057    
7058     list = create_list ();
7059     gtk_paned_add1 (GTK_PANED (vpaned), list);
7060     gtk_widget_show (list);
7061    
7062     text = create_text ();
7063     gtk_paned_add2 (GTK_PANED (vpaned), text);
7064     gtk_widget_show (text);
7065     gtk_widget_show (window);
7066
7067     gtk_main ();
7068
7069     return 0;
7070 }
7071 <!-- example-end -->
7072 </programlisting>
7073
7074 </sect1>
7075
7076 <!-- ----------------------------------------------------------------- -->
7077 <sect1 id="sec-Viewports">
7078 <title>Viewports</title>
7079
7080 <para>It is unlikely that you will ever need to use the Viewport widget
7081 directly. You are much more likely to use the
7082 <link linkend="sec-ScrolledWindows">Scrolled Window</link> widget which
7083 itself uses the Viewport.</para>
7084
7085 <para>A viewport widget allows you to place a larger widget within it such
7086 that you can view a part of it at a time. It uses
7087 <link linkend="ch-Adjustments">Adjustments</link> to define the area that
7088 is currently in view.</para>
7089
7090 <para>A Viewport is created with the function</para>
7091
7092 <programlisting role="C">
7093 GtkWidget *gtk_viewport_new( GtkAdjustment *hadjustment,
7094                              GtkAdjustment *vadjustment );
7095 </programlisting>
7096
7097 <para>As you can see you can specify the horizontal and vertical Adjustments
7098 that the widget is to use when you create the widget. It will create
7099 its own if you pass NULL as the value of the arguments.</para>
7100
7101 <para>You can get and set the adjustments after the widget has been created
7102 using the following four functions:</para>
7103
7104 <programlisting role="C">
7105 GtkAdjustment *gtk_viewport_get_hadjustment (GtkViewport *viewport );
7106
7107 GtkAdjustment *gtk_viewport_get_vadjustment (GtkViewport *viewport );
7108
7109 void gtk_viewport_set_hadjustment( GtkViewport   *viewport,
7110                                    GtkAdjustment *adjustment );
7111
7112 void gtk_viewport_set_vadjustment( GtkViewport   *viewport,
7113                                    GtkAdjustment *adjustment );
7114 </programlisting>
7115
7116 <para>The only other viewport function is used to alter its appearance:</para>
7117
7118 <programlisting role="C">
7119 void gtk_viewport_set_shadow_type( GtkViewport   *viewport,
7120                                    GtkShadowType  type );
7121 </programlisting>
7122
7123 <para>Possible values for the <literal>type</literal> parameter are:</para>
7124 <programlisting role="C">
7125   GTK_SHADOW_NONE,
7126   GTK_SHADOW_IN,
7127   GTK_SHADOW_OUT,
7128   GTK_SHADOW_ETCHED_IN,
7129   GTK_SHADOW_ETCHED_OUT
7130 </programlisting>
7131  
7132 </sect1>
7133
7134 <!-- ----------------------------------------------------------------- -->
7135 <sect1 id="sec-ScrolledWindows"
7136 <title>Scrolled Windows</title>
7137
7138 <para>Scrolled windows are used to create a scrollable area with another
7139 widget inside it. You may insert any type of widget into a scrolled
7140 window, and it will be accessible regardless of the size by using the
7141 scrollbars.</para>
7142
7143 <para>The following function is used to create a new scrolled window.</para>
7144
7145 <programlisting role="C">
7146 GtkWidget *gtk_scrolled_window_new( GtkAdjustment *hadjustment,
7147                                     GtkAdjustment *vadjustment );
7148 </programlisting>
7149
7150 <para>Where the first argument is the adjustment for the horizontal
7151 direction, and the second, the adjustment for the vertical direction.
7152 These are almost always set to NULL.</para>
7153
7154 <programlisting role="C">
7155 void gtk_scrolled_window_set_policy( GtkScrolledWindow *scrolled_window,
7156                                      GtkPolicyType      hscrollbar_policy,
7157                                      GtkPolicyType      vscrollbar_policy );
7158 </programlisting>
7159
7160 <para>This sets the policy to be used with respect to the scrollbars.
7161 The first argument is the scrolled window you wish to change. The second
7162 sets the policy for the horizontal scrollbar, and the third the policy for 
7163 the vertical scrollbar.</para>
7164
7165 <para>The policy may be one of <literal>GTK_POLICY_AUTOMATIC</literal> or
7166 <literal>GTK_POLICY_ALWAYS</literal>. <literal>GTK_POLICY_AUTOMATIC</literal> will automatically
7167 decide whether you need scrollbars, whereas <literal>GTK_POLICY_ALWAYS</literal>
7168 will always leave the scrollbars there.</para>
7169
7170 <para>You can then place your object into the scrolled window using the
7171 following function.</para>
7172
7173 <programlisting role="C">
7174 void gtk_scrolled_window_add_with_viewport( GtkScrolledWindow *scrolled_window,
7175                                             GtkWidget         *child);
7176 </programlisting>
7177
7178 <para>Here is a simple example that packs a table with 100 toggle buttons
7179 into a scrolled window. I've only commented on the parts that may be
7180 new to you.</para>
7181
7182 <para>
7183 <inlinemediaobject>
7184 <imageobject>
7185 <imagedata fileref="images/scrolledwin.png" format="png">
7186 </imageobject>
7187 </inlinemediaobject>
7188 </para>
7189
7190 <programlisting role="C">
7191 <!-- example-start scrolledwin scrolledwin.c -->
7192
7193 #include &lt;stdio.h&gt;
7194 #include &lt;gtk/gtk.h&gt;
7195
7196 void destroy( GtkWidget *widget,
7197               gpointer   data )
7198 {
7199     gtk_main_quit ();
7200 }
7201
7202 int main( int   argc,
7203           char *argv[] )
7204 {
7205     static GtkWidget *window;
7206     GtkWidget *scrolled_window;
7207     GtkWidget *table;
7208     GtkWidget *button;
7209     char buffer[32];
7210     int i, j;
7211     
7212     gtk_init (&amp;argc, &amp;argv);
7213     
7214     /* Create a new dialog window for the scrolled window to be
7215      * packed into.  */
7216     window = gtk_dialog_new ();
7217     g_signal_connect (G_OBJECT (window), "destroy",
7218                       G_CALLBACK (destroy), NULL);
7219     gtk_window_set_title (GTK_WINDOW (window), "GtkScrolledWindow example");
7220     gtk_container_set_border_width (GTK_CONTAINER (window), 0);
7221     gtk_widget_set_size_request (window, 300, 300);
7222     
7223     /* create a new scrolled window. */
7224     scrolled_window = gtk_scrolled_window_new (NULL, NULL);
7225     
7226     gtk_container_set_border_width (GTK_CONTAINER (scrolled_window), 10);
7227     
7228     /* the policy is one of GTK_POLICY AUTOMATIC, or GTK_POLICY_ALWAYS.
7229      * GTK_POLICY_AUTOMATIC will automatically decide whether you need
7230      * scrollbars, whereas GTK_POLICY_ALWAYS will always leave the scrollbars
7231      * there.  The first one is the horizontal scrollbar, the second, 
7232      * the vertical. */
7233     gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
7234                                     GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
7235     /* The dialog window is created with a vbox packed into it. */                                                              
7236     gtk_box_pack_start (GTK_BOX (GTK_DIALOG(window)-&gt;vbox), scrolled_window, 
7237                         TRUE, TRUE, 0);
7238     gtk_widget_show (scrolled_window);
7239     
7240     /* create a table of 10 by 10 squares. */
7241     table = gtk_table_new (10, 10, FALSE);
7242     
7243     /* set the spacing to 10 on x and 10 on y */
7244     gtk_table_set_row_spacings (GTK_TABLE (table), 10);
7245     gtk_table_set_col_spacings (GTK_TABLE (table), 10);
7246     
7247     /* pack the table into the scrolled window */
7248     gtk_scrolled_window_add_with_viewport (
7249                    GTK_SCROLLED_WINDOW (scrolled_window), table);
7250     gtk_widget_show (table);
7251     
7252     /* this simply creates a grid of toggle buttons on the table
7253      * to demonstrate the scrolled window. */
7254     for (i = 0; i &lt; 10; i++)
7255        for (j = 0; j &lt; 10; j++) {
7256           sprintf (buffer, "button (%d,%d)\n", i, j);
7257           button = gtk_toggle_button_new_with_label (buffer);
7258           gtk_table_attach_defaults (GTK_TABLE (table), button,
7259                                      i, i+1, j, j+1);
7260           gtk_widget_show (button);
7261        }
7262     
7263     /* Add a "close" button to the bottom of the dialog */
7264     button = gtk_button_new_with_label ("close");
7265     g_signal_connect_swapped (G_OBJECT (button), "clicked",
7266                               G_CALLBACK (gtk_widget_destroy),
7267                               G_OBJECT (window));
7268     
7269     /* this makes it so the button is the default. */
7270     
7271     GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
7272     gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)-&gt;action_area), button, TRUE, TRUE, 0);
7273     
7274     /* This grabs this button to be the default button. Simply hitting
7275      * the "Enter" key will cause this button to activate. */
7276     gtk_widget_grab_default (button);
7277     gtk_widget_show (button);
7278     
7279     gtk_widget_show (window);
7280     
7281     gtk_main();
7282     
7283     return 0;
7284 }
7285 <!-- example-end -->
7286 </programlisting>
7287
7288 <para>Try playing with resizing the window. You'll notice how the scrollbars
7289 react. You may also wish to use the gtk_widget_set_size_request() call to set
7290 the default size of the window or other widgets.</para>
7291
7292 </sect1>
7293
7294 <!-- ----------------------------------------------------------------- -->   
7295 <sect1 id="sec-ButtonBoxes">
7296 <title>Button Boxes</title>
7297
7298 <para>Button Boxes are a convenient way to quickly layout a group of
7299 buttons. They come in both horizontal and vertical flavours. You
7300 create a new Button Box with one of the following calls, which create
7301 a horizontal or vertical box, respectively:</para>
7302
7303 <programlisting role="C">
7304 GtkWidget *gtk_hbutton_box_new( void );
7305
7306 GtkWidget *gtk_vbutton_box_new( void );
7307 </programlisting>
7308
7309 <para>Buttons are added to a Button Box using the usual function:</para>
7310
7311 <programlisting role="C">
7312     gtk_container_add (GTK_CONTAINER (button_box), child_widget);
7313 </programlisting>
7314
7315 <para>Here's an example that illustrates all the different layout settings
7316 for Button Boxes.</para>
7317
7318 <para>
7319 <inlinemediaobject>
7320 <imageobject>
7321 <imagedata fileref="images/buttonbox.png" format="png">
7322 </imageobject>
7323 </inlinemediaobject>
7324 </para>
7325
7326 <programlisting role="C">
7327 <!-- example-start buttonbox buttonbox.c -->
7328
7329 #include &lt;gtk/gtk.h&gt;
7330
7331 /* Create a Button Box with the specified parameters */
7332 GtkWidget *create_bbox( gint  horizontal,
7333                         char *title,
7334                         gint  spacing,
7335                         gint  child_w,
7336                         gint  child_h,
7337                         gint  layout )
7338 {
7339   GtkWidget *frame;
7340   GtkWidget *bbox;
7341   GtkWidget *button;
7342
7343   frame = gtk_frame_new (title);
7344
7345   if (horizontal)
7346     bbox = gtk_hbutton_box_new ();
7347   else
7348     bbox = gtk_vbutton_box_new ();
7349
7350   gtk_container_set_border_width (GTK_CONTAINER (bbox), 5);
7351   gtk_container_add (GTK_CONTAINER (frame), bbox);
7352
7353   /* Set the appearance of the Button Box */
7354   gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), layout);
7355   gtk_box_set_spacing (GTK_BOX (bbox), spacing);
7356   /*gtk_button_box_set_child_size (GTK_BUTTON_BOX (bbox), child_w, child_h);*/
7357
7358   button = gtk_button_new_from_stock (GTK_STOCK_OK);
7359   gtk_container_add (GTK_CONTAINER (bbox), button);
7360
7361   button = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
7362   gtk_container_add (GTK_CONTAINER (bbox), button);
7363
7364   button = gtk_button_new_from_stock (GTK_STOCK_HELP);
7365   gtk_container_add (GTK_CONTAINER (bbox), button);
7366
7367   return frame;
7368 }
7369
7370 int main( int   argc,
7371           char *argv[] )
7372 {
7373   static GtkWidget* window = NULL;
7374   GtkWidget *main_vbox;
7375   GtkWidget *vbox;
7376   GtkWidget *hbox;
7377   GtkWidget *frame_horz;
7378   GtkWidget *frame_vert;
7379
7380   /* Initialize GTK */
7381   gtk_init (&amp;argc, &amp;argv);
7382
7383   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
7384   gtk_window_set_title (GTK_WINDOW (window), "Button Boxes");
7385
7386   g_signal_connect (G_OBJECT (window), "destroy",
7387                     G_CALLBACK (gtk_main_quit),
7388                     NULL);
7389
7390   gtk_container_set_border_width (GTK_CONTAINER (window), 10);
7391
7392   main_vbox = gtk_vbox_new (FALSE, 0);
7393   gtk_container_add (GTK_CONTAINER (window), main_vbox);
7394
7395   frame_horz = gtk_frame_new ("Horizontal Button Boxes");
7396   gtk_box_pack_start (GTK_BOX (main_vbox), frame_horz, TRUE, TRUE, 10);
7397
7398   vbox = gtk_vbox_new (FALSE, 0);
7399   gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
7400   gtk_container_add (GTK_CONTAINER (frame_horz), vbox);
7401
7402   gtk_box_pack_start (GTK_BOX (vbox),
7403            create_bbox (TRUE, "Spread (spacing 40)", 40, 85, 20, GTK_BUTTONBOX_SPREAD),
7404                       TRUE, TRUE, 0);
7405
7406   gtk_box_pack_start (GTK_BOX (vbox),
7407            create_bbox (TRUE, "Edge (spacing 30)", 30, 85, 20, GTK_BUTTONBOX_EDGE),
7408                       TRUE, TRUE, 5);
7409
7410   gtk_box_pack_start (GTK_BOX (vbox),
7411            create_bbox (TRUE, "Start (spacing 20)", 20, 85, 20, GTK_BUTTONBOX_START),
7412                       TRUE, TRUE, 5);
7413
7414   gtk_box_pack_start (GTK_BOX (vbox),
7415            create_bbox (TRUE, "End (spacing 10)", 10, 85, 20, GTK_BUTTONBOX_END),
7416                       TRUE, TRUE, 5);
7417
7418   frame_vert = gtk_frame_new ("Vertical Button Boxes");
7419   gtk_box_pack_start (GTK_BOX (main_vbox), frame_vert, TRUE, TRUE, 10);
7420
7421   hbox = gtk_hbox_new (FALSE, 0);
7422   gtk_container_set_border_width (GTK_CONTAINER (hbox), 10);
7423   gtk_container_add (GTK_CONTAINER (frame_vert), hbox);
7424
7425   gtk_box_pack_start (GTK_BOX (hbox),
7426            create_bbox (FALSE, "Spread (spacing 5)", 5, 85, 20, GTK_BUTTONBOX_SPREAD),
7427                       TRUE, TRUE, 0);
7428
7429   gtk_box_pack_start (GTK_BOX (hbox),
7430            create_bbox (FALSE, "Edge (spacing 30)", 30, 85, 20, GTK_BUTTONBOX_EDGE),
7431                       TRUE, TRUE, 5);
7432
7433   gtk_box_pack_start (GTK_BOX (hbox),
7434            create_bbox (FALSE, "Start (spacing 20)", 20, 85, 20, GTK_BUTTONBOX_START),
7435                       TRUE, TRUE, 5);
7436
7437   gtk_box_pack_start (GTK_BOX (hbox),
7438            create_bbox (FALSE, "End (spacing 20)", 20, 85, 20, GTK_BUTTONBOX_END),
7439                       TRUE, TRUE, 5);
7440
7441   gtk_widget_show_all (window);
7442
7443   /* Enter the event loop */
7444   gtk_main ();
7445     
7446   return 0;
7447 }
7448 <!-- example-end -->
7449 </programlisting>
7450
7451 </sect1>
7452
7453 <!-- ----------------------------------------------------------------- -->   
7454 <sect1 id="sec-Toolbar">
7455 <title>Toolbar</title>
7456
7457 <para>Toolbars are usually used to group some number of widgets in order to
7458 simplify customization of their look and layout. Typically a toolbar
7459 consists of buttons with icons, labels and tooltips, but any other
7460 widget can also be put inside a toolbar. Finally, items can be
7461 arranged horizontally or vertically and buttons can be displayed with
7462 icons, labels, or both.</para>
7463
7464 <para>Creating a toolbar is (as one may already suspect) done with the
7465 following function:</para>
7466
7467 <programlisting role="C">
7468 GtkWidget *gtk_toolbar_new( void );
7469 </programlisting>
7470
7471 <para>After creating a toolbar one can append, prepend and insert items
7472 (that means simple text strings) or elements (that means any widget
7473 types) into the toolbar. To describe an item we need a label text, a
7474 tooltip text, a private tooltip text, an icon for the button and a
7475 callback function for it. For example, to append or prepend an item
7476 you may use the following functions:</para>
7477
7478 <programlisting role="C">
7479 GtkWidget *gtk_toolbar_append_item( GtkToolbar    *toolbar,
7480                                     const char    *text,
7481                                     const char    *tooltip_text,
7482                                     const char    *tooltip_private_text,
7483                                     GtkWidget     *icon,
7484                                     GtkSignalFunc  callback,
7485                                     gpointer       user_data );
7486
7487 GtkWidget *gtk_toolbar_prepend_item( GtkToolbar    *toolbar,
7488                                      const char    *text,
7489                                      const char    *tooltip_text,
7490                                      const char    *tooltip_private_text,
7491                                      GtkWidget     *icon,
7492                                      GtkSignalFunc  callback,
7493                                      gpointer       user_data );
7494 </programlisting>
7495
7496 <para>If you want to use gtk_toolbar_insert_item(), the only additional
7497 parameter which must be specified is the position in which the item
7498 should be inserted, thus:</para>
7499
7500 <programlisting role="C">
7501 GtkWidget *gtk_toolbar_insert_item( GtkToolbar    *toolbar,
7502                                     const char    *text,
7503                                     const char    *tooltip_text,
7504                                     const char    *tooltip_private_text,
7505                                     GtkWidget     *icon,
7506                                     GtkSignalFunc  callback,
7507                                     gpointer       user_data,
7508                                     gint           position );
7509 </programlisting>
7510
7511 <para>To simplify adding spaces between toolbar items, you may use the
7512 following functions:</para>
7513
7514 <programlisting role="C">
7515 void gtk_toolbar_append_space( GtkToolbar *toolbar );
7516
7517 void gtk_toolbar_prepend_space( GtkToolbar *toolbar );
7518
7519 void gtk_toolbar_insert_space( GtkToolbar *toolbar,
7520                                gint        position );
7521 </programlisting>
7522
7523 <para>If it's required, the orientation of a toolbar and its style can be
7524 changed "on the fly" using the following functions:</para>
7525
7526 <programlisting role="C">
7527 void gtk_toolbar_set_orientation( GtkToolbar     *toolbar,
7528                                   GtkOrientation  orientation );
7529
7530 void gtk_toolbar_set_style( GtkToolbar      *toolbar,
7531                             GtkToolbarStyle  style );
7532
7533 void gtk_toolbar_set_tooltips( GtkToolbar *toolbar,
7534                                gint        enable );
7535 </programlisting>
7536
7537 <para>Where <literal>orientation</literal> is one of <literal>GTK_ORIENTATION_HORIZONTAL</literal> or
7538 <literal>GTK_ORIENTATION_VERTICAL</literal>. The <literal>style</literal> is used to set
7539 appearance of the toolbar items by using one of
7540 <literal>GTK_TOOLBAR_ICONS</literal>, <literal>GTK_TOOLBAR_TEXT</literal>, or
7541 <literal>GTK_TOOLBAR_BOTH</literal>.</para>
7542
7543 <para>To show some other things that can be done with a toolbar, let's take
7544 the following program (we'll interrupt the listing with some
7545 additional explanations):</para>
7546
7547 <programlisting role="C">
7548 #include &lt;gtk/gtk.h&gt;
7549
7550 /* This function is connected to the Close button or
7551  * closing the window from the WM */
7552 gint delete_event (GtkWidget *widget, GdkEvent *event, gpointer data)
7553 {
7554   gtk_main_quit ();
7555   return FALSE;
7556 }
7557 </programlisting>
7558
7559 <para>The above beginning seems for sure familiar to you if it's not your first
7560 GTK program. There is one additional thing though, we include a nice XPM
7561 picture to serve as an icon for all of the buttons.</para>
7562
7563 <programlisting role="C">
7564 GtkWidget* close_button; /* This button will emit signal to close
7565                           * application */
7566 GtkWidget* tooltips_button; /* to enable/disable tooltips */
7567 GtkWidget* text_button,
7568          * icon_button,
7569          * both_button; /* radio buttons for toolbar style */
7570 GtkWidget* entry; /* a text entry to show packing any widget into
7571                    * toolbar */
7572 </programlisting>
7573
7574 <para>In fact not all of the above widgets are needed here, but to make things
7575 clearer I put them all together.</para>
7576
7577 <programlisting role="C">
7578 /* that's easy... when one of the buttons is toggled, we just
7579  * check which one is active and set the style of the toolbar
7580  * accordingly
7581  * ATTENTION: our toolbar is passed as data to callback ! */
7582 void radio_event (GtkWidget *widget, gpointer data)
7583 {
7584   if (GTK_TOGGLE_BUTTON (text_button)->active) 
7585     gtk_toolbar_set_style (GTK_TOOLBAR (data), GTK_TOOLBAR_TEXT);
7586   else if (GTK_TOGGLE_BUTTON (icon_button)->active)
7587     gtk_toolbar_set_style (GTK_TOOLBAR (data), GTK_TOOLBAR_ICONS);
7588   else if (GTK_TOGGLE_BUTTON (both_button)->active)
7589     gtk_toolbar_set_style (GTK_TOOLBAR (data), GTK_TOOLBAR_BOTH);
7590 }
7591
7592 /* even easier, just check given toggle button and enable/disable 
7593  * tooltips */
7594 void toggle_event (GtkWidget *widget, gpointer data)
7595 {
7596   gtk_toolbar_set_tooltips (GTK_TOOLBAR (data),
7597                             GTK_TOGGLE_BUTTON (widget)->active );
7598 }
7599 </programlisting>
7600
7601 <para>The above are just two callback functions that will be called when
7602 one of the buttons on a toolbar is pressed. You should already be
7603 familiar with things like this if you've already used toggle buttons (and
7604 radio buttons).</para>
7605
7606 <programlisting role="C">
7607 int main (int argc, char *argv[])
7608 {
7609   /* Here is our main window (a dialog) and a handle for the handlebox */
7610   GtkWidget* dialog;
7611   GtkWidget* handlebox;
7612
7613   /* Ok, we need a toolbar, an icon with a mask (one for all of 
7614      the buttons) and an icon widget to put this icon in (but 
7615      we'll create a separate widget for each button) */
7616   GtkWidget * toolbar;
7617   GtkWidget * iconw;
7618
7619   /* this is called in all GTK application. */
7620   gtk_init (&amp;argc, &amp;argv);
7621   
7622   /* create a new window with a given title, and nice size */
7623   dialog = gtk_dialog_new ();
7624   gtk_window_set_title (GTK_WINDOW (dialog), "GTKToolbar Tutorial");
7625   gtk_widget_set_size_request (GTK_WIDGET (dialog), 600, 300);
7626   GTK_WINDOW (dialog)->allow_shrink = TRUE;
7627
7628   /* typically we quit if someone tries to close us */
7629   g_signal_connect (G_OBJECT (dialog), "delete_event",
7630                     G_CALLBACK (delete_event), NULL);
7631
7632   /* we need to realize the window because we use pixmaps for 
7633    * items on the toolbar in the context of it */
7634   gtk_widget_realize (dialog);
7635
7636   /* to make it nice we'll put the toolbar into the handle box, 
7637    * so that it can be detached from the main window */
7638   handlebox = gtk_handle_box_new ();
7639   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
7640                       handlebox, FALSE, FALSE, 5);
7641 </programlisting>
7642
7643 <para>The above should be similar to any other GTK application. Just
7644 initialization of GTK, creating the window, etc. There is only one
7645 thing that probably needs some explanation: a handle box. A handle box
7646 is just another box that can be used to pack widgets in to. The
7647 difference between it and typical boxes is that it can be detached
7648 from a parent window (or, in fact, the handle box remains in the
7649 parent, but it is reduced to a very small rectangle, while all of its
7650 contents are reparented to a new freely floating window). It is
7651 usually nice to have a detachable toolbar, so these two widgets occur
7652 together quite often.</para>
7653
7654 <programlisting role="C">
7655   /* toolbar will be horizontal, with both icons and text, and
7656    * with 5pxl spaces between items and finally, 
7657    * we'll also put it into our handlebox */
7658   toolbar = gtk_toolbar_new ();
7659   gtk_toolbar_set_orientation (GTK_TOOLBAR (toolbar), GTK_ORIENTATION_HORIZONTAL);
7660   gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_BOTH);
7661   gtk_container_set_border_width (GTK_CONTAINER (toolbar), 5);
7662   gtk_toolbar_set_space_size (GTK_TOOLBAR (toolbar), 5);
7663   gtk_container_add (GTK_CONTAINER (handlebox), toolbar);
7664 </programlisting>
7665
7666 <para>Well, what we do above is just a straightforward initialization of
7667 the toolbar widget.</para>
7668
7669 <programlisting role="C">
7670   /* our first item is &lt;close&gt; button */
7671   iconw = gtk_image_new_from_file ("gtk.xpm"); /* icon widget */
7672   close_button = 
7673     gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), /* our toolbar */
7674                              "Close",               /* button label */
7675                              "Closes this app",     /* this button's tooltip */
7676                              "Private",             /* tooltip private info */
7677                              iconw,                 /* icon widget */
7678                              GTK_SIGNAL_FUNC (delete_event), /* a signal */
7679                              NULL);
7680   gtk_toolbar_append_space (GTK_TOOLBAR (toolbar)); /* space after item */
7681 </programlisting>
7682
7683 <para>In the above code you see the simplest case: adding a button to
7684 toolbar.  Just before appending a new item, we have to construct an
7685 image widget to serve as an icon for this item; this step will have
7686 to be repeated for each new item. Just after the item we also add a
7687 space, so the following items will not touch each other. As you see
7688 gtk_toolbar_append_item() returns a pointer to our newly created button
7689 widget, so that we can work with it in the normal way.</para>
7690
7691 <programlisting role="C">
7692   /* now, let's make our radio buttons group... */
7693   iconw = gtk_image_new_from_file ("gtk.xpm");
7694   icon_button = gtk_toolbar_append_element (
7695                     GTK_TOOLBAR (toolbar),
7696                     GTK_TOOLBAR_CHILD_RADIOBUTTON, /* a type of element */
7697                     NULL,                          /* pointer to widget */
7698                     "Icon",                        /* label */
7699                     "Only icons in toolbar",       /* tooltip */
7700                     "Private",                     /* tooltip private string */
7701                     iconw,                         /* icon */
7702                     GTK_SIGNAL_FUNC (radio_event), /* signal */
7703                     toolbar);                      /* data for signal */
7704   gtk_toolbar_append_space (GTK_TOOLBAR (toolbar));
7705 </programlisting>
7706
7707 <para>Here we begin creating a radio buttons group. To do this we use
7708 gtk_toolbar_append_element.  In fact, using this function one can also
7709 +add simple items or even spaces (type = <literal>GTK_TOOLBAR_CHILD_SPACE</literal>
7710 or +<literal>GTK_TOOLBAR_CHILD_BUTTON</literal>). In the above case we start
7711 creating a radio group. In creating other radio buttons for this group
7712 a pointer to the previous button in the group is required, so that a
7713 list of buttons can be easily constructed (see the section on <link
7714 linkend="sec-RadioButtons">Radio Buttons</link> earlier in this
7715 tutorial).</para>
7716
7717 <programlisting role="C">
7718   /* following radio buttons refer to previous ones */
7719   iconw = gtk_image_new_from_file ("gtk.xpm");
7720   text_button = 
7721     gtk_toolbar_append_element (GTK_TOOLBAR (toolbar),
7722                                 GTK_TOOLBAR_CHILD_RADIOBUTTON,
7723                                 icon_button,
7724                                 "Text",
7725                                 "Only texts in toolbar",
7726                                 "Private",
7727                                 iconw,
7728                                 GTK_SIGNAL_FUNC (radio_event),
7729                                 toolbar);
7730   gtk_toolbar_append_space (GTK_TOOLBAR (toolbar));
7731                                           
7732   iconw = gtk_image_new_from_file ("gtk.xpm");
7733   both_button = 
7734     gtk_toolbar_append_element (GTK_TOOLBAR (toolbar),
7735                                 GTK_TOOLBAR_CHILD_RADIOBUTTON,
7736                                 text_button,
7737                                 "Both",
7738                                 "Icons and text in toolbar",
7739                                 "Private",
7740                                 iconw,
7741                                 GTK_SIGNAL_FUNC (radio_event),
7742                                 toolbar);
7743   gtk_toolbar_append_space (GTK_TOOLBAR (toolbar));
7744   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (both_button), TRUE);
7745 </programlisting>
7746
7747 <para>In the end we have to set the state of one of the buttons manually
7748 (otherwise they all stay in active state, preventing us from switching
7749 between them).</para>
7750
7751 <programlisting role="C">
7752   /* here we have just a simple toggle button */
7753   iconw = gtk_image_new_from_file ("gtk.xpm");
7754   tooltips_button = 
7755     gtk_toolbar_append_element (GTK_TOOLBAR (toolbar),
7756                                 GTK_TOOLBAR_CHILD_TOGGLEBUTTON,
7757                                 NULL,
7758                                 "Tooltips",
7759                                 "Toolbar with or without tips",
7760                                 "Private",
7761                                 iconw,
7762                                 GTK_SIGNAL_FUNC (toggle_event),
7763                                 toolbar);
7764   gtk_toolbar_append_space (GTK_TOOLBAR (toolbar));
7765   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (tooltips_button), TRUE);
7766 </programlisting>
7767
7768 <para>A toggle button can be created in the obvious way (if one knows how to create
7769 radio buttons already).</para>
7770
7771 <programlisting role="C">
7772   /* to pack a widget into toolbar, we only have to 
7773    * create it and append it with an appropriate tooltip */
7774   entry = gtk_entry_new ();
7775   gtk_toolbar_append_widget (GTK_TOOLBAR (toolbar), 
7776                              entry, 
7777                              "This is just an entry", 
7778                              "Private");
7779
7780   /* well, it isn't created within the toolbar, so we must still show it */
7781   gtk_widget_show (entry);
7782 </programlisting>
7783
7784 <para>As you see, adding any kind of widget to a toolbar is simple. The
7785 one thing you have to remember is that this widget must be shown manually
7786 (contrary to other items which will be shown together with the toolbar).</para>
7787
7788 <programlisting role="C">
7789   /* that's it ! let's show everything. */
7790   gtk_widget_show (toolbar);
7791   gtk_widget_show (handlebox);
7792   gtk_widget_show (dialog);
7793
7794   /* rest in gtk_main and wait for the fun to begin! */
7795   gtk_main ();
7796   
7797   return 0;
7798 }
7799 </programlisting>
7800
7801 <para>So, here we are at the end of toolbar tutorial. Of course, to appreciate
7802 it in full you need also this nice XPM icon, so here it is:</para>
7803
7804 <programlisting role="C">
7805 /* XPM */
7806 static char * gtk_xpm[] = {
7807 "32 39 5 1",
7808 ".      c none",
7809 "+      c black",
7810 "@      c #3070E0",
7811 "#      c #F05050",
7812 "$      c #35E035",
7813 "................+...............",
7814 "..............+++++.............",
7815 "............+++++@@++...........",
7816 "..........+++++@@@@@@++.........",
7817 "........++++@@@@@@@@@@++........",
7818 "......++++@@++++++++@@@++.......",
7819 ".....+++@@@+++++++++++@@@++.....",
7820 "...+++@@@@+++@@@@@@++++@@@@+....",
7821 "..+++@@@@+++@@@@@@@@+++@@@@@++..",
7822 ".++@@@@@@+++@@@@@@@@@@@@@@@@@@++",
7823 ".+#+@@@@@@++@@@@+++@@@@@@@@@@@@+",
7824 ".+##++@@@@+++@@@+++++@@@@@@@@$@.",
7825 ".+###++@@@@+++@@@+++@@@@@++$$$@.",
7826 ".+####+++@@@+++++++@@@@@+@$$$$@.",
7827 ".+#####+++@@@@+++@@@@++@$$$$$$+.",
7828 ".+######++++@@@@@@@++@$$$$$$$$+.",
7829 ".+#######+##+@@@@+++$$$$$$@@$$+.",
7830 ".+###+++##+##+@@++@$$$$$$++$$$+.",
7831 ".+###++++##+##+@@$$$$$$$@+@$$@+.",
7832 ".+###++++++#+++@$$@+@$$@++$$$@+.",
7833 ".+####+++++++#++$$@+@$$++$$$$+..",
7834 ".++####++++++#++$$@+@$++@$$$$+..",
7835 ".+#####+++++##++$$++@+++$$$$$+..",
7836 ".++####+++##+#++$$+++++@$$$$$+..",
7837 ".++####+++####++$$++++++@$$$@+..",
7838 ".+#####++#####++$$+++@++++@$@+..",
7839 ".+#####++#####++$$++@$$@+++$@@..",
7840 ".++####++#####++$$++$$$$$+@$@++.",
7841 ".++####++#####++$$++$$$$$$$$+++.",
7842 ".+++####+#####++$$++$$$$$$$@+++.",
7843 "..+++#########+@$$+@$$$$$$+++...",
7844 "...+++########+@$$$$$$$$@+++....",
7845 ".....+++######+@$$$$$$$+++......",
7846 "......+++#####+@$$$$$@++........",
7847 ".......+++####+@$$$$+++.........",
7848 ".........++###+$$$@++...........",
7849 "..........++##+$@+++............",
7850 "...........+++++++..............",
7851 ".............++++..............."};
7852 </programlisting>
7853
7854 </sect1>
7855
7856 <!-- ----------------------------------------------------------------- -->
7857 <sect1 id="sec-Notebooks">
7858 <title>Notebooks</title>
7859
7860 <para>The NoteBook Widget is a collection of "pages" that overlap each
7861 other, each page contains different information with only one page
7862 visible at a time. This widget has become more common lately in GUI
7863 programming, and it is a good way to show blocks of similar
7864 information that warrant separation in their display.</para>
7865
7866 <para>The first function call you will need to know, as you can probably
7867 guess by now, is used to create a new notebook widget.</para>
7868
7869 <programlisting role="C">
7870 GtkWidget *gtk_notebook_new( void );
7871 </programlisting>
7872
7873 <para>Once the notebook has been created, there are a number of functions
7874 that operate on the notebook widget. Let's look at them individually.</para>
7875
7876 <para>The first one we will look at is how to position the page indicators.
7877 These page indicators or "tabs" as they are referred to, can be
7878 positioned in four ways: top, bottom, left, or right.</para>
7879
7880 <programlisting role="C">
7881 void gtk_notebook_set_tab_pos( GtkNotebook     *notebook,
7882                                GtkPositionType  pos );
7883 </programlisting>
7884
7885 <para>GtkPositionType will be one of the following, which are pretty self
7886 explanatory:</para>
7887 <programlisting role="C">
7888   GTK_POS_LEFT
7889   GTK_POS_RIGHT
7890   GTK_POS_TOP
7891   GTK_POS_BOTTOM
7892 </programlisting>
7893
7894 <para><literal>GTK_POS_TOP</literal> is the default.</para>
7895
7896 <para>Next we will look at how to add pages to the notebook. There are three
7897 ways to add pages to the NoteBook. Let's look at the first two
7898 together as they are quite similar.</para>
7899
7900 <programlisting role="C">
7901 void gtk_notebook_append_page( GtkNotebook *notebook,
7902                                GtkWidget   *child,
7903                                GtkWidget   *tab_label );
7904
7905 void gtk_notebook_prepend_page( GtkNotebook *notebook,
7906                                 GtkWidget   *child,
7907                                 GtkWidget   *tab_label );
7908 </programlisting>
7909
7910 <para>These functions add pages to the notebook by inserting them from the
7911 back of the notebook (append), or the front of the notebook (prepend).
7912 <literal>child</literal> is the widget that is placed within the notebook page, and
7913 <literal>tab_label</literal> is the label for the page being added. The <literal>child</literal>
7914 widget must be created separately, and is typically a set of options
7915 setup witin one of the other container widgets, such as a table.</para>
7916
7917 <para>The final function for adding a page to the notebook contains all of
7918 the properties of the previous two, but it allows you to specify what
7919 position you want the page to be in the notebook.</para>
7920
7921 <programlisting role="C">
7922 void gtk_notebook_insert_page( GtkNotebook *notebook,
7923                                GtkWidget   *child,
7924                                GtkWidget   *tab_label,
7925                                gint         position );
7926 </programlisting>
7927
7928 <para>The parameters are the same as _append_ and _prepend_ except it
7929 contains an extra parameter, <literal>position</literal>.  This parameter is used to
7930 specify what place this page will be inserted into the first page
7931 having position zero.</para>
7932
7933 <para>Now that we know how to add a page, lets see how we can remove a page
7934 from the notebook.</para>
7935
7936 <programlisting role="C">
7937 void gtk_notebook_remove_page( GtkNotebook *notebook,
7938                                gint         page_num );
7939 </programlisting>
7940
7941 <para>This function takes the page specified by <literal>page_num</literal> and removes it
7942 from the widget pointed to by <literal>notebook</literal>.</para>
7943
7944 <para>To find out what the current page is in a notebook use the function:</para>
7945
7946 <programlisting role="C">
7947 gint gtk_notebook_get_current_page( GtkNotebook *notebook );
7948 </programlisting>
7949
7950 <para>These next two functions are simple calls to move the notebook page
7951 forward or backward. Simply provide the respective function call with
7952 the notebook widget you wish to operate on. Note: When the NoteBook is
7953 currently on the last page, and gtk_notebook_next_page() is called, the
7954 notebook will wrap back to the first page. Likewise, if the NoteBook
7955 is on the first page, and gtk_notebook_prev_page() is called, the
7956 notebook will wrap to the last page.</para>
7957
7958 <programlisting role="C">
7959 void gtk_notebook_next_page( GtkNoteBook *notebook );
7960
7961 void gtk_notebook_prev_page( GtkNoteBook *notebook );
7962 </programlisting>
7963
7964 <para>This next function sets the "active" page. If you wish the notebook to
7965 be opened to page 5 for example, you would use this function.  Without
7966 using this function, the notebook defaults to the first page.</para>
7967
7968 <programlisting role="C">
7969 void gtk_notebook_set_current_page( GtkNotebook *notebook,
7970                                     gint         page_num );
7971 </programlisting>
7972
7973 <para>The next two functions add or remove the notebook page tabs and the
7974 notebook border respectively.</para>
7975
7976 <programlisting role="C">
7977 void gtk_notebook_set_show_tabs( GtkNotebook *notebook,
7978                                  gboolean     show_tabs );
7979
7980 void gtk_notebook_set_show_border( GtkNotebook *notebook,
7981                                    gboolean     show_border );
7982 </programlisting>
7983
7984 <para>The next function is useful when the you have a large number of pages,
7985 and the tabs don't fit on the page. It allows the tabs to be scrolled
7986 through using two arrow buttons.</para>
7987
7988 <programlisting role="C">
7989 void gtk_notebook_set_scrollable( GtkNotebook *notebook,
7990                                   gboolean     scrollable );
7991 </programlisting>
7992
7993 <para><literal>show_tabs</literal>, <literal>show_border</literal> and <literal>scrollable</literal> can be either
7994 TRUE or FALSE.</para>
7995
7996 <para>Now let's look at an example, it is expanded from the 
7997 <filename>testgtk.c</filename> code
7998 that comes with the GTK distribution. This small program creates a
7999 window with a notebook and six buttons. The notebook contains 11
8000 pages, added in three different ways, appended, inserted, and
8001 prepended. The buttons allow you rotate the tab positions, add/remove
8002 the tabs and border, remove a page, change pages in both a forward and
8003 backward manner, and exit the program.</para>
8004
8005 <para>
8006 <inlinemediaobject>
8007 <imageobject>
8008 <imagedata fileref="images/notebook.png" format="png">
8009 </imageobject>
8010 </inlinemediaobject>
8011 </para>
8012
8013 <programlisting role="C">
8014 <!-- example-start notebook notebook.c -->
8015
8016 #include &lt;stdio.h&gt;
8017 #include &lt;gtk/gtk.h&gt;
8018
8019 /* This function rotates the position of the tabs */
8020 void rotate_book( GtkButton   *button,
8021                   GtkNotebook *notebook )
8022 {
8023     gtk_notebook_set_tab_pos (notebook, (notebook-&gt;tab_pos + 1) % 4);
8024 }
8025
8026 /* Add/Remove the page tabs and the borders */
8027 void tabsborder_book( GtkButton   *button,
8028                       GtkNotebook *notebook )
8029 {
8030     gint tval = FALSE;
8031     gint bval = FALSE;
8032     if (notebook-&gt;show_tabs == 0)
8033             tval = TRUE; 
8034     if (notebook-&gt;show_border == 0)
8035             bval = TRUE;
8036     
8037     gtk_notebook_set_show_tabs (notebook, tval);
8038     gtk_notebook_set_show_border (notebook, bval);
8039 }
8040
8041 /* Remove a page from the notebook */
8042 void remove_book( GtkButton   *button,
8043                   GtkNotebook *notebook )
8044 {
8045     gint page;
8046     
8047     page = gtk_notebook_get_current_page (notebook);
8048     gtk_notebook_remove_page (notebook, page);
8049     /* Need to refresh the widget -- 
8050      This forces the widget to redraw itself. */
8051     gtk_widget_queue_draw (GTK_WIDGET (notebook));
8052 }
8053
8054 gint delete( GtkWidget *widget,
8055              GtkWidget *event,
8056              gpointer   data )
8057 {
8058     gtk_main_quit ();
8059     return FALSE;
8060 }
8061
8062 int main( int argc,
8063           char *argv[] )
8064 {
8065     GtkWidget *window;
8066     GtkWidget *button;
8067     GtkWidget *table;
8068     GtkWidget *notebook;
8069     GtkWidget *frame;
8070     GtkWidget *label;
8071     GtkWidget *checkbutton;
8072     int i;
8073     char bufferf[32];
8074     char bufferl[32];
8075     
8076     gtk_init (&amp;argc, &amp;argv);
8077     
8078     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
8079     
8080     g_signal_connect (G_OBJECT (window), "delete_event",
8081                       G_CALLBACK (delete), NULL);
8082     
8083     gtk_container_set_border_width (GTK_CONTAINER (window), 10);
8084
8085     table = gtk_table_new (3, 6, FALSE);
8086     gtk_container_add (GTK_CONTAINER (window), table);
8087     
8088     /* Create a new notebook, place the position of the tabs */
8089     notebook = gtk_notebook_new ();
8090     gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP);
8091     gtk_table_attach_defaults (GTK_TABLE (table), notebook, 0, 6, 0, 1);
8092     gtk_widget_show (notebook);
8093     
8094     /* Let's append a bunch of pages to the notebook */
8095     for (i = 0; i &lt; 5; i++) {
8096         sprintf(bufferf, "Append Frame %d", i + 1);
8097         sprintf(bufferl, "Page %d", i + 1);
8098         
8099         frame = gtk_frame_new (bufferf);
8100         gtk_container_set_border_width (GTK_CONTAINER (frame), 10);
8101         gtk_widget_set_size_request (frame, 100, 75);
8102         gtk_widget_show (frame);
8103         
8104         label = gtk_label_new (bufferf);
8105         gtk_container_add (GTK_CONTAINER (frame), label);
8106         gtk_widget_show (label);
8107         
8108         label = gtk_label_new (bufferl);
8109         gtk_notebook_append_page (GTK_NOTEBOOK (notebook), frame, label);
8110     }
8111       
8112     /* Now let's add a page to a specific spot */
8113     checkbutton = gtk_check_button_new_with_label ("Check me please!");
8114     gtk_widget_set_size_request (checkbutton, 100, 75);
8115     gtk_widget_show (checkbutton);
8116    
8117     label = gtk_label_new ("Add page");
8118     gtk_notebook_insert_page (GTK_NOTEBOOK (notebook), checkbutton, label, 2);
8119     
8120     /* Now finally let's prepend pages to the notebook */
8121     for (i = 0; i &lt; 5; i++) {
8122         sprintf (bufferf, "Prepend Frame %d", i + 1);
8123         sprintf (bufferl, "PPage %d", i + 1);
8124         
8125         frame = gtk_frame_new (bufferf);
8126         gtk_container_set_border_width (GTK_CONTAINER (frame), 10);
8127         gtk_widget_set_size_request (frame, 100, 75);
8128         gtk_widget_show (frame);
8129         
8130         label = gtk_label_new (bufferf);
8131         gtk_container_add (GTK_CONTAINER (frame), label);
8132         gtk_widget_show (label);
8133         
8134         label = gtk_label_new (bufferl);
8135         gtk_notebook_prepend_page (GTK_NOTEBOOK (notebook), frame, label);
8136     }
8137     
8138     /* Set what page to start at (page 4) */
8139     gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), 3);
8140
8141     /* Create a bunch of buttons */
8142     button = gtk_button_new_with_label ("close");
8143     g_signal_connect_swapped (G_OBJECT (button), "clicked",
8144                               G_CALLBACK (delete), NULL);
8145     gtk_table_attach_defaults (GTK_TABLE (table), button, 0, 1, 1, 2);
8146     gtk_widget_show (button);
8147     
8148     button = gtk_button_new_with_label ("next page");
8149     g_signal_connect_swapped (G_OBJECT (button), "clicked",
8150                               G_CALLBACK (gtk_notebook_next_page),
8151                               G_OBJECT (notebook));
8152     gtk_table_attach_defaults (GTK_TABLE (table), button, 1, 2, 1, 2);
8153     gtk_widget_show (button);
8154     
8155     button = gtk_button_new_with_label ("prev page");
8156     g_signal_connect_swapped (G_OBJECT (button), "clicked",
8157                               G_CALLBACK (gtk_notebook_prev_page),
8158                               G_OBJECT (notebook));
8159     gtk_table_attach_defaults (GTK_TABLE (table), button, 2, 3, 1, 2);
8160     gtk_widget_show (button);
8161     
8162     button = gtk_button_new_with_label ("tab position");
8163     g_signal_connect (G_OBJECT (button), "clicked",
8164                       G_CALLBACK (rotate_book),
8165                       (gpointer) notebook);
8166     gtk_table_attach_defaults (GTK_TABLE (table), button, 3, 4, 1, 2);
8167     gtk_widget_show (button);
8168     
8169     button = gtk_button_new_with_label ("tabs/border on/off");
8170     g_signal_connect (G_OBJECT (button), "clicked",
8171                       G_CALLBACK (tabsborder_book),
8172                       (gpointer) notebook);
8173     gtk_table_attach_defaults (GTK_TABLE (table), button, 4, 5, 1, 2);
8174     gtk_widget_show (button);
8175     
8176     button = gtk_button_new_with_label ("remove page");
8177     g_signal_connect (G_OBJECT (button), "clicked",
8178                       G_CALLBACK (remove_book),
8179                       (gpointer) notebook);
8180     gtk_table_attach_defaults (GTK_TABLE (table), button, 5, 6, 1, 2);
8181     gtk_widget_show (button);
8182     
8183     gtk_widget_show (table);
8184     gtk_widget_show (window);
8185     
8186     gtk_main ();
8187     
8188     return 0;
8189 }
8190 <!-- example-end -->
8191 </programlisting>
8192
8193 <para>I hope this helps you on your way with creating notebooks for your
8194 GTK applications.</para>
8195
8196 </sect1>
8197 </chapter>
8198
8199 <!-- ***************************************************************** -->
8200 <chapter id="ch-MenuWidget">
8201 <title>Menu Widget</title>
8202
8203 <para>There are two ways to create menus: there's the easy way, and there's
8204 the hard way. Both have their uses, but you can usually use the
8205 Itemfactory (the easy way). The "hard" way is to create all the menus
8206 using the calls directly. The easy way is to use the gtk_item_factory
8207 calls. This is much simpler, but there are advantages and
8208 disadvantages to each approach.</para>
8209
8210 <para>The Itemfactory is much easier to use, and to add new menus to,
8211 although writing a few wrapper functions to create menus using the
8212 manual method could go a long way towards usability. With the
8213 Itemfactory, it is not possible to add images or the character '/' to
8214 the menus.</para>
8215
8216 <!-- ----------------------------------------------------------------- -->
8217 <sect1 id="sec-ManualMenuCreation">
8218 <title>Manual Menu Creation</title>
8219
8220 <para>In the true tradition of teaching, we'll show you the hard way
8221 first. <literal>:)</literal></para>
8222
8223 <para>There are three widgets that go into making a menubar and submenus:</para>
8224
8225 <itemizedlist>
8226 <listitem><simpara>a menu item, which is what the user wants to select, e.g.,
8227 "Save"</simpara>
8228 </listitem>
8229 <listitem><simpara>a menu, which acts as a container for the menu items, and</simpara>
8230 </listitem>
8231 <listitem><simpara>a menubar, which is a container for each of the individual
8232 menus.</simpara>
8233 </listitem>
8234 </itemizedlist>
8235
8236 <para>This is slightly complicated by the fact that menu item widgets are
8237 used for two different things. They are both the widgets that are
8238 packed into the menu, and the widget that is packed into the menubar,
8239 which, when selected, activates the menu.</para>
8240
8241 <para>Let's look at the functions that are used to create menus and
8242 menubars.  This first function is used to create a new menubar.</para>
8243
8244 <programlisting role="C">
8245 GtkWidget *gtk_menu_bar_new( void );
8246 </programlisting>
8247
8248 <para>This rather self explanatory function creates a new menubar. You use
8249 gtk_container_add() to pack this into a window, or the box_pack
8250 functions to pack it into a box - the same as buttons.</para>
8251
8252 <programlisting role="C">
8253 GtkWidget *gtk_menu_new( void );
8254 </programlisting>
8255
8256 <para>This function returns a pointer to a new menu; it is never actually
8257 shown (with gtk_widget_show()), it is just a container for the menu
8258 items. I hope this will become more clear when you look at the
8259 example below.</para>
8260
8261 <para>The next three calls are used to create menu items that are packed into
8262 the menu (and menubar).</para>
8263
8264 <programlisting role="C">
8265 GtkWidget *gtk_menu_item_new( void );
8266
8267 GtkWidget *gtk_menu_item_new_with_label( const char *label );
8268
8269 GtkWidget *gtk_menu_item_new_with_mnemnonic( const char *label );
8270 </programlisting>
8271
8272 <para>These calls are used to create the menu items that are to be
8273 displayed.  Remember to differentiate between a "menu" as created with
8274 gtk_menu_new() and a "menu item" as created by the gtk_menu_item_new()
8275 functions. The menu item will be an actual button with an associated
8276 action, whereas a menu will be a container holding menu items.</para>
8277
8278 <para>The gtk_menu_item_new_with_label() and gtk_menu_item_new() functions are just as
8279 you'd expect after reading about the buttons. One creates a new menu
8280 item with a label already packed into it, and the other just creates a
8281 blank menu item.</para>
8282
8283 <para>Once you've created a menu item you have to put it into a menu. This
8284 is done using the function gtk_menu_shelll_append. In order to capture when
8285 the item is selected by the user, we need to connect to the
8286 <literal>activate</literal> signal in the usual way. So, if we wanted to create a
8287 standard <literal>File</literal> menu, with the options <literal>Open</literal>, <literal>Save</literal>, and
8288 <literal>Quit</literal>, the code would look something like:</para>
8289
8290 <programlisting role="C">
8291     file_menu = gtk_menu_new ();    /* Don't need to show menus */
8292
8293     /* Create the menu items */
8294     open_item = gtk_menu_item_new_with_label ("Open");
8295     save_item = gtk_menu_item_new_with_label ("Save");
8296     quit_item = gtk_menu_item_new_with_label ("Quit");
8297
8298     /* Add them to the menu */
8299     gtk_menu_shell_append (GTK_MENU_SHELL (file_menu), open_item);
8300     gtk_menu_shell_append (GTK_MENU_SHELL (file_menu), save_item);
8301     gtk_menu_shell_append (GTK_MENU_SHELL (file_menu), quit_item);
8302
8303     /* Attach the callback functions to the activate signal */
8304     g_signal_connect_swapped (G_OBJECT (open_item), "activate",
8305                               G_CALLBACK (menuitem_response),
8306                               (gpointer) "file.open");
8307     g_signal_connect_swapped (G_OBJECT (save_item), "activate",
8308                               G_CALLBACK (menuitem_response),
8309                               (gpointer) "file.save");
8310
8311     /* We can attach the Quit menu item to our exit function */
8312     g_signal_connect_swapped (G_OBJECT (quit_item), "activate",
8313                               G_CALLBACK (destroy),
8314                               (gpointer) "file.quit");
8315
8316     /* We do need to show menu items */
8317     gtk_widget_show (open_item);
8318     gtk_widget_show (save_item);
8319     gtk_widget_show (quit_item);
8320 </programlisting>
8321
8322 <para>At this point we have our menu. Now we need to create a menubar and a
8323 menu item for the <literal>File</literal> entry, to which we add our menu. The code
8324 looks like this:</para>
8325
8326 <programlisting role="C">
8327     menu_bar = gtk_menu_bar_new ();
8328     gtk_container_add (GTK_CONTAINER (window), menu_bar);
8329     gtk_widget_show (menu_bar);
8330
8331     file_item = gtk_menu_item_new_with_label ("File");
8332     gtk_widget_show (file_item);
8333 </programlisting>
8334
8335 <para>Now we need to associate the menu with <literal>file_item</literal>. This is done
8336 with the function</para>
8337
8338 <programlisting role="C">
8339 void gtk_menu_item_set_submenu( GtkMenuItem *menu_item,
8340                                 GtkWidget   *submenu );
8341 </programlisting>
8342
8343 <para>So, our example would continue with</para>
8344
8345 <programlisting role="C">
8346     gtk_menu_item_set_submenu (GTK_MENU_ITEM (file_item), file_menu);
8347 </programlisting>
8348
8349 <para>All that is left to do is to add the menu to the menubar, which is
8350 accomplished using the function</para>
8351
8352 <programlisting role="C">
8353 void gtk_menu_bar_append( GtkMenuBar *menu_bar,
8354                           GtkWidget  *menu_item );
8355 </programlisting>
8356
8357 <para>which in our case looks like this:</para>
8358
8359 <programlisting role="C">
8360     gtk_menu_bar_append (GTK_MENU_BAR (menu_bar), file_item);
8361 </programlisting>
8362
8363 <para>If we wanted the menu right justified on the menubar, such as help
8364 menus often are, we can use the following function (again on
8365 <literal>file_item</literal> in the current example) before attaching it to the
8366 menubar.</para>
8367
8368 <programlisting role="C">
8369 void gtk_menu_item_right_justify( GtkMenuItem *menu_item );
8370 </programlisting>
8371
8372 <para>Here is a summary of the steps needed to create a menu bar with menus
8373 attached:</para>
8374
8375 <itemizedlist>
8376 <listitem><simpara> Create a new menu using gtk_menu_new()</simpara>
8377 </listitem>
8378
8379 <listitem><simpara> Use multiple calls to gtk_menu_item_new() for each item you
8380 wish to have on your menu. And use gtk_menu_shell_append() to put each of
8381 these new items on to the menu.</simpara>
8382 </listitem>
8383
8384 <listitem><simpara> Create a menu item using gtk_menu_item_new(). This will be the
8385 root of the menu, the text appearing here will be on the menubar
8386 itself.</simpara>
8387 </listitem>
8388
8389 <listitem><simpara>Use gtk_menu_item_set_submenu() to attach the menu to the root
8390 menu item (the one created in the above step).</simpara>
8391 </listitem>
8392
8393 <listitem><simpara> Create a new menubar using gtk_menu_bar_new. This step only
8394 needs to be done once when creating a series of menus on one menu bar.</simpara>
8395 </listitem>
8396
8397 <listitem><simpara> Use gtk_menu_bar_append() to put the root menu onto the menubar.</simpara>
8398 </listitem>
8399 </itemizedlist>
8400
8401 <para>Creating a popup menu is nearly the same. The difference is that the
8402 menu is not posted "automatically" by a menubar, but explicitly by
8403 calling the function gtk_menu_popup() from a button-press event, for
8404 example.  Take these steps:</para>
8405
8406 <itemizedlist>
8407 <listitem><simpara>Create an event handling function. It needs to have the
8408 prototype</simpara>
8409 <programlisting role="C">
8410 static gint handler (GtkWidget *widget,
8411                      GdkEvent  *event);
8412 </programlisting>
8413 <simpara>and it will use the event to find out where to pop up the menu.</simpara>
8414 </listitem>
8415
8416 <listitem><simpara>In the event handler, if the event is a mouse button press,
8417 treat <literal>event</literal> as a button event (which it is) and use it as
8418 shown in the sample code to pass information to gtk_menu_popup().</simpara>
8419 </listitem>
8420
8421 <listitem><simpara>Bind that event handler to a widget with</simpara>
8422 <programlisting role="C">
8423     g_signal_connect_swapped (G_OBJECT (widget), "event",
8424                               G_CALLBACK (handler),
8425                               G_OBJECT (menu));
8426 </programlisting>
8427 <simpara>where <literal>widget</literal> is the widget you are binding to,
8428 <literal>handler</literal> is the handling function, and <literal>menu</literal> is a menu
8429 created with gtk_menu_new(). This can be a menu which is also posted
8430 by a menu bar, as shown in the sample code.</simpara>
8431 </listitem>
8432 </itemizedlist>
8433
8434 </sect1>
8435
8436 <!-- ----------------------------------------------------------------- -->
8437 <sect1 id="sec-ManualMenuExample">
8438 <title>Manual Menu Example</title>
8439
8440 <para>That should about do it. Let's take a look at an example to help clarify.</para>
8441
8442 <para>
8443 <inlinemediaobject>
8444 <imageobject>
8445 <imagedata fileref="images/menu.png" format="png">
8446 </imageobject>
8447 </inlinemediaobject>
8448 </para>
8449
8450 <programlisting role="C">
8451 <!-- example-start menu menu.c -->
8452
8453 #include &lt;stdio.h&gt;
8454 #include &lt;gtk/gtk.h&gt;
8455
8456 static gint button_press (GtkWidget *, GdkEvent *);
8457 static void menuitem_response (gchar *);
8458
8459 int main( int   argc,
8460           char *argv[] )
8461 {
8462
8463     GtkWidget *window;
8464     GtkWidget *menu;
8465     GtkWidget *menu_bar;
8466     GtkWidget *root_menu;
8467     GtkWidget *menu_items;
8468     GtkWidget *vbox;
8469     GtkWidget *button;
8470     char buf[128];
8471     int i;
8472
8473     gtk_init (&amp;argc, &amp;argv);
8474
8475     /* create a new window */
8476     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
8477     gtk_widget_set_size_request (GTK_WIDGET (window), 200, 100);
8478     gtk_window_set_title (GTK_WINDOW (window), "GTK Menu Test");
8479     g_signal_connect (G_OBJECT (window), "delete_event",
8480                       G_CALLBACK (gtk_main_quit), NULL);
8481
8482     /* Init the menu-widget, and remember -- never
8483      * gtk_show_widget() the menu widget!! 
8484      * This is the menu that holds the menu items, the one that
8485      * will pop up when you click on the "Root Menu" in the app */
8486     menu = gtk_menu_new ();
8487
8488     /* Next we make a little loop that makes three menu-entries for "test-menu".
8489      * Notice the call to gtk_menu_shell_append.  Here we are adding a list of
8490      * menu items to our menu.  Normally, we'd also catch the "clicked"
8491      * signal on each of the menu items and setup a callback for it,
8492      * but it's omitted here to save space. */
8493
8494     for (i = 0; i &lt; 3; i++)
8495         {
8496             /* Copy the names to the buf. */
8497             sprintf (buf, "Test-undermenu - %d", i);
8498
8499             /* Create a new menu-item with a name... */
8500             menu_items = gtk_menu_item_new_with_label (buf);
8501
8502             /* ...and add it to the menu. */
8503             gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_items);
8504
8505             /* Do something interesting when the menuitem is selected */
8506             g_signal_connect_swapped (G_OBJECT (menu_items), "activate",
8507                                       G_CALLBACK (menuitem_response), 
8508                                       (gpointer) g_strdup (buf));
8509
8510             /* Show the widget */
8511             gtk_widget_show (menu_items);
8512         }
8513
8514     /* This is the root menu, and will be the label
8515      * displayed on the menu bar.  There won't be a signal handler attached,
8516      * as it only pops up the rest of the menu when pressed. */
8517     root_menu = gtk_menu_item_new_with_label ("Root Menu");
8518
8519     gtk_widget_show (root_menu);
8520
8521     /* Now we specify that we want our newly created "menu" to be the menu
8522      * for the "root menu" */
8523     gtk_menu_item_set_submenu (GTK_MENU_ITEM (root_menu), menu);
8524
8525     /* A vbox to put a menu and a button in: */
8526     vbox = gtk_vbox_new (FALSE, 0);
8527     gtk_container_add (GTK_CONTAINER (window), vbox);
8528     gtk_widget_show (vbox);
8529
8530     /* Create a menu-bar to hold the menus and add it to our main window */
8531     menu_bar = gtk_menu_bar_new ();
8532     gtk_box_pack_start (GTK_BOX (vbox), menu_bar, FALSE, FALSE, 2);
8533     gtk_widget_show (menu_bar);
8534
8535     /* Create a button to which to attach menu as a popup */
8536     button = gtk_button_new_with_label ("press me");
8537     g_signal_connect_swapped (G_OBJECT (button), "event",
8538                               G_CALLBACK (button_press), 
8539                               G_OBJECT (menu));
8540     gtk_box_pack_end (GTK_BOX (vbox), button, TRUE, TRUE, 2);
8541     gtk_widget_show (button);
8542
8543     /* And finally we append the menu-item to the menu-bar -- this is the
8544      * "root" menu-item I have been raving about =) */
8545     gtk_menu_shell_append (GTK_MENU_SHELL (menu_bar), root_menu);
8546
8547     /* always display the window as the last step so it all splashes on
8548      * the screen at once. */
8549     gtk_widget_show (window);
8550
8551     gtk_main ();
8552
8553     return 0;
8554 }
8555
8556 /* Respond to a button-press by posting a menu passed in as widget.
8557  *
8558  * Note that the "widget" argument is the menu being posted, NOT
8559  * the button that was pressed.
8560  */
8561
8562 static gint button_press( GtkWidget *widget,
8563                           GdkEvent *event )
8564 {
8565
8566     if (event-&gt;type == GDK_BUTTON_PRESS) {
8567         GdkEventButton *bevent = (GdkEventButton *) event; 
8568         gtk_menu_popup (GTK_MENU (widget), NULL, NULL, NULL, NULL,
8569                         bevent-&gt;button, bevent-&gt;time);
8570         /* Tell calling code that we have handled this event; the buck
8571          * stops here. */
8572         return TRUE;
8573     }
8574
8575     /* Tell calling code that we have not handled this event; pass it on. */
8576     return FALSE;
8577 }
8578
8579
8580 /* Print a string when a menu item is selected */
8581
8582 static void menuitem_response( gchar *string )
8583 {
8584     printf ("%s\n", string);
8585 }
8586 <!-- example-end -->
8587 </programlisting>
8588
8589 <para>You may also set a menu item to be insensitive and, using an accelerator
8590 table, bind keys to menu functions.</para>
8591
8592 </sect1>
8593
8594 <!-- ----------------------------------------------------------------- -->
8595 <sect1 id="sec-UsingItemFactory">
8596 <title>Using ItemFactory</title>
8597
8598 <para>Now that we've shown you the hard way, here's how you do it using the
8599 gtk_item_factory calls.</para>
8600
8601 <para>ItemFactory creates a menu out of an array of ItemFactory entries. This 
8602 means you can define your menu in its simplest form and then create the
8603 menu/menubar widgets with a minimum of function calls.</para>
8604
8605 <!-- ----------------------------------------------------------------- -->
8606 <sect2 id="sec-ItemFactoryEntries">
8607 <title>ItemFactory entries</title>
8608
8609 <para>At the core of ItemFactory is the ItemFactoryEntry. This structure defines
8610 one menu item, and when an array of these entries is defined a whole
8611 menu is formed. The ItemFactory entry struct definition looks like this:</para>
8612
8613 <programlisting role="C">
8614 struct _GtkItemFactoryEntry
8615 {
8616   gchar *path;
8617   gchar *accelerator;
8618
8619   GtkItemFactoryCallback callback;
8620   guint                  callback_action;
8621
8622   gchar          *item_type;
8623 };
8624 </programlisting>
8625
8626 <para>Each field defines part of the menu item.</para>
8627
8628 <para><literal>*path</literal> is a string which defines both the name and the
8629 path of a menu item, for example, "/File/Open" would be the name of a menu
8630 item which would come under the ItemFactory entry with path "/File". Note however
8631 that "/File/Open" would be displayed in the File menu as "Open". Also note
8632 since the forward slashes are used to define the path of the menu,
8633 they cannot be used as part of the name. A letter preceded by an underscore
8634 indicates an accelerator (shortcut) key once the menu is open.</para>
8635
8636 <para>
8637 <literal>*accelerator</literal> is a string that indicates a key combination
8638 that can be used as a shortcut to that menu item. The string can be made up
8639 of either a single character, or a combination of modifier keys with a single
8640 character. It is case insensitive.</para>
8641
8642
8643 <para>The available modifier keys are:</para>
8644
8645 <programlisting role="C">
8646 "&lt;ALT&gt;                             - alt
8647 "&lt;CTL&gt;" or "&lt;CTRL&gt;" or "&lt;CONTROL&gt;" - control
8648 "&lt;MOD1&gt;" to "&lt;MOD5&gt;"               - modn
8649 "&lt;SHFT&gt;" or "&lt;SHIFT&gt;"              - shift
8650 </programlisting>
8651
8652 <para>Examples:</para>
8653 <programlisting role="C">
8654 "&lt;ConTroL&gt;a"
8655 "&lt;SHFT&gt;&lt;ALT&gt;&lt;CONTROL&gt;X"
8656 </programlisting>
8657
8658 <para>
8659 <literal>callback</literal> is the function that is called when the menu item
8660 emits the "activate" signal. The form of the callback is described
8661 in the <link linkend="sec-ItemFactoryCallback">Callback Description</link>
8662 section.</para>
8663
8664 <para>
8665 The value of <literal>callback_action</literal> is passed to the callback
8666 function. It also affects the function prototype, as shown
8667 in the <link linkend="sec-ItemFactoryCallback">Callback Description</link>
8668 section.</para>
8669
8670 <para>
8671 <literal>item_type</literal> is a string that defines what type of widget is
8672 packed into the menu items container. It can be:</para>
8673
8674 <programlisting role="C">
8675 NULL or "" or "&lt;Item&gt;" - create a simple item
8676 "&lt;Title&gt;"              - create a title item
8677 "&lt;CheckItem&gt;"          - create a check item
8678 "&lt;ToggleItem&gt;"         - create a toggle item
8679 "&lt;RadioItem&gt;"          - create a (root) radio item
8680 "Path"                 - create a sister radio item
8681 "&lt;Tearoff&gt;"            - create a tearoff
8682 "&lt;Separator&gt;"          - create a separator
8683 "&lt;Branch&gt;"             - create an item to hold submenus (optional)
8684 "&lt;LastBranch&gt;"         - create a right justified branch
8685 </programlisting>
8686
8687 <para>Note that &lt;LastBranch&gt; is only useful for one submenu of
8688 a menubar.</para>
8689
8690 <!-- ----------------------------------------------------------------- -->
8691 <sect3 id="sec-ItemFactoryCallback">
8692 <title>Callback Description</title>
8693
8694 <para>
8695 The callback for an ItemFactory entry can take two forms. If
8696 <literal>callback_action</literal> is zero, it is of the following
8697 form:</para>
8698
8699 <programlisting role="C">
8700 void callback(void)
8701 </programlisting>
8702
8703 <para>otherwise it is of the form:</para>
8704
8705 <programlisting role="C">
8706 void callback(gpointer    callback_data,
8707               guint       callback_action,
8708               GtkWidget  *widget)
8709 </programlisting>
8710
8711 <para>
8712 <literal>callback_data</literal> is a pointer to an arbitrary piece of data and
8713 is set during the call to gtk_item_factory_create_items().</para>
8714
8715 <para>
8716 <literal>callback_action</literal> is the same value as
8717 <literal>callback_action</literal> in the ItemFactory entry.</para>
8718
8719 <para>
8720 <literal>*widget</literal> is a pointer to a menu item widget
8721 (described in <link linkend="sec-ManualMenuCreation">Manual Menu Creation</link>).
8722 </para>
8723 </sect3>
8724
8725 <!-- ----------------------------------------------------------------- -->
8726 <sect3 id="sec-ItemFactoryEntryExamples">
8727 <title>ItemFactory entry examples</title>
8728
8729 <para>Creating a simple menu item:</para>
8730
8731 <programlisting role="C">
8732 GtkItemFactoryEntry entry = {"/_File/_Open...", "&lt;CTRL&gt;O", print_hello,
8733                                 0, "&lt;Item&gt;"};
8734 </programlisting>
8735
8736 <para>This will define a new simple menu entry "/File/Open" (displayed as "Open"),
8737 under the menu entry "/File". It has the accelerator (shortcut) control+'O'
8738 that when clicked calls the function print_hello(). print_hello() is of
8739 the form <literal>void print_hello(void)</literal> since the callback_action
8740 field is zero. When displayed the 'O' in "Open" will be underlined and if the
8741 menu item is visible on the screen pressing 'O' will activate the item. Note
8742 that "File/_Open" could also have been used as the path instead of
8743 "/_File/_Open".</para>
8744
8745 <para>Creating an entry with a more complex callback:</para>
8746
8747 <programlisting role="C">
8748 GtkItemFactoryEntry entry = {"/_View/Display _FPS", NULL, print_state,
8749                                 7,"&lt;CheckItem&gt;"};
8750 </programlisting>
8751
8752 <para>This defines a new menu item displayed as "Display FPS" which is under
8753 the menu item "View". When clicked the function print_state() will be called.
8754 Since <literal>callback_action</literal> is not zero print_state() is of the
8755 form:</para>
8756
8757 <programlisting role="C">
8758 void print_state(gpointer    callback_data,
8759                  guint       callback_action,
8760                  GtkWidget  *widget)
8761 </programlisting>
8762
8763 <para>with <literal>callback_action</literal> equal to 7.</para>
8764
8765 <para>Creating a radio button set:</para>
8766
8767 <programlisting role="C">
8768 GtkItemFactoryEntry entry1 = {"/_View/_Low Resolution", NULL, change_resolution,
8769                                 1, "&lt;RadioButton&gt;"};
8770 GtkItemFactoryEntry entry2 = {"/_View/_High Resolution", NULL, change_resolution,
8771                                 2, "/View/Low Resolution"};
8772 </programlisting>
8773
8774 <para><literal>entry1</literal> defines a lone radio button that when toggled
8775 calls the function change_resolution() with the parameter
8776 <literal>callback_action</literal> equal to 1. change_resolution() is of
8777 the form:</para>
8778
8779 <programlisting role="C">
8780 void change_resolution(gpointer    callback_data,
8781                        guint       callback_action,
8782                        GtkWidget  *widget)
8783 </programlisting>
8784
8785 <para><literal>entry2</literal> defines a radio button that belongs to the
8786 radio group that entry1 belongs to. It calls the same function when toggled
8787 but with the parameter <literal>callback_action</literal> equal to 2. Note that
8788 the item_type of <literal>entry2</literal> is the path of entry1
8789 <emphasis>without</emphasis> the accelerators ('_'). If another radio button was
8790 required in the same group then it would be defined in the same way as
8791 <literal>entry2</literal> was with its <literal>item_type</literal> again
8792 equal to "/View/Low Resolution".</para>
8793 </sect3>
8794
8795 <!-- ----------------------------------------------------------------- -->
8796 <sect3 id="sec-ItemFactoryEntryArrays">
8797 <title>ItemFactoryEntry Arrays</title>
8798
8799 <para>An ItemFactoryEntry on it's own however isn't useful. An array of
8800 entries is what's required to define a menu. Below is an example of how
8801 you'd declare this array.</para>
8802
8803 <programlisting role="C">
8804 static GtkItemFactoryEntry entries[] = {
8805   { "/_File",         NULL,      NULL,         0, "&lt;Branch&gt;" },
8806   { "/File/tear1",    NULL,      NULL,         0, "&lt;Tearoff&gt;" },
8807   { "/File/_New",     "&lt;CTRL&gt;N", new_file,     1, "&lt;Item&gt;" },
8808   { "/File/_Open...", "&lt;CTRL&gt;O", open_file,    1, "&lt;Item&gt;" },
8809   { "/File/sep1",     NULL,      NULL,         0, "&lt;Separator&gt;" },
8810   { "/File/_Quit",    "&lt;CTRL&gt;Q", quit_program, 0, "&lt;Item&gt;"} };
8811 </programlisting>
8812 </sect3>
8813 </sect2>
8814
8815 <!-- ----------------------------------------------------------------- -->
8816 <sect2 id="sec-ItemFactoryCreation">
8817 <title>Creating an ItemFactory</title>
8818
8819 <para>An array of GtkItemFactoryEntry items defines a menu. Once this
8820 array is defined then the item factory can be created. The function that
8821 does this is:</para>
8822
8823 <programlisting role="C">
8824 GtkItemFactory* gtk_item_factory_new( GtkType        container_type,
8825                                       const gchar   *path,
8826                                       GtkAccelGroup *accel_group );
8827 </programlisting>
8828
8829 <para><literal>container_type</literal> can be one of:</para>
8830
8831 <programlisting role="C">
8832 GTK_TYPE_MENU
8833 GTK_TYPE_MENU_BAR
8834 GTK_TYPE_OPTION_MENU
8835 </programlisting>
8836
8837 <para><literal>container_type</literal> defines what type of menu
8838 you want, so when you extract it later it is either a menu (for pop-ups
8839 for instance), a menu bar, or an option menu (like a combo box but with
8840 a menu of pull downs).</para>
8841
8842 <para><literal>path</literal> defines the path of the root of the menu.
8843 Basically it is a unique name for the root of the menu, it must be
8844 surrounded by "&lt;&gt;". This is important for the naming of the
8845 accelerators and should be unique. It should be unique both for each
8846 menu and between each program. For example in a program named 'foo', the
8847 main menu should be called "&lt;FooMain&gt;", and a pop-up menu
8848 "&lt;FooImagePopUp&gt;", or similar. What's important is that they're unique.</para>
8849
8850 <para><literal>accel_group</literal> is a pointer to a gtk_accel_group. The
8851 item factory sets up the accelerator table while generating menus. New
8852 accelerator groups are generated by gtk_accel_group_new().</para>
8853
8854 <para>But this is just the first step. To convert the array of GtkItemFactoryEntry
8855 information into widgets the following function is used:</para>
8856
8857 <programlisting role="C">
8858 void gtk_item_factory_create_items( GtkItemFactory      *ifactory,
8859                                     guint                n_entries,
8860                                     GtkItemFactoryEntry *entries,
8861                                     gpointer             callback_data );
8862 </programlisting>
8863
8864 <para><literal>*ifactory</literal> a pointer to the above created item factory.</para>
8865 <para><literal>n_entries</literal> is the number of entries in the
8866 GtkItemFactoryEntry array.</para>
8867 <para><literal>*entries</literal> is a pointer to the GtkItemFactoryEntry array.</para>
8868 <para><literal>callback_data</literal> is what gets passed to all the callback functions
8869 for all the entries with callback_action != 0.</para>
8870
8871 <para>The accelerator group has now been formed, so you'll probably want
8872 to attach it to the window the menu is in:</para>
8873
8874 <programlisting role="C">
8875 void gtk_window_add_accel_group( GtkWindow     *window,
8876                                  GtkAccelGroup *accel_group);
8877 </programlisting>
8878 </sect2>
8879
8880 <!-- ----------------------------------------------------------------- -->
8881 <sect2 id="sec-UsingMenuandItems">
8882 <title>Making use of the menu and its menu items</title>
8883
8884 <para>The last thing to do is make use of the menu. The following function
8885 extracts the relevant widgets from the ItemFactory:</para>
8886
8887 <programlisting role="C">
8888 GtkWidget* gtk_item_factory_get_widget( GtkItemFactory *ifactory,
8889                                         const gchar    *path );
8890 </programlisting>
8891
8892 <para>For instance if an ItemFactory has two entries "/File" and "/File/New",
8893 using a path of "/File" would retrieve a <emphasis>menu</emphasis> widget from the
8894 ItemFactory. Using a path of "/File/New" would retrieve a
8895 <emphasis>menu item</emphasis> widget. This makes it possible to set the initial state
8896 of menu items. For example to set the default radio
8897 item to the one with the path "/Shape/Oval" then the following code would
8898 be used:</para>
8899
8900 <programlisting role="C">
8901 gtk_check_menu_item_set_active(
8902         GTK_CHECK_MENU_ITEM (gtk_item_factory_get_item (item_factory, "/Shape/Oval")),
8903         TRUE);
8904 </programlisting>
8905
8906 <para>Finally to retrieve the root of the menu use gtk_item_factory_get_item()
8907 with a path of "&lt;main&gt;" (or whatever path was used in
8908 gtk_item_factory_new()). In the case of the ItemFactory being created with
8909 type GTK_TYPE_MENU_BAR this returns a menu bar widget. With type GTK_TYPE_MENU
8910 a menu widget is returned. With type GTK_TYPE_OPTION_MENU an option menu
8911 widget is returned.</para>
8912
8913 <para><emphasis>Remember</emphasis> for an entry defined with path "/_File"
8914 the path here is actually "/File".</para>
8915
8916 <para>Now you have a menubar or menu which can be manipulated in the same
8917 way as shown in the
8918 <link linkend="sec-ManualMenuCreation">Manual Menu Creation</link>
8919 section.</para>
8920 </sect2>
8921 </sect1>
8922
8923 <!-- ----------------------------------------------------------------- -->
8924 <sect1 id="sec-ItemFactoryExample">
8925 <title>Item Factory Example</title>
8926
8927 <para>Here is an example using the GTK item factory.</para>
8928
8929 <programlisting role="C">
8930 <!-- example-start menu itemfactory.c -->
8931
8932 #include &lt;gtk/gtk.h&gt;
8933 #include &lt;strings.h&gt;
8934
8935 /* Obligatory basic callback */
8936 static void print_hello( GtkWidget *w,
8937                          gpointer   data )
8938 {
8939   g_message ("Hello, World!\n");
8940 }
8941
8942 /* For the check button */
8943 static void print_toggle(gpointer   callback_data,
8944                          guint      callback_action,
8945                          GtkWidget *menu_item)
8946 {
8947    g_message ("Check button state - %d\n",
8948               GTK_CHECK_MENU_ITEM(menu_item)-&amp;gt;active);
8949 }
8950
8951 /* For the radio buttons */
8952 static void print_selected(gpointer   callback_data,
8953                            guint      callback_action,
8954                            GtkWidget *menu_item)
8955 {
8956    if(GTK_CHECK_MENU_ITEM(menu_item)-&amp;gt;active)
8957      g_message("Radio button %d selected\n", callback_action);
8958 }
8959
8960 /* Our menu, an array of GtkItemFactoryEntry structures that defines each menu item */
8961 static GtkItemFactoryEntry menu_items[] = {
8962   { "/_File",         NULL,         NULL,           0, "&amp;lt;Branch&amp;gt;" },
8963   { "/File/_New",     "&amp;lt;control&amp;gt;N", print_hello,    0, "&lt;Item&gt;" },
8964   { "/File/_Open",    "&amp;lt;control&amp;gt;O", print_hello,    0, "&lt;Item&gt;" },
8965   { "/File/_Save",    "&amp;lt;control&amp;gt;S", print_hello,    0, "&lt;Item&gt;" },
8966   { "/File/Save _As", NULL,         NULL,           0, "&lt;Item&gt;" },
8967   { "/File/sep1",     NULL,         NULL,           0, "&amp;lt;Separator&amp;gt;" },
8968   { "/File/Quit",     "&amp;lt;control&amp;gt;Q", gtk_main_quit,  0, "&lt;Item&gt;" },
8969   { "/_Options",      NULL,         NULL,           0, "&amp;lt;Branch&amp;gt;" },
8970   { "/Options/tear",  NULL,         NULL,           0, "&amp;lt;Tearoff&amp;gt;" },
8971   { "/Options/Check", NULL,         print_toggle,   1, "&amp;lt;CheckItem&amp;gt;" },
8972   { "/Options/sep",   NULL,         NULL,           0, "&amp;lt;Separator&amp;gt;" },
8973   { "/Options/Rad1",  NULL,         print_selected, 1, "&amp;lt;RadioItem&amp;gt;" },
8974   { "/Options/Rad2",  NULL,         print_selected, 2, "/Options/Rad1" },
8975   { "/Options/Rad3",  NULL,         print_selected, 3, "/Options/Rad1" },
8976   { "/_Help",         NULL,         NULL,           0, "&amp;lt;LastBranch&amp;gt;" },
8977   { "/_Help/About",   NULL,         NULL,           0, "&lt;Item&gt;" },
8978 };
8979
8980 static gint nmenu_items = sizeof (menu_items) / sizeof (menu_items[0]);
8981
8982 /* Returns a menubar widget made from the above menu */
8983 GtkWidget *get_menubar_menu( GtkWidget  *window)
8984 {
8985   GtkItemFactory *item_factory;
8986   GtkAccelGroup *accel_group;
8987
8988   /* Make an accelerator group (shortcut keys) */
8989   accel_group = gtk_accel_group_new ();
8990
8991   /* Make an ItemFactory (that makes a menubar) */
8992   item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "&amp;lt;main&amp;gt;",
8993                                        accel_group);
8994
8995   /* This function generates the menu items. Pass the item factory,
8996      the number of items in the array, the array itself, and any
8997      callback data for the the menu items. */
8998   gtk_item_factory_create_items (item_factory, nmenu_items, menu_items, NULL);
8999
9000   /* Attach the new accelerator group to the window. */
9001   gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
9002
9003   /* Finally, return the actual menu bar created by the item factory. */
9004   return gtk_item_factory_get_widget (item_factory, "&amp;lt;main&amp;gt;");
9005 }
9006
9007 /* Popup the menu when the popup button is pressed */
9008 static gint popup_cb(GtkWidget *widget, GdkEvent *event, GtkWidget *menu)
9009 {
9010    GdkEventButton *bevent = (GdkEventButton *)event;
9011   
9012    /* Only take button presses */
9013    if(event-&amp;gt;type != GDK_BUTTON_PRESS)
9014      return FALSE;
9015   
9016    /* Show the menu */
9017    gtk_menu_popup(GTK_MENU(menu), NULL, NULL,
9018                   NULL, NULL, bevent-&amp;gt;button, bevent-&amp;gt;time);
9019   
9020    return TRUE;
9021 }
9022
9023 /* Same as with get_menubar_menu() but just return a button with a signal to
9024    call a popup menu */
9025 GtkWidget *get_popup_menu(void)
9026 {
9027    GtkItemFactory *item_factory;
9028    GtkWidget *button, *menu;
9029   
9030    /* Same as before but don't bother with the accelerators */
9031    item_factory = gtk_item_factory_new (GTK_TYPE_MENU, "&amp;lt;main&amp;gt;",
9032                                         NULL);
9033    gtk_item_factory_create_items (item_factory, nmenu_items, menu_items, NULL);
9034    menu = gtk_item_factory_get_widget(item_factory, "&amp;lt;main&amp;gt;");
9035   
9036    /* Make a button to activate the popup menu */
9037    button = gtk_button_new_with_label("Popup");
9038    /* Make the menu popup when clicked */
9039    g_signal_connect(G_OBJECT(button),
9040                     "event",
9041                     G_CALLBACK(popup_cb),
9042                     (gpointer) menu);
9043
9044    return button;
9045 }
9046
9047 /* Same again but return an option menu */
9048 GtkWidget *get_option_menu(void)
9049 {
9050    GtkItemFactory *item_factory;
9051    GtkWidget *option_menu;
9052   
9053    /* Same again, not bothering with the accelerators */
9054    item_factory = gtk_item_factory_new (GTK_TYPE_OPTION_MENU, "&amp;lt;main&amp;gt;",
9055                                         NULL);
9056    gtk_item_factory_create_items (item_factory, nmenu_items, menu_items, NULL);
9057    option_menu = gtk_item_factory_get_widget(item_factory, "&amp;lt;main&amp;gt;");
9058
9059    return option_menu;
9060 }
9061
9062 /* You have to start somewhere */
9063 int main( int argc,
9064           char *argv[] )
9065 {
9066   GtkWidget *window;
9067   GtkWidget *main_vbox;
9068   GtkWidget *menubar, *option_menu, *popup_button;
9069  
9070   /* Initialize GTK */
9071   gtk_init (&amp;argc, &amp;argv);
9072  
9073   /* Make a window */
9074   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
9075   g_signal_connect (G_OBJECT (window), "destroy",
9076                     G_CALLBACK (gtk_main_quit),
9077                     NULL);
9078   gtk_window_set_title (GTK_WINDOW(window), "Item Factory");
9079   gtk_widget_set_size_request (GTK_WIDGET(window), 300, 200);
9080  
9081   /* Make a vbox to put the three menus in */
9082   main_vbox = gtk_vbox_new (FALSE, 1);
9083   gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 1);
9084   gtk_container_add (GTK_CONTAINER (window), main_vbox);
9085  
9086   /* Get the three types of menu */
9087   /* Note: all three menus are separately created, so they are not the
9088      same menu */
9089   menubar = get_menubar_menu (window);
9090   popup_button = get_popup_menu();
9091   option_menu = get_option_menu();
9092   
9093   /* Pack it all together */
9094   gtk_box_pack_start (GTK_BOX (main_vbox), menubar, FALSE, TRUE, 0);
9095   gtk_box_pack_end (GTK_BOX (main_vbox), popup_button, FALSE, TRUE, 0);
9096   gtk_box_pack_end (GTK_BOX (main_vbox), option_menu, FALSE, TRUE, 0);
9097
9098   /* Show the widgets */
9099   gtk_widget_show_all (window);
9100   
9101   /* Finished! */
9102   gtk_main ();
9103  
9104   return(0);
9105 }
9106 /* example-end */
9107 </programlisting>
9108
9109 </sect1>
9110 </chapter>
9111
9112 <!-- ***************************************************************** -->
9113 <chapter id="ch-UndocWidgets">
9114 <title>Undocumented Widgets</title>
9115
9116 <para>These all require authors! :) Please consider contributing to our
9117 tutorial.</para>
9118
9119 <para>If you must use one of these widgets that are undocumented, I strongly
9120 suggest you take a look at their respective header files in the GTK
9121 distribution. GTK's function names are very descriptive. Once you
9122 have an understanding of how things work, it's not difficult to figure
9123 out how to use a widget simply by looking at its function
9124 declarations. This, along with a few examples from others' code, and
9125 it should be no problem.</para>
9126
9127 <para>When you do come to understand all the functions of a new undocumented
9128 widget, please consider writing a tutorial on it so others may benefit
9129 from your time.</para>
9130
9131 <!-- ----------------------------------------------------------------- -->
9132 <sect1 id="sec-AccelLabel">
9133 <title>Accel Label</title>
9134
9135 <para></para>
9136
9137 </sect1>
9138
9139 <!-- ----------------------------------------------------------------- -->
9140 <sect1 id="sec-OptionMenu">
9141 <title>Option Menu</title>
9142
9143 <para></para>
9144
9145 </sect1>
9146
9147 <!-- ----------------------------------------------------------------- -->
9148 <sect1 id="sec-MenuItems">
9149 <title>Menu Items</title>
9150
9151 <para></para>
9152
9153 <sect2 id="sec-CheckMenuItem">
9154 <title>Check Menu Item</title>
9155
9156 <para></para>
9157 </sect2>
9158
9159 <sect2 id="sec-RadioMenuItem">
9160 <title>Radio Menu Item</title>
9161
9162 <para></para>
9163 </sect2>
9164
9165 <sect2 id="sec-SeparatorMenuItem">
9166 <title>Separator Menu Item</title>
9167
9168 <para></para>
9169 </sect2>
9170
9171 <sect2 id="sec-TearoffMenuItem">
9172 <title>Tearoff Menu Item</title>
9173
9174 <para></para>
9175 </sect2>
9176 </sect1>
9177
9178 <!-- ----------------------------------------------------------------- -->
9179 <sect1 id="sec-Curves">
9180 <title>Curves</title>
9181
9182 <para></para>
9183
9184 </sect1>
9185
9186 <!-- ----------------------------------------------------------------- -->
9187 <sect1 id="sec-DrawingArea">
9188 <title>Drawing Area</title>
9189
9190 <para></para>
9191
9192 </sect1>
9193
9194 <!-- ----------------------------------------------------------------- -->
9195 <sect1 id="sec-FontSelectionDialog">
9196 <title>Font Selection Dialog</title>
9197
9198 <para></para>
9199
9200 </sect1>
9201
9202 <!-- ----------------------------------------------------------------- -->
9203 <sect1 id="sec-MessageDialog">
9204 <title>Message Dialog</title>
9205
9206 <para></para>
9207
9208 </sect1>
9209
9210 <!-- ----------------------------------------------------------------- -->
9211 <sect1 id="sec-GammaCurve">
9212 <title>Gamma Curve</title>
9213
9214 <para></para>
9215
9216 </sect1>
9217
9218 <!-- ----------------------------------------------------------------- -->
9219 <sect1 id="sec-Image">
9220 <title>Image</title>
9221
9222 <para></para>
9223
9224 </sect1>
9225
9226 <!-- ----------------------------------------------------------------- -->
9227 <sect1 id="sec-PlugsAndSockets">
9228 <title>Plugs and Sockets</title>
9229
9230 <para></para>
9231
9232 </sect1>
9233
9234 <!-- ----------------------------------------------------------------- -->
9235 <sect1 id="sec-TreeView">
9236 <title>Tree View</title>
9237
9238 <para></para>
9239
9240 </sect1>
9241
9242 <!-- ----------------------------------------------------------------- -->
9243 <sect1 id="sec-TextView">
9244 <title>Text View</title>
9245
9246 <para></para>
9247
9248 </sect1>
9249 </chapter>
9250
9251 <!-- ***************************************************************** -->
9252 <chapter id="ch-SettingWidgetAttributes">
9253 <title>Setting Widget Attributes</title>
9254
9255 <para>This describes the functions used to operate on widgets. These can be
9256 used to set style, padding, size, etc.</para>
9257
9258 <para>(Maybe I should make a whole section on accelerators.)</para>
9259
9260 <programlisting role="C">
9261 void gtk_widget_activate( GtkWidget *widget );
9262
9263 void gtk_widget_set_name( GtkWidget *widget,
9264                           gchar     *name );
9265
9266 gchar *gtk_widget_get_name( GtkWidget *widget );
9267
9268 void gtk_widget_set_sensitive( GtkWidget *widget,
9269                                gboolean   sensitive );
9270
9271 void gtk_widget_set_style( GtkWidget *widget,
9272                            GtkStyle  *style );
9273                                            
9274 GtkStyle *gtk_widget_get_style( GtkWidget *widget );
9275
9276 GtkStyle *gtk_widget_get_default_style( void );
9277
9278 void gtk_widget_set_size_request ( GtkWidget *widget,
9279                                    gint       width,
9280                                    gint       height );
9281
9282 void gtk_widget_grab_focus( GtkWidget *widget );
9283
9284 void gtk_widget_show( GtkWidget *widget );
9285
9286 void gtk_widget_hide( GtkWidget *widget );
9287 </programlisting>
9288
9289 </chapter>
9290
9291 <!-- ***************************************************************** -->
9292 <chapter id="ch-Timeouts">
9293 <title>Timeouts, IO and Idle Functions</title>
9294
9295 <!-- ----------------------------------------------------------------- -->
9296 <sect1 id="sec-Timeouts">
9297 <title>Timeouts</title>
9298
9299 <para>You may be wondering how you make GTK do useful work when in gtk_main.
9300 Well, you have several options. Using the following function you can
9301 create a timeout function that will be called every "interval"
9302 milliseconds.</para>
9303
9304 <programlisting role="C">
9305 gint gtk_timeout_add( guint32     interval,
9306                       GtkFunction function,
9307                       gpointer    data );
9308 </programlisting>
9309
9310 <para>The first argument is the number of milliseconds between calls to your
9311 function. The second argument is the function you wish to have called,
9312 and the third, the data passed to this callback function. The return
9313 value is an integer "tag" which may be used to stop the timeout by
9314 calling:</para>
9315
9316 <programlisting role="C">
9317 void gtk_timeout_remove( gint tag );
9318 </programlisting>
9319
9320 <para>You may also stop the timeout function by returning zero or FALSE from
9321 your callback function. Obviously this means if you want your function
9322 to continue to be called, it should return a non-zero value,
9323 i.e., TRUE.</para>
9324
9325 <para>The declaration of your callback should look something like this:</para>
9326
9327 <programlisting role="C">
9328 gint timeout_callback( gpointer data );
9329 </programlisting>
9330
9331 </sect1>
9332
9333 <!-- ----------------------------------------------------------------- -->
9334 <sect1 id="sec-MonitoringIO">
9335 <title>Monitoring IO</title>
9336
9337 <para>A nifty feature of GDK (the library that underlies GTK), is the
9338 ability to have it check for data on a file descriptor for you (as
9339 returned by open(2) or socket(2)). This is especially useful for
9340 networking applications. The function:</para>
9341
9342 <programlisting role="C">
9343 gint gdk_input_add( gint              source,
9344                     GdkInputCondition condition,
9345                     GdkInputFunction  function,
9346                     gpointer          data );
9347 </programlisting>
9348
9349 <para>Where the first argument is the file descriptor you wish to have
9350 watched, and the second specifies what you want GDK to look for. This
9351 may be one of:</para>
9352
9353 <itemizedlist>
9354 <listitem><simpara><literal>GDK_INPUT_READ</literal> - Call your function when there is data
9355 ready for reading on your file descriptor.</simpara>
9356 </listitem>
9357
9358 <listitem><simpara>><literal>GDK_INPUT_WRITE</literal> - Call your function when the file
9359 descriptor is ready for writing.</simpara>
9360 </listitem>
9361 </itemizedlist>
9362
9363 <para>As I'm sure you've figured out already, the third argument is the
9364 function you wish to have called when the above conditions are
9365 satisfied, and the fourth is the data to pass to this function.</para>
9366
9367 <para>The return value is a tag that may be used to stop GDK from monitoring
9368 this file descriptor using the following function.</para>
9369
9370 <programlisting role="C">
9371 void gdk_input_remove( gint tag );
9372 </programlisting>
9373
9374 <para>The callback function should be declared as:</para>
9375
9376 <programlisting role="C">
9377 void input_callback( gpointer          data,
9378                      gint              source, 
9379                      GdkInputCondition condition );
9380 </programlisting>
9381
9382 <para>Where <literal>source</literal> and <literal>condition</literal> are as specified above.</para>
9383
9384 </sect1>
9385
9386 <!-- ----------------------------------------------------------------- -->
9387 <sect1 id="sec-IdleFunctions">
9388 <title>Idle Functions</title>
9389
9390 <para><!-- TODO: Need to check on idle priorities - TRG -->
9391 What if you have a function which you want to be called when nothing
9392 else is happening ?</para>
9393
9394 <programlisting role="C">
9395 gint gtk_idle_add( GtkFunction function,
9396                    gpointer    data );
9397 </programlisting>
9398
9399 <para>This causes GTK to call the specified function whenever nothing else
9400 is happening.</para>
9401
9402 <programlisting role="C">
9403 void gtk_idle_remove( gint tag );
9404 </programlisting>
9405
9406 <para>I won't explain the meaning of the arguments as they follow very much
9407 like the ones above. The function pointed to by the first argument to
9408 gtk_idle_add will be called whenever the opportunity arises. As with
9409 the others, returning FALSE will stop the idle function from being
9410 called.</para>
9411
9412 </sect1>
9413 </chapter>
9414
9415 <!-- ***************************************************************** -->
9416 <chapter id="ch-AdvancedEventsAndSignals">
9417 <title>Advanced Event and Signal Handling</title>
9418
9419 <!-- ----------------------------------------------------------------- -->
9420 <sect1 id="sec-SignalFunctions">
9421 <title>Signal Functions</title>
9422
9423 <!-- ----------------------------------------------------------------- -->
9424 <sect2>
9425 <title>Connecting and Disconnecting Signal Handlers</title>
9426
9427 <programlisting role="C">
9428 gulong g_signal_connect( GObject     *object,
9429                          const gchar *name,
9430                          GCallback    func,
9431                          gpointer     func_data );
9432
9433 gulong g_signal_connect_after( GObject       *object,
9434                                const gchar   *name,
9435                                GCallback      func,
9436                                gpointer       func_data );
9437
9438 gulong g_signal_connect_swapped( GObject       *object,
9439                                  const gchar   *name,
9440                                  GCallback      func,
9441                                  GObject       *slot_object );
9442
9443 void g_signal_handler_disconnect( GObject *object,
9444                                   gulong   handler_id );
9445
9446 void g_signal_handlers_disconnect_by_func( GObject   *object,
9447                                            GCallback  func,
9448                                            gpointer   data );
9449 </programlisting>
9450
9451 </sect2>
9452
9453 <!-- ----------------------------------------------------------------- -->
9454 <sect2>
9455 <title>Blocking and Unblocking Signal Handlers</title>
9456
9457 <programlisting role="C">
9458 void g_signal_handler_block( GObject *object,
9459                              gulong   handler_id);
9460
9461 void g_signal_handlers_block_by_func( GObject   *object,
9462                                       GCallback  func,
9463                                       gpointer   data );
9464
9465 void g_signal_handler_unblock( GObject *object,
9466                                gulong   handler_id );
9467
9468 void g_signal_handler_unblock_by_func( GObject   *object,
9469                                        GCallback  func,
9470                                        gpointer   data );
9471 </programlisting>
9472
9473 </sect2>
9474
9475 <!-- ----------------------------------------------------------------- -->
9476 <sect2>
9477 <title>Emitting and Stopping Signals</title>
9478
9479 <programlisting role="C">
9480 void g_signal_emit( GObject *object,
9481                     guint      signal_id,
9482                     ... );
9483
9484 void g_signal_emit_by_name( GObject     *object,
9485                             const gchar *name,
9486                             ... );
9487
9488 void g_signal_emitv( const GValue *instance_and_params,
9489                      guint         signal_id,
9490                      GQuark        detail,
9491                      GValue       *return_value );
9492
9493 void g_signal_stop_emission( GObject *object,
9494                              guint    signal_id,
9495                              GQuark   detail );
9496
9497 void g_signal_stop_emission_by_name( GObject   *object,
9498                                      const gchar *detailed_signal );
9499 </programlisting>
9500
9501 </sect2>
9502 </sect1>
9503
9504 <!-- ----------------------------------------------------------------- -->
9505 <sect1 id="sec-SignalEmissionAndPropagation">
9506 <title>Signal Emission and Propagation</title>
9507
9508 <para>Signal emission is the process whereby GTK runs all handlers for a
9509 specific object and signal.</para>
9510
9511 <para>First, note that the return value from a signal emission is the return
9512 value of the <emphasis>last</emphasis> handler executed. Since event signals are
9513 all of type <literal>GTK_RUN_LAST</literal>, this will be the default (GTK supplied)
9514 handler, unless you connect with gtk_signal_connect_after().</para>
9515
9516 <para>The way an event (say "button_press_event") is handled, is:</para>
9517
9518 <itemizedlist>
9519 <listitem><simpara>Start with the widget where the event occured.</simpara>
9520 </listitem>
9521
9522 <listitem><simpara>Emit the generic "event" signal. If that signal handler returns
9523 a value of TRUE, stop all processing.</simpara>
9524 </listitem>
9525
9526 <listitem><simpara>Otherwise, emit a specific, "button_press_event" signal. If that
9527 returns TRUE, stop all processing.</simpara>
9528 </listitem>
9529
9530 <listitem><simpara>Otherwise, go to the widget's parent, and repeat the above two
9531 steps.</simpara>
9532 </listitem>
9533
9534 <listitem><simpara>Continue until some signal handler returns TRUE, or until the
9535 top-level widget is reached.</simpara>
9536 </listitem>
9537 </itemizedlist>
9538
9539 <para>Some consequences of the above are:</para>
9540
9541 <itemizedlist>
9542 <listitem><simpara>Your handler's return value will have no effect if there is a
9543 default handler, unless you connect with gtk_signal_connect_after().</simpara>
9544 </listitem>
9545
9546 <listitem><simpara>To prevent the default handler from being run, you need to
9547 connect with gtk_signal_connect() and use
9548 gtk_signal_emit_stop_by_name() - the return value only affects whether
9549 the signal is propagated, not the current emission.</simpara>
9550 </listitem>
9551 </itemizedlist>
9552
9553 </sect1>
9554 </chapter>
9555
9556 <!-- continue GTK+ 2.0 review here -->
9557
9558 <!-- ***************************************************************** -->
9559 <chapter id="ch-ManagingSelections">
9560 <title>Managing Selections</title>
9561
9562 <!-- ----------------------------------------------------------------- -->
9563 <sect1 id="sec-SelectionsOverview">
9564 <title>Overview</title>
9565
9566 <para>One type of interprocess communication supported by X and GTK is
9567 <emphasis>selections</emphasis>. A selection identifies a chunk of data, for
9568 instance, a portion of text, selected by the user in some fashion, for
9569 instance, by dragging with the mouse. Only one application on a
9570 display (the <emphasis>owner</emphasis>) can own a particular selection at one
9571 time, so when a selection is claimed by one application, the previous
9572 owner must indicate to the user that selection has been
9573 relinquished. Other applications can request the contents of a
9574 selection in different forms, called <emphasis>targets</emphasis>. There can be
9575 any number of selections, but most X applications only handle one, the
9576 <emphasis>primary selection</emphasis>.</para>
9577
9578 <para>In most cases, it isn't necessary for a GTK application to deal with
9579 selections itself. The standard widgets, such as the Entry widget,
9580 already have the capability to claim the selection when appropriate
9581 (e.g., when the user drags over text), and to retrieve the contents of
9582 the selection owned by another widget or another application (e.g.,
9583 when the user clicks the second mouse button). However, there may be
9584 cases in which you want to give other widgets the ability to supply
9585 the selection, or you wish to retrieve targets not supported by
9586 default.</para>
9587
9588 <para>A fundamental concept needed to understand selection handling is that
9589 of the <emphasis>atom</emphasis>. An atom is an integer that uniquely identifies a
9590 string (on a certain display). Certain atoms are predefined by the X
9591 server, and in some cases there are constants in <literal>gtk.h</literal>
9592 corresponding to these atoms. For instance the constant
9593 <literal>GDK_PRIMARY_SELECTION</literal> corresponds to the string "PRIMARY".
9594 In other cases, you should use the functions
9595 <literal>gdk_atom_intern()</literal>, to get the atom corresponding to a string,
9596 and <literal>gdk_atom_name()</literal>, to get the name of an atom. Both
9597 selections and targets are identified by atoms.</para>
9598
9599 </sect1>
9600 <!-- ----------------------------------------------------------------- -->
9601 <sect1 id="sec-RetrievingTheSelection">
9602 <title>Retrieving the selection</title>
9603
9604 <para>Retrieving the selection is an asynchronous process. To start the
9605 process, you call:</para>
9606
9607 <programlisting role="C">
9608 gboolean gtk_selection_convert( GtkWidget *widget, 
9609                                 GdkAtom    selection, 
9610                                 GdkAtom    target,
9611                                 guint32    time );
9612 </programlisting>
9613
9614 <para>This <emphasis>converts</emphasis> the selection into the form specified by
9615 <literal>target</literal>. If at all possible, the time field should be the time
9616 from the event that triggered the selection. This helps make sure that
9617 events occur in the order that the user requested them. However, if it
9618 is not available (for instance, if the conversion was triggered by a
9619 "clicked" signal), then you can use the constant
9620 <literal>GDK_CURRENT_TIME</literal>.</para>
9621
9622 <para>When the selection owner responds to the request, a
9623 "selection_received" signal is sent to your application. The handler
9624 for this signal receives a pointer to a <literal>GtkSelectionData</literal>
9625 structure, which is defined as:</para>
9626
9627 <programlisting role="C">
9628 struct _GtkSelectionData
9629 {
9630   GdkAtom selection;
9631   GdkAtom target;
9632   GdkAtom type;
9633   gint    format;
9634   guchar *data;
9635   gint    length;
9636 };
9637 </programlisting>
9638
9639 <para><literal>selection</literal> and <literal>target</literal> are the values you gave in your
9640 <literal>gtk_selection_convert()</literal> call. <literal>type</literal> is an atom that
9641 identifies the type of data returned by the selection owner. Some
9642 possible values are "STRING", a string of latin-1 characters, "ATOM",
9643 a series of atoms, "INTEGER", an integer, etc. Most targets can only
9644 return one type. <literal>format</literal> gives the length of the units (for
9645 instance characters) in bits. Usually, you don't care about this when
9646 receiving data. <literal>data</literal> is a pointer to the returned data, and
9647 <literal>length</literal> gives the length of the returned data, in bytes. If
9648 <literal>length</literal> is negative, then an error occurred and the selection
9649 could not be retrieved. This might happen if no application owned the
9650 selection, or if you requested a target that the application didn't
9651 support. The buffer is actually guaranteed to be one byte longer than
9652 <literal>length</literal>; the extra byte will always be zero, so it isn't
9653 necessary to make a copy of strings just to nul-terminate them.</para>
9654
9655 <para>In the following example, we retrieve the special target "TARGETS",
9656 which is a list of all targets into which the selection can be
9657 converted.</para>
9658
9659 <programlisting role="C">
9660 <!-- example-start selection gettargets.c -->
9661
9662 #include &lt;stdlib.h&gt;
9663 #include &lt;gtk/gtk.h&gt;
9664
9665 void selection_received( GtkWidget        *widget, 
9666                          GtkSelectionData *selection_data, 
9667                          gpointer          data );
9668
9669 /* Signal handler invoked when user clicks on the "Get Targets" button */
9670 void get_targets( GtkWidget *widget,
9671                   gpointer data )
9672 {
9673   static GdkAtom targets_atom = GDK_NONE;
9674   GtkWidget *window = (GtkWidget *)data;        
9675
9676   /* Get the atom corresponding to the string "TARGETS" */
9677   if (targets_atom == GDK_NONE)
9678     targets_atom = gdk_atom_intern ("TARGETS", FALSE);
9679
9680   /* And request the "TARGETS" target for the primary selection */
9681   gtk_selection_convert (window, GDK_SELECTION_PRIMARY, targets_atom,
9682                          GDK_CURRENT_TIME);
9683 }
9684
9685 /* Signal handler called when the selections owner returns the data */
9686 void selection_received( GtkWidget        *widget,
9687                          GtkSelectionData *selection_data, 
9688                          gpointer          data )
9689 {
9690   GdkAtom *atoms;
9691   GList *item_list;
9692   int i;
9693
9694   /* **** IMPORTANT **** Check to see if retrieval succeeded  */
9695   if (selection_data-&gt;length &lt; 0)
9696     {
9697       g_print ("Selection retrieval failed\n");
9698       return;
9699     }
9700   /* Make sure we got the data in the expected form */
9701   if (selection_data-&gt;type != GDK_SELECTION_TYPE_ATOM)
9702     {
9703       g_print ("Selection \"TARGETS\" was not returned as atoms!\n");
9704       return;
9705     }
9706   
9707   /* Print out the atoms we received */
9708   atoms = (GdkAtom *)selection_data-&gt;data;
9709
9710   item_list = NULL;
9711   for (i = 0; i &lt; selection_data-&gt;length / sizeof(GdkAtom); i++)
9712     {
9713       char *name;
9714       name = gdk_atom_name (atoms[i]);
9715       if (name != NULL)
9716         g_print ("%s\n",name);
9717       else
9718         g_print ("(bad atom)\n");
9719     }
9720
9721   return;
9722 }
9723
9724 int main( int   argc,
9725           char *argv[] )
9726 {
9727   GtkWidget *window;
9728   GtkWidget *button;
9729   
9730   gtk_init (&amp;argc, &amp;argv);
9731
9732   /* Create the toplevel window */
9733
9734   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
9735   gtk_window_set_title (GTK_WINDOW (window), "Event Box");
9736   gtk_container_set_border_width (GTK_CONTAINER (window), 10);
9737
9738   g_signal_connect (G_OBJECT (window), "destroy",
9739                     G_CALLBACK (exit), NULL);
9740
9741   /* Create a button the user can click to get targets */
9742
9743   button = gtk_button_new_with_label ("Get Targets");
9744   gtk_container_add (GTK_CONTAINER (window), button);
9745
9746   g_signal_connect (G_OBJECT (button), "clicked",
9747                     G_CALLBACK (get_targets), (gpointer) window);
9748   g_signal_connect (G_OBJECT (window), "selection_received",
9749                     G_CALLBACK (selection_received), NULL);
9750
9751   gtk_widget_show (button);
9752   gtk_widget_show (window);
9753   
9754   gtk_main ();
9755   
9756   return 0;
9757 }
9758 <!-- example-end -->
9759 </programlisting>
9760
9761 </sect1>
9762 <!-- ----------------------------------------------------------------- -->
9763 <sect1 id="sec-SupplyingTheSelection">
9764 <title>Supplying the selection</title>
9765
9766 <para>Supplying the selection is a bit more complicated. You must register 
9767 handlers that will be called when your selection is requested. For
9768 each selection/target pair you will handle, you make a call to:</para>
9769
9770 <programlisting role="C">
9771 void gtk_selection_add_target (GtkWidget           *widget, 
9772                                GdkAtom              selection,
9773                                GdkAtom              target,
9774                                guint                info);
9775 </programlisting>
9776
9777 <para><literal>widget</literal>, <literal>selection</literal>, and <literal>target</literal> identify the requests
9778 this handler will manage. When a request for a selection is received,
9779 the "selection_get" signal will be called. <literal>info</literal> can be used as an
9780 enumerator to identify the specific target within the callback function.</para>
9781
9782 <para>The callback function has the signature:</para>
9783
9784 <programlisting role="C">
9785 void  "selection_get" (GtkWidget          *widget,
9786                        GtkSelectionData   *selection_data,
9787                        guint               info,
9788                        guint               time);
9789 </programlisting>
9790
9791 <para>The GtkSelectionData is the same as above, but this time, we're
9792 responsible for filling in the fields <literal>type</literal>, <literal>format</literal>,
9793 <literal>data</literal>, and <literal>length</literal>. (The <literal>format</literal> field is actually
9794 important here - the X server uses it to figure out whether the data
9795 needs to be byte-swapped or not. Usually it will be 8 - <emphasis>i.e.</emphasis> a
9796 character - or 32 - <emphasis>i.e.</emphasis> an integer.) This is done by calling the
9797 function:</para>
9798
9799 <programlisting role="C">
9800 void gtk_selection_data_set( GtkSelectionData *selection_data,
9801                              GdkAtom           type,
9802                              gint              format,
9803                              guchar           *data,
9804                              gint              length );
9805 </programlisting>
9806
9807 <para>This function takes care of properly making a copy of the data so that
9808 you don't have to worry about keeping it around. (You should not fill
9809 in the fields of the GtkSelectionData structure by hand.)</para>
9810
9811 <para>When prompted by the user, you claim ownership of the selection by
9812 calling:</para>
9813
9814 <programlisting role="C">
9815 gboolean gtk_selection_owner_set( GtkWidget *widget,
9816                                   GdkAtom    selection,
9817                                   guint32    time );
9818 </programlisting>
9819
9820 <para>If another application claims ownership of the selection, you will
9821 receive a "selection_clear_event".</para>
9822
9823 <para>As an example of supplying the selection, the following program adds
9824 selection functionality to a toggle button. When the toggle button is
9825 depressed, the program claims the primary selection. The only target
9826 supported (aside from certain targets like "TARGETS" supplied by GTK
9827 itself), is the "STRING" target. When this target is requested, a
9828 string representation of the time is returned.</para>
9829
9830 <programlisting role="C">
9831 <!-- example-start selection setselection.c -->
9832
9833 #include &lt;stdlib.h&gt;
9834 #include &lt;gtk/gtk.h&gt;
9835 #include &lt;time.h&gt;
9836 #include &lt;string.h&gt;
9837
9838 GtkWidget *selection_button;
9839 GtkWidget *selection_widget;
9840
9841 /* Callback when the user toggles the selection */
9842 void selection_toggled( GtkWidget *widget,
9843                         gint      *have_selection )
9844 {
9845   if (GTK_TOGGLE_BUTTON (widget)-&gt;active)
9846     {
9847       *have_selection = gtk_selection_owner_set (selection_widget,
9848                                                  GDK_SELECTION_PRIMARY,
9849                                                  GDK_CURRENT_TIME);
9850       /* if claiming the selection failed, we return the button to
9851          the out state */
9852       if (!*have_selection)
9853         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), FALSE);
9854     }
9855   else
9856     {
9857       if (*have_selection)
9858         {
9859           /* Before clearing the selection by setting the owner to NULL,
9860              we check if we are the actual owner */
9861           if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget-&gt;window)
9862             gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY,
9863                                      GDK_CURRENT_TIME);
9864           *have_selection = FALSE;
9865         }
9866     }
9867 }
9868
9869 /* Called when another application claims the selection */
9870 gint selection_clear( GtkWidget         *widget,
9871                       GdkEventSelection *event,
9872                       gint              *have_selection )
9873 {
9874   *have_selection = FALSE;
9875   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (selection_button), FALSE);
9876
9877   return TRUE;
9878 }
9879
9880 /* Supplies the current time as the selection. */
9881 void selection_handle( GtkWidget        *widget, 
9882                        GtkSelectionData *selection_data,
9883                        guint             info,
9884                        guint             time_stamp,
9885                        gpointer          data )
9886 {
9887   gchar *timestr;
9888   time_t current_time;
9889
9890   current_time = time (NULL);
9891   timestr = asctime (localtime (&amp;current_time)); 
9892   /* When we return a single string, it should not be null terminated.
9893      That will be done for us */
9894
9895   gtk_selection_data_set (selection_data, GDK_SELECTION_TYPE_STRING,
9896                           8, timestr, strlen (timestr));
9897 }
9898
9899 int main( int   argc,
9900           char *argv[] )
9901 {
9902   GtkWidget *window;
9903
9904   static int have_selection = FALSE;
9905   
9906   gtk_init (&amp;argc, &amp;argv);
9907
9908   /* Create the toplevel window */
9909
9910   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
9911   gtk_window_set_title (GTK_WINDOW (window), "Event Box");
9912   gtk_container_set_border_width (GTK_CONTAINER (window), 10);
9913
9914   g_signal_connect (G_OBJECT (window), "destroy",
9915                     G_CALLBACK (exit), NULL);
9916
9917   /* Create a toggle button to act as the selection */
9918
9919   selection_widget = gtk_invisible_new ();
9920   selection_button = gtk_toggle_button_new_with_label ("Claim Selection");
9921   gtk_container_add (GTK_CONTAINER (window), selection_button);
9922   gtk_widget_show (selection_button);
9923
9924   g_signal_connect (G_OBJECT (selection_button), "toggled",
9925                     G_CALLBACK (selection_toggled), (gpointer) &amp;have_selection);
9926   g_signal_connect (G_OBJECT (selection_widget), "selection_clear_event",
9927                     G_CALLBACK (selection_clear), (gpointer) &amp;have_selection);
9928
9929   gtk_selection_add_target (selection_widget,
9930                             GDK_SELECTION_PRIMARY,
9931                             GDK_SELECTION_TYPE_STRING,
9932                             1);
9933   g_signal_connect (G_OBJECT (selection_widget), "selection_get",
9934                     G_CALLBACK (selection_handle), (gpointer) &amp;have_selection);
9935
9936   gtk_widget_show (selection_button);
9937   gtk_widget_show (window);
9938   
9939   gtk_main ();
9940   
9941   return 0;
9942 }
9943 <!-- example-end -->
9944 </programlisting>
9945
9946 </sect1>
9947 </chapter>
9948
9949 <!-- ***************************************************************** -->
9950 <chapter id="ch-DragAngDrop">
9951 <title>Drag-and-drop (DND)</title>
9952
9953 <para>GTK+ has a high level set of functions for doing inter-process
9954 communication via the drag-and-drop system. GTK+ can perform
9955 drag-and-drop on top of the low level Xdnd and Motif drag-and-drop
9956 protocols.</para>
9957
9958 <!-- ----------------------------------------------------------------- -->
9959 <sect1 id="sec-DragAndDropOverview">
9960 <title>Overview</title>
9961
9962 <para>An application capable of GTK+ drag-and-drop first defines and sets up
9963 the GTK+ widget(s) for drag-and-drop. Each widget can be a source
9964 and/or destination for drag-and-drop. Note that these GTK+ widgets must have
9965 an associated X Window, check using GTK_WIDGET_NO_WINDOW(widget)).</para>
9966
9967 <para>Source widgets can send out drag data, thus allowing the user to drag
9968 things off of them, while destination widgets can receive drag data.
9969 Drag-and-drop destinations can limit who they accept drag data from,
9970 e.g. the same application or any application (including itself).</para>
9971
9972 <para>Sending and receiving drop data makes use of GTK+ signals.
9973 Dropping an item to a destination widget requires both a data
9974 request (for the source widget) and data received signal handler (for
9975 the target widget). Additional signal handers can be connected if you
9976 want to know when a drag begins (at the very instant it starts), to
9977 when a drop is made, and when the entire drag-and-drop procedure has
9978 ended (successfully or not).</para>
9979
9980 <para>Your application will need to provide data for source widgets when
9981 requested, that involves having a drag data request signal handler. For
9982 destination widgets they will need a drop data received signal
9983 handler. </para>
9984
9985 <para>So a typical drag-and-drop cycle would look as follows:</para>
9986 <orderedlist>
9987 <listitem><simpara> Drag begins.</simpara>
9988 </listitem>
9989 <listitem><simpara> Drag data request (when a drop occurs).</simpara>
9990 </listitem>
9991 <listitem><simpara> Drop data received (may be on same or different
9992 application).</simpara>
9993 </listitem>
9994 <listitem><simpara> Drag data delete (if the drag was a move).</simpara>
9995 </listitem>
9996 <listitem><simpara> Drag-and-drop procedure done.</simpara>
9997 </listitem>
9998 </orderedlist>
9999
10000 <para>There are a few minor steps that go in between here and there, but we
10001 will get into detail about that later.</para>
10002
10003 </sect1>
10004
10005 <!-- ----------------------------------------------------------------- -->
10006 <sect1 id="sec-DragAndDropProperties">
10007 <title>Properties</title>
10008
10009 <para>Drag data has the following properties:</para>
10010
10011 <itemizedlist>
10012 <listitem><simpara> Drag action type (ie GDK_ACTION_COPY, GDK_ACTION_MOVE).</simpara>
10013 </listitem>
10014
10015 <listitem><simpara> Client specified arbitrary drag-and-drop type (a name and number pair).</simpara>
10016 </listitem>
10017
10018 <listitem><simpara> Sent and received data format type.</simpara>
10019 </listitem>
10020 </itemizedlist>
10021
10022 <para>Drag actions are quite obvious, they specify if the widget can
10023 drag with the specified action(s), e.g. GDK_ACTION_COPY and/or
10024 GDK_ACTION_MOVE. A GDK_ACTION_COPY would be a typical drag-and-drop
10025 without the source data being deleted while GDK_ACTION_MOVE would be
10026 just like GDK_ACTION_COPY but the source data will be 'suggested' to be
10027 deleted after the received signal handler is called. There are
10028 additional drag actions including GDK_ACTION_LINK which you may want to
10029 look into when you get to more advanced levels of drag-and-drop.</para>
10030
10031 <para>The client specified arbitrary drag-and-drop type is much more
10032 flexible, because your application will be defining and checking for
10033 that specifically. You will need to set up your destination widgets to
10034 receive certain drag-and-drop types by specifying a name and/or number.
10035 It would be more reliable to use a name since another application may
10036 just happen to use the same number for an entirely different
10037 meaning.</para>
10038
10039 <para>Sent and received data format types (<emphasis>selection
10040 target</emphasis>) come into play only in your request and received
10041 data handler functions. The term <emphasis>selection target</emphasis>
10042 is somewhat misleading. It is a term adapted from GTK+ selection
10043 (cut/copy and paste). What <emphasis>selection target</emphasis>
10044 actually means is the data's format type (i.e. GdkAtom, integer, or
10045 string) that being sent or received. Your request data handler function
10046 needs to specify the type (<emphasis>selection target</emphasis>) of
10047 data that it sends out and your received data handler needs to handle
10048 the type (<emphasis>selection target</emphasis>) of data
10049 received.</para>
10050
10051 </sect1>
10052
10053 <!-- ----------------------------------------------------------------- -->
10054 <sect1 id="sec-DragAndDropFunctions">
10055 <title>Functions</title>
10056
10057 <!-- ----------------------------------------------------------------- -->
10058 <sect2 id="sec-DNDSourceWidgets">
10059 <title>Setting up the source widget</title>
10060
10061 <para>The function <literal>gtk_drag_source_set()</literal> specifies a
10062 set of target types for a drag operation on a widget.</para>
10063
10064 <programlisting role="C">
10065 void gtk_drag_source_set( GtkWidget            *widget,
10066                           GdkModifierType       start_button_mask,
10067                           const GtkTargetEntry *targets,
10068                           gint                  n_targets,
10069                           GdkDragAction         actions );
10070 </programlisting>
10071
10072 <para>The parameters signify the following:</para>
10073 <itemizedlist>
10074 <listitem><simpara><literal>widget</literal> specifies the drag source
10075 widget</simpara>
10076 </listitem>
10077 <listitem><simpara><literal>start_button_mask</literal> specifies a
10078 bitmask of buttons that can start the drag (e.g. GDK_BUTTON1_MASK)</simpara>
10079 </listitem>
10080 <listitem><simpara><literal>targets</literal> specifies a table of
10081 target data types the drag will support</simpara>
10082 </listitem>
10083 <listitem><simpara><literal>n_targets</literal> specifies the number of
10084 targets above</simpara>
10085 </listitem>
10086 <listitem><simpara><literal>actions</literal> specifies a bitmask of
10087 possible actions for a drag from this window</simpara>
10088 </listitem>
10089 </itemizedlist>
10090
10091 <para>The <literal>targets</literal> parameter is an array of the
10092 following structure:</para>
10093
10094 <programlisting role="C">
10095 struct GtkTargetEntry {
10096    gchar *target;
10097    guint  flags;
10098    guint  info;
10099  };
10100 </programlisting>
10101
10102 <para>The fields specify a string representing the drag type, optional
10103 flags and application assigned integer identifier.</para>
10104
10105 <para>If a widget is no longer required to act as a source for
10106 drag-and-drop operations, the function
10107 <literal>gtk_drag_source_unset()</literal> can be used to remove a set
10108 of drag-and-drop target types.</para>
10109
10110 <programlisting role="C">
10111 void gtk_drag_source_unset( GtkWidget *widget );
10112 </programlisting>
10113
10114 </sect2>
10115
10116 <!-- ----------------------------------------------------------------- -->
10117 <sect2 id="sec-SignalsOnSourceWidgets">
10118 <title>Signals on the source widget:</title>
10119
10120 <para>The source widget is sent the following signals during a
10121 drag-and-drop operation.</para>
10122
10123 <table pgwide="1">
10124 <title>Source widget signals</title>
10125 <tgroup cols="2">
10126 <colspec colname="Name" colwidth="150">
10127 <colspec colname="Prototype">
10128 <tbody>
10129 <row>
10130 <entry align="left" valign="middle">drag_begin</entry>
10131 <entry align="left" valign="middle"><literal>void (*drag_begin)(GtkWidget *widget,
10132 GdkDragContext *dc, gpointer data)</literal></entry>
10133 </row>
10134 <row>
10135 <entry align="left" valign="middle">drag_motion</entry>
10136 <entry align="left" valign="middle"><literal>gboolean (*drag_motion)(GtkWidget *widget,
10137 GdkDragContext *dc, gint x, gint y, guint t, gpointer data)</literal></entry>
10138 </row>
10139 <row>
10140 <entry align="left" valign="middle">drag_data_get</entry>
10141 <entry align="left" valign="middle"><literal>void (*drag_data_get)(GtkWidget *widget,
10142 GdkDragContext *dc, GtkSelectionData *selection_data, guint info, guint t, gpointer data)</literal></entry>
10143 </row>
10144 <row>
10145 <entry align="left" valign="middle">drag_data_delete</entry>
10146 <entry align="left" valign="middle"><literal>void (*drag_data_delete)(GtkWidget *widget,
10147 GdkDragContext *dc, gpointer data)</literal></entry>
10148 </row>
10149 <row>
10150 <entry align="left" valign="middle">drag_drop</entry>
10151 <entry align="left" valign="middle"><literal>gboolean (*drag_drop)(GtkWidget *widget,
10152 GdkDragContext *dc, gint x, gint y, guint t, gpointer data)</literal></entry>
10153 </row>
10154 <row>
10155 <entry align="left" valign="middle">drag_end</entry>
10156 <entry align="left" valign="middle"><literal>void (*drag_end)(GtkWidget *widget,
10157 GdkDragContext *dc, gpointer data)</literal></entry>
10158 </row>
10159 </tbody>
10160 </tgroup>
10161 </table>
10162
10163 </sect2>
10164
10165 <!-- ----------------------------------------------------------------- -->
10166 <sect2 id="sec-DNDDestWidgets">
10167 <title>Setting up a destination widget:</title>
10168
10169 <para> <literal> gtk_drag_dest_set()</literal> specifies
10170 that this widget can receive drops and specifies what types of drops it
10171 can receive.</para>
10172
10173 <para> <literal> gtk_drag_dest_unset()</literal> specifies
10174 that the widget can no longer receive drops.</para>
10175
10176 <programlisting role="C">
10177 void gtk_drag_dest_set( GtkWidget            *widget,
10178                         GtkDestDefaults       flags,
10179                         const GtkTargetEntry *targets,
10180                         gint                  n_targets,
10181                         GdkDragAction         actions );
10182
10183 void gtk_drag_dest_unset( GtkWidget *widget );
10184 </programlisting>
10185
10186 </sect2>
10187
10188 <!-- ----------------------------------------------------------------- -->
10189 <sect2 id="sec-SignalsOnDestWidgets">
10190 <title>Signals on the destination widget:</title>
10191
10192 <para>The destination widget is sent the following signals during a
10193 drag-and-drop operation.</para>
10194
10195 <table pgwide="1">
10196 <title>Destination widget signals</title>
10197 <tgroup cols="2">
10198 <colspec colname="Name" colwidth="150">
10199 <colspec colname="Prototype">
10200 <tbody>
10201 <row>
10202 <entry align="left" valign="middle">drag_data_received</entry>
10203 <entry align="left" valign="middle"><literal>void (*drag_data_received)(GtkWidget *widget,
10204 GdkDragContext *dc, gint x, gint y, GtkSelectionData *selection_data, guint info, guint t,
10205 gpointer data)</literal></entry>
10206 </row>
10207 </tbody>
10208 </tgroup>
10209 </table>
10210
10211 </sect2>
10212 </sect1>
10213 </chapter>
10214
10215 <!-- ***************************************************************** -->
10216 <chapter id="ch-GLib">
10217 <title>GLib</title>
10218
10219 <para>GLib is a lower-level library that provides many useful definitions
10220 and functions available for use when creating GDK and GTK
10221 applications. These include definitions for basic types and their
10222 limits, standard macros, type conversions, byte order, memory
10223 allocation, warnings and assertions, message logging, timers, string
10224 utilities, hook functions, a lexical scanner, dynamic loading of
10225 modules, and automatic string completion. A number of data structures
10226 (and their related operations) are also defined, including memory
10227 chunks, doubly-linked lists, singly-linked lists, hash tables, strings
10228 (which can grow dynamically), string chunks (groups of strings),
10229 arrays (which can grow in size as elements are added), balanced binary
10230 trees, N-ary trees, quarks (a two-way association of a string and a
10231 unique integer identifier), keyed data lists (lists of data elements
10232 accessible by a string or integer id), relations and tuples (tables of
10233 data which can be indexed on any number of fields), and caches.</para>
10234
10235 <para>A summary of some of GLib's capabilities follows; not every function,
10236 data structure, or operation is covered here.  For more complete
10237 information about the GLib routines, see the GLib documentation. One
10238 source of GLib documentation is <ulink url="http://www.gtk.org/">http://www.gtk.org/</ulink>.</para>
10239
10240 <para>If you are using a language other than C, you should consult your
10241 language's binding documentation. In some cases your language may
10242 have equivalent functionality built-in, while in other cases it may
10243 not.</para>
10244
10245 <!-- ----------------------------------------------------------------- -->
10246 <sect1 id="sec-Definitions">
10247 <title>Definitions</title>
10248
10249 <para>Definitions for the extremes of many of the standard types are:</para>
10250
10251 <programlisting role="C">
10252 G_MINFLOAT
10253 G_MAXFLOAT
10254 G_MINDOUBLE
10255 G_MAXDOUBLE
10256 G_MINSHORT
10257 G_MAXSHORT
10258 G_MININT
10259 G_MAXINT
10260 G_MINLONG
10261 G_MAXLONG
10262 </programlisting>
10263
10264 <para>Also, the following typedefs. The ones left unspecified are dynamically set
10265 depending on the architecture. Remember to avoid counting on the size of a
10266 pointer if you want to be portable! E.g., a pointer on an Alpha is 8
10267 bytes, but 4 on Intel 80x86 family CPUs.</para>
10268
10269 <programlisting role="C">
10270 char   gchar;
10271 short  gshort;
10272 long   glong;
10273 int    gint;
10274 char   gboolean;
10275
10276 unsigned char   guchar;
10277 unsigned short  gushort;
10278 unsigned long   gulong;
10279 unsigned int    guint;
10280
10281 float   gfloat;
10282 double  gdouble;
10283 long double gldouble;
10284
10285 void* gpointer;
10286
10287 gint8
10288 guint8
10289 gint16
10290 guint16
10291 gint32
10292 guint32
10293 </programlisting>
10294
10295 </sect1>
10296
10297 <!-- ----------------------------------------------------------------- -->
10298 <sect1 id="sec-DoublyLinkedLists">
10299 <title>Doubly Linked Lists</title>
10300
10301 <para>The following functions are used to create, manage, and destroy
10302 standard doubly linked lists. Each element in the list contains a
10303 piece of data, together with pointers which link to the previous and
10304 next elements in the list. This enables easy movement in either
10305 direction through the list. The data item is of type "gpointer",
10306 which means the data can be a pointer to your real data or (through
10307 casting) a numeric value (but do not assume that int and gpointer have
10308 the same size!). These routines internally allocate list elements in
10309 blocks, which is more efficient than allocating elements individually.</para>
10310
10311 <para>There is no function to specifically create a list. Instead, simply
10312 create a variable of type GList* and set its value to NULL; NULL is
10313 considered to be the empty list.</para>
10314
10315 <para>To add elements to a list, use the g_list_append(), g_list_prepend(),
10316 g_list_insert(), or g_list_insert_sorted() routines. In all cases
10317 they accept a pointer to the beginning of the list, and return the
10318 (possibly changed) pointer to the beginning of the list. Thus, for
10319 all of the operations that add or remove elements, be sure to save the
10320 returned value!</para>
10321
10322 <programlisting role="C">
10323 GList *g_list_append( GList    *list,
10324                       gpointer  data );
10325 </programlisting>
10326
10327 <para>This adds a new element (with value <literal>data</literal>) onto the end of the
10328 list.</para>
10329   
10330 <programlisting role="C">
10331 GList *g_list_prepend( GList    *list,
10332                        gpointer  data );
10333 </programlisting>
10334
10335 <para>This adds a new element (with value <literal>data</literal>) to the beginning of the
10336 list.</para>
10337
10338 <programlisting role="C">
10339 GList *g_list_insert( GList    *list,
10340                       gpointer  data,
10341                       gint      position );
10342 </programlisting>
10343
10344 <para>This inserts a new element (with value data) into the list at the
10345 given position. If position is 0, this is just like g_list_prepend();
10346 if position is less than 0, this is just like g_list_append().</para>
10347
10348 <programlisting role="C">
10349 GList *g_list_remove( GList    *list,
10350                       gpointer  data );
10351 </programlisting>
10352
10353 <para>This removes the element in the list with the value <literal>data</literal>;
10354 if the element isn't there, the list is unchanged.</para>
10355
10356 <programlisting role="C">
10357 void g_list_free( GList *list );
10358 </programlisting>
10359
10360 <para>This frees all of the memory used by a GList. If the list elements
10361 refer to dynamically-allocated memory, then they should be freed
10362 first.</para>
10363
10364 <para>There are many other GLib functions that support doubly linked lists;
10365 see the glib documentation for more information.  Here are a few of
10366 the more useful functions' signatures:</para>
10367
10368 <programlisting role="C">  
10369 GList *g_list_remove_link( GList *list,
10370                            GList *link );
10371
10372 GList *g_list_reverse( GList *list );
10373
10374 GList *g_list_nth( GList *list,
10375                    gint   n );
10376                            
10377 GList *g_list_find( GList    *list,
10378                     gpointer  data );
10379
10380 GList *g_list_last( GList *list );
10381
10382 GList *g_list_first( GList *list );
10383
10384 gint g_list_length( GList *list );
10385
10386 void g_list_foreach( GList    *list,
10387                      GFunc     func,
10388                      gpointer  user_data );
10389 </programlisting>
10390
10391 </sect1>
10392
10393 <!-- ----------------------------------------------------------------- -->
10394 <sect1 id="sec-SinglyLinkedLists">
10395 <title>Singly Linked Lists</title>
10396
10397 <para>Many of the above functions for singly linked lists are identical to the
10398 above. Here is a list of some of their operations:</para>
10399
10400 <programlisting role="C">
10401 GSList *g_slist_append( GSList   *list,
10402                         gpointer  data );
10403                 
10404 GSList *g_slist_prepend( GSList   *list,
10405                          gpointer  data );
10406                              
10407 GSList *g_slist_insert( GSList   *list,
10408                         gpointer  data,
10409                         gint      position );
10410                              
10411 GSList *g_slist_remove( GSList   *list,
10412                         gpointer  data );
10413                              
10414 GSList *g_slist_remove_link( GSList *list,
10415                              GSList *link );
10416                              
10417 GSList *g_slist_reverse( GSList *list );
10418
10419 GSList *g_slist_nth( GSList *list,
10420                      gint    n );
10421                              
10422 GSList *g_slist_find( GSList   *list,
10423                       gpointer  data );
10424                              
10425 GSList *g_slist_last( GSList *list );
10426
10427 gint g_slist_length( GSList *list );
10428
10429 void g_slist_foreach( GSList   *list,
10430                       GFunc     func,
10431                       gpointer  user_data );
10432         
10433 </programlisting>
10434
10435 </sect1>
10436
10437 <!-- ----------------------------------------------------------------- -->
10438 <sect1 id="sec-MemoryManagement">
10439 <title>Memory Management</title>
10440
10441 <programlisting role="C">
10442 gpointer g_malloc( gulong size );
10443 </programlisting>
10444
10445 <para>This is a replacement for malloc(). You do not need to check the return
10446 value as it is done for you in this function. If the memory allocation
10447 fails for whatever reasons, your applications will be terminated.</para>
10448
10449 <programlisting role="C">
10450 gpointer g_malloc0( gulong size );
10451 </programlisting>
10452
10453 <para>Same as above, but zeroes the memory before returning a pointer to it.</para>
10454
10455 <programlisting role="C">
10456 gpointer g_realloc( gpointer mem,
10457                     gulong   size );
10458 </programlisting>
10459
10460 <para>Relocates "size" bytes of memory starting at "mem".  Obviously, the
10461 memory should have been previously allocated.</para>
10462
10463 <programlisting role="C">
10464 void g_free( gpointer mem );
10465 </programlisting>
10466
10467 <para>Frees memory. Easy one. If <literal>mem</literal> is NULL it simply returns.</para>
10468
10469 <programlisting role="C">
10470 void g_mem_profile( void );
10471 </programlisting>
10472
10473 <para>Dumps a profile of used memory, but requires that you add <literal>#define
10474 MEM_PROFILE</literal> to the top of glib/gmem.c and re-make and make install.</para>
10475
10476 <programlisting role="C">
10477 void g_mem_check( gpointer mem );
10478 </programlisting>
10479
10480 <para>Checks that a memory location is valid. Requires you add <literal>#define
10481 MEM_CHECK</literal> to the top of gmem.c and re-make and make install.</para>
10482
10483 </sect1>
10484
10485 <!-- ----------------------------------------------------------------- -->
10486 <sect1 id="sec-Timers">
10487 <title>Timers</title>
10488
10489 <para>Timer functions can be used to time operations (e.g., to see how much
10490 time has elapsed). First, you create a new timer with g_timer_new().
10491 You can then use g_timer_start() to start timing an operation,
10492 g_timer_stop() to stop timing an operation, and g_timer_elapsed() to
10493 determine the elapsed time.</para>
10494
10495 <programlisting role="C">
10496 GTimer *g_timer_new( void );
10497
10498 void g_timer_destroy( GTimer *timer );
10499
10500 void g_timer_start( GTimer  *timer );
10501
10502 void g_timer_stop( GTimer  *timer );
10503
10504 void g_timer_reset( GTimer  *timer );
10505
10506 gdouble g_timer_elapsed( GTimer *timer,
10507                          gulong *microseconds );
10508 </programlisting>
10509
10510 </sect1>
10511
10512 <!-- ----------------------------------------------------------------- -->
10513 <sect1 id="sec-StringHandling">
10514 <title>String Handling</title>
10515
10516 <para>GLib defines a new type called a GString, which is similar to a
10517 standard C string but one that grows automatically. Its string data
10518 is null-terminated. What this gives you is protection from buffer
10519 overflow programming errors within your program. This is a very
10520 important feature, and hence I recommend that you make use of
10521 GStrings. GString itself has a simple public definition:</para>
10522
10523 <programlisting role="C">
10524 struct GString 
10525 {
10526   gchar *str; /* Points to the string's current \0-terminated value. */
10527   gint len; /* Current length */
10528 };
10529 </programlisting>
10530
10531 <para>As you might expect, there are a number of operations you can do with
10532 a GString.</para>
10533
10534 <programlisting role="C">
10535 GString *g_string_new( gchar *init );
10536 </programlisting>
10537
10538 <para>This constructs a GString, copying the string value of <literal>init</literal>
10539 into the GString and returning a pointer to it. NULL may be given as
10540 the argument for an initially empty GString.</para>
10541
10542 <programlisting role="C">
10543 void g_string_free( GString *string,
10544                     gint     free_segment );
10545 </programlisting>
10546
10547 <para>This frees the memory for the given GString. If <literal>free_segment</literal> is
10548 TRUE, then this also frees its character data.</para>
10549
10550 <programlisting role="C">            
10551 GString *g_string_assign( GString     *lval,
10552                           const gchar *rval );
10553 </programlisting>
10554
10555 <para>This copies the characters from rval into lval, destroying the
10556 previous contents of lval. Note that lval will be lengthened as
10557 necessary to hold the string's contents, unlike the standard strcpy()
10558 function.</para>
10559
10560 <para>The rest of these functions should be relatively obvious (the _c
10561 versions accept a character instead of a string):</para>
10562              
10563 <programlisting role="C">            
10564 GString *g_string_truncate( GString *string,
10565                             gint     len );
10566                              
10567 GString *g_string_append( GString *string,
10568                           gchar   *val );
10569                             
10570 GString *g_string_append_c( GString *string,
10571                             gchar    c );
10572         
10573 GString *g_string_prepend( GString *string,
10574                            gchar   *val );
10575                              
10576 GString *g_string_prepend_c( GString *string,
10577                              gchar    c );
10578         
10579 void g_string_sprintf( GString *string,
10580                        gchar   *fmt,
10581                        ...);
10582         
10583 void g_string_sprintfa ( GString *string,
10584                          gchar   *fmt,
10585                          ... );
10586 </programlisting>
10587
10588 </sect1>
10589
10590 <!-- ----------------------------------------------------------------- -->
10591 <sect1 id="sec-UtilityAndErrorFunctions">
10592 <title>Utility and Error Functions</title>
10593
10594 <programlisting role="C">
10595 gchar *g_strdup( const gchar *str );
10596 </programlisting>
10597
10598 <para>Replacement strdup function.  Copies the original strings contents to
10599 newly allocated memory, and returns a pointer to it.</para>
10600
10601 <programlisting role="C">
10602 gchar *g_strerror( gint errnum );
10603 </programlisting>
10604
10605 <para>I recommend using this for all error messages.  It's much nicer, and more
10606 portable than perror() or others.  The output is usually of the form:</para>
10607
10608 <programlisting role="C">
10609 program name:function that failed:file or further description:strerror
10610 </programlisting>
10611
10612 <para>Here's an example of one such call used in our hello_world program:</para>
10613
10614 <programlisting role="C">
10615 g_print("hello_world:open:%s:%s\n", filename, g_strerror(errno));
10616 </programlisting>
10617
10618 <programlisting role="C">
10619 void g_error( gchar *format, ... );
10620 </programlisting>
10621
10622 <para>Prints an error message. The format is just like printf, but it
10623 prepends "** ERROR **: " to your message, and exits the program.  
10624 Use only for fatal errors.</para>
10625
10626 <programlisting role="C">
10627 void g_warning( gchar *format, ... );
10628 </programlisting>
10629
10630 <para>Same as above, but prepends "** WARNING **: ", and does not exit the
10631 program.</para>
10632
10633 <programlisting role="C">
10634 void g_message( gchar *format, ... );
10635 </programlisting>
10636
10637 <para>Prints "message: " prepended to the string you pass in.</para>
10638
10639 <programlisting role="C">
10640 void g_print( gchar *format, ... );
10641 </programlisting>
10642
10643 <para>Replacement for printf().</para>
10644
10645 <para>And our last function:</para>
10646
10647 <programlisting role="C">
10648 gchar *g_strsignal( gint signum );
10649 </programlisting>
10650
10651 <para>Prints out the name of the Unix system signal given the signal number.
10652 Useful in generic signal handling functions.</para>
10653
10654 <para>All of the above are more or less just stolen from glib.h.  If anyone cares
10655 to document any function, just send me an email!</para>
10656
10657 </sect1>
10658 </chapter>
10659
10660 <!-- ***************************************************************** -->
10661 <chapter id="ch-GTKRCFiles">
10662 <title>GTK's rc Files</title>
10663
10664 <para>GTK has its own way of dealing with application defaults, by using rc
10665 files. These can be used to set the colors of just about any widget, and
10666 can also be used to tile pixmaps onto the background of some widgets.  </para>
10667
10668 <!-- ----------------------------------------------------------------- -->
10669 <sect1 id="sec-FunctionsForRCFiles">
10670 <title>Functions For rc Files</title>
10671
10672 <para>When your application starts, you should include a call to:</para>
10673
10674 <programlisting role="C">
10675 void gtk_rc_parse( char *filename );
10676 </programlisting>
10677
10678 <para>Passing in the filename of your rc file. This will cause GTK to parse
10679 this file, and use the style settings for the widget types defined
10680 there.</para>
10681
10682 <para>If you wish to have a special set of widgets that can take on a
10683 different style from others, or any other logical division of widgets,
10684 use a call to:</para>
10685
10686 <programlisting role="C">
10687 void gtk_widget_set_name( GtkWidget *widget,
10688                           gchar     *name );
10689 </programlisting>
10690
10691 <para>Passing your newly created widget as the first argument, and the name
10692 you wish to give it as the second. This will allow you to change the
10693 attributes of this widget by name through the rc file.</para>
10694
10695 <para>If we use a call something like this:</para>
10696
10697 <programlisting role="C">
10698 button = gtk_button_new_with_label ("Special Button");
10699 gtk_widget_set_name (button, "special button");
10700 </programlisting>
10701
10702 <para>Then this button is given the name "special button" and may be addressed by
10703 name in the rc file as "special button.GtkButton".  [<--- Verify ME!]</para>
10704
10705 <para>The example rc file below, sets the properties of the main window, and lets
10706 all children of that main window inherit the style described by the "main
10707 button" style.  The code used in the application is:</para>
10708
10709 <programlisting role="C">
10710 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
10711 gtk_widget_set_name (window, "main window");
10712 </programlisting>
10713
10714 <para>And then the style is defined in the rc file using:</para>
10715
10716 <programlisting role="C">
10717 widget "main window.*GtkButton*" style "main_button"
10718 </programlisting>
10719
10720 <para>Which sets all the Button widgets in the "main window" to the
10721 "main_buttons" style as defined in the rc file.</para>
10722
10723 <para>As you can see, this is a fairly powerful and flexible system.  Use your
10724 imagination as to how best to take advantage of this.</para>
10725
10726 </sect1>
10727
10728 <!-- ----------------------------------------------------------------- -->
10729 <sect1 id="sec-GTKsRCFileFormat">
10730 <title>GTK's rc File Format</title>
10731
10732 <para>The format of the GTK file is illustrated in the example below. This is
10733 the testgtkrc file from the GTK distribution, but I've added a
10734 few comments and things. You may wish to include this explanation in
10735 your application to allow the user to fine tune his application.</para>
10736
10737 <para>There are several directives to change the attributes of a widget.</para>
10738
10739 <itemizedlist>
10740 <listitem><simpara>fg - Sets the foreground color of a widget.</simpara>
10741 </listitem>
10742 <listitem><simpara>bg - Sets the background color of a widget.</simpara>
10743 </listitem>
10744 <listitem><simpara>bg_pixmap - Sets the background of a widget to a tiled pixmap.</simpara>
10745 </listitem>
10746 <listitem><simpara>font - Sets the font to be used with the given widget.</simpara>
10747 </listitem>
10748 </itemizedlist>
10749
10750 <para>In addition to this, there are several states a widget can be in, and you
10751 can set different colors, pixmaps and fonts for each state. These states are:</para>
10752
10753 <itemizedlist>
10754 <listitem><simpara>NORMAL - The normal state of a widget, without the mouse over top of
10755 it, and not being pressed, etc.</simpara>
10756 </listitem>
10757 <listitem><simpara>PRELIGHT - When the mouse is over top of the widget, colors defined
10758 using this state will be in effect.</simpara>
10759 </listitem>
10760 <listitem><simpara>ACTIVE - When the widget is pressed or clicked it will be active, and
10761 the attributes assigned by this tag will be in effect.</simpara>
10762 </listitem>
10763 <listitem><simpara>INSENSITIVE - When a widget is set insensitive, and cannot be
10764 activated, it will take these attributes.</simpara>
10765 </listitem>
10766 <listitem><simpara>SELECTED - When an object is selected, it takes these attributes.</simpara>
10767 </listitem>
10768 </itemizedlist>
10769
10770 <para>When using the "fg" and "bg" keywords to set the colors of widgets, the
10771 format is:</para>
10772
10773 <programlisting role="C">
10774 fg[&lt;STATE>] = { Red, Green, Blue }
10775 </programlisting>
10776
10777 <para>Where STATE is one of the above states (PRELIGHT, ACTIVE, etc), and the Red,
10778 Green and Blue are values in the range of 0 - 1.0,  { 1.0, 1.0, 1.0 } being
10779 white. They must be in float form, or they will register as 0, so a straight 
10780 "1" will not work, it must be "1.0".  A straight "0" is fine because it 
10781 doesn't matter if it's not recognized.  Unrecognized values are set to 0.</para>
10782
10783 <para>bg_pixmap is very similar to the above, except the colors are replaced by a
10784 filename.</para>
10785
10786 <para>pixmap_path is a list of paths separated by ":"'s.  These paths will be
10787 searched for any pixmap you specify.</para>
10788
10789 <para>The font directive is simply:</para>
10790
10791 <programlisting role="C">
10792 font = "&lt;font name>"
10793 </programlisting>
10794
10795 <para>The only hard part is figuring out the font string. Using xfontsel or
10796 a similar utility should help.</para>
10797
10798 <para>The "widget_class" sets the style of a class of widgets. These classes are
10799 listed in the widget overview on the class hierarchy.</para>
10800
10801 <para>The "widget" directive sets a specifically named set of widgets to a
10802 given style, overriding any style set for the given widget class.
10803 These widgets are registered inside the application using the
10804 gtk_widget_set_name() call. This allows you to specify the attributes of a
10805 widget on a per widget basis, rather than setting the attributes of an
10806 entire widget class. I urge you to document any of these special widgets so
10807 users may customize them.</para>
10808
10809 <para>When the keyword <literal>parent</> is used as an attribute, the widget will take on
10810 the attributes of its parent in the application.</para>
10811
10812 <para>When defining a style, you may assign the attributes of a previously defined
10813 style to this new one.</para>
10814
10815 <programlisting role="C">
10816 style "main_button" = "button"
10817 {
10818   font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
10819   bg[PRELIGHT] = { 0.75, 0, 0 }
10820 }
10821 </programlisting>
10822
10823 <para>This example takes the "button" style, and creates a new "main_button" style
10824 simply by changing the font and prelight background color of the "button"
10825 style.</para>
10826
10827 <para>Of course, many of these attributes don't apply to all widgets. It's a
10828 simple matter of common sense really. Anything that could apply, should.</para>
10829
10830 </sect1>
10831
10832 <!-- ----------------------------------------------------------------- -->
10833 <sect1 id="sec-ExampleRCFile">
10834 <title>Example rc file</title>
10835
10836 <programlisting role="C">
10837 # pixmap_path "&lt;dir 1>:&lt;dir 2>:&lt;dir 3>:..."
10838 #
10839 pixmap_path "/usr/include/X11R6/pixmaps:/home/imain/pixmaps"
10840 #
10841 # style &lt;name> [= &lt;name>]
10842 # {
10843 #   &lt;option>
10844 # }
10845 #
10846 # widget &lt;widget_set> style &lt;style_name>
10847 # widget_class &lt;widget_class_set> style &lt;style_name>
10848
10849 # Here is a list of all the possible states.  Note that some do not apply to
10850 # certain widgets.
10851 #
10852 # NORMAL - The normal state of a widget, without the mouse over top of
10853 # it, and not being pressed, etc.
10854 #
10855 # PRELIGHT - When the mouse is over top of the widget, colors defined
10856 # using this state will be in effect.
10857 #
10858 # ACTIVE - When the widget is pressed or clicked it will be active, and
10859 # the attributes assigned by this tag will be in effect.
10860 #
10861 # INSENSITIVE - When a widget is set insensitive, and cannot be
10862 # activated, it will take these attributes.
10863 #
10864 # SELECTED - When an object is selected, it takes these attributes.
10865 #
10866 # Given these states, we can set the attributes of the widgets in each of
10867 # these states using the following directives.
10868 #
10869 # fg - Sets the foreground color of a widget.
10870 # fg - Sets the background color of a widget.
10871 # bg_pixmap - Sets the background of a widget to a tiled pixmap.
10872 # font - Sets the font to be used with the given widget.
10873 #
10874
10875 # This sets a style called "button".  The name is not really important, as
10876 # it is assigned to the actual widgets at the bottom of the file.
10877
10878 style "window"
10879 {
10880   #This sets the padding around the window to the pixmap specified.
10881   #bg_pixmap[&lt;STATE>] = "&lt;pixmap filename>"
10882   bg_pixmap[NORMAL] = "warning.xpm"
10883 }
10884
10885 style "scale"
10886 {
10887   #Sets the foreground color (font color) to red when in the "NORMAL"
10888   #state.
10889   
10890   fg[NORMAL] = { 1.0, 0, 0 }
10891   
10892   #Sets the background pixmap of this widget to that of its parent.
10893   bg_pixmap[NORMAL] = "&lt;parent>"
10894 }
10895
10896 style "button"
10897 {
10898   # This shows all the possible states for a button.  The only one that
10899   # doesn't apply is the SELECTED state.
10900   
10901   fg[PRELIGHT] = { 0, 1.0, 1.0 }
10902   bg[PRELIGHT] = { 0, 0, 1.0 }
10903   bg[ACTIVE] = { 1.0, 0, 0 }
10904   fg[ACTIVE] = { 0, 1.0, 0 }
10905   bg[NORMAL] = { 1.0, 1.0, 0 }
10906   fg[NORMAL] = { .99, 0, .99 }
10907   bg[INSENSITIVE] = { 1.0, 1.0, 1.0 }
10908   fg[INSENSITIVE] = { 1.0, 0, 1.0 }
10909 }
10910
10911 # In this example, we inherit the attributes of the "button" style and then
10912 # override the font and background color when prelit to create a new
10913 # "main_button" style.
10914
10915 style "main_button" = "button"
10916 {
10917   font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
10918   bg[PRELIGHT] = { 0.75, 0, 0 }
10919 }
10920
10921 style "toggle_button" = "button"
10922 {
10923   fg[NORMAL] = { 1.0, 0, 0 }
10924   fg[ACTIVE] = { 1.0, 0, 0 }
10925   
10926   # This sets the background pixmap of the toggle_button to that of its
10927   # parent widget (as defined in the application).
10928   bg_pixmap[NORMAL] = "&lt;parent>"
10929 }
10930
10931 style "text"
10932 {
10933   bg_pixmap[NORMAL] = "marble.xpm"
10934   fg[NORMAL] = { 1.0, 1.0, 1.0 }
10935 }
10936
10937 style "ruler"
10938 {
10939   font = "-adobe-helvetica-medium-r-normal--*-80-*-*-*-*-*-*"
10940 }
10941
10942 # pixmap_path "~/.pixmaps"
10943
10944 # These set the widget types to use the styles defined above.
10945 # The widget types are listed in the class hierarchy, but could probably be
10946 # just listed in this document for the users reference.
10947
10948 widget_class "GtkWindow" style "window"
10949 widget_class "GtkDialog" style "window"
10950 widget_class "GtkFileSelection" style "window"
10951 widget_class "*Gtk*Scale" style "scale"
10952 widget_class "*GtkCheckButton*" style "toggle_button"
10953 widget_class "*GtkRadioButton*" style "toggle_button"
10954 widget_class "*GtkButton*" style "button"
10955 widget_class "*Ruler" style "ruler"
10956 widget_class "*GtkText" style "text"
10957
10958 # This sets all the buttons that are children of the "main window" to
10959 # the main_button style.  These must be documented to be taken advantage of.
10960 widget "main window.*GtkButton*" style "main_button"
10961 </programlisting>
10962
10963 </sect1>
10964 </chapter>
10965
10966 <!-- ***************************************************************** -->
10967 <chapter id="ch-WritingYourOwnWidgets">
10968 <title>Writing Your Own Widgets</title>
10969
10970 <!-- ----------------------------------------------------------------- -->
10971 <sect1 id="sec-WidgetsOverview">
10972 <title>Overview</title>
10973
10974 <para>Although the GTK distribution comes with many types of widgets that
10975 should cover most basic needs, there may come a time when you need to
10976 create your own new widget type. Since GTK uses widget inheritance
10977 extensively, and there is already a widget that is close to what you want,
10978 it is often possible to make a useful new widget type in
10979 just a few lines of code. But before starting work on a new widget, check
10980 around first to make sure that someone has not already written
10981 it. This will prevent duplication of effort and keep the number of
10982 GTK widgets out there to a minimum, which will help keep both the code
10983 and the interface of different applications consistent. As a flip side
10984 to this, once you finish your widget, announce it to the world so
10985 other people can benefit. The best place to do this is probably the
10986 <literal>gtk-list</literal>.</para>
10987
10988 <para>Complete sources for the example widgets are available at the place you 
10989 got this tutorial, or from:</para>
10990
10991 <para><ulink url="http://www.gtk.org/~otaylor/gtk/tutorial/">http://www.gtk.org/~otaylor/gtk/tutorial/</ulink></para>
10992
10993
10994 </sect1>
10995
10996 <!-- ----------------------------------------------------------------- -->
10997 <sect1 id="sec-TheAnatomyOfAWidget">
10998 <title>The Anatomy Of A Widget</title>
10999
11000 <para>In order to create a new widget, it is important to have an
11001 understanding of how GTK objects work. This section is just meant as a
11002 brief overview. See the reference documentation for the details. </para>
11003
11004 <para>GTK widgets are implemented in an object oriented fashion. However,
11005 they are implemented in standard C. This greatly improves portability
11006 and stability over using current generation C++ compilers; however,
11007 it does mean that the widget writer has to pay attention to some of
11008 the implementation details. The information common to all instances of
11009 one class of widgets (e.g., to all Button widgets) is stored in the 
11010 <emphasis>class structure</emphasis>. There is only one copy of this in
11011 which is stored information about the class's signals
11012 (which act like virtual functions in C). To support inheritance, the
11013 first field in the class structure must be a copy of the parent's
11014 class structure. The declaration of the class structure of GtkButtton
11015 looks like:</para>
11016
11017 <programlisting role="C">
11018 struct _GtkButtonClass
11019 {
11020   GtkContainerClass parent_class;
11021
11022   void (* pressed)  (GtkButton *button);
11023   void (* released) (GtkButton *button);
11024   void (* clicked)  (GtkButton *button);
11025   void (* enter)    (GtkButton *button);
11026   void (* leave)    (GtkButton *button);
11027 };
11028 </programlisting>
11029
11030 <para>When a button is treated as a container (for instance, when it is
11031 resized), its class structure can be cast to GtkContainerClass, and
11032 the relevant fields used to handle the signals.</para>
11033
11034 <para>There is also a structure for each widget that is created on a
11035 per-instance basis. This structure has fields to store information that
11036 is different for each instance of the widget. We'll call this
11037 structure the <emphasis>object structure</emphasis>. For the Button class, it looks
11038 like:</para>
11039
11040 <programlisting role="C">
11041 struct _GtkButton
11042 {
11043   GtkContainer container;
11044
11045   GtkWidget *child;
11046
11047   guint in_button : 1;
11048   guint button_down : 1;
11049 };
11050 </programlisting>
11051
11052 <para>Note that, similar to the class structure, the first field is the
11053 object structure of the parent class, so that this structure can be
11054 cast to the parent class' object structure as needed.</para>
11055
11056 </sect1>
11057
11058 <!-- ----------------------------------------------------------------- -->
11059 <sect1 id="sec-CreatingACompositeWidget">
11060 <title>Creating a Composite widget</title>
11061
11062 <!-- ----------------------------------------------------------------- -->
11063 <sect2>
11064 <title>Introduction</title>
11065
11066 <para>One type of widget that you may be interested in creating is a
11067 widget that is merely an aggregate of other GTK widgets. This type of
11068 widget does nothing that couldn't be done without creating new
11069 widgets, but provides a convenient way of packaging user interface
11070 elements for reuse. The FileSelection and ColorSelection widgets in
11071 the standard distribution are examples of this type of widget.</para>
11072
11073 <para>The example widget that we'll create in this section is the Tictactoe
11074 widget, a 3x3 array of toggle buttons which triggers a signal when all
11075 three buttons in a row, column, or on one of the diagonals are
11076 depressed. </para>
11077
11078 <para>
11079 <inlinemediaobject>
11080 <imageobject>
11081 <imagedata fileref="images/tictactoe.png" format="png">
11082 </imageobject>
11083 </inlinemediaobject>
11084 </para>
11085
11086 </sect2>
11087
11088 <!-- ----------------------------------------------------------------- -->
11089 <sect2>
11090 <title>Choosing a parent class</title>
11091
11092 <para>The parent class for a composite widget is typically the container
11093 class that holds all of the elements of the composite widget. For
11094 example, the parent class of the FileSelection widget is the
11095 Dialog class. Since our buttons will be arranged in a table, it
11096 might seem natural to make our parent class the Table
11097 class. Unfortunately, this turns out not to work. The creation of a
11098 widget is divided among two functions - a <literal>WIDGETNAME_new()</literal>
11099 function that the user calls, and a <literal>WIDGETNAME_init()</literal> function
11100 which does the basic work of initializing the widget which is
11101 independent of the arguments passed to the <literal>_new()</literal>
11102 function. Descendant widgets only call the <literal>_init</literal> function of
11103 their parent widget. But this division of labor doesn't work well for
11104 tables, which when created need to know the number of rows and
11105 columns in the table. Unless we want to duplicate most of the
11106 functionality of <literal>gtk_table_new()</literal> in our Tictactoe widget, we had
11107 best avoid deriving it from Table. For that reason, we derive it
11108 from VBox instead, and stick our table inside the VBox.</para>
11109
11110 </sect2>
11111
11112 <!-- ----------------------------------------------------------------- -->
11113 <sect2>
11114 <title>The header file</title>
11115
11116 <para>Each widget class has a header file which declares the object and
11117 class structures for that widget, along with public functions. 
11118 A couple of features are worth pointing out. To prevent duplicate
11119 definitions, we wrap the entire header file in:</para>
11120
11121 <programlisting role="C">
11122 #ifndef __TICTACTOE_H__
11123 #define __TICTACTOE_H__
11124 .
11125 .
11126 .
11127 #endif /* __TICTACTOE_H__ */
11128 </programlisting>
11129
11130 <para>And to keep C++ programs that include the header file happy, in:</para>
11131
11132 <programlisting role="C">
11133 #ifdef __cplusplus
11134 extern "C" {
11135 #endif /* __cplusplus */
11136 .
11137 .
11138 .
11139 #ifdef __cplusplus
11140 }
11141 #endif /* __cplusplus */
11142 </programlisting>
11143
11144 <para>Along with the functions and structures, we declare three standard
11145 macros in our header file, <literal>TICTACTOE(obj)</literal>,
11146 <literal>TICTACTOE_CLASS(klass)</literal>, and <literal>IS_TICTACTOE(obj)</literal>, which cast a
11147 pointer into a pointer to the object or class structure, and check
11148 if an object is a Tictactoe widget respectively.</para>
11149
11150 <para>Here is the complete header file:</para>
11151
11152 <programlisting role="C">
11153 <!-- example-start tictactoe tictactoe.h -->
11154
11155 /* GTK - The GIMP Toolkit
11156  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
11157  *
11158  * This library is free software; you can redistribute it and/or
11159  * modify it under the terms of the GNU Library General Public
11160  * License as published by the Free Software Foundation; either
11161  * version 2 of the License, or (at your option) any later version.
11162  *
11163  * This library is distributed in the hope that it will be useful,
11164  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11165  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11166  * Library General Public License for more details.
11167  *
11168  * You should have received a copy of the GNU Library General Public
11169  * License along with this library; if not, write to the
11170  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
11171  * Boston, MA 02111-1307, USA.
11172  */
11173 #ifndef __TICTACTOE_H__
11174 #define __TICTACTOE_H__
11175
11176
11177 #include &lt;gdk/gdk.h&gt;
11178 #include &lt;gtk/gtkvbox.h&gt;
11179
11180
11181 #ifdef __cplusplus
11182 extern "C" {
11183 #endif /* __cplusplus */
11184
11185 #define TICTACTOE(obj)          GTK_CHECK_CAST (obj, tictactoe_get_type (), Tictactoe)
11186 #define TICTACTOE_CLASS(klass)  GTK_CHECK_CLASS_CAST (klass, tictactoe_get_type (), TictactoeClass)
11187 #define IS_TICTACTOE(obj)       GTK_CHECK_TYPE (obj, tictactoe_get_type ())
11188
11189
11190 typedef struct _Tictactoe       Tictactoe;
11191 typedef struct _TictactoeClass  TictactoeClass;
11192
11193 struct _Tictactoe
11194 {
11195   GtkVBox vbox;
11196   
11197   GtkWidget *buttons[3][3];
11198 };
11199
11200 struct _TictactoeClass
11201 {
11202   GtkVBoxClass parent_class;
11203
11204   void (* tictactoe) (Tictactoe *ttt);
11205 };
11206
11207 GtkType        tictactoe_get_type        (void);
11208 GtkWidget*     tictactoe_new             (void);
11209 void           tictactoe_clear           (Tictactoe *ttt);
11210
11211 #ifdef __cplusplus
11212 }
11213 #endif /* __cplusplus */
11214
11215 #endif /* __TICTACTOE_H__ */
11216
11217 <!-- example-end -->
11218 </programlisting>
11219
11220 </sect2>
11221
11222 <!-- ----------------------------------------------------------------- -->
11223 <sect2>
11224 <title>The <literal>_get_type()</literal> function</title>
11225
11226 <para>We now continue on to the implementation of our widget. A core
11227 function for every widget is the function
11228 <literal>WIDGETNAME_get_type()</literal>. This function, when first called, tells
11229 GTK about the widget class, and gets an ID that uniquely identifies
11230 the widget class. Upon subsequent calls, it just returns the ID.</para>
11231
11232 <programlisting role="C">
11233 GtkType
11234 tictactoe_get_type ()
11235 {
11236   static guint ttt_type = 0;
11237
11238   if (!ttt_type)
11239     {
11240       GtkTypeInfo ttt_info =
11241       {
11242         "Tictactoe",
11243         sizeof (Tictactoe),
11244         sizeof (TictactoeClass),
11245         (GtkClassInitFunc) tictactoe_class_init,
11246         (GtkObjectInitFunc) tictactoe_init,
11247         (GtkArgSetFunc) NULL,
11248         (GtkArgGetFunc) NULL
11249       };
11250
11251       ttt_type = gtk_type_unique (gtk_vbox_get_type (), &amp;ttt_info);
11252     }
11253
11254   return ttt_type;
11255 }
11256 </programlisting>
11257
11258 <para>The GtkTypeInfo structure has the following definition:</para>
11259
11260 <programlisting role="C">
11261 struct _GtkTypeInfo
11262 {
11263   gchar *type_name;
11264   guint object_size;
11265   guint class_size;
11266   GtkClassInitFunc class_init_func;
11267   GtkObjectInitFunc object_init_func;
11268   GtkArgSetFunc arg_set_func;
11269   GtkArgGetFunc arg_get_func;
11270 };
11271 </programlisting>
11272
11273 <para>The fields of this structure are pretty self-explanatory. We'll ignore
11274 the <literal>arg_set_func</literal> and <literal>arg_get_func</literal> fields here: they have an important, 
11275 but as yet largely
11276 unimplemented, role in allowing widget options to be conveniently set
11277 from interpreted languages. Once GTK has a correctly filled in copy of
11278 this structure, it knows how to create objects of a particular widget
11279 type. </para>
11280
11281 </sect2>
11282
11283 <!-- ----------------------------------------------------------------- -->
11284 <sect2>
11285 <title>The <literal>_class_init()</literal> function</title>
11286
11287 <para>The <literal>WIDGETNAME_class_init()</literal> function initializes the fields of
11288 the widget's class structure, and sets up any signals for the
11289 class. For our Tictactoe widget it looks like:</para>
11290
11291 <programlisting role="C">
11292 enum {
11293   TICTACTOE_SIGNAL,
11294   LAST_SIGNAL
11295 };
11296
11297
11298 static gint tictactoe_signals[LAST_SIGNAL] = { 0 };
11299
11300 static void
11301 tictactoe_class_init (TictactoeClass *class)
11302 {
11303   GtkObjectClass *object_class;
11304
11305   object_class = (GtkObjectClass*) class;
11306   
11307   tictactoe_signals[TICTACTOE_SIGNAL] = gtk_signal_new ("tictactoe",
11308                                          GTK_RUN_FIRST,
11309                                          object_class->type,
11310                                          GTK_SIGNAL_OFFSET (TictactoeClass, tictactoe),
11311                                          gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
11312
11313
11314   gtk_object_class_add_signals (object_class, tictactoe_signals, LAST_SIGNAL);
11315
11316   class->tictactoe = NULL;
11317 }
11318 </programlisting>
11319
11320 <para>Our widget has just one signal, the <literal>tictactoe</literal> signal that is
11321 invoked when a row, column, or diagonal is completely filled in. Not
11322 every composite widget needs signals, so if you are reading this for
11323 the first time, you may want to skip to the next section now, as
11324 things are going to get a bit complicated.</para>
11325
11326 <para>The function:</para>
11327
11328 <programlisting role="C">
11329 gint gtk_signal_new( const gchar         *name,
11330                      GtkSignalRunType     run_type,
11331                      GtkType              object_type,
11332                      gint                 function_offset,
11333                      GtkSignalMarshaller  marshaller,
11334                      GtkType              return_val,
11335                      guint                nparams,
11336                      ...);
11337 </programlisting>
11338
11339 <para>Creates a new signal. The parameters are:</para>
11340
11341 <itemizedlist>
11342 <listitem><simpara> <literal>name</literal>: The name of the signal.</simpara>
11343 </listitem>
11344
11345 <listitem><simpara> <literal>run_type</literal>: Whether the default handler runs before or after
11346 user handlers. Usually this will be <literal>GTK_RUN_FIRST</literal>, or <literal>GTK_RUN_LAST</literal>,
11347 although there are other possibilities.</simpara>
11348 </listitem>
11349
11350 <listitem><simpara> <literal>object_type</literal>: The ID of the object that this signal applies
11351 to. (It will also apply to that objects descendants.)</simpara>
11352 </listitem>
11353
11354 <listitem><simpara> <literal>function_offset</literal>: The offset within the class structure of
11355 a pointer to the default handler.</simpara>
11356 </listitem>
11357
11358 <listitem><simpara> <literal>marshaller</literal>: A function that is used to invoke the signal
11359 handler. For signal handlers that have no arguments other than the
11360 object that emitted the signal and user data, we can use the
11361 pre-supplied marshaller function <literal>gtk_signal_default_marshaller</literal>.</simpara>
11362 </listitem>
11363
11364 <listitem><simpara> <literal>return_val</literal>: The type of the return val.</simpara>
11365 </listitem>
11366
11367 <listitem><simpara> <literal>nparams</literal>: The number of parameters of the signal handler
11368 (other than the two default ones mentioned above)</simpara>
11369 </listitem>
11370
11371 <listitem><simpara> <literal>...</literal>: The types of the parameters.</simpara>
11372 </listitem>
11373 </itemizedlist>
11374
11375 <para>When specifying types, the <literal>GtkType</literal> enumeration is used:</para>
11376
11377 <programlisting role="C">
11378 typedef enum
11379 {
11380   GTK_TYPE_INVALID,
11381   GTK_TYPE_NONE,
11382   GTK_TYPE_CHAR,
11383   GTK_TYPE_BOOL,
11384   GTK_TYPE_INT,
11385   GTK_TYPE_UINT,
11386   GTK_TYPE_LONG,
11387   GTK_TYPE_ULONG,
11388   GTK_TYPE_FLOAT,
11389   GTK_TYPE_DOUBLE,
11390   GTK_TYPE_STRING,
11391   GTK_TYPE_ENUM,
11392   GTK_TYPE_FLAGS,
11393   GTK_TYPE_BOXED,
11394   GTK_TYPE_FOREIGN,
11395   GTK_TYPE_CALLBACK,
11396   GTK_TYPE_ARGS,
11397
11398   GTK_TYPE_POINTER,
11399
11400   /* it'd be great if the next two could be removed eventually */
11401   GTK_TYPE_SIGNAL,
11402   GTK_TYPE_C_CALLBACK,
11403
11404   GTK_TYPE_OBJECT
11405
11406 } GtkFundamentalType;
11407 </programlisting>
11408
11409 <para><literal>gtk_signal_new()</literal> returns a unique integer identifier for the
11410 signal, that we store in the <literal>tictactoe_signals</literal> array, which we
11411 index using an enumeration. (Conventionally, the enumeration elements
11412 are the signal name, uppercased, but here there would be a conflict
11413 with the <literal>TICTACTOE()</literal> macro, so we called it <literal>TICTACTOE_SIGNAL</literal>
11414 instead.</para>
11415
11416 <para>After creating our signals, we need to tell GTK to associate our
11417 signals with the Tictactoe class. We do that by calling
11418 <literal>gtk_object_class_add_signals()</literal>. We then set the pointer which
11419 points to the default handler for the "tictactoe" signal to NULL,
11420 indicating that there is no default action.</para>
11421
11422 </sect2>
11423
11424 <!-- ----------------------------------------------------------------- -->
11425 <sect2>
11426 <title>The <literal>_init()</literal> function</title>
11427
11428 <para>Each widget class also needs a function to initialize the object
11429 structure. Usually, this function has the fairly limited role of
11430 setting the fields of the structure to default values. For composite
11431 widgets, however, this function also creates the component widgets.</para>
11432
11433 <programlisting role="C">
11434 static void
11435 tictactoe_init (Tictactoe *ttt)
11436 {
11437   GtkWidget *table;
11438   gint i,j;
11439   
11440   table = gtk_table_new (3, 3, TRUE);
11441   gtk_container_add (GTK_CONTAINER(ttt), table);
11442   gtk_widget_show (table);
11443
11444   for (i=0;i<3; i++)
11445     for (j=0;j<3; j++)
11446       {
11447         ttt->buttons[i][j] = gtk_toggle_button_new ();
11448         gtk_table_attach_defaults (GTK_TABLE(table), ttt->buttons[i][j], 
11449                                    i, i+1, j, j+1);
11450         gtk_signal_connect (GTK_OBJECT (ttt->buttons[i][j]), "toggled",
11451                             GTK_SIGNAL_FUNC (tictactoe_toggle), ttt);
11452         gtk_widget_set_size_request (ttt->buttons[i][j], 20, 20);
11453         gtk_widget_show (ttt->buttons[i][j]);
11454       }
11455 }
11456 </programlisting>
11457
11458 </sect2>
11459
11460 <!-- ----------------------------------------------------------------- -->
11461 <sect2>
11462 <title>And the rest...</title>
11463
11464 <para>There is one more function that every widget (except for base widget
11465 types like Bin that cannot be instantiated) needs to have - the
11466 function that the user calls to create an object of that type. This is
11467 conventionally called <literal>WIDGETNAME_new()</literal>. In some
11468 widgets, though not for the Tictactoe widgets, this function takes
11469 arguments, and does some setup based on the arguments. The other two
11470 functions are specific to the Tictactoe widget. </para>
11471
11472 <para><literal>tictactoe_clear()</literal> is a public function that resets all the
11473 buttons in the widget to the up position. Note the use of
11474 <literal>gtk_signal_handler_block_by_data()</literal> to keep our signal handler for
11475 button toggles from being triggered unnecessarily.</para>
11476
11477 <para><literal>tictactoe_toggle()</literal> is the signal handler that is invoked when the
11478 user clicks on a button. It checks to see if there are any winning
11479 combinations that involve the toggled button, and if so, emits
11480 the "tictactoe" signal.</para>
11481
11482 <programlisting role="C">
11483 GtkWidget*
11484 tictactoe_new ()
11485 {
11486   return GTK_WIDGET ( gtk_type_new (tictactoe_get_type ()));
11487 }
11488
11489 void           
11490 tictactoe_clear (Tictactoe *ttt)
11491 {
11492   int i,j;
11493
11494   for (i=0;i<3;i++)
11495     for (j=0;j<3;j++)
11496       {
11497         gtk_signal_handler_block_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
11498         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ttt->buttons[i][j]),
11499                                      FALSE);
11500         gtk_signal_handler_unblock_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
11501       }
11502 }
11503
11504 static void
11505 tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt)
11506 {
11507   int i,k;
11508
11509   static int rwins[8][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
11510                              { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
11511                              { 0, 1, 2 }, { 0, 1, 2 } };
11512   static int cwins[8][3] = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
11513                              { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
11514                              { 0, 1, 2 }, { 2, 1, 0 } };
11515
11516   int success, found;
11517
11518   for (k=0; k<8; k++)
11519     {
11520       success = TRUE;
11521       found = FALSE;
11522
11523       for (i=0;i<3;i++)
11524         {
11525           success = success &amp;&amp; 
11526             GTK_TOGGLE_BUTTON(ttt->buttons[rwins[k][i]][cwins[k][i]])->active;
11527           found = found ||
11528             ttt->buttons[rwins[k][i]][cwins[k][i]] == widget;
11529         }
11530       
11531       if (success &amp;&amp; found)
11532         {
11533           gtk_signal_emit (GTK_OBJECT (ttt), 
11534                            tictactoe_signals[TICTACTOE_SIGNAL]);
11535           break;
11536         }
11537     }
11538 }
11539 </programlisting>
11540
11541 <para>And finally, an example program using our Tictactoe widget:</para>
11542
11543 <programlisting role="C">
11544 #include &lt;gtk/gtk.h&gt;
11545 #include "tictactoe.h"
11546
11547 /* Invoked when a row, column or diagonal is completed */
11548 void
11549 win (GtkWidget *widget, gpointer data)
11550 {
11551   g_print ("Yay!\n");
11552   tictactoe_clear (TICTACTOE (widget));
11553 }
11554
11555 int 
11556 main (int argc, char *argv[])
11557 {
11558   GtkWidget *window;
11559   GtkWidget *ttt;
11560   
11561   gtk_init (&amp;argc, &amp;argv);
11562
11563   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
11564   
11565   gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
11566   
11567   gtk_signal_connect (GTK_OBJECT (window), "destroy",
11568                       GTK_SIGNAL_FUNC (gtk_exit), NULL);
11569   
11570   gtk_container_set_border_width (GTK_CONTAINER (window), 10);
11571
11572   /* Create a new Tictactoe widget */
11573   ttt = tictactoe_new ();
11574   gtk_container_add (GTK_CONTAINER (window), ttt);
11575   gtk_widget_show (ttt);
11576
11577   /* And attach to its "tictactoe" signal */
11578   gtk_signal_connect (GTK_OBJECT (ttt), "tictactoe",
11579                       GTK_SIGNAL_FUNC (win), NULL);
11580
11581   gtk_widget_show (window);
11582   
11583   gtk_main ();
11584   
11585   return 0;
11586 }
11587 </programlisting>
11588
11589 </sect2>
11590 </sect1>
11591
11592 <!-- ----------------------------------------------------------------- -->
11593 <sect1 id="sec-CreatingAWidgetFromScratch">
11594 <title>Creating a widget from scratch</title>
11595
11596 <!-- ----------------------------------------------------------------- -->
11597 <sect2>
11598 <title>Introduction</title>
11599
11600 <para>In this section, we'll learn more about how widgets display themselves
11601 on the screen and interact with events. As an example of this, we'll
11602 create an analog dial widget with a pointer that the user can drag to
11603 set the value.</para>
11604
11605 <para>
11606 <inlinemediaobject>
11607 <imageobject>
11608 <imagedata fileref="images/gtkdial.png" format="png">
11609 </imageobject>
11610 </inlinemediaobject>
11611 </para>
11612
11613 </sect2>
11614
11615 <!-- ----------------------------------------------------------------- -->
11616 <sect2>
11617 <title>Displaying a widget on the screen</title>
11618
11619 <para>There are several steps that are involved in displaying on the screen.
11620 After the widget is created with a call to <literal>WIDGETNAME_new()</literal>,
11621 several more functions are needed:</para>
11622
11623 <itemizedlist>
11624 <listitem><simpara> <literal>WIDGETNAME_realize()</literal> is responsible for creating an X
11625 window for the widget if it has one.</simpara>
11626 </listitem>
11627 <listitem><simpara> <literal>WIDGETNAME_map()</literal> is invoked after the user calls
11628 <literal>gtk_widget_show()</literal>. It is responsible for making sure the widget
11629 is actually drawn on the screen (<emphasis>mapped</emphasis>). For a container class,
11630 it must also make calls to <literal>map()</literal>> functions of any child widgets.</simpara>
11631 </listitem>
11632 <listitem><simpara> <literal>WIDGETNAME_draw()</literal> is invoked when <literal>gtk_widget_draw()</literal>
11633 is called for the widget or one of its ancestors. It makes the actual
11634 calls to the drawing functions to draw the widget on the screen. For
11635 container widgets, this function must make calls to
11636 <literal>gtk_widget_draw()</literal> for its child widgets.</simpara>
11637 </listitem>
11638 <listitem><simpara> <literal>WIDGETNAME_expose()</literal> is a handler for expose events for the
11639 widget. It makes the necessary calls to the drawing functions to draw
11640 the exposed portion on the screen. For container widgets, this
11641 function must generate expose events for its child widgets which don't
11642 have their own windows. (If they have their own windows, then X will
11643 generate the necessary expose events.)</simpara>
11644 </listitem>
11645 </itemizedlist>
11646
11647 <para>You might notice that the last two functions are quite similar - each
11648 is responsible for drawing the widget on the screen. In fact many
11649 types of widgets don't really care about the difference between the
11650 two. The default <literal>draw()</literal> function in the widget class simply
11651 generates a synthetic expose event for the redrawn area. However, some
11652 types of widgets can save work by distinguishing between the two
11653 functions. For instance, if a widget has multiple X windows, then
11654 since expose events identify the exposed window, it can redraw only
11655 the affected window, which is not possible for calls to <literal>draw()</literal>.</para>
11656
11657 <para>Container widgets, even if they don't care about the difference for
11658 themselves, can't simply use the default <literal>draw()</literal> function because
11659 their child widgets might care about the difference. However,
11660 it would be wasteful to duplicate the drawing code between the two
11661 functions. The convention is that such widgets have a function called
11662 <literal>WIDGETNAME_paint()</literal> that does the actual work of drawing the
11663 widget, that is then called by the <literal>draw()</literal> and <literal>expose()</literal>
11664 functions.</para>
11665
11666 <para>In our example approach, since the dial widget is not a container
11667 widget, and only has a single window, we can take the simplest
11668 approach and use the default <literal>draw()</literal> function and only implement
11669 an <literal>expose()</literal> function.</para>
11670
11671 </sect2>
11672
11673 <!-- ----------------------------------------------------------------- -->
11674 <sect2>
11675 <title>The origins of the Dial Widget</title>
11676
11677 <para>Just as all land animals are just variants on the first amphibian that
11678 crawled up out of the mud, GTK widgets tend to start off as variants
11679 of some other, previously written widget. Thus, although this section
11680 is entitled "Creating a Widget from Scratch", the Dial widget really
11681 began with the source code for the Range widget. This was picked as a
11682 starting point because it would be nice if our Dial had the same
11683 interface as the Scale widgets which are just specialized descendants
11684 of the Range widget. So, though the source code is presented below in
11685 finished form, it should not be implied that it was written, <emphasis>ab
11686 initio</emphasis> in this fashion. Also, if you aren't yet familiar with
11687 how scale widgets work from the application writer's point of view, it
11688 would be a good idea to look them over before continuing.</para>
11689
11690 </sect2>
11691
11692 <!-- ----------------------------------------------------------------- -->
11693 <sect2>
11694 <title>The Basics</title>
11695
11696 <para>Quite a bit of our widget should look pretty familiar from the
11697 Tictactoe widget. First, we have a header file:</para>
11698
11699 <programlisting role="C">
11700 /* GTK - The GIMP Toolkit
11701  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
11702  *
11703  * This library is free software; you can redistribute it and/or
11704  * modify it under the terms of the GNU Library General Public
11705  * License as published by the Free Software Foundation; either
11706  * version 2 of the License, or (at your option) any later version.
11707  *
11708  * This library is distributed in the hope that it will be useful,
11709  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11710  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11711  * Library General Public License for more details.
11712  *
11713  * You should have received a copy of the GNU Library General Public
11714  * License along with this library; if not, write to the Free
11715  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
11716  */
11717
11718 #ifndef __GTK_DIAL_H__
11719 #define __GTK_DIAL_H__
11720
11721 #include &lt;gdk/gdk.h&gt;
11722 #include &lt;gtk/gtkadjustment.h&gt;
11723 #include &lt;gtk/gtkwidget.h&gt;
11724
11725
11726 #ifdef __cplusplus
11727 extern "C" {
11728 #endif /* __cplusplus */
11729
11730
11731 #define GTK_DIAL(obj)          GTK_CHECK_CAST (obj, gtk_dial_get_type (), GtkDial)
11732 #define GTK_DIAL_CLASS(klass)  GTK_CHECK_CLASS_CAST (klass, gtk_dial_get_type (), GtkDialClass)
11733 #define GTK_IS_DIAL(obj)       GTK_CHECK_TYPE (obj, gtk_dial_get_type ())
11734
11735
11736 typedef struct _GtkDial        GtkDial;
11737 typedef struct _GtkDialClass   GtkDialClass;
11738
11739 struct _GtkDial
11740 {
11741   GtkWidget widget;
11742
11743   /* update policy (GTK_UPDATE_[CONTINUOUS/DELAYED/DISCONTINUOUS]) */
11744   guint policy : 2;
11745
11746   /* Button currently pressed or 0 if none */
11747   guint8 button;
11748
11749   /* Dimensions of dial components */
11750   gint radius;
11751   gint pointer_width;
11752
11753   /* ID of update timer, or 0 if none */
11754   guint32 timer;
11755
11756   /* Current angle */
11757   gfloat angle;
11758
11759   /* Old values from adjustment stored so we know when something changes */
11760   gfloat old_value;
11761   gfloat old_lower;
11762   gfloat old_upper;
11763
11764   /* The adjustment object that stores the data for this dial */
11765   GtkAdjustment *adjustment;
11766 };
11767
11768 struct _GtkDialClass
11769 {
11770   GtkWidgetClass parent_class;
11771 };
11772
11773
11774 GtkWidget*     gtk_dial_new                    (GtkAdjustment *adjustment);
11775 GtkType        gtk_dial_get_type               (void);
11776 GtkAdjustment* gtk_dial_get_adjustment         (GtkDial      *dial);
11777 void           gtk_dial_set_update_policy      (GtkDial      *dial,
11778                                                 GtkUpdateType  policy);
11779
11780 void           gtk_dial_set_adjustment         (GtkDial      *dial,
11781                                                 GtkAdjustment *adjustment);
11782 #ifdef __cplusplus
11783 }
11784 #endif /* __cplusplus */
11785
11786
11787 #endif /* __GTK_DIAL_H__ */
11788 </programlisting>
11789
11790 <para>Since there is quite a bit more going on in this widget than the last
11791 one, we have more fields in the data structure, but otherwise things
11792 are pretty similar.</para>
11793
11794 <para>Next, after including header files and declaring a few constants,
11795 we have some functions to provide information about the widget
11796 and initialize it:</para>
11797
11798 <programlisting role="C">
11799 #include &lt;math.h&gt;
11800 #include &lt;stdio.h&gt;
11801 #include &lt;gtk/gtkmain.h&gt;
11802 #include &lt;gtk/gtksignal.h&gt;
11803
11804 #include "gtkdial.h"
11805
11806 #define SCROLL_DELAY_LENGTH  300
11807 #define DIAL_DEFAULT_SIZE 100
11808
11809 /* Forward declarations */
11810
11811 [ omitted to save space ]
11812
11813 /* Local data */
11814
11815 static GtkWidgetClass *parent_class = NULL;
11816
11817 GtkType
11818 gtk_dial_get_type ()
11819 {
11820   static GtkType dial_type = 0;
11821
11822   if (!dial_type)
11823     {
11824       static const GtkTypeInfo dial_info =
11825       {
11826         "GtkDial",
11827         sizeof (GtkDial),
11828         sizeof (GtkDialClass),
11829         (GtkClassInitFunc) gtk_dial_class_init,
11830         (GtkObjectInitFunc) gtk_dial_init,
11831         /* reserved_1 */ NULL,
11832         /* reserved_1 */ NULL,
11833         (GtkClassInitFunc) NULL
11834       };
11835
11836       dial_type = gtk_type_unique (GTK_TYPE_WIDGET, &amp;dial_info);
11837     }
11838
11839   return dial_type;
11840 }
11841
11842 static void
11843 gtk_dial_class_init (GtkDialClass *class)
11844 {
11845   GtkObjectClass *object_class;
11846   GtkWidgetClass *widget_class;
11847
11848   object_class = (GtkObjectClass*) class;
11849   widget_class = (GtkWidgetClass*) class;
11850
11851   parent_class = gtk_type_class (gtk_widget_get_type ());
11852
11853   object_class->destroy = gtk_dial_destroy;
11854
11855   widget_class->realize = gtk_dial_realize;
11856   widget_class->expose_event = gtk_dial_expose;
11857   widget_class->size_request = gtk_dial_size_request;
11858   widget_class->size_allocate = gtk_dial_size_allocate;
11859   widget_class->button_press_event = gtk_dial_button_press;
11860   widget_class->button_release_event = gtk_dial_button_release;
11861   widget_class->motion_notify_event = gtk_dial_motion_notify;
11862 }
11863
11864 static void
11865 gtk_dial_init (GtkDial *dial)
11866 {
11867   dial->button = 0;
11868   dial->policy = GTK_UPDATE_CONTINUOUS;
11869   dial->timer = 0;
11870   dial->radius = 0;
11871   dial->pointer_width = 0;
11872   dial->angle = 0.0;
11873   dial->old_value = 0.0;
11874   dial->old_lower = 0.0;
11875   dial->old_upper = 0.0;
11876   dial->adjustment = NULL;
11877 }
11878
11879 GtkWidget*
11880 gtk_dial_new (GtkAdjustment *adjustment)
11881 {
11882   GtkDial *dial;
11883
11884   dial = gtk_type_new (gtk_dial_get_type ());
11885
11886   if (!adjustment)
11887     adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
11888
11889   gtk_dial_set_adjustment (dial, adjustment);
11890
11891   return GTK_WIDGET (dial);
11892 }
11893
11894 static void
11895 gtk_dial_destroy (GtkObject *object)
11896 {
11897   GtkDial *dial;
11898
11899   g_return_if_fail (object != NULL);
11900   g_return_if_fail (GTK_IS_DIAL (object));
11901
11902   dial = GTK_DIAL (object);
11903
11904   if (dial->adjustment)
11905     gtk_object_unref (GTK_OBJECT (dial->adjustment));
11906
11907   if (GTK_OBJECT_CLASS (parent_class)->destroy)
11908     (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
11909 }
11910 </programlisting>
11911
11912 <para>Note that this <literal>init()</literal> function does less than for the Tictactoe
11913 widget, since this is not a composite widget, and the <literal>new()</literal>
11914 function does more, since it now has an argument. Also, note that when
11915 we store a pointer to the Adjustment object, we increment its
11916 reference count, (and correspondingly decrement it when we no longer
11917 use it) so that GTK can keep track of when it can be safely destroyed.</para>
11918
11919 <para>Also, there are a few function to manipulate the widget's options:</para>
11920
11921 <programlisting role="C">
11922 GtkAdjustment*
11923 gtk_dial_get_adjustment (GtkDial *dial)
11924 {
11925   g_return_val_if_fail (dial != NULL, NULL);
11926   g_return_val_if_fail (GTK_IS_DIAL (dial), NULL);
11927
11928   return dial->adjustment;
11929 }
11930
11931 void
11932 gtk_dial_set_update_policy (GtkDial      *dial,
11933                              GtkUpdateType  policy)
11934 {
11935   g_return_if_fail (dial != NULL);
11936   g_return_if_fail (GTK_IS_DIAL (dial));
11937
11938   dial->policy = policy;
11939 }
11940
11941 void
11942 gtk_dial_set_adjustment (GtkDial      *dial,
11943                           GtkAdjustment *adjustment)
11944 {
11945   g_return_if_fail (dial != NULL);
11946   g_return_if_fail (GTK_IS_DIAL (dial));
11947
11948   if (dial->adjustment)
11949     {
11950       gtk_signal_disconnect_by_data (GTK_OBJECT (dial->adjustment), (gpointer) dial);
11951       gtk_object_unref (GTK_OBJECT (dial->adjustment));
11952     }
11953
11954   dial->adjustment = adjustment;
11955   gtk_object_ref (GTK_OBJECT (dial->adjustment));
11956
11957   gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
11958                       (GtkSignalFunc) gtk_dial_adjustment_changed,
11959                       (gpointer) dial);
11960   gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
11961                       (GtkSignalFunc) gtk_dial_adjustment_value_changed,
11962                       (gpointer) dial);
11963
11964   dial->old_value = adjustment->value;
11965   dial->old_lower = adjustment->lower;
11966   dial->old_upper = adjustment->upper;
11967
11968   gtk_dial_update (dial);
11969 }
11970 </programlisting>
11971
11972 </sect2>
11973
11974 <!-- ----------------------------------------------------------------- -->
11975 <sect2>
11976 <title><literal>gtk_dial_realize()</literal></title>
11977
11978 <para>Now we come to some new types of functions. First, we have a function
11979 that does the work of creating the X window. Notice that a mask is
11980 passed to the function <literal>gdk_window_new()</literal> which specifies which fields of
11981 the GdkWindowAttr structure actually have data in them (the remaining
11982 fields will be given default values). Also worth noting is the way the
11983 event mask of the widget is created. We call
11984 <literal>gtk_widget_get_events()</literal> to retrieve the event mask that the user
11985 has specified for this widget (with <literal>gtk_widget_set_events()</literal>), and
11986 add the events that we are interested in ourselves.</para>
11987
11988 <para>After creating the window, we set its style and background, and put a
11989 pointer to the widget in the user data field of the GdkWindow. This
11990 last step allows GTK to dispatch events for this window to the correct
11991 widget.</para>
11992
11993 <programlisting role="C">
11994 static void
11995 gtk_dial_realize (GtkWidget *widget)
11996 {
11997   GtkDial *dial;
11998   GdkWindowAttr attributes;
11999   gint attributes_mask;
12000
12001   g_return_if_fail (widget != NULL);
12002   g_return_if_fail (GTK_IS_DIAL (widget));
12003
12004   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
12005   dial = GTK_DIAL (widget);
12006
12007   attributes.x = widget->allocation.x;
12008   attributes.y = widget->allocation.y;
12009   attributes.width = widget->allocation.width;
12010   attributes.height = widget->allocation.height;
12011   attributes.wclass = GDK_INPUT_OUTPUT;
12012   attributes.window_type = GDK_WINDOW_CHILD;
12013   attributes.event_mask = gtk_widget_get_events (widget) | 
12014     GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | 
12015     GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
12016     GDK_POINTER_MOTION_HINT_MASK;
12017   attributes.visual = gtk_widget_get_visual (widget);
12018   attributes.colormap = gtk_widget_get_colormap (widget);
12019
12020   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
12021   widget->window = gdk_window_new (widget->parent->window, &amp;attributes, attributes_mask);
12022
12023   widget->style = gtk_style_attach (widget->style, widget->window);
12024
12025   gdk_window_set_user_data (widget->window, widget);
12026
12027   gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
12028 }
12029 </programlisting>
12030
12031 </sect2>
12032
12033 <!-- ----------------------------------------------------------------- -->
12034 <sect2>
12035 <title>Size negotiation</title>
12036
12037 <para>Before the first time that the window containing a widget is
12038 displayed, and whenever the layout of the window changes, GTK asks
12039 each child widget for its desired size. This request is handled by the
12040 function <literal>gtk_dial_size_request()</literal>. Since our widget isn't a
12041 container widget, and has no real constraints on its size, we just
12042 return a reasonable default value.</para>
12043
12044 <programlisting role="C">
12045 static void 
12046 gtk_dial_size_request (GtkWidget      *widget,
12047                        GtkRequisition *requisition)
12048 {
12049   requisition->width = DIAL_DEFAULT_SIZE;
12050   requisition->height = DIAL_DEFAULT_SIZE;
12051 }
12052 </programlisting>
12053
12054 <para>After all the widgets have requested an ideal size, the layout of the
12055 window is computed and each child widget is notified of its actual
12056 size. Usually, this will be at least as large as the requested size,
12057 but if for instance the user has resized the window, it may
12058 occasionally be smaller than the requested size. The size notification
12059 is handled by the function <literal>gtk_dial_size_allocate()</literal>. Notice that
12060 as well as computing the sizes of some component pieces for future
12061 use, this routine also does the grunt work of moving the widget's X
12062 window into the new position and size.</para>
12063
12064 <programlisting role="C">
12065 static void
12066 gtk_dial_size_allocate (GtkWidget     *widget,
12067                         GtkAllocation *allocation)
12068 {
12069   GtkDial *dial;
12070
12071   g_return_if_fail (widget != NULL);
12072   g_return_if_fail (GTK_IS_DIAL (widget));
12073   g_return_if_fail (allocation != NULL);
12074
12075   widget->allocation = *allocation;
12076   if (GTK_WIDGET_REALIZED (widget))
12077     {
12078       dial = GTK_DIAL (widget);
12079
12080       gdk_window_move_resize (widget->window,
12081                               allocation->x, allocation->y,
12082                               allocation->width, allocation->height);
12083
12084       dial->radius = MAX(allocation->width,allocation->height) * 0.45;
12085       dial->pointer_width = dial->radius / 5;
12086     }
12087 }
12088 </programlisting>
12089
12090 </sect2>
12091
12092 <!-- ----------------------------------------------------------------- -->
12093 <sect2>
12094 <title><literal>gtk_dial_expose()</literal></title>
12095
12096 <para>As mentioned above, all the drawing of this widget is done in the
12097 handler for expose events. There's not much to remark on here except
12098 the use of the function <literal>gtk_draw_polygon</literal> to draw the pointer with
12099 three dimensional shading according to the colors stored in the
12100 widget's style.</para>
12101
12102 <programlisting role="C">
12103 static gint
12104 gtk_dial_expose (GtkWidget      *widget,
12105                  GdkEventExpose *event)
12106 {
12107   GtkDial *dial;
12108   GdkPoint points[3];
12109   gdouble s,c;
12110   gdouble theta;
12111   gint xc, yc;
12112   gint tick_length;
12113   gint i;
12114
12115   g_return_val_if_fail (widget != NULL, FALSE);
12116   g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
12117   g_return_val_if_fail (event != NULL, FALSE);
12118
12119   if (event->count > 0)
12120     return FALSE;
12121   
12122   dial = GTK_DIAL (widget);
12123
12124   gdk_window_clear_area (widget->window,
12125                          0, 0,
12126                          widget->allocation.width,
12127                          widget->allocation.height);
12128
12129   xc = widget->allocation.width/2;
12130   yc = widget->allocation.height/2;
12131
12132   /* Draw ticks */
12133
12134   for (i=0; i<25; i++)
12135     {
12136       theta = (i*M_PI/18. - M_PI/6.);
12137       s = sin(theta);
12138       c = cos(theta);
12139
12140       tick_length = (i%6 == 0) ? dial->pointer_width : dial->pointer_width/2;
12141       
12142       gdk_draw_line (widget->window,
12143                      widget->style->fg_gc[widget->state],
12144                      xc + c*(dial->radius - tick_length),
12145                      yc - s*(dial->radius - tick_length),
12146                      xc + c*dial->radius,
12147                      yc - s*dial->radius);
12148     }
12149
12150   /* Draw pointer */
12151
12152   s = sin(dial->angle);
12153   c = cos(dial->angle);
12154
12155
12156   points[0].x = xc + s*dial->pointer_width/2;
12157   points[0].y = yc + c*dial->pointer_width/2;
12158   points[1].x = xc + c*dial->radius;
12159   points[1].y = yc - s*dial->radius;
12160   points[2].x = xc - s*dial->pointer_width/2;
12161   points[2].y = yc - c*dial->pointer_width/2;
12162
12163   gtk_draw_polygon (widget->style,
12164                     widget->window,
12165                     GTK_STATE_NORMAL,
12166                     GTK_SHADOW_OUT,
12167                     points, 3,
12168                     TRUE);
12169   
12170   return FALSE;
12171 }
12172 </programlisting>
12173
12174 </sect2>
12175
12176 <!-- ----------------------------------------------------------------- -->
12177 <sect2>
12178 <title>Event handling</title>
12179
12180 <para>The rest of the widget's code handles various types of events, and
12181 isn't too different from what would be found in many GTK
12182 applications. Two types of events can occur - either the user can
12183 click on the widget with the mouse and drag to move the pointer, or
12184 the value of the Adjustment object can change due to some external
12185 circumstance.</para>
12186
12187 <para>When the user clicks on the widget, we check to see if the click was
12188 appropriately near the pointer, and if so, store the button that the
12189 user clicked with in the <literal>button</literal> field of the widget
12190 structure, and grab all mouse events with a call to
12191 <literal>gtk_grab_add()</literal>. Subsequent motion of the mouse causes the
12192 value of the control to be recomputed (by the function
12193 <literal>gtk_dial_update_mouse</literal>). Depending on the policy that has been
12194 set, "value_changed" events are either generated instantly
12195 (<literal>GTK_UPDATE_CONTINUOUS</literal>), after a delay in a timer added with
12196 <literal>gtk_timeout_add()</literal> (<literal>GTK_UPDATE_DELAYED</literal>), or only when the
12197 button is released (<literal>GTK_UPDATE_DISCONTINUOUS</literal>).</para>
12198
12199 <programlisting role="C">
12200 static gint
12201 gtk_dial_button_press (GtkWidget      *widget,
12202                        GdkEventButton *event)
12203 {
12204   GtkDial *dial;
12205   gint dx, dy;
12206   double s, c;
12207   double d_parallel;
12208   double d_perpendicular;
12209
12210   g_return_val_if_fail (widget != NULL, FALSE);
12211   g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
12212   g_return_val_if_fail (event != NULL, FALSE);
12213
12214   dial = GTK_DIAL (widget);
12215
12216   /* Determine if button press was within pointer region - we 
12217      do this by computing the parallel and perpendicular distance of
12218      the point where the mouse was pressed from the line passing through
12219      the pointer */
12220   
12221   dx = event->x - widget->allocation.width / 2;
12222   dy = widget->allocation.height / 2 - event->y;
12223   
12224   s = sin(dial->angle);
12225   c = cos(dial->angle);
12226   
12227   d_parallel = s*dy + c*dx;
12228   d_perpendicular = fabs(s*dx - c*dy);
12229   
12230   if (!dial->button &&
12231       (d_perpendicular < dial->pointer_width/2) &&
12232       (d_parallel > - dial->pointer_width))
12233     {
12234       gtk_grab_add (widget);
12235
12236       dial->button = event->button;
12237
12238       gtk_dial_update_mouse (dial, event->x, event->y);
12239     }
12240
12241   return FALSE;
12242 }
12243
12244 static gint
12245 gtk_dial_button_release (GtkWidget      *widget,
12246                           GdkEventButton *event)
12247 {
12248   GtkDial *dial;
12249
12250   g_return_val_if_fail (widget != NULL, FALSE);
12251   g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
12252   g_return_val_if_fail (event != NULL, FALSE);
12253
12254   dial = GTK_DIAL (widget);
12255
12256   if (dial->button == event->button)
12257     {
12258       gtk_grab_remove (widget);
12259
12260       dial->button = 0;
12261
12262       if (dial->policy == GTK_UPDATE_DELAYED)
12263         gtk_timeout_remove (dial->timer);
12264       
12265       if ((dial->policy != GTK_UPDATE_CONTINUOUS) &&
12266           (dial->old_value != dial->adjustment->value))
12267         gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
12268     }
12269
12270   return FALSE;
12271 }
12272
12273 static gint
12274 gtk_dial_motion_notify (GtkWidget      *widget,
12275                          GdkEventMotion *event)
12276 {
12277   GtkDial *dial;
12278   GdkModifierType mods;
12279   gint x, y, mask;
12280
12281   g_return_val_if_fail (widget != NULL, FALSE);
12282   g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
12283   g_return_val_if_fail (event != NULL, FALSE);
12284
12285   dial = GTK_DIAL (widget);
12286
12287   if (dial->button != 0)
12288     {
12289       x = event->x;
12290       y = event->y;
12291
12292       if (event->is_hint || (event->window != widget->window))
12293         gdk_window_get_pointer (widget->window, &amp;x, &amp;y, &amp;mods);
12294
12295       switch (dial->button)
12296         {
12297         case 1:
12298           mask = GDK_BUTTON1_MASK;
12299           break;
12300         case 2:
12301           mask = GDK_BUTTON2_MASK;
12302           break;
12303         case 3:
12304           mask = GDK_BUTTON3_MASK;
12305           break;
12306         default:
12307           mask = 0;
12308           break;
12309         }
12310
12311       if (mods & mask)
12312         gtk_dial_update_mouse (dial, x,y);
12313     }
12314
12315   return FALSE;
12316 }
12317
12318 static gint
12319 gtk_dial_timer (GtkDial *dial)
12320 {
12321   g_return_val_if_fail (dial != NULL, FALSE);
12322   g_return_val_if_fail (GTK_IS_DIAL (dial), FALSE);
12323
12324   if (dial->policy == GTK_UPDATE_DELAYED)
12325     gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
12326
12327   return FALSE;
12328 }
12329
12330 static void
12331 gtk_dial_update_mouse (GtkDial *dial, gint x, gint y)
12332 {
12333   gint xc, yc;
12334   gfloat old_value;
12335
12336   g_return_if_fail (dial != NULL);
12337   g_return_if_fail (GTK_IS_DIAL (dial));
12338
12339   xc = GTK_WIDGET(dial)->allocation.width / 2;
12340   yc = GTK_WIDGET(dial)->allocation.height / 2;
12341
12342   old_value = dial->adjustment->value;
12343   dial->angle = atan2(yc-y, x-xc);
12344
12345   if (dial->angle < -M_PI/2.)
12346     dial->angle += 2*M_PI;
12347
12348   if (dial->angle < -M_PI/6)
12349     dial->angle = -M_PI/6;
12350
12351   if (dial->angle > 7.*M_PI/6.)
12352     dial->angle = 7.*M_PI/6.;
12353
12354   dial->adjustment->value = dial->adjustment->lower + (7.*M_PI/6 - dial->angle) *
12355     (dial->adjustment->upper - dial->adjustment->lower) / (4.*M_PI/3.);
12356
12357   if (dial->adjustment->value != old_value)
12358     {
12359       if (dial->policy == GTK_UPDATE_CONTINUOUS)
12360         {
12361           gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
12362         }
12363       else
12364         {
12365           gtk_widget_draw (GTK_WIDGET(dial), NULL);
12366
12367           if (dial->policy == GTK_UPDATE_DELAYED)
12368             {
12369               if (dial->timer)
12370                 gtk_timeout_remove (dial->timer);
12371
12372               dial->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
12373                                              (GtkFunction) gtk_dial_timer,
12374                                              (gpointer) dial);
12375             }
12376         }
12377     }
12378 }
12379 </programlisting>
12380
12381 <para>Changes to the Adjustment by external means are communicated to our
12382 widget by the "changed" and "value_changed" signals. The handlers
12383 for these functions call <literal>gtk_dial_update()</literal> to validate the
12384 arguments, compute the new pointer angle, and redraw the widget (by
12385 calling <literal>gtk_widget_draw()</literal>).</para>
12386
12387 <programlisting role="C">
12388 static void
12389 gtk_dial_update (GtkDial *dial)
12390 {
12391   gfloat new_value;
12392   
12393   g_return_if_fail (dial != NULL);
12394   g_return_if_fail (GTK_IS_DIAL (dial));
12395
12396   new_value = dial->adjustment->value;
12397   
12398   if (new_value < dial->adjustment->lower)
12399     new_value = dial->adjustment->lower;
12400
12401   if (new_value > dial->adjustment->upper)
12402     new_value = dial->adjustment->upper;
12403
12404   if (new_value != dial->adjustment->value)
12405     {
12406       dial->adjustment->value = new_value;
12407       gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
12408     }
12409
12410   dial->angle = 7.*M_PI/6. - (new_value - dial->adjustment->lower) * 4.*M_PI/3. /
12411     (dial->adjustment->upper - dial->adjustment->lower);
12412
12413   gtk_widget_draw (GTK_WIDGET(dial), NULL);
12414 }
12415
12416 static void
12417 gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
12418                               gpointer       data)
12419 {
12420   GtkDial *dial;
12421
12422   g_return_if_fail (adjustment != NULL);
12423   g_return_if_fail (data != NULL);
12424
12425   dial = GTK_DIAL (data);
12426
12427   if ((dial->old_value != adjustment->value) ||
12428       (dial->old_lower != adjustment->lower) ||
12429       (dial->old_upper != adjustment->upper))
12430     {
12431       gtk_dial_update (dial);
12432
12433       dial->old_value = adjustment->value;
12434       dial->old_lower = adjustment->lower;
12435       dial->old_upper = adjustment->upper;
12436     }
12437 }
12438
12439 static void
12440 gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
12441                                     gpointer       data)
12442 {
12443   GtkDial *dial;
12444
12445   g_return_if_fail (adjustment != NULL);
12446   g_return_if_fail (data != NULL);
12447
12448   dial = GTK_DIAL (data);
12449
12450   if (dial->old_value != adjustment->value)
12451     {
12452       gtk_dial_update (dial);
12453
12454       dial->old_value = adjustment->value;
12455     }
12456 }
12457 </programlisting>
12458
12459 </sect2>
12460
12461 <!-- ----------------------------------------------------------------- -->
12462 <sect2>
12463 <title>Possible Enhancements</title>
12464
12465 <para>The Dial widget as we've described it so far runs about 670 lines of
12466 code. Although that might sound like a fair bit, we've really
12467 accomplished quite a bit with that much code, especially since much of
12468 that length is headers and boilerplate. However, there are quite a few
12469 more enhancements that could be made to this widget:</para>
12470
12471 <itemizedlist>
12472 <listitem><simpara> If you try this widget out, you'll find that there is some
12473 flashing as the pointer is dragged around. This is because the entire
12474 widget is erased every time the pointer is moved before being
12475 redrawn. Often, the best way to handle this problem is to draw to an
12476 offscreen pixmap, then copy the final results onto the screen in one
12477 step. (The ProgressBar widget draws itself in this fashion.)</simpara>
12478 </listitem>
12479
12480 <listitem><simpara> The user should be able to use the up and down arrow keys to
12481 increase and decrease the value.</simpara>
12482 </listitem>
12483
12484 <listitem><simpara> It would be nice if the widget had buttons to increase and
12485 decrease the value in small or large steps. Although it would be
12486 possible to use embedded Button widgets for this, we would also like
12487 the buttons to auto-repeat when held down, as the arrows on a
12488 scrollbar do. Most of the code to implement this type of behavior can
12489 be found in the Range widget.</simpara>
12490 </listitem>
12491
12492 <listitem><simpara> The Dial widget could be made into a container widget with a
12493 single child widget positioned at the bottom between the buttons
12494 mentioned above. The user could then add their choice of a label or
12495 entry widget to display the current value of the dial.</simpara>
12496 </listitem>
12497 </itemizedlist>
12498
12499 </sect2>
12500 </sect1>
12501
12502 <!-- ----------------------------------------------------------------- -->
12503 <sect1 id="sec-LearningMore">
12504 <title>Learning More</title>
12505
12506 <para>Only a small part of the many details involved in creating widgets
12507 could be described above. If you want to write your own widgets, the
12508 best source of examples is the GTK source itself. Ask yourself some
12509 questions about the widget you want to write: IS it a Container
12510 widget? Does it have its own window? Is it a modification of an
12511 existing widget? Then find a similar widget, and start making changes.
12512 Good luck!</para>
12513
12514 </sect1>
12515 </chapter>
12516
12517 <!-- ***************************************************************** -->
12518 <chapter id="ch-Scribble">
12519 <title>Scribble, A Simple Example Drawing Program</title>
12520
12521 <!-- ----------------------------------------------------------------- -->
12522 <sect1 id="sec-ScribbleOverview">
12523 <title>Overview</title>
12524
12525 <para>In this section, we will build a simple drawing program. In the
12526 process, we will examine how to handle mouse events, how to draw in a
12527 window, and how to do drawing better by using a backing pixmap. After
12528 creating the simple drawing program, we will extend it by adding
12529 support for XInput devices, such as drawing tablets. GTK provides
12530 support routines which makes getting extended information, such as
12531 pressure and tilt, from such devices quite easy.</para>
12532
12533 <para>
12534 <inlinemediaobject>
12535 <imageobject>
12536 <imagedata fileref="images/scribble.png" format="png">
12537 </imageobject>
12538 </inlinemediaobject>
12539 </para>
12540
12541 </sect1>
12542
12543 <!-- ----------------------------------------------------------------- -->
12544 <sect1 id="sec-EventHandling">
12545 <title>Event Handling</title>
12546
12547 <para>The GTK signals we have already discussed are for high-level actions,
12548 such as a menu item being selected. However, sometimes it is useful to
12549 learn about lower-level occurrences, such as the mouse being moved, or
12550 a key being pressed. There are also GTK signals corresponding to these
12551 low-level <emphasis>events</emphasis>. The handlers for these signals have an
12552 extra parameter which is a pointer to a structure containing
12553 information about the event. For instance, motion event handlers are
12554 passed a pointer to a GdkEventMotion structure which looks (in part)
12555 like:</para>
12556
12557 <programlisting role="C">
12558 struct _GdkEventMotion
12559 {
12560   GdkEventType type;
12561   GdkWindow *window;
12562   guint32 time;
12563   gdouble x;
12564   gdouble y;
12565   ...
12566   guint state;
12567   ...
12568 };
12569 </programlisting>
12570
12571 <para><literal>type</literal> will be set to the event type, in this case
12572 <literal>GDK_MOTION_NOTIFY</literal>, window is the window in which the event
12573 occurred. <literal>x</literal> and <literal>y</literal> give the coordinates of the event.
12574 <literal>state</literal> specifies the modifier state when the event
12575 occurred (that is, it specifies which modifier keys and mouse buttons
12576 were pressed). It is the bitwise OR of some of the following:</para>
12577
12578 <programlisting role="C">
12579 GDK_SHIFT_MASK  
12580 GDK_LOCK_MASK   
12581 GDK_CONTROL_MASK
12582 GDK_MOD1_MASK   
12583 GDK_MOD2_MASK   
12584 GDK_MOD3_MASK   
12585 GDK_MOD4_MASK   
12586 GDK_MOD5_MASK   
12587 GDK_BUTTON1_MASK
12588 GDK_BUTTON2_MASK
12589 GDK_BUTTON3_MASK
12590 GDK_BUTTON4_MASK
12591 GDK_BUTTON5_MASK
12592 </programlisting>
12593
12594 <para>As for other signals, to determine what happens when an event occurs
12595 we call <literal>gtk_signal_connect()</literal>. But we also need let GTK
12596 know which events we want to be notified about. To do this, we call
12597 the function:</para>
12598
12599 <programlisting role="C">
12600 void gtk_widget_set_events (GtkWidget *widget,
12601                             gint      events);
12602 </programlisting>
12603
12604 <para>The second field specifies the events we are interested in. It
12605 is the bitwise OR of constants that specify different types
12606 of events. For future reference the event types are:</para>
12607
12608 <programlisting role="C">
12609 GDK_EXPOSURE_MASK
12610 GDK_POINTER_MOTION_MASK
12611 GDK_POINTER_MOTION_HINT_MASK
12612 GDK_BUTTON_MOTION_MASK     
12613 GDK_BUTTON1_MOTION_MASK    
12614 GDK_BUTTON2_MOTION_MASK    
12615 GDK_BUTTON3_MOTION_MASK    
12616 GDK_BUTTON_PRESS_MASK      
12617 GDK_BUTTON_RELEASE_MASK    
12618 GDK_KEY_PRESS_MASK         
12619 GDK_KEY_RELEASE_MASK       
12620 GDK_ENTER_NOTIFY_MASK      
12621 GDK_LEAVE_NOTIFY_MASK      
12622 GDK_FOCUS_CHANGE_MASK      
12623 GDK_STRUCTURE_MASK         
12624 GDK_PROPERTY_CHANGE_MASK   
12625 GDK_PROXIMITY_IN_MASK      
12626 GDK_PROXIMITY_OUT_MASK     
12627 </programlisting>
12628
12629 <para>There are a few subtle points that have to be observed when calling
12630 <literal>gtk_widget_set_events()</literal>. First, it must be called before the X window
12631 for a GTK widget is created. In practical terms, this means you
12632 should call it immediately after creating the widget. Second, the
12633 widget must have an associated X window. For efficiency, many widget
12634 types do not have their own window, but draw in their parent's window.
12635 These widgets are:</para>
12636
12637 <programlisting role="C">
12638 GtkAlignment
12639 GtkArrow
12640 GtkBin
12641 GtkBox
12642 GtkImage
12643 GtkItem
12644 GtkLabel
12645 GtkPixmap
12646 GtkScrolledWindow
12647 GtkSeparator
12648 GtkTable
12649 GtkAspectFrame
12650 GtkFrame
12651 GtkVBox
12652 GtkHBox
12653 GtkVSeparator
12654 GtkHSeparator
12655 </programlisting>
12656
12657 <para>To capture events for these widgets, you need to use an EventBox
12658 widget. See the section on the <link linkend="sec-EventBox">EventBox</link> widget for details.</para>
12659
12660 <para>For our drawing program, we want to know when the mouse button is
12661 pressed and when the mouse is moved, so we specify
12662 <literal>GDK_POINTER_MOTION_MASK</literal> and <literal>GDK_BUTTON_PRESS_MASK</literal>. We also
12663 want to know when we need to redraw our window, so we specify
12664 <literal>GDK_EXPOSURE_MASK</literal>. Although we want to be notified via a
12665 Configure event when our window size changes, we don't have to specify
12666 the corresponding <literal>GDK_STRUCTURE_MASK</literal> flag, because it is
12667 automatically specified for all windows.</para>
12668
12669 <para>It turns out, however, that there is a problem with just specifying
12670 <literal>GDK_POINTER_MOTION_MASK</literal>. This will cause the server to add a new
12671 motion event to the event queue every time the user moves the mouse.
12672 Imagine that it takes us 0.1 seconds to handle a motion event, but the
12673 X server queues a new motion event every 0.05 seconds. We will soon
12674 get way behind the users drawing. If the user draws for 5 seconds,
12675 it will take us another 5 seconds to catch up after they release 
12676 the mouse button! What we would like is to only get one motion
12677 event for each event we process. The way to do this is to 
12678 specify <literal>GDK_POINTER_MOTION_HINT_MASK</literal>. </para>
12679
12680 <para>When we specify <literal>GDK_POINTER_MOTION_HINT_MASK</literal>, the server sends
12681 us a motion event the first time the pointer moves after entering
12682 our window, or after a button press or release event. Subsequent 
12683 motion events will be suppressed until we explicitly ask for
12684 the position of the pointer using the function:</para>
12685
12686 <programlisting role="C">
12687 GdkWindow*    gdk_window_get_pointer     (GdkWindow       *window,
12688                                           gint            *x,
12689                                           gint            *y,
12690                                           GdkModifierType *mask);
12691 </programlisting>
12692
12693 <para>(There is another function, <literal>gtk_widget_get_pointer()</literal> which
12694 has a simpler interface, but turns out not to be very useful, since
12695 it only retrieves the position of the mouse, not whether the buttons
12696 are pressed.)</para>
12697
12698 <para>The code to set the events for our window then looks like:</para>
12699
12700 <programlisting role="C">
12701   gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
12702                       (GtkSignalFunc) expose_event, NULL);
12703   gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event",
12704                       (GtkSignalFunc) configure_event, NULL);
12705   gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event",
12706                       (GtkSignalFunc) motion_notify_event, NULL);
12707   gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event",
12708                       (GtkSignalFunc) button_press_event, NULL);
12709
12710   gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
12711                          | GDK_LEAVE_NOTIFY_MASK
12712                          | GDK_BUTTON_PRESS_MASK
12713                          | GDK_POINTER_MOTION_MASK
12714                          | GDK_POINTER_MOTION_HINT_MASK);
12715 </programlisting>
12716
12717 <para>We'll save the "expose_event" and "configure_event" handlers for
12718 later. The "motion_notify_event" and "button_press_event" handlers
12719 are pretty simple:</para>
12720
12721 <programlisting role="C">
12722 static gint
12723 button_press_event (GtkWidget *widget, GdkEventButton *event)
12724 {
12725   if (event->button == 1 &amp;&amp; pixmap != NULL)
12726       draw_brush (widget, event->x, event->y);
12727
12728   return TRUE;
12729 }
12730
12731 static gint
12732 motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
12733 {
12734   int x, y;
12735   GdkModifierType state;
12736
12737   if (event->is_hint)
12738     gdk_window_get_pointer (event->window, &amp;x, &amp;y, &amp;state);
12739   else
12740     {
12741       x = event->x;
12742       y = event->y;
12743       state = event->state;
12744     }
12745     
12746   if (state &amp; GDK_BUTTON1_MASK &amp;&amp; pixmap != NULL)
12747     draw_brush (widget, x, y);
12748   
12749   return TRUE;
12750 }
12751 </programlisting>
12752
12753 </sect1>
12754
12755 <!-- ----------------------------------------------------------------- -->
12756 <sect1 id="sec-TheDrawingAreaWidget">
12757 <title>The DrawingArea Widget, And Drawing</title>
12758
12759 <para>We now turn to the process of drawing on the screen. The 
12760 widget we use for this is the DrawingArea widget. A drawing area
12761 widget is essentially an X window and nothing more. It is a blank
12762 canvas in which we can draw whatever we like. A drawing area
12763 is created using the call:</para>
12764
12765 <programlisting role="C">
12766 GtkWidget* gtk_drawing_area_new        (void);
12767 </programlisting>
12768
12769 <para>A default size for the widget can be specified by calling:</para>
12770
12771 <programlisting role="C">
12772 void       gtk_drawing_area_size       (GtkDrawingArea      *darea,
12773                                         gint                 width,
12774                                         gint                 height);
12775 </programlisting>
12776
12777 <para>This default size can be overridden, as is true for all widgets,
12778 by calling <literal>gtk_widget_set_size_request()</literal>, and that, in turn, can
12779 be overridden if the user manually resizes the the window containing
12780 the drawing area.</para>
12781
12782 <para>It should be noted that when we create a DrawingArea widget, we are
12783 <emphasis>completely</emphasis> responsible for drawing the contents. If our
12784 window is obscured then uncovered, we get an exposure event and must
12785 redraw what was previously hidden.</para>
12786
12787 <para>Having to remember everything that was drawn on the screen so we
12788 can properly redraw it can, to say the least, be a nuisance. In
12789 addition, it can be visually distracting if portions of the
12790 window are cleared, then redrawn step by step. The solution to
12791 this problem is to use an offscreen <emphasis>backing pixmap</emphasis>.
12792 Instead of drawing directly to the screen, we draw to an image
12793 stored in server memory but not displayed, then when the image
12794 changes or new portions of the image are displayed, we copy the
12795 relevant portions onto the screen.</para>
12796
12797 <para>To create an offscreen pixmap, we call the function:</para>
12798
12799 <programlisting role="C">
12800 GdkPixmap* gdk_pixmap_new               (GdkWindow  *window,
12801                                          gint        width,
12802                                          gint        height,
12803                                          gint        depth);
12804 </programlisting>
12805
12806 <para>The <literal>window</literal> parameter specifies a GDK window that this pixmap
12807 takes some of its properties from. <literal>width</literal> and <literal>height</literal>
12808 specify the size of the pixmap. <literal>depth</literal> specifies the <emphasis>color
12809 depth</emphasis>, that is the number of bits per pixel, for the new window.
12810 If the depth is specified as <literal>-1</literal>, it will match the depth
12811 of <literal>window</literal>.</para>
12812
12813 <para>We create the pixmap in our "configure_event" handler. This event
12814 is generated whenever the window changes size, including when it
12815 is originally created.</para>
12816
12817 <programlisting role="C">
12818 /* Backing pixmap for drawing area */
12819 static GdkPixmap *pixmap = NULL;
12820
12821 /* Create a new backing pixmap of the appropriate size */
12822 static gint
12823 configure_event (GtkWidget *widget, GdkEventConfigure *event)
12824 {
12825   if (pixmap)
12826     gdk_pixmap_unref(pixmap);
12827
12828   pixmap = gdk_pixmap_new(widget->window,
12829                           widget->allocation.width,
12830                           widget->allocation.height,
12831                           -1);
12832   gdk_draw_rectangle (pixmap,
12833                       widget->style->white_gc,
12834                       TRUE,
12835                       0, 0,
12836                       widget->allocation.width,
12837                       widget->allocation.height);
12838
12839   return TRUE;
12840 }
12841 </programlisting>
12842
12843 <para>The call to <literal>gdk_draw_rectangle()</literal> clears the pixmap
12844 initially to white. We'll say more about that in a moment.</para>
12845
12846 <para>Our exposure event handler then simply copies the relevant portion
12847 of the pixmap onto the screen (we determine the area we need
12848 to redraw by using the event->area field of the exposure event):</para>
12849
12850 <programlisting role="C">
12851 /* Redraw the screen from the backing pixmap */
12852 static gint
12853 expose_event (GtkWidget *widget, GdkEventExpose *event)
12854 {
12855   gdk_draw_pixmap(widget->window,
12856                   widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
12857                   pixmap,
12858                   event->area.x, event->area.y,
12859                   event->area.x, event->area.y,
12860                   event->area.width, event->area.height);
12861
12862   return FALSE;
12863 }
12864 </programlisting>
12865
12866 <para>We've now seen how to keep the screen up to date with our pixmap, but
12867 how do we actually draw interesting stuff on our pixmap?  There are a
12868 large number of calls in GTK's GDK library for drawing on
12869 <emphasis>drawables</emphasis>. A drawable is simply something that can be drawn
12870 upon. It can be a window, a pixmap, or a bitmap (a black and white
12871 image).  We've already seen two such calls above,
12872 <literal>gdk_draw_rectangle()</literal> and <literal>gdk_draw_pixmap()</literal>. The
12873 complete list is:</para>
12874
12875 <programlisting role="C">
12876 gdk_draw_line ()
12877 gdk_draw_rectangle ()
12878 gdk_draw_arc ()
12879 gdk_draw_polygon ()
12880 gdk_draw_string ()
12881 gdk_draw_text ()
12882 gdk_draw_pixmap ()
12883 gdk_draw_bitmap ()
12884 gdk_draw_image ()
12885 gdk_draw_points ()
12886 gdk_draw_segments ()
12887 </programlisting>
12888
12889 <para>See the reference documentation or the header file
12890 <literal>&lt;gdk/gdk.h&gt;</literal> for further details on these functions.
12891 These functions all share the same first two arguments. The first
12892 argument is the drawable to draw upon, the second argument is a
12893 <emphasis>graphics context</emphasis> (GC). </para>
12894
12895 <para>A graphics context encapsulates information about things such as
12896 foreground and background color and line width. GDK has a full set of
12897 functions for creating and modifying graphics contexts, but to keep
12898 things simple we'll just use predefined graphics contexts. Each widget
12899 has an associated style. (Which can be modified in a gtkrc file, see
12900 the section GTK's rc file.) This, among other things, stores a number
12901 of graphics contexts. Some examples of accessing these graphics
12902 contexts are:</para>
12903
12904 <programlisting role="C">
12905 widget->style->white_gc
12906 widget->style->black_gc
12907 widget->style->fg_gc[GTK_STATE_NORMAL]
12908 widget->style->bg_gc[GTK_WIDGET_STATE(widget)]
12909 </programlisting>
12910
12911 <para>The fields <literal>fg_gc</literal>, <literal>bg_gc</literal>, <literal>dark_gc</literal>, and
12912 <literal>light_gc</literal> are indexed by a parameter of type
12913 <literal>GtkStateType</literal> which can take on the values:</para>
12914
12915 <programlisting role="C">
12916 GTK_STATE_NORMAL,
12917 GTK_STATE_ACTIVE,
12918 GTK_STATE_PRELIGHT,
12919 GTK_STATE_SELECTED,
12920 GTK_STATE_INSENSITIVE
12921 </programlisting>
12922
12923 <para>For instance, for <literal>GTK_STATE_SELECTED</literal> the default foreground
12924 color is white and the default background color, dark blue.</para>
12925
12926 <para>Our function <literal>draw_brush()</literal>, which does the actual drawing
12927 on the screen, is then:</para>
12928
12929 <programlisting role="C">
12930 /* Draw a rectangle on the screen */
12931 static void
12932 draw_brush (GtkWidget *widget, gdouble x, gdouble y)
12933 {
12934   GdkRectangle update_rect;
12935
12936   update_rect.x = x - 5;
12937   update_rect.y = y - 5;
12938   update_rect.width = 10;
12939   update_rect.height = 10;
12940   gdk_draw_rectangle (pixmap,
12941                       widget->style->black_gc,
12942                       TRUE,
12943                       update_rect.x, update_rect.y,
12944                       update_rect.width, update_rect.height);
12945   gtk_widget_draw (widget, &amp;update_rect);
12946 }
12947 </programlisting>
12948
12949 <para>After we draw the rectangle representing the brush onto the pixmap,
12950 we call the function:</para>
12951
12952 <programlisting role="C">
12953 void       gtk_widget_draw                (GtkWidget           *widget,
12954                                            GdkRectangle        *area);
12955 </programlisting>
12956
12957 <para>which notifies X that the area given by the <literal>area</literal> parameter
12958 needs to be updated. X will eventually generate an expose event
12959 (possibly combining the areas passed in several calls to
12960 <literal>gtk_widget_draw()</literal>) which will cause our expose event handler
12961 to copy the relevant portions to the screen.</para>
12962
12963 <para>We have now covered the entire drawing program except for a few
12964 mundane details like creating the main window.</para>
12965
12966 </sect1>
12967
12968 <!-- ----------------------------------------------------------------- -->
12969 <sect1 id="sec-AddingXInputSupport">
12970 <title>Adding XInput support</title>
12971
12972 <para>It is now possible to buy quite inexpensive input devices such 
12973 as drawing tablets, which allow drawing with a much greater
12974 ease of artistic expression than does a mouse. The simplest way
12975 to use such devices is simply as a replacement for the mouse,
12976 but that misses out many of the advantages of these devices,
12977 such as:</para>
12978
12979 <itemizedlist>
12980 <listitem><simpara> Pressure sensitivity</simpara>
12981 </listitem>
12982 <listitem><simpara> Tilt reporting</simpara>
12983 </listitem>
12984 <listitem><simpara> Sub-pixel positioning</simpara>
12985 </listitem>
12986 <listitem><simpara> Multiple inputs (for example, a stylus with a point and eraser)</simpara>
12987 </listitem>
12988 </itemizedlist>
12989
12990 <para>For information about the XInput extension, see the <ulink
12991 url="http://www.gtk.org/~otaylor/xinput/howto/index.html">XInput HOWTO</ulink>.</para>
12992
12993 <para>If we examine the full definition of, for example, the GdkEventMotion
12994 structure, we see that it has fields to support extended device
12995 information.</para>
12996
12997 <programlisting role="C">
12998 struct _GdkEventMotion
12999 {
13000   GdkEventType type;
13001   GdkWindow *window;
13002   guint32 time;
13003   gdouble x;
13004   gdouble y;
13005   gdouble pressure;
13006   gdouble xtilt;
13007   gdouble ytilt;
13008   guint state;
13009   gint16 is_hint;
13010   GdkInputSource source;
13011   guint32 deviceid;
13012 };
13013 </programlisting>
13014
13015 <para><literal>pressure</literal> gives the pressure as a floating point number between
13016 0 and 1. <literal>xtilt</literal> and <literal>ytilt</literal> can take on values between 
13017 -1 and 1, corresponding to the degree of tilt in each direction.
13018 <literal>source</literal> and <literal>deviceid</literal> specify the device for which the
13019 event occurred in two different ways. <literal>source</literal> gives some simple
13020 information about the type of device. It can take the enumeration
13021 values:</para>
13022
13023 <programlisting role="C">
13024 GDK_SOURCE_MOUSE
13025 GDK_SOURCE_PEN
13026 GDK_SOURCE_ERASER
13027 GDK_SOURCE_CURSOR
13028 </programlisting>
13029
13030 <para><literal>deviceid</literal> specifies a unique numeric ID for the device. This can
13031 be used to find out further information about the device using the
13032 <literal>gdk_input_list_devices()</literal> call (see below). The special value
13033 <literal>GDK_CORE_POINTER</literal> is used for the core pointer device. (Usually
13034 the mouse.)</para>
13035
13036 <!-- ----------------------------------------------------------------- -->
13037 <sect2>
13038 <title>Enabling extended device information</title>
13039
13040 <para>To let GTK know about our interest in the extended device information,
13041 we merely have to add a single line to our program:</para>
13042
13043 <programlisting role="C">
13044 gtk_widget_set_extension_events (drawing_area, GDK_EXTENSION_EVENTS_CURSOR);
13045 </programlisting>
13046
13047 <para>By giving the value <literal>GDK_EXTENSION_EVENTS_CURSOR</literal> we say that
13048 we are interested in extension events, but only if we don't have
13049 to draw our own cursor. See the section <link
13050 linkend="sec-FurtherSophistications"> Further Sophistications </link> below
13051 for more information about drawing the cursor. We could also 
13052 give the values <literal>GDK_EXTENSION_EVENTS_ALL</literal> if we were willing 
13053 to draw our own cursor, or <literal>GDK_EXTENSION_EVENTS_NONE</literal> to revert
13054 back to the default condition.</para>
13055
13056 <para>This is not completely the end of the story however. By default,
13057 no extension devices are enabled. We need a mechanism to allow
13058 users to enable and configure their extension devices. GTK provides
13059 the InputDialog widget to automate this process. The following
13060 procedure manages an InputDialog widget. It creates the dialog if
13061 it isn't present, and raises it to the top otherwise.</para>
13062
13063 <programlisting role="C">
13064 void
13065 input_dialog_destroy (GtkWidget *w, gpointer data)
13066 {
13067   *((GtkWidget **)data) = NULL;
13068 }
13069
13070 void
13071 create_input_dialog ()
13072 {
13073   static GtkWidget *inputd = NULL;
13074
13075   if (!inputd)
13076     {
13077       inputd = gtk_input_dialog_new();
13078
13079       gtk_signal_connect (GTK_OBJECT(inputd), "destroy",
13080                           (GtkSignalFunc)input_dialog_destroy, &amp;inputd);
13081       gtk_signal_connect_object (GTK_OBJECT(GTK_INPUT_DIALOG(inputd)->close_button),
13082                                  "clicked",
13083                                  (GtkSignalFunc)gtk_widget_hide,
13084                                  GTK_OBJECT(inputd));
13085       gtk_widget_hide ( GTK_INPUT_DIALOG(inputd)->save_button);
13086
13087       gtk_widget_show (inputd);
13088     }
13089   else
13090     {
13091       if (!GTK_WIDGET_MAPPED(inputd))
13092         gtk_widget_show(inputd);
13093       else
13094         gdk_window_raise(inputd->window);
13095     }
13096 }
13097 </programlisting>
13098
13099 <para>(You might want to take note of the way we handle this dialog.  By
13100 connecting to the "destroy" signal, we make sure that we don't keep a
13101 pointer to dialog around after it is destroyed - that could lead to a
13102 segfault.)</para>
13103
13104 <para>The InputDialog has two buttons "Close" and "Save", which by default
13105 have no actions assigned to them. In the above function we make
13106 "Close" hide the dialog, hide the "Save" button, since we don't
13107 implement saving of XInput options in this program.</para>
13108
13109 </sect2>
13110
13111 <!-- ----------------------------------------------------------------- -->
13112 <sect2>
13113 <title>Using extended device information</title>
13114
13115 <para>Once we've enabled the device, we can just use the extended 
13116 device information in the extra fields of the event structures.
13117 In fact, it is always safe to use this information since these
13118 fields will have reasonable default values even when extended
13119 events are not enabled.</para>
13120
13121 <para>Once change we do have to make is to call
13122 <literal>gdk_input_window_get_pointer()</literal> instead of
13123 <literal>gdk_window_get_pointer</literal>. This is necessary because
13124 <literal>gdk_window_get_pointer</literal> doesn't return the extended device
13125 information.</para>
13126
13127 <programlisting role="C">
13128 void gdk_input_window_get_pointer( GdkWindow       *window,
13129                                    guint32         deviceid,
13130                                    gdouble         *x,
13131                                    gdouble         *y,
13132                                    gdouble         *pressure,
13133                                    gdouble         *xtilt,
13134                                    gdouble         *ytilt,
13135                                    GdkModifierType *mask);
13136 </programlisting>
13137
13138 <para>When calling this function, we need to specify the device ID as
13139 well as the window. Usually, we'll get the device ID from the
13140 <literal>deviceid</literal> field of an event structure. Again, this function
13141 will return reasonable values when extension events are not
13142 enabled. (In this case, <literal>event->deviceid</literal> will have the value
13143 <literal>GDK_CORE_POINTER</literal>).</para>
13144
13145 <para>So the basic structure of our button-press and motion event handlers
13146 doesn't change much - we just need to add code to deal with the
13147 extended information.</para>
13148
13149 <programlisting role="C">
13150 static gint
13151 button_press_event (GtkWidget *widget, GdkEventButton *event)
13152 {
13153   print_button_press (event->deviceid);
13154   
13155   if (event->button == 1 &amp;&amp; pixmap != NULL)
13156     draw_brush (widget, event->source, event->x, event->y, event->pressure);
13157
13158   return TRUE;
13159 }
13160
13161 static gint
13162 motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
13163 {
13164   gdouble x, y;
13165   gdouble pressure;
13166   GdkModifierType state;
13167
13168   if (event->is_hint)
13169     gdk_input_window_get_pointer (event->window, event->deviceid,
13170                                   &amp;x, &amp;y, &amp;pressure, NULL, NULL, &amp;state);
13171   else
13172     {
13173       x = event->x;
13174       y = event->y;
13175       pressure = event->pressure;
13176       state = event->state;
13177     }
13178     
13179   if (state &amp; GDK_BUTTON1_MASK &amp;&amp; pixmap != NULL)
13180     draw_brush (widget, event->source, x, y, pressure);
13181   
13182   return TRUE;
13183 }
13184 </programlisting>
13185
13186 <para>We also need to do something with the new information. Our new
13187 <literal>draw_brush()</literal> function draws with a different color for
13188 each <literal>event->source</literal> and changes the brush size depending
13189 on the pressure.</para>
13190
13191 <programlisting role="C">
13192 /* Draw a rectangle on the screen, size depending on pressure,
13193    and color on the type of device */
13194 static void
13195 draw_brush (GtkWidget *widget, GdkInputSource source,
13196             gdouble x, gdouble y, gdouble pressure)
13197 {
13198   GdkGC *gc;
13199   GdkRectangle update_rect;
13200
13201   switch (source)
13202     {
13203     case GDK_SOURCE_MOUSE:
13204       gc = widget->style->dark_gc[GTK_WIDGET_STATE (widget)];
13205       break;
13206     case GDK_SOURCE_PEN:
13207       gc = widget->style->black_gc;
13208       break;
13209     case GDK_SOURCE_ERASER:
13210       gc = widget->style->white_gc;
13211       break;
13212     default:
13213       gc = widget->style->light_gc[GTK_WIDGET_STATE (widget)];
13214     }
13215
13216   update_rect.x = x - 10 * pressure;
13217   update_rect.y = y - 10 * pressure;
13218   update_rect.width = 20 * pressure;
13219   update_rect.height = 20 * pressure;
13220   gdk_draw_rectangle (pixmap, gc, TRUE,
13221                       update_rect.x, update_rect.y,
13222                       update_rect.width, update_rect.height);
13223   gtk_widget_draw (widget, &amp;update_rect);
13224 }
13225 </programlisting>
13226
13227 </sect2>
13228
13229 <!-- ----------------------------------------------------------------- -->
13230 <sect2>
13231 <title>Finding out more about a device</title>
13232
13233 <para>As an example of how to find out more about a device, our program
13234 will print the name of the device that generates each button
13235 press. To find out the name of a device, we call the function:</para>
13236
13237 <programlisting role="C">
13238 GList *gdk_input_list_devices               (void);
13239 </programlisting>
13240
13241 <para>which returns a GList (a linked list type from the GLib library)
13242 of GdkDeviceInfo structures. The GdkDeviceInfo structure is defined
13243 as:</para>
13244
13245 <programlisting role="C">
13246 struct _GdkDeviceInfo
13247 {
13248   guint32 deviceid;
13249   gchar *name;
13250   GdkInputSource source;
13251   GdkInputMode mode;
13252   gint has_cursor;
13253   gint num_axes;
13254   GdkAxisUse *axes;
13255   gint num_keys;
13256   GdkDeviceKey *keys;
13257 };
13258 </programlisting>
13259
13260 <para>Most of these fields are configuration information that you can ignore
13261 unless you are implementing XInput configuration saving. The fieldwe
13262 are interested in here is <literal>name</literal> which is simply the name that X
13263 assigns to the device. The other field that isn't configuration
13264 information is <literal>has_cursor</literal>. If <literal>has_cursor</literal> is false, then we
13265 we need to draw our own cursor. But since we've specified
13266 <literal>GDK_EXTENSION_EVENTS_CURSOR</literal>, we don't have to worry about this.</para>
13267
13268 <para>Our <literal>print_button_press()</literal> function simply iterates through
13269 the returned list until it finds a match, then prints out
13270 the name of the device.</para>
13271
13272 <programlisting role="C">
13273 static void
13274 print_button_press (guint32 deviceid)
13275 {
13276   GList *tmp_list;
13277
13278   /* gdk_input_list_devices returns an internal list, so we shouldn't
13279      free it afterwards */
13280   tmp_list = gdk_input_list_devices();
13281
13282   while (tmp_list)
13283     {
13284       GdkDeviceInfo *info = (GdkDeviceInfo *)tmp_list->data;
13285
13286       if (info->deviceid == deviceid)
13287         {
13288           printf("Button press on device '%s'\n", info->name);
13289           return;
13290         }
13291
13292       tmp_list = tmp_list->next;
13293     }
13294 }
13295 </programlisting>
13296
13297 <para>That completes the changes to "XInputize" our program.</para>
13298
13299 </sect2>
13300
13301 <!-- ----------------------------------------------------------------- -->
13302 <sect2 id="sec-FurtherSophistications">
13303 <title>Further sophistications</title>
13304
13305 <para>Although our program now supports XInput quite well, it lacks some
13306 features we would want in a full-featured application. First, the user
13307 probably doesn't want to have to configure their device each time they
13308 run the program, so we should allow them to save the device
13309 configuration. This is done by iterating through the return of
13310 <literal>gdk_input_list_devices()</literal> and writing out the configuration to a
13311 file.</para>
13312
13313 <para>To restore the state next time the program is run, GDK provides
13314 functions to change device configuration:</para>
13315
13316 <programlisting role="C">
13317 gdk_input_set_extension_events()
13318 gdk_input_set_source()
13319 gdk_input_set_mode()
13320 gdk_input_set_axes()
13321 gdk_input_set_key()
13322 </programlisting>
13323
13324 <para>(The list returned from <literal>gdk_input_list_devices()</literal> should not be
13325 modified directly.) An example of doing this can be found in the
13326 drawing program gsumi. (Available from <ulink
13327 url="http://www.msc.cornell.edu/~otaylor/gsumi/">http://www.msc.cornell.edu/~otaylor/gsumi/</ulink>) Eventually, it
13328 would be nice to have a standard way of doing this for all
13329 applications. This probably belongs at a slightly higher level than
13330 GTK, perhaps in the GNOME library.</para>
13331
13332 <para>Another major omission that we have mentioned above is the lack of
13333 cursor drawing. Platforms other than XFree86 currently do not allow
13334 simultaneously using a device as both the core pointer and directly by
13335 an application. See the <ulink
13336 url="http://www.msc.cornell.edu/~otaylor/xinput/XInput-HOWTO.html">XInput-HOWTO</ulink> for more information about this. This means that
13337 applications that want to support the widest audience need to draw
13338 their own cursor.</para>
13339
13340 <para>An application that draws its own cursor needs to do two things:
13341 determine if the current device needs a cursor drawn or not, and
13342 determine if the current device is in proximity. (If the current
13343 device is a drawing tablet, it's a nice touch to make the cursor 
13344 disappear when the stylus is lifted from the tablet. When the
13345 device is touching the stylus, that is called "in proximity.")
13346 The first is done by searching the device list, as we did
13347 to find out the device name. The second is achieved by selecting
13348 "proximity_out" events. An example of drawing one's own cursor is
13349 found in the "testinput" program found in the GTK distribution.</para>
13350
13351 </sect2>
13352
13353 </sect1>
13354 </chapter>
13355
13356 <!-- ***************************************************************** -->
13357 <chapter id="ch-Tips">
13358 <title>Tips For Writing GTK Applications</title>
13359
13360 <para>This section is simply a gathering of wisdom, general style guidelines
13361 and hints to creating good GTK applications. Currently this section
13362 is very short, but I hope it will get longer in future editions of
13363 this tutorial.</para>
13364
13365 <para>Use GNU autoconf and automake! They are your friends :) Automake
13366 examines C files, determines how they depend on each other, and
13367 generates a Makefile so the files can be compiled in the correct
13368 order. Autoconf permits automatic configuration of software
13369 installation, handling a large number of system quirks to increase
13370 portability. I am planning to make a quick intro on them here.</para>
13371
13372 <para>When writing C code, use only C comments (beginning with "/*" and
13373 ending with "*/"), and don't use C++-style comments ("//").  Although
13374 many C compilers understand C++ comments, others don't, and the ANSI C
13375 standard does not require that C++-style comments be processed as
13376 comments.</para>
13377
13378 </chapter>
13379
13380 <!-- ***************************************************************** -->
13381 <chapter id="ch-Contributing">
13382 <title>Contributing</title>
13383
13384 <para>This document, like so much other great software out there, was
13385 created for free by volunteers.  If you are at all knowledgeable about
13386 any aspect of GTK that does not already have documentation, please
13387 consider contributing to this document.</para>
13388
13389 <para>If you do decide to contribute, please mail your text to Tony Gale,
13390 <literal><ulink url="mailto:gale@gtk.org">gale@gtk.org</ulink></literal>. Also, be aware that the entirety of this
13391 document is free, and any addition by you provide must also be
13392 free. That is, people may use any portion of your examples in their
13393 programs, and copies of this document may be distributed at will, etc.</para>
13394
13395 <para>Thank you.</para>
13396
13397 </chapter>
13398
13399 <!-- ***************************************************************** -->
13400 <chapter id="ch-Credits">
13401 <title>Credits</title>
13402
13403 <para>We would like to thank the following for their contributions to this text.</para>
13404
13405 <itemizedlist>
13406 <listitem><simpara>Bawer Dagdeviren, <literal><ulink url="mailto:chamele0n@geocities.com">chamele0n@geocities.com</ulink></literal> for the menus tutorial.</simpara>
13407 </listitem>
13408
13409 <listitem><simpara>Raph Levien, <literal><ulink url="mailto:raph@acm.org">raph@acm.org</ulink></literal>
13410 for hello world ala GTK, widget packing, and general all around wisdom.
13411 He's also generously donated a home for this tutorial.</simpara>
13412 </listitem>
13413
13414 <listitem><simpara>Peter Mattis, <literal><ulink url="mailto:petm@xcf.berkeley.edu">petm@xcf.berkeley.edu</ulink></literal> for the simplest GTK program.. 
13415 and the ability to make it :)</simpara>
13416 </listitem>
13417
13418 <listitem><simpara>Werner Koch <literal><ulink url="mailto:werner.koch@guug.de">werner.koch@guug.de</ulink></literal> for converting the original plain text to
13419 SGML, and the widget class hierarchy.</simpara>
13420 </listitem>
13421
13422 <listitem><simpara>Mark Crichton <literal><ulink
13423 url="mailto:crichton@expert.cc.purdue.edu">crichton@expert.cc.purdue.edu</ulink></literal> for the menu factory code,
13424 and the table packing tutorial.</simpara>
13425 </listitem>
13426
13427 <listitem><simpara>Owen Taylor <literal><ulink url="mailto:owt1@cornell.edu">owt1@cornell.edu</ulink></literal> for the EventBox widget section (and the
13428 patch to the distro).  He's also responsible for the selections code
13429 and tutorial, as well as the sections on writing your own GTK widgets,
13430 and the example application. Thanks a lot Owen for all you help!</simpara>
13431 </listitem>
13432
13433 <listitem><simpara>Mark VanderBoom <literal><ulink url="mailto:mvboom42@calvin.edu">mvboom42@calvin.edu</ulink></literal> for his wonderful work on the
13434 Notebook, Progress Bar, Dialogs, and File selection widgets.  Thanks a
13435 lot Mark!  You've been a great help.</simpara>
13436 </listitem>
13437
13438 <listitem><simpara>Tim Janik <literal><ulink url="mailto:timj@gtk.org">timj@gtk.org</ulink></literal> for his great job on the Lists
13439 Widget. His excellent work on automatically extracting the widget tree
13440 and signal information from GTK. Thanks Tim :)</simpara>
13441 </listitem>
13442
13443 <listitem><simpara>Rajat Datta <literal><ulink url="mailto:rajat@ix.netcom.com">rajat@ix.netcom.com</ulink>
13444 </literal> for the excellent job on the Pixmap
13445 tutorial.</simpara>
13446 </listitem>
13447
13448 <listitem><simpara>Michael K. Johnson <literal><ulink url="mailto:johnsonm@redhat.com">johnsonm@redhat.com</ulink></literal> for info and code for popup menus.</simpara>
13449 </listitem>
13450
13451 <listitem><simpara>David Huggins-Daines <literal><ulink
13452 url="mailto:bn711@freenet.carleton.ca">bn711@freenet.carleton.ca</ulink></literal> for the Range Widgets and Tree
13453 Widget sections.</simpara>
13454 </listitem>
13455
13456 <listitem><simpara>Stefan Mars <literal><ulink url="mailto:mars@lysator.liu.se">mars@lysator.liu.se</ulink></literal> for the CList section.</simpara>
13457 </listitem>
13458
13459 <listitem><simpara>David A. Wheeler <literal><ulink url="mailto:dwheeler@ida.org">dwheeler@ida.org</ulink></literal> for portions of the text on GLib
13460 and various tutorial fixups and improvements.
13461 The GLib text was in turn based on material developed by Damon Chaplin
13462 <literal><ulink url="mailto:DAChaplin@msn.com">DAChaplin@msn.com</ulink></literal></simpara>
13463 </listitem>
13464
13465 <listitem><simpara>David King for style checking the entire document.</simpara>
13466 </listitem>
13467 </itemizedlist>
13468
13469 <para>And to all of you who commented on and helped refine this document.</para>
13470
13471 <para>Thanks.</para>
13472
13473 </chapter>
13474
13475 <!-- ***************************************************************** -->
13476 <chapter id="ch-Copyright">
13477 <title>Tutorial Copyright and Permissions Notice</title>
13478
13479 <para>The GTK Tutorial is Copyright (C) 1997 Ian Main. </para>
13480
13481 <para>Copyright (C) 1998-2002 Tony Gale.</para>
13482
13483 <para>Permission is granted to make and distribute verbatim copies of this 
13484 manual provided the copyright notice and this permission notice are 
13485 preserved on all copies.</para>
13486
13487 <para>Permission is granted to copy and distribute modified versions of 
13488 this document under the conditions for verbatim copying, provided that 
13489 this copyright notice is included exactly as in the original,
13490 and that the entire resulting derived work is distributed under 
13491 the terms of a permission notice identical to this one.</para>
13492
13493 <para>Permission is granted to copy and distribute translations of this 
13494 document into another language, under the above conditions for modified 
13495 versions.</para>
13496
13497 <para>If you are intending to incorporate this document into a published 
13498 work, please contact the maintainer, and we will make an effort 
13499 to ensure that you have the most up to date information available.</para>
13500
13501 <para>There is no guarantee that this document lives up to its intended
13502 purpose.  This is simply provided as a free resource.  As such,
13503 the authors and maintainers of the information provided within can
13504 not make any guarantee that the information is even accurate.</para>
13505
13506 </chapter>
13507
13508 <!-- ***************************************************************** -->
13509 <!-- ***************************************************************** -->
13510
13511 <!-- ***************************************************************** -->
13512 <appendix id="app-GTKSignals">
13513 <title>GTK Signals</title>
13514
13515 <para>As GTK is an object oriented widget set, it has a hierarchy of
13516 inheritance. This inheritance mechanism applies for
13517 signals. Therefore, you should refer to the widget hierarchy tree when
13518 using the signals listed in this section.</para>
13519
13520 <!-- ----------------------------------------------------------------- -->
13521 <sect1 id="sec-GtkObject">
13522 <title>GtkObject</title>
13523
13524 <programlisting role="C">
13525 void GtkObject::destroy (GtkObject *,
13526                          gpointer);
13527 </programlisting>
13528
13529 </sect1>
13530
13531 <!-- ----------------------------------------------------------------- -->
13532 <sect1 id="sec-GtkWidget">
13533 <title>GtkWidget</title>
13534
13535 <programlisting role="C">
13536 void GtkWidget::show    (GtkWidget *,
13537                          gpointer);
13538 void GtkWidget::hide    (GtkWidget *,
13539                          gpointer);
13540 void GtkWidget::map     (GtkWidget *,
13541                          gpointer);
13542 void GtkWidget::unmap   (GtkWidget *,
13543                          gpointer);
13544 void GtkWidget::realize (GtkWidget *,
13545                          gpointer);
13546 void GtkWidget::unrealize       (GtkWidget *,
13547                                  gpointer);
13548 void GtkWidget::draw    (GtkWidget *,
13549                          ggpointer,
13550                          gpointer);
13551 void GtkWidget::draw-focus      (GtkWidget *,
13552                                  gpointer);
13553 void GtkWidget::draw-default    (GtkWidget *,
13554                                  gpointer);
13555 void GtkWidget::size-request    (GtkWidget *,
13556                                  ggpointer,
13557                                  gpointer);
13558 void GtkWidget::size-allocate   (GtkWidget *,
13559                                  ggpointer,
13560                                  gpointer);
13561 void GtkWidget::state-changed   (GtkWidget *,
13562                                  GtkStateType,
13563                                  gpointer);
13564 void GtkWidget::parent-set      (GtkWidget *,
13565                                  GtkObject *,
13566                                  gpointer);
13567 void GtkWidget::style-set       (GtkWidget *,
13568                                  GtkStyle *,
13569                                  gpointer);
13570 void GtkWidget::add-accelerator (GtkWidget *,
13571                                  gguint,
13572                                  GtkAccelGroup *,
13573                                  gguint,
13574                                  GdkModifierType,
13575                                  GtkAccelFlags,
13576                                  gpointer);
13577 void GtkWidget::remove-accelerator      (GtkWidget *,
13578                                          GtkAccelGroup *,
13579                                          gguint,
13580                                          GdkModifierType,
13581                                          gpointer);
13582 gboolean GtkWidget::event       (GtkWidget *,
13583                                  GdkEvent *,
13584                                  gpointer);
13585 gboolean GtkWidget::button-press-event  (GtkWidget *,
13586                                          GdkEvent *,
13587                                          gpointer);
13588 gboolean GtkWidget::button-release-event        (GtkWidget *,
13589                                                  GdkEvent *,
13590                                                  gpointer);
13591 gboolean GtkWidget::motion-notify-event (GtkWidget *,
13592                                          GdkEvent *,
13593                                          gpointer);
13594 gboolean GtkWidget::delete-event        (GtkWidget *,
13595                                          GdkEvent *,
13596                                          gpointer);
13597 gboolean GtkWidget::destroy-event       (GtkWidget *,
13598                                          GdkEvent *,
13599                                          gpointer);
13600 gboolean GtkWidget::expose-event        (GtkWidget *,
13601                                          GdkEvent *,
13602                                          gpointer);
13603 gboolean GtkWidget::key-press-event     (GtkWidget *,
13604                                          GdkEvent *,
13605                                          gpointer);
13606 gboolean GtkWidget::key-release-event   (GtkWidget *,
13607                                          GdkEvent *,
13608                                          gpointer);
13609 gboolean GtkWidget::enter-notify-event  (GtkWidget *,
13610                                          GdkEvent *,
13611                                          gpointer);
13612 gboolean GtkWidget::leave-notify-event  (GtkWidget *,
13613                                          GdkEvent *,
13614                                          gpointer);
13615 gboolean GtkWidget::configure-event     (GtkWidget *,
13616                                          GdkEvent *,
13617                                          gpointer);
13618 gboolean GtkWidget::focus-in-event      (GtkWidget *,
13619                                          GdkEvent *,
13620                                          gpointer);
13621 gboolean GtkWidget::focus-out-event     (GtkWidget *,
13622                                          GdkEvent *,
13623                                          gpointer);
13624 gboolean GtkWidget::map-event   (GtkWidget *,
13625                                  GdkEvent *,
13626                                  gpointer);
13627 gboolean GtkWidget::unmap-event (GtkWidget *,
13628                                  GdkEvent *,
13629                                  gpointer);
13630 gboolean GtkWidget::property-notify-event       (GtkWidget *,
13631                                                  GdkEvent *,
13632                                                  gpointer);
13633 gboolean GtkWidget::selection-clear-event       (GtkWidget *,
13634                                                  GdkEvent *,
13635                                                  gpointer);
13636 gboolean GtkWidget::selection-request-event     (GtkWidget *,
13637                                                  GdkEvent *,
13638                                                  gpointer);
13639 gboolean GtkWidget::selection-notify-event      (GtkWidget *,
13640                                                  GdkEvent *,
13641                                                  gpointer);
13642 void GtkWidget::selection-get   (GtkWidget *,
13643                                  GtkSelectionData *,
13644                                  gguint,
13645                                  gpointer);
13646 void GtkWidget::selection-received      (GtkWidget *,
13647                                          GtkSelectionData *,
13648                                          gguint,
13649                                          gpointer);
13650 gboolean GtkWidget::proximity-in-event  (GtkWidget *,
13651                                          GdkEvent *,
13652                                          gpointer);
13653 gboolean GtkWidget::proximity-out-event (GtkWidget *,
13654                                          GdkEvent *,
13655                                          gpointer);
13656 void GtkWidget::drag-begin      (GtkWidget *,
13657                                  GdkDragContext *,
13658                                  gpointer);
13659 void GtkWidget::drag-end        (GtkWidget *,
13660                                  GdkDragContext *,
13661                                  gpointer);
13662 void GtkWidget::drag-data-delete        (GtkWidget *,
13663                                          GdkDragContext *,
13664                                          gpointer);
13665 void GtkWidget::drag-leave      (GtkWidget *,
13666                                  GdkDragContext *,
13667                                  gguint,
13668                                  gpointer);
13669 gboolean GtkWidget::drag-motion (GtkWidget *,
13670                                  GdkDragContext *,
13671                                  ggint,
13672                                  ggint,
13673                                  gguint,
13674                                  gpointer);
13675 gboolean GtkWidget::drag-drop   (GtkWidget *,
13676                                  GdkDragContext *,
13677                                  ggint,
13678                                  ggint,
13679                                  gguint,
13680                                  gpointer);
13681 void GtkWidget::drag-data-get   (GtkWidget *,
13682                                  GdkDragContext *,
13683                                  GtkSelectionData *,
13684                                  gguint,
13685                                  gguint,
13686                                  gpointer);
13687 void GtkWidget::drag-data-received      (GtkWidget *,
13688                                          GdkDragContext *,
13689                                          ggint,
13690                                          ggint,
13691                                          GtkSelectionData *,
13692                                          gguint,
13693                                          gguint,
13694                                          gpointer);
13695 gboolean GtkWidget::client-event        (GtkWidget *,
13696                                          GdkEvent *,
13697                                          gpointer);
13698 gboolean GtkWidget::no-expose-event     (GtkWidget *,
13699                                          GdkEvent *,
13700                                          gpointer);
13701 gboolean GtkWidget::visibility-notify-event     (GtkWidget *,
13702                                                  GdkEvent *,
13703                                                  gpointer);
13704 void GtkWidget::debug-msg       (GtkWidget *,
13705                                  GtkString *,
13706                                  gpointer);
13707 </programlisting>
13708
13709 </sect1>
13710
13711 <!-- ----------------------------------------------------------------- -->
13712 <sect1 id="sec-GtkData">
13713 <title>GtkData</title>
13714
13715 <programlisting role="C">
13716 void GtkData::disconnect        (GtkData *,
13717                                  gpointer);
13718 </programlisting>
13719
13720 </sect1>
13721
13722 <!-- ----------------------------------------------------------------- -->
13723 <sect1 id="sec-GtkContainer">
13724 <title>GtkContainer</title>
13725
13726 <programlisting role="C">
13727 void GtkContainer::add  (GtkContainer *,
13728                          GtkWidget *,
13729                          gpointer);
13730 void GtkContainer::remove       (GtkContainer *,
13731                                  GtkWidget *,
13732                                  gpointer);
13733 void GtkContainer::check-resize (GtkContainer *,
13734                                  gpointer);
13735 GtkDirectionType GtkContainer::focus    (GtkContainer *,
13736                                          GtkDirectionType,
13737                                          gpointer);
13738 void GtkContainer::set-focus-child      (GtkContainer *,
13739                                          GtkWidget *,
13740                                          gpointer);
13741 </programlisting>
13742
13743 </sect1>
13744
13745 <!-- ----------------------------------------------------------------- -->
13746 <sect1 id="sec-GtkCalendar">
13747 <title>GtkCalendar</title>
13748
13749 <programlisting role="C">
13750 void GtkCalendar::month-changed (GtkCalendar *,
13751                                  gpointer);
13752 void GtkCalendar::day-selected  (GtkCalendar *,
13753                                  gpointer);
13754 void GtkCalendar::day-selected-double-click     (GtkCalendar *,
13755                                                  gpointer);
13756 void GtkCalendar::prev-month    (GtkCalendar *,
13757                                  gpointer);
13758 void GtkCalendar::next-month    (GtkCalendar *,
13759                                  gpointer);
13760 void GtkCalendar::prev-year     (GtkCalendar *,
13761                                  gpointer);
13762 void GtkCalendar::next-year     (GtkCalendar *,
13763                                  gpointer);
13764 </programlisting>
13765
13766 </sect1>
13767
13768 <!-- ----------------------------------------------------------------- -->
13769 <sect1 id="sec-GtkEditable">
13770 <title>GtkEditable</title>
13771
13772 <programlisting role="C">
13773 void GtkEditable::changed       (GtkEditable *,
13774                                  gpointer);
13775 void GtkEditable::insert-text   (GtkEditable *,
13776                                  GtkString *,
13777                                  ggint,
13778                                  ggpointer,
13779                                  gpointer);
13780 void GtkEditable::delete-text   (GtkEditable *,
13781                                  ggint,
13782                                  ggint,
13783                                  gpointer);
13784 void GtkEditable::activate      (GtkEditable *,
13785                                  gpointer);
13786 void GtkEditable::set-editable  (GtkEditable *,
13787                                  gboolean,
13788                                  gpointer);
13789 void GtkEditable::move-cursor   (GtkEditable *,
13790                                  ggint,
13791                                  ggint,
13792                                  gpointer);
13793 void GtkEditable::move-word     (GtkEditable *,
13794                                  ggint,
13795                                  gpointer);
13796 void GtkEditable::move-page     (GtkEditable *,
13797                                  ggint,
13798                                  ggint,
13799                                  gpointer);
13800 void GtkEditable::move-to-row   (GtkEditable *,
13801                                  ggint,
13802                                  gpointer);
13803 void GtkEditable::move-to-column        (GtkEditable *,
13804                                          ggint,
13805                                          gpointer);
13806 void GtkEditable::kill-char     (GtkEditable *,
13807                                  ggint,
13808                                  gpointer);
13809 void GtkEditable::kill-word     (GtkEditable *,
13810                                  ggint,
13811                                  gpointer);
13812 void GtkEditable::kill-line     (GtkEditable *,
13813                                  ggint,
13814                                  gpointer);
13815 void GtkEditable::cut-clipboard (GtkEditable *,
13816                                  gpointer);
13817 void GtkEditable::copy-clipboard        (GtkEditable *,
13818                                          gpointer);
13819 void GtkEditable::paste-clipboard       (GtkEditable *,
13820                                          gpointer);
13821 </programlisting>
13822
13823 </sect1>
13824
13825 <!-- ----------------------------------------------------------------- -->
13826 <sect1 id="sec-GtkNotebook">
13827 <title>GtkNotebook</title>
13828
13829 <programlisting role="C">
13830 void GtkNotebook::switch-page   (GtkNotebook *,
13831                                  ggpointer,
13832                                  gguint,
13833                                  gpointer);
13834 </programlisting>
13835
13836 </sect1>
13837
13838 <!-- ----------------------------------------------------------------- -->
13839 <sect1 id="sec-GtkList">
13840 <title>GtkList</title>
13841
13842 <programlisting role="C">
13843 void GtkList::selection-changed (GtkList *,
13844                                  gpointer);
13845 void GtkList::select-child      (GtkList *,
13846                                  GtkWidget *,
13847                                  gpointer);
13848 void GtkList::unselect-child    (GtkList *,
13849                                  GtkWidget *,
13850                                  gpointer);
13851 </programlisting>
13852
13853 </sect1>
13854
13855 <!-- ----------------------------------------------------------------- -->
13856 <sect1 id="sec-GtkMenuShell">
13857 <title>GtkMenuShell</title>
13858
13859 <programlisting role="C">
13860 void GtkMenuShell::deactivate   (GtkMenuShell *,
13861                                  gpointer);
13862 void GtkMenuShell::selection-done       (GtkMenuShell *,
13863                                          gpointer);
13864 void GtkMenuShell::move-current (GtkMenuShell *,
13865                                  GtkMenuDirectionType,
13866                                  gpointer);
13867 void GtkMenuShell::activate-current     (GtkMenuShell *,
13868                                          gboolean,
13869                                          gpointer);
13870 void GtkMenuShell::cancel       (GtkMenuShell *,
13871                                  gpointer);
13872 </programlisting>
13873
13874 </sect1>
13875
13876 <!-- ----------------------------------------------------------------- -->
13877 <sect1 id="sec-GtkToolbar">
13878 <title>GtkToolbar</title>
13879
13880 <programlisting role="C">
13881 void GtkToolbar::orientation-changed    (GtkToolbar *,
13882                                          ggint,
13883                                          gpointer);
13884 void GtkToolbar::style-changed  (GtkToolbar *,
13885                                  ggint,
13886                                  gpointer);
13887 </programlisting>
13888
13889 </sect1>
13890
13891 <!-- ----------------------------------------------------------------- -->
13892 <sect1 id="sec-GtkButton">
13893 <title>GtkButton</title>
13894
13895 <programlisting role="C">
13896 void GtkButton::pressed (GtkButton *,
13897                          gpointer);
13898 void GtkButton::released        (GtkButton *,
13899                                  gpointer);
13900 void GtkButton::clicked (GtkButton *,
13901                          gpointer);
13902 void GtkButton::enter   (GtkButton *,
13903                          gpointer);
13904 void GtkButton::leave   (GtkButton *,
13905                          gpointer);
13906 </programlisting>
13907
13908 </sect1>
13909
13910 <!-- ----------------------------------------------------------------- -->
13911 <sect1 id="sec-GtkItem">
13912 <title>GtkItem</title>
13913
13914 <programlisting role="C">
13915 void GtkItem::select    (GtkItem *,
13916                          gpointer);
13917 void GtkItem::deselect  (GtkItem *,
13918                          gpointer);
13919 void GtkItem::toggle    (GtkItem *,
13920                          gpointer);
13921 </programlisting>
13922
13923 </sect1>
13924
13925 <!-- ----------------------------------------------------------------- -->
13926 <sect1 id="sec-GtkWindow">
13927 <title>GtkWindow</title>
13928
13929 <programlisting role="C">
13930 void GtkWindow::set-focus       (GtkWindow *,
13931                                  ggpointer,
13932                                  gpointer);
13933 </programlisting>
13934
13935 </sect1>
13936
13937 <!-- ----------------------------------------------------------------- -->
13938 <sect1 id="sec-GtkHandleBox">
13939 <title>GtkHandleBox</title>
13940
13941 <programlisting role="C">
13942 void GtkHandleBox::child-attached       (GtkHandleBox *,
13943                                          GtkWidget *,
13944                                          gpointer);
13945 void GtkHandleBox::child-detached       (GtkHandleBox *,
13946                                          GtkWidget *,
13947                                          gpointer);
13948 </programlisting>
13949
13950 </sect1>
13951
13952 <!-- ----------------------------------------------------------------- -->
13953 <sect1 id="sec-GtkToggleButton">
13954 <title>GtkToggleButton</title>
13955
13956 <programlisting role="C">
13957 void GtkToggleButton::toggled   (GtkToggleButton *,
13958                                  gpointer);
13959 </programlisting>
13960
13961 </sect1>
13962
13963 <!-- ----------------------------------------------------------------- -->
13964 <sect1 id="sec-GtkMenuItem">
13965 <title>GtkMenuItem</title>
13966
13967 <programlisting role="C">
13968 void GtkMenuItem::activate      (GtkMenuItem *,
13969                                  gpointer);
13970 void GtkMenuItem::activate-item (GtkMenuItem *,
13971                                  gpointer);
13972 </programlisting>
13973
13974 </sect1>
13975
13976 <!-- ----------------------------------------------------------------- -->
13977 <sect1 id="sec-GtkCheckMenuItem">
13978 <title>GtkCheckMenuItem</title>
13979
13980 <programlisting role="C">
13981 void GtkCheckMenuItem::toggled  (GtkCheckMenuItem *,
13982                                  gpointer);
13983 </programlisting>
13984
13985 </sect1>
13986
13987 <!-- ----------------------------------------------------------------- -->
13988 <sect1 id="sec-GtkInputDialog">
13989 <title>GtkInputDialog</title>
13990
13991 <programlisting role="C">
13992 void GtkInputDialog::enable-device      (GtkInputDialog *,
13993                                          ggint,
13994                                          gpointer);
13995 void GtkInputDialog::disable-device     (GtkInputDialog *,
13996                                          ggint,
13997                                          gpointer);
13998 </programlisting>
13999
14000 </sect1>
14001
14002 <!-- ----------------------------------------------------------------- -->
14003 <sect1 id="sec-GtkColorSelection">
14004 <title>GtkColorSelection</title>
14005
14006 <programlisting role="C">
14007 void GtkColorSelection::color-changed   (GtkColorSelection *,
14008                                          gpointer);
14009 </programlisting>
14010
14011 </sect1>
14012
14013 <!-- ----------------------------------------------------------------- -->
14014 <sect1 id="sec-GtkStatusBar">
14015 <title>GtkStatusBar</title>
14016
14017 <programlisting role="C">
14018 void GtkStatusbar::text-pushed  (GtkStatusbar *,
14019                                  gguint,
14020                                  GtkString *,
14021                                  gpointer);
14022 void GtkStatusbar::text-popped  (GtkStatusbar *,
14023                                  gguint,
14024                                  GtkString *,
14025                                  gpointer);
14026 </programlisting>
14027
14028 </sect1>
14029
14030 <!-- ----------------------------------------------------------------- -->
14031 <sect1 id="sec-GtkCurve">
14032 <title>GtkCurve</title>
14033
14034 <programlisting role="C">
14035 void GtkCurve::curve-type-changed       (GtkCurve *,
14036                                          gpointer);
14037 </programlisting>
14038
14039 </sect1>
14040
14041 <!-- ----------------------------------------------------------------- -->
14042 <sect1 id="sec-GtkAdjustment">
14043 <title>GtkAdjustment</title>
14044
14045 <programlisting role="C">
14046 void GtkAdjustment::changed     (GtkAdjustment *,
14047                                  gpointer);
14048 void GtkAdjustment::value-changed       (GtkAdjustment *,
14049                                          gpointer);
14050 </programlisting>
14051
14052 </sect1>
14053 </appendix>
14054
14055 <!-- ***************************************************************** -->
14056 <appendix id="app-GDKEventTypes">
14057 <title>GDK Event Types</title>
14058
14059 <para>The following data types are passed into event handlers by GTK+. For
14060 each data type listed, the signals that use this data type are listed.</para>
14061
14062 <itemizedlist>
14063 <listitem><simpara>  GdkEvent</simpara>
14064           <itemizedlist>
14065           <listitem><simpara>drag_end_event</simpara>
14066           </listitem>
14067           </itemizedlist>
14068 </listitem>
14069
14070 <listitem><simpara>  GdkEventType<</simpara>
14071 </listitem>
14072
14073 <listitem><simpara>  GdkEventAny</simpara>
14074           <itemizedlist>
14075           <listitem><simpara>delete_event</simpara>
14076           </listitem>
14077           <listitem><simpara>destroy_event</simpara>
14078           </listitem>
14079           <listitem><simpara>map_event</simpara>
14080           </listitem>
14081           <listitem><simpara>unmap_event</simpara>
14082           </listitem>
14083           <listitem><simpara>no_expose_event</simpara>
14084           </listitem>
14085           </itemizedlist>
14086 </listitem>
14087
14088 <listitem><simpara>  GdkEventExpose</simpara>
14089           <itemizedlist>
14090           <listitem><simpara>expose_event</simpara>
14091           </listitem>
14092           </itemizedlist>
14093 </listitem>
14094
14095 <listitem><simpara>  GdkEventNoExpose</simpara>
14096 </listitem>
14097
14098 <listitem><simpara>  GdkEventVisibility</simpara>
14099 </listitem>
14100
14101 <listitem><simpara>  GdkEventMotion</simpara>
14102           <itemizedlist>
14103           <listitem><simpara>motion_notify_event</simpara>
14104           </listitem>
14105           </itemizedlist>
14106 </listitem>
14107 <listitem><simpara>  GdkEventButton</simpara>
14108           <itemizedlist>
14109           <listitem><simpara>button_press_event</simpara>
14110           </listitem>
14111           <listitem><simpara>button_release_event</simpara>
14112           </listitem>
14113           </itemizedlist>
14114 </listitem>
14115
14116 <listitem><simpara>  GdkEventKey</simpara>
14117           <itemizedlist>
14118           <listitem><simpara>key_press_event</simpara>
14119           </listitem>
14120           <listitem><simpara>key_release_event</simpara>
14121           </listitem>
14122           </itemizedlist>
14123 </listitem>
14124
14125 <listitem><simpara>  GdkEventCrossing</simpara>
14126           <itemizedlist>
14127           <listitem><simpara>enter_notify_event</simpara>
14128           </listitem>
14129           <listitem><simpara>leave_notify_event</simpara>
14130           </listitem>
14131           </itemizedlist>
14132 </listitem>
14133
14134 <listitem><simpara>  GdkEventFocus</simpara>
14135           <itemizedlist>
14136           <listitem><simpara>focus_in_event</simpara>
14137           </listitem>
14138           <listitem><simpara>focus_out_event</simpara>
14139           </listitem>
14140           </itemizedlist>
14141 </listitem>
14142
14143 <listitem><simpara>  GdkEventConfigure</simpara>
14144           <itemizedlist>
14145           <listitem><simpara>configure_event</simpara>
14146           </listitem>
14147           </itemizedlist>
14148 </listitem>
14149
14150 <listitem><simpara>  GdkEventProperty</simpara>
14151           <itemizedlist>
14152           <listitem><simpara>property_notify_event</simpara>
14153           </listitem>
14154           </itemizedlist>
14155 </listitem>
14156
14157 <listitem><simpara>  GdkEventSelection</simpara>
14158           <itemizedlist>
14159           <listitem><simpara>selection_clear_event</simpara>
14160           </listitem>
14161           <listitem><simpara>selection_request_event</simpara>
14162           </listitem>
14163           <listitem><simpara>selection_notify_event</simpara>
14164           </listitem>
14165           </itemizedlist>
14166 </listitem>
14167
14168 <listitem><simpara>  GdkEventProximity</simpara>
14169           <itemizedlist>
14170           <listitem><simpara>proximity_in_event</simpara>
14171           </listitem>
14172           <listitem><simpara>proximity_out_event</simpara>
14173           </listitem>
14174           </itemizedlist>
14175 </listitem>
14176
14177 <listitem><simpara>  GdkEventDragBegin</simpara>
14178           <itemizedlist>
14179           <listitem><simpara>drag_begin_event</simpara>
14180           </listitem>
14181           </itemizedlist>
14182 </listitem>
14183
14184 <listitem><simpara>  GdkEventDragRequest</simpara>
14185           <itemizedlist>
14186           <listitem><simpara>drag_request_event</simpara>
14187           </listitem>
14188           </itemizedlist>
14189 </listitem>
14190
14191 <listitem><simpara>  GdkEventDropEnter</simpara>
14192           <itemizedlist>
14193           <listitem><simpara>drop_enter_event</simpara>
14194           </listitem>
14195           </itemizedlist>
14196 </listitem>
14197
14198 <listitem><simpara>  GdkEventDropLeave</simpara>
14199           <itemizedlist>
14200           <listitem><simpara>drop_leave_event</simpara>
14201           </listitem>
14202           </itemizedlist>
14203 </listitem>
14204
14205 <listitem><simpara>  GdkEventDropDataAvailable</simpara>
14206           <itemizedlist>
14207           <listitem><simpara>drop_data_available_event</simpara>
14208           </listitem>
14209           </itemizedlist>
14210 </listitem>
14211
14212 <listitem><simpara>  GdkEventClient</simpara>
14213           <itemizedlist>
14214           <listitem><simpara>client_event</simpara>
14215           </listitem>
14216           </itemizedlist>
14217 </listitem>
14218
14219 <listitem><simpara>  GdkEventOther</simpara>
14220           <itemizedlist>
14221           <listitem><simpara>other_event</simpara>
14222           </listitem>
14223           </itemizedlist>
14224 </listitem>
14225 </itemizedlist>
14226
14227 <para>The data type <literal>GdkEventType</literal> is a special data type that is used by
14228 all the other data types as an indicator of the data type being passed
14229 to the signal handler. As you will see below, each of the event data
14230 structures has a member of this type. It is defined as an enumeration
14231 type as follows:</para>
14232
14233 <programlisting role="C">
14234 typedef enum
14235 {
14236   GDK_NOTHING           = -1,
14237   GDK_DELETE            = 0,
14238   GDK_DESTROY           = 1,
14239   GDK_EXPOSE            = 2,
14240   GDK_MOTION_NOTIFY     = 3,
14241   GDK_BUTTON_PRESS      = 4,
14242   GDK_2BUTTON_PRESS     = 5,
14243   GDK_3BUTTON_PRESS     = 6,
14244   GDK_BUTTON_RELEASE    = 7,
14245   GDK_KEY_PRESS         = 8,
14246   GDK_KEY_RELEASE       = 9,
14247   GDK_ENTER_NOTIFY      = 10,
14248   GDK_LEAVE_NOTIFY      = 11,
14249   GDK_FOCUS_CHANGE      = 12,
14250   GDK_CONFIGURE         = 13,
14251   GDK_MAP               = 14,
14252   GDK_UNMAP             = 15,
14253   GDK_PROPERTY_NOTIFY   = 16,
14254   GDK_SELECTION_CLEAR   = 17,
14255   GDK_SELECTION_REQUEST = 18,
14256   GDK_SELECTION_NOTIFY  = 19,
14257   GDK_PROXIMITY_IN      = 20,
14258   GDK_PROXIMITY_OUT     = 21,
14259   GDK_DRAG_BEGIN        = 22,
14260   GDK_DRAG_REQUEST      = 23,
14261   GDK_DROP_ENTER        = 24,
14262   GDK_DROP_LEAVE        = 25,
14263   GDK_DROP_DATA_AVAIL   = 26,
14264   GDK_CLIENT_EVENT      = 27,
14265   GDK_VISIBILITY_NOTIFY = 28,
14266   GDK_NO_EXPOSE         = 29,
14267   GDK_OTHER_EVENT       = 9999  /* Deprecated, use filters instead */
14268 } GdkEventType;
14269 </programlisting>
14270
14271 <para>The other event type that is different from the others is
14272 <literal>GdkEvent</literal> itself. This is a union of all the other
14273 data types, which allows it to be cast to a specific
14274 event data type within a signal handler.</para>
14275
14276 <!-- Just a big list for now, needs expanding upon - TRG -->
14277 <para>So, the event data types are defined as follows:</para>
14278
14279 <programlisting role="C">
14280 struct _GdkEventAny
14281 {
14282   GdkEventType type;
14283   GdkWindow *window;
14284   gint8 send_event;
14285 };
14286
14287 struct _GdkEventExpose
14288 {
14289   GdkEventType type;
14290   GdkWindow *window;
14291   gint8 send_event;
14292   GdkRectangle area;
14293   gint count; /* If non-zero, how many more events follow. */
14294 };
14295
14296 struct _GdkEventNoExpose
14297 {
14298   GdkEventType type;
14299   GdkWindow *window;
14300   gint8 send_event;
14301   /* XXX: does anyone need the X major_code or minor_code fields? */
14302 };
14303
14304 struct _GdkEventVisibility
14305 {
14306   GdkEventType type;
14307   GdkWindow *window;
14308   gint8 send_event;
14309   GdkVisibilityState state;
14310 };
14311
14312 struct _GdkEventMotion
14313 {
14314   GdkEventType type;
14315   GdkWindow *window;
14316   gint8 send_event;
14317   guint32 time;
14318   gdouble x;
14319   gdouble y;
14320   gdouble pressure;
14321   gdouble xtilt;
14322   gdouble ytilt;
14323   guint state;
14324   gint16 is_hint;
14325   GdkInputSource source;
14326   guint32 deviceid;
14327   gdouble x_root, y_root;
14328 };
14329
14330 struct _GdkEventButton
14331 {
14332   GdkEventType type;
14333   GdkWindow *window;
14334   gint8 send_event;
14335   guint32 time;
14336   gdouble x;
14337   gdouble y;
14338   gdouble pressure;
14339   gdouble xtilt;
14340   gdouble ytilt;
14341   guint state;
14342   guint button;
14343   GdkInputSource source;
14344   guint32 deviceid;
14345   gdouble x_root, y_root;
14346 };
14347
14348 struct _GdkEventKey
14349 {
14350   GdkEventType type;
14351   GdkWindow *window;
14352   gint8 send_event;
14353   guint32 time;
14354   guint state;
14355   guint keyval;
14356   gint length;
14357   gchar *string;
14358 };
14359
14360 struct _GdkEventCrossing
14361 {
14362   GdkEventType type;
14363   GdkWindow *window;
14364   gint8 send_event;
14365   GdkWindow *subwindow;
14366   GdkNotifyType detail;
14367 };
14368
14369 struct _GdkEventFocus
14370 {
14371   GdkEventType type;
14372   GdkWindow *window;
14373   gint8 send_event;
14374   gint16 in;
14375 };
14376
14377 struct _GdkEventConfigure
14378 {
14379   GdkEventType type;
14380   GdkWindow *window;
14381   gint8 send_event;
14382   gint16 x, y;
14383   gint16 width;
14384   gint16 height;
14385 };
14386
14387 struct _GdkEventProperty
14388 {
14389   GdkEventType type;
14390   GdkWindow *window;
14391   gint8 send_event;
14392   GdkAtom atom;
14393   guint32 time;
14394   guint state;
14395 };
14396
14397 struct _GdkEventSelection
14398 {
14399   GdkEventType type;
14400   GdkWindow *window;
14401   gint8 send_event;
14402   GdkAtom selection;
14403   GdkAtom target;
14404   GdkAtom property;
14405   guint32 requestor;
14406   guint32 time;
14407 };
14408
14409 /* This event type will be used pretty rarely. It only is important
14410    for XInput aware programs that are drawing their own cursor */
14411
14412 struct _GdkEventProximity
14413 {
14414   GdkEventType type;
14415   GdkWindow *window;
14416   gint8 send_event;
14417   guint32 time;
14418   GdkInputSource source;
14419   guint32 deviceid;
14420 };
14421
14422 struct _GdkEventDragRequest
14423 {
14424   GdkEventType type;
14425   GdkWindow *window;
14426   gint8 send_event;
14427   guint32 requestor;
14428   union {
14429     struct {
14430       guint protocol_version:4;
14431       guint sendreply:1;
14432       guint willaccept:1;
14433       guint delete_data:1; /* Do *not* delete if link is sent, only
14434                               if data is sent */
14435       guint senddata:1;
14436       guint reserved:22;
14437     } flags;
14438     glong allflags;
14439   } u;
14440   guint8 isdrop; /* This gdk event can be generated by a couple of
14441                     X events - this lets the app know whether the
14442                     drop really occurred or we just set the data */
14443
14444   GdkPoint drop_coords;
14445   gchar *data_type;
14446   guint32 timestamp;
14447 };
14448
14449 struct _GdkEventDragBegin
14450 {
14451   GdkEventType type;
14452   GdkWindow *window;
14453   gint8 send_event;
14454   union {
14455     struct {
14456       guint protocol_version:4;
14457       guint reserved:28;
14458     } flags;
14459     glong allflags;
14460   } u;
14461 };
14462
14463 struct _GdkEventDropEnter
14464 {
14465   GdkEventType type;
14466   GdkWindow *window;
14467   gint8 send_event;
14468   guint32 requestor;
14469   union {
14470     struct {
14471       guint protocol_version:4;
14472       guint sendreply:1;
14473       guint extended_typelist:1;
14474       guint reserved:26;
14475     } flags;
14476     glong allflags;
14477   } u;
14478 };
14479
14480 struct _GdkEventDropLeave
14481 {
14482   GdkEventType type;
14483   GdkWindow *window;
14484   gint8 send_event;
14485   guint32 requestor;
14486   union {
14487     struct {
14488       guint protocol_version:4;
14489       guint reserved:28;
14490     } flags;
14491     glong allflags;
14492   } u;
14493 };
14494
14495 struct _GdkEventDropDataAvailable
14496 {
14497   GdkEventType type;
14498   GdkWindow *window;
14499   gint8 send_event;
14500   guint32 requestor;
14501   union {
14502     struct {
14503       guint protocol_version:4;
14504       guint isdrop:1;
14505       guint reserved:25;
14506     } flags;
14507     glong allflags;
14508   } u;
14509   gchar *data_type; /* MIME type */
14510   gulong data_numbytes;
14511   gpointer data;
14512   guint32 timestamp;
14513   GdkPoint coords;
14514 };
14515
14516 struct _GdkEventClient
14517 {
14518   GdkEventType type;
14519   GdkWindow *window;
14520   gint8 send_event;
14521   GdkAtom message_type;
14522   gushort data_format;
14523   union {
14524     char b[20];
14525     short s[10];
14526     long l[5];
14527   } data;
14528 };
14529
14530 struct _GdkEventOther
14531 {
14532   GdkEventType type;
14533   GdkWindow *window;
14534   gint8 send_event;
14535   GdkXEvent *xevent;
14536 };
14537 </programlisting>
14538
14539 </appendix>
14540
14541 <!-- ***************************************************************** -->
14542 <appendix id="app-CodeExamples">
14543 <title>Code Examples</title>
14544
14545 <para>Below are the code examples that are used in the above text
14546 which are not included in complete form elsewhere.</para>
14547
14548 <!-- ----------------------------------------------------------------- -->
14549 <sect1 id="sec-Tictactoe">
14550 <title>Tictactoe</title>
14551 <!-- ----------------------------------------------------------------- -->
14552 <sect2>
14553 <title>tictactoe.h</title>
14554
14555 <programlisting role="C">
14556 <!-- example-start tictactoe tictactoe.h -->
14557
14558 /* GTK - The GIMP Toolkit
14559  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
14560  *
14561  * This library is free software; you can redistribute it and/or
14562  * modify it under the terms of the GNU Library General Public
14563  * License as published by the Free Software Foundation; either
14564  * version 2 of the License, or (at your option) any later version.
14565  *
14566  * This library is distributed in the hope that it will be useful,
14567  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14568  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14569  * Library General Public License for more details.
14570  *
14571  * You should have received a copy of the GNU Library General Public
14572  * License along with this library; if not, write to the
14573  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
14574  * Boston, MA 02111-1307, USA.
14575  */
14576 #ifndef __TICTACTOE_H__
14577 #define __TICTACTOE_H__
14578
14579
14580 #include &lt;gdk/gdk.h&gt;
14581 #include &lt;gtk/gtkvbox.h&gt;
14582
14583
14584 #ifdef __cplusplus
14585 extern "C" {
14586 #endif /* __cplusplus */
14587
14588 #define TICTACTOE(obj)          GTK_CHECK_CAST (obj, tictactoe_get_type (), Tictactoe)
14589 #define TICTACTOE_CLASS(klass)  GTK_CHECK_CLASS_CAST (klass, tictactoe_get_type (), TictactoeClass)
14590 #define IS_TICTACTOE(obj)       GTK_CHECK_TYPE (obj, tictactoe_get_type ())
14591
14592
14593 typedef struct _Tictactoe       Tictactoe;
14594 typedef struct _TictactoeClass  TictactoeClass;
14595
14596 struct _Tictactoe
14597 {
14598   GtkVBox vbox;
14599   
14600   GtkWidget *buttons[3][3];
14601 };
14602
14603 struct _TictactoeClass
14604 {
14605   GtkVBoxClass parent_class;
14606
14607   void (* tictactoe) (Tictactoe *ttt);
14608 };
14609
14610 GtkType        tictactoe_get_type        (void);
14611 GtkWidget*     tictactoe_new             (void);
14612 void           tictactoe_clear           (Tictactoe *ttt);
14613
14614 #ifdef __cplusplus
14615 }
14616 #endif /* __cplusplus */
14617
14618 #endif /* __TICTACTOE_H__ */
14619
14620 <!-- example-end -->
14621 </programlisting>
14622
14623 </sect2>
14624
14625 <!-- ----------------------------------------------------------------- -->
14626 <sect2>
14627 <title>tictactoe.c</title>
14628
14629 <programlisting role="C">
14630 <!-- example-start tictactoe tictactoe.c -->
14631
14632 /* GTK - The GIMP Toolkit
14633  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
14634  *
14635  * This library is free software; you can redistribute it and/or
14636  * modify it under the terms of the GNU Library General Public
14637  * License as published by the Free Software Foundation; either
14638  * version 2 of the License, or (at your option) any later version.
14639  *
14640  * This library is distributed in the hope that it will be useful,
14641  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14642  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14643  * Library General Public License for more details.
14644  *
14645  * You should have received a copy of the GNU Library General Public
14646  * License along with this library; if not, write to the
14647  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
14648  * Boston, MA 02111-1307, USA.
14649  */
14650 #include "gtk/gtksignal.h"
14651 #include "gtk/gtktable.h"
14652 #include "gtk/gtktogglebutton.h"
14653 #include "tictactoe.h"
14654
14655 enum {
14656   TICTACTOE_SIGNAL,
14657   LAST_SIGNAL
14658 };
14659
14660 static void tictactoe_class_init          (TictactoeClass *klass);
14661 static void tictactoe_init                (Tictactoe      *ttt);
14662 static void tictactoe_toggle              (GtkWidget *widget, Tictactoe *ttt);
14663
14664 static gint tictactoe_signals[LAST_SIGNAL] = { 0 };
14665
14666 GType
14667 tictactoe_get_type ()
14668 {
14669   static GType ttt_type = 0;
14670
14671   if (!ttt_type)
14672     {
14673       static const GTypeInfo ttt_info =
14674       {
14675         sizeof (TictactoeClass),
14676         NULL,
14677         NULL,
14678         (GClassInitFunc) tictactoe_class_init,
14679         NULL,
14680         NULL,
14681         sizeof (Tictactoe),
14682         0,
14683         (GInstanceInitFunc) tictactoe_init,
14684       };
14685
14686       ttt_type = g_type_register_static (GTK_TYPE_VBOX, "Tictactoe", &amp;ttt_info, 0);
14687     }
14688
14689   return ttt_type;
14690 }
14691
14692 static void
14693 tictactoe_class_init (TictactoeClass *class)
14694 {
14695   GtkObjectClass *object_class;
14696
14697   object_class = (GtkObjectClass*) class;
14698   
14699   tictactoe_signals[TICTACTOE_SIGNAL] = g_signal_new ("tictactoe",
14700                                          G_TYPE_FROM_CLASS (object_class),
14701                                          G_SIGNAL_RUN_FIRST,
14702                                          0,
14703                                          NULL, 
14704                                          NULL,                
14705                                          g_cclosure_marshal_VOID__VOID,
14706                                          G_TYPE_NONE, 0, NULL);
14707
14708
14709   class-&gt;tictactoe = NULL;
14710 }
14711
14712 static void
14713 tictactoe_init (Tictactoe *ttt)
14714 {
14715   GtkWidget *table;
14716   gint i,j;
14717   
14718   table = gtk_table_new (3, 3, TRUE);
14719   gtk_container_add (GTK_CONTAINER (ttt), table);
14720   gtk_widget_show (table);
14721
14722   for (i = 0; i &lt; 3; i++)
14723     for (j = 0; j &lt; 3; j++)
14724       {
14725         ttt-&gt;buttons[i][j] = gtk_toggle_button_new ();
14726         gtk_table_attach_defaults (GTK_TABLE (table), ttt-&gt;buttons[i][j], 
14727                                    i, i+1, j, j+1);
14728         g_signal_connect (G_OBJECT (ttt-&gt;buttons[i][j]), "toggled",
14729                           G_CALLBACK (tictactoe_toggle), (gpointer) ttt);
14730         gtk_widget_set_size_request (ttt-&gt;buttons[i][j], 20, 20);
14731         gtk_widget_show (ttt-&gt;buttons[i][j]);
14732       }
14733 }
14734
14735 GtkWidget*
14736 tictactoe_new ()
14737 {
14738   return GTK_WIDGET (g_object_new (tictactoe_get_type (), NULL));
14739 }
14740
14741 void           
14742 tictactoe_clear (Tictactoe *ttt)
14743 {
14744   int i,j;
14745
14746   for (i = 0; i &lt; 3; i++)
14747     for (j = 0; j &lt; 3; j++)
14748       {
14749         g_signal_handlers_block_by_func (G_OBJECT (ttt-&gt;buttons[i][j]), 
14750                                          NULL, ttt);
14751         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ttt-&gt;buttons[i][j]),
14752                                       FALSE);
14753         g_signal_handlers_unblock_by_func (G_OBJECT (ttt-&gt;buttons[i][j]), 
14754                                            NULL, ttt);
14755       }
14756 }
14757
14758 static void
14759 tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt)
14760 {
14761   int i,k;
14762
14763   static int rwins[8][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
14764                              { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
14765                              { 0, 1, 2 }, { 0, 1, 2 } };
14766   static int cwins[8][3] = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
14767                              { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
14768                              { 0, 1, 2 }, { 2, 1, 0 } };
14769
14770   int success, found;
14771
14772   for (k = 0; k &lt; 8; k++)
14773     {
14774       success = TRUE;
14775       found = FALSE;
14776
14777       for (i = 0; i &lt; 3; i++)
14778         {
14779           success = success &amp;&amp; 
14780             GTK_TOGGLE_BUTTON (ttt-&gt;buttons[rwins[k][i]][cwins[k][i]])-&gt;active;
14781           found = found ||
14782             ttt-&gt;buttons[rwins[k][i]][cwins[k][i]] == widget;
14783         }
14784       
14785       if (success &amp;&amp; found)
14786         {
14787           g_signal_emit (G_OBJECT (ttt), 
14788                          tictactoe_signals[TICTACTOE_SIGNAL], 0);
14789           break;
14790         }
14791     }
14792 }
14793
14794 <!-- example-end -->
14795 </programlisting>
14796
14797 </sect2>
14798
14799 <!-- ----------------------------------------------------------------- -->
14800 <sect2>
14801 <title>ttt_test.c</title>
14802
14803 <programlisting role="C">
14804 <!-- example-start tictactoe ttt_test.c -->
14805
14806 #include &lt;stdlib.h&gt;
14807 #include &lt;gtk/gtk.h&gt;
14808 #include "tictactoe.h"
14809
14810 void win( GtkWidget *widget,
14811           gpointer   data )
14812 {
14813   g_print ("Yay!\n");
14814   tictactoe_clear (TICTACTOE (widget));
14815 }
14816
14817 int main( int   argc,
14818           char *argv[] )
14819 {
14820   GtkWidget *window;
14821   GtkWidget *ttt;
14822   
14823   gtk_init (&amp;argc, &amp;argv);
14824
14825   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
14826   
14827   gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
14828   
14829   g_signal_connect (G_OBJECT (window), "destroy",
14830                     G_CALLBACK (exit), NULL);
14831   
14832   gtk_container_set_border_width (GTK_CONTAINER (window), 10);
14833
14834   ttt = tictactoe_new ();
14835   
14836   gtk_container_add (GTK_CONTAINER (window), ttt);
14837   gtk_widget_show (ttt);
14838
14839   g_signal_connect (G_OBJECT (ttt), "tictactoe",
14840                     G_CALLBACK (win), NULL);
14841
14842   gtk_widget_show (window);
14843   
14844   gtk_main ();
14845   
14846   return 0;
14847 }
14848
14849 <!-- example-end -->
14850 </programlisting>
14851
14852 </sect2>
14853 </sect1>
14854
14855 <!-- ----------------------------------------------------------------- -->
14856 <sect1 id="sec-GtkDial">
14857 <title>GtkDial</title>
14858
14859 <!-- ----------------------------------------------------------------- -->
14860 <sect2>
14861 <title>gtkdial.h</title>
14862
14863 <programlisting role="C">
14864 <!-- example-start gtkdial gtkdial.h -->
14865
14866 /* GTK - The GIMP Toolkit
14867  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
14868  *
14869  * This library is free software; you can redistribute it and/or
14870  * modify it under the terms of the GNU Library General Public
14871  * License as published by the Free Software Foundation; either
14872  * version 2 of the License, or (at your option) any later version.
14873  *
14874  * This library is distributed in the hope that it will be useful,
14875  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14876  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14877  * Library General Public License for more details.
14878  *
14879  * You should have received a copy of the GNU Library General Public
14880  * License along with this library; if not, write to the
14881  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
14882  * Boston, MA 02111-1307, USA.
14883  */
14884 #ifndef __GTK_DIAL_H__
14885 #define __GTK_DIAL_H__
14886
14887
14888 #include &lt;gdk/gdk.h&gt;
14889 #include &lt;gtk/gtkadjustment.h&gt;
14890 #include &lt;gtk/gtkwidget.h&gt;
14891
14892
14893 #ifdef __cplusplus
14894 extern "C" {
14895 #endif /* __cplusplus */
14896
14897
14898 #define GTK_DIAL(obj)          GTK_CHECK_CAST (obj, gtk_dial_get_type (), GtkDial)
14899 #define GTK_DIAL_CLASS(klass)  GTK_CHECK_CLASS_CAST (klass, gtk_dial_get_type (), GtkDialClass)
14900 #define GTK_IS_DIAL(obj)       GTK_CHECK_TYPE (obj, gtk_dial_get_type ())
14901
14902
14903 typedef struct _GtkDial        GtkDial;
14904 typedef struct _GtkDialClass   GtkDialClass;
14905
14906 struct _GtkDial
14907 {
14908   GtkWidget widget;
14909
14910   /* update policy (GTK_UPDATE_[CONTINUOUS/DELAYED/DISCONTINUOUS]) */
14911   guint policy : 2;
14912
14913   /* Button currently pressed or 0 if none */
14914   guint8 button;
14915
14916   /* Dimensions of dial components */
14917   gint radius;
14918   gint pointer_width;
14919
14920   /* ID of update timer, or 0 if none */
14921   guint32 timer;
14922
14923   /* Current angle */
14924   gfloat angle;
14925   gfloat last_angle;
14926
14927   /* Old values from adjustment stored so we know when something changes */
14928   gfloat old_value;
14929   gfloat old_lower;
14930   gfloat old_upper;
14931
14932   /* The adjustment object that stores the data for this dial */
14933   GtkAdjustment *adjustment;
14934 };
14935
14936 struct _GtkDialClass
14937 {
14938   GtkWidgetClass parent_class;
14939 };
14940
14941
14942 GtkWidget*     gtk_dial_new                    (GtkAdjustment *adjustment);
14943 GtkType        gtk_dial_get_type               (void);
14944 GtkAdjustment* gtk_dial_get_adjustment         (GtkDial      *dial);
14945 void           gtk_dial_set_update_policy      (GtkDial      *dial,
14946                                                 GtkUpdateType  policy);
14947
14948 void           gtk_dial_set_adjustment         (GtkDial      *dial,
14949                                                 GtkAdjustment *adjustment);
14950 #ifdef __cplusplus
14951 }
14952 #endif /* __cplusplus */
14953
14954
14955 #endif /* __GTK_DIAL_H__ */
14956 <!-- example-end -->
14957 </programlisting>
14958
14959 </sect2>
14960
14961 <!-- ----------------------------------------------------------------- -->
14962 <sect2>
14963 <title>gtkdial.c</title>
14964
14965 <programlisting role="C">
14966 <!-- example-start gtkdial gtkdial.c -->
14967
14968 /* GTK - The GIMP Toolkit
14969  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
14970  *
14971  * This library is free software; you can redistribute it and/or
14972  * modify it under the terms of the GNU Library General Public
14973  * License as published by the Free Software Foundation; either
14974  * version 2 of the License, or (at your option) any later version.
14975  *
14976  * This library is distributed in the hope that it will be useful,
14977  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14978  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14979  * Library General Public License for more details.
14980  *
14981  * You should have received a copy of the GNU Library General Public
14982  * License along with this library; if not, write to the
14983  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
14984  * Boston, MA 02111-1307, USA.
14985  */
14986 #include &lt;math.h&gt;
14987 #include &lt;stdio.h&gt;
14988 #include &lt;gtk/gtkmain.h&gt;
14989 #include &lt;gtk/gtksignal.h&gt;
14990
14991 #include "gtkdial.h"
14992
14993 #define SCROLL_DELAY_LENGTH  300
14994 #define DIAL_DEFAULT_SIZE 100
14995
14996 /* Forward declarations */
14997
14998 static void gtk_dial_class_init               (GtkDialClass    *klass);
14999 static void gtk_dial_init                     (GtkDial         *dial);
15000 static void gtk_dial_destroy                  (GtkObject        *object);
15001 static void gtk_dial_realize                  (GtkWidget        *widget);
15002 static void gtk_dial_size_request             (GtkWidget      *widget,
15003                                                GtkRequisition *requisition);
15004 static void gtk_dial_size_allocate            (GtkWidget     *widget,
15005                                                GtkAllocation *allocation);
15006 static gint gtk_dial_expose                   (GtkWidget        *widget,
15007                                                 GdkEventExpose   *event);
15008 static gint gtk_dial_button_press             (GtkWidget        *widget,
15009                                                 GdkEventButton   *event);
15010 static gint gtk_dial_button_release           (GtkWidget        *widget,
15011                                                 GdkEventButton   *event);
15012 static gint gtk_dial_motion_notify            (GtkWidget        *widget,
15013                                                 GdkEventMotion   *event);
15014 static gint gtk_dial_timer                    (GtkDial         *dial);
15015
15016 static void gtk_dial_update_mouse             (GtkDial *dial, gint x, gint y);
15017 static void gtk_dial_update                   (GtkDial *dial);
15018 static void gtk_dial_adjustment_changed       (GtkAdjustment    *adjustment,
15019                                                 gpointer          data);
15020 static void gtk_dial_adjustment_value_changed (GtkAdjustment    *adjustment,
15021                                                 gpointer          data);
15022
15023 /* Local data */
15024
15025 static GtkWidgetClass *parent_class = NULL;
15026
15027 GType
15028 gtk_dial_get_type ()
15029 {
15030   static GType dial_type = 0;
15031
15032   if (!dial_type)
15033     {
15034       static const GTypeInfo dial_info =
15035       {
15036         sizeof (GtkDialClass),
15037         NULL,
15038         NULL,
15039         (GClassInitFunc) gtk_dial_class_init,
15040         NULL,
15041         NULL,
15042         sizeof (GtkDial),
15043         0,
15044         (GInstanceInitFunc) gtk_dial_init,
15045       };
15046
15047       dial_type = g_type_register_static (GTK_TYPE_WIDGET, "GtkDial", &amp;dial_info, 0);
15048     }
15049
15050   return dial_type;
15051 }
15052
15053 static void
15054 gtk_dial_class_init (GtkDialClass *class)
15055 {
15056   GtkObjectClass *object_class;
15057   GtkWidgetClass *widget_class;
15058
15059   object_class = (GtkObjectClass*) class;
15060   widget_class = (GtkWidgetClass*) class;
15061
15062   parent_class = gtk_type_class (gtk_widget_get_type ());
15063
15064   object_class-&gt;destroy = gtk_dial_destroy;
15065
15066   widget_class-&gt;realize = gtk_dial_realize;
15067   widget_class-&gt;expose_event = gtk_dial_expose;
15068   widget_class-&gt;size_request = gtk_dial_size_request;
15069   widget_class-&gt;size_allocate = gtk_dial_size_allocate;
15070   widget_class-&gt;button_press_event = gtk_dial_button_press;
15071   widget_class-&gt;button_release_event = gtk_dial_button_release;
15072   widget_class-&gt;motion_notify_event = gtk_dial_motion_notify;
15073 }
15074
15075 static void
15076 gtk_dial_init (GtkDial *dial)
15077 {
15078   dial-&gt;button = 0;
15079   dial-&gt;policy = GTK_UPDATE_CONTINUOUS;
15080   dial-&gt;timer = 0;
15081   dial-&gt;radius = 0;
15082   dial-&gt;pointer_width = 0;
15083   dial-&gt;angle = 0.0;
15084   dial-&gt;old_value = 0.0;
15085   dial-&gt;old_lower = 0.0;
15086   dial-&gt;old_upper = 0.0;
15087   dial-&gt;adjustment = NULL;
15088 }
15089
15090 GtkWidget*
15091 gtk_dial_new (GtkAdjustment *adjustment)
15092 {
15093   GtkDial *dial;
15094
15095   dial = g_object_new (gtk_dial_get_type (), NULL);
15096
15097   if (!adjustment)
15098     adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
15099
15100   gtk_dial_set_adjustment (dial, adjustment);
15101
15102   return GTK_WIDGET (dial);
15103 }
15104
15105 static void
15106 gtk_dial_destroy (GtkObject *object)
15107 {
15108   GtkDial *dial;
15109
15110   g_return_if_fail (object != NULL);
15111   g_return_if_fail (GTK_IS_DIAL (object));
15112
15113   dial = GTK_DIAL (object);
15114
15115   if (dial-&gt;adjustment)
15116     {
15117       g_object_unref (GTK_OBJECT (dial-&gt;adjustment));
15118       dial-&gt;adjustment = NULL;
15119     }
15120
15121   if (GTK_OBJECT_CLASS (parent_class)-&gt;destroy)
15122     (* GTK_OBJECT_CLASS (parent_class)-&gt;destroy) (object);
15123 }
15124
15125 GtkAdjustment*
15126 gtk_dial_get_adjustment (GtkDial *dial)
15127 {
15128   g_return_val_if_fail (dial != NULL, NULL);
15129   g_return_val_if_fail (GTK_IS_DIAL (dial), NULL);
15130
15131   return dial-&gt;adjustment;
15132 }
15133
15134 void
15135 gtk_dial_set_update_policy (GtkDial      *dial,
15136                              GtkUpdateType  policy)
15137 {
15138   g_return_if_fail (dial != NULL);
15139   g_return_if_fail (GTK_IS_DIAL (dial));
15140
15141   dial-&gt;policy = policy;
15142 }
15143
15144 void
15145 gtk_dial_set_adjustment (GtkDial      *dial,
15146                           GtkAdjustment *adjustment)
15147 {
15148   g_return_if_fail (dial != NULL);
15149   g_return_if_fail (GTK_IS_DIAL (dial));
15150
15151   if (dial-&gt;adjustment)
15152     {
15153       g_signal_handlers_disconnect_by_func (GTK_OBJECT (dial-&gt;adjustment), NULL, (gpointer) dial);
15154       g_object_unref (GTK_OBJECT (dial-&gt;adjustment));
15155     }
15156
15157   dial-&gt;adjustment = adjustment;
15158   g_object_ref (GTK_OBJECT (dial-&gt;adjustment));
15159
15160   g_signal_connect (GTK_OBJECT (adjustment), "changed",
15161                     GTK_SIGNAL_FUNC (gtk_dial_adjustment_changed),
15162                     (gpointer) dial);
15163   g_signal_connect (GTK_OBJECT (adjustment), "value_changed",
15164                     GTK_SIGNAL_FUNC (gtk_dial_adjustment_value_changed),
15165                     (gpointer) dial);
15166
15167   dial-&gt;old_value = adjustment-&gt;value;
15168   dial-&gt;old_lower = adjustment-&gt;lower;
15169   dial-&gt;old_upper = adjustment-&gt;upper;
15170
15171   gtk_dial_update (dial);
15172 }
15173
15174 static void
15175 gtk_dial_realize (GtkWidget *widget)
15176 {
15177   GtkDial *dial;
15178   GdkWindowAttr attributes;
15179   gint attributes_mask;
15180
15181   g_return_if_fail (widget != NULL);
15182   g_return_if_fail (GTK_IS_DIAL (widget));
15183
15184   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
15185   dial = GTK_DIAL (widget);
15186
15187   attributes.x = widget-&gt;allocation.x;
15188   attributes.y = widget-&gt;allocation.y;
15189   attributes.width = widget-&gt;allocation.width;
15190   attributes.height = widget-&gt;allocation.height;
15191   attributes.wclass = GDK_INPUT_OUTPUT;
15192   attributes.window_type = GDK_WINDOW_CHILD;
15193   attributes.event_mask = gtk_widget_get_events (widget) | 
15194     GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | 
15195     GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
15196     GDK_POINTER_MOTION_HINT_MASK;
15197   attributes.visual = gtk_widget_get_visual (widget);
15198   attributes.colormap = gtk_widget_get_colormap (widget);
15199
15200   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
15201   widget-&gt;window = gdk_window_new (widget-&gt;parent-&gt;window, &amp;attributes, attributes_mask);
15202
15203   widget-&gt;style = gtk_style_attach (widget-&gt;style, widget-&gt;window);
15204
15205   gdk_window_set_user_data (widget-&gt;window, widget);
15206
15207   gtk_style_set_background (widget-&gt;style, widget-&gt;window, GTK_STATE_ACTIVE);
15208 }
15209
15210 static void 
15211 gtk_dial_size_request (GtkWidget      *widget,
15212                        GtkRequisition *requisition)
15213 {
15214   requisition-&gt;width = DIAL_DEFAULT_SIZE;
15215   requisition-&gt;height = DIAL_DEFAULT_SIZE;
15216 }
15217
15218 static void
15219 gtk_dial_size_allocate (GtkWidget     *widget,
15220                         GtkAllocation *allocation)
15221 {
15222   GtkDial *dial;
15223
15224   g_return_if_fail (widget != NULL);
15225   g_return_if_fail (GTK_IS_DIAL (widget));
15226   g_return_if_fail (allocation != NULL);
15227
15228   widget-&gt;allocation = *allocation;
15229   dial = GTK_DIAL (widget);
15230
15231   if (GTK_WIDGET_REALIZED (widget))
15232     {
15233
15234       gdk_window_move_resize (widget-&gt;window,
15235                               allocation-&gt;x, allocation-&gt;y,
15236                               allocation-&gt;width, allocation-&gt;height);
15237
15238     }
15239   dial-&gt;radius = MIN (allocation-&gt;width, allocation-&gt;height) * 0.45;
15240   dial-&gt;pointer_width = dial-&gt;radius / 5;
15241 }
15242
15243 static gint
15244 gtk_dial_expose (GtkWidget      *widget,
15245                  GdkEventExpose *event)
15246 {
15247   GtkDial *dial;
15248   GdkPoint points[6];
15249   gdouble s,c;
15250   gdouble theta, last, increment;
15251   GtkStyle      *blankstyle;
15252   gint xc, yc;
15253   gint upper, lower;
15254   gint tick_length;
15255   gint i, inc;
15256
15257   g_return_val_if_fail (widget != NULL, FALSE);
15258   g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
15259   g_return_val_if_fail (event != NULL, FALSE);
15260
15261   if (event-&gt;count &gt; 0)
15262     return FALSE;
15263   
15264   dial = GTK_DIAL (widget);
15265
15266 /*  gdk_window_clear_area (widget-&gt;window,
15267                          0, 0,
15268                          widget-&gt;allocation.width,
15269                          widget-&gt;allocation.height);
15270 */
15271   xc = widget-&gt;allocation.width / 2;
15272   yc = widget-&gt;allocation.height / 2;
15273
15274   upper = dial-&gt;adjustment-&gt;upper;
15275   lower = dial-&gt;adjustment-&gt;lower;
15276
15277   /* Erase old pointer */
15278
15279   s = sin (dial-&gt;last_angle);
15280   c = cos (dial-&gt;last_angle);
15281   dial-&gt;last_angle = dial-&gt;angle;
15282
15283   points[0].x = xc + s*dial-&gt;pointer_width/2;
15284   points[0].y = yc + c*dial-&gt;pointer_width/2;
15285   points[1].x = xc + c*dial-&gt;radius;
15286   points[1].y = yc - s*dial-&gt;radius;
15287   points[2].x = xc - s*dial-&gt;pointer_width/2;
15288   points[2].y = yc - c*dial-&gt;pointer_width/2;
15289   points[3].x = xc - c*dial-&gt;radius/10;
15290   points[3].y = yc + s*dial-&gt;radius/10;
15291   points[4].x = points[0].x;
15292   points[4].y = points[0].y;
15293
15294   blankstyle = gtk_style_new ();
15295   blankstyle-&gt;bg_gc[GTK_STATE_NORMAL] =
15296                 widget-&gt;style-&gt;bg_gc[GTK_STATE_NORMAL];
15297   blankstyle-&gt;dark_gc[GTK_STATE_NORMAL] =
15298                 widget-&gt;style-&gt;bg_gc[GTK_STATE_NORMAL];
15299   blankstyle-&gt;light_gc[GTK_STATE_NORMAL] =
15300                 widget-&gt;style-&gt;bg_gc[GTK_STATE_NORMAL];
15301   blankstyle-&gt;black_gc =
15302                 widget-&gt;style-&gt;bg_gc[GTK_STATE_NORMAL];
15303
15304   gtk_paint_polygon (blankstyle,
15305                     widget-&gt;window,
15306                     GTK_STATE_NORMAL,
15307                     GTK_SHADOW_OUT,
15308                     NULL,
15309                     widget,
15310                     NULL,
15311                     points, 5,
15312                     FALSE);
15313
15314   g_object_unref (blankstyle);
15315
15316
15317   /* Draw ticks */
15318
15319   if ((upper - lower) == 0)
15320     return FALSE;
15321
15322   increment = (100*M_PI) / (dial-&gt;radius*dial-&gt;radius);
15323
15324   inc = (upper - lower);
15325
15326   while (inc &lt; 100) inc *= 10;
15327   while (inc &gt;= 1000) inc /= 10;
15328   last = -1;
15329
15330   for (i = 0; i &lt;= inc; i++)
15331     {
15332       theta = ((gfloat)i*M_PI / (18*inc/24.) - M_PI/6.);
15333
15334       if ((theta - last) &lt; (increment))
15335         continue;     
15336       last = theta;
15337
15338       s = sin (theta);
15339       c = cos (theta);
15340
15341       tick_length = (i%(inc/10) == 0) ? dial-&gt;pointer_width : dial-&gt;pointer_width / 2;
15342
15343       gdk_draw_line (widget-&gt;window,
15344                      widget-&gt;style-&gt;fg_gc[widget-&gt;state],
15345                      xc + c*(dial-&gt;radius - tick_length),
15346                      yc - s*(dial-&gt;radius - tick_length),
15347                      xc + c*dial-&gt;radius,
15348                      yc - s*dial-&gt;radius);
15349     }
15350
15351   /* Draw pointer */
15352
15353   s = sin (dial-&gt;angle);
15354   c = cos (dial-&gt;angle);
15355   dial-&gt;last_angle = dial-&gt;angle;
15356
15357   points[0].x = xc + s*dial-&gt;pointer_width/2;
15358   points[0].y = yc + c*dial-&gt;pointer_width/2;
15359   points[1].x = xc + c*dial-&gt;radius;
15360   points[1].y = yc - s*dial-&gt;radius;
15361   points[2].x = xc - s*dial-&gt;pointer_width/2;
15362   points[2].y = yc - c*dial-&gt;pointer_width/2;
15363   points[3].x = xc - c*dial-&gt;radius/10;
15364   points[3].y = yc + s*dial-&gt;radius/10;
15365   points[4].x = points[0].x;
15366   points[4].y = points[0].y;
15367
15368
15369   gtk_paint_polygon (widget-&gt;style,
15370                     widget-&gt;window,
15371                     GTK_STATE_NORMAL,
15372                     GTK_SHADOW_OUT,
15373                     NULL,
15374                     widget,
15375                     NULL,
15376                     points, 5,
15377                     TRUE);
15378
15379   return FALSE;
15380 }
15381
15382 static gint
15383 gtk_dial_button_press (GtkWidget      *widget,
15384                        GdkEventButton *event)
15385 {
15386   GtkDial *dial;
15387   gint dx, dy;
15388   double s, c;
15389   double d_parallel;
15390   double d_perpendicular;
15391
15392   g_return_val_if_fail (widget != NULL, FALSE);
15393   g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
15394   g_return_val_if_fail (event != NULL, FALSE);
15395
15396   dial = GTK_DIAL (widget);
15397
15398   /* Determine if button press was within pointer region - we 
15399      do this by computing the parallel and perpendicular distance of
15400      the point where the mouse was pressed from the line passing through
15401      the pointer */
15402   
15403   dx = event-&gt;x - widget-&gt;allocation.width / 2;
15404   dy = widget-&gt;allocation.height / 2 - event-&gt;y;
15405   
15406   s = sin (dial-&gt;angle);
15407   c = cos (dial-&gt;angle);
15408   
15409   d_parallel = s*dy + c*dx;
15410   d_perpendicular = fabs (s*dx - c*dy);
15411   
15412   if (!dial-&gt;button &amp;&amp;
15413       (d_perpendicular &lt; dial-&gt;pointer_width/2) &amp;&amp;
15414       (d_parallel &gt; - dial-&gt;pointer_width))
15415     {
15416       gtk_grab_add (widget);
15417
15418       dial-&gt;button = event-&gt;button;
15419
15420       gtk_dial_update_mouse (dial, event-&gt;x, event-&gt;y);
15421     }
15422
15423   return FALSE;
15424 }
15425
15426 static gint
15427 gtk_dial_button_release (GtkWidget      *widget,
15428                           GdkEventButton *event)
15429 {
15430   GtkDial *dial;
15431
15432   g_return_val_if_fail (widget != NULL, FALSE);
15433   g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
15434   g_return_val_if_fail (event != NULL, FALSE);
15435
15436   dial = GTK_DIAL (widget);
15437
15438   if (dial-&gt;button == event-&gt;button)
15439     {
15440       gtk_grab_remove (widget);
15441
15442       dial-&gt;button = 0;
15443
15444       if (dial-&gt;policy == GTK_UPDATE_DELAYED)
15445         gtk_timeout_remove (dial-&gt;timer);
15446       
15447       if ((dial-&gt;policy != GTK_UPDATE_CONTINUOUS) &amp;&amp;
15448           (dial-&gt;old_value != dial-&gt;adjustment-&gt;value))
15449         g_signal_emit_by_name (GTK_OBJECT (dial-&gt;adjustment), "value_changed");
15450     }
15451
15452   return FALSE;
15453 }
15454
15455 static gint
15456 gtk_dial_motion_notify (GtkWidget      *widget,
15457                          GdkEventMotion *event)
15458 {
15459   GtkDial *dial;
15460   GdkModifierType mods;
15461   gint x, y, mask;
15462
15463   g_return_val_if_fail (widget != NULL, FALSE);
15464   g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
15465   g_return_val_if_fail (event != NULL, FALSE);
15466
15467   dial = GTK_DIAL (widget);
15468
15469   if (dial-&gt;button != 0)
15470     {
15471       x = event-&gt;x;
15472       y = event-&gt;y;
15473
15474       if (event-&gt;is_hint || (event-&gt;window != widget-&gt;window))
15475         gdk_window_get_pointer (widget-&gt;window, &amp;x, &amp;y, &amp;mods);
15476
15477       switch (dial-&gt;button)
15478         {
15479         case 1:
15480           mask = GDK_BUTTON1_MASK;
15481           break;
15482         case 2:
15483           mask = GDK_BUTTON2_MASK;
15484           break;
15485         case 3:
15486           mask = GDK_BUTTON3_MASK;
15487           break;
15488         default:
15489           mask = 0;
15490           break;
15491         }
15492
15493       if (mods &amp; mask)
15494         gtk_dial_update_mouse (dial, x,y);
15495     }
15496
15497   return FALSE;
15498 }
15499
15500 static gint
15501 gtk_dial_timer (GtkDial *dial)
15502 {
15503   g_return_val_if_fail (dial != NULL, FALSE);
15504   g_return_val_if_fail (GTK_IS_DIAL (dial), FALSE);
15505
15506   if (dial-&gt;policy == GTK_UPDATE_DELAYED)
15507     g_signal_emit_by_name (GTK_OBJECT (dial-&gt;adjustment), "value_changed");
15508
15509   return FALSE;
15510 }
15511
15512 static void
15513 gtk_dial_update_mouse (GtkDial *dial, gint x, gint y)
15514 {
15515   gint xc, yc;
15516   gfloat old_value;
15517
15518   g_return_if_fail (dial != NULL);
15519   g_return_if_fail (GTK_IS_DIAL (dial));
15520
15521   xc = GTK_WIDGET(dial)-&gt;allocation.width / 2;
15522   yc = GTK_WIDGET(dial)-&gt;allocation.height / 2;
15523
15524   old_value = dial-&gt;adjustment-&gt;value;
15525   dial-&gt;angle = atan2(yc-y, x-xc);
15526
15527   if (dial-&gt;angle &lt; -M_PI/2.)
15528     dial-&gt;angle += 2*M_PI;
15529
15530   if (dial-&gt;angle &lt; -M_PI/6)
15531     dial-&gt;angle = -M_PI/6;
15532
15533   if (dial-&gt;angle &gt; 7.*M_PI/6.)
15534     dial-&gt;angle = 7.*M_PI/6.;
15535
15536   dial-&gt;adjustment-&gt;value = dial-&gt;adjustment-&gt;lower + (7.*M_PI/6 - dial-&gt;angle) *
15537     (dial-&gt;adjustment-&gt;upper - dial-&gt;adjustment-&gt;lower) / (4.*M_PI/3.);
15538
15539   if (dial-&gt;adjustment-&gt;value != old_value)
15540     {
15541       if (dial-&gt;policy == GTK_UPDATE_CONTINUOUS)
15542         {
15543           g_signal_emit_by_name (GTK_OBJECT (dial-&gt;adjustment), "value_changed");
15544         }
15545       else
15546         {
15547           gtk_widget_queue_draw (GTK_WIDGET (dial));
15548
15549           if (dial-&gt;policy == GTK_UPDATE_DELAYED)
15550             {
15551               if (dial-&gt;timer)
15552                 gtk_timeout_remove (dial-&gt;timer);
15553
15554               dial-&gt;timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
15555                                              (GtkFunction) gtk_dial_timer,
15556                                              (gpointer) dial);
15557             }
15558         }
15559     }
15560 }
15561
15562 static void
15563 gtk_dial_update (GtkDial *dial)
15564 {
15565   gfloat new_value;
15566   
15567   g_return_if_fail (dial != NULL);
15568   g_return_if_fail (GTK_IS_DIAL (dial));
15569
15570   new_value = dial-&gt;adjustment-&gt;value;
15571   
15572   if (new_value &lt; dial-&gt;adjustment-&gt;lower)
15573     new_value = dial-&gt;adjustment-&gt;lower;
15574
15575   if (new_value &gt; dial-&gt;adjustment-&gt;upper)
15576     new_value = dial-&gt;adjustment-&gt;upper;
15577
15578   if (new_value != dial-&gt;adjustment-&gt;value)
15579     {
15580       dial-&gt;adjustment-&gt;value = new_value;
15581       g_signal_emit_by_name (GTK_OBJECT (dial-&gt;adjustment), "value_changed");
15582     }
15583
15584   dial-&gt;angle = 7.*M_PI/6. - (new_value - dial-&gt;adjustment-&gt;lower) * 4.*M_PI/3. /
15585     (dial-&gt;adjustment-&gt;upper - dial-&gt;adjustment-&gt;lower);
15586
15587   gtk_widget_queue_draw (GTK_WIDGET (dial));
15588 }
15589
15590 static void
15591 gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
15592                               gpointer       data)
15593 {
15594   GtkDial *dial;
15595
15596   g_return_if_fail (adjustment != NULL);
15597   g_return_if_fail (data != NULL);
15598
15599   dial = GTK_DIAL (data);
15600
15601   if ((dial-&gt;old_value != adjustment-&gt;value) ||
15602       (dial-&gt;old_lower != adjustment-&gt;lower) ||
15603       (dial-&gt;old_upper != adjustment-&gt;upper))
15604     {
15605       gtk_dial_update (dial);
15606
15607       dial-&gt;old_value = adjustment-&gt;value;
15608       dial-&gt;old_lower = adjustment-&gt;lower;
15609       dial-&gt;old_upper = adjustment-&gt;upper;
15610     }
15611 }
15612
15613 static void
15614 gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
15615                                     gpointer       data)
15616 {
15617   GtkDial *dial;
15618
15619   g_return_if_fail (adjustment != NULL);
15620   g_return_if_fail (data != NULL);
15621
15622   dial = GTK_DIAL (data);
15623
15624   if (dial-&gt;old_value != adjustment-&gt;value)
15625     {
15626       gtk_dial_update (dial);
15627
15628       dial-&gt;old_value = adjustment-&gt;value;
15629     }
15630 }
15631 <!-- example-end -->
15632 </programlisting>
15633
15634 </sect2>
15635
15636 <!-- ----------------------------------------------------------------- -->
15637 <sect2>
15638 <title>dial_test.c</title>
15639
15640 <programlisting role="C">
15641 <!-- example-start gtkdial dial_test.c -->
15642
15643 #include &lt;stdio.h&gt;
15644 #include &lt;stdlib.h&gt;
15645 #include &lt;gtk/gtk.h&gt;
15646 #include "gtkdial.h"
15647
15648 void value_changed( GtkAdjustment *adjustment,
15649                     GtkWidget     *label )
15650 {
15651   char buffer[16];
15652
15653   sprintf(buffer,"%4.2f",adjustment-&gt;value);
15654   gtk_label_set_text (GTK_LABEL (label), buffer);
15655 }
15656
15657 int main( int   argc,
15658           char *argv[])
15659 {
15660   GtkWidget *window;
15661   GtkAdjustment *adjustment;
15662   GtkWidget *dial;
15663   GtkWidget *frame;
15664   GtkWidget *vbox;
15665   GtkWidget *label;
15666   
15667   gtk_init (&amp;argc, &amp;argv);
15668
15669   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
15670   
15671   gtk_window_set_title (GTK_WINDOW (window), "Dial");
15672   
15673   g_signal_connect (G_OBJECT (window), "destroy",
15674                     G_CALLBACK (exit), NULL);
15675   
15676   gtk_container_set_border_width (GTK_CONTAINER (window), 10);
15677
15678   vbox = gtk_vbox_new (FALSE, 5);
15679   gtk_container_add (GTK_CONTAINER (window), vbox);
15680   gtk_widget_show (vbox);
15681
15682   frame = gtk_frame_new (NULL);
15683   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
15684   gtk_container_add (GTK_CONTAINER (vbox), frame);
15685   gtk_widget_show (frame); 
15686  
15687   adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0, 0, 100, 0.01, 0.1, 0));
15688   
15689   dial = gtk_dial_new (adjustment);
15690   gtk_dial_set_update_policy (GTK_DIAL (dial), GTK_UPDATE_DELAYED);
15691   /*  gtk_widget_set_size_request (dial, 100, 100); */
15692   
15693   gtk_container_add (GTK_CONTAINER (frame), dial);
15694   gtk_widget_show (dial);
15695
15696   label = gtk_label_new ("0.00");
15697   gtk_box_pack_end (GTK_BOX (vbox), label, 0, 0, 0);
15698   gtk_widget_show (label);
15699
15700   g_signal_connect (G_OBJECT (adjustment), "value_changed",
15701                     G_CALLBACK (value_changed), (gpointer) label);
15702   
15703   gtk_widget_show (window);
15704   
15705   gtk_main ();
15706   
15707   return 0;
15708 }
15709 <!-- example-end -->
15710 </programlisting>
15711
15712 </sect2>
15713 </sect1>
15714
15715 <!-- ----------------------------------------------------------------- -->
15716 <sect1 id="sec-Scribble">
15717 <title>Scribble</title>
15718
15719 <!-- ----------------------------------------------------------------- -->
15720 <sect2>
15721 <title>scribble-simple.c</title>
15722
15723 <programlisting role="C">
15724 <!-- example-start scribble-simple scribble-simple.c -->
15725
15726 /* GTK - The GIMP Toolkit
15727  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
15728  *
15729  * This library is free software; you can redistribute it and/or
15730  * modify it under the terms of the GNU Library General Public
15731  * License as published by the Free Software Foundation; either
15732  * version 2 of the License, or (at your option) any later version.
15733  *
15734  * This library is distributed in the hope that it will be useful,
15735  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15736  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15737  * Library General Public License for more details.
15738  *
15739  * You should have received a copy of the GNU Library General Public
15740  * License along with this library; if not, write to the
15741  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
15742  * Boston, MA 02111-1307, USA.
15743  */
15744
15745 #include &lt;stdlib.h&gt;
15746 #include &lt;gtk/gtk.h&gt;
15747
15748 /* Backing pixmap for drawing area */
15749 static GdkPixmap *pixmap = NULL;
15750
15751 /* Create a new backing pixmap of the appropriate size */
15752 static gint configure_event( GtkWidget         *widget,
15753                              GdkEventConfigure *event )
15754 {
15755   if (pixmap)
15756     g_object_unref (pixmap);
15757
15758   pixmap = gdk_pixmap_new (widget-&gt;window,
15759                            widget-&gt;allocation.width,
15760                            widget-&gt;allocation.height,
15761                            -1);
15762   gdk_draw_rectangle (pixmap,
15763                       widget-&gt;style-&gt;white_gc,
15764                       TRUE,
15765                       0, 0,
15766                       widget-&gt;allocation.width,
15767                       widget-&gt;allocation.height);
15768
15769   return TRUE;
15770 }
15771
15772 /* Redraw the screen from the backing pixmap */
15773 static gint expose_event( GtkWidget      *widget,
15774                           GdkEventExpose *event )
15775 {
15776   gdk_draw_drawable (widget-&gt;window,
15777                      widget-&gt;style-&gt;fg_gc[GTK_WIDGET_STATE (widget)],
15778                      pixmap,
15779                      event-&gt;area.x, event-&gt;area.y,
15780                      event-&gt;area.x, event-&gt;area.y,
15781                      event-&gt;area.width, event-&gt;area.height);
15782
15783   return FALSE;
15784 }
15785
15786 /* Draw a rectangle on the screen */
15787 static void draw_brush( GtkWidget *widget,
15788                         gdouble    x,
15789                         gdouble    y)
15790 {
15791   GdkRectangle update_rect;
15792
15793   update_rect.x = x - 5;
15794   update_rect.y = y - 5;
15795   update_rect.width = 10;
15796   update_rect.height = 10;
15797   gdk_draw_rectangle (pixmap,
15798                       widget-&gt;style-&gt;black_gc,
15799                       TRUE,
15800                       update_rect.x, update_rect.y,
15801                       update_rect.width, update_rect.height);
15802   gtk_widget_queue_draw_area (widget, 
15803                       update_rect.x, update_rect.y,
15804                       update_rect.width, update_rect.height);
15805 }
15806
15807 static gint button_press_event( GtkWidget      *widget,
15808                                 GdkEventButton *event )
15809 {
15810   if (event-&gt;button == 1 &amp;&amp; pixmap != NULL)
15811     draw_brush (widget, event-&gt;x, event-&gt;y);
15812
15813   return TRUE;
15814 }
15815
15816 static gint motion_notify_event( GtkWidget *widget,
15817                                  GdkEventMotion *event )
15818 {
15819   int x, y;
15820   GdkModifierType state;
15821
15822   if (event-&gt;is_hint)
15823     gdk_window_get_pointer (event-&gt;window, &amp;x, &amp;y, &amp;state);
15824   else
15825     {
15826       x = event-&gt;x;
15827       y = event-&gt;y;
15828       state = event-&gt;state;
15829     }
15830     
15831   if (state &amp; GDK_BUTTON1_MASK &amp;&amp; pixmap != NULL)
15832     draw_brush (widget, x, y);
15833   
15834   return TRUE;
15835 }
15836
15837 void quit ()
15838 {
15839   exit (0);
15840 }
15841
15842 int main( int   argc, 
15843           char *argv[] )
15844 {
15845   GtkWidget *window;
15846   GtkWidget *drawing_area;
15847   GtkWidget *vbox;
15848
15849   GtkWidget *button;
15850
15851   gtk_init (&amp;argc, &amp;argv);
15852
15853   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
15854   gtk_widget_set_name (window, "Test Input");
15855
15856   vbox = gtk_vbox_new (FALSE, 0);
15857   gtk_container_add (GTK_CONTAINER (window), vbox);
15858   gtk_widget_show (vbox);
15859
15860   g_signal_connect (G_OBJECT (window), "destroy",
15861                     G_CALLBACK (quit), NULL);
15862
15863   /* Create the drawing area */
15864
15865   drawing_area = gtk_drawing_area_new ();
15866   gtk_widget_set_size_request (GTK_WIDGET (drawing_area), 200, 200);
15867   gtk_box_pack_start (GTK_BOX (vbox), drawing_area, TRUE, TRUE, 0);
15868
15869   gtk_widget_show (drawing_area);
15870
15871   /* Signals used to handle backing pixmap */
15872
15873   g_signal_connect (G_OBJECT (drawing_area), "expose_event",
15874                     G_CALLBACK (expose_event), NULL);
15875   g_signal_connect (G_OBJECT (drawing_area),"configure_event",
15876                     G_CALLBACK (configure_event), NULL);
15877
15878   /* Event signals */
15879
15880   g_signal_connect (G_OBJECT (drawing_area), "motion_notify_event",
15881                     G_CALLBACK (motion_notify_event), NULL);
15882   g_signal_connect (G_OBJECT (drawing_area), "button_press_event",
15883                     G_CALLBACK (button_press_event), NULL);
15884
15885   gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
15886                          | GDK_LEAVE_NOTIFY_MASK
15887                          | GDK_BUTTON_PRESS_MASK
15888                          | GDK_POINTER_MOTION_MASK
15889                          | GDK_POINTER_MOTION_HINT_MASK);
15890
15891   /* .. And a quit button */
15892   button = gtk_button_new_with_label ("Quit");
15893   gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
15894
15895   g_signal_connect_swapped (G_OBJECT (button), "clicked",
15896                             G_CALLBACK (gtk_widget_destroy),
15897                             G_OBJECT (window));
15898   gtk_widget_show (button);
15899
15900   gtk_widget_show (window);
15901
15902   gtk_main ();
15903
15904   return 0;
15905 }
15906 <!-- example-end -->
15907 </programlisting>
15908
15909 </sect2>
15910
15911 <!-- ----------------------------------------------------------------- -->
15912 <sect2>
15913 <title>scribble-xinput.c</title>
15914
15915 <programlisting role="C">
15916 <!-- example-start scribble-xinput scribble-xinput.c -->
15917
15918 /* GTK - The GIMP Toolkit
15919  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
15920  *
15921  * This library is free software; you can redistribute it and/or
15922  * modify it under the terms of the GNU Library General Public
15923  * License as published by the Free Software Foundation; either
15924  * version 2 of the License, or (at your option) any later version.
15925  *
15926  * This library is distributed in the hope that it will be useful,
15927  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15928  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15929  * Library General Public License for more details.
15930  *
15931  * You should have received a copy of the GNU Library General Public
15932  * License along with this library; if not, write to the
15933  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
15934  * Boston, MA 02111-1307, USA.
15935  */
15936
15937 #include &lt;gtk/gtk.h&gt;
15938
15939 /* Backing pixmap for drawing area */
15940 static GdkPixmap *pixmap = NULL;
15941
15942 /* Create a new backing pixmap of the appropriate size */
15943 static gint
15944 configure_event (GtkWidget *widget, GdkEventConfigure *event)
15945 {
15946   if (pixmap)
15947      g_object_unref (pixmap);
15948
15949   pixmap = gdk_pixmap_new (widget-&gt;window,
15950                            widget-&gt;allocation.width,
15951                            widget-&gt;allocation.height,
15952                            -1);
15953   gdk_draw_rectangle (pixmap,
15954                       widget-&gt;style-&gt;white_gc,
15955                       TRUE,
15956                       0, 0,
15957                       widget-&gt;allocation.width,
15958                       widget-&gt;allocation.height);
15959
15960   return TRUE;
15961 }
15962
15963 /* Redraw the screen from the backing pixmap */
15964 static gint
15965 expose_event (GtkWidget *widget, GdkEventExpose *event)
15966 {
15967   gdk_draw_drawable (widget-&gt;window,
15968                      widget-&gt;style-&gt;fg_gc[GTK_WIDGET_STATE (widget)],
15969                      pixmap,
15970                      event-&gt;area.x, event-&gt;area.y,
15971                      event-&gt;area.x, event-&gt;area.y,
15972                      event-&gt;area.width, event-&gt;area.height);
15973
15974   return FALSE;
15975 }
15976
15977 /* Draw a rectangle on the screen, size depending on pressure,
15978    and color on the type of device */
15979 static void
15980 draw_brush (GtkWidget *widget, GdkInputSource source,
15981             gdouble x, gdouble y, gdouble pressure)
15982 {
15983   GdkGC *gc;
15984   GdkRectangle update_rect;
15985
15986   switch (source)
15987     {
15988     case GDK_SOURCE_MOUSE:
15989       gc = widget-&gt;style-&gt;dark_gc[GTK_WIDGET_STATE (widget)];
15990       break;
15991     case GDK_SOURCE_PEN:
15992       gc = widget-&gt;style-&gt;black_gc;
15993       break;
15994     case GDK_SOURCE_ERASER:
15995       gc = widget-&gt;style-&gt;white_gc;
15996       break;
15997     default:
15998       gc = widget-&gt;style-&gt;light_gc[GTK_WIDGET_STATE (widget)];
15999     }
16000
16001   update_rect.x = x - 10 * pressure;
16002   update_rect.y = y - 10 * pressure;
16003   update_rect.width = 20 * pressure;
16004   update_rect.height = 20 * pressure;
16005   gdk_draw_rectangle (pixmap, gc, TRUE,
16006                       update_rect.x, update_rect.y,
16007                       update_rect.width, update_rect.height);
16008   gtk_widget_queue_draw_area (widget, 
16009                       update_rect.x, update_rect.y,
16010                       update_rect.width, update_rect.height);
16011 }
16012
16013 static void
16014 print_button_press (GdkDevice *device)
16015 {
16016   g_print ("Button press on device '%s'\n", device-&gt;name);
16017 }
16018
16019 static gint
16020 button_press_event (GtkWidget *widget, GdkEventButton *event)
16021 {
16022   print_button_press (event-&gt;device);
16023   
16024   if (event-&gt;button == 1 &amp;&amp; pixmap != NULL) {
16025     gdouble pressure;
16026     gdk_event_get_axis ((GdkEvent *)event, GDK_AXIS_PRESSURE, &amp;pressure);
16027     draw_brush (widget, event-&gt;device-&gt;source, event-&gt;x, event-&gt;y, pressure);
16028   }
16029
16030   return TRUE;
16031 }
16032
16033 static gint
16034 motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
16035 {
16036   gdouble x, y;
16037   gdouble pressure;
16038   GdkModifierType state;
16039
16040   if (event-&gt;is_hint) 
16041     {
16042       gdk_device_get_state (event-&gt;device, event-&gt;window, NULL, &amp;state);
16043       gdk_event_get_axis ((GdkEvent *)event, GDK_AXIS_X, &amp;x);
16044       gdk_event_get_axis ((GdkEvent *)event, GDK_AXIS_Y, &amp;y);
16045       gdk_event_get_axis ((GdkEvent *)event, GDK_AXIS_PRESSURE, &amp;pressure);
16046     }
16047   else
16048     {
16049       x = event-&gt;x;
16050       y = event-&gt;y;
16051       gdk_event_get_axis ((GdkEvent *)event, GDK_AXIS_PRESSURE, &amp;pressure);
16052       state = event-&gt;state;
16053     }
16054     
16055   if (state &amp; GDK_BUTTON1_MASK &amp;&amp; pixmap != NULL)
16056     draw_brush (widget, event-&gt;device-&gt;source, x, y, pressure);
16057   
16058   return TRUE;
16059 }
16060
16061 void
16062 input_dialog_destroy (GtkWidget *w, gpointer data)
16063 {
16064   *((GtkWidget **)data) = NULL;
16065 }
16066
16067 void
16068 create_input_dialog ()
16069 {
16070   static GtkWidget *inputd = NULL;
16071
16072   if (!inputd)
16073     {
16074       inputd = gtk_input_dialog_new();
16075
16076       g_signal_connect (G_OBJECT (inputd), "destroy",
16077                         G_CALLBACK (input_dialog_destroy), (gpointer) &amp;inputd);
16078       g_signal_connect_swapped (G_OBJECT (GTK_INPUT_DIALOG (inputd)-&gt;close_button),
16079                                 "clicked",
16080                                 G_CALLBACK (gtk_widget_hide),
16081                                 G_OBJECT (inputd));
16082       gtk_widget_hide (GTK_INPUT_DIALOG (inputd)-&gt;save_button);
16083
16084       gtk_widget_show (inputd);
16085     }
16086   else
16087     {
16088       if (!GTK_WIDGET_MAPPED (inputd))
16089         gtk_widget_show (inputd);
16090       else
16091         gdk_window_raise (inputd-&gt;window);
16092     }
16093 }
16094
16095 void
16096 quit ()
16097 {
16098   exit (0);
16099 }
16100
16101 int
16102 main (int argc, char *argv[])
16103 {
16104   GtkWidget *window;
16105   GtkWidget *drawing_area;
16106   GtkWidget *vbox;
16107
16108   GtkWidget *button;
16109
16110   gtk_init (&amp;argc, &amp;argv);
16111
16112   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
16113   gtk_widget_set_name (window, "Test Input");
16114
16115   vbox = gtk_vbox_new (FALSE, 0);
16116   gtk_container_add (GTK_CONTAINER (window), vbox);
16117   gtk_widget_show (vbox);
16118
16119   g_signal_connect (G_OBJECT (window), "destroy",
16120                     G_CALLBACK (quit), NULL);
16121
16122   /* Create the drawing area */
16123
16124   drawing_area = gtk_drawing_area_new ();
16125   gtk_widget_set_size_request (GTK_WIDGET (drawing_area), 200, 200);
16126   gtk_box_pack_start (GTK_BOX (vbox), drawing_area, TRUE, TRUE, 0);
16127
16128   gtk_widget_show (drawing_area);
16129
16130   /* Signals used to handle backing pixmap */
16131
16132   g_signal_connect (G_OBJECT (drawing_area), "expose_event",
16133                     G_CALLBACK (expose_event), NULL);
16134   g_signal_connect (G_OBJECT(drawing_area),"configure_event",
16135                     G_CALLBACK (configure_event), NULL);
16136
16137   /* Event signals */
16138
16139   g_signal_connect (G_OBJECT (drawing_area), "motion_notify_event",
16140                     G_CALLBACK (motion_notify_event), NULL);
16141   g_signal_connect (G_OBJECT (drawing_area), "button_press_event",
16142                     G_CALLBACK (button_press_event), NULL);
16143
16144   gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
16145                          | GDK_LEAVE_NOTIFY_MASK
16146                          | GDK_BUTTON_PRESS_MASK
16147                          | GDK_POINTER_MOTION_MASK
16148                          | GDK_POINTER_MOTION_HINT_MASK);
16149
16150   /* The following call enables tracking and processing of extension
16151      events for the drawing area */
16152   gtk_widget_set_extension_events (drawing_area, GDK_EXTENSION_EVENTS_CURSOR);
16153
16154   /* .. And some buttons */
16155   button = gtk_button_new_with_label ("Input Dialog");
16156   gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
16157
16158   g_signal_connect (G_OBJECT (button), "clicked",
16159                     G_CALLBACK (create_input_dialog), NULL);
16160   gtk_widget_show (button);
16161
16162   button = gtk_button_new_with_label ("Quit");
16163   gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
16164
16165   g_signal_connect_swapped (G_OBJECT (button), "clicked",
16166                             G_CALLBACK (gtk_widget_destroy),
16167                             G_OBJECT (window));
16168   gtk_widget_show (button);
16169
16170   gtk_widget_show (window);
16171
16172   gtk_main ();
16173
16174   return 0;
16175 }
16176 <!-- example-end -->
16177 </programlisting>
16178
16179 </sect2>
16180 </sect1>
16181
16182 </appendix>
16183 </book>