]> Pileus Git - ~andy/gtk/blob - docs/tutorial/gtk-tut.sgml
Practically everything changed.
[~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>January 24th, 2003</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 GTK+ 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 (GTK+ 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 (GTK+ 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.</para>
68
69 <para>GTK is essentially an object oriented application programmers
70 interface (API). Although written completely in C, it is implemented
71 using the idea of classes and callback functions (pointers to
72 functions).</para>
73
74 <para>There is also a third component called GLib which contains a few
75 replacements for some standard calls, as well as some additional
76 functions for handling linked lists, etc. The replacement functions
77 are used to increase GTK's portability, as some of the functions
78 implemented here are not available or are nonstandard on other Unixes
79 such as g_strerror(). Some also contain enhancements to the libc
80 versions, such as g_malloc() that has enhanced debugging utilities.</para>
81
82 <para>In version 2.0, GLib has picked up the type system which forms the
83 foundation for GTK's class hierarchy, the signal system which is used
84 throughout GTK, a thread API which abstracts the different native thread APIs 
85 of the various platforms and a facility for loading modules.
86 </para>
87
88 <para>As the last component, GTK uses the Pango library for internationalized
89 text output.
90 </para>
91
92 <para>This tutorial describes the C interface to GTK. There are GTK
93 bindings for many other languages including C++, Guile, Perl, Python,
94 TOM, Ada95, Objective C, Free Pascal, Eiffel, Java and C#. If you intend to
95 use another language's bindings to GTK, look at that binding's
96 documentation first. In some cases that documentation may describe
97 some important conventions (which you should know first) and then
98 refer you back to this tutorial. There are also some cross-platform
99 APIs (such as wxWindows and V) which use GTK as one of their target
100 platforms; again, consult their documentation first.</para>
101
102 <para>If you're developing your GTK application in C++, a few extra notes
103 are in order. There's a C++ binding to GTK called GTK--, which
104 provides a more C++-like interface to GTK; you should probably look
105 into this instead. If you don't like that approach for whatever
106 reason, there are two alternatives for using GTK. First, you can use
107 only the C subset of C++ when interfacing with GTK and then use the C
108 interface as described in this tutorial. Second, you can use GTK and
109 C++ together by declaring all callbacks as static functions in C++
110 classes, and again calling GTK using its C interface. If you choose
111 this last approach, you can include as the callback's data value a
112 pointer to the object to be manipulated (the so-called "this" value).
113 Selecting between these options is simply a matter of preference,
114 since in all three approaches you get C++ and GTK. None of these
115 approaches requires the use of a specialized preprocessor, so no
116 matter what you choose you can use standard C++ with GTK.</para>
117
118 <para>This tutorial is an attempt to document as much as possible of GTK,
119 but it is by no means complete. This tutorial assumes a good
120 understanding of C, and how to create C programs. It would be a great
121 benefit for the reader to have previous X programming experience, but
122 it shouldn't be necessary. If you are learning GTK as your first
123 widget set, please comment on how you found this tutorial, and what
124 you had trouble with. There are also C++, Objective C, ADA, Guile and
125 other language bindings available, but I don't follow these.</para>
126
127 <para>This document is a "work in progress". Please look for updates on
128 <ulink url="http://www.gtk.org/">http://www.gtk.org/</ulink>.</para>
129
130 <para>I would very much like to hear of any problems you have learning GTK
131 from this document, and would appreciate input as to how it may be
132 improved. Please see the section on <link linkend="ch-Contributing">Contributing
133 </link> for further information.</para>
134
135 </chapter>
136
137 <!-- ***************************************************************** -->
138 <chapter id="ch-GettingStarted">
139 <title>Getting Started</title>
140
141 <para>The first thing to do, of course, is download the GTK source and
142 install it. You can always get the latest version from <ulink 
143 url="ftp://ftp.gtk.org/pub/gtk">ftp.gtk.org</ulink>. You can also view 
144 other sources of GTK information on
145 <ulink url="http://www.gtk.org/">http://www.gtk.org/</ulink>. GTK
146 uses GNU autoconf for configuration. Once untar'd, type 
147 <literal>./configure --help</literal> to see a list of options.</para>
148
149 <para>The GTK source distribution also contains the complete source to all
150 of the examples used in this tutorial, along with Makefiles to aid
151 compilation.</para>
152
153 <para>To begin our introduction to GTK, we'll start with the simplest
154 program possible. This program will create a 200x200 pixel window and
155 has no way of exiting except to be killed by using the shell.</para>
156
157 <para>
158 <inlinemediaobject>
159 <imageobject>
160 <imagedata fileref="images/base.png" format="png">
161 </imageobject>
162 </inlinemediaobject>
163 </para>
164
165 <programlisting role="C">
166 <!-- example-start base base.c -->
167
168 #include &lt;gtk/gtk.h&gt;
169
170 int main( int   argc,
171           char *argv[] )
172 {
173     GtkWidget *window;
174     
175     gtk_init (&amp;argc, &amp;argv);
176     
177     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
178     gtk_widget_show  (window);
179     
180     gtk_main ();
181     
182     return 0;
183 }
184 <!-- example-end -->
185 </programlisting>
186
187 <para>You can compile the above program with gcc using:</para>
188 <para><literallayout>
189 <literal>gcc base.c -o base `pkg-config --cflags --libs gtk+-2.0`</literal>
190 </literallayout></para>
191
192 <para>The meaning of the unusual compilation options is explained below in
193 <link linkend="sec-Compiling">Compiling Hello World</link>.</para>
194
195 <para>All programs will of course include <filename>gtk/gtk.h</filename> which 
196 declares the variables, functions, structures, etc. that will be used in your GTK
197 application.</para>
198
199 <para>The next line:</para>
200
201 <programlisting role="C">
202 gtk_init (&amp;argc, &amp;argv);
203 </programlisting>
204
205 <para>calls the function gtk_init(gint *argc, gchar ***argv) which will be called 
206 in all GTK applications. This sets up a few things for us such as the default visual 
207 and color map and then proceeds to call gdk_init(gint *argc, gchar ***argv). 
208 This function initializes the library for use, sets up default signal handlers, and 
209 checks the arguments passed to your application on the command line, looking for
210 one of the following:</para>
211
212 <itemizedlist spacing=Compact>
213 <listitem><simpara> <literal>--gtk-module</literal></simpara>
214 </listitem>
215 <listitem><simpara> <literal>--g-fatal-warnings</literal></simpara>
216 </listitem>
217 <listitem><simpara> <literal>--gtk-debug</literal></simpara>
218 </listitem>
219 <listitem><simpara> <literal>--gtk-no-debug</literal></simpara>
220 </listitem>
221 <listitem><simpara> <literal>--gdk-debug</literal></simpara>
222 </listitem>
223 <listitem><simpara> <literal>--gdk-no-debug</literal></simpara>
224 </listitem>
225 <listitem><simpara> <literal>--display</literal></simpara>
226 </listitem>
227 <listitem><simpara> <literal>--sync</literal></simpara>
228 </listitem>
229 <listitem><simpara> <literal>--name</literal></simpara>
230 </listitem>
231 <listitem><simpara> <literal>--class</literal></simpara>
232 </listitem>
233 </itemizedlist>
234
235 <para>It removes these from the argument list, leaving anything it does not
236 recognize for your application to parse or ignore. This creates a set
237 of standard arguments accepted by all GTK applications.</para>
238
239 <para>The next two lines of code create and display a window.</para>
240
241 <programlisting role="C">
242   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
243   gtk_widget_show (window);
244 </programlisting>
245
246 <para>The <literal>GTK_WINDOW_TOPLEVEL</literal> argument specifies that we want the
247 window to undergo window manager decoration and placement. Rather than
248 create a window of 0x0 size, a window without children is set to
249 200x200 by default so you can still manipulate it.</para>
250
251 <para>The gtk_widget_show() function lets GTK know that we are done setting
252 the attributes of this widget, and that it can display it.</para>
253
254 <para>The last line enters the GTK main processing loop.</para>
255
256 <programlisting role="C">
257   gtk_main ();
258 </programlisting>
259
260 <para>gtk_main() is another call you will see in every GTK application.
261 When control reaches this point, GTK will sleep waiting for X events
262 (such as button or key presses), timeouts, or file IO notifications to
263 occur. In our simple example, however, events are ignored.</para>
264
265 <!-- ----------------------------------------------------------------- -->
266 <sect1 id="sec-HelloWorld">
267 <title>Hello World in GTK</title>
268
269 <para>Now for a program with a widget (a button). It's the classic
270 hello world a la GTK.</para>
271
272 <para>
273 <inlinemediaobject>
274 <imageobject>
275 <imagedata fileref="images/helloworld.png" format="png">
276 </imageobject>
277 </inlinemediaobject>
278 </para>
279
280 <programlisting role="C">
281 <!-- example-start helloworld helloworld.c -->
282
283 #include &lt;gtk/gtk.h&gt;
284
285 /* This is a callback function. The data arguments are ignored
286  * in this example. More on callbacks below. */
287 static void hello( GtkWidget *widget,
288                    gpointer   data )
289 {
290     g_print ("Hello World\n");
291 }
292
293 static gboolean delete_event( GtkWidget *widget,
294                               GdkEvent  *event,
295                               gpointer   data )
296 {
297     /* If you return FALSE in the "delete_event" signal handler,
298      * GTK will emit the "destroy" signal. Returning TRUE means
299      * you don't want the window to be destroyed.
300      * This is useful for popping up 'are you sure you want to quit?'
301      * type dialogs. */
302
303     g_print ("delete event occurred\n");
304
305     /* Change TRUE to FALSE and the main window will be destroyed with
306      * a "delete_event". */
307
308     return TRUE;
309 }
310
311 /* Another callback */
312 static void destroy( GtkWidget *widget,
313                      gpointer   data )
314 {
315     gtk_main_quit ();
316 }
317
318 int main( int   argc,
319           char *argv[] )
320 {
321     /* GtkWidget is the storage type for widgets */
322     GtkWidget *window;
323     GtkWidget *button;
324     
325     /* This is called in all GTK applications. Arguments are parsed
326      * from the command line and are returned to the application. */
327     gtk_init (&amp;argc, &amp;argv);
328     
329     /* create a new window */
330     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
331     
332     /* When the window is given the "delete_event" signal (this is given
333      * by the window manager, usually by the "close" option, or on the
334      * titlebar), we ask it to call the delete_event () function
335      * as defined above. The data passed to the callback
336      * function is NULL and is ignored in the callback function. */
337     g_signal_connect (G_OBJECT (window), "delete_event",
338                       G_CALLBACK (delete_event), NULL);
339     
340     /* Here we connect the "destroy" event to a signal handler.  
341      * This event occurs when we call gtk_widget_destroy() on the window,
342      * or if we return FALSE in the "delete_event" callback. */
343     g_signal_connect (G_OBJECT (window), "destroy",
344                       G_CALLBACK (destroy), NULL);
345     
346     /* Sets the border width of the window. */
347     gtk_container_set_border_width (GTK_CONTAINER (window), 10);
348     
349     /* Creates a new button with the label "Hello World". */
350     button = gtk_button_new_with_label ("Hello World");
351     
352     /* When the button receives the "clicked" signal, it will call the
353      * function hello() passing it NULL as its argument.  The hello()
354      * function is defined above. */
355     g_signal_connect (G_OBJECT (button), "clicked",
356                       G_CALLBACK (hello), NULL);
357     
358     /* This will cause the window to be destroyed by calling
359      * gtk_widget_destroy(window) when "clicked".  Again, the destroy
360      * signal could come from here, or the window manager. */
361     g_signal_connect_swapped (G_OBJECT (button), "clicked",
362                               G_CALLBACK (gtk_widget_destroy),
363                               G_OBJECT (window));
364     
365     /* This packs the button into the window (a gtk container). */
366     gtk_container_add (GTK_CONTAINER (window), button);
367     
368     /* The final step is to display this newly created widget. */
369     gtk_widget_show (button);
370     
371     /* and the window */
372     gtk_widget_show (window);
373     
374     /* All GTK applications must have a gtk_main(). Control ends here
375      * and waits for an event to occur (like a key press or
376      * mouse event). */
377     gtk_main ();
378     
379     return 0;
380 }
381 <!-- example-end -->
382 </programlisting>
383
384 </sect1>
385
386 <!-- ----------------------------------------------------------------- -->
387 <sect1 id="sec-Compiling">
388 <title>Compiling Hello World</title>
389
390 <para>To compile use:</para>
391
392 <para><literallayout>
393 <literal>gcc -Wall -g helloworld.c -o helloworld `pkg-config --cflags gtk+-2.0` \</literal>
394 <literal>    `pkg-config --libs gtk+-2.0`</literal>
395 </literallayout></para>
396
397 <para>This uses the program <literal>pkg-config</literal>, which can be obtained from
398 <ulink url="http://www.freedesktop.org">www.freedesktop.org</ulink>. This program 
399 reads the <filename>.pc</filename> which comes with GTK to determine what 
400 compiler switches are needed to compile programs that use GTK. 
401 <literal>pkg-config --cflags gtk+-2.0</literal> will output a list of include
402 directories for the compiler to look in, and 
403 <literal>pkg-config --libs gtk+-2.0</literal>
404 will output the list of libraries for the compiler to link with and
405 the directories to find them in. In the above example they could have
406 been combined into a single instance, such as
407 <literal>pkg-config --cflags --libs gtk+-2.0</literal>.</para>
408
409 <para>Note that the type of single quote used in the compile command above
410 is significant.</para>
411
412 <para>The libraries that are usually linked in are:</para>
413
414 <itemizedlist>
415 <listitem><simpara>The GTK library (<literal>-lgtk</literal>), the widget library, 
416 based on top of GDK.</simpara>
417 </listitem>
418
419 <listitem><simpara>The GDK library (<literal>-lgdk</literal>), the Xlib wrapper.</simpara>
420 </listitem>
421
422 <listitem><simpara>The gdk-pixbuf library (<literal>-lgdk_pixbuf</literal>), the image 
423 manipulation library.</simpara>
424 </listitem>
425
426 <listitem><simpara>The Pango library (<literal>-lpango</literal>) for internationalized 
427 text.</simpara>
428 </listitem>
429
430 <listitem><simpara>The gobject library (<literal>-lgobject</literal>), containing the
431 type system on which GTK is based.</simpara>
432 </listitem>
433
434 <listitem><simpara>The gmodule library (<literal>-lgmodule</literal>), which is used 
435 to load run time extensions.</simpara>
436 </listitem>
437
438 <listitem><simpara>The GLib library (<literal>-lglib</literal>), containing miscellaneous
439 functions; only g_print() is used in this particular example. GTK is built on top
440 of GLib so you will always require this library. See the section on
441 <link linkend="ch-glib">GLib</link> for details.</simpara>
442 </listitem>
443
444 <listitem><simpara>The Xlib library (<literal>-lX11</literal>) which is used by GDK.</simpara>
445 </listitem>
446
447 <listitem><simpara>The Xext library (<literal>-lXext</literal>). This contains code 
448 for shared memory pixmaps and other X extensions.</simpara>
449 </listitem>
450
451 <listitem><simpara>The math library (<literal>-lm</literal>). This is used by GTK 
452 for various purposes.</simpara>
453 </listitem>
454 </itemizedlist>
455
456 </sect1>
457
458 <!-- ----------------------------------------------------------------- -->
459 <sect1 id="sec-TheoryOfSignalsAndCallbacks">
460 <title>Theory of Signals and Callbacks</title>
461
462 <note>
463 <para>In version 2.0, the signal system has been moved from GTK to GLib, therefore the
464 functions and types explained in this section have a "g_" prefix rather than a "gtk_" 
465 prefix. We won't go into details about the extensions which the GLib 2.0 signal system
466 has relative to the GTK 1.2 signal system.</para>
467 </note>
468
469 <para>Before we look in detail at <emphasis>helloworld</emphasis>, we'll discuss signals
470 and callbacks. GTK is an event driven toolkit, which means it will
471 sleep in gtk_main() until an event occurs and control is passed to the
472 appropriate function.</para>
473
474 <para>This passing of control is done using the idea of "signals". (Note
475 that these signals are not the same as the Unix system signals, and
476 are not implemented using them, although the terminology is almost
477 identical.) When an event occurs, such as the press of a mouse button,
478 the appropriate signal will be "emitted" by the widget that was
479 pressed.  This is how GTK does most of its useful work. There are
480 signals that all widgets inherit, such as "destroy", and there are
481 signals that are widget specific, such as "toggled" on a toggle
482 button.</para>
483
484 <para>To make a button perform an action, we set up a signal handler to
485 catch these signals and call the appropriate function. This is done by
486 using a function such as:</para>
487
488 <programlisting role="C">
489 gulong g_signal_connect( gpointer      *object,
490                          const gchar   *name,
491                          GCallback     func,
492                          gpointer      func_data );
493 </programlisting>
494
495 <para>where the first argument is the widget which will be emitting the
496 signal, and the second the name of the signal you wish to catch. The
497 third is the function you wish to be called when it is caught, and the
498 fourth, the data you wish to have passed to this function.</para>
499
500 <para>The function specified in the third argument is called a "callback
501 function", and should generally be of the form</para>
502
503 <programlisting role="C">
504 void callback_func( GtkWidget *widget,
505                     ... /* other signal arguments */
506                     gpointer   callback_data );
507 </programlisting>
508
509 <para>where the first argument will be a pointer to the widget that emitted
510 the signal, and the last a pointer to the data given as the last
511 argument to the g_signal_connect() function as shown above.</para>
512
513 <para>Note that the above form for a signal callback function declaration is
514 only a general guide, as some widget specific signals generate
515 different calling parameters.</para>
516
517 <para>Another call used in the <emphasis>helloworld</emphasis> example, is:</para>
518
519 <programlisting role="C">
520 gulong g_signal_connect_swapped( gpointer     *object,
521                                  const gchar  *name,
522                                  GCallback    func,
523                                  gpointer     *callback_data );
524 </programlisting>
525
526 <para>g_signal_connect_swapped() is the same as g_signal_connect() except
527 that the instance on which the signal is emitted and data will be swapped when
528 calling the handler. So when using this function to connect signals, the callback
529 should be of the form</para>
530
531 <programlisting role="C">
532 void callback_func( gpointer   callback_data,
533                     ... /* other signal arguments */
534                     GtkWidget *widget);
535 </programlisting>
536
537 <para>where the object is usually a widget. We usually don't setup callbacks
538 for g_signal_connect_swapped() however. They are usually used to call a
539 GTK function that accepts a single widget or object as an argument, when a signal
540 is emitted on some <emphasis>other</emphasis> object. In the 
541 <emphasis>helloworld</emphasis> example, we connect to the "clicked" signal
542 on the button, but call gtk_widget_destroy() on the window.</para>
543
544 <para>If your callbacks need additional data, use g_signal_connect() instead
545 of g_signal_connect_swapped().</para>
546
547 </sect1>
548
549 <!-- ----------------------------------------------------------------- -->
550 <sect1 id="sec-Events">
551 <title>Events</title>
552
553 <para>In addition to the signal mechanism described above, there is a set
554 of <emphasis>events</emphasis> that reflect the X event mechanism. Callbacks may
555 also be attached to these events. These events are:</para>
556
557 <itemizedlist spacing=Compact>
558 <listitem><simpara> event</simpara>
559 </listitem>
560 <listitem><simpara> button_press_event</simpara>
561 </listitem>
562 <listitem><simpara> button_release_event</simpara>
563 </listitem>
564 <listitem><simpara> scroll_event</simpara>
565 </listitem>
566 <listitem><simpara> motion_notify_event</simpara>
567 </listitem>
568 <listitem><simpara> delete_event</simpara>
569 </listitem>
570 <listitem><simpara> destroy_event</simpara>
571 </listitem>
572 <listitem><simpara> expose_event</simpara>
573 </listitem>
574 <listitem><simpara> key_press_event</simpara>
575 </listitem>
576 <listitem><simpara> key_release_event</simpara>
577 </listitem>
578 <listitem><simpara> enter_notify_event</simpara>
579 </listitem>
580 <listitem><simpara> leave_notify_event</simpara>
581 </listitem>
582 <listitem><simpara> configure_event</simpara>
583 </listitem>
584 <listitem><simpara> focus_in_event</simpara>
585 </listitem>
586 <listitem><simpara> focus_out_event</simpara>
587 </listitem>
588 <listitem><simpara> map_event</simpara>
589 </listitem>
590 <listitem><simpara> unmap_event</simpara>
591 </listitem>
592 <listitem><simpara> property_notify_event</simpara>
593 </listitem>
594 <listitem><simpara> selection_clear_event</simpara>
595 </listitem>
596 <listitem><simpara> selection_request_event</simpara>
597 </listitem>
598 <listitem><simpara> selection_notify_event</simpara>
599 </listitem>
600 <listitem><simpara> proximity_in_event</simpara>
601 </listitem>
602 <listitem><simpara> proximity_out_event</simpara>
603 </listitem>
604 <listitem><simpara> visibility_notify_event</simpara>
605 </listitem>
606 <listitem><simpara> client_event</simpara>
607 </listitem>
608 <listitem><simpara> no_expose_event</simpara>
609 </listitem>
610 <listitem><simpara> window_state_event</simpara>
611 </listitem>
612 </itemizedlist>
613
614 <para>In order to connect a callback function to one of these events you
615 use the function g_signal_connect(), as described above, using one of
616 the above event names as the <literal>name</literal> parameter. The callback
617 function for events has a slightly different form than that for
618 signals:</para>
619
620 <programlisting role="C">
621 gint callback_func( GtkWidget *widget,
622                     GdkEvent  *event,
623                     gpointer   callback_data );
624 </programlisting>
625
626 <para>GdkEvent is a C <literal>union</literal> structure whose type will depend upon 
627 which of the above events has occurred. In order for us to tell which event
628 has been issued each of the possible alternatives has a <literal>type</literal>
629 member that reflects the event being issued. The other components
630 of the event structure will depend upon the type of the
631 event. Possible values for the type are:</para>
632
633 <programlisting role="C">
634   GDK_NOTHING
635   GDK_DELETE
636   GDK_DESTROY
637   GDK_EXPOSE
638   GDK_MOTION_NOTIFY
639   GDK_BUTTON_PRESS
640   GDK_2BUTTON_PRESS
641   GDK_3BUTTON_PRESS
642   GDK_BUTTON_RELEASE
643   GDK_KEY_PRESS
644   GDK_KEY_RELEASE
645   GDK_ENTER_NOTIFY
646   GDK_LEAVE_NOTIFY
647   GDK_FOCUS_CHANGE
648   GDK_CONFIGURE
649   GDK_MAP
650   GDK_UNMAP
651   GDK_PROPERTY_NOTIFY
652   GDK_SELECTION_CLEAR
653   GDK_SELECTION_REQUEST
654   GDK_SELECTION_NOTIFY
655   GDK_PROXIMITY_IN
656   GDK_PROXIMITY_OUT
657   GDK_DRAG_ENTER
658   GDK_DRAG_LEAVE
659   GDK_DRAG_MOTION
660   GDK_DRAG_STATUS
661   GDK_DROP_START
662   GDK_DROP_FINISHED
663   GDK_CLIENT_EVENT
664   GDK_VISIBILITY_NOTIFY
665   GDK_NO_EXPOSE
666   GDK_SCROLL
667   GDK_WINDOW_STATE
668   GDK_SETTING
669 </programlisting>
670
671 <para>So, to connect a callback function to one of these events we would use
672 something like:</para>
673
674 <programlisting role="C">
675 g_signal_connect (G_OBJECT (button), "button_press_event",
676                   G_CALLBACK (button_press_callback), NULL);
677 </programlisting>
678
679 <para>This assumes that <literal>button</literal> is a Button widget. Now, when the
680 mouse is over the button and a mouse button is pressed, the function
681 button_press_callback() will be called. This function may be declared as:</para>
682
683 <programlisting role="C">
684 static gboolean button_press_callback( GtkWidget      *widget, 
685                                        GdkEventButton *event,
686                                        gpointer        data );
687 </programlisting>
688
689 <para>Note that we can declare the second argument as type
690 <literal>GdkEventButton</literal> as we know what type of event will occur for this
691 function to be called.</para>
692
693 <para>The value returned from this function indicates whether the event
694 should be propagated further by the GTK event handling
695 mechanism. Returning TRUE indicates that the event has been handled,
696 and that it should not propagate further. Returning FALSE continues
697 the normal event handling.  See the section on
698 <link linkend="ch-AdvancedEventsAndSignals">Advanced Event and Signal Handling</link> 
699 for more details on this propagation process.</para>
700
701 <para>For details on the GdkEvent data types, see the appendix entitled
702 <link linkend="app-GDKEventTypes">GDK Event Types</link>.</para>
703
704 <para>The GDK selection and drag-and-drop APIs also emit a number of events which
705 are reflected in GTK by the signals. See <link 
706 linkend="sec-SignalsOnSourceWidgets">Signals on the source widget</link> and <link 
707 linkend="sec-SignalsOnDestWidgets">Signals on the destination widget</link>
708 for details on the signatures of the callback functions for these signals:</para>
709
710 <itemizedlist spacing=Compact>
711 <listitem><simpara> selection_received</simpara>
712 </listitem>
713 <listitem><simpara> selection_get</simpara>
714 </listitem>
715 <listitem><simpara> drag_begin_event</simpara>
716 </listitem>
717 <listitem><simpara> drag_end_event</simpara>
718 </listitem>
719 <listitem><simpara> drag_data_delete</simpara>
720 </listitem>
721 <listitem><simpara> drag_motion</simpara>
722 </listitem>
723 <listitem><simpara> drag_drop</simpara>
724 </listitem>
725 <listitem><simpara> drag_data_get</simpara>
726 </listitem>
727 <listitem><simpara> drag_data_received</simpara>
728 </listitem>
729 </itemizedlist>
730
731 </sect1>
732
733 <!-- ----------------------------------------------------------------- -->
734 <sect1 id="sec-SteppingThroughHelloWorld">
735 <title>Stepping Through Hello World</title>
736
737 <para>Now that we know the theory behind this, let's clarify by walking
738 through the example <emphasis>helloworld</emphasis> program.</para>
739
740 <para>Here is the callback function that will be called when the button is
741 "clicked". We ignore both the widget and the data in this example, but
742 it is not hard to do things with them. The next example will use the
743 data argument to tell us which button was pressed.</para>
744
745 <programlisting role="C">
746 static void hello( GtkWidget *widget,
747                    gpointer   data )
748 {
749     g_print ("Hello World\n");
750 }
751 </programlisting>
752
753 <para>The next callback is a bit special. The "delete_event" occurs when the
754 window manager sends this event to the application. We have a choice
755 here as to what to do about these events. We can ignore them, make
756 some sort of response, or simply quit the application.</para>
757
758 <para>The value you return in this callback lets GTK know what action to
759 take.  By returning TRUE, we let it know that we don't want to have
760 the "destroy" signal emitted, keeping our application running. By
761 returning FALSE, we ask that "destroy" be emitted, which in turn will
762 call our "destroy" signal handler.</para>
763
764
765 <programlisting role="C">
766 static gboolean delete_event( GtkWidget *widget,
767                               GdkEvent  *event,
768                               gpointer   data )
769 {
770     g_print ("delete event occurred\n");
771
772     return TRUE; 
773 }
774 </programlisting>
775
776 <para>Here is another callback function which causes the program to quit by
777 calling gtk_main_quit(). This function tells GTK that it is to exit
778 from gtk_main when control is returned to it.</para>
779
780 <programlisting role="C">
781 static void destroy( GtkWidget *widget,
782                      gpointer   data )
783 {
784     gtk_main_quit ();
785 }
786 </programlisting>
787
788 <para>I assume you know about the main() function... yes, as with other
789 applications, all GTK applications will also have one of these.</para>
790
791 <programlisting role="C">
792 int main( int   argc,
793           char *argv[] )
794 {
795 </programlisting>
796
797 <para>This next part declares pointers to a structure of type
798 GtkWidget. These are used below to create a window and a button.</para>
799
800 <programlisting role="C">
801     GtkWidget *window;
802     GtkWidget *button;
803 </programlisting>
804
805 <para>Here is our gtk_init() again. As before, this initializes the toolkit,
806 and parses the arguments found on the command line. Any argument it
807 recognizes from the command line, it removes from the list, and
808 modifies argc and argv to make it look like they never existed,
809 allowing your application to parse the remaining arguments.</para>
810
811 <programlisting role="C">
812     gtk_init (&amp;argc, &amp;argv);
813 </programlisting>
814
815 <para>Create a new window. This is fairly straightforward. Memory is
816 allocated for the GtkWidget *window structure so it now points to a
817 valid structure. It sets up a new window, but it is not displayed
818 until we call gtk_widget_show(window) near the end of our program.</para>
819
820 <programlisting role="C">
821     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
822 </programlisting>
823
824 <para>Here are two examples of connecting a signal handler to an object, in
825 this case, the window. Here, the "delete_event" and "destroy" signals
826 are caught. The first is emitted when we use the window manager to
827 kill the window, or when we use the gtk_widget_destroy() call passing
828 in the window widget as the object to destroy. The second is emitted
829 when, in the "delete_event" handler, we return FALSE.
830  
831 The <literal>G_OBJECT</literal> and <literal>G_CALLBACK</literal> are macros 
832 that perform type casting and checking for us, as well as aid the readability of
833 the code.</para>
834
835 <programlisting role="C">
836     g_signal_connect (G_OBJECT (window), "delete_event",
837                       G_CALLBACK (delete_event), NULL);
838     g_signal_connect (G_OBJECT (window), "destroy",
839                       G_CALLBACK (destroy), NULL);
840 </programlisting>
841
842 <para>This next function is used to set an attribute of a container object.
843 This just sets the window so it has a blank area along the inside of
844 it 10 pixels wide where no widgets will go. There are other similar
845 functions which we will look at in the section on
846 <link linkend="ch-SettingWidgetAttributes">Setting Widget Attributes</link></para>
847
848 <para>And again, <literal>GTK_CONTAINER</literal> is a macro to perform type casting.</para>
849
850 <programlisting role="C">
851     gtk_container_set_border_width (GTK_CONTAINER (window), 10);
852 </programlisting>
853
854 <para>This call creates a new button. It allocates space for a new GtkWidget
855 structure in memory, initializes it, and makes the button pointer
856 point to it. It will have the label "Hello World" on it when
857 displayed.</para>
858
859 <programlisting role="C">
860     button = gtk_button_new_with_label ("Hello World");
861 </programlisting>
862
863 <para>Here, we take this button, and make it do something useful. We attach
864 a signal handler to it so when it emits the "clicked" signal, our
865 hello() function is called. The data is ignored, so we simply pass in
866 NULL to the hello() callback function. Obviously, the "clicked" signal
867 is emitted when we click the button with our mouse pointer.</para>
868
869 <programlisting role="C">
870     g_signal_connect (G_OBJECT (button), "clicked",
871                       G_CALLBACK (hello), NULL);
872 </programlisting>
873
874 <para>We are also going to use this button to exit our program. This will
875 illustrate how the "destroy" signal may come from either the window
876 manager, or our program. When the button is "clicked", same as above,
877 it calls the first hello() callback function, and then this one in the
878 order they are set up. You may have as many callback functions as you
879 need, and all will be executed in the order you connected
880 them. Because the gtk_widget_destroy() function accepts only a
881 GtkWidget *widget as an argument, we use the g_signal_connect_swapped() 
882 function here instead of straight g_signal_connect().</para>
883
884 <programlisting role="C">
885     g_signal_connect_swapped (G_OBJECT (button), "clicked",
886                               G_CALLBACK (gtk_widget_destroy),
887                               G_OBJECT (window));
888 </programlisting>
889
890 <para>This is a packing call, which will be explained in depth later on in
891 <link linkend="ch-PackingWidgets">Packing Widgets</link>. But it is
892 fairly easy to understand. It simply tells GTK that the button is to
893 be placed in the window where it will be displayed. Note that a GTK
894 container can only contain one widget. There are other widgets, that
895 are described later, which are designed to layout multiple widgets in
896 various ways.
897  </para>
898
899 <programlisting role="C">
900     gtk_container_add (GTK_CONTAINER (window), button);
901 </programlisting>
902
903 <para>Now we have everything set up the way we want it to be. With all the
904 signal handlers in place, and the button placed in the window where it
905 should be, we ask GTK to "show" the widgets on the screen. The window
906 widget is shown last so the whole window will pop up at once rather
907 than seeing the window pop up, and then the button form inside of
908 it. Although with such a simple example, you'd never notice.</para>
909
910 <programlisting role="C">
911     gtk_widget_show (button);
912
913     gtk_widget_show (window);
914 </programlisting>
915
916 <para>And of course, we call gtk_main() which waits for events to come from
917 the X server and will call on the widgets to emit signals when these
918 events come.</para>
919
920 <programlisting role="C">
921     gtk_main ();
922 </programlisting>
923
924 <para>And the final return. Control returns here after gtk_main_quit() is called.</para>
925
926 <programlisting role="C">
927     return 0;
928 </programlisting>
929
930 <para>Now, when we click the mouse button on a GTK button, the widget emits
931 a "clicked" signal. In order for us to use this information, our
932 program sets up a signal handler to catch that signal, which
933 dispatches the function of our choice. In our example, when the button
934 we created is "clicked", the hello() function is called with a NULL
935 argument, and then the next handler for this signal is called. This
936 calls the gtk_widget_destroy() function, passing it the window widget
937 as its argument, destroying the window widget. This causes the window
938 to emit the "destroy" signal, which is caught, and calls our destroy()
939 callback function, which simply exits GTK.</para>
940
941 <para>Another course of events is to use the window manager to kill the
942 window, which will cause the "delete_event" to be emitted. This will
943 call our "delete_event" handler. If we return TRUE here, the window
944 will be left as is and nothing will happen. Returning FALSE will cause
945 GTK to emit the "destroy" signal which of course calls the "destroy"
946 callback, exiting GTK.</para>
947
948 </sect1>
949 </chapter>
950
951 <!-- ***************************************************************** -->
952 <chapter id="ch-MovingOn">
953 <title>Moving On</title>
954
955 <!-- ----------------------------------------------------------------- -->
956 <sect1 id="sec-DataTypes">
957 <title>Data Types</title>
958
959 <para>There are a few things you probably noticed in the previous examples
960 that need explaining. The gint, gchar, etc. that you see are typedefs
961 to int and char, respectively, that are part of the GLib system. This
962 is done to get around that nasty dependency on the size of simple data
963 types when doing calculations.</para>
964
965 <para>A good example is "gint32" which will be typedef'd to a 32 bit integer
966 for any given platform, whether it be the 64 bit alpha, or the 32 bit
967 i386. The typedefs are very straightforward and intuitive. They are
968 all defined in <filename>glib/glib.h</filename> (which gets included from 
969 <filename>gtk.h</filename>).</para>
970
971 <para>You'll also notice GTK's ability to use GtkWidget when the function
972 calls for a GtkObject. GTK is an object oriented design, and a widget
973 is an object.</para>
974
975 </sect1>
976
977 <!-- ----------------------------------------------------------------- -->
978 <sect1 id="sec-MoreOnSignalHandlers">
979 <title>More on Signal Handlers</title>
980
981 <para>Lets take another look at the g_signal_connect() declaration.</para>
982
983 <programlisting role="C">
984 gulong g_signal_connect( gpointer object,
985                          const gchar *name,
986                          GCallback func,
987                          gpointer func_data );
988 </programlisting>
989
990 <para>Notice the gulong return value? This is a tag that identifies your
991 callback function. As stated above, you may have as many callbacks per
992 signal and per object as you need, and each will be executed in turn,
993 in the order they were attached.</para>
994
995 <para>This tag allows you to remove this callback from the list by using:</para>
996
997 <programlisting role="C">
998 void g_signal_handler_disconnect( gpointer object,
999                                   gulong   id );
1000 </programlisting>
1001
1002 <para>So, by passing in the widget you wish to remove the handler from, and
1003 the tag returned by one of the signal_connect functions, you can
1004 disconnect a signal handler.</para>
1005
1006 <para>You can also temporarily disable signal handlers with the
1007 g_signal_handler_block() and g_signal_handler_unblock() family of
1008 functions.</para>
1009
1010 <programlisting role="C">
1011 void g_signal_handler_block( gpointer object,
1012                              gulong   id );
1013
1014 void g_signal_handlers_block_by_func( gpointer  object,
1015                                       GCallback func,
1016                                       gpointer  data );
1017
1018 void g_signal_handler_unblock( gpointer object,
1019                                gulong   id );
1020
1021 void g_signal_handlers_unblock_by_func( gpointer  object,
1022                                         GCallback func,
1023                                         gpointer  data );
1024 </programlisting>
1025
1026 </sect1>
1027
1028 <!-- ----------------------------------------------------------------- -->
1029 <sect1 id="sec-AnUpgradedHelloWorld">
1030 <title>An Upgraded Hello World</title>
1031
1032 <para>Let's take a look at a slightly improved <emphasis>helloworld</emphasis> with
1033 better examples of callbacks. This will also introduce us to our next
1034 topic, packing widgets.</para>
1035
1036 <para>
1037 <inlinemediaobject>
1038 <imageobject>
1039 <imagedata fileref="images/helloworld2.png" format="png">
1040 </imageobject>
1041 </inlinemediaobject>
1042 </para>
1043
1044 <programlisting role="C">
1045 <!-- example-start helloworld2 helloworld2.c -->
1046
1047 #include &lt;gtk/gtk.h&gt;
1048
1049 /* Our new improved callback.  The data passed to this function
1050  * is printed to stdout. */
1051 static void callback( GtkWidget *widget,
1052                       gpointer   data )
1053 {
1054     g_print ("Hello again - %s was pressed\n", (gchar *) data);
1055 }
1056
1057 /* another callback */
1058 static gboolean delete_event( GtkWidget *widget,
1059                               GdkEvent  *event,
1060                               gpointer   data )
1061 {
1062     gtk_main_quit ();
1063     return FALSE;
1064 }
1065
1066 int main( int   argc,
1067           char *argv[] )
1068 {
1069     /* GtkWidget is the storage type for widgets */
1070     GtkWidget *window;
1071     GtkWidget *button;
1072     GtkWidget *box1;
1073
1074     /* This is called in all GTK applications. Arguments are parsed
1075      * from the command line and are returned to the application. */
1076     gtk_init (&amp;argc, &amp;argv);
1077
1078     /* Create a new window */
1079     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1080
1081     /* This is a new call, which just sets the title of our
1082      * new window to "Hello Buttons!" */
1083     gtk_window_set_title (GTK_WINDOW (window), "Hello Buttons!");
1084
1085     /* Here we just set a handler for delete_event that immediately
1086      * exits GTK. */
1087     g_signal_connect (G_OBJECT (window), "delete_event",
1088                       G_CALLBACK (delete_event), NULL);
1089
1090     /* Sets the border width of the window. */
1091     gtk_container_set_border_width (GTK_CONTAINER (window), 10);
1092
1093     /* We create a box to pack widgets into.  This is described in detail
1094      * in the "packing" section. The box is not really visible, it
1095      * is just used as a tool to arrange widgets. */
1096     box1 = gtk_hbox_new (FALSE, 0);
1097
1098     /* Put the box into the main window. */
1099     gtk_container_add (GTK_CONTAINER (window), box1);
1100
1101     /* Creates a new button with the label "Button 1". */
1102     button = gtk_button_new_with_label ("Button 1");
1103     
1104     /* Now when the button is clicked, we call the "callback" function
1105      * with a pointer to "button 1" as its argument */
1106     g_signal_connect (G_OBJECT (button), "clicked",
1107                       G_CALLBACK (callback), (gpointer) "button 1");
1108
1109     /* Instead of gtk_container_add, we pack this button into the invisible
1110      * box, which has been packed into the window. */
1111     gtk_box_pack_start (GTK_BOX(box1), button, TRUE, TRUE, 0);
1112
1113     /* Always remember this step, this tells GTK that our preparation for
1114      * this button is complete, and it can now be displayed. */
1115     gtk_widget_show (button);
1116
1117     /* Do these same steps again to create a second button */
1118     button = gtk_button_new_with_label ("Button 2");
1119
1120     /* Call the same callback function with a different argument,
1121      * passing a pointer to "button 2" instead. */
1122     g_signal_connect (G_OBJECT (button), "clicked",
1123                       G_CALLBACK (callback), (gpointer) "button 2");
1124
1125     gtk_box_pack_start(GTK_BOX (box1), button, TRUE, TRUE, 0);
1126
1127     /* The order in which we show the buttons is not really important, but I
1128      * recommend showing the window last, so it all pops up at once. */
1129     gtk_widget_show (button);
1130
1131     gtk_widget_show (box1);
1132
1133     gtk_widget_show (window);
1134     
1135     /* Rest in gtk_main and wait for the fun to begin! */
1136     gtk_main ();
1137
1138     return 0;
1139 }
1140 <!-- example-end -->
1141 </programlisting>
1142
1143 <para>Compile this program using the same linking arguments as our first
1144 example.  You'll notice this time there is no easy way to exit the
1145 program, you have to use your window manager or command line to kill
1146 it. A good exercise for the reader would be to insert a third "Quit"
1147 button that will exit the program. You may also wish to play with the
1148 options to gtk_box_pack_start() while reading the next section.  Try
1149 resizing the window, and observe the behavior.</para>
1150
1151 </sect1>
1152 </chapter>
1153
1154 <!-- ***************************************************************** -->
1155 <chapter id="ch-PackingWidgets">
1156 <title>Packing Widgets</title>
1157
1158 <para>When creating an application, you'll want to put more than one widget
1159 inside a window. Our first <emphasis>helloworld</emphasis> example only used one
1160 widget so we could simply use a gtk_container_add() call to "pack" the
1161 widget into the window. But when you want to put more than one widget
1162 into a window, how do you control where that widget is positioned?
1163 This is where packing comes in.</para>
1164
1165 <!-- ----------------------------------------------------------------- -->
1166 <sect1 id="sec-TheoryOfPackingBoxes">
1167 <title>Theory of Packing Boxes</title>
1168
1169 <para>Most packing is done by creating boxes. These
1170 are invisible widget containers that we can pack our widgets into
1171 which come in two forms, a horizontal box, and a vertical box. When
1172 packing widgets into a horizontal box, the objects are inserted
1173 horizontally from left to right or right to left depending on the call
1174 used. In a vertical box, widgets are packed from top to bottom or vice
1175 versa. You may use any combination of boxes inside or beside other
1176 boxes to create the desired effect.</para>
1177
1178 <para>To create a new horizontal box, we use a call to gtk_hbox_new(), and
1179 for vertical boxes, gtk_vbox_new(). The gtk_box_pack_start() and
1180 gtk_box_pack_end() functions are used to place objects inside of these
1181 containers. The gtk_box_pack_start() function will start at the top
1182 and work its way down in a vbox, and pack left to right in an hbox.
1183 gtk_box_pack_end() will do the opposite, packing from bottom to top in
1184 a vbox, and right to left in an hbox. Using these functions allows us
1185 to right justify or left justify our widgets and may be mixed in any
1186 way to achieve the desired effect. We will use gtk_box_pack_start() in
1187 most of our examples. An object may be another container or a
1188 widget. In fact, many widgets are actually containers themselves,
1189 including the button, but we usually only use a label inside a button.</para>
1190
1191 <para>By using these calls, GTK knows where you want to place your widgets
1192 so it can do automatic resizing and other nifty things. There are also
1193 a number of options as to how your widgets should be packed. As you
1194 can imagine, this method gives us a quite a bit of flexibility when
1195 placing and creating widgets.</para>
1196
1197 </sect1>
1198
1199 <!-- ----------------------------------------------------------------- -->
1200 <sect1 id="sec-DetailsOfBoxes">
1201 <title>Details of Boxes</title>
1202
1203 <para>Because of this flexibility, packing boxes in GTK can be confusing at
1204 first. There are a lot of options, and it's not immediately obvious how
1205 they all fit together. In the end, however, there are basically five
1206 different styles.</para>
1207
1208 <para>
1209 <inlinemediaobject>
1210 <imageobject>
1211 <imagedata fileref="images/packbox1.png" format="png">
1212 </imageobject>
1213 </inlinemediaobject>
1214 </para>
1215
1216 <para>Each line contains one horizontal box (hbox) with several buttons. The
1217 call to gtk_box_pack is shorthand for the call to pack each of the
1218 buttons into the hbox. Each of the buttons is packed into the hbox the
1219 same way (i.e., same arguments to the gtk_box_pack_start() function).</para>
1220
1221 <para>This is the declaration of the gtk_box_pack_start() function.</para>
1222
1223 <programlisting role="C">
1224 void gtk_box_pack_start( GtkBox    *box,
1225                          GtkWidget *child,
1226                          gboolean   expand,
1227                          gboolean   fill,
1228                          guint      padding );
1229 </programlisting>
1230
1231 <para>The first argument is the box you are packing the object into, the
1232 second is the object. The objects will all be buttons for now, so
1233 we'll be packing buttons into boxes.</para>
1234
1235 <para>The expand argument to gtk_box_pack_start() and gtk_box_pack_end()
1236 controls whether the widgets are laid out in the box to fill in all
1237 the extra space in the box so the box is expanded to fill the area
1238 allotted to it (TRUE); or the box is shrunk to just fit the widgets
1239 (FALSE). Setting expand to FALSE will allow you to do right and left
1240 justification of your widgets.  Otherwise, they will all expand to fit
1241 into the box, and the same effect could be achieved by using only one
1242 of gtk_box_pack_start() or gtk_box_pack_end().</para>
1243
1244 <para>The fill argument to the gtk_box_pack functions control whether the
1245 extra space is allocated to the objects themselves (TRUE), or as extra
1246 padding in the box around these objects (FALSE). It only has an effect
1247 if the expand argument is also TRUE.</para>
1248
1249 <para>When creating a new box, the function looks like this:</para>
1250
1251 <programlisting role="C">
1252 GtkWidget *gtk_hbox_new ( gboolean homogeneous,
1253                           gint     spacing );
1254 </programlisting>
1255
1256 <para>The homogeneous argument to gtk_hbox_new() (and the same for
1257 gtk_vbox_new()) controls whether each object in the box has the same
1258 size (i.e., the same width in an hbox, or the same height in a
1259 vbox). If it is set, the gtk_box_pack() routines function essentially
1260 as if the <literal>expand</literal> argument was always turned on.</para>
1261
1262 <para>What's the difference between spacing (set when the box is created)
1263 and padding (set when elements are packed)? Spacing is added between
1264 objects, and padding is added on either side of an object. The
1265 following figure should make it clearer:</para>
1266
1267 <para>
1268 <inlinemediaobject>
1269 <imageobject>
1270 <imagedata fileref="images/packbox2.png" format="png">
1271 </imageobject>
1272 </inlinemediaobject>
1273 </para>
1274
1275 <para>Here is the code used to create the above images. I've commented it
1276 fairly heavily so I hope you won't have any problems following
1277 it. Compile it yourself and play with it.</para>
1278
1279 </sect1>
1280
1281 <!-- ----------------------------------------------------------------- -->
1282 <sect1 id="sec-PackingDemonstrationProgram">
1283 <title>Packing Demonstration Program</title>
1284
1285 <programlisting role="C">
1286 /* example-start packbox packbox.c */
1287
1288 #include &lt;stdio.h&gt;
1289 #include &lt;stdlib.h&gt;
1290 #include "gtk/gtk.h"
1291
1292 static gboolean delete_event( GtkWidget *widget,
1293                               GdkEvent  *event,
1294                               gpointer   data )
1295 {
1296     gtk_main_quit ();
1297     return FALSE;
1298 }
1299
1300 /* Make a new hbox filled with button-labels. Arguments for the 
1301  * variables we're interested are passed in to this function. 
1302  * We do not show the box, but do show everything inside. */
1303 static GtkWidget *make_box( gboolean homogeneous,
1304                             gint     spacing,
1305                             gboolean expand,
1306                             gboolean fill,
1307                             guint    padding ) 
1308 {
1309     GtkWidget *box;
1310     GtkWidget *button;
1311     char padstr[80];
1312     
1313     /* Create a new hbox with the appropriate homogeneous
1314      * and spacing settings */
1315     box = gtk_hbox_new (homogeneous, spacing);
1316     
1317     /* Create a series of buttons with the appropriate settings */
1318     button = gtk_button_new_with_label ("gtk_box_pack");
1319     gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
1320     gtk_widget_show (button);
1321     
1322     button = gtk_button_new_with_label ("(box,");
1323     gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
1324     gtk_widget_show (button);
1325     
1326     button = gtk_button_new_with_label ("button,");
1327     gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
1328     gtk_widget_show (button);
1329     
1330     /* Create a button with the label depending on the value of
1331      * expand. */
1332     if (expand == TRUE)
1333             button = gtk_button_new_with_label ("TRUE,");
1334     else
1335             button = gtk_button_new_with_label ("FALSE,");
1336     
1337     gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
1338     gtk_widget_show (button);
1339     
1340     /* This is the same as the button creation for "expand"
1341      * above, but uses the shorthand form. */
1342     button = gtk_button_new_with_label (fill ? "TRUE," : "FALSE,");
1343     gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
1344     gtk_widget_show (button);
1345     
1346     sprintf (padstr, "%d);", padding);
1347     
1348     button = gtk_button_new_with_label (padstr);
1349     gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
1350     gtk_widget_show (button);
1351     
1352     return box;
1353 }
1354
1355 int main( int   argc,
1356           char *argv[]) 
1357 {
1358     GtkWidget *window;
1359     GtkWidget *button;
1360     GtkWidget *box1;
1361     GtkWidget *box2;
1362     GtkWidget *separator;
1363     GtkWidget *label;
1364     GtkWidget *quitbox;
1365     int which;
1366     
1367     /* Our init, don't forget this! :) */
1368     gtk_init (&amp;argc, &amp;argv);
1369     
1370     if (argc != 2) {
1371         fprintf (stderr, "usage: packbox num, where num is 1, 2, or 3.\n");
1372         /* This just does cleanup in GTK and exits with an exit status of 1. */
1373         exit (1);
1374     }
1375     
1376     which = atoi (argv[1]);
1377
1378     /* Create our window */
1379     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1380
1381     /* You should always remember to connect the delete_event signal
1382      * to the main window. This is very important for proper intuitive
1383      * behavior */
1384     g_signal_connect (G_OBJECT (window), "delete_event",
1385                       G_CALLBACK (delete_event), NULL);
1386     gtk_container_set_border_width (GTK_CONTAINER (window), 10);
1387     
1388     /* We create a vertical box (vbox) to pack the horizontal boxes into.
1389      * This allows us to stack the horizontal boxes filled with buttons one
1390      * on top of the other in this vbox. */
1391     box1 = gtk_vbox_new (FALSE, 0);
1392     
1393     /* which example to show. These correspond to the pictures above. */
1394     switch (which) {
1395     case 1:
1396         /* create a new label. */
1397         label = gtk_label_new ("gtk_hbox_new (FALSE, 0);");
1398         
1399         /* Align the label to the left side.  We'll discuss this function and 
1400          * others in the section on Widget Attributes. */
1401         gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
1402
1403         /* Pack the label into the vertical box (vbox box1).  Remember that 
1404          * widgets added to a vbox will be packed one on top of the other in
1405          * order. */
1406         gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
1407         
1408         /* Show the label */
1409         gtk_widget_show (label);
1410         
1411         /* Call our make box function - homogeneous = FALSE, spacing = 0,
1412          * expand = FALSE, fill = FALSE, padding = 0 */
1413         box2 = make_box (FALSE, 0, FALSE, FALSE, 0);
1414         gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1415         gtk_widget_show (box2);
1416
1417         /* Call our make box function - homogeneous = FALSE, spacing = 0,
1418          * expand = TRUE, fill = FALSE, padding = 0 */
1419         box2 = make_box (FALSE, 0, TRUE, FALSE, 0);
1420         gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1421         gtk_widget_show (box2);
1422         
1423         /* Args are: homogeneous, spacing, expand, fill, padding */
1424         box2 = make_box (FALSE, 0, TRUE, TRUE, 0);
1425         gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1426         gtk_widget_show (box2);
1427         
1428         /* Creates a separator, we'll learn more about these later, 
1429          * but they are quite simple. */
1430         separator = gtk_hseparator_new ();
1431         
1432         /* Pack the separator into the vbox. Remember each of these
1433          * widgets is being packed into a vbox, so they'll be stacked
1434          * vertically. */
1435         gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1436         gtk_widget_show (separator);
1437         
1438         /* Create another new label, and show it. */
1439         label = gtk_label_new ("gtk_hbox_new (TRUE, 0);");
1440         gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
1441         gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
1442         gtk_widget_show (label);
1443         
1444         /* Args are: homogeneous, spacing, expand, fill, padding */
1445         box2 = make_box (TRUE, 0, TRUE, FALSE, 0);
1446         gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1447         gtk_widget_show (box2);
1448         
1449         /* Args are: homogeneous, spacing, expand, fill, padding */
1450         box2 = make_box (TRUE, 0, TRUE, TRUE, 0);
1451         gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1452         gtk_widget_show (box2);
1453         
1454         /* Another new separator. */
1455         separator = gtk_hseparator_new ();
1456         /* The last 3 arguments to gtk_box_pack_start are:
1457          * expand, fill, padding. */
1458         gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1459         gtk_widget_show (separator);
1460         
1461         break;
1462
1463     case 2:
1464
1465         /* Create a new label, remember box1 is a vbox as created 
1466          * near the beginning of main() */
1467         label = gtk_label_new ("gtk_hbox_new (FALSE, 10);");
1468         gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
1469         gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
1470         gtk_widget_show (label);
1471         
1472         /* Args are: homogeneous, spacing, expand, fill, padding */
1473         box2 = make_box (FALSE, 10, TRUE, FALSE, 0);
1474         gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1475         gtk_widget_show (box2);
1476         
1477         /* Args are: homogeneous, spacing, expand, fill, padding */
1478         box2 = make_box (FALSE, 10, TRUE, TRUE, 0);
1479         gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1480         gtk_widget_show (box2);
1481         
1482         separator = gtk_hseparator_new ();
1483         /* The last 3 arguments to gtk_box_pack_start are:
1484          * expand, fill, padding. */
1485         gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1486         gtk_widget_show (separator);
1487         
1488         label = gtk_label_new ("gtk_hbox_new (FALSE, 0);");
1489         gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
1490         gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
1491         gtk_widget_show (label);
1492         
1493         /* Args are: homogeneous, spacing, expand, fill, padding */
1494         box2 = make_box (FALSE, 0, TRUE, FALSE, 10);
1495         gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1496         gtk_widget_show (box2);
1497         
1498         /* Args are: homogeneous, spacing, expand, fill, padding */
1499         box2 = make_box (FALSE, 0, TRUE, TRUE, 10);
1500         gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1501         gtk_widget_show (box2);
1502         
1503         separator = gtk_hseparator_new ();
1504         /* The last 3 arguments to gtk_box_pack_start are: expand, fill, padding. */
1505         gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1506         gtk_widget_show (separator);
1507         break;
1508     
1509     case 3:
1510
1511         /* This demonstrates the ability to use gtk_box_pack_end() to
1512          * right justify widgets. First, we create a new box as before. */
1513         box2 = make_box (FALSE, 0, FALSE, FALSE, 0);
1514
1515         /* Create the label that will be put at the end. */
1516         label = gtk_label_new ("end");
1517         /* Pack it using gtk_box_pack_end(), so it is put on the right
1518          * side of the hbox created in the make_box() call. */
1519         gtk_box_pack_end (GTK_BOX (box2), label, FALSE, FALSE, 0);
1520         /* Show the label. */
1521         gtk_widget_show (label);
1522         
1523         /* Pack box2 into box1 (the vbox remember ? :) */
1524         gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
1525         gtk_widget_show (box2);
1526         
1527         /* A separator for the bottom. */
1528         separator = gtk_hseparator_new ();
1529         /* This explicitly sets the separator to 400 pixels wide by 5 pixels
1530          * high. This is so the hbox we created will also be 400 pixels wide,
1531          * and the "end" label will be separated from the other labels in the
1532          * hbox. Otherwise, all the widgets in the hbox would be packed as
1533          * close together as possible. */
1534         gtk_widget_set_size_request (separator, 400, 5);
1535         /* pack the separator into the vbox (box1) created near the start 
1536          * of main() */
1537         gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
1538         gtk_widget_show (separator);    
1539     }
1540     
1541     /* Create another new hbox.. remember we can use as many as we need! */
1542     quitbox = gtk_hbox_new (FALSE, 0);
1543     
1544     /* Our quit button. */
1545     button = gtk_button_new_with_label ("Quit");
1546     
1547     /* Setup the signal to terminate the program when the button is clicked */
1548     g_signal_connect_swapped (G_OBJECT (button), "clicked",
1549                               G_CALLBACK (gtk_main_quit),
1550                               G_OBJECT (window));
1551     /* Pack the button into the quitbox.
1552      * The last 3 arguments to gtk_box_pack_start are:
1553      * expand, fill, padding. */
1554     gtk_box_pack_start (GTK_BOX (quitbox), button, TRUE, FALSE, 0);
1555     /* pack the quitbox into the vbox (box1) */
1556     gtk_box_pack_start (GTK_BOX (box1), quitbox, FALSE, FALSE, 0);
1557     
1558     /* Pack the vbox (box1) which now contains all our widgets, into the
1559      * main window. */
1560     gtk_container_add (GTK_CONTAINER (window), box1);
1561     
1562     /* And show everything left */
1563     gtk_widget_show (button);
1564     gtk_widget_show (quitbox);
1565     
1566     gtk_widget_show (box1);
1567     /* Showing the window last so everything pops up at once. */
1568     gtk_widget_show (window);
1569     
1570     /* And of course, our main function. */
1571     gtk_main ();
1572
1573     /* Control returns here when gtk_main_quit() is called, but not when 
1574      * exit() is used. */
1575     
1576     return 0;
1577 }
1578 <!-- example-end -->
1579 </programlisting>
1580
1581 </sect1>
1582
1583 <!-- ----------------------------------------------------------------- -->
1584 <sect1 id="sec-PackingUsingTables">
1585 <title>Packing Using Tables</title>
1586
1587 <para>Let's take a look at another way of packing - Tables. These can be
1588 extremely useful in certain situations.</para>
1589
1590 <para>Using tables, we create a grid that we can place widgets in. The
1591 widgets may take up as many spaces as we specify.</para>
1592
1593 <para>The first thing to look at, of course, is the gtk_table_new() function:</para>
1594
1595 <programlisting role="C">
1596 GtkWidget *gtk_table_new( guint    rows,
1597                           guint    columns,
1598                           gboolean homogeneous );
1599 </programlisting>
1600
1601 <para>The first argument is the number of rows to make in the table, while
1602 the second, obviously, is the number of columns.</para>
1603
1604 <para>The homogeneous argument has to do with how the table's boxes are
1605 sized. If homogeneous is TRUE, the table boxes are resized to the size
1606 of the largest widget in the table. If homogeneous is FALSE, the size
1607 of a table boxes is dictated by the tallest widget in its same row,
1608 and the widest widget in its column.</para>
1609
1610 <para>The rows and columns are laid out from 0 to n, where n was the number
1611 specified in the call to gtk_table_new. So, if you specify rows = 2
1612 and columns = 2, the layout would look something like this:</para>
1613
1614 <programlisting role="C">
1615  0          1          2
1616 0+----------+----------+
1617  |          |          |
1618 1+----------+----------+
1619  |          |          |
1620 2+----------+----------+
1621 </programlisting>
1622
1623 <para>Note that the coordinate system starts in the upper left hand corner.
1624 To place a widget into a box, use the following function:</para>
1625
1626 <programlisting role="C">
1627 void gtk_table_attach( GtkTable         *table,
1628                        GtkWidget        *child,
1629                        guint            left_attach,
1630                        guint            right_attach,
1631                        guint            top_attach,
1632                        guint            bottom_attach,
1633                        GtkAttachOptions xoptions,
1634                        GtkAttachOptions yoptions,
1635                        guint            xpadding,
1636                        guint            ypadding );
1637 </programlisting>
1638
1639 <para>The first argument ("table") is the table you've created and the
1640 second ("child") the widget you wish to place in the table.</para>
1641
1642 <para>The left and right attach arguments specify where to place the widget,
1643 and how many boxes to use. If you want a button in the lower right
1644 table entry of our 2x2 table, and want it to fill that entry <emphasis>only</emphasis>,
1645 left_attach would be = 1, right_attach = 2, top_attach = 1,
1646 bottom_attach = 2.</para>
1647
1648 <para>Now, if you wanted a widget to take up the whole top row of our 2x2
1649 table, you'd use left_attach = 0, right_attach = 2, top_attach = 0,
1650 bottom_attach = 1.</para>
1651
1652 <para>The xoptions and yoptions are used to specify packing options and may
1653 be bitwise OR'ed together to allow multiple options.</para>
1654
1655 <para>These options are:</para>
1656
1657 <variablelist>
1658 <varlistentry>
1659 <term><literal>GTK_FILL</literal></term>
1660 <listitem><para>If the table box is larger than the widget, and
1661 <literal>GTK_FILL</literal> is specified, the widget will expand to use all the room
1662 available.</para>
1663 </listitem>
1664 </varlistentry>
1665
1666 <varlistentry>
1667 <term><literal>GTK_SHRINK</literal></term>
1668 <listitem><para>If the table widget was allocated less space
1669 then was requested (usually by the user resizing the window), then the
1670 widgets would normally just be pushed off the bottom of the window and
1671 disappear. If <literal>GTK_SHRINK</literal> is specified, the widgets will shrink
1672 with the table.</para>
1673 </listitem>
1674 </varlistentry>
1675
1676 <varlistentry>
1677 <term><literal>GTK_EXPAND</literal></term>
1678 <listitem><para>This will cause the table to expand to use up
1679 any remaining space in the window.</para>
1680 </listitem>
1681 </varlistentry>
1682 </variablelist>
1683
1684 <para>Padding is just like in boxes, creating a clear area around the widget
1685 specified in pixels.</para>
1686
1687 <para>gtk_table_attach() has a <emphasis>lot</emphasis> of options.  
1688 So, there's a shortcut:</para>
1689
1690 <programlisting role="C">
1691 void gtk_table_attach_defaults( GtkTable  *table,
1692                                 GtkWidget *widget,
1693                                 guint      left_attach,
1694                                 guint      right_attach,
1695                                 guint      top_attach,
1696                                 guint      bottom_attach );
1697 </programlisting>
1698
1699 <para>The X and Y options default to <literal>GTK_FILL | GTK_EXPAND</literal>, 
1700 and X and Y padding are set to 0. The rest of the arguments are identical to the
1701 previous function.</para>
1702
1703 <para>We also have gtk_table_set_row_spacing() and
1704 gtk_table_set_col_spacing(). These places spacing between the rows at
1705 the specified row or column.</para>
1706
1707 <programlisting role="C">
1708 void gtk_table_set_row_spacing( GtkTable *table,
1709                                 guint     row,
1710                                 guint     spacing );
1711 </programlisting>
1712
1713 <para>and</para>
1714
1715 <programlisting role="C">
1716 void gtk_table_set_col_spacing ( GtkTable *table,
1717                                  guint     column,
1718                                  guint     spacing );
1719 </programlisting>
1720
1721 <para>Note that for columns, the space goes to the right of the column, and
1722 for rows, the space goes below the row.</para>
1723
1724 <para>You can also set a consistent spacing of all rows and/or columns with:</para>
1725
1726 <programlisting role="C">
1727 void gtk_table_set_row_spacings( GtkTable *table,
1728                                  guint    spacing );
1729 </programlisting>
1730
1731 <para>And,</para>
1732
1733 <programlisting role="C">
1734 void gtk_table_set_col_spacings( GtkTable *table,
1735                                  guint     spacing );
1736 </programlisting>
1737
1738 <para>Note that with these calls, the last row and last column do not get
1739 any spacing.</para>
1740
1741 </sect1>
1742
1743 <!-- ----------------------------------------------------------------- -->
1744 <sect1 id="sec-TablePackingExamples">
1745 <title>Table Packing Example</title>
1746
1747 <para>Here we make a window with three buttons in a 2x2 table.
1748 The first two buttons will be placed in the upper row.
1749 A third, quit button, is placed in the lower row, spanning both columns.
1750 Which means it should look something like this:</para>
1751
1752 <para>
1753 <inlinemediaobject>
1754 <imageobject>
1755 <imagedata fileref="images/table.png" format="png">
1756 </imageobject>
1757 </inlinemediaobject>
1758 </para>
1759
1760 <para>Here's the source code:</para>
1761
1762 <programlisting role="C">
1763 <!-- example-start table table.c -->
1764
1765 #include &lt;gtk/gtk.h&gt;
1766
1767 /* Our callback.
1768  * The data passed to this function is printed to stdout */
1769 static void callback( GtkWidget *widget,
1770                       gpointer   data )
1771 {
1772     g_print ("Hello again - %s was pressed\n", (char *) data);
1773 }
1774
1775 /* This callback quits the program */
1776 static gboolean delete_event( GtkWidget *widget,
1777                               GdkEvent  *event,
1778                               gpointer   data )
1779 {
1780     gtk_main_quit ();
1781     return FALSE;
1782 }
1783
1784 int main( int   argc,
1785           char *argv[] )
1786 {
1787     GtkWidget *window;
1788     GtkWidget *button;
1789     GtkWidget *table;
1790
1791     gtk_init (&amp;argc, &amp;argv);
1792
1793     /* Create a new window */
1794     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1795
1796     /* Set the window title */
1797     gtk_window_set_title (GTK_WINDOW (window), "Table");
1798
1799     /* Set a handler for delete_event that immediately
1800      * exits GTK. */
1801     g_signal_connect (G_OBJECT (window), "delete_event",
1802                       G_CALLBACK (delete_event), NULL);
1803
1804     /* Sets the border width of the window. */
1805     gtk_container_set_border_width (GTK_CONTAINER (window), 20);
1806
1807     /* Create a 2x2 table */
1808     table = gtk_table_new (2, 2, TRUE);
1809
1810     /* Put the table in the main window */
1811     gtk_container_add (GTK_CONTAINER (window), table);
1812
1813     /* Create first button */
1814     button = gtk_button_new_with_label ("button 1");
1815
1816     /* When the button is clicked, we call the "callback" function
1817      * with a pointer to "button 1" as its argument */
1818     g_signal_connect (G_OBJECT (button), "clicked",
1819                       G_CALLBACK (callback), (gpointer) "button 1");
1820
1821
1822     /* Insert button 1 into the upper left quadrant of the table */
1823     gtk_table_attach_defaults (GTK_TABLE (table), button, 0, 1, 0, 1);
1824
1825     gtk_widget_show (button);
1826
1827     /* Create second button */
1828
1829     button = gtk_button_new_with_label ("button 2");
1830
1831     /* When the button is clicked, we call the "callback" function
1832      * with a pointer to "button 2" as its argument */
1833     g_signal_connect (G_OBJECT (button), "clicked",
1834                       G_CALLBACK (callback), (gpointer) "button 2");
1835     /* Insert button 2 into the upper right quadrant of the table */
1836     gtk_table_attach_defaults (GTK_TABLE (table), button, 1, 2, 0, 1);
1837
1838     gtk_widget_show (button);
1839
1840     /* Create "Quit" button */
1841     button = gtk_button_new_with_label ("Quit");
1842
1843     /* When the button is clicked, we call the "delete_event" function
1844      * and the program exits */
1845     g_signal_connect (G_OBJECT (button), "clicked",
1846                       G_CALLBACK (delete_event), NULL);
1847
1848     /* Insert the quit button into the both 
1849      * lower quadrants of the table */
1850     gtk_table_attach_defaults (GTK_TABLE (table), button, 0, 2, 1, 2);
1851
1852     gtk_widget_show (button);
1853
1854     gtk_widget_show (table);
1855     gtk_widget_show (window);
1856
1857     gtk_main ();
1858
1859     return 0;
1860 }
1861 <!-- example-end -->
1862 </programlisting>
1863
1864 </sect1>
1865 </chapter>
1866
1867 <!-- ***************************************************************** -->
1868 <chapter id="ch-WidgetOverview">
1869 <title>Widget Overview</title>
1870
1871 <para>The general steps to creating a widget in GTK are:</para>
1872 <orderedlist>
1873 <listitem><simpara> gtk_*_new() - one of various functions to create a new widget.
1874 These are all detailed in this section.</simpara>
1875 </listitem>
1876
1877 <listitem><simpara> Connect all signals and events we wish to use to the
1878 appropriate handlers.</simpara>
1879 </listitem>
1880
1881 <listitem><simpara> Set the attributes of the widget.</simpara>
1882 </listitem>
1883
1884 <listitem><simpara> Pack the widget into a container using the appropriate call
1885 such as gtk_container_add() or gtk_box_pack_start().</simpara>
1886 </listitem>
1887
1888 <listitem><simpara> gtk_widget_show() the widget.</simpara>
1889 </listitem>
1890 </orderedlist>
1891
1892 <para>gtk_widget_show() lets GTK know that we are done setting the
1893 attributes of the widget, and it is ready to be displayed. You may
1894 also use gtk_widget_hide to make it disappear again. The order in
1895 which you show the widgets is not important, but I suggest showing the
1896 window last so the whole window pops up at once rather than seeing the
1897 individual widgets come up on the screen as they're formed. The
1898 children of a widget (a window is a widget too) will not be displayed
1899 until the window itself is shown using the gtk_widget_show() function.</para>
1900
1901 <!-- ----------------------------------------------------------------- -->
1902 <sect1 id="sec-Casting">
1903 <title>Casting</title>
1904
1905 <para>You'll notice as you go on that GTK uses a type casting system. This
1906 is always done using macros that both test the ability to cast the
1907 given item, and perform the cast. Some common ones you will see are:</para>
1908
1909 <programlisting role="C">
1910   G_OBJECT (object)
1911   GTK_WIDGET (widget)
1912   GTK_OBJECT (object)
1913   GTK_SIGNAL_FUNC (function)
1914   GTK_CONTAINER (container)
1915   GTK_WINDOW (window)
1916   GTK_BOX (box)
1917 </programlisting>
1918
1919 <para>These are all used to cast arguments in functions. You'll see them in the
1920 examples, and can usually tell when to use them simply by looking at the
1921 function's declaration.</para>
1922
1923 <para>As you can see below in the class hierarchy, all GtkWidgets are
1924 derived from the GObject base class. This means you can use a widget
1925 in any place the function asks for an object - simply use the
1926 <literal>G_OBJECT()</literal> macro.</para>
1927
1928 <para>For example:</para>
1929
1930 <programlisting role="C">
1931 g_signal_connect( G_OBJECT (button), "clicked",
1932                   G_CALLBACK (callback_function), callback_data);
1933 </programlisting>
1934
1935 <para>This casts the button into an object, and provides a cast for the
1936 function pointer to the callback.</para>
1937
1938 <para>Many widgets are also containers. If you look in the class hierarchy
1939 below, you'll notice that many widgets derive from the Container
1940 class. Any one of these widgets may be used with the
1941 <literal>GTK_CONTAINER</literal> macro to pass them to functions that ask for
1942 containers.</para>
1943
1944 <para>Unfortunately, these macros are not extensively covered in the
1945 tutorial, but I recommend taking a look through the GTK header
1946 files or the GTK API reference manual. It can be very educational. In fact, 
1947 it's not difficult to learn how a widget works just by looking at the 
1948 function declarations.</para>
1949
1950 </sect1>
1951
1952 <!-- ----------------------------------------------------------------- -->
1953 <sect1 id="sec-WidgetHierarchy">
1954 <title>Widget Hierarchy</title>
1955
1956 <para>For your reference, here is the class hierarchy tree used to implement 
1957 widgets. (Deprecated widgets and auxiliary classes have been omitted.)</para>
1958
1959 <programlisting role="C">
1960 GObject
1961  |  
1962  GtkObject
1963   +GtkWidget
1964   | +GtkMisc
1965   | | +GtkLabel
1966   | | | `GtkAccelLabel
1967   | | +GtkArrow
1968   | | `GtkImage
1969   | +GtkContainer
1970   | | +GtkBin
1971   | | | +GtkAlignment
1972   | | | +GtkFrame
1973   | | | | `GtkAspectFrame
1974   | | | +GtkButton
1975   | | | | +GtkToggleButton
1976   | | | | | `GtkCheckButton
1977   | | | | |   `GtkRadioButton
1978   | | | | `GtkOptionMenu
1979   | | | +GtkItem
1980   | | | | +GtkMenuItem
1981   | | | |   +GtkCheckMenuItem
1982   | | | |   | `GtkRadioMenuItem
1983   | | | |   +GtkImageMenuItem
1984   | | | |   +GtkSeparatorMenuItem
1985   | | | |   `GtkTearoffMenuItem
1986   | | | +GtkWindow
1987   | | | | +GtkDialog
1988   | | | | | +GtkColorSelectionDialog
1989   | | | | | +GtkFileSelection
1990   | | | | | +GtkFontSelectionDialog
1991   | | | | | +GtkInputDialog
1992   | | | | | `GtkMessageDialog
1993   | | | | `GtkPlug
1994   | | | +GtkEventBox
1995   | | | +GtkHandleBox
1996   | | | +GtkScrolledWindow
1997   | | | `GtkViewport
1998   | | +GtkBox
1999   | | | +GtkButtonBox
2000   | | | | +GtkHButtonBox
2001   | | | | `GtkVButtonBox
2002   | | | +GtkVBox
2003   | | | | +GtkColorSelection
2004   | | | | +GtkFontSelection
2005   | | | | `GtkGammaCurve
2006   | | | `GtkHBox
2007   | | |   +GtkCombo
2008   | | |   `GtkStatusbar
2009   | | +GtkFixed
2010   | | +GtkPaned
2011   | | | +GtkHPaned
2012   | | | `GtkVPaned
2013   | | +GtkLayout
2014   | | +GtkMenuShell
2015   | | | +GtkMenuBar
2016   | | | `GtkMenu
2017   | | +GtkNotebook
2018   | | +GtkSocket
2019   | | +GtkTable
2020   | | +GtkTextView
2021   | | +GtkToolbar
2022   | | `GtkTreeView
2023   | +GtkCalendar
2024   | +GtkDrawingArea
2025   | | `GtkCurve
2026   | +GtkEditable
2027   | | +GtkEntry
2028   | |   `GtkSpinButton
2029   | +GtkRuler
2030   | | +GtkHRuler
2031   | | `GtkVRuler
2032   | +GtkRange
2033   | | +GtkScale
2034   | | | +GtkHScale
2035   | | | `GtkVScale
2036   | | `GtkScrollbar
2037   | |   +GtkHScrollbar
2038   | |   `GtkVScrollbar
2039   | +GtkSeparator
2040   | | +GtkHSeparator
2041   | | `GtkVSeparator
2042   | +GtkInvisible
2043   | +GtkPreview
2044   | `GtkProgressBar
2045   +GtkAdjustment
2046   +GtkCellRenderer
2047   | +GtkCellRendererPixbuf
2048   | +GtkCellRendererText
2049   | +GtkCellRendererToggle
2050   +GtkItemFactory
2051   +GtkTooltips
2052   `GtkTreeViewColumn
2053 </programlisting>
2054
2055 </sect1>
2056
2057 <!-- ----------------------------------------------------------------- -->
2058 <sect1 id="sec-WidgetsWithoutWindows">
2059 <title>Widgets Without Windows</title>
2060
2061 <para>The following widgets do not have an associated window. If you want to
2062 capture events, you'll have to use the EventBox. See the section on
2063 the <link linkend="sec-EventBox">EventBox</link> widget.</para>
2064
2065 <programlisting role="C">
2066 GtkAlignment
2067 GtkArrow
2068 GtkBin
2069 GtkBox
2070 GtkButton
2071 GtkCheckButton
2072 GtkFixed
2073 GtkImage
2074 GtkLabel
2075 GtkMenuItem
2076 GtkNotebook
2077 GtkPaned
2078 GtkRadioButton
2079 GtkRange
2080 GtkScrolledWindow
2081 GtkSeparator
2082 GtkTable
2083 GtkToolbar
2084 GtkAspectFrame
2085 GtkFrame
2086 GtkVBox
2087 GtkHBox
2088 GtkVSeparator
2089 GtkHSeparator
2090 </programlisting>
2091
2092 <para>We'll further our exploration of GTK by examining each widget in turn,
2093 creating a few simple functions to display them. Another good source
2094 is the <literal>testgtk</literal> program that comes with GTK. It can be found in
2095 <filename>tests/testgtk.c</filename>.</para>
2096
2097 </sect1>
2098 </chapter>
2099
2100 <!-- ***************************************************************** -->
2101 <chapter id="ch-ButtonWidget">
2102 <title>The Button Widget</title>
2103
2104 <!-- ----------------------------------------------------------------- -->
2105 <sect1 id="sec-NormalButtons">
2106 <title>Normal Buttons</title>
2107
2108 <para>We've almost seen all there is to see of the button widget. It's
2109 pretty simple. There is however more than one way to create a button. You can
2110 use the gtk_button_new_with_label() or gtk_button_new_with_mnemonic() to create 
2111 a button with a label, use gtk_button_new_from_stock() to create a button
2112 containing the image and text from a stock item or use gtk_button_new() to
2113 create a blank button. It's then up to you to pack a label or pixmap into 
2114 this new button. To do this, create a new box, and then pack your objects into 
2115 this box using the usual gtk_box_pack_start(), and then use gtk_container_add() 
2116 to pack the box into the button.</para>
2117
2118 <para>Here's an example of using gtk_button_new() to create a button with a
2119 image and a label in it. I've broken up the code to create a box from the rest 
2120 so you can use it in your programs. There are further examples of using images 
2121 later in the tutorial.</para>
2122
2123 <para>
2124 <inlinemediaobject>
2125 <imageobject>
2126 <imagedata fileref="images/buttons.png" format="png">
2127 </imageobject>
2128 </inlinemediaobject>
2129 </para>
2130
2131 <programlisting role="C">
2132 <!-- example-start buttons buttons.c -->
2133
2134 #include &lt;stdlib.h&gt;
2135 #include &lt;gtk/gtk.h&gt;
2136
2137 /* Create a new hbox with an image and a label packed into it
2138  * and return the box. */
2139
2140 static GtkWidget *xpm_label_box( gchar     *xpm_filename,
2141                                  gchar     *label_text )
2142 {
2143     GtkWidget *box;
2144     GtkWidget *label;
2145     GtkWidget *image;
2146
2147     /* Create box for image and label */
2148     box = gtk_hbox_new (FALSE, 0);
2149     gtk_container_set_border_width (GTK_CONTAINER (box), 2);
2150
2151     /* Now on to the image stuff */
2152     image = gtk_image_new_from_file (xpm_filename);
2153
2154     /* Create a label for the button */
2155     label = gtk_label_new (label_text);
2156
2157     /* Pack the image and label into the box */
2158     gtk_box_pack_start (GTK_BOX (box), image, FALSE, FALSE, 3);
2159     gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 3);
2160
2161     gtk_widget_show (image);
2162     gtk_widget_show (label);
2163
2164     return box;
2165 }
2166
2167 /* Our usual callback function */
2168 static void callback( GtkWidget *widget,
2169                       gpointer   data )
2170 {
2171     g_print ("Hello again - %s was pressed\n", (char *) data);
2172 }
2173
2174 int main( int   argc,
2175           char *argv[] )
2176 {
2177     /* GtkWidget is the storage type for widgets */
2178     GtkWidget *window;
2179     GtkWidget *button;
2180     GtkWidget *box;
2181
2182     gtk_init (&amp;argc, &amp;argv);
2183
2184     /* Create a new window */
2185     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2186
2187     gtk_window_set_title (GTK_WINDOW (window), "Pixmap'd Buttons!");
2188
2189     /* It's a good idea to do this for all windows. */
2190     g_signal_connect (G_OBJECT (window), "destroy",
2191                       G_CALLBACK (gtk_main_quit), NULL);
2192
2193     g_signal_connect (G_OBJECT (window), "delete_event",
2194                       G_CALLBACK (gtk_main_quit), NULL);
2195
2196     /* Sets the border width of the window. */
2197     gtk_container_set_border_width (GTK_CONTAINER (window), 10);
2198
2199     /* Create a new button */
2200     button = gtk_button_new ();
2201
2202     /* Connect the "clicked" signal of the button to our callback */
2203     g_signal_connect (G_OBJECT (button), "clicked",
2204                       G_CALLBACK (callback), (gpointer) "cool button");
2205
2206     /* This calls our box creating function */
2207     box = xpm_label_box ("info.xpm", "cool button");
2208
2209     /* Pack and show all our widgets */
2210     gtk_widget_show (box);
2211
2212     gtk_container_add (GTK_CONTAINER (button), box);
2213
2214     gtk_widget_show (button);
2215
2216     gtk_container_add (GTK_CONTAINER (window), button);
2217
2218     gtk_widget_show (window);
2219
2220     /* Rest in gtk_main and wait for the fun to begin! */
2221     gtk_main ();
2222
2223     return 0;
2224 }
2225 <!-- example-end -->
2226 </programlisting>
2227
2228 <para>The xpm_label_box() function could be used to pack images and labels into
2229 any widget that can be a container.</para>
2230
2231 <para>The Button widget has the following signals:</para>
2232
2233 <itemizedlist>
2234 <listitem><simpara><literal>pressed</literal> - emitted when pointer button is pressed within
2235 Button widget</simpara>
2236 </listitem>
2237 <listitem><simpara><literal>released</literal> - emitted when pointer button is released within
2238 Button widget</simpara>
2239 </listitem>
2240 <listitem><simpara><literal>clicked</literal> - emitted when pointer button is pressed and then
2241 released within Button widget</simpara>
2242 </listitem>
2243 <listitem><simpara><literal>enter</literal> - emitted when pointer enters Button widget</simpara>
2244 </listitem>
2245 <listitem><simpara><literal>leave</literal> - emitted when pointer leaves Button widget</simpara>
2246 </listitem>
2247 </itemizedlist>
2248
2249 </sect1>
2250
2251 <!-- ----------------------------------------------------------------- -->
2252 <sect1 id="sec-ToggleButtons">
2253 <title>Toggle Buttons</title>
2254
2255 <para>Toggle buttons are derived from normal buttons and are very similar,
2256 except they will always be in one of two states, alternated by a
2257 click. They may be depressed, and when you click again, they will pop
2258 back up. Click again, and they will pop back down.</para>
2259
2260 <para>Toggle buttons are the basis for check buttons and radio buttons, as
2261 such, many of the calls used for toggle buttons are inherited by radio
2262 and check buttons. I will point these out when we come to them.</para>
2263
2264 <para>Creating a new toggle button:</para>
2265
2266 <programlisting role="C">
2267 GtkWidget *gtk_toggle_button_new( void );
2268
2269 GtkWidget *gtk_toggle_button_new_with_label( const gchar *label );
2270
2271 GtkWidget *gtk_toggle_button_new_with_mnemonic( const gchar *label );
2272 </programlisting>
2273
2274 <para>As you can imagine, these work identically to the normal button widget
2275 calls. The first creates a blank toggle button, and the last two, a
2276 button with a label widget already packed into it. The _mnemonic() variant
2277 additionally parses the label for '_'-prefixed mnemonic characters.</para>
2278
2279 <para>To retrieve the state of the toggle widget, including radio and check
2280 buttons, we use a construct as shown in our example below. This tests
2281 the state of the toggle button, by accessing the <literal>active</literal> field of the
2282 toggle widget's structure, after first using the
2283 <literal>GTK_TOGGLE_BUTTON</literal> macro to cast the widget pointer into a toggle
2284 widget pointer. The signal of interest to us emitted by toggle
2285 buttons (the toggle button, check button, and radio button widgets) is
2286 the "toggled" signal. To check the state of these buttons, set up a
2287 signal handler to catch the toggled signal, and access the structure
2288 to determine its state. The callback will look something like:</para>
2289
2290 <programlisting role="C">
2291 void toggle_button_callback (GtkWidget *widget, gpointer data)
2292 {
2293     if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) 
2294     {
2295         /* If control reaches here, the toggle button is down */
2296     
2297     } else {
2298     
2299         /* If control reaches here, the toggle button is up */
2300     }
2301 }
2302 </programlisting>
2303
2304 <para>To force the state of a toggle button, and its children, the radio and
2305 check buttons, use this function:</para>
2306
2307 <programlisting role="C">
2308 void gtk_toggle_button_set_active( GtkToggleButton *toggle_button,
2309                                    gboolean        is_active );
2310 </programlisting>
2311
2312 <para>The above call can be used to set the state of the toggle button, and
2313 its children the radio and check buttons. Passing in your created
2314 button as the first argument, and a TRUE or FALSE for the second state
2315 argument to specify whether it should be down (depressed) or up
2316 (released). Default is up, or FALSE.</para>
2317
2318 <para>Note that when you use the gtk_toggle_button_set_active() function, and
2319 the state is actually changed, it causes the "clicked" and "toggled"
2320 signals to be emitted from the button.</para>
2321
2322 <programlisting role="C">
2323 gboolean gtk_toggle_button_get_active   (GtkToggleButton *toggle_button);
2324 </programlisting>
2325
2326 <para>This returns the current state of the toggle button as a boolean
2327 TRUE/FALSE value.</para>
2328
2329 </sect1>
2330
2331 <!-- ----------------------------------------------------------------- -->
2332 <sect1 id="sec-CheckButtons">
2333 <title>Check Buttons</title>
2334
2335 <para>Check buttons inherit many properties and functions from the the
2336 toggle buttons above, but look a little different. Rather than being
2337 buttons with text inside them, they are small squares with the text to
2338 the right of them. These are often used for toggling options on and
2339 off in applications.</para>
2340
2341 <para>The creation functions are similar to those of the normal button.</para>
2342
2343 <programlisting role="C">
2344 GtkWidget *gtk_check_button_new( void );
2345
2346 GtkWidget *gtk_check_button_new_with_label ( const gchar *label );
2347
2348 GtkWidget *gtk_check_button_new_with_mnemonic ( const gchar *label );
2349 </programlisting>
2350
2351 <para>The gtk_check_button_new_with_label() function creates a check button 
2352 with a label beside it.</para>
2353
2354 <para>Checking the state of the check button is identical to that of the
2355 toggle button.</para>
2356
2357 </sect1>
2358
2359 <!-- ----------------------------------------------------------------- -->
2360 <sect1 id="sec-RadioButtons">
2361 <title>Radio Buttons</title>
2362
2363 <para>Radio buttons are similar to check buttons except they are grouped so
2364 that only one may be selected/depressed at a time. This is good for
2365 places in your application where you need to select from a short list
2366 of options.</para>
2367
2368 <para>Creating a new radio button is done with one of these calls:</para>
2369
2370 <programlisting role="C">
2371 GtkWidget *gtk_radio_button_new( GSList *group );
2372
2373 GtkWidget *gtk_radio_button_new_from_widget( GtkRadioButton *group );
2374
2375 GtkWidget *gtk_radio_button_new_with_label( GSList *group,
2376                                             const gchar  *label );
2377
2378 GtkWidget* gtk_radio_button_new_with_label_from_widget( GtkRadioButton *group,
2379                                                         const gchar    *label );
2380
2381 GtkWidget *gtk_radio_button_new_with_mnemonic( GSList *group,
2382                                                const gchar  *label );
2383
2384 GtkWidget *gtk_radio_button_new_with_mnemonic_from_widget( GtkRadioButton *group,
2385                                                            const gchar  *label );
2386
2387 </programlisting>
2388
2389 <para>You'll notice the extra argument to these calls. They require a group
2390 to perform their duty properly. The first call to gtk_radio_button_new() or 
2391 gtk_radio_button_new_with_label() should pass NULL as the first argument. 
2392 Then create a group using:</para>
2393
2394 <programlisting role="C">
2395 GSList *gtk_radio_button_get_group( GtkRadioButton *radio_button );
2396 </programlisting>
2397
2398 <para>The important thing to remember is that gtk_radio_button_get_group() must be
2399 called for each new button added to the group, with the previous button passed 
2400 in as an argument. The result is then passed into the next call to 
2401 gtk_radio_button_new() or gtk_radio_button_new_with_label(). This allows a
2402 chain of buttons to be established. The example below should make this clear.</para>
2403
2404 <para>You can shorten this slightly by using the following syntax, which
2405 removes the need for a variable to hold the list of buttons:</para>
2406
2407 <programlisting role="C">
2408      button2 = gtk_radio_button_new_with_label(
2409                  gtk_radio_button_get_group (GTK_RADIO_BUTTON (button1)),
2410                  "button2");
2411 </programlisting>
2412
2413 <para>
2414 The _from_widget() variants of the creation functions allow you to shorten this
2415 further, by omitting the gtk_radio_button_get_group() call. This form is used 
2416 in the example to create the third button:
2417 </para>
2418
2419 <programlisting role="C">
2420      button2 = gtk_radio_button_new_with_label_from_widget(
2421                  GTK_RADIO_BUTTON (button1), 
2422                  "button2");
2423 </programlisting>
2424
2425 <para>It is also a good idea to explicitly set which button should be the
2426 default depressed button with:</para>
2427
2428 <programlisting role="C">
2429 void gtk_toggle_button_set_active( GtkToggleButton *toggle_button,
2430                                    gboolean        state );
2431 </programlisting>
2432
2433 <para>This is described in the section on toggle buttons, and works in
2434 exactly the same way.  Once the radio buttons are grouped together,
2435 only one of the group may be active at a time. If the user clicks on
2436 one radio button, and then on another, the first radio button will
2437 first emit a "toggled" signal (to report becoming inactive), and then
2438 the second will emit its "toggled" signal (to report becoming active).</para>
2439
2440 <para>The following example creates a radio button group with three buttons.</para>
2441
2442 <para>
2443 <inlinemediaobject>
2444 <imageobject>
2445 <imagedata fileref="images/radiobuttons.png" format="png">
2446 </imageobject>
2447 </inlinemediaobject>
2448 </para>
2449
2450 <programlisting role="C">
2451 <!-- example-start radiobuttons radiobuttons.c -->
2452
2453 #include &lt;glib.h&gt;
2454 #include &lt;gtk/gtk.h&gt;
2455
2456 static gboolean close_application( GtkWidget *widget,
2457                                    GdkEvent  *event,
2458                                    gpointer   data )
2459 {
2460   gtk_main_quit ();
2461   return FALSE;
2462 }
2463
2464 int main( int   argc,
2465           char *argv[] )
2466 {
2467     GtkWidget *window = NULL;
2468     GtkWidget *box1;
2469     GtkWidget *box2;
2470     GtkWidget *button;
2471     GtkWidget *separator;
2472     GSList *group;
2473   
2474     gtk_init (&amp;argc, &amp;argv);    
2475       
2476     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2477   
2478     g_signal_connect (G_OBJECT (window), "delete_event",
2479                       G_CALLBACK (close_application),
2480                       NULL);
2481
2482     gtk_window_set_title (GTK_WINDOW (window), "radio buttons");
2483     gtk_container_set_border_width (GTK_CONTAINER (window), 0);
2484
2485     box1 = gtk_vbox_new (FALSE, 0);
2486     gtk_container_add (GTK_CONTAINER (window), box1);
2487     gtk_widget_show (box1);
2488
2489     box2 = gtk_vbox_new (FALSE, 10);
2490     gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
2491     gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
2492     gtk_widget_show (box2);
2493
2494     button = gtk_radio_button_new_with_label (NULL, "button1");
2495     gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
2496     gtk_widget_show (button);
2497
2498     group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (button));
2499     button = gtk_radio_button_new_with_label (group, "button2");
2500     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
2501     gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
2502     gtk_widget_show (button);
2503
2504     button = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON (button),
2505                                                           "button3");
2506     gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
2507     gtk_widget_show (button);
2508
2509     separator = gtk_hseparator_new ();
2510     gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
2511     gtk_widget_show (separator);
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, FALSE, TRUE, 0);
2516     gtk_widget_show (box2);
2517
2518     button = gtk_button_new_with_label ("close");
2519     g_signal_connect_swapped (G_OBJECT (button), "clicked",
2520                               G_CALLBACK (close_application),
2521                               G_OBJECT (window));
2522     gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
2523     GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
2524     gtk_widget_grab_default (button);
2525     gtk_widget_show (button);
2526     gtk_widget_show (window);
2527      
2528     gtk_main ();
2529
2530     return 0;
2531 }
2532 <!-- example-end -->
2533 </programlisting>
2534
2535 </sect1>
2536 </chapter>
2537
2538 <!-- ***************************************************************** -->
2539 <chapter id="ch-Adjustments">
2540 <title>Adjustments</title>
2541
2542 <para>GTK has various widgets that can be visually adjusted by the user
2543 using the mouse or the keyboard, such as the range widgets, described
2544 in the <link linkend="ch-RangeWidgets">Range Widgets</link>
2545 section. There are also a few widgets that display some adjustable
2546 portion of a larger area of data, such as the text widget and the
2547 viewport widget.</para>
2548
2549 <para>Obviously, an application needs to be able to react to changes the
2550 user makes in range widgets. One way to do this would be to have each
2551 widget emit its own type of signal when its adjustment changes, and
2552 either pass the new value to the signal handler, or require it to look
2553 inside the widget's data structure in order to ascertain the value.
2554 But you may also want to connect the adjustments of several widgets
2555 together, so that adjusting one adjusts the others. The most obvious
2556 example of this is connecting a scrollbar to a panning viewport or a
2557 scrolling text area. If each widget has its own way of setting or
2558 getting the adjustment value, then the programmer may have to write
2559 their own signal handlers to translate between the output of one
2560 widget's signal and the "input" of another's adjustment setting
2561 function.</para>
2562
2563 <para>GTK solves this problem using the Adjustment object, which is not a
2564 widget but a way for widgets to store and pass adjustment information
2565 in an abstract and flexible form. The most obvious use of Adjustment
2566 is to store the configuration parameters and values of range widgets,
2567 such as scrollbars and scale controls. However, since Adjustments are
2568 derived from Object, they have some special powers beyond those of
2569 normal data structures. Most importantly, they can emit signals, just
2570 like widgets, and these signals can be used not only to allow your
2571 program to react to user input on adjustable widgets, but also to
2572 propagate adjustment values transparently between adjustable widgets.</para>
2573
2574 <para>You will see how adjustments fit in when you see the other widgets
2575 that incorporate them:
2576 <link linkend="sec-ProgressBars">Progress Bars</link>,
2577 <link linkend="sec-Viewports">Viewports</link>,
2578 <link linkend="sec-ScrolledWindows">Scrolled Windows</link>, and others.</para>
2579
2580 <!-- ----------------------------------------------------------------- -->
2581 <sect1 id="sec-CreatingAnAdjustment">
2582 <title>Creating an Adjustment</title>
2583
2584 <para>Many of the widgets which use adjustment objects do so automatically,
2585 but some cases will be shown in later examples where you may need to
2586 create one yourself. You create an adjustment using:</para>
2587
2588 <programlisting role="C">
2589 GtkObject *gtk_adjustment_new( gdouble value,
2590                                gdouble lower,
2591                                gdouble upper,
2592                                gdouble step_increment,
2593                                gdouble page_increment,
2594                                gdouble page_size );
2595 </programlisting>
2596
2597 <para>The <literal>value</literal> argument is the initial value you want to give to the
2598 adjustment, usually corresponding to the topmost or leftmost position
2599 of an adjustable widget. The <literal>lower</literal> argument specifies the lowest
2600 value which the adjustment can hold. The <literal>step_increment</literal> argument
2601 specifies the "smaller" of the two increments by which the user can
2602 change the value, while the <literal>page_increment</literal> is the "larger" one.
2603 The <literal>page_size</literal> argument usually corresponds somehow to the visible
2604 area of a panning widget. The <literal>upper</literal> argument is used to represent
2605 the bottom most or right most coordinate in a panning widget's
2606 child. Therefore it is <emphasis>not</emphasis> always the largest number that
2607 <literal>value</literal> can take, since the <literal>page_size</literal> of such widgets is
2608 usually non-zero.</para>
2609
2610 </sect1>
2611
2612 <!-- ----------------------------------------------------------------- -->
2613 <sect1 id="sec-UsingAdjustments">
2614 <title>Using Adjustments the Easy Way</title>
2615
2616 <para>The adjustable widgets can be roughly divided into those which use and
2617 require specific units for these values and those which treat them as
2618 arbitrary numbers. The group which treats the values as arbitrary
2619 numbers includes the range widgets (scrollbars and scales, the
2620 progress bar widget, and the spin button widget). These widgets are
2621 all the widgets which are typically "adjusted" directly by the user
2622 with the mouse or keyboard. They will treat the <literal>lower</literal> and
2623 <literal>upper</literal> values of an adjustment as a range within which the user
2624 can manipulate the adjustment's <literal>value</literal>. By default, they will only
2625 modify the <literal>value</literal> of an adjustment.</para>
2626
2627 <para>The other group includes the text widget, the viewport widget, the
2628 compound list widget, and the scrolled window widget. All of these
2629 widgets use pixel values for their adjustments. These are also all
2630 widgets which are typically "adjusted" indirectly using scrollbars.
2631 While all widgets which use adjustments can either create their own
2632 adjustments or use ones you supply, you'll generally want to let this
2633 particular category of widgets create its own adjustments. Usually,
2634 they will eventually override all the values except the <literal>value</literal>
2635 itself in whatever adjustments you give them, but the results are, in
2636 general, undefined (meaning, you'll have to read the source code to
2637 find out, and it may be different from widget to widget).</para>
2638
2639 <para>Now, you're probably thinking, since text widgets and viewports insist
2640 on setting everything except the <literal>value</literal> of their adjustments,
2641 while scrollbars will <emphasis>only</emphasis> touch the adjustment's 
2642 <literal>value</literal>, if you <emphasis>share</emphasis> an adjustment
2643 object between a scrollbar and a text widget, manipulating the scrollbar will 
2644 automagically adjust the viewport widget?  Of course it will! Just like this:</para>
2645
2646 <programlisting role="C">
2647   /* creates its own adjustments */
2648   viewport = gtk_viewport_new (NULL, NULL);
2649   /* uses the newly-created adjustment for the scrollbar as well */
2650   vscrollbar = gtk_vscrollbar_new (gtk_viewport_get_vadjustment (viewport));
2651 </programlisting>
2652
2653 </sect1>
2654
2655 <!-- ----------------------------------------------------------------- -->
2656 <sect1 id="sec-AdjustmentInternals">
2657 <title>Adjustment Internals</title>
2658
2659 <para>Ok, you say, that's nice, but what if I want to create my own handlers
2660 to respond when the user adjusts a range widget or a spin button, and
2661 how do I get at the value of the adjustment in these handlers?  To
2662 answer these questions and more, let's start by taking a look at
2663 <literal>struct _GtkAdjustment</literal> itself:</para>
2664
2665 <programlisting role="C">
2666 struct _GtkAdjustment
2667 {
2668   GtkObject parent_instance;
2669   
2670   gdouble lower;
2671   gdouble upper;
2672   gdouble value;
2673   gdouble step_increment;
2674   gdouble page_increment;
2675   gdouble page_size;
2676 };
2677 </programlisting>
2678
2679 <para>If you don't like to poke directly at struct internals like a 
2680 <emphasis>real</emphasis> C programmer, you can use the following accessor to
2681 inspect the <literal>value</literal> of an adjustment:</para>
2682
2683 <programlisting role="C">
2684 gdouble gtk_adjustment_get_value( GtkAdjustment *adjustment);
2685 </programlisting>
2686
2687 <para>Since, when you set the <literal>value</literal> of an Adjustment, you generally
2688 want the change to be reflected by every widget that uses this
2689 adjustment, GTK provides this convenience function to do this:</para>
2690
2691 <programlisting role="C">
2692 void gtk_adjustment_set_value( GtkAdjustment *adjustment,
2693                                gdouble       value );
2694 </programlisting>
2695
2696 <para>As mentioned earlier, Adjustment is a subclass of Object just
2697 like all the various widgets, and thus it is able to emit signals.
2698 This is, of course, why updates happen automagically when you share an
2699 adjustment object between a scrollbar and another adjustable widget;
2700 all adjustable widgets connect signal handlers to their adjustment's
2701 <literal>value_changed</literal> signal, as can your program. Here's the definition
2702 of this signal in <literal>struct _GtkAdjustmentClass</literal>:</para>
2703
2704 <programlisting role="C">
2705   void (* value_changed) (GtkAdjustment *adjustment);
2706 </programlisting>
2707
2708 <para>The various widgets that use the Adjustment object will emit this
2709 signal on an adjustment whenever they change its value. This happens
2710 both when user input causes the slider to move on a range widget, as
2711 well as when the program explicitly changes the value with
2712 gtk_adjustment_set_value(). So, for example, if you have a scale
2713 widget, and you want to change the rotation of a picture whenever its
2714 value changes, you would create a callback like this:</para>
2715
2716 <programlisting role="C">
2717 void cb_rotate_picture (GtkAdjustment *adj, GtkWidget *picture)
2718 {
2719   set_picture_rotation (picture, gtk_adjustment_get_value (adj));
2720 ...
2721 </programlisting>
2722
2723 <para>and connect it to the scale widget's adjustment like this:</para>
2724
2725 <programlisting role="C">
2726 g_signal_connect (G_OBJECT (adj), "value_changed",
2727                   G_CALLBACK (cb_rotate_picture), (gpointer) picture);
2728 </programlisting>
2729
2730 <para>What about when a widget reconfigures the <literal>upper</literal> or <literal>lower</literal>
2731 fields of its adjustment, such as when a user adds more text to a text
2732 widget?  In this case, it emits the <literal>changed</literal> signal, which looks
2733 like this:</para>
2734
2735 <programlisting role="C">
2736   void (* changed) (GtkAdjustment *adjustment);
2737 </programlisting>
2738
2739 <para>Range widgets typically connect a handler to this signal, which
2740 changes their appearance to reflect the change - for example, the size
2741 of the slider in a scrollbar will grow or shrink in inverse proportion
2742 to the difference between the <literal>lower</literal> and <literal>upper</literal> values of its
2743 adjustment.</para>
2744
2745 <para>You probably won't ever need to attach a handler to this signal,
2746 unless you're writing a new type of range widget.  However, if you
2747 change any of the values in a Adjustment directly, you should emit
2748 this signal on it to reconfigure whatever widgets are using it, like
2749 this:</para>
2750
2751 <programlisting role="C">
2752 g_signal_emit_by_name (G_OBJECT (adjustment), "changed");
2753 </programlisting>
2754
2755 <para>Now go forth and adjust!</para>
2756
2757 </sect1>
2758 </chapter>
2759
2760 <!-- ***************************************************************** -->
2761 <chapter id="ch-RangeWidgets">
2762 <title>Range Widgets</title>
2763
2764 <para>The category of range widgets includes the ubiquitous scrollbar widget
2765 and the less common scale widget. Though these two types of widgets
2766 are generally used for different purposes, they are quite similar in
2767 function and implementation. All range widgets share a set of common
2768 graphic elements, each of which has its own X window and receives
2769 events. They all contain a "trough" and a "slider" (what is sometimes
2770 called a "thumbwheel" in other GUI environments). Dragging the slider
2771 with the pointer moves it back and forth within the trough, while
2772 clicking in the trough advances the slider towards the location of the
2773 click, either completely, or by a designated amount, depending on
2774 which mouse button is used.</para>
2775
2776 <para>As mentioned in <link linkend="ch-Adjustments">Adjustments</link> above,
2777 all range widgets are associated with an adjustment object, from which
2778 they calculate the length of the slider and its position within the
2779 trough. When the user manipulates the slider, the range widget will
2780 change the value of the adjustment.</para>
2781
2782 <!-- ----------------------------------------------------------------- -->
2783 <sect1 id="sec-ScrollbarWidgets">
2784 <title>Scrollbar Widgets</title>
2785
2786 <para>These are your standard, run-of-the-mill scrollbars. These should be
2787 used only for scrolling some other widget, such as a list, a text box,
2788 or a viewport (and it's generally easier to use the scrolled window
2789 widget in most cases).  For other purposes, you should use scale
2790 widgets, as they are friendlier and more featureful.</para>
2791
2792 <para>There are separate types for horizontal and vertical scrollbars.
2793 There really isn't much to say about these. You create them with the
2794 following functions:</para>
2795
2796 <programlisting role="C">
2797 GtkWidget *gtk_hscrollbar_new( GtkAdjustment *adjustment );
2798
2799 GtkWidget *gtk_vscrollbar_new( GtkAdjustment *adjustment );
2800 </programlisting>
2801
2802 <para>and that's about it (if you don't believe me, look in the header
2803 files!).  The <literal>adjustment</literal> argument can either be a pointer to an
2804 existing Adjustment, or NULL, in which case one will be created for
2805 you. Specifying NULL might actually be useful in this case, if you
2806 wish to pass the newly-created adjustment to the constructor function
2807 of some other widget which will configure it for you, such as a text
2808 widget.</para>
2809
2810 </sect1>
2811
2812 <!-- ----------------------------------------------------------------- -->
2813 <sect1 id="sec-ScaleWidgets">
2814 <title>Scale Widgets</title>
2815
2816 <para>Scale widgets are used to allow the user to visually select and
2817 manipulate a value within a specific range. You might want to use a
2818 scale widget, for example, to adjust the magnification level on a
2819 zoomed preview of a picture, or to control the brightness of a color,
2820 or to specify the number of minutes of inactivity before a screensaver
2821 takes over the screen.</para>
2822
2823 <!-- ----------------------------------------------------------------- -->
2824 <sect2>
2825 <title>Creating a Scale Widget</title>
2826
2827 <para>As with scrollbars, there are separate widget types for horizontal and
2828 vertical scale widgets. (Most programmers seem to favour horizontal
2829 scale widgets.) Since they work essentially the same way, there's no
2830 need to treat them separately here. The following functions create vertical and 
2831 horizontal scale widgets, respectively:</para>
2832
2833 <programlisting role="C">
2834 GtkWidget *gtk_vscale_new( GtkAdjustment *adjustment );
2835
2836 GtkWidget *gtk_vscale_new_with_range( gdouble min,
2837                                       gdouble max,
2838                                       gdouble step );
2839
2840 GtkWidget *gtk_hscale_new( GtkAdjustment *adjustment );
2841
2842 GtkWidget *gtk_hscale_new_with_range( gdouble min,
2843                                       gdouble max,
2844                                       gdouble step );
2845 </programlisting>
2846
2847 <para>The <literal>adjustment</literal> argument can either be an adjustment which has
2848 already been created with gtk_adjustment_new(), or NULL, in
2849 which case, an anonymous Adjustment is created with all of its
2850 values set to <literal>0.0</literal> (which isn't very useful in this case). 
2851 In order to avoid confusing yourself, you probably want to create your
2852 adjustment with a <literal>page_size</literal> of <literal>0.0</literal> so 
2853 that its <literal>upper</literal> value actually corresponds to the highest 
2854 value the user can select. The _new_with_range()�variants take care of creating
2855 a suitable adjustment. (If you're <emphasis>already</emphasis> thoroughly
2856 confused, read the section on <link linkend="ch-Adjustments">Adjustments</link> 
2857 again for an explanation of what exactly adjustments do and how to create and 
2858 manipulate them.)</para>
2859
2860 </sect2>
2861
2862 <!-- ----------------------------------------------------------------- -->
2863 <sect2>
2864 <title>Functions and Signals (well, functions, at least)</title>
2865
2866 <para>Scale widgets can display their current value as a number beside the
2867 trough. The default behaviour is to show the value, but you can change
2868 this with this function:</para>
2869
2870 <programlisting role="C">
2871 void gtk_scale_set_draw_value( GtkScale *scale,
2872                                gboolean draw_value );
2873 </programlisting>
2874
2875 <para>As you might have guessed, <literal>draw_value</literal> is either <literal>TRUE</literal> or
2876 <literal>FALSE</literal>, with predictable consequences for either one.</para>
2877
2878 <para>The value displayed by a scale widget is rounded to one decimal point
2879 by default, as is the <literal>value</literal> field in its Adjustment. You can
2880 change this with:</para>
2881
2882 <programlisting role="C">
2883 void gtk_scale_set_digits( GtkScale *scale,
2884                             gint     digits );
2885 </programlisting>
2886
2887 <para>where <literal>digits</literal> is the number of decimal places you want. You can
2888 set <literal>digits</literal> to anything you like, but no more than 13 decimal
2889 places will actually be drawn on screen.</para>
2890
2891 <para>Finally, the value can be drawn in different positions
2892 relative to the trough:</para>
2893
2894 <programlisting role="C">
2895 void gtk_scale_set_value_pos( GtkScale        *scale,
2896                               GtkPositionType  pos );
2897 </programlisting>
2898
2899 <para>The argument <literal>pos</literal> is of type <literal>GtkPositionType</literal>,
2900 which can take one of the following values:</para>
2901
2902 <programlisting role="C">
2903   GTK_POS_LEFT
2904   GTK_POS_RIGHT
2905   GTK_POS_TOP
2906   GTK_POS_BOTTOM
2907 </programlisting>
2908
2909 <para>If you position the value on the "side" of the trough (e.g., on the
2910 top or bottom of a horizontal scale widget), then it will follow the
2911 slider up and down the trough.</para>
2912
2913 <para>All the preceding functions are defined in
2914 <literal>&lt;gtk/gtkscale.h&gt;</literal>. The header files for all GTK widgets
2915 are automatically included when you include
2916 <literal>&lt;gtk/gtk.h&gt;</literal>. But you should look over the header files
2917 of all widgets that interest you, in order to learn more about their functions
2918 and features.</para>
2919
2920 </sect2>
2921 </sect1>
2922
2923 <!-- ----------------------------------------------------------------- -->
2924 <sect1 id="sec-CommonRangeFunctions">
2925 <title>Common Range Functions</title>
2926
2927 <para>The Range widget class is fairly complicated internally, but, like
2928 all the "base class" widgets, most of its complexity is only
2929 interesting if you want to hack on it. Also, almost all of the
2930 functions and signals it defines are only really used in writing
2931 derived widgets. There are, however, a few useful functions that are
2932 defined in <literal>&lt;gtk/gtkrange.h&gt;</literal> and will work on all range
2933 widgets.</para>
2934
2935 <!-- ----------------------------------------------------------------- -->
2936 <sect2>
2937 <title>Setting the Update Policy</title>
2938
2939 <para>The "update policy" of a range widget defines at what points during
2940 user interaction it will change the <literal>value</literal> field of its
2941 Adjustment and emit the "value_changed" signal on this
2942 Adjustment. The update policies, defined in
2943 <literal>&lt;gtk/gtkenums.h&gt;</literal> as type <literal>enum GtkUpdateType</literal>,
2944 are:</para>
2945
2946 <variablelist>
2947 <varlistentry>
2948 <term><literal>GTK_UPDATE_CONTINUOUS</literal></term>
2949 <listitem><para>This is the default. The
2950 "value_changed" signal is emitted continuously, i.e., whenever the
2951 slider is moved by even the tiniest amount.</para>
2952 </listitem>
2953 </varlistentry>
2954 <varlistentry>
2955 <term><literal>GTK_UPDATE_DISCONTINUOUS</literal></term>
2956 <listitem><para>The "value_changed" signal is
2957 only emitted once the slider has stopped moving and the user has
2958 released the mouse button.</para>
2959 </listitem>
2960 </varlistentry>
2961 <varlistentry>
2962 <term><literal>GTK_UPDATE_DELAYED</literal></term>
2963 <listitem><para>The "value_changed" signal is emitted
2964 when the user releases the mouse button, or if the slider stops moving
2965 for a short period of time.</para>
2966 </listitem>
2967 </varlistentry>
2968 </variablelist>
2969
2970 <para>The update policy of a range widget can be set by casting it using the
2971 <literal>GTK_RANGE(widget)</literal> macro and passing it to this function:</para>
2972
2973 <programlisting role="C">
2974 void gtk_range_set_update_policy( GtkRange      *range,
2975                                   GtkUpdateType  policy);
2976 </programlisting>
2977
2978 </sect2>
2979
2980 <!-- ----------------------------------------------------------------- -->
2981 <sect2>
2982 <title>Getting and Setting Adjustments</title>
2983
2984 <para>Getting and setting the adjustment for a range widget "on the fly" is
2985 done, predictably, with:</para>
2986
2987 <programlisting role="C">
2988 GtkAdjustment* gtk_range_get_adjustment( GtkRange *range );
2989
2990 void gtk_range_set_adjustment( GtkRange      *range,
2991                                GtkAdjustment *adjustment );
2992 </programlisting>
2993
2994 <para><literal>gtk_range_get_adjustment()</literal> returns a pointer to the adjustment to
2995 which <literal>range</literal> is connected.</para>
2996
2997 <para><literal>gtk_range_set_adjustment()</literal> does absolutely nothing if you pass it
2998 the adjustment that <literal>range</literal> is already using, regardless of whether
2999 you changed any of its fields or not. If you pass it a new
3000 Adjustment, it will unreference the old one if it exists (possibly
3001 destroying it), connect the appropriate signals to the new one, and
3002 call the private function <literal>gtk_range_adjustment_changed()</literal>, which
3003 will (or at least, is supposed to...) recalculate the size and/or
3004 position of the slider and redraw if necessary. As mentioned in the
3005 section on adjustments, if you wish to reuse the same Adjustment,
3006 when you modify its values directly, you should emit the "changed"
3007 signal on it, like this:</para>
3008
3009 <programlisting role="C">
3010 g_signal_emit_by_name (G_OBJECT (adjustment), "changed");
3011 </programlisting>
3012
3013 </sect2>
3014 </sect1>
3015
3016 <!-- ----------------------------------------------------------------- -->
3017 <sect1 id="sec-KeyAndMouseBindings">
3018 <title>Key and Mouse bindings</title>
3019
3020 <para>All of the GTK range widgets react to mouse clicks in more or less
3021 the same way. Clicking button-1 in the trough will cause its
3022 adjustment's <literal>page_increment</literal> to be added or subtracted from its
3023 <literal>value</literal>, and the slider to be moved accordingly. Clicking mouse
3024 button-2 in the trough will jump the slider to the point at which the
3025 button was clicked. Clicking button-3 in the trough of a range or any button on 
3026 a scrollbar's arrows will cause its adjustment's value to change by
3027 <literal>step_increment</literal> at a time.</para>
3028
3029 <para>Scrollbars are not focusable, thus have no key bindings. The key bindings
3030 for the other range widgets (which are, of course, only active when the widget 
3031 has focus) are do <emphasis>not</emphasis> differentiate between horizontal and 
3032 vertical range widgets.</para>
3033
3034 <para>All range widgets can be operated with the left, right, up and down arrow
3035 keys, as well as with the <literal>Page Up</literal> and <literal>Page Down</literal> 
3036 keys. The arrows move the slider up and down by <literal>step_increment</literal>, while
3037 <literal>Page Up</literal> and <literal>Page Down</literal> move it by 
3038 <literal>page_increment</literal>.</para>
3039
3040 <para>The user can also move the slider all the way to one end or the other
3041 of the trough using the keyboard. This is done with the <literal>Home</literal> 
3042 and <literal>End</literal> keys.</para>
3043
3044 </sect1>
3045
3046 <!-- ----------------------------------------------------------------- -->
3047 <sect1 id="sec-RangeWidgetsExample">
3048 <title>Example</title>
3049
3050 <para>This example is a somewhat modified version of the "range controls"
3051 test from <filename>testgtk.c</filename>. It basically puts up a window with three
3052 range widgets all connected to the same adjustment, and a couple of
3053 controls for adjusting some of the parameters mentioned above and in
3054 the section on adjustments, so you can see how they affect the way
3055 these widgets work for the user.</para>
3056
3057 <para>
3058 <inlinemediaobject>
3059 <imageobject>
3060 <imagedata fileref="images/rangewidgets.png" format="png">
3061 </imageobject>
3062 </inlinemediaobject>
3063 </para>
3064
3065 <programlisting role="C">
3066 <!-- example-start rangewidgets rangewidgets.c -->
3067
3068 #include &lt;gtk/gtk.h&gt;
3069
3070 GtkWidget *hscale, *vscale;
3071
3072 static void cb_pos_menu_select( GtkWidget       *item,
3073                                 GtkPositionType  pos )
3074 {
3075     /* Set the value position on both scale widgets */
3076     gtk_scale_set_value_pos (GTK_SCALE (hscale), pos);
3077     gtk_scale_set_value_pos (GTK_SCALE (vscale), pos);
3078 }
3079
3080 static void cb_update_menu_select( GtkWidget     *item,
3081                                    GtkUpdateType  policy )
3082 {
3083     /* Set the update policy for both scale widgets */
3084     gtk_range_set_update_policy (GTK_RANGE (hscale), policy);
3085     gtk_range_set_update_policy (GTK_RANGE (vscale), policy);
3086 }
3087
3088 static void cb_digits_scale( GtkAdjustment *adj )
3089 {
3090     /* Set the number of decimal places to which adj->value is rounded */
3091     gtk_scale_set_digits (GTK_SCALE (hscale), (gint) adj->value);
3092     gtk_scale_set_digits (GTK_SCALE (vscale), (gint) adj->value);
3093 }
3094
3095 static void cb_page_size( GtkAdjustment *get,
3096                           GtkAdjustment *set )
3097 {
3098     /* Set the page size and page increment size of the sample
3099      * adjustment to the value specified by the "Page Size" scale */
3100     set->page_size = get->value;
3101     set->page_increment = get->value;
3102
3103     /* This sets the adjustment and makes it emit the "changed" signal to 
3104        reconfigure all the widgets that are attached to this signal.  */
3105     gtk_adjustment_set_value (set, CLAMP (set->value,
3106                                           set->lower,
3107                                           (set->upper - set->page_size)));
3108     g_signal_emit_by_name(G_OBJECT(set), "changed");
3109 }
3110
3111 static void cb_draw_value( GtkToggleButton *button )
3112 {
3113     /* Turn the value display on the scale widgets off or on depending
3114      *  on the state of the checkbutton */
3115     gtk_scale_set_draw_value (GTK_SCALE (hscale), button->active);
3116     gtk_scale_set_draw_value (GTK_SCALE (vscale), button->active);  
3117 }
3118
3119 /* Convenience functions */
3120
3121 static GtkWidget *make_menu_item ( gchar     *name,
3122                                    GCallback  callback,
3123                                    gpointer   data )
3124 {
3125     GtkWidget *item;
3126   
3127     item = gtk_menu_item_new_with_label (name);
3128     g_signal_connect (G_OBJECT (item), "activate",
3129                       callback, (gpointer) data);
3130     gtk_widget_show (item);
3131
3132     return item;
3133 }
3134
3135 static void scale_set_default_values( GtkScale *scale )
3136 {
3137     gtk_range_set_update_policy (GTK_RANGE (scale),
3138                                  GTK_UPDATE_CONTINUOUS);
3139     gtk_scale_set_digits (scale, 1);
3140     gtk_scale_set_value_pos (scale, GTK_POS_TOP);
3141     gtk_scale_set_draw_value (scale, TRUE);
3142 }
3143
3144 /* makes the sample window */
3145
3146 static void create_range_controls( void )
3147 {
3148     GtkWidget *window;
3149     GtkWidget *box1, *box2, *box3;
3150     GtkWidget *button;
3151     GtkWidget *scrollbar;
3152     GtkWidget *separator;
3153     GtkWidget *opt, *menu, *item;
3154     GtkWidget *label;
3155     GtkWidget *scale;
3156     GtkObject *adj1, *adj2;
3157
3158     /* Standard window-creating stuff */
3159     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3160     g_signal_connect (G_OBJECT (window), "destroy",
3161                       G_CALLBACK (gtk_main_quit),
3162                       NULL);
3163     gtk_window_set_title (GTK_WINDOW (window), "range controls");
3164
3165     box1 = gtk_vbox_new (FALSE, 0);
3166     gtk_container_add (GTK_CONTAINER (window), box1);
3167     gtk_widget_show (box1);
3168
3169     box2 = gtk_hbox_new (FALSE, 10);
3170     gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
3171     gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
3172     gtk_widget_show (box2);
3173
3174     /* value, lower, upper, step_increment, page_increment, page_size */
3175     /* Note that the page_size value only makes a difference for
3176      * scrollbar widgets, and the highest value you'll get is actually
3177      * (upper - page_size). */
3178     adj1 = gtk_adjustment_new (0.0, 0.0, 101.0, 0.1, 1.0, 1.0);
3179   
3180     vscale = gtk_vscale_new (GTK_ADJUSTMENT (adj1));
3181     scale_set_default_values (GTK_SCALE (vscale));
3182     gtk_box_pack_start (GTK_BOX (box2), vscale, TRUE, TRUE, 0);
3183     gtk_widget_show (vscale);
3184
3185     box3 = gtk_vbox_new (FALSE, 10);
3186     gtk_box_pack_start (GTK_BOX (box2), box3, TRUE, TRUE, 0);
3187     gtk_widget_show (box3);
3188
3189     /* Reuse the same adjustment */
3190     hscale = gtk_hscale_new (GTK_ADJUSTMENT (adj1));
3191     gtk_widget_set_size_request (GTK_WIDGET (hscale), 200, -1);
3192     scale_set_default_values (GTK_SCALE (hscale));
3193     gtk_box_pack_start (GTK_BOX (box3), hscale, TRUE, TRUE, 0);
3194     gtk_widget_show (hscale);
3195
3196     /* Reuse the same adjustment again */
3197     scrollbar = gtk_hscrollbar_new (GTK_ADJUSTMENT (adj1));
3198     /* Notice how this causes the scales to always be updated
3199      * continuously when the scrollbar is moved */
3200     gtk_range_set_update_policy (GTK_RANGE (scrollbar), 
3201                                  GTK_UPDATE_CONTINUOUS);
3202     gtk_box_pack_start (GTK_BOX (box3), scrollbar, TRUE, TRUE, 0);
3203     gtk_widget_show (scrollbar);
3204
3205     box2 = gtk_hbox_new (FALSE, 10);
3206     gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
3207     gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
3208     gtk_widget_show (box2);
3209
3210     /* A checkbutton to control whether the value is displayed or not */
3211     button = gtk_check_button_new_with_label("Display value on scale widgets");
3212     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
3213     g_signal_connect (G_OBJECT (button), "toggled",
3214                       G_CALLBACK (cb_draw_value), NULL);
3215     gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
3216     gtk_widget_show (button);
3217   
3218     box2 = gtk_hbox_new (FALSE, 10);
3219     gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
3220
3221     /* An option menu to change the position of the value */
3222     label = gtk_label_new ("Scale Value Position:");
3223     gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0);
3224     gtk_widget_show (label);
3225   
3226     opt = gtk_option_menu_new ();
3227     menu = gtk_menu_new ();
3228
3229     item = make_menu_item ("Top",
3230                            G_CALLBACK (cb_pos_menu_select),
3231                            GINT_TO_POINTER (GTK_POS_TOP));
3232     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3233   
3234     item = make_menu_item ("Bottom", G_CALLBACK (cb_pos_menu_select), 
3235                            GINT_TO_POINTER (GTK_POS_BOTTOM));
3236     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3237   
3238     item = make_menu_item ("Left", G_CALLBACK (cb_pos_menu_select),
3239                            GINT_TO_POINTER (GTK_POS_LEFT));
3240     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3241   
3242     item = make_menu_item ("Right", G_CALLBACK (cb_pos_menu_select),
3243                            GINT_TO_POINTER (GTK_POS_RIGHT));
3244     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3245   
3246     gtk_option_menu_set_menu (GTK_OPTION_MENU (opt), menu);
3247     gtk_box_pack_start (GTK_BOX (box2), opt, TRUE, TRUE, 0);
3248     gtk_widget_show (opt);
3249
3250     gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
3251     gtk_widget_show (box2);
3252
3253     box2 = gtk_hbox_new (FALSE, 10);
3254     gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
3255
3256     /* Yet another option menu, this time for the update policy of the
3257      * scale widgets */
3258     label = gtk_label_new ("Scale Update Policy:");
3259     gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0);
3260     gtk_widget_show (label);
3261   
3262     opt = gtk_option_menu_new ();
3263     menu = gtk_menu_new ();
3264   
3265     item = make_menu_item ("Continuous",
3266                            G_CALLBACK (cb_update_menu_select),
3267                            GINT_TO_POINTER (GTK_UPDATE_CONTINUOUS));
3268     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3269   
3270     item = make_menu_item ("Discontinuous",
3271                            G_CALLBACK (cb_update_menu_select),
3272                            GINT_TO_POINTER (GTK_UPDATE_DISCONTINUOUS));
3273     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3274   
3275     item = make_menu_item ("Delayed",
3276                            G_CALLBACK (cb_update_menu_select),
3277                            GINT_TO_POINTER (GTK_UPDATE_DELAYED));
3278     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
3279   
3280     gtk_option_menu_set_menu (GTK_OPTION_MENU (opt), menu);
3281     gtk_box_pack_start (GTK_BOX (box2), opt, TRUE, TRUE, 0);
3282     gtk_widget_show (opt);
3283   
3284     gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
3285     gtk_widget_show (box2);
3286
3287     box2 = gtk_hbox_new (FALSE, 10);
3288     gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
3289   
3290     /* An HScale widget for adjusting the number of digits on the
3291      * sample scales. */
3292     label = gtk_label_new ("Scale Digits:");
3293     gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0);
3294     gtk_widget_show (label);
3295
3296     adj2 = gtk_adjustment_new (1.0, 0.0, 5.0, 1.0, 1.0, 0.0);
3297     g_signal_connect (G_OBJECT (adj2), "value_changed",
3298                       G_CALLBACK (cb_digits_scale), NULL);
3299     scale = gtk_hscale_new (GTK_ADJUSTMENT (adj2));
3300     gtk_scale_set_digits (GTK_SCALE (scale), 0);
3301     gtk_box_pack_start (GTK_BOX (box2), scale, TRUE, TRUE, 0);
3302     gtk_widget_show (scale);
3303
3304     gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
3305     gtk_widget_show (box2);
3306   
3307     box2 = gtk_hbox_new (FALSE, 10);
3308     gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
3309   
3310     /* And, one last HScale widget for adjusting the page size of the
3311      * scrollbar. */
3312     label = gtk_label_new ("Scrollbar Page Size:");
3313     gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0);
3314     gtk_widget_show (label);
3315
3316     adj2 = gtk_adjustment_new (1.0, 1.0, 101.0, 1.0, 1.0, 0.0);
3317     g_signal_connect (G_OBJECT (adj2), "value_changed",
3318                       G_CALLBACK (cb_page_size), (gpointer) adj1);
3319     scale = gtk_hscale_new (GTK_ADJUSTMENT (adj2));
3320     gtk_scale_set_digits (GTK_SCALE (scale), 0);
3321     gtk_box_pack_start (GTK_BOX (box2), scale, TRUE, TRUE, 0);
3322     gtk_widget_show (scale);
3323
3324     gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
3325     gtk_widget_show (box2);
3326
3327     separator = gtk_hseparator_new ();
3328     gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
3329     gtk_widget_show (separator);
3330
3331     box2 = gtk_vbox_new (FALSE, 10);
3332     gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
3333     gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
3334     gtk_widget_show (box2);
3335
3336     button = gtk_button_new_with_label ("Quit");
3337     g_signal_connect_swapped (G_OBJECT (button), "clicked",
3338                               G_CALLBACK (gtk_main_quit),
3339                               NULL);
3340     gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
3341     GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
3342     gtk_widget_grab_default (button);
3343     gtk_widget_show (button);
3344
3345     gtk_widget_show (window);
3346 }
3347
3348 int main( int   argc,
3349           char *argv[] )
3350 {
3351     gtk_init (&amp;argc, &amp;argv);
3352
3353     create_range_controls ();
3354
3355     gtk_main ();
3356
3357     return 0;
3358 }
3359
3360 <!-- example-end -->
3361 </programlisting>
3362
3363 <para>You will notice that the program does not call g_signal_connect()
3364 for the "delete_event", but only for the "destroy" signal. This will
3365 still perform the desired function, because an unhandled
3366 "delete_event" will result in a "destroy" signal being given to the
3367 window.</para>
3368
3369 </sect1>
3370 </chapter>
3371
3372 <!-- ***************************************************************** -->
3373 <chapter id="ch-MiscWidgets">
3374 <title>Miscellaneous Widgets</title>
3375
3376 <!-- ----------------------------------------------------------------- -->
3377 <sect1 id="sec-Labels">
3378 <title>Labels</title>
3379
3380 <para>Labels are used a lot in GTK, and are relatively simple. Labels emit
3381 no signals as they do not have an associated X window. If you need to
3382 catch signals, or do clipping, place it inside a <link linkend="sec-EventBox">
3383 EventBox</link> widget or a Button widget.</para>
3384
3385 <para>To create a new label, use:</para>
3386
3387 <programlisting role="C">
3388 GtkWidget *gtk_label_new( const char *str );
3389
3390 GtkWidget *gtk_label_new_with_mnemonic( const char *str );
3391 </programlisting>
3392
3393 <para>The sole argument is the string you wish the label to display.</para>
3394
3395 <para>To change the label's text after creation, use the function:</para>
3396
3397 <programlisting role="C">
3398 void gtk_label_set_text( GtkLabel   *label,
3399                          const char *str );
3400 </programlisting>
3401
3402 <para>The first argument is the label you created previously (cast
3403 using the <literal>GTK_LABEL()</literal> macro), and the second is the new string.</para>
3404
3405 <para>The space needed for the new string will be automatically adjusted if
3406 needed. You can produce multi-line labels by putting line breaks in
3407 the label string.</para>
3408
3409 <para>To retrieve the current string, use:</para>
3410
3411 <programlisting role="C">
3412 const gchar* gtk_label_get_text( GtkLabel  *label );                    
3413 </programlisting>
3414
3415 <para>Do not free the returned string, as it is used internally by GTK.</para>
3416
3417 <para>The label text can be justified using:</para>
3418
3419 <programlisting role="C">
3420 void gtk_label_set_justify( GtkLabel         *label,
3421                             GtkJustification  jtype );
3422 </programlisting>
3423
3424 <para>Values for <literal>jtype</literal> are:</para>
3425 <programlisting role="C">
3426   GTK_JUSTIFY_LEFT
3427   GTK_JUSTIFY_RIGHT
3428   GTK_JUSTIFY_CENTER (the default)
3429   GTK_JUSTIFY_FILL
3430 </programlisting>
3431
3432 <para>The label widget is also capable of line wrapping the text
3433 automatically. This can be activated using:</para>
3434
3435 <programlisting role="C">
3436 void gtk_label_set_line_wrap (GtkLabel *label,
3437                               gboolean  wrap);
3438 </programlisting>
3439
3440 <para>The <literal>wrap</literal> argument takes a TRUE or FALSE value.</para>
3441
3442 <para>If you want your label underlined, then you can set a pattern on the
3443 label:</para>
3444
3445 <programlisting role="C">
3446 void       gtk_label_set_pattern   (GtkLabel          *label,
3447                                     const gchar       *pattern);
3448 </programlisting>
3449
3450 <para>The pattern argument indicates how the underlining should look. It
3451 consists of a string of underscore and space characters. An underscore
3452 indicates that the corresponding character in the label should be
3453 underlined. For example, the string <literal>"__     __"</literal> would underline the
3454 first two characters and eight and ninth characters.</para>
3455
3456 <note><para>If you simply want to have an underlined accelerator ("mnemonic") 
3457 in your label, you should use gtk_label_new_with_mnemonic() or 
3458 gtk_label_set_text_with_mnemonic(), not gtk_label_set_pattern().</para>
3459 </note>
3460
3461 <para>Below is a short example to illustrate these functions. This example
3462 makes use of the Frame widget to better demonstrate the label
3463 styles. You can ignore this for now as the <link linkend="sec-Frames">Frame</link> 
3464 widget is explained later on.</para>
3465
3466 <para>In GTK+ 2.0, label texts can contain markup for font and other text attribute 
3467 changes, and labels may be selectable (for copy-and-paste). These advanced features
3468 won't be explained here.</para>
3469
3470 <para>
3471 <inlinemediaobject>
3472 <imageobject>
3473 <imagedata fileref="images/label.png" format="png">
3474 </imageobject>
3475 </inlinemediaobject>
3476 </para>
3477
3478 <programlisting role="C">
3479 <!-- example-start label label.c -->
3480
3481 #include &lt;gtk/gtk.h&gt;
3482
3483 int main( int   argc,
3484           char *argv[] )
3485 {
3486   static GtkWidget *window = NULL;
3487   GtkWidget *hbox;
3488   GtkWidget *vbox;
3489   GtkWidget *frame;
3490   GtkWidget *label;
3491
3492   /* Initialise GTK */
3493   gtk_init (&amp;argc, &amp;argv);
3494
3495   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3496   g_signal_connect (G_OBJECT (window), "destroy",
3497                     G_CALLBACK (gtk_main_quit),
3498                     NULL);
3499
3500   gtk_window_set_title (GTK_WINDOW (window), "Label");
3501   vbox = gtk_vbox_new (FALSE, 5);
3502   hbox = gtk_hbox_new (FALSE, 5);
3503   gtk_container_add (GTK_CONTAINER (window), hbox);
3504   gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
3505   gtk_container_set_border_width (GTK_CONTAINER (window), 5);
3506   
3507   frame = gtk_frame_new ("Normal Label");
3508   label = gtk_label_new ("This is a Normal label");
3509   gtk_container_add (GTK_CONTAINER (frame), label);
3510   gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3511   
3512   frame = gtk_frame_new ("Multi-line Label");
3513   label = gtk_label_new ("This is a Multi-line label.\nSecond line\n" \
3514                          "Third line");
3515   gtk_container_add (GTK_CONTAINER (frame), label);
3516   gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3517   
3518   frame = gtk_frame_new ("Left Justified Label");
3519   label = gtk_label_new ("This is a Left-Justified\n" \
3520                          "Multi-line label.\nThird      line");
3521   gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
3522   gtk_container_add (GTK_CONTAINER (frame), label);
3523   gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3524   
3525   frame = gtk_frame_new ("Right Justified Label");
3526   label = gtk_label_new ("This is a Right-Justified\nMulti-line label.\n" \
3527                          "Fourth line, (j/k)");
3528   gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_RIGHT);
3529   gtk_container_add (GTK_CONTAINER (frame), label);
3530   gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3531
3532   vbox = gtk_vbox_new (FALSE, 5);
3533   gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
3534   frame = gtk_frame_new ("Line wrapped label");
3535   label = gtk_label_new ("This is an example of a line-wrapped label.  It " \
3536                          "should not be taking up the entire             " /* big space to test spacing */\
3537                          "width allocated to it, but automatically " \
3538                          "wraps the words to fit.  " \
3539                          "The time has come, for all good men, to come to " \
3540                          "the aid of their party.  " \
3541                          "The sixth sheik's six sheep's sick.\n" \
3542                          "     It supports multiple paragraphs correctly, " \
3543                          "and  correctly   adds "\
3544                          "many          extra  spaces. ");
3545   gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
3546   gtk_container_add (GTK_CONTAINER (frame), label);
3547   gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3548   
3549   frame = gtk_frame_new ("Filled, wrapped label");
3550   label = gtk_label_new ("This is an example of a line-wrapped, filled label.  " \
3551                          "It should be taking "\
3552                          "up the entire              width allocated to it.  " \
3553                          "Here is a sentence to prove "\
3554                          "my point.  Here is another sentence. "\
3555                          "Here comes the sun, do de do de do.\n"\
3556                          "    This is a new paragraph.\n"\
3557                          "    This is another newer, longer, better " \
3558                          "paragraph.  It is coming to an end, "\
3559                          "unfortunately.");
3560   gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_FILL);
3561   gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
3562   gtk_container_add (GTK_CONTAINER (frame), label);
3563   gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3564   
3565   frame = gtk_frame_new ("Underlined label");
3566   label = gtk_label_new ("This label is underlined!\n"
3567                          "This one is underlined in quite a funky fashion");
3568   gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
3569   gtk_label_set_pattern (GTK_LABEL (label),
3570                          "_________________________ _ _________ _ ______     __ _______ ___");
3571   gtk_container_add (GTK_CONTAINER (frame), label);
3572   gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
3573   
3574   gtk_widget_show_all (window);
3575
3576   gtk_main ();
3577   
3578   return 0;
3579 }
3580 <!-- example-end -->
3581 </programlisting>
3582
3583 </sect1>
3584
3585 <!-- ----------------------------------------------------------------- -->
3586 <sect1 id="sec-Arrows">
3587 <title>Arrows</title>
3588
3589 <para>The Arrow widget draws an arrowhead, facing in a number of possible
3590 directions and having a number of possible styles. It can be very
3591 useful when placed on a button in many applications. Like the Label
3592 widget, it emits no signals.</para>
3593
3594 <para>There are only two functions for manipulating an Arrow widget:</para>
3595
3596 <programlisting role="C">
3597 GtkWidget *gtk_arrow_new( GtkArrowType   arrow_type,
3598                           GtkShadowType  shadow_type );
3599
3600 void gtk_arrow_set( GtkArrow      *arrow,
3601                     GtkArrowType   arrow_type,
3602                     GtkShadowType  shadow_type );
3603 </programlisting>
3604
3605 <para>The first creates a new arrow widget with the indicated type and
3606 appearance. The second allows these values to be altered
3607 retrospectively. The <literal>arrow_type</literal> argument may take one of the
3608 following values:</para>
3609
3610 <programlisting role="C">
3611   GTK_ARROW_UP
3612   GTK_ARROW_DOWN
3613   GTK_ARROW_LEFT
3614   GTK_ARROW_RIGHT
3615 </programlisting>
3616
3617 <para>These values obviously indicate the direction in which the arrow will
3618 point. The <literal>shadow_type</literal> argument may take one of these values:</para>
3619
3620 <programlisting role="C">
3621   GTK_SHADOW_IN
3622   GTK_SHADOW_OUT (the default)
3623   GTK_SHADOW_ETCHED_IN
3624   GTK_SHADOW_ETCHED_OUT
3625 </programlisting>
3626
3627 <para>Here's a brief example to illustrate their use.</para>
3628
3629 <para>
3630 <inlinemediaobject>
3631 <imageobject>
3632 <imagedata fileref="images/arrow.png" format="png">
3633 </imageobject>
3634 </inlinemediaobject>
3635 </para>
3636
3637 <programlisting role="C">
3638 <!-- example-start arrow arrow.c -->
3639
3640 #include &lt;gtk/gtk.h&gt;
3641
3642 /* Create an Arrow widget with the specified parameters
3643  * and pack it into a button */
3644 static GtkWidget *create_arrow_button( GtkArrowType  arrow_type,
3645                                        GtkShadowType shadow_type )
3646 {
3647   GtkWidget *button;
3648   GtkWidget *arrow;
3649
3650   button = gtk_button_new ();
3651   arrow = gtk_arrow_new (arrow_type, shadow_type);
3652
3653   gtk_container_add (GTK_CONTAINER (button), arrow);
3654   
3655   gtk_widget_show (button);
3656   gtk_widget_show (arrow);
3657
3658   return button;
3659 }
3660
3661 int main( int   argc,
3662           char *argv[] )
3663 {
3664   /* GtkWidget is the storage type for widgets */
3665   GtkWidget *window;
3666   GtkWidget *button;
3667   GtkWidget *box;
3668
3669   /* Initialize the toolkit */
3670   gtk_init (&amp;argc, &amp;argv);
3671
3672   /* Create a new window */
3673   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3674
3675   gtk_window_set_title (GTK_WINDOW (window), "Arrow Buttons");
3676
3677   /* It's a good idea to do this for all windows. */
3678   g_signal_connect (G_OBJECT (window), "destroy",
3679                     G_CALLBACK (gtk_main_quit), NULL);
3680
3681   /* Sets the border width of the window. */
3682   gtk_container_set_border_width (GTK_CONTAINER (window), 10);
3683
3684   /* Create a box to hold the arrows/buttons */
3685   box = gtk_hbox_new (FALSE, 0);
3686   gtk_container_set_border_width (GTK_CONTAINER (box), 2);
3687   gtk_container_add (GTK_CONTAINER (window), box);
3688
3689   /* Pack and show all our widgets */
3690   gtk_widget_show (box);
3691
3692   button = create_arrow_button (GTK_ARROW_UP, GTK_SHADOW_IN);
3693   gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 3);
3694
3695   button = create_arrow_button (GTK_ARROW_DOWN, GTK_SHADOW_OUT);
3696   gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 3);
3697   
3698   button = create_arrow_button (GTK_ARROW_LEFT, GTK_SHADOW_ETCHED_IN);
3699   gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 3);
3700   
3701   button = create_arrow_button (GTK_ARROW_RIGHT, GTK_SHADOW_ETCHED_OUT);
3702   gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 3);
3703   
3704   gtk_widget_show (window);
3705   
3706   /* Rest in gtk_main and wait for the fun to begin! */
3707   gtk_main ();
3708   
3709   return 0;
3710 }
3711 <!-- example-end -->
3712 </programlisting>
3713
3714 </sect1>
3715
3716 <!-- ----------------------------------------------------------------- -->
3717 <sect1 id="sec-TheTooltipsObject">
3718 <title>The Tooltips Object</title>
3719
3720 <para>These are the little text strings that pop up when you leave your
3721 pointer over a button or other widget for a few seconds. They are easy
3722 to use, so I will just explain them without giving an example. If you
3723 want to see some code, take a look at the <filename>testgtk.c</filename> program
3724 distributed with GTK.</para>
3725
3726 <para>Widgets that do not receive events (widgets that do not have their
3727 own window) will not work with tooltips.</para>
3728
3729 <para>The first call you will use creates a new tooltip. You only need to do
3730 this once for a set of tooltips as the <literal>GtkTooltips</literal> object this
3731 function returns can be used to create multiple tooltips.</para>
3732
3733 <programlisting role="C">
3734 GtkTooltips *gtk_tooltips_new( void );
3735 </programlisting>
3736
3737 <para>Once you have created a new tooltip, and the widget you wish to use it
3738 on, simply use this call to set it:</para>
3739
3740 <programlisting role="C">
3741 void gtk_tooltips_set_tip( GtkTooltips *tooltips,
3742                            GtkWidget   *widget,
3743                            const gchar *tip_text,
3744                            const gchar *tip_private );
3745 </programlisting>
3746
3747 <para>The first argument is the tooltip you've already created, followed by
3748 the widget you wish to have this tooltip pop up for, and the text you
3749 wish it to say. The last argument is a text string that can be used as
3750 an identifier when using GtkTipsQuery to implement context sensitive
3751 help. For now, you can set it to NULL.</para>
3752
3753 <!-- TODO: sort out what how to do the context sensitive help -->
3754
3755 <para>Here's a short example:</para>
3756
3757 <programlisting role="C">
3758 GtkTooltips *tooltips;
3759 GtkWidget *button;
3760 .
3761 .
3762 .
3763 tooltips = gtk_tooltips_new ();
3764 button = gtk_button_new_with_label ("button 1");
3765 .
3766 .
3767 .
3768 gtk_tooltips_set_tip (tooltips, button, "This is button 1", NULL);
3769 </programlisting>
3770
3771 <para>There are other calls that can be used with tooltips. I will just list
3772 them with a brief description of what they do.</para>
3773
3774 <programlisting role="C">
3775 void gtk_tooltips_enable( GtkTooltips *tooltips );
3776 </programlisting>
3777
3778 <para>Enable a disabled set of tooltips.</para>
3779
3780 <programlisting role="C">
3781 void gtk_tooltips_disable( GtkTooltips *tooltips );
3782 </programlisting>
3783
3784 <para>Disable an enabled set of tooltips.</para>
3785
3786 <para>And that's all the functions associated with tooltips. More than
3787 you'll ever want to know :-)</para>
3788
3789 </sect1>
3790
3791 <!-- ----------------------------------------------------------------- -->
3792 <sect1 id="sec-ProgressBars">
3793 <title>Progress Bars</title>
3794
3795 <para>Progress bars are used to show the status of an operation. They are
3796 pretty easy to use, as you will see with the code below. But first
3797 lets start out with the calls to create a new progress bar.</para>
3798
3799 <programlisting role="C">
3800 GtkWidget *gtk_progress_bar_new( void );
3801 </programlisting>
3802
3803 <para>Now that the progress bar has been created we can use it.</para>
3804
3805 <programlisting role="C">
3806 void gtk_progress_bar_set_fraction ( GtkProgressBar *pbar,
3807                                      gdouble        fraction );
3808 </programlisting>
3809
3810 <para>The first argument is the progress bar you wish to operate on, and the
3811 second argument is the amount "completed", meaning the amount the
3812 progress bar has been filled from 0-100%. This is passed to the
3813 function as a real number ranging from 0 to 1.</para>
3814
3815 <para>GTK v1.2 has added new functionality to the progress bar that enables
3816 it to display its value in different ways, and to inform the user of
3817 its current value and its range.</para>
3818
3819 <para>A progress bar may be set to one of a number of orientations using the
3820 function</para>
3821
3822 <programlisting role="C">
3823 void gtk_progress_bar_set_orientation( GtkProgressBar *pbar,
3824                                        GtkProgressBarOrientation orientation );
3825 </programlisting>
3826
3827 <para>The <literal>orientation</literal> argument may take one of the following
3828 values to indicate the direction in which the progress bar moves:</para>
3829
3830 <programlisting role="C">
3831   GTK_PROGRESS_LEFT_TO_RIGHT
3832   GTK_PROGRESS_RIGHT_TO_LEFT
3833   GTK_PROGRESS_BOTTOM_TO_TOP
3834   GTK_PROGRESS_TOP_TO_BOTTOM
3835 </programlisting>
3836
3837 <para>As well as indicating the amount of progress that has occured, the
3838 progress bar may be set to just indicate that there is some activity. 
3839 This can be useful in situations where progress cannot be measured against 
3840 a value range. The following function indicates that some progress has been 
3841 made.</para>
3842
3843 <programlisting role="C">
3844 void gtk_progress_bar_pulse ( GtkProgressBar *progress );
3845 </programlisting>
3846
3847 <para>The step size of the activity indicator is set using the following 
3848 function.</para>
3849
3850 <programlisting role="C">
3851 void gtk_progress_bar_set_pulse_step( GtkProgressBar *pbar,
3852                                       gdouble         fraction );
3853 </programlisting>
3854
3855 <para>When not in activity mode, the progress bar can also display a
3856 configurable text string within its trough, using the following
3857 function.</para>
3858
3859 <programlisting role="C">
3860 void gtk_progress_bar_set_text( GtkProgressBar *progress,
3861                                 const gchar    *text );
3862 </programlisting>
3863
3864 <note><para>Note that gtk_progress_set_text() doesn't support the printf()-like formatting
3865 of the GTK+ 1.2 Progressbar.</para></note>
3866
3867 <para>You can turn off the display of the string by calling gtk_progess_bar_set_text()
3868 again with NULL as second argument.</para>
3869
3870 <para>The current text setting of a progressbar can be retrieved with the 
3871 following function. Do not free the returned string.</para>
3872
3873 <programlisting role="C">
3874 const gchar *gtk_progress_bar_get_text( GtkProgressBar *pbar );
3875 </programlisting>
3876
3877 <para>Progress Bars are usually used with timeouts or other such functions
3878 (see section on <link linkend="ch-Timeouts">Timeouts, I/O and Idle Functions</link>) 
3879 to give the illusion of multitasking. All will employ the
3880 gtk_progress_bar_set_fraction() or gtk_progress_bar_pulse() functions in the 
3881 same manner.</para>
3882
3883 <para>Here is an example of the progress bar, updated using timeouts. This
3884 code also shows you how to reset the Progress Bar.</para>
3885
3886 <para>
3887 <inlinemediaobject>
3888 <imageobject>
3889 <imagedata fileref="images/progressbar.png" format="png">
3890 </imageobject>
3891 </inlinemediaobject>
3892 </para>
3893
3894 <programlisting role="C">
3895 <!-- example-start progressbar progressbar.c -->
3896
3897 #include &lt;gtk/gtk.h&gt;
3898
3899 typedef struct _ProgressData {
3900   GtkWidget *window;
3901   GtkWidget *pbar;
3902   int timer;
3903   gboolean activity_mode;
3904 } ProgressData;
3905
3906 /* Update the value of the progress bar so that we get
3907  * some movement */
3908 static gboolean progress_timeout( gpointer data )
3909 {
3910   ProgressData *pdata = (ProgressData *)data;
3911   gdouble new_val;
3912   
3913   if (pdata-&gt;activity_mode) 
3914     gtk_progress_bar_pulse (GTK_PROGRESS_BAR (pdata-&gt;pbar));
3915   else 
3916     {
3917       /* Calculate the value of the progress bar using the
3918        * value range set in the adjustment object */
3919       
3920       new_val = gtk_progress_bar_get_fraction (GTK_PROGRESS_BAR (pdata-&gt;pbar)) + 0.01;
3921       
3922       if (new_val &gt; 1.0)
3923         new_val = 0.0;
3924       
3925       /* Set the new value */
3926       gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (pdata-&gt;pbar), new_val);
3927     }
3928   
3929   /* As this is a timeout function, return TRUE so that it
3930    * continues to get called */
3931   return TRUE;
3932
3933
3934 /* Callback that toggles the text display within the progress bar trough */
3935 static void toggle_show_text( GtkWidget    *widget,
3936                               ProgressData *pdata )
3937 {
3938   const gchar *text;
3939   
3940   text = gtk_progress_bar_get_text (GTK_PROGRESS_BAR (pdata-&gt;pbar));
3941   if (text &amp;&amp; *text)
3942     gtk_progress_bar_set_text (GTK_PROGRESS_BAR (pdata-&gt;pbar), "");
3943   else 
3944     gtk_progress_bar_set_text (GTK_PROGRESS_BAR (pdata-&gt;pbar), "some text");
3945 }
3946
3947 /* Callback that toggles the activity mode of the progress bar */
3948 static void toggle_activity_mode( GtkWidget    *widget,
3949                                   ProgressData *pdata )
3950 {
3951   pdata-&gt;activity_mode = !pdata-&gt;activity_mode;
3952   if (pdata-&gt;activity_mode) 
3953       gtk_progress_bar_pulse (GTK_PROGRESS_BAR (pdata-&gt;pbar));
3954   else
3955       gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (pdata-&gt;pbar), 0.0);
3956 }
3957
3958  
3959 /* Callback that toggles the orientation of the progress bar */
3960 static void toggle_orientation( GtkWidget    *widget,
3961                                 ProgressData *pdata )
3962 {
3963   switch (gtk_progress_bar_get_orientation (GTK_PROGRESS_BAR (pdata-&gt;pbar))) {
3964   case GTK_PROGRESS_LEFT_TO_RIGHT:
3965     gtk_progress_bar_set_orientation (GTK_PROGRESS_BAR (pdata-&gt;pbar), 
3966                                       GTK_PROGRESS_RIGHT_TO_LEFT);
3967     break;
3968   case GTK_PROGRESS_RIGHT_TO_LEFT:
3969     gtk_progress_bar_set_orientation (GTK_PROGRESS_BAR (pdata-&gt;pbar), 
3970                                       GTK_PROGRESS_LEFT_TO_RIGHT);
3971     break;
3972   default:;
3973     /* do nothing */
3974   }
3975 }
3976
3977  
3978 /* Clean up allocated memory and remove the timer */
3979 static void destroy_progress( GtkWidget    *widget,
3980                               ProgressData *pdata)
3981 {
3982     g_source_remove (pdata-&gt;timer);
3983     pdata-&gt;timer = 0;
3984     pdata-&gt;window = NULL;
3985     g_free (pdata);
3986     gtk_main_quit ();
3987 }
3988
3989 int main( int   argc,
3990           char *argv[])
3991 {
3992     ProgressData *pdata;
3993     GtkWidget *align;
3994     GtkWidget *separator;
3995     GtkWidget *table;
3996     GtkWidget *button;
3997     GtkWidget *check;
3998     GtkWidget *vbox;
3999
4000     gtk_init (&amp;argc, &amp;argv);
4001
4002     /* Allocate memory for the data that is passed to the callbacks */
4003     pdata = g_malloc (sizeof (ProgressData));
4004   
4005     pdata-&gt;window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
4006     gtk_window_set_resizable (GTK_WINDOW (pdata-&gt;window), TRUE);
4007
4008     g_signal_connect (G_OBJECT (pdata-&gt;window), "destroy",
4009                       G_CALLBACK (destroy_progress),
4010                       (gpointer) pdata);
4011     gtk_window_set_title (GTK_WINDOW (pdata-&gt;window), "GtkProgressBar");
4012     gtk_container_set_border_width (GTK_CONTAINER (pdata-&gt;window), 0);
4013
4014     vbox = gtk_vbox_new (FALSE, 5);
4015     gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
4016     gtk_container_add (GTK_CONTAINER (pdata-&gt;window), vbox);
4017     gtk_widget_show (vbox);
4018   
4019     /* Create a centering alignment object */
4020     align = gtk_alignment_new (0.5, 0.5, 0, 0);
4021     gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 5);
4022     gtk_widget_show (align);
4023
4024     /* Create the GtkProgressBar */
4025     pdata-&gt;pbar = gtk_progress_bar_new ();
4026     pdata-&gt;activity_mode = FALSE;
4027
4028     gtk_container_add (GTK_CONTAINER (align), pdata-&gt;pbar);
4029     gtk_widget_show (pdata-&gt;pbar);
4030
4031     /* Add a timer callback to update the value of the progress bar */
4032     pdata-&gt;timer = g_timeout_add (100, progress_timeout, pdata);
4033
4034     separator = gtk_hseparator_new ();
4035     gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, 0);
4036     gtk_widget_show (separator);
4037
4038     /* rows, columns, homogeneous */
4039     table = gtk_table_new (2, 3, FALSE);
4040     gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0);
4041     gtk_widget_show (table);
4042
4043     /* Add a check button to select displaying of the trough text */
4044     check = gtk_check_button_new_with_label ("Show text");
4045     gtk_table_attach (GTK_TABLE (table), check, 0, 1, 0, 1,
4046                       GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
4047                       5, 5);
4048     g_signal_connect (G_OBJECT (check), "clicked",
4049                       G_CALLBACK (toggle_show_text),
4050                       (gpointer) pdata);
4051     gtk_widget_show (check);
4052
4053     /* Add a check button to toggle activity mode */
4054     check = gtk_check_button_new_with_label ("Activity mode");
4055     gtk_table_attach (GTK_TABLE (table), check, 0, 1, 1, 2,
4056                       GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
4057                       5, 5);
4058     g_signal_connect (G_OBJECT (check), "clicked",
4059                       G_CALLBACK (toggle_activity_mode),
4060                       (gpointer) pdata);
4061     gtk_widget_show (check);
4062
4063     /* Add a check button to toggle orientation */
4064     check = gtk_check_button_new_with_label ("Right to Left");
4065     gtk_table_attach (GTK_TABLE (table), check, 0, 1, 2, 3,
4066                       GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
4067                       5, 5);
4068     g_signal_connect (G_OBJECT (check), "clicked",
4069                       G_CALLBACK (toggle_orientation),
4070                       (gpointer) pdata);
4071     gtk_widget_show (check);
4072
4073     /* Add a button to exit the program */
4074     button = gtk_button_new_with_label ("close");
4075     g_signal_connect_swapped (G_OBJECT (button), "clicked",
4076                               G_CALLBACK (gtk_widget_destroy),
4077                               G_OBJECT (pdata-&gt;window));
4078     gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
4079
4080     /* This makes it so the button is the default. */
4081     GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
4082
4083     /* This grabs this button to be the default button. Simply hitting
4084      * the "Enter" key will cause this button to activate. */
4085     gtk_widget_grab_default (button);
4086     gtk_widget_show (button);
4087
4088     gtk_widget_show (pdata-&gt;window);
4089
4090     gtk_main ();
4091     
4092     return 0;
4093 }
4094 <!-- example-end -->
4095 </programlisting>
4096
4097 </sect1>
4098
4099 <!-- ----------------------------------------------------------------- -->
4100 <sect1 id="sec-Dialogs">
4101 <title>Dialogs</title>
4102
4103 <para>The Dialog widget is very simple, and is actually just a window with a
4104 few things pre-packed into it for you. The structure for a Dialog is:</para>
4105
4106 <programlisting role="C">
4107 struct GtkDialog
4108 {
4109       GtkWindow window;
4110     
4111       GtkWidget *vbox;
4112       GtkWidget *action_area;
4113 };
4114 </programlisting>
4115
4116 <para>So you see, it simply creates a window, and then packs a vbox into the
4117 top, which contains a separator and then an hbox called the
4118 "action_area".</para>
4119
4120 <para>The Dialog widget can be used for pop-up messages to the user, and
4121 other similar tasks. There are two functions to create a new Dialog.</para>
4122
4123 <programlisting role="C">
4124 GtkWidget *gtk_dialog_new( void );
4125
4126 GtkWidget *gtk_dialog_new_with_buttons( const gchar    *title,
4127                                         GtkWindow      *parent,
4128                                         GtkDialogFlags  flags, 
4129                                         const gchar    *first_button_text,
4130                                         ... );
4131 </programlisting>
4132
4133 <para>The first function will create an empty dialog, and it is now up to you to use
4134  it. You could pack a button in the action_area by doing something like this:</para>
4135
4136 <programlisting role="C">
4137     button = ...
4138     gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area),
4139                         button, TRUE, TRUE, 0);
4140     gtk_widget_show (button);
4141 </programlisting>
4142
4143 <para>And you could add to the vbox area by packing, for instance, a label 
4144 in it, try something like this:</para>
4145
4146 <programlisting role="C">
4147     label = gtk_label_new ("Dialogs are groovy");
4148     gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox),
4149                         label, TRUE, TRUE, 0);
4150     gtk_widget_show (label);
4151 </programlisting>
4152
4153 <para>As an example in using the dialog box, you could put two buttons in
4154 the action_area, a Cancel button and an Ok button, and a label in the
4155 vbox area, asking the user a question or giving an error etc. Then
4156 you could attach a different signal to each of the buttons and perform
4157 the operation the user selects.</para>
4158
4159 <para>If the simple functionality provided by the default vertical and
4160 horizontal boxes in the two areas doesn't give you enough control for
4161 your application, then you can simply pack another layout widget into
4162 the boxes provided. For example, you could pack a table into the
4163 vertical box.</para>
4164
4165 <para>The more complicated _new_with_buttons() variant allows to set one or
4166 more of the following flags.</para>
4167
4168 <variablelist>
4169 <varlistentry>
4170 <term><literal>GTK_DIALOG_MODAL</literal></term>
4171 <listitem><para>make the dialog modal.
4172 </para></listitem>
4173 </varlistentry>
4174 <varlistentry>
4175 <term><literal>GTK_DIALOG_DESTROY_WITH_PARENT</literal></term>
4176 <listitem><para>ensures that the dialog window is destroyed together with the specified
4177 parent.</para></listitem>
4178 </varlistentry>
4179 <varlistentry>
4180 <term><literal>GTK_DIALOG_NO_SEPARATOR</literal></term>
4181 <listitem><para>omits the separator between the vbox and the action_area.
4182 </para></listitem>
4183 </varlistentry>
4184 </variablelist>
4185 </sect1>
4186
4187 <!-- ----------------------------------------------------------------- -->
4188 <sect1 id="sec-Rulers">
4189 <title>Rulers</title>
4190
4191 <para>Ruler widgets are used to indicate the location of the mouse pointer
4192 in a given window. A window can have a vertical ruler spanning across
4193 the height and a horizontal ruler spanning down the width. A small
4194 triangular indicator on the ruler shows the exact location of the
4195 pointer relative to the ruler.</para>
4196
4197 <para>A ruler must first be created. Horizontal and vertical rulers are
4198 created using</para>
4199
4200 <programlisting role="C">
4201 GtkWidget *gtk_hruler_new( void );    /* horizontal ruler */
4202
4203 GtkWidget *gtk_vruler_new( void );    /* vertical ruler   */
4204 </programlisting>
4205
4206 <para>Once a ruler is created, we can define the unit of measurement. Units
4207 of measure for rulers can be <literal>GTK_PIXELS</literal>, <literal>GTK_INCHES</literal> or
4208 <literal>GTK_CENTIMETERS</literal>. This is set using</para>
4209
4210 <programlisting role="C">
4211 void gtk_ruler_set_metric( GtkRuler      *ruler,
4212                            GtkMetricType  metric );
4213 </programlisting>
4214
4215 <para>The default measure is <literal>GTK_PIXELS</literal>.</para>
4216
4217 <programlisting role="C">
4218     gtk_ruler_set_metric( GTK_RULER(ruler), GTK_PIXELS );
4219 </programlisting>
4220
4221 <para>Other important characteristics of a ruler are how to mark the units
4222 of scale and where the position indicator is initially placed. These
4223 are set for a ruler using</para>
4224
4225 <programlisting role="C">
4226 void gtk_ruler_set_range( GtkRuler *ruler,
4227                           gdouble   lower,
4228                           gdouble   upper,
4229                           gdouble   position,
4230                           gdouble   max_size );
4231 </programlisting>
4232
4233 <para>The lower and upper arguments define the extent of the ruler, and
4234 max_size is the largest possible number that will be displayed.
4235 Position defines the initial position of the pointer indicator within
4236 the ruler.</para>
4237
4238 <para>A vertical ruler can span an 800 pixel wide window thus</para>
4239
4240 <programlisting role="C">
4241     gtk_ruler_set_range( GTK_RULER(vruler), 0, 800, 0, 800);
4242 </programlisting>
4243
4244 <para>The markings displayed on the ruler will be from 0 to 800, with a
4245 number for every 100 pixels. If instead we wanted the ruler to range
4246 from 7 to 16, we would code</para>
4247
4248 <programlisting role="C">
4249     gtk_ruler_set_range( GTK_RULER(vruler), 7, 16, 0, 20);
4250 </programlisting>
4251
4252 <para>The indicator on the ruler is a small triangular mark that indicates
4253 the position of the pointer relative to the ruler. If the ruler is
4254 used to follow the mouse pointer, the motion_notify_event signal
4255 should be connected to the motion_notify_event method of the ruler.
4256 To follow all mouse movements within a window area, we would use</para>
4257
4258 <programlisting role="C">
4259 #define EVENT_METHOD(i, x) GTK_WIDGET_GET_CLASS(i)->x
4260
4261     g_signal_connect_swapped (G_OBJECT (area), "motion_notify_event",
4262            G_CALLBACK (EVENT_METHOD (ruler, motion_notify_event)),
4263            G_OBJECT (ruler));
4264 </programlisting>
4265
4266 <para>The following example creates a drawing area with a horizontal ruler
4267 above it and a vertical ruler to the left of it. The size of the
4268 drawing area is 600 pixels wide by 400 pixels high. The horizontal
4269 ruler spans from 7 to 13 with a mark every 100 pixels, while the
4270 vertical ruler spans from 0 to 400 with a mark every 100 pixels.
4271 Placement of the drawing area and the rulers is done using a table.</para>
4272
4273 <para>
4274 <inlinemediaobject>
4275 <imageobject>
4276 <imagedata fileref="images/rulers.png" format="png">
4277 </imageobject>
4278 </inlinemediaobject>
4279 </para>
4280
4281 <programlisting role="C">
4282 <!-- example-start rulers rulers.c -->
4283
4284 #include &lt;gtk/gtk.h&gt;
4285
4286 #define EVENT_METHOD(i, x) GTK_WIDGET_GET_CLASS(i)-&gt;x
4287
4288 #define XSIZE  600
4289 #define YSIZE  400
4290
4291 /* This routine gets control when the close button is clicked */
4292 static gboolean close_application( GtkWidget *widget,
4293                                    GdkEvent  *event,
4294                                    gpointer   data )
4295 {
4296     gtk_main_quit ();
4297     return FALSE;
4298 }
4299
4300 /* The main routine */
4301 int main( int   argc,
4302           char *argv[] ) {
4303     GtkWidget *window, *table, *area, *hrule, *vrule;
4304
4305     /* Initialize GTK and create the main window */
4306     gtk_init (&amp;argc, &amp;argv);
4307
4308     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
4309     g_signal_connect (G_OBJECT (window), "delete_event",
4310                       G_CALLBACK (close_application), NULL);
4311     gtk_container_set_border_width (GTK_CONTAINER (window), 10);
4312
4313     /* Create a table for placing the ruler and the drawing area */
4314     table = gtk_table_new (3, 2, FALSE);
4315     gtk_container_add (GTK_CONTAINER (window), table);
4316
4317     area = gtk_drawing_area_new ();
4318     gtk_widget_set_size_request (GTK_WIDGET (area), XSIZE, YSIZE);
4319     gtk_table_attach (GTK_TABLE (table), area, 1, 2, 1, 2,
4320                       GTK_EXPAND|GTK_FILL, GTK_FILL, 0, 0);
4321     gtk_widget_set_events (area, GDK_POINTER_MOTION_MASK |
4322                                  GDK_POINTER_MOTION_HINT_MASK);
4323
4324     /* The horizontal ruler goes on top. As the mouse moves across the
4325      * drawing area, a motion_notify_event is passed to the
4326      * appropriate event handler for the ruler. */
4327     hrule = gtk_hruler_new ();
4328     gtk_ruler_set_metric (GTK_RULER (hrule), GTK_PIXELS);
4329     gtk_ruler_set_range (GTK_RULER (hrule), 7, 13, 0, 20);
4330     g_signal_connect_swapped (G_OBJECT (area), "motion_notify_event",
4331                               G_CALLBACK (EVENT_METHOD (hrule, motion_notify_event)),
4332                               G_OBJECT (hrule));
4333     gtk_table_attach (GTK_TABLE (table), hrule, 1, 2, 0, 1,
4334                       GTK_EXPAND|GTK_SHRINK|GTK_FILL, GTK_FILL, 0, 0);
4335     
4336     /* The vertical ruler goes on the left. As the mouse moves across
4337      * the drawing area, a motion_notify_event is passed to the
4338      * appropriate event handler for the ruler. */
4339     vrule = gtk_vruler_new ();
4340     gtk_ruler_set_metric (GTK_RULER (vrule), GTK_PIXELS);
4341     gtk_ruler_set_range (GTK_RULER (vrule), 0, YSIZE, 10, YSIZE );
4342     g_signal_connect_swapped (G_OBJECT (area), "motion_notify_event",
4343                               G_CALLBACK (EVENT_METHOD (vrule, motion_notify_event)),
4344                               G_OBJECT (vrule));
4345     gtk_table_attach (GTK_TABLE (table), vrule, 0, 1, 1, 2,
4346                       GTK_FILL, GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0);
4347
4348     /* Now show everything */
4349     gtk_widget_show (area);
4350     gtk_widget_show (hrule);
4351     gtk_widget_show (vrule);
4352     gtk_widget_show (table);
4353     gtk_widget_show (window);
4354     gtk_main ();
4355
4356     return 0;
4357 }
4358 <!-- example-end -->
4359 </programlisting>
4360
4361 </sect1>
4362
4363 <!-- ----------------------------------------------------------------- -->
4364 <sect1 id="sec-Statusbars">
4365 <title>Statusbars</title>
4366
4367 <para>Statusbars are simple widgets used to display a text message. They
4368 keep a stack of the messages pushed onto them, so that popping the
4369 current message will re-display the previous text message.</para>
4370
4371 <para>In order to allow different parts of an application to use the same
4372 statusbar to display messages, the statusbar widget issues Context
4373 Identifiers which are used to identify different "users". The message
4374 on top of the stack is the one displayed, no matter what context it is
4375 in. Messages are stacked in last-in-first-out order, not context
4376 identifier order.</para>
4377
4378 <para>A statusbar is created with a call to:</para>
4379
4380 <programlisting role="C">
4381 GtkWidget *gtk_statusbar_new( void );
4382 </programlisting>
4383
4384 <para>A new Context Identifier is requested using a call to the following 
4385 function with a short textual description of the context:</para>
4386
4387 <programlisting role="C">
4388 guint gtk_statusbar_get_context_id( GtkStatusbar *statusbar,
4389                                     const gchar  *context_description );
4390 </programlisting>
4391
4392 <para>There are three functions that can operate on statusbars:</para>
4393
4394 <programlisting role="C">
4395 guint gtk_statusbar_push( GtkStatusbar *statusbar,
4396                           guint         context_id,
4397                           const gchar  *text );
4398
4399 void gtk_statusbar_pop( GtkStatusbar *statusbar)
4400                         guint         context_id );
4401
4402 void gtk_statusbar_remove( GtkStatusbar *statusbar,
4403                            guint         context_id,
4404                            guint         message_id ); 
4405 </programlisting>
4406
4407 <para>The first, gtk_statusbar_push(), is used to add a new message to the
4408 statusbar.  It returns a Message Identifier, which can be passed later
4409 to the function gtk_statusbar_remove to remove the message with the
4410 given Message and Context Identifiers from the statusbar's stack.</para>
4411
4412 <para>The function gtk_statusbar_pop() removes the message highest in the
4413 stack with the given Context Identifier.</para>
4414
4415 <para>In addition to messages, statusbars may also display a resize grip, which 
4416 can be dragged with the mouse to resize the toplevel window containing the statusbar,
4417 similar to dragging the window frame. The following functions control the display
4418 of the resize grip.</para>
4419
4420 <programlisting role="C">
4421 void     gtk_statusbar_set_has_resize_grip( GtkStatusbar *statusbar,
4422                                             gboolean      setting );
4423
4424 gboolean gtk_statusbar_get_has_resize_grip( GtkStatusbar *statusbar );
4425 </programlisting>
4426
4427 <para>The following example creates a statusbar and two buttons, one for
4428 pushing items onto the statusbar, and one for popping the last item
4429 back off.</para>
4430
4431 <para>
4432 <inlinemediaobject>
4433 <imageobject>
4434 <imagedata fileref="images/statusbar.png" format="png">
4435 </imageobject>
4436 </inlinemediaobject>
4437 </para>
4438
4439 <programlisting role="C">
4440 <!-- example-start statusbar statusbar.c -->
4441
4442 #include &lt;stdlib.h&gt;
4443 #include &lt;gtk/gtk.h&gt;
4444 #include &lt;glib.h&gt;
4445
4446 GtkWidget *status_bar;
4447
4448 static void push_item( GtkWidget *widget,
4449                        gpointer   data )
4450 {
4451   static int count = 1;
4452   gchar *buff;
4453
4454   buff = g_strdup_printf ("Item %d", count++);
4455   gtk_statusbar_push (GTK_STATUSBAR (status_bar), GPOINTER_TO_INT (data), buff);
4456   g_free (buff);
4457 }
4458
4459 static void pop_item( GtkWidget *widget,
4460                       gpointer   data )
4461 {
4462   gtk_statusbar_pop (GTK_STATUSBAR (status_bar), GPOINTER_TO_INT (data));
4463 }
4464
4465 int main( int   argc,
4466           char *argv[] )
4467 {
4468
4469     GtkWidget *window;
4470     GtkWidget *vbox;
4471     GtkWidget *button;
4472
4473     gint context_id;
4474
4475     gtk_init (&amp;argc, &amp;argv);
4476
4477     /* create a new window */
4478     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
4479     gtk_widget_set_size_request (GTK_WIDGET (window), 200, 100);
4480     gtk_window_set_title (GTK_WINDOW (window), "GTK Statusbar Example");
4481     g_signal_connect (G_OBJECT (window), "delete_event",
4482                       G_CALLBACK (exit), NULL);
4483  
4484     vbox = gtk_vbox_new (FALSE, 1);
4485     gtk_container_add (GTK_CONTAINER (window), vbox);
4486     gtk_widget_show (vbox);
4487           
4488     status_bar = gtk_statusbar_new ();      
4489     gtk_box_pack_start (GTK_BOX (vbox), status_bar, TRUE, TRUE, 0);
4490     gtk_widget_show (status_bar);
4491
4492     context_id = gtk_statusbar_get_context_id(
4493                           GTK_STATUSBAR (status_bar), "Statusbar example");
4494
4495     button = gtk_button_new_with_label ("push item");
4496     g_signal_connect (G_OBJECT (button), "clicked",
4497                       G_CALLBACK (push_item), GINT_TO_POINTER (context_id));
4498     gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 2);
4499     gtk_widget_show (button);              
4500
4501     button = gtk_button_new_with_label ("pop last item");
4502     g_signal_connect (G_OBJECT (button), "clicked",
4503                       G_CALLBACK (pop_item), GINT_TO_POINTER (context_id));
4504     gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 2);
4505     gtk_widget_show (button);
4506
4507     /* always display the window as the last step so it all splashes on
4508      * the screen at once. */
4509     gtk_widget_show (window);
4510
4511     gtk_main ();
4512
4513     return 0;
4514 }
4515 <!-- example-end -->
4516 </programlisting>
4517
4518 </sect1>
4519
4520 <!-- ----------------------------------------------------------------- -->
4521 <sect1 id="sec-TextEntries">
4522 <title>Text Entries</title>
4523
4524 <para>The Entry widget allows text to be typed and displayed in a single line
4525 text box. The text may be set with function calls that allow new text
4526 to replace, prepend or append the current contents of the Entry widget.</para>
4527
4528 <para>Create a new Entry widget with the following function.</para>
4529
4530 <programlisting role="C">
4531 GtkWidget *gtk_entry_new( void );
4532 </programlisting>
4533
4534 <para>The next function alters the text which is currently
4535 within the Entry widget.</para>
4536
4537 <programlisting role="C">
4538 void gtk_entry_set_text( GtkEntry    *entry,
4539                          const gchar *text );
4540 </programlisting>
4541
4542 <para>The function gtk_entry_set_text() sets the contents of the Entry widget,
4543 replacing the current contents. Note that the class Entry implements the Editable
4544 interface (yes, gobject supports Java-like interfaces) which contains some more
4545 functions for manipulating the contents.
4546  </para>
4547
4548 <para>The contents of the Entry can be retrieved by using a call to the
4549 following function. This is useful in the callback functions described below.</para>
4550
4551 <programlisting role="C">
4552 const gchar *gtk_entry_get_text( GtkEntry *entry );
4553 </programlisting>
4554
4555 <para>The value returned by this function is used internally, and must not
4556 be freed using either free() or g_free().</para>
4557
4558 <para>If we don't want the contents of the Entry to be changed by someone typing
4559 into it, we can change its editable state.</para>
4560
4561 <programlisting role="C">
4562 void gtk_editable_set_editable( GtkEditable *entry,
4563                                 gboolean     editable );
4564 </programlisting>
4565
4566 <para>The function above allows us to toggle the editable state of the
4567 Entry widget by passing in a TRUE or FALSE value for the <literal>editable</literal>
4568 argument.</para>
4569
4570 <para>If we are using the Entry where we don't want the text entered to be
4571 visible, for example when a password is being entered, we can use the
4572 following function, which also takes a boolean flag.</para>
4573
4574 <programlisting role="C">
4575 void gtk_entry_set_visibility( GtkEntry *entry,
4576                                gboolean  visible );
4577 </programlisting>
4578
4579 <para>A region of the text may be set as selected by using the following
4580 function. This would most often be used after setting some default
4581 text in an Entry, making it easy for the user to remove it.</para>
4582
4583 <programlisting role="C">
4584 void gtk_editable_select_region( GtkEditable *entry,
4585                                  gint         start,
4586                                  gint         end );
4587 </programlisting>
4588
4589 <para>If we want to catch when the user has entered text, we can connect to
4590 the <literal>activate</literal> or <literal>changed</literal> signal. Activate is raised when the
4591 user hits the enter key within the Entry widget. Changed is raised
4592 when the text changes at all, e.g., for every character entered or
4593 removed.</para>
4594
4595 <para>The following code is an example of using an Entry widget.</para>
4596
4597 <para>
4598 <inlinemediaobject>
4599 <imageobject>
4600 <imagedata fileref="images/entry.png" format="png">
4601 </imageobject>
4602 </inlinemediaobject>
4603 </para>
4604
4605 <programlisting role="C">
4606 <!-- example-start entry entry.c -->
4607
4608 #include &lt;stdio.h&gt;
4609 #include &lt;stdlib.h&gt;
4610 #include &lt;gtk/gtk.h&gt;
4611
4612 static void enter_callback( GtkWidget *widget,
4613                             GtkWidget *entry )
4614 {
4615   const gchar *entry_text;
4616   entry_text = gtk_entry_get_text (GTK_ENTRY (entry));
4617   printf ("Entry contents: %s\n", entry_text);
4618 }
4619
4620 static void entry_toggle_editable( GtkWidget *checkbutton,
4621                                    GtkWidget *entry )
4622 {
4623   gtk_editable_set_editable (GTK_EDITABLE (entry),
4624                              GTK_TOGGLE_BUTTON (checkbutton)-&gt;active);
4625 }
4626
4627 static void entry_toggle_visibility( GtkWidget *checkbutton,
4628                                      GtkWidget *entry )
4629 {
4630   gtk_entry_set_visibility (GTK_ENTRY (entry),
4631                             GTK_TOGGLE_BUTTON (checkbutton)-&gt;active);
4632 }
4633
4634 int main( int   argc,
4635           char *argv[] )
4636 {
4637
4638     GtkWidget *window;
4639     GtkWidget *vbox, *hbox;
4640     GtkWidget *entry;
4641     GtkWidget *button;
4642     GtkWidget *check;
4643     gint tmp_pos;
4644
4645     gtk_init (&amp;argc, &amp;argv);
4646
4647     /* create a new window */
4648     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
4649     gtk_widget_set_size_request (GTK_WIDGET (window), 200, 100);
4650     gtk_window_set_title (GTK_WINDOW (window), "GTK Entry");
4651     g_signal_connect (G_OBJECT (window), "destroy",
4652                       G_CALLBACK (gtk_main_quit), NULL);
4653     g_signal_connect_swapped (G_OBJECT (window), "delete_event",
4654                               G_CALLBACK (gtk_widget_destroy), 
4655                               G_OBJECT (window));
4656
4657     vbox = gtk_vbox_new (FALSE, 0);
4658     gtk_container_add (GTK_CONTAINER (window), vbox);
4659     gtk_widget_show (vbox);
4660
4661     entry = gtk_entry_new ();
4662     gtk_entry_set_max_length (GTK_ENTRY (entry), 50);
4663     g_signal_connect (G_OBJECT (entry), "activate",
4664                       G_CALLBACK (enter_callback),
4665                       (gpointer) entry);
4666     gtk_entry_set_text (GTK_ENTRY (entry), "hello");
4667     tmp_pos = GTK_ENTRY (entry)-&gt;text_length;
4668     gtk_editable_insert_text (GTK_EDITABLE (entry), " world", -1, &amp;tmp_pos);
4669     gtk_editable_select_region (GTK_EDITABLE (entry),
4670                                 0, GTK_ENTRY (entry)-&gt;text_length);
4671     gtk_box_pack_start (GTK_BOX (vbox), entry, TRUE, TRUE, 0);
4672     gtk_widget_show (entry);
4673
4674     hbox = gtk_hbox_new (FALSE, 0);
4675     gtk_container_add (GTK_CONTAINER (vbox), hbox);
4676     gtk_widget_show (hbox);
4677                                   
4678     check = gtk_check_button_new_with_label ("Editable");
4679     gtk_box_pack_start (GTK_BOX (hbox), check, TRUE, TRUE, 0);
4680     g_signal_connect (G_OBJECT (check), "toggled",
4681                       G_CALLBACK (entry_toggle_editable), (gpointer) entry);
4682     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), TRUE);
4683     gtk_widget_show (check);
4684     
4685     check = gtk_check_button_new_with_label ("Visible");
4686     gtk_box_pack_start (GTK_BOX (hbox), check, TRUE, TRUE, 0);
4687     g_signal_connect (G_OBJECT (check), "toggled",
4688                       G_CALLBACK (entry_toggle_visibility), (gpointer) entry);
4689     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), TRUE);
4690     gtk_widget_show (check);
4691                                    
4692     button = gtk_button_new_from_stock (GTK_STOCK_CLOSE);
4693     g_signal_connect_swapped (G_OBJECT (button), "clicked",
4694                               G_CALLBACK (gtk_widget_destroy),
4695                               G_OBJECT (window));
4696     gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);
4697     GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
4698     gtk_widget_grab_default (button);
4699     gtk_widget_show (button);
4700     
4701     gtk_widget_show (window);
4702
4703     gtk_main();
4704
4705     return 0;
4706 }
4707 <!-- example-end -->
4708 </programlisting>
4709
4710 </sect1>
4711
4712 <!-- ----------------------------------------------------------------- -->
4713 <sect1 id="sec-SpinButtons">
4714 <title>Spin Buttons</title>
4715
4716 <para>The Spin Button widget is generally used to allow the user to select a
4717 value from a range of numeric values. It consists of a text
4718 entry box with up and down arrow buttons attached to the
4719 side. Selecting one of the buttons causes the value to "spin" up and
4720 down the range of possible values. The entry box may also be edited
4721 directly to enter a specific value.</para>
4722
4723 <para>The Spin Button allows the value to have zero or a number of decimal
4724 places and to be incremented/decremented in configurable steps. The
4725 action of holding down one of the buttons optionally results in an
4726 acceleration of change in the value according to how long it is
4727 depressed.</para>
4728
4729 <para>The Spin Button uses an <link linkend="ch-Adjustments">Adjustment</link>
4730 object to hold information about the range of values that the spin
4731 button can take. This makes for a powerful Spin Button widget.</para>
4732
4733 <para>Recall that an adjustment widget is created with the following
4734 function, which illustrates the information that it holds:</para>
4735
4736 <programlisting role="C">
4737 GtkObject *gtk_adjustment_new( gdouble value,
4738                                gdouble lower,
4739                                gdouble upper,
4740                                gdouble step_increment,
4741                                gdouble page_increment,
4742                                gdouble page_size );
4743 </programlisting>
4744
4745 <para>These attributes of an Adjustment are used by the Spin Button in the
4746 following way:</para>
4747
4748 <itemizedlist>
4749 <listitem><simpara> <literal>value</literal>: initial value for the Spin Button</simpara>
4750 </listitem>
4751 <listitem><simpara> <literal>lower</literal>: lower range value</simpara>
4752 </listitem>
4753 <listitem><simpara> <literal>upper</literal>: upper range value</simpara>
4754 </listitem>
4755 <listitem><simpara> <literal>step_increment</literal>: value to increment/decrement when pressing
4756 mouse button 1 on a button</simpara>
4757 </listitem>
4758 <listitem><simpara> <literal>page_increment</literal>: value to increment/decrement when pressing
4759 mouse button 2 on a button</simpara>
4760 </listitem>
4761 <listitem><simpara> <literal>page_size</literal>: unused</simpara>
4762 </listitem>
4763 </itemizedlist>
4764
4765 <para>Additionally, mouse button 3 can be used to jump directly to the
4766 <literal>upper</literal> or <literal>lower</literal> values when used to select one of the
4767 buttons. Lets look at how to create a Spin Button:</para>
4768
4769 <programlisting role="C">
4770 GtkWidget *gtk_spin_button_new( GtkAdjustment *adjustment,
4771                                 gdouble        climb_rate,
4772                                 guint          digits );
4773 </programlisting>
4774
4775 <para>The <literal>climb_rate</literal> argument take a value between 0.0 and 1.0 and
4776 indicates the amount of acceleration that the Spin Button has. The
4777 <literal>digits</literal> argument specifies the number of decimal places to which
4778 the value will be displayed.</para>
4779
4780 <para>A Spin Button can be reconfigured after creation using the following
4781 function:</para>
4782
4783 <programlisting role="C">
4784 void gtk_spin_button_configure( GtkSpinButton *spin_button,
4785                                 GtkAdjustment *adjustment,
4786                                 gdouble        climb_rate,
4787                                 guint          digits );
4788 </programlisting>
4789
4790 <para>The <literal>spin_button</literal> argument specifies the Spin Button widget that is
4791 to be reconfigured. The other arguments are as specified above.</para>
4792
4793 <para>The adjustment can be set and retrieved independantly using the
4794 following two functions:</para>
4795
4796 <programlisting role="C">
4797 void gtk_spin_button_set_adjustment( GtkSpinButton  *spin_button,
4798                                      GtkAdjustment  *adjustment );
4799
4800 GtkAdjustment *gtk_spin_button_get_adjustment( GtkSpinButton *spin_button );
4801 </programlisting>
4802
4803 <para>The number of decimal places can also be altered using:</para>
4804
4805 <programlisting role="C">
4806 void gtk_spin_button_set_digits( GtkSpinButton *spin_button,
4807                                  guint          digits) ;
4808 </programlisting>
4809
4810 <para>The value that a Spin Button is currently displaying can be changed
4811 using the following function:</para>
4812
4813 <programlisting role="C">
4814 void gtk_spin_button_set_value( GtkSpinButton *spin_button,
4815                                 gdouble        value );
4816 </programlisting>
4817
4818 <para>The current value of a Spin Button can be retrieved as either a
4819 floating point or integer value with the following functions:</para>
4820
4821 <programlisting role="C">
4822 gdouble gtk_spin_button_get_value ( GtkSpinButton *spin_button );
4823
4824 gint gtk_spin_button_get_value_as_int( GtkSpinButton *spin_button );
4825 </programlisting>
4826
4827 <para>If you want to alter the value of a Spin Button relative to its current
4828 value, then the following function can be used:</para>
4829
4830 <programlisting role="C">
4831 void gtk_spin_button_spin( GtkSpinButton *spin_button,
4832                            GtkSpinType    direction,
4833                            gdouble        increment );
4834 </programlisting>
4835
4836 <para>The <literal>direction</literal> parameter can take one of the following values:</para>
4837
4838 <programlisting role="C">
4839   GTK_SPIN_STEP_FORWARD
4840   GTK_SPIN_STEP_BACKWARD
4841   GTK_SPIN_PAGE_FORWARD
4842   GTK_SPIN_PAGE_BACKWARD
4843   GTK_SPIN_HOME
4844   GTK_SPIN_END
4845   GTK_SPIN_USER_DEFINED
4846 </programlisting>
4847
4848 <para>This function packs in quite a bit of functionality, which I will
4849 attempt to clearly explain. Many of these settings use values from the
4850 Adjustment object that is associated with a Spin Button.</para>
4851
4852 <para><literal>GTK_SPIN_STEP_FORWARD</literal> and <literal>GTK_SPIN_STEP_BACKWARD</literal> change the
4853 value of the Spin Button by the amount specified by <literal>increment</literal>,
4854 unless <literal>increment</literal> is equal to 0, in which case the value is
4855 changed by the value of <literal>step_increment</literal> in theAdjustment.</para>
4856
4857 <para><literal>GTK_SPIN_PAGE_FORWARD</literal> and <literal>GTK_SPIN_PAGE_BACKWARD</literal> simply
4858 alter the value of the Spin Button by <literal>increment</literal>.</para>
4859
4860 <para><literal>GTK_SPIN_HOME</literal> sets the value of the Spin Button to the bottom of
4861 the Adjustments range.</para>
4862
4863 <para><literal>GTK_SPIN_END</literal> sets the value of the Spin Button to the top of the
4864 Adjustments range.</para>
4865
4866 <para><literal>GTK_SPIN_USER_DEFINED</literal> simply alters the value of the Spin Button
4867 by the specified amount.</para>
4868
4869 <para>We move away from functions for setting and retreving the range attributes
4870 of the Spin Button now, and move onto functions that affect the
4871 appearance and behaviour of the Spin Button widget itself.</para>
4872
4873 <para>The first of these functions is used to constrain the text box of the
4874 Spin Button such that it may only contain a numeric value. This
4875 prevents a user from typing anything other than numeric values into
4876 the text box of a Spin Button:</para>
4877
4878 <programlisting role="C">
4879 void gtk_spin_button_set_numeric( GtkSpinButton *spin_button,
4880                                   gboolean       numeric );
4881 </programlisting>
4882
4883 <para>You can set whether a Spin Button will wrap around between the upper
4884 and lower range values with the following function:</para>
4885
4886 <programlisting role="C">
4887 void gtk_spin_button_set_wrap( GtkSpinButton *spin_button,
4888                                gboolean       wrap );
4889 </programlisting>
4890
4891 <para>You can set a Spin Button to round the value to the nearest
4892 <literal>step_increment</literal>, which is set within the Adjustment object used
4893 with the Spin Button. This is accomplished with the following
4894 function:</para>
4895
4896 <programlisting role="C">
4897 void gtk_spin_button_set_snap_to_ticks( GtkSpinButton  *spin_button,
4898                                         gboolean        snap_to_ticks );
4899 </programlisting>
4900
4901 <para>The update policy of a Spin Button can be changed with the following
4902 function:</para>
4903
4904 <programlisting role="C">
4905 void gtk_spin_button_set_update_policy( GtkSpinButton  *spin_button,
4906                                         GtkSpinButtonUpdatePolicy policy );
4907 </programlisting>
4908
4909 <para>The possible values of <literal>policy</literal> are either <literal>GTK_UPDATE_ALWAYS</literal> or
4910 <literal>GTK_UPDATE_IF_VALID</literal>.</para>
4911
4912 <para>These policies affect the behavior of a Spin Button when parsing
4913 inserted text and syncing its value with the values of the
4914 Adjustment.</para>
4915
4916 <para>In the case of <literal>GTK_UPDATE_IF_VALID</literal> the Spin Button value only
4917 gets changed if the text input is a numeric value that is within the
4918 range specified by the Adjustment. Otherwise the text is reset to the
4919 current value.</para>
4920
4921 <para>In case of <literal>GTK_UPDATE_ALWAYS</literal> we ignore errors while converting
4922 text into a numeric value.</para>
4923
4924 <para>Finally, you can explicitly request that a Spin Button update itself:</para>
4925
4926 <programlisting role="C">
4927 void gtk_spin_button_update( GtkSpinButton  *spin_button );
4928 </programlisting>
4929
4930 <para>It's example time again.</para>
4931
4932 <para>
4933 <inlinemediaobject>
4934 <imageobject>
4935 <imagedata fileref="images/spinbutton.png" format="png">
4936 </imageobject>
4937 </inlinemediaobject>
4938 </para>
4939
4940 <programlisting role="C">
4941 <!-- example-start spinbutton spinbutton.c -->
4942
4943 #include &lt;stdio.h&gt;
4944 #include &lt;gtk/gtk.h&gt;
4945
4946 static GtkWidget *spinner1;
4947
4948 static void toggle_snap( GtkWidget     *widget,
4949                          GtkSpinButton *spin )
4950 {
4951   gtk_spin_button_set_snap_to_ticks (spin, GTK_TOGGLE_BUTTON (widget)-&gt;active);
4952 }
4953
4954 static void toggle_numeric( GtkWidget *widget,
4955                             GtkSpinButton *spin )
4956 {
4957   gtk_spin_button_set_numeric (spin, GTK_TOGGLE_BUTTON (widget)-&gt;active);
4958 }
4959
4960 static void change_digits( GtkWidget *widget,
4961                            GtkSpinButton *spin )
4962 {
4963   gtk_spin_button_set_digits (GTK_SPIN_BUTTON (spinner1),
4964                               gtk_spin_button_get_value_as_int (spin));
4965 }
4966
4967 static void get_value( GtkWidget *widget,
4968                        gpointer data )
4969 {
4970   gchar *buf;
4971   GtkLabel *label;
4972   GtkSpinButton *spin;
4973
4974   spin = GTK_SPIN_BUTTON (spinner1);
4975   label = GTK_LABEL (g_object_get_data (G_OBJECT (widget), "user_data"));
4976   if (GPOINTER_TO_INT (data) == 1)
4977     buf = g_strdup_printf ("%d", gtk_spin_button_get_value_as_int (spin));
4978   else
4979     buf = g_strdup_printf ("%0.*f", spin-&gt;digits,
4980                            gtk_spin_button_get_value (spin));
4981   gtk_label_set_text (label, buf);
4982   g_free (buf);
4983 }
4984
4985
4986 int main( int   argc,
4987           char *argv[] )
4988 {
4989   GtkWidget *window;
4990   GtkWidget *frame;
4991   GtkWidget *hbox;
4992   GtkWidget *main_vbox;
4993   GtkWidget *vbox;
4994   GtkWidget *vbox2;
4995   GtkWidget *spinner2;
4996   GtkWidget *spinner;
4997   GtkWidget *button;
4998   GtkWidget *label;
4999   GtkWidget *val_label;
5000   GtkAdjustment *adj;
5001
5002   /* Initialise GTK */
5003   gtk_init (&amp;argc, &amp;argv);
5004
5005   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
5006
5007   g_signal_connect (G_OBJECT (window), "destroy",
5008                     G_CALLBACK (gtk_main_quit),
5009                     NULL);
5010
5011   gtk_window_set_title (GTK_WINDOW (window), "Spin Button");
5012
5013   main_vbox = gtk_vbox_new (FALSE, 5);
5014   gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 10);
5015   gtk_container_add (GTK_CONTAINER (window), main_vbox);
5016   
5017   frame = gtk_frame_new ("Not accelerated");
5018   gtk_box_pack_start (GTK_BOX (main_vbox), frame, TRUE, TRUE, 0);
5019   
5020   vbox = gtk_vbox_new (FALSE, 0);
5021   gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
5022   gtk_container_add (GTK_CONTAINER (frame), vbox);
5023   
5024   /* Day, month, year spinners */
5025   
5026   hbox = gtk_hbox_new (FALSE, 0);
5027   gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 5);
5028   
5029   vbox2 = gtk_vbox_new (FALSE, 0);
5030   gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
5031   
5032   label = gtk_label_new ("Day :");
5033   gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
5034   gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, TRUE, 0);
5035   
5036   adj = (GtkAdjustment *) gtk_adjustment_new (1.0, 1.0, 31.0, 1.0,
5037                                               5.0, 0.0);
5038   spinner = gtk_spin_button_new (adj, 0, 0);
5039   gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner), TRUE);
5040   gtk_box_pack_start (GTK_BOX (vbox2), spinner, FALSE, TRUE, 0);
5041   
5042   vbox2 = gtk_vbox_new (FALSE, 0);
5043   gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
5044   
5045   label = gtk_label_new ("Month :");
5046   gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
5047   gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, TRUE, 0);
5048   
5049   adj = (GtkAdjustment *) gtk_adjustment_new (1.0, 1.0, 12.0, 1.0,
5050                                               5.0, 0.0);
5051   spinner = gtk_spin_button_new (adj, 0, 0);
5052   gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner), TRUE);
5053   gtk_box_pack_start (GTK_BOX (vbox2), spinner, FALSE, TRUE, 0);
5054   
5055   vbox2 = gtk_vbox_new (FALSE, 0);
5056   gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
5057   
5058   label = gtk_label_new ("Year :");
5059   gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
5060   gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, TRUE, 0);
5061   
5062   adj = (GtkAdjustment *) gtk_adjustment_new (1998.0, 0.0, 2100.0,
5063                                               1.0, 100.0, 0.0);
5064   spinner = gtk_spin_button_new (adj, 0, 0);
5065   gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner), FALSE);
5066   gtk_widget_set_size_request (spinner, 55, -1);
5067   gtk_box_pack_start (GTK_BOX (vbox2), spinner, FALSE, TRUE, 0);
5068   
5069   frame = gtk_frame_new ("Accelerated");
5070   gtk_box_pack_start (GTK_BOX (main_vbox), frame, TRUE, TRUE, 0);
5071   
5072   vbox = gtk_vbox_new (FALSE, 0);
5073   gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
5074   gtk_container_add (GTK_CONTAINER (frame), vbox);
5075   
5076   hbox = gtk_hbox_new (FALSE, 0);
5077   gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 5);
5078   
5079   vbox2 = gtk_vbox_new (FALSE, 0);
5080   gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
5081   
5082   label = gtk_label_new ("Value :");
5083   gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
5084   gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, TRUE, 0);
5085   
5086   adj = (GtkAdjustment *) gtk_adjustment_new (0.0, -10000.0, 10000.0,
5087                                               0.5, 100.0, 0.0);
5088   spinner1 = gtk_spin_button_new (adj, 1.0, 2);
5089   gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner1), TRUE);
5090   gtk_widget_set_size_request (spinner1, 100, -1);
5091   gtk_box_pack_start (GTK_BOX (vbox2), spinner1, FALSE, TRUE, 0);
5092   
5093   vbox2 = gtk_vbox_new (FALSE, 0);
5094   gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
5095   
5096   label = gtk_label_new ("Digits :");
5097   gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
5098   gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, TRUE, 0);
5099   
5100   adj = (GtkAdjustment *) gtk_adjustment_new (2, 1, 5, 1, 1, 0);
5101   spinner2 = gtk_spin_button_new (adj, 0.0, 0);
5102   gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner2), TRUE);
5103   g_signal_connect (G_OBJECT (adj), "value_changed",
5104                     G_CALLBACK (change_digits),
5105                     (gpointer) spinner2);
5106   gtk_box_pack_start (GTK_BOX (vbox2), spinner2, FALSE, TRUE, 0);
5107   
5108   hbox = gtk_hbox_new (FALSE, 0);
5109   gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 5);
5110   
5111   button = gtk_check_button_new_with_label ("Snap to 0.5-ticks");
5112   g_signal_connect (G_OBJECT (button), "clicked",
5113                     G_CALLBACK (toggle_snap),
5114                     (gpointer) spinner1);
5115   gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);
5116   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
5117   
5118   button = gtk_check_button_new_with_label ("Numeric only input mode");
5119   g_signal_connect (G_OBJECT (button), "clicked",
5120                     G_CALLBACK (toggle_numeric),
5121                     (gpointer) spinner1);
5122   gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);
5123   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
5124   
5125   val_label = gtk_label_new ("");
5126   
5127   hbox = gtk_hbox_new (FALSE, 0);
5128   gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 5);
5129   button = gtk_button_new_with_label ("Value as Int");
5130   g_object_set_data (G_OBJECT (button), "user_data", val_label);
5131   g_signal_connect (G_OBJECT (button), "clicked",
5132                     G_CALLBACK (get_value),
5133                     GINT_TO_POINTER (1));
5134   gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 5);
5135   
5136   button = gtk_button_new_with_label ("Value as Float");
5137   g_object_set_data (G_OBJECT (button), "user_data", val_label);
5138   g_signal_connect (G_OBJECT (button), "clicked",
5139                     G_CALLBACK (get_value),
5140                     GINT_TO_POINTER (2));
5141   gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 5);
5142   
5143   gtk_box_pack_start (GTK_BOX (vbox), val_label, TRUE, TRUE, 0);
5144   gtk_label_set_text (GTK_LABEL (val_label), "0");
5145   
5146   hbox = gtk_hbox_new (FALSE, 0);
5147   gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, TRUE, 0);
5148   
5149   button = gtk_button_new_with_label ("Close");
5150   g_signal_connect_swapped (G_OBJECT (button), "clicked",
5151                             G_CALLBACK (gtk_widget_destroy),
5152                             G_OBJECT (window));
5153   gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 5);
5154
5155   gtk_widget_show_all (window);
5156
5157   /* Enter the event loop */
5158   gtk_main ();
5159     
5160   return 0;
5161 }
5162
5163 <!-- example-end -->
5164 </programlisting>
5165
5166 </sect1>
5167
5168 <!-- ----------------------------------------------------------------- -->
5169 <sect1 id="sec-ComboBox">
5170 <title>Combo Box</title>
5171
5172 <para>The combo box is another fairly simple widget that is really just a
5173 collection of other widgets. From the user's point of view, the widget
5174 consists of a text entry box and a pull down menu from which the user
5175 can select one of a set of predefined entries. Alternatively, the user
5176 can type a different option directly into the text box.</para>
5177
5178 <para>The following extract from the structure that defines a Combo Box
5179 identifies several of the components:</para>
5180
5181 <programlisting role="C">
5182 struct _GtkCombo { 
5183         GtkHBox hbox; 
5184         GtkWidget *entry; 
5185         GtkWidget *button;
5186         GtkWidget *popup; 
5187         GtkWidget *popwin; 
5188         GtkWidget *list;
5189         ...  };
5190 </programlisting>
5191
5192 <para>As you can see, the Combo Box has two principal parts that you really
5193 care about: an entry and a list.</para>
5194
5195 <para>First off, to create a combo box, use:</para>
5196
5197 <programlisting role="C">
5198 GtkWidget *gtk_combo_new( void );
5199 </programlisting>
5200
5201 <para>Now, if you want to set the string in the entry section of the combo
5202 box, this is done by manipulating the <literal>entry</literal> widget directly:</para>
5203
5204 <programlisting role="C">
5205     gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (combo)->entry), "My String.");
5206 </programlisting>
5207
5208 <para>To set the values in the popdown list, one uses the function:</para>
5209
5210 <programlisting role="C">
5211 void gtk_combo_set_popdown_strings( GtkCombo *combo,
5212                                     GList    *strings );
5213 </programlisting>
5214
5215 <para>Before you can do this, you have to assemble a GList of the strings
5216 that you want. GList is a linked list implementation that is part of
5217 <link linkend="ch-GLib">GLib</link>, a library supporting GTK. For the
5218 moment, the quick and dirty explanation is that you need to set up a
5219 GList pointer, set it equal to NULL, then append strings to it with</para>
5220
5221 <programlisting role="C">
5222 GList *g_list_append( GList *glist, 
5223                       gpointer data );
5224 </programlisting>
5225
5226 <para>It is important that you set the initial GList pointer to NULL. The
5227 value returned from the g_list_append() function must be used as the new
5228 pointer to the GList.</para>
5229
5230 <para>Here's a typical code segment for creating a set of options:</para>
5231
5232 <programlisting role="C">
5233     GList *glist = NULL;
5234
5235     glist = g_list_append (glist, "String 1");
5236     glist = g_list_append (glist, "String 2");
5237     glist = g_list_append (glist, "String 3"); 
5238     glist = g_list_append (glist, "String 4");
5239
5240     gtk_combo_set_popdown_strings (GTK_COMBO (combo), glist);
5241     
5242     /* can free glist now, combo takes a copy */
5243 </programlisting>
5244
5245 <para>The combo widget makes a copy of the strings passed to it in the glist
5246 structure. As a result, you need to make sure you free the memory used
5247 by the list if that is appropriate for your application.</para>
5248
5249 <para>At this point you have a working combo box that has been set up.
5250 There are a few aspects of its behavior that you can change. These
5251 are accomplished with the functions: </para>
5252
5253 <programlisting role="C">
5254 void gtk_combo_set_use_arrows( GtkCombo *combo,
5255                                gboolean  val );
5256
5257 void gtk_combo_set_use_arrows_always( GtkCombo *combo,
5258                                       gboolean  val );
5259
5260 void gtk_combo_set_case_sensitive( GtkCombo *combo,
5261                                    gboolean  val );
5262 </programlisting>
5263
5264 <para>gtk_combo_set_use_arrows() lets the user change the value in the
5265 entry using the up/down arrow keys. This doesn't bring up the list, but
5266 rather replaces the current text in the entry with the next list entry
5267 (up or down, as your key choice indicates). It does this by searching
5268 in the list for the item corresponding to the current value in the
5269 entry and selecting the previous/next item accordingly. Usually in an
5270 entry the arrow keys are used to change focus (you can do that anyway
5271 using TAB). Note that when the current item is the last of the list
5272 and you press arrow-down it changes the focus (the same applies with
5273 the first item and arrow-up).</para>
5274
5275 <para>If the current value in the entry is not in the list, then the
5276 function of gtk_combo_set_use_arrows() is disabled.</para>
5277
5278 <para>gtk_combo_set_use_arrows_always() similarly allows the use the
5279 the up/down arrow keys to cycle through the choices in the dropdown
5280 list, except that it wraps around the values in the list, completely
5281 disabling the use of the up and down arrow keys for changing focus.</para>
5282
5283 <para>gtk_combo_set_case_sensitive() toggles whether or not GTK
5284 searches for entries in a case sensitive manner. This is used when the
5285 Combo widget is asked to find a value from the list using the current
5286 entry in the text box. This completion can be performed in either a
5287 case sensitive or insensitive manner, depending upon the use of this
5288 function. The Combo widget can also simply complete the current entry
5289 if the user presses the key combination MOD-1 and "Tab". MOD-1 is
5290 often mapped to the "Alt" key, by the <literal>xmodmap</literal> utility. Note,
5291 however that some window managers also use this key combination, which
5292 will override its use within GTK.</para>
5293
5294 <para>Now that we have a combo box, tailored to look and act how we want it,
5295 all that remains is being able to get data from the combo box. This is
5296 relatively straightforward. The majority of the time, all you are
5297 going to care about getting data from is the entry. The entry is
5298 accessed simply by <literal>GTK_ENTRY (GTK_COMBO (combo)->entry)</literal>. The
5299 two principal things that you are going to want to do with it are
5300 connect to the activate signal, which indicates that the user has
5301 pressed the Return or Enter key, and read the text. The first is
5302 accomplished using something like:</para>
5303
5304 <programlisting role="C">
5305     g_signal_connect (G_OBJECT (GTK_COMBO (combo)->entry), "activate",
5306                       G_CALLBACK (my_callback_function), (gpointer) my_data);
5307 </programlisting>
5308
5309 <para>Getting the text at any arbitrary time is accomplished by simply using
5310 the entry function:</para>
5311
5312 <programlisting role="C">
5313 gchar *gtk_entry_get_text( GtkEntry *entry );
5314 </programlisting>
5315
5316 <para>Such as:</para>
5317
5318 <programlisting role="C">
5319     gchar *string;
5320
5321     string = gtk_entry_get_text (GTK_ENTRY (GTK_COMBO (combo)->entry));
5322 </programlisting>
5323
5324 <para>That's about all there is to it. There is a function</para>
5325
5326 <programlisting role="C">
5327 void gtk_combo_disable_activate( GtkCombo *combo );
5328 </programlisting>
5329
5330 <para>that will disable the activate signal on the entry widget in the combo
5331 box. Personally, I can't think of why you'd want to use it, but it
5332 does exist.</para>
5333
5334 <!-- There is also a function to set the string on a particular item, void
5335 gtk_combo_set_item_string(GtkCombo *combo, GtkItem *item, const gchar
5336 *item_value), but this requires that you have a pointer to the
5337 appropriate Item. Frankly, I have no idea how to do that.
5338 -->
5339
5340 </sect1>
5341
5342 <!-- ----------------------------------------------------------------- -->
5343 <sect1 id="sec-Calendar">
5344 <title>Calendar</title>
5345
5346 <para>The Calendar widget is an effective way to display and retrieve
5347 monthly date related information. It is a very simple widget to create
5348 and work with.</para>
5349
5350 <para>Creating a GtkCalendar widget is a simple as: </para>
5351
5352 <programlisting role="C">
5353 GtkWidget *gtk_calendar_new( void );
5354 </programlisting>
5355
5356 <para>There might be times where you need to change a lot of information
5357 within this widget and the following functions allow you to make
5358 multiple change to a Calendar widget without the user seeing multiple
5359 on-screen updates.</para>
5360
5361 <programlisting role="C">
5362 void gtk_calendar_freeze( GtkCalendar *Calendar );
5363
5364 void gtk_calendar_thaw( GtkCalendar *Calendar );
5365 </programlisting>
5366
5367 <para>They work just like the freeze/thaw functions of every other
5368 widget.</para>
5369
5370 <para>The Calendar widget has a few options that allow you to change the way
5371 the widget both looks and operates by using the function</para>
5372
5373 <programlisting role="C">
5374 void gtk_calendar_display_options( GtkCalendar               *calendar,
5375                                    GtkCalendarDisplayOptions  flags );
5376 </programlisting>
5377
5378 <para>The <literal>flags</literal> argument can be formed by combining either of the
5379 following five options using the logical bitwise OR (|) operation:</para>
5380
5381 <variablelist>
5382 <varlistentry>
5383 <term><literal>GTK_CALENDAR_SHOW_HEADING</literal></term>
5384 <listitem><para>this option specifies that the month and year should be shown 
5385 when drawing the calendar.</para>
5386 </listitem>
5387 </varlistentry>
5388 <varlistentry>
5389 <term><literal>GTK_CALENDAR_SHOW_DAY_NAMES</literal></term>
5390 <listitem><para>this option specifies that the three letter descriptions should 
5391 be displayed for each day (eg Mon,Tue, etc.).</para>
5392 </listitem>
5393 </varlistentry>
5394 <varlistentry>
5395 <term><literal>GTK_CALENDAR_NO_MONTH_CHANGE</literal></term>
5396 <listitem><para>this option states that the user
5397 should not and can not change the currently displayed month. This can
5398 be good if you only need to display a particular month such as if you
5399 are displaying 12 calendar widgets for every month in a particular
5400 year.</para>
5401 </listitem>
5402 </varlistentry>
5403 <varlistentry>
5404 <term><literal>GTK_CALENDAR_SHOW_WEEK_NUMBERS</literal></term>
5405 <listitem><para>this option specifies that the
5406 number for each week should be displayed down the left side of the
5407 calendar. (eg. Jan 1 = Week 1,Dec 31 = Week 52).</para>
5408 </listitem>
5409 </varlistentry>
5410 <varlistentry>
5411 <term><literal>GTK_CALENDAR_WEEK_START_MONDAY</literal></term>
5412 <listitem><para>this option states that the
5413 calander week will start on Monday instead of Sunday which is the
5414 default. This only affects the order in which days are displayed from
5415 left to right.</para>
5416 </listitem>
5417 </varlistentry>
5418 </variablelist>
5419
5420 <para>The following functions are used to set the the currently displayed
5421 date:</para>
5422
5423 <programlisting role="C">
5424 gint gtk_calendar_select_month( GtkCalendar *calendar, 
5425                                 guint        month,
5426                                 guint        year );
5427
5428 void gtk_calendar_select_day( GtkCalendar *calendar,
5429                               guint        day );
5430 </programlisting>
5431
5432 <para>The return value from <literal>gtk_calendar_select_month()</literal> is a boolean
5433 value indicating whether the selection was successful.</para>
5434
5435 <para>With <literal>gtk_calendar_select_day()</literal> the specified day number is
5436 selected within the current month, if that is possible. A
5437 <literal>day</literal> value of 0 will deselect any current selection.</para>
5438
5439 <para>In addition to having a day selected, any number of days in the month
5440 may be "marked". A marked day is highlighted within the calendar
5441 display. The following functions are provided to manipulate marked
5442 days:</para>
5443
5444 <programlisting role="C">
5445 gint gtk_calendar_mark_day( GtkCalendar *calendar,
5446                             guint        day);
5447
5448 gint gtk_calendar_unmark_day( GtkCalendar *calendar,
5449                               guint        day);
5450
5451 void gtk_calendar_clear_marks( GtkCalendar *calendar);
5452 </programlisting>
5453
5454 <para>The currently marked days are stored within an array within the
5455 GtkCalendar structure. This array is 31 elements long so to test
5456 whether a particular day is currently marked, you need to access the
5457 corresponding element of the array (don't forget in C that array
5458 elements are numbered 0 to n-1). For example:</para>
5459
5460 <programlisting role="C">
5461     GtkCalendar *calendar;
5462     calendar = gtk_calendar_new ();
5463
5464     ...
5465
5466     /* Is day 7 marked? */
5467     if (calendar->marked_date[7-1])
5468        /* day is marked */
5469 </programlisting>
5470
5471 <para>Note that marks are persistent across month and year changes.</para>
5472
5473 <para>The final Calendar widget function is used to retrieve the currently
5474 selected date, month and/or year.</para>
5475
5476 <programlisting role="C">
5477 void gtk_calendar_get_date( GtkCalendar *calendar, 
5478                             guint       *year,
5479                             guint       *month,
5480                             guint       *day );
5481 </programlisting>
5482
5483 <para>This function requires you to pass the addresses of <literal>guint</literal>
5484 variables, into which the result will be placed. Passing <literal>NULL</literal> as
5485 a value will result in the corresponding value not being returned.</para>
5486
5487 <para>The Calendar widget can generate a number of signals indicating date
5488 selection and change. The names of these signals are self explanatory,
5489 and are:</para>
5490
5491 <itemizedlist>
5492 <listitem><simpara> <literal>month_changed</literal></simpara>
5493 </listitem>
5494 <listitem><simpara> <literal>day_selected</literal></simpara>
5495 </listitem>
5496 <listitem><simpara> <literal>day_selected_double_click</literal></simpara>
5497 </listitem>
5498 <listitem><simpara> <literal>prev_month</literal></simpara>
5499 </listitem>
5500 <listitem><simpara> <literal>next_month</literal></simpara>
5501 </listitem>
5502 <listitem><simpara> <literal>prev_year</literal></simpara>
5503 </listitem>
5504 <listitem><simpara> <literal>next_year</literal></simpara>
5505 </listitem>
5506 </itemizedlist>
5507
5508 <para>That just leaves us with the need to put all of this together into
5509 example code.</para>
5510
5511 <para>
5512 <inlinemediaobject>
5513 <imageobject>
5514 <imagedata fileref="images/calendar.png" format="png">
5515 </imageobject>
5516 </inlinemediaobject>
5517 </para>
5518
5519 <programlisting role="C">
5520 <!-- example-start calendar calendar.c -->
5521 /*
5522  * Copyright (C) 1998 Cesar Miquel, Shawn T. Amundson, Mattias Gr�nlund
5523  * Copyright (C) 2000 Tony Gale
5524  *
5525  * This program is free software; you can redistribute it and/or modify
5526  * it under the terms of the GNU General Public License as published by
5527  * the Free Software Foundation; either version 2 of the License, or
5528  * (at your option) any later version.
5529  *
5530  * This program is distributed in the hope that it will be useful,
5531  * but WITHOUT ANY WARRANTY; without even the implied warranty of
5532  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
5533  * GNU General Public License for more details.
5534  *
5535  * You should have received a copy of the GNU General Public License
5536  * along with this program; if not, write to the Free Software
5537  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
5538  */
5539
5540 #include &lt;stdio.h&gt;
5541 #include &lt;string.h&gt;
5542 #include &lt;gtk/gtk.h&gt;
5543
5544 #define DEF_PAD 10
5545 #define DEF_PAD_SMALL 5
5546
5547 #define TM_YEAR_BASE 1900
5548
5549 typedef struct _CalendarData {
5550   GtkWidget *flag_checkboxes[5];
5551   gboolean  settings[5];
5552   GtkWidget *font_dialog;
5553   GtkWidget *window;
5554   GtkWidget *prev2_sig;
5555   GtkWidget *prev_sig;
5556   GtkWidget *last_sig;
5557   GtkWidget *month;
5558 } CalendarData;
5559
5560 enum {
5561   calendar_show_header,
5562   calendar_show_days,
5563   calendar_month_change, 
5564   calendar_show_week,
5565   calendar_monday_first
5566 };
5567
5568 /*
5569  * GtkCalendar
5570  */
5571
5572 static void calendar_date_to_string( CalendarData *data,
5573                                      char         *buffer,
5574                                      gint          buff_len )
5575 {
5576   GDate date;
5577   guint year, month, day;
5578
5579   gtk_calendar_get_date (GTK_CALENDAR (data-&gt;window),
5580                          &amp;year, &amp;month, &amp;day);
5581   g_date_set_dmy (&amp;date, day, month + 1, year);
5582   g_date_strftime (buffer, buff_len - 1, "%x", &amp;date);
5583
5584 }
5585
5586 static void calendar_set_signal_strings( char         *sig_str,
5587                                          CalendarData *data )
5588 {
5589   const gchar *prev_sig;
5590
5591   prev_sig = gtk_label_get_text (GTK_LABEL (data-&gt;prev_sig));
5592   gtk_label_set_text (GTK_LABEL (data-&gt;prev2_sig), prev_sig);
5593
5594   prev_sig = gtk_label_get_text (GTK_LABEL (data-&gt;last_sig));
5595   gtk_label_set_text (GTK_LABEL (data-&gt;prev_sig), prev_sig);
5596   gtk_label_set_text (GTK_LABEL (data-&gt;last_sig), sig_str);
5597 }
5598
5599 static void calendar_month_changed( GtkWidget    *widget,
5600                                     CalendarData *data )
5601 {
5602   char buffer[256] = "month_changed: ";
5603
5604   calendar_date_to_string (data, buffer + 15, 256 - 15);
5605   calendar_set_signal_strings (buffer, data);
5606 }
5607
5608 static void calendar_day_selected( GtkWidget    *widget,
5609                                    CalendarData *data )
5610 {
5611   char buffer[256] = "day_selected: ";
5612
5613   calendar_date_to_string (data, buffer + 14, 256 - 14);
5614   calendar_set_signal_strings (buffer, data);
5615 }
5616
5617 static void calendar_day_selected_double_click ( GtkWidget    *widget,
5618                                                  CalendarData *data )
5619 {
5620   char buffer[256] = "day_selected_double_click: ";
5621   guint day;
5622
5623   calendar_date_to_string (data, buffer + 27, 256 - 27);
5624   calendar_set_signal_strings (buffer, data);
5625
5626   gtk_calendar_get_date (GTK_CALENDAR (data-&gt;window),
5627                          NULL, NULL, &amp;day);
5628
5629   if (GTK_CALENDAR (data-&gt;window)-&gt;marked_date[day-1] == 0) {
5630     gtk_calendar_mark_day (GTK_CALENDAR (data-&gt;window), day);
5631   } else { 
5632     gtk_calendar_unmark_day (GTK_CALENDAR (data-&gt;window), day);
5633   }
5634 }
5635
5636 static void calendar_prev_month( GtkWidget    *widget,
5637                                  CalendarData *data )
5638 {
5639   char buffer[256] = "prev_month: ";
5640
5641   calendar_date_to_string (data, buffer + 12, 256 - 12);
5642   calendar_set_signal_strings (buffer, data);
5643 }
5644
5645 static void calendar_next_month( GtkWidget    *widget,
5646                                  CalendarData *data )
5647 {
5648   char buffer[256] = "next_month: ";
5649
5650   calendar_date_to_string (data, buffer + 12, 256 - 12);
5651   calendar_set_signal_strings (buffer, data);
5652 }
5653
5654 static void calendar_prev_year( GtkWidget    *widget,
5655                                 CalendarData *data )
5656 {
5657   char buffer[256] = "prev_year: ";
5658
5659   calendar_date_to_string (data, buffer + 11, 256 - 11);
5660   calendar_set_signal_strings (buffer, data);
5661 }
5662
5663 static void calendar_next_year( GtkWidget    *widget,
5664                                 CalendarData *data )
5665 {
5666   char buffer[256] = "next_year: ";
5667
5668   calendar_date_to_string (data, buffer + 11, 256 - 11);
5669   calendar_set_signal_strings (buffer, data);
5670 }
5671
5672
5673 static void calendar_set_flags( CalendarData *calendar )
5674 {
5675   gint i;
5676   gint options = 0;
5677   for (i = 0;i &lt; 5; i++) 
5678     if (calendar-&gt;settings[i])
5679       {
5680         options = options + (1 &lt;&lt; i);
5681       }
5682   if (calendar-&gt;window)
5683     gtk_calendar_display_options (GTK_CALENDAR (calendar-&gt;window), options);
5684 }
5685
5686 static void calendar_toggle_flag( GtkWidget    *toggle,
5687                                   CalendarData *calendar)
5688 {
5689   gint i;
5690   gint j;
5691   j = 0;
5692   for (i = 0; i &lt; 5; i++)
5693     if (calendar-&gt;flag_checkboxes[i] == toggle)
5694       j = i;
5695
5696   calendar-&gt;settings[j] = !calendar-&gt;settings[j];
5697   calendar_set_flags (calendar);
5698   
5699 }
5700
5701 static void calendar_font_selection_ok( GtkWidget    *button,
5702                                         CalendarData *calendar )
5703 {
5704   GtkRcStyle *style;
5705   char *font_name;
5706
5707   if (calendar-&gt;window)
5708     {
5709       font_name = gtk_font_selection_dialog_get_font_name (GTK_FONT_SELECTION_DIALOG (calendar-&gt;font_dialog));
5710       if (font_name) 
5711         {
5712           style = gtk_rc_style_new ();
5713           pango_font_description_free (style-&gt;font_desc);
5714           style-&gt;font_desc = pango_font_description_from_string (font_name);
5715           gtk_widget_modify_style (calendar-&gt;window, style);
5716           g_free (font_name);
5717         }
5718     }
5719
5720   gtk_widget_destroy (calendar-&gt;font_dialog);
5721 }
5722
5723 static void calendar_select_font( GtkWidget    *button,
5724                                   CalendarData *calendar )
5725 {
5726   GtkWidget *window;
5727
5728   if (!calendar-&gt;font_dialog) {
5729     window = gtk_font_selection_dialog_new ("Font Selection Dialog");
5730     g_return_if_fail (GTK_IS_FONT_SELECTION_DIALOG (window));
5731     calendar-&gt;font_dialog = window;
5732     
5733     gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_MOUSE);
5734     
5735     g_signal_connect (window, "destroy",
5736                       G_CALLBACK (gtk_widget_destroyed),
5737                       &amp;calendar-&gt;font_dialog);
5738     
5739     g_signal_connect (GTK_FONT_SELECTION_DIALOG (window)-&gt;ok_button,
5740                       "clicked", G_CALLBACK (calendar_font_selection_ok),
5741                       calendar);
5742     g_signal_connect_swapped (GTK_FONT_SELECTION_DIALOG (window)-&gt;cancel_button,
5743                              "clicked", G_CALLBACK (gtk_widget_destroy), 
5744                              calendar-&gt;font_dialog);
5745   }
5746   window = calendar-&gt;font_dialog;
5747   if (!GTK_WIDGET_VISIBLE (window))
5748     gtk_widget_show (window);
5749   else
5750     gtk_widget_destroy (window);
5751
5752 }
5753
5754 static void create_calendar( void )
5755 {
5756   GtkWidget *window;
5757   GtkWidget *vbox, *vbox2, *vbox3;
5758   GtkWidget *hbox;
5759   GtkWidget *hbbox;
5760   GtkWidget *calendar;
5761   GtkWidget *toggle;
5762   GtkWidget *button;
5763   GtkWidget *frame;
5764   GtkWidget *separator;
5765   GtkWidget *label;
5766   GtkWidget *bbox;
5767   static CalendarData calendar_data;
5768   gint i;
5769   
5770   struct {
5771     char *label;
5772   } flags[] =
5773     {
5774       { "Show Heading" },
5775       { "Show Day Names" },
5776       { "No Month Change" },
5777       { "Show Week Numbers" },
5778       { "Week Start Monday" }
5779     };
5780
5781   
5782   calendar_data.window = NULL;
5783   calendar_data.font_dialog = NULL;
5784
5785   for (i = 0; i &lt; 5; i++) {
5786     calendar_data.settings[i] = 0;
5787   }
5788
5789   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
5790   gtk_window_set_title (GTK_WINDOW (window), "GtkCalendar Example");
5791   gtk_container_set_border_width (GTK_CONTAINER (window), 5);
5792   g_signal_connect (window, "destroy",
5793                     G_CALLBACK (gtk_main_quit),
5794                     NULL);
5795   g_signal_connect (window, "delete-event",
5796                     G_CALLBACK (gtk_false),
5797                     NULL);
5798   gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
5799
5800   vbox = gtk_vbox_new (FALSE, DEF_PAD);
5801   gtk_container_add (GTK_CONTAINER (window), vbox);
5802
5803   /*
5804    * The top part of the window, Calendar, flags and fontsel.
5805    */
5806
5807   hbox = gtk_hbox_new (FALSE, DEF_PAD);
5808   gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, DEF_PAD);
5809   hbbox = gtk_hbutton_box_new ();
5810   gtk_box_pack_start (GTK_BOX (hbox), hbbox, FALSE, FALSE, DEF_PAD);
5811   gtk_button_box_set_layout (GTK_BUTTON_BOX (hbbox), GTK_BUTTONBOX_SPREAD);
5812   gtk_box_set_spacing (GTK_BOX (hbbox), 5);
5813
5814   /* Calendar widget */
5815   frame = gtk_frame_new ("Calendar");
5816   gtk_box_pack_start(GTK_BOX (hbbox), frame, FALSE, TRUE, DEF_PAD);
5817   calendar=gtk_calendar_new ();
5818   calendar_data.window = calendar;
5819   calendar_set_flags (&amp;calendar_data);
5820   gtk_calendar_mark_day (GTK_CALENDAR (calendar), 19);  
5821   gtk_container_add (GTK_CONTAINER (frame), calendar);
5822   g_signal_connect (calendar, "month_changed", 
5823                     G_CALLBACK (calendar_month_changed),
5824                     &amp;calendar_data);
5825   g_signal_connect (calendar, "day_selected", 
5826                     G_CALLBACK (calendar_day_selected),
5827                     &amp;calendar_data);
5828   g_signal_connect (calendar, "day_selected_double_click", 
5829                     G_CALLBACK (calendar_day_selected_double_click),
5830                     &amp;calendar_data);
5831   g_signal_connect (calendar, "prev_month", 
5832                     G_CALLBACK (calendar_prev_month),
5833                     &amp;calendar_data);
5834   g_signal_connect (calendar, "next_month", 
5835                     G_CALLBACK (calendar_next_month),
5836                     &amp;calendar_data);
5837   g_signal_connect (calendar, "prev_year", 
5838                     G_CALLBACK (calendar_prev_year),
5839                     &amp;calendar_data);
5840   g_signal_connect (calendar, "next_year", 
5841                     G_CALLBACK (calendar_next_year),
5842                     &amp;calendar_data);
5843
5844
5845   separator = gtk_vseparator_new ();
5846   gtk_box_pack_start (GTK_BOX (hbox), separator, FALSE, TRUE, 0);
5847
5848   vbox2 = gtk_vbox_new (FALSE, DEF_PAD);
5849   gtk_box_pack_start (GTK_BOX (hbox), vbox2, FALSE, FALSE, DEF_PAD);
5850   
5851   /* Build the Right frame with the flags in */ 
5852
5853   frame = gtk_frame_new ("Flags");
5854   gtk_box_pack_start (GTK_BOX (vbox2), frame, TRUE, TRUE, DEF_PAD);
5855   vbox3 = gtk_vbox_new (TRUE, DEF_PAD_SMALL);
5856   gtk_container_add (GTK_CONTAINER (frame), vbox3);
5857
5858   for (i = 0; i &lt; 5; i++)
5859     {
5860       toggle = gtk_check_button_new_with_label (flags[i].label);
5861       g_signal_connect (toggle,
5862                         "toggled",
5863                         G_CALLBACK (calendar_toggle_flag),
5864                         &amp;calendar_data);
5865       gtk_box_pack_start (GTK_BOX (vbox3), toggle, TRUE, TRUE, 0);
5866       calendar_data.flag_checkboxes[i] = toggle;
5867     }
5868   /* Build the right font-button */ 
5869   button = gtk_button_new_with_label ("Font...");
5870   g_signal_connect (button,
5871                     "clicked",
5872                     G_CALLBACK (calendar_select_font),
5873                     &amp;calendar_data);
5874   gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0);
5875
5876   /*
5877    *  Build the Signal-event part.
5878    */
5879
5880   frame = gtk_frame_new ("Signal events");
5881   gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, DEF_PAD);
5882
5883   vbox2 = gtk_vbox_new (TRUE, DEF_PAD_SMALL);
5884   gtk_container_add (GTK_CONTAINER (frame), vbox2);
5885   
5886   hbox = gtk_hbox_new (FALSE, 3);
5887   gtk_box_pack_start (GTK_BOX (vbox2), hbox, FALSE, TRUE, 0);
5888   label = gtk_label_new ("Signal:");
5889   gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
5890   calendar_data.last_sig = gtk_label_new ("");
5891   gtk_box_pack_start (GTK_BOX (hbox), calendar_data.last_sig, FALSE, TRUE, 0);
5892
5893   hbox = gtk_hbox_new (FALSE, 3);
5894   gtk_box_pack_start (GTK_BOX (vbox2), hbox, FALSE, TRUE, 0);
5895   label = gtk_label_new ("Previous signal:");
5896   gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
5897   calendar_data.prev_sig = gtk_label_new ("");
5898   gtk_box_pack_start (GTK_BOX (hbox), calendar_data.prev_sig, FALSE, TRUE, 0);
5899
5900   hbox = gtk_hbox_new (FALSE, 3);
5901   gtk_box_pack_start (GTK_BOX (vbox2), hbox, FALSE, TRUE, 0);
5902   label = gtk_label_new ("Second previous signal:");
5903   gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
5904   calendar_data.prev2_sig = gtk_label_new ("");
5905   gtk_box_pack_start (GTK_BOX (hbox), calendar_data.prev2_sig, FALSE, TRUE, 0);
5906
5907   bbox = gtk_hbutton_box_new ();
5908   gtk_box_pack_start (GTK_BOX (vbox), bbox, FALSE, FALSE, 0);
5909   gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END);
5910
5911   button = gtk_button_new_with_label ("Close");
5912   g_signal_connect (button, "clicked", 
5913                     G_CALLBACK (gtk_main_quit), 
5914                     NULL);
5915   gtk_container_add (GTK_CONTAINER (bbox), button);
5916   GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
5917   gtk_widget_grab_default (button);
5918
5919   gtk_widget_show_all (window);
5920 }
5921
5922
5923 int main (int   argc,
5924           char *argv[])
5925 {
5926   gtk_init (&amp;argc, &amp;argv);
5927
5928   create_calendar ();
5929
5930   gtk_main ();
5931
5932   return 0;
5933 }
5934 <!-- example-end -->
5935 </programlisting>
5936
5937 </sect1>
5938
5939 <!-- ----------------------------------------------------------------- -->
5940 <sect1 id="sec-ColorSelection">
5941 <title>Color Selection</title>
5942
5943 <para>The color selection widget is, not surprisingly, a widget for
5944 interactive selection of colors. This composite widget lets the user
5945 select a color by manipulating RGB (Red, Green, Blue) and HSV (Hue,
5946 Saturation, Value) triples.  This is done either by adjusting single
5947 values with sliders or entries, or by picking the desired color from a
5948 hue-saturation wheel/value bar.  Optionally, the opacity of the color
5949 can also be set.</para>
5950
5951 <para>The color selection widget currently emits only one signal,
5952 "color_changed", which is emitted whenever the current color in the
5953 widget changes, either when the user changes it or if it's set
5954 explicitly through gtk_color_selection_set_color().</para>
5955
5956 <para>Lets have a look at what the color selection widget has to offer
5957 us. The widget comes in two flavours: GtkColorSelection and
5958 GtkColorSelectionDialog.</para>
5959
5960 <programlisting role="C">
5961 GtkWidget *gtk_color_selection_new( void );
5962 </programlisting>
5963         
5964 <para>You'll probably not be using this constructor directly. It creates an
5965 orphan ColorSelection widget which you'll have to parent
5966 yourself. The ColorSelection widget inherits from the VBox
5967 widget.</para>
5968
5969 <programlisting role="C">
5970 GtkWidget *gtk_color_selection_dialog_new( const gchar *title );
5971 </programlisting>
5972
5973 <para>This is the most common color selection constructor. It creates a
5974 ColorSelectionDialog. It consists of a Frame containing a
5975 ColorSelection widget, an HSeparator and an HBox with three buttons,
5976 "Ok", "Cancel" and "Help". You can reach these buttons by accessing
5977 the "ok_button", "cancel_button" and "help_button" widgets in the
5978 ColorSelectionDialog structure,
5979 (i.e., <literal>GTK_COLOR_SELECTION_DIALOG (colorseldialog)->ok_button</literal>)).</para>
5980
5981 <programlisting role="C">
5982 void gtk_color_selection_set_has_opacity_control( GtkColorSelection *colorsel,
5983                                                   gboolean           has_opacity );
5984 </programlisting>
5985
5986 <para>The color selection widget supports adjusting the opacity of a color
5987 (also known as the alpha channel). This is disabled by
5988 default. Calling this function with has_opacity set to TRUE enables
5989 opacity. Likewise, has_opacity set to FALSE will disable opacity.</para>
5990
5991 <programlisting role="C">
5992 void gtk_color_selection_set_current_color( GtkColorSelection *colorsel,
5993                                             GdkColor          *color );
5994
5995 void gtk_color_selection_set_current_alpha( GtkColorSelection *colorsel,
5996                                             guint16            alpha );
5997 </programlisting>
5998
5999 <para>You can set the current color explicitly by calling 
6000 gtk_color_selection_set_current_color() with a pointer to a GdkColor. 
6001 Setting the opacity (alpha channel) is done with 
6002 gtk_color_selection_set_current_alpha(). The alpha value should be between
6003 0 (fully transparent) and 65535 (fully opaque).
6004 </para>
6005
6006 <programlisting role="C">
6007 void gtk_color_selection_get_current_color( GtkColorSelection *colorsel,
6008                                             GdkColor *color );
6009
6010 void gtk_color_selection_get_current_alpha( GtkColorSelection *colorsel,
6011                                             guint16           *alpha );
6012 </programlisting>
6013
6014 <para>When you need to query the current color, typically when you've
6015 received a "color_changed" signal, you use these functions.</para>
6016
6017 <para><!-- Need to do a whole section on DnD - TRG
6018 Drag and drop
6019 -------------</para>
6020
6021 <para>The color sample areas (right under the hue-saturation wheel) supports
6022 drag and drop. The type of drag and drop is "application/x-color". The
6023 message data consists of an array of 4 (or 5 if opacity is enabled)
6024 gdouble values, where the value at position 0 is 0.0 (opacity on) or
6025 1.0 (opacity off) followed by the red, green and blue values at
6026 positions 1,2 and 3 respectively.  If opacity is enabled, the opacity
6027 is passed in the value at position 4.
6028 --></para>
6029
6030 <para>Here's a simple example demonstrating the use of the
6031 ColorSelectionDialog. The program displays a window containing a
6032 drawing area. Clicking on it opens a color selection dialog, and
6033 changing the color in the color selection dialog changes the
6034 background color.</para>
6035
6036 <para>
6037 <inlinemediaobject>
6038 <imageobject>
6039 <imagedata fileref="images/colorsel.png" format="png">
6040 </imageobject>
6041 </inlinemediaobject>
6042 </para>
6043
6044 <programlisting role="C">
6045 <!-- example-start colorsel colorsel.c -->
6046
6047 #include &lt;glib.h&gt;
6048 #include &lt;gdk/gdk.h&gt;
6049 #include &lt;gtk/gtk.h&gt;
6050
6051 GtkWidget *colorseldlg = NULL;
6052 GtkWidget *drawingarea = NULL;
6053 GdkColor color;
6054
6055 /* Color changed handler */
6056
6057 static void color_changed_cb( GtkWidget         *widget,
6058                               GtkColorSelection *colorsel )
6059 {
6060   GdkColor ncolor;
6061
6062   gtk_color_selection_get_current_color (colorsel, &amp;ncolor);
6063   gtk_widget_modify_bg (drawingarea, GTK_STATE_NORMAL, &amp;ncolor);       
6064 }
6065
6066 /* Drawingarea event handler */
6067
6068 static gboolean area_event( GtkWidget *widget,
6069                             GdkEvent  *event,
6070                             gpointer   client_data )
6071 {
6072   gint handled = FALSE;
6073   gint response;
6074   GtkColorSelection *colorsel;
6075
6076   /* Check if we've received a button pressed event */
6077
6078   if (event-&gt;type == GDK_BUTTON_PRESS)
6079     {
6080       handled = TRUE;
6081
6082        /* Create color selection dialog */
6083       if (colorseldlg == NULL)
6084         colorseldlg = gtk_color_selection_dialog_new ("Select background color");
6085
6086       /* Get the ColorSelection widget */
6087       colorsel = GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (colorseldlg)-&gt;colorsel);
6088
6089       gtk_color_selection_set_previous_color (colorsel, &amp;color);
6090       gtk_color_selection_set_current_color (colorsel, &amp;color);
6091       gtk_color_selection_set_has_palette (colorsel, TRUE);
6092
6093       /* Connect to the "color_changed" signal, set the client-data
6094        * to the colorsel widget */
6095       g_signal_connect (G_OBJECT (colorsel), "color_changed",
6096                         G_CALLBACK (color_changed_cb), (gpointer) colorsel);
6097
6098       /* Show the dialog */
6099       response = gtk_dialog_run (GTK_DIALOG (colorseldlg));
6100
6101       if (response == GTK_RESPONSE_OK)
6102         gtk_color_selection_get_current_color (colorsel, &amp;color);
6103       else 
6104         gtk_widget_modify_bg (drawingarea, GTK_STATE_NORMAL, &amp;color);
6105
6106       gtk_widget_hide (colorseldlg);
6107     }
6108
6109   return handled;
6110 }
6111
6112 /* Close down and exit handler */
6113
6114 static gboolean destroy_window( GtkWidget *widget,
6115                                 GdkEvent  *event,
6116                                 gpointer   client_data )
6117 {
6118   gtk_main_quit ();
6119   return TRUE;
6120 }
6121
6122 /* Main */
6123
6124 gint main( gint   argc,
6125            gchar *argv[] )
6126 {
6127   GtkWidget *window;
6128
6129   /* Initialize the toolkit, remove gtk-related commandline stuff */
6130
6131   gtk_init (&amp;argc, &amp;argv);
6132
6133   /* Create toplevel window, set title and policies */
6134
6135   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6136   gtk_window_set_title (GTK_WINDOW (window), "Color selection test");
6137   gtk_window_set_policy (GTK_WINDOW (window), TRUE, TRUE, TRUE);
6138
6139   /* Attach to the "delete" and "destroy" events so we can exit */
6140
6141   g_signal_connect (GTK_OBJECT (window), "delete_event",
6142                     GTK_SIGNAL_FUNC (destroy_window), (gpointer) window);
6143   
6144   /* Create drawingarea, set size and catch button events */
6145
6146   drawingarea = gtk_drawing_area_new ();
6147
6148   color.red = 0;
6149   color.blue = 65535;
6150   color.green = 0;
6151   gtk_widget_modify_bg (drawingarea, GTK_STATE_NORMAL, &amp;color);       
6152
6153   gtk_widget_set_size_request (GTK_WIDGET (drawingarea), 200, 200);
6154
6155   gtk_widget_set_events (drawingarea, GDK_BUTTON_PRESS_MASK);
6156
6157   g_signal_connect (GTK_OBJECT (drawingarea), "event", 
6158                     GTK_SIGNAL_FUNC (area_event), (gpointer) drawingarea);
6159   
6160   /* Add drawingarea to window, then show them both */
6161
6162   gtk_container_add (GTK_CONTAINER (window), drawingarea);
6163
6164   gtk_widget_show (drawingarea);
6165   gtk_widget_show (window);
6166   
6167   /* Enter the gtk main loop (this never returns) */
6168
6169   gtk_main ();
6170
6171   /* Satisfy grumpy compilers */
6172
6173   return 0;
6174 }
6175 <!-- example-end -->
6176 </programlisting>
6177
6178 </sect1>
6179
6180 <!-- ----------------------------------------------------------------- -->
6181 <sect1 id="sec-FileSelections">
6182 <title>File Selections</title>
6183
6184 <para>The file selection widget is a quick and simple way to display a File
6185 dialog box. It comes complete with Ok, Cancel, and Help buttons, a
6186 great way to cut down on programming time.</para>
6187
6188 <para>To create a new file selection box use:</para>
6189
6190 <programlisting role="C">
6191 GtkWidget *gtk_file_selection_new( const gchar *title );
6192 </programlisting>
6193
6194 <para>To set the filename, for example to bring up a specific directory, or
6195 give a default filename, use this function:</para>
6196
6197 <programlisting role="C">
6198 void gtk_file_selection_set_filename( GtkFileSelection *filesel,
6199                                       const gchar      *filename );
6200 </programlisting>
6201
6202 <para>To grab the text that the user has entered or clicked on, use this 
6203 function:</para>
6204
6205 <programlisting role="C">
6206 gchar *gtk_file_selection_get_filename( GtkFileSelection *filesel );
6207 </programlisting>
6208
6209 <para>There are also pointers to the widgets contained within the file 
6210 selection widget. These are:</para>
6211
6212 <programlisting role="C">
6213   dir_list
6214   file_list
6215   selection_entry
6216   selection_text
6217   main_vbox
6218   ok_button
6219   cancel_button
6220   help_button
6221 </programlisting>
6222  
6223 <para>Most likely you will want to use the ok_button, cancel_button, and
6224 help_button pointers in signaling their use.</para>
6225
6226 <para>Included here is an example stolen from <filename>testgtk.c</filename>,
6227 modified to run on its own. As you will see, there is nothing much to creating a file
6228 selection widget. While in this example the Help button appears on the
6229 screen, it does nothing as there is not a signal attached to it.</para>
6230
6231 <para>
6232 <inlinemediaobject>
6233 <imageobject>
6234 <imagedata fileref="images/filesel.png" format="png">
6235 </imageobject>
6236 </inlinemediaobject>
6237 </para>
6238
6239 <programlisting role="C">
6240 <!-- example-start filesel filesel.c -->
6241
6242 #include &lt;gtk/gtk.h&gt;
6243
6244 /* Get the selected filename and print it to the console */
6245 static void file_ok_sel( GtkWidget        *w,
6246                          GtkFileSelection *fs )
6247 {
6248     g_print ("%s\n", gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs)));
6249 }
6250
6251 int main( int   argc,
6252           char *argv[] )
6253 {
6254     GtkWidget *filew;
6255     
6256     gtk_init (&amp;argc, &amp;argv);
6257     
6258     /* Create a new file selection widget */
6259     filew = gtk_file_selection_new ("File selection");
6260     
6261     g_signal_connect (G_OBJECT (filew), "destroy",
6262                       G_CALLBACK (gtk_main_quit), NULL);
6263     /* Connect the ok_button to file_ok_sel function */
6264     g_signal_connect (G_OBJECT (GTK_FILE_SELECTION (filew)-&gt;ok_button),
6265                       "clicked", G_CALLBACK (file_ok_sel), (gpointer) filew);
6266     
6267     /* Connect the cancel_button to destroy the widget */
6268     g_signal_connect_swapped (G_OBJECT (GTK_FILE_SELECTION (filew)-&gt;cancel_button),
6269                               "clicked", G_CALLBACK (gtk_widget_destroy),
6270                               G_OBJECT (filew));
6271     
6272     /* Lets set the filename, as if this were a save dialog, and we are giving
6273      a default filename */
6274     gtk_file_selection_set_filename (GTK_FILE_SELECTION(filew), 
6275                                      "penguin.png");
6276     
6277     gtk_widget_show (filew);
6278     gtk_main ();
6279     return 0;
6280 }
6281 <!-- example-end -->
6282 </programlisting>
6283
6284 </sect1>
6285 </chapter>
6286
6287 <!-- ***************************************************************** -->
6288 <chapter id="ch-ContainerWidgets">
6289 <title>Container Widgets</title>
6290
6291 <!-- ----------------------------------------------------------------- -->   
6292 <sect1 id="sec-EventBox">
6293 <title>The EventBox</title>
6294
6295 <para>Some GTK widgets don't have associated X windows, so they just draw on
6296 their parents. Because of this, they cannot receive events and if they
6297 are incorrectly sized, they don't clip so you can get messy
6298 overwriting, etc. If you require more from these widgets, the EventBox
6299 is for you.</para>
6300
6301 <para>At first glance, the EventBox widget might appear to be totally
6302 useless. It draws nothing on the screen and responds to no
6303 events. However, it does serve a function - it provides an X window
6304 for its child widget. This is important as many GTK widgets do not
6305 have an associated X window. Not having an X window saves memory and
6306 improves performance, but also has some drawbacks. A widget without an
6307 X window cannot receive events, and does not perform any clipping on
6308 its contents. Although the name <emphasis>EventBox</emphasis> emphasizes the
6309 event-handling function, the widget can also be used for clipping.
6310 (and more, see the example below).</para>
6311
6312 <para>To create a new EventBox widget, use:</para>
6313
6314 <programlisting role="C">
6315 GtkWidget *gtk_event_box_new( void );
6316 </programlisting>
6317
6318 <para>A child widget can then be added to this EventBox:</para>
6319
6320 <programlisting role="C">
6321     gtk_container_add (GTK_CONTAINER (event_box), child_widget);
6322 </programlisting>
6323
6324 <para>The following example demonstrates both uses of an EventBox - a label
6325 is created that is clipped to a small box, and set up so that a
6326 mouse-click on the label causes the program to exit. Resizing the
6327 window reveals varying amounts of the label.</para>
6328
6329 <para>
6330 <inlinemediaobject>
6331 <imageobject>
6332 <imagedata fileref="images/eventbox.png" format="png">
6333 </imageobject>
6334 </inlinemediaobject>
6335 </para>
6336
6337 <programlisting role="C">
6338 <!-- example-start eventbox eventbox.c -->
6339
6340 #include &lt;stdlib.h&gt;
6341 #include &lt;gtk/gtk.h&gt;
6342
6343 int main( int argc,
6344           char *argv[] )
6345 {
6346     GtkWidget *window;
6347     GtkWidget *event_box;
6348     GtkWidget *label;
6349     
6350     gtk_init (&amp;argc, &amp;argv);
6351     
6352     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6353     
6354     gtk_window_set_title (GTK_WINDOW (window), "Event Box");
6355     
6356     g_signal_connect (G_OBJECT (window), "destroy",
6357                       G_CALLBACK (exit), NULL);
6358     
6359     gtk_container_set_border_width (GTK_CONTAINER (window), 10);
6360     
6361     /* Create an EventBox and add it to our toplevel window */
6362     
6363     event_box = gtk_event_box_new ();
6364     gtk_container_add (GTK_CONTAINER (window), event_box);
6365     gtk_widget_show (event_box);
6366     
6367     /* Create a long label */
6368     
6369     label = gtk_label_new ("Click here to quit, quit, quit, quit, quit");
6370     gtk_container_add (GTK_CONTAINER (event_box), label);
6371     gtk_widget_show (label);
6372     
6373     /* Clip it short. */
6374     gtk_widget_set_size_request (label, 110, 20);
6375     
6376     /* And bind an action to it */
6377     gtk_widget_set_events (event_box, GDK_BUTTON_PRESS_MASK);
6378     g_signal_connect (G_OBJECT (event_box), "button_press_event",
6379                       G_CALLBACK (exit), NULL);
6380     
6381     /* Yet one more thing you need an X window for ... */
6382     
6383     gtk_widget_realize (event_box);
6384     gdk_window_set_cursor (event_box-&gt;window, gdk_cursor_new (GDK_HAND1));
6385     
6386     gtk_widget_show (window);
6387     
6388     gtk_main ();
6389     
6390     return 0;
6391 }
6392 <!-- example-end -->
6393 </programlisting>
6394
6395 </sect1>
6396
6397 <!-- ----------------------------------------------------------------- -->   
6398 <sect1 id="sec-TheAlignmentWidget">
6399 <title>The Alignment widget</title>
6400
6401 <para>The alignment widget allows you to place a widget within its window at
6402 a position and size relative to the size of the Alignment widget
6403 itself. For example, it can be very useful for centering a widget
6404 within the window.</para>
6405
6406 <para>There are only two functions associated with the Alignment widget:</para>
6407
6408 <programlisting role="C">
6409 GtkWidget* gtk_alignment_new( gfloat xalign,
6410                               gfloat yalign,
6411                               gfloat xscale,
6412                               gfloat yscale );
6413
6414 void gtk_alignment_set( GtkAlignment *alignment,
6415                         gfloat        xalign,
6416                         gfloat        yalign,
6417                         gfloat        xscale,
6418                         gfloat        yscale );
6419 </programlisting>
6420
6421 <para>The first function creates a new Alignment widget with the specified
6422 parameters. The second function allows the alignment parameters of an
6423 exisiting Alignment widget to be altered.</para>
6424
6425 <para>All four alignment parameters are floating point numbers which can
6426 range from 0.0 to 1.0. The <literal>xalign</literal> and <literal>yalign</literal> arguments
6427 affect the position of the widget placed within the Alignment
6428 widget. The <literal>xscale</literal> and <literal>yscale</literal> arguments affect the amount of
6429 space allocated to the widget.</para>
6430
6431 <para>A child widget can be added to this Alignment widget using:</para>
6432
6433 <programlisting role="C">
6434     gtk_container_add (GTK_CONTAINER (alignment), child_widget);
6435 </programlisting>
6436
6437 <para>For an example of using an Alignment widget, refer to the example for
6438 the <link linkend="sec-ProgressBars">Progress Bar</link> widget.</para>
6439
6440 </sect1>
6441
6442 <!-- ----------------------------------------------------------------- -->
6443 <sect1 id="sec-FixedContainer">
6444 <title>Fixed Container</title>
6445
6446 <para>The Fixed container allows you to place widgets at a fixed position
6447 within it's window, relative to it's upper left hand corner. The
6448 position of the widgets can be changed dynamically.</para>
6449
6450 <para>There are only a few functions associated with the fixed widget:</para>
6451
6452 <programlisting role="C">
6453 GtkWidget* gtk_fixed_new( void );
6454
6455 void gtk_fixed_put( GtkFixed  *fixed,
6456                     GtkWidget *widget,
6457                     gint       x,
6458                     gint       y );
6459
6460 void gtk_fixed_move( GtkFixed  *fixed,
6461                      GtkWidget *widget,
6462                      gint       x,
6463                      gint       y );
6464 </programlisting>
6465
6466 <para>The function gtk_fixed_new() allows you to create a new Fixed
6467 container.</para>
6468
6469 <para>gtk_fixed_put() places <literal>widget</literal> in the container <literal>fixed</literal> at
6470 the position specified by <literal>x</literal> and <literal>y</literal>.</para>
6471
6472 <para>gtk_fixed_move() allows the specified widget to be moved to a new
6473 position.</para>
6474
6475 <programlisting role="C">
6476 void gtk_fixed_set_has_window( GtkFixed  *fixed,
6477                                gboolean   has_window );
6478
6479 gboolean gtk_fixed_get_has_window( GtkFixed *fixed );
6480 </programlisting>
6481
6482 <para>Normally, Fixed widgets don't have their own X window. Since this is
6483 different from the behaviour of Fixed widgets in earlier releases of GTK, 
6484 the function gtk_fixed_set_has_window() allows the creation of Fixed widgets 
6485 <emphasis>with</emphasis> their own window. It has to be called before
6486 realizing the widget.</para>
6487
6488 <para>The following example illustrates how to use the Fixed Container.</para>
6489
6490 <para>
6491 <inlinemediaobject>
6492 <imageobject>
6493 <imagedata fileref="images/fixed.png" format="png">
6494 </imageobject>
6495 </inlinemediaobject>
6496 </para>
6497
6498 <programlisting role="C">
6499 <!-- example-start fixed fixed.c -->
6500
6501 #include &lt;gtk/gtk.h&gt;
6502
6503 /* I'm going to be lazy and use some global variables to
6504  * store the position of the widget within the fixed
6505  * container */
6506 gint x = 50;
6507 gint y = 50;
6508
6509 /* This callback function moves the button to a new position
6510  * in the Fixed container. */
6511 static void move_button( GtkWidget *widget,
6512                          GtkWidget *fixed )
6513 {
6514   x = (x + 30) % 300;
6515   y = (y + 50) % 300;
6516   gtk_fixed_move (GTK_FIXED (fixed), widget, x, y); 
6517 }
6518
6519 int main( int   argc,
6520           char *argv[] )
6521 {
6522   /* GtkWidget is the storage type for widgets */
6523   GtkWidget *window;
6524   GtkWidget *fixed;
6525   GtkWidget *button;
6526   gint i;
6527
6528   /* Initialise GTK */
6529   gtk_init (&amp;argc, &amp;argv);
6530     
6531   /* Create a new window */
6532   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6533   gtk_window_set_title (GTK_WINDOW (window), "Fixed Container");
6534
6535   /* Here we connect the "destroy" event to a signal handler */ 
6536   g_signal_connect (G_OBJECT (window), "destroy",
6537                     G_CALLBACK (gtk_main_quit), NULL);
6538  
6539   /* Sets the border width of the window. */
6540   gtk_container_set_border_width (GTK_CONTAINER (window), 10);
6541
6542   /* Create a Fixed Container */
6543   fixed = gtk_fixed_new ();
6544   gtk_container_add (GTK_CONTAINER (window), fixed);
6545   gtk_widget_show (fixed);
6546   
6547   for (i = 1 ; i &lt;= 3 ; i++) {
6548     /* Creates a new button with the label "Press me" */
6549     button = gtk_button_new_with_label ("Press me");
6550   
6551     /* When the button receives the "clicked" signal, it will call the
6552      * function move_button() passing it the Fixed Container as its
6553      * argument. */
6554     g_signal_connect (G_OBJECT (button), "clicked",
6555                       G_CALLBACK (move_button), (gpointer) fixed);
6556   
6557     /* This packs the button into the fixed containers window. */
6558     gtk_fixed_put (GTK_FIXED (fixed), button, i*50, i*50);
6559   
6560     /* The final step is to display this newly created widget. */
6561     gtk_widget_show (button);
6562   }
6563
6564   /* Display the window */
6565   gtk_widget_show (window);
6566     
6567   /* Enter the event loop */
6568   gtk_main ();
6569     
6570   return 0;
6571 }
6572 <!-- example-end -->
6573 </programlisting>
6574
6575 </sect1>
6576
6577 <!-- ----------------------------------------------------------------- -->
6578 <sect1 id="sec-LayoutContainer">
6579 <title>Layout Container</title>
6580
6581 <para>The Layout container is similar to the Fixed container except that it
6582 implements an infinite (where infinity is less than 2^32) scrolling
6583 area. The X window system has a limitation where windows can be at
6584 most 32767 pixels wide or tall. The Layout container gets around this
6585 limitation by doing some exotic stuff using window and bit gravities,
6586 so that you can have smooth scrolling even when you have many child
6587 widgets in your scrolling area.</para>
6588
6589 <para>A Layout container is created using:</para>
6590
6591 <programlisting role="C">
6592 GtkWidget *gtk_layout_new( GtkAdjustment *hadjustment,
6593                            GtkAdjustment *vadjustment );
6594 </programlisting>
6595
6596 <para>As you can see, you can optionally specify the Adjustment objects that
6597 the Layout widget will use for its scrolling.</para>
6598
6599 <para>You can add and move widgets in the Layout container using the
6600 following two functions:</para>
6601
6602 <programlisting role="C">
6603 void gtk_layout_put( GtkLayout *layout,
6604                      GtkWidget *widget,
6605                      gint       x,
6606                      gint       y );
6607
6608 void gtk_layout_move( GtkLayout *layout,
6609                       GtkWidget *widget,
6610                       gint       x,
6611                       gint       y );
6612 </programlisting>
6613
6614 <para>The size of the Layout container can be set using the next function:</para>
6615
6616 <programlisting role="C">
6617 void gtk_layout_set_size( GtkLayout *layout,
6618                           guint      width,
6619                           guint      height );
6620 </programlisting>
6621
6622 <para>The final four functions for use with Layout widgets are for
6623 manipulating the horizontal and vertical adjustment widgets:</para>
6624
6625 <programlisting role="C">
6626 GtkAdjustment* gtk_layout_get_hadjustment( GtkLayout *layout );
6627
6628 GtkAdjustment* gtk_layout_get_vadjustment( GtkLayout *layout );
6629
6630 void gtk_layout_set_hadjustment( GtkLayout     *layout,
6631                                  GtkAdjustment *adjustment );
6632
6633 void gtk_layout_set_vadjustment( GtkLayout     *layout,
6634                                  GtkAdjustment *adjustment);
6635 </programlisting>
6636
6637 </sect1>
6638
6639 <!-- ----------------------------------------------------------------- -->
6640 <sect1 id="sec-Frames">
6641 <title>Frames</title>
6642
6643 <para>Frames can be used to enclose one or a group of widgets with a box
6644 which can optionally be labelled. The position of the label and the
6645 style of the box can be altered to suit.</para>
6646
6647 <para>A Frame can be created with the following function:</para>
6648
6649 <programlisting role="C">
6650 GtkWidget *gtk_frame_new( const gchar *label );
6651 </programlisting>
6652
6653 <para>The label is by default placed in the upper left hand corner of the
6654 frame. A value of NULL for the <literal>label</literal> argument will result in no
6655 label being displayed. The text of the label can be changed using the
6656 next function.</para>
6657
6658 <programlisting role="C">
6659 void gtk_frame_set_label( GtkFrame    *frame,
6660                           const gchar *label );
6661 </programlisting>
6662
6663 <para>The position of the label can be changed using this function:</para>
6664
6665 <programlisting role="C">
6666 void gtk_frame_set_label_align( GtkFrame *frame,
6667                                 gfloat    xalign,
6668                                 gfloat    yalign );
6669 </programlisting>
6670
6671 <para><literal>xalign</literal> and <literal>yalign</literal> take values between 0.0 and 1.0. <literal>xalign</literal>
6672 indicates the position of the label along the top horizontal of the
6673 frame. <literal>yalign</literal> is not currently used. The default value of xalign
6674 is 0.0 which places the label at the left hand end of the frame.</para>
6675
6676 <para>The next function alters the style of the box that is used to outline
6677 the frame.</para>
6678
6679 <programlisting role="C">
6680 void gtk_frame_set_shadow_type( GtkFrame      *frame,
6681                                 GtkShadowType  type);
6682 </programlisting>
6683
6684 <para>The <literal>type</literal> argument can take one of the following values:</para>
6685 <programlisting role="C">
6686   GTK_SHADOW_NONE
6687   GTK_SHADOW_IN
6688   GTK_SHADOW_OUT
6689   GTK_SHADOW_ETCHED_IN (the default)
6690   GTK_SHADOW_ETCHED_OUT
6691 </programlisting>
6692
6693 <para>The following code example illustrates the use of the Frame widget.</para>
6694
6695 <para>
6696 <inlinemediaobject>
6697 <imageobject>
6698 <imagedata fileref="images/frame.png" format="png">
6699 </imageobject>
6700 </inlinemediaobject>
6701 </para>
6702
6703 <programlisting role="C">
6704 <!-- example-start frame frame.c -->
6705
6706 #include &lt;gtk/gtk.h&gt;
6707
6708 int main( int   argc,
6709           char *argv[] )
6710 {
6711   /* GtkWidget is the storage type for widgets */
6712   GtkWidget *window;
6713   GtkWidget *frame;
6714
6715   /* Initialise GTK */
6716   gtk_init (&amp;argc, &amp;argv);
6717     
6718   /* Create a new window */
6719   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6720   gtk_window_set_title (GTK_WINDOW (window), "Frame Example");
6721
6722   /* Here we connect the "destroy" event to a signal handler */ 
6723   g_signal_connect (G_OBJECT (window), "destroy",
6724                     G_CALLBACK (gtk_main_quit), NULL);
6725
6726   gtk_widget_set_size_request (window, 300, 300);
6727   /* Sets the border width of the window. */
6728   gtk_container_set_border_width (GTK_CONTAINER (window), 10);
6729
6730   /* Create a Frame */
6731   frame = gtk_frame_new (NULL);
6732   gtk_container_add (GTK_CONTAINER (window), frame);
6733
6734   /* Set the frame's label */
6735   gtk_frame_set_label (GTK_FRAME (frame), "GTK Frame Widget");
6736
6737   /* Align the label at the right of the frame */
6738   gtk_frame_set_label_align (GTK_FRAME (frame), 1.0, 0.0);
6739
6740   /* Set the style of the frame */
6741   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_OUT);
6742
6743   gtk_widget_show (frame);
6744   
6745   /* Display the window */
6746   gtk_widget_show (window);
6747     
6748   /* Enter the event loop */
6749   gtk_main ();
6750     
6751   return 0;
6752 }
6753 <!-- example-end -->
6754 </programlisting>
6755 </sect1>
6756
6757 <!-- ----------------------------------------------------------------- -->   
6758 <sect1 id="sec-AspectFrames">
6759 <title>Aspect Frames</title>
6760
6761 <para>The aspect frame widget is like a frame widget, except that it also
6762 enforces the aspect ratio (that is, the ratio of the width to the
6763 height) of the child widget to have a certain value, adding extra
6764 space if necessary. This is useful, for instance, if you want to
6765 preview a larger image. The size of the preview should vary when the
6766 user resizes the window, but the aspect ratio needs to always match
6767 the original image.</para>
6768   
6769 <para>To create a new aspect frame use:</para>
6770
6771 <programlisting role="C">
6772 GtkWidget *gtk_aspect_frame_new( const gchar *label,
6773                                  gfloat       xalign,
6774                                  gfloat       yalign,
6775                                  gfloat       ratio,
6776                                  gboolean     obey_child);
6777 </programlisting>
6778    
6779 <para><literal>xalign</literal> and <literal>yalign</literal> specify alignment as with Alignment
6780 widgets. If <literal>obey_child</literal> is TRUE, the aspect ratio of a child
6781 widget will match the aspect ratio of the ideal size it requests.
6782 Otherwise, it is given by <literal>ratio</literal>.</para>
6783    
6784 <para>To change the options of an existing aspect frame, you can use:</para>
6785
6786 <programlisting role="C">
6787 void gtk_aspect_frame_set( GtkAspectFrame *aspect_frame,
6788                            gfloat          xalign,
6789                            gfloat          yalign,
6790                            gfloat          ratio,
6791                            gboolean        obey_child);
6792 </programlisting>
6793    
6794 <para>As an example, the following program uses an AspectFrame to present a
6795 drawing area whose aspect ratio will always be 2:1, no matter how the
6796 user resizes the top-level window.</para>
6797
6798 <para>
6799 <inlinemediaobject>
6800 <imageobject>
6801 <imagedata fileref="images/aspectframe.png" format="png">
6802 </imageobject>
6803 </inlinemediaobject>
6804 </para>
6805
6806 <programlisting role="C">
6807 <!-- example-start aspectframe aspectframe.c -->
6808
6809 #include &lt;gtk/gtk.h&gt;
6810    
6811 int main( int argc,
6812           char *argv[] )
6813 {
6814     GtkWidget *window;
6815     GtkWidget *aspect_frame;
6816     GtkWidget *drawing_area;
6817     gtk_init (&amp;argc, &amp;argv);
6818    
6819     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
6820     gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
6821     g_signal_connect (G_OBJECT (window), "destroy",
6822                       G_CALLBACK (gtk_main_quit), NULL);
6823     gtk_container_set_border_width (GTK_CONTAINER (window), 10);
6824    
6825     /* Create an aspect_frame and add it to our toplevel window */
6826    
6827     aspect_frame = gtk_aspect_frame_new ("2x1", /* label */
6828                                          0.5, /* center x */
6829                                          0.5, /* center y */
6830                                          2, /* xsize/ysize = 2 */
6831                                          FALSE /* ignore child's aspect */);
6832    
6833     gtk_container_add (GTK_CONTAINER (window), aspect_frame);
6834     gtk_widget_show (aspect_frame);
6835    
6836     /* Now add a child widget to the aspect frame */
6837    
6838     drawing_area = gtk_drawing_area_new ();
6839    
6840     /* Ask for a 200x200 window, but the AspectFrame will give us a 200x100
6841      * window since we are forcing a 2x1 aspect ratio */
6842     gtk_widget_set_size_request (drawing_area, 200, 200);
6843     gtk_container_add (GTK_CONTAINER (aspect_frame), drawing_area);
6844     gtk_widget_show (drawing_area);
6845    
6846     gtk_widget_show (window);
6847     gtk_main ();
6848     return 0;
6849 }
6850 <!-- example-end -->
6851 </programlisting>
6852
6853 </sect1>
6854
6855 <!-- ----------------------------------------------------------------- -->   
6856 <sect1 id="sec-PanedWindowWidgets">
6857 <title>Paned Window Widgets</title>
6858
6859 <para>The paned window widgets are useful when you want to divide an area
6860 into two parts, with the relative size of the two parts controlled by
6861 the user. A groove is drawn between the two portions with a handle
6862 that the user can drag to change the ratio. The division can either be
6863 horizontal (HPaned) or vertical (VPaned).</para>
6864    
6865 <para>To create a new paned window, call one of:</para>
6866
6867 <programlisting role="C">
6868 GtkWidget *gtk_hpaned_new (void);
6869
6870 GtkWidget *gtk_vpaned_new (void);
6871 </programlisting>
6872
6873 <para>After creating the paned window widget, you need to add child widgets
6874 to its two halves. To do this, use the functions:</para>
6875
6876 <programlisting role="C">
6877 void gtk_paned_add1 (GtkPaned *paned, GtkWidget *child);
6878
6879 void gtk_paned_add2 (GtkPaned *paned, GtkWidget *child);
6880 </programlisting>
6881
6882 <para><literal>gtk_paned_add1()</literal> adds the child widget to the left or top half of
6883 the paned window. <literal>gtk_paned_add2()</literal> adds the child widget to the
6884 right or bottom half of the paned window.</para>
6885
6886 <para>As an example, we will create part of the user interface of an
6887 imaginary email program. A window is divided into two portions
6888 vertically, with the top portion being a list of email messages and
6889 the bottom portion the text of the email message. Most of the program
6890 is pretty straightforward. A couple of points to note: text can't be
6891 added to a Text widget until it is realized. This could be done by
6892 calling gtk_widget_realize(), but as a demonstration of an
6893 alternate technique, we connect a handler to the "realize" signal to
6894 add the text. Also, we need to add the <literal>GTK_SHRINK</literal> option to some
6895 of the items in the table containing the text window and its
6896 scrollbars, so that when the bottom portion is made smaller, the
6897 correct portions shrink instead of being pushed off the bottom of the
6898 window.</para>
6899
6900 <para>
6901 <inlinemediaobject>
6902 <imageobject>
6903 <imagedata fileref="images/paned.png" format="png">
6904 </imageobject>
6905 </inlinemediaobject>
6906 </para>
6907
6908 <programlisting role="C">
6909 <!-- example-start paned paned.c -->
6910
6911 #include &lt;stdio.h&gt;
6912 #include &lt;gtk/gtk.h&gt;
6913    
6914 /* Create the list of "messages" */
6915 static GtkWidget *create_list( void )
6916 {
6917
6918     GtkWidget *scrolled_window;
6919     GtkWidget *tree_view;
6920     GtkListStore *model;
6921     GtkTreeIter iter;
6922     GtkCellRenderer *cell;
6923     GtkTreeViewColumn *column;
6924
6925     int i;
6926    
6927     /* Create a new scrolled window, with scrollbars only if needed */
6928     scrolled_window = gtk_scrolled_window_new (NULL, NULL);
6929     gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
6930                                     GTK_POLICY_AUTOMATIC, 
6931                                     GTK_POLICY_AUTOMATIC);
6932    
6933     model = gtk_list_store_new (1, G_TYPE_STRING);
6934     tree_view = gtk_tree_view_new ();
6935     gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled_window), 
6936                                            tree_view);
6937     gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view), GTK_TREE_MODEL (model));
6938     gtk_widget_show (tree_view);
6939    
6940     /* Add some messages to the window */
6941     for (i = 0; i &lt; 10; i++) {
6942         gchar *msg = g_strdup_printf ("Message #%d", i);
6943         gtk_list_store_append (GTK_LIST_STORE (model), &amp;iter);
6944         gtk_list_store_set (GTK_LIST_STORE (model), 
6945                             &amp;iter,
6946                             0, msg,
6947                             -1);
6948         g_free (msg);
6949     }
6950    
6951     cell = gtk_cell_renderer_text_new ();
6952
6953     column = gtk_tree_view_column_new_with_attributes ("Messages",
6954                                                        cell,
6955                                                        "text", 0,
6956                                                        NULL);
6957   
6958     gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view),
6959                                  GTK_TREE_VIEW_COLUMN (column));
6960
6961     return scrolled_window;
6962 }
6963    
6964 /* Add some text to our text widget - this is a callback that is invoked
6965 when our window is realized. We could also force our window to be
6966 realized with gtk_widget_realize, but it would have to be part of
6967 a hierarchy first */
6968
6969 static void insert_text( GtkTextBuffer *buffer )
6970 {
6971    GtkTextIter iter;
6972  
6973    gtk_text_buffer_get_iter_at_offset (buffer, &amp;iter, 0);
6974
6975    gtk_text_buffer_insert (buffer, &amp;iter,   
6976     "From: pathfinder@nasa.gov\n"
6977     "To: mom@nasa.gov\n"
6978     "Subject: Made it!\n"
6979     "\n"
6980     "We just got in this morning. The weather has been\n"
6981     "great - clear but cold, and there are lots of fun sights.\n"
6982     "Sojourner says hi. See you soon.\n"
6983     " -Path\n", -1);
6984 }
6985    
6986 /* Create a scrolled text area that displays a "message" */
6987 static GtkWidget *create_text( void )
6988 {
6989    GtkWidget *scrolled_window;
6990    GtkWidget *view;
6991    GtkTextBuffer *buffer;
6992
6993    view = gtk_text_view_new ();
6994    buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
6995
6996    scrolled_window = gtk_scrolled_window_new (NULL, NULL);
6997    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
6998                                    GTK_POLICY_AUTOMATIC,
6999                                    GTK_POLICY_AUTOMATIC);
7000
7001    gtk_container_add (GTK_CONTAINER (scrolled_window), view);
7002    insert_text (buffer);
7003
7004    gtk_widget_show_all (scrolled_window);
7005
7006    return scrolled_window;
7007 }
7008    
7009 int main( int   argc,
7010           char *argv[] )
7011 {
7012     GtkWidget *window;
7013     GtkWidget *vpaned;
7014     GtkWidget *list;
7015     GtkWidget *text;
7016
7017     gtk_init (&amp;argc, &amp;argv);
7018    
7019     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
7020     gtk_window_set_title (GTK_WINDOW (window), "Paned Windows");
7021     g_signal_connect (G_OBJECT (window), "destroy",
7022                       G_CALLBACK (gtk_main_quit), NULL);
7023     gtk_container_set_border_width (GTK_CONTAINER (window), 10);
7024     gtk_widget_set_size_request (GTK_WIDGET (window), 450, 400);
7025
7026     /* create a vpaned widget and add it to our toplevel window */
7027    
7028     vpaned = gtk_vpaned_new ();
7029     gtk_container_add (GTK_CONTAINER (window), vpaned);
7030     gtk_widget_show (vpaned);
7031    
7032     /* Now create the contents of the two halves of the window */
7033    
7034     list = create_list ();
7035     gtk_paned_add1 (GTK_PANED (vpaned), list);
7036     gtk_widget_show (list);
7037    
7038     text = create_text ();
7039     gtk_paned_add2 (GTK_PANED (vpaned), text);
7040     gtk_widget_show (text);
7041     gtk_widget_show (window);
7042
7043     gtk_main ();
7044
7045     return 0;
7046 }
7047 <!-- example-end -->
7048 </programlisting>
7049
7050 </sect1>
7051
7052 <!-- ----------------------------------------------------------------- -->
7053 <sect1 id="sec-Viewports">
7054 <title>Viewports</title>
7055
7056 <para>It is unlikely that you will ever need to use the Viewport widget
7057 directly. You are much more likely to use the
7058 <link linkend="sec-ScrolledWindows">Scrolled Window</link> widget which
7059 itself uses the Viewport.</para>
7060
7061 <para>A viewport widget allows you to place a larger widget within it such
7062 that you can view a part of it at a time. It uses
7063 <link linkend="ch-Adjustments">Adjustments</link> to define the area that
7064 is currently in view.</para>
7065
7066 <para>A Viewport is created with the function</para>
7067
7068 <programlisting role="C">
7069 GtkWidget *gtk_viewport_new( GtkAdjustment *hadjustment,
7070                              GtkAdjustment *vadjustment );
7071 </programlisting>
7072
7073 <para>As you can see you can specify the horizontal and vertical Adjustments
7074 that the widget is to use when you create the widget. It will create
7075 its own if you pass NULL as the value of the arguments.</para>
7076
7077 <para>You can get and set the adjustments after the widget has been created
7078 using the following four functions:</para>
7079
7080 <programlisting role="C">
7081 GtkAdjustment *gtk_viewport_get_hadjustment( GtkViewport *viewport );
7082
7083 GtkAdjustment *gtk_viewport_get_vadjustment( GtkViewport *viewport );
7084
7085 void gtk_viewport_set_hadjustment( GtkViewport   *viewport,
7086                                    GtkAdjustment *adjustment );
7087
7088 void gtk_viewport_set_vadjustment( GtkViewport   *viewport,
7089                                    GtkAdjustment *adjustment );
7090 </programlisting>
7091
7092 <para>The only other viewport function is used to alter its appearance:</para>
7093
7094 <programlisting role="C">
7095 void gtk_viewport_set_shadow_type( GtkViewport   *viewport,
7096                                    GtkShadowType  type );
7097 </programlisting>
7098
7099 <para>Possible values for the <literal>type</literal> parameter are:</para>
7100 <programlisting role="C">
7101   GTK_SHADOW_NONE,
7102   GTK_SHADOW_IN,
7103   GTK_SHADOW_OUT,
7104   GTK_SHADOW_ETCHED_IN,
7105   GTK_SHADOW_ETCHED_OUT
7106 </programlisting>
7107  
7108 </sect1>
7109
7110 <!-- ----------------------------------------------------------------- -->
7111 <sect1 id="sec-ScrolledWindows"
7112 <title>Scrolled Windows</title>
7113
7114 <para>Scrolled windows are used to create a scrollable area with another
7115 widget inside it. You may insert any type of widget into a scrolled
7116 window, and it will be accessible regardless of the size by using the
7117 scrollbars.</para>
7118
7119 <para>The following function is used to create a new scrolled window.</para>
7120
7121 <programlisting role="C">
7122 GtkWidget *gtk_scrolled_window_new( GtkAdjustment *hadjustment,
7123                                     GtkAdjustment *vadjustment );
7124 </programlisting>
7125
7126 <para>Where the first argument is the adjustment for the horizontal
7127 direction, and the second, the adjustment for the vertical direction.
7128 These are almost always set to NULL.</para>
7129
7130 <programlisting role="C">
7131 void gtk_scrolled_window_set_policy( GtkScrolledWindow *scrolled_window,
7132                                      GtkPolicyType      hscrollbar_policy,
7133                                      GtkPolicyType      vscrollbar_policy );
7134 </programlisting>
7135
7136 <para>This sets the policy to be used with respect to the scrollbars.
7137 The first argument is the scrolled window you wish to change. The second
7138 sets the policy for the horizontal scrollbar, and the third the policy for 
7139 the vertical scrollbar.</para>
7140
7141 <para>The policy may be one of <literal>GTK_POLICY_AUTOMATIC</literal> or
7142 <literal>GTK_POLICY_ALWAYS</literal>. <literal>GTK_POLICY_AUTOMATIC</literal> will automatically
7143 decide whether you need scrollbars, whereas <literal>GTK_POLICY_ALWAYS</literal>
7144 will always leave the scrollbars there.</para>
7145
7146 <para>You can then place your object into the scrolled window using the
7147 following function.</para>
7148
7149 <programlisting role="C">
7150 void gtk_scrolled_window_add_with_viewport( GtkScrolledWindow *scrolled_window,
7151                                             GtkWidget         *child);
7152 </programlisting>
7153
7154 <para>Here is a simple example that packs a table with 100 toggle buttons
7155 into a scrolled window. I've only commented on the parts that may be
7156 new to you.</para>
7157
7158 <para>
7159 <inlinemediaobject>
7160 <imageobject>
7161 <imagedata fileref="images/scrolledwin.png" format="png">
7162 </imageobject>
7163 </inlinemediaobject>
7164 </para>
7165
7166 <programlisting role="C">
7167 <!-- example-start scrolledwin scrolledwin.c -->
7168
7169 #include &lt;stdio.h&gt;
7170 #include &lt;gtk/gtk.h&gt;
7171
7172 static void destroy( GtkWidget *widget,
7173                      gpointer   data )
7174 {
7175     gtk_main_quit ();
7176 }
7177
7178 int main( int   argc,
7179           char *argv[] )
7180 {
7181     static GtkWidget *window;
7182     GtkWidget *scrolled_window;
7183     GtkWidget *table;
7184     GtkWidget *button;
7185     char buffer[32];
7186     int i, j;
7187     
7188     gtk_init (&amp;argc, &amp;argv);
7189     
7190     /* Create a new dialog window for the scrolled window to be
7191      * packed into.  */
7192     window = gtk_dialog_new ();
7193     g_signal_connect (G_OBJECT (window), "destroy",
7194                       G_CALLBACK (destroy), NULL);
7195     gtk_window_set_title (GTK_WINDOW (window), "GtkScrolledWindow example");
7196     gtk_container_set_border_width (GTK_CONTAINER (window), 0);
7197     gtk_widget_set_size_request (window, 300, 300);
7198     
7199     /* create a new scrolled window. */
7200     scrolled_window = gtk_scrolled_window_new (NULL, NULL);
7201     
7202     gtk_container_set_border_width (GTK_CONTAINER (scrolled_window), 10);
7203     
7204     /* the policy is one of GTK_POLICY AUTOMATIC, or GTK_POLICY_ALWAYS.
7205      * GTK_POLICY_AUTOMATIC will automatically decide whether you need
7206      * scrollbars, whereas GTK_POLICY_ALWAYS will always leave the scrollbars
7207      * there.  The first one is the horizontal scrollbar, the second, 
7208      * the vertical. */
7209     gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
7210                                     GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
7211     /* The dialog window is created with a vbox packed into it. */                                                              
7212     gtk_box_pack_start (GTK_BOX (GTK_DIALOG(window)-&gt;vbox), scrolled_window, 
7213                         TRUE, TRUE, 0);
7214     gtk_widget_show (scrolled_window);
7215     
7216     /* create a table of 10 by 10 squares. */
7217     table = gtk_table_new (10, 10, FALSE);
7218     
7219     /* set the spacing to 10 on x and 10 on y */
7220     gtk_table_set_row_spacings (GTK_TABLE (table), 10);
7221     gtk_table_set_col_spacings (GTK_TABLE (table), 10);
7222     
7223     /* pack the table into the scrolled window */
7224     gtk_scrolled_window_add_with_viewport (
7225                    GTK_SCROLLED_WINDOW (scrolled_window), table);
7226     gtk_widget_show (table);
7227     
7228     /* this simply creates a grid of toggle buttons on the table
7229      * to demonstrate the scrolled window. */
7230     for (i = 0; i &lt; 10; i++)
7231        for (j = 0; j &lt; 10; j++) {
7232           sprintf (buffer, "button (%d,%d)\n", i, j);
7233           button = gtk_toggle_button_new_with_label (buffer);
7234           gtk_table_attach_defaults (GTK_TABLE (table), button,
7235                                      i, i+1, j, j+1);
7236           gtk_widget_show (button);
7237        }
7238     
7239     /* Add a "close" button to the bottom of the dialog */
7240     button = gtk_button_new_with_label ("close");
7241     g_signal_connect_swapped (G_OBJECT (button), "clicked",
7242                               G_CALLBACK (gtk_widget_destroy),
7243                               G_OBJECT (window));
7244     
7245     /* this makes it so the button is the default. */
7246     
7247     GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
7248     gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)-&gt;action_area), button, TRUE, TRUE, 0);
7249     
7250     /* This grabs this button to be the default button. Simply hitting
7251      * the "Enter" key will cause this button to activate. */
7252     gtk_widget_grab_default (button);
7253     gtk_widget_show (button);
7254     
7255     gtk_widget_show (window);
7256     
7257     gtk_main();
7258     
7259     return 0;
7260 }
7261 <!-- example-end -->
7262 </programlisting>
7263
7264 <para>Try playing with resizing the window. You'll notice how the scrollbars
7265 react. You may also wish to use the gtk_widget_set_size_request() call to set
7266 the default size of the window or other widgets.</para>
7267
7268 </sect1>
7269
7270 <!-- ----------------------------------------------------------------- -->   
7271 <sect1 id="sec-ButtonBoxes">
7272 <title>Button Boxes</title>
7273
7274 <para>Button Boxes are a convenient way to quickly layout a group of
7275 buttons. They come in both horizontal and vertical flavours. You
7276 create a new Button Box with one of the following calls, which create
7277 a horizontal or vertical box, respectively:</para>
7278
7279 <programlisting role="C">
7280 GtkWidget *gtk_hbutton_box_new( void );
7281
7282 GtkWidget *gtk_vbutton_box_new( void );
7283 </programlisting>
7284
7285 <para>Buttons are added to a Button Box using the usual function:</para>
7286
7287 <programlisting role="C">
7288     gtk_container_add (GTK_CONTAINER (button_box), child_widget);
7289 </programlisting>
7290
7291 <para>Here's an example that illustrates all the different layout settings
7292 for Button Boxes.</para>
7293
7294 <para>
7295 <inlinemediaobject>
7296 <imageobject>
7297 <imagedata fileref="images/buttonbox.png" format="png">
7298 </imageobject>
7299 </inlinemediaobject>
7300 </para>
7301
7302 <programlisting role="C">
7303 <!-- example-start buttonbox buttonbox.c -->
7304
7305 #include &lt;gtk/gtk.h&gt;
7306
7307 /* Create a Button Box with the specified parameters */
7308 static GtkWidget *create_bbox( gint  horizontal,
7309                                char *title,
7310                                gint  spacing,
7311                                gint  child_w,
7312                                gint  child_h,
7313                                gint  layout )
7314 {
7315   GtkWidget *frame;
7316   GtkWidget *bbox;
7317   GtkWidget *button;
7318
7319   frame = gtk_frame_new (title);
7320
7321   if (horizontal)
7322     bbox = gtk_hbutton_box_new ();
7323   else
7324     bbox = gtk_vbutton_box_new ();
7325
7326   gtk_container_set_border_width (GTK_CONTAINER (bbox), 5);
7327   gtk_container_add (GTK_CONTAINER (frame), bbox);
7328
7329   /* Set the appearance of the Button Box */
7330   gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), layout);
7331   gtk_box_set_spacing (GTK_BOX (bbox), spacing);
7332   /*gtk_button_box_set_child_size (GTK_BUTTON_BOX (bbox), child_w, child_h);*/
7333
7334   button = gtk_button_new_from_stock (GTK_STOCK_OK);
7335   gtk_container_add (GTK_CONTAINER (bbox), button);
7336
7337   button = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
7338   gtk_container_add (GTK_CONTAINER (bbox), button);
7339
7340   button = gtk_button_new_from_stock (GTK_STOCK_HELP);
7341   gtk_container_add (GTK_CONTAINER (bbox), button);
7342
7343   return frame;
7344 }
7345
7346 int main( int   argc,
7347           char *argv[] )
7348 {
7349   static GtkWidget* window = NULL;
7350   GtkWidget *main_vbox;
7351   GtkWidget *vbox;
7352   GtkWidget *hbox;
7353   GtkWidget *frame_horz;
7354   GtkWidget *frame_vert;
7355
7356   /* Initialize GTK */
7357   gtk_init (&amp;argc, &amp;argv);
7358
7359   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
7360   gtk_window_set_title (GTK_WINDOW (window), "Button Boxes");
7361
7362   g_signal_connect (G_OBJECT (window), "destroy",
7363                     G_CALLBACK (gtk_main_quit),
7364                     NULL);
7365
7366   gtk_container_set_border_width (GTK_CONTAINER (window), 10);
7367
7368   main_vbox = gtk_vbox_new (FALSE, 0);
7369   gtk_container_add (GTK_CONTAINER (window), main_vbox);
7370
7371   frame_horz = gtk_frame_new ("Horizontal Button Boxes");
7372   gtk_box_pack_start (GTK_BOX (main_vbox), frame_horz, TRUE, TRUE, 10);
7373
7374   vbox = gtk_vbox_new (FALSE, 0);
7375   gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
7376   gtk_container_add (GTK_CONTAINER (frame_horz), vbox);
7377
7378   gtk_box_pack_start (GTK_BOX (vbox),
7379            create_bbox (TRUE, "Spread (spacing 40)", 40, 85, 20, GTK_BUTTONBOX_SPREAD),
7380                       TRUE, TRUE, 0);
7381
7382   gtk_box_pack_start (GTK_BOX (vbox),
7383            create_bbox (TRUE, "Edge (spacing 30)", 30, 85, 20, GTK_BUTTONBOX_EDGE),
7384                       TRUE, TRUE, 5);
7385
7386   gtk_box_pack_start (GTK_BOX (vbox),
7387            create_bbox (TRUE, "Start (spacing 20)", 20, 85, 20, GTK_BUTTONBOX_START),
7388                       TRUE, TRUE, 5);
7389
7390   gtk_box_pack_start (GTK_BOX (vbox),
7391            create_bbox (TRUE, "End (spacing 10)", 10, 85, 20, GTK_BUTTONBOX_END),
7392                       TRUE, TRUE, 5);
7393
7394   frame_vert = gtk_frame_new ("Vertical Button Boxes");
7395   gtk_box_pack_start (GTK_BOX (main_vbox), frame_vert, TRUE, TRUE, 10);
7396
7397   hbox = gtk_hbox_new (FALSE, 0);
7398   gtk_container_set_border_width (GTK_CONTAINER (hbox), 10);
7399   gtk_container_add (GTK_CONTAINER (frame_vert), hbox);
7400
7401   gtk_box_pack_start (GTK_BOX (hbox),
7402            create_bbox (FALSE, "Spread (spacing 5)", 5, 85, 20, GTK_BUTTONBOX_SPREAD),
7403                       TRUE, TRUE, 0);
7404
7405   gtk_box_pack_start (GTK_BOX (hbox),
7406            create_bbox (FALSE, "Edge (spacing 30)", 30, 85, 20, GTK_BUTTONBOX_EDGE),
7407                       TRUE, TRUE, 5);
7408
7409   gtk_box_pack_start (GTK_BOX (hbox),
7410            create_bbox (FALSE, "Start (spacing 20)", 20, 85, 20, GTK_BUTTONBOX_START),
7411                       TRUE, TRUE, 5);
7412
7413   gtk_box_pack_start (GTK_BOX (hbox),
7414            create_bbox (FALSE, "End (spacing 20)", 20, 85, 20, GTK_BUTTONBOX_END),
7415                       TRUE, TRUE, 5);
7416
7417   gtk_widget_show_all (window);
7418
7419   /* Enter the event loop */
7420   gtk_main ();
7421     
7422   return 0;
7423 }
7424 <!-- example-end -->
7425 </programlisting>
7426
7427 </sect1>
7428
7429 <!-- ----------------------------------------------------------------- -->   
7430 <sect1 id="sec-Toolbar">
7431 <title>Toolbar</title>
7432
7433 <para>Toolbars are usually used to group some number of widgets in order to
7434 simplify customization of their look and layout. Typically a toolbar
7435 consists of buttons with icons, labels and tooltips, but any other
7436 widget can also be put inside a toolbar. Finally, items can be
7437 arranged horizontally or vertically and buttons can be displayed with
7438 icons, labels, or both.</para>
7439
7440 <para>Creating a toolbar is (as one may already suspect) done with the
7441 following function:</para>
7442
7443 <programlisting role="C">
7444 GtkWidget *gtk_toolbar_new( void );
7445 </programlisting>
7446
7447 <para>After creating a toolbar one can append, prepend and insert items
7448 (that means simple text strings) or elements (that means any widget
7449 types) into the toolbar. To describe an item we need a label text, a
7450 tooltip text, a private tooltip text, an icon for the button and a
7451 callback function for it. For example, to append or prepend an item
7452 you may use the following functions:</para>
7453
7454 <programlisting role="C">
7455 GtkWidget *gtk_toolbar_append_item( GtkToolbar    *toolbar,
7456                                     const char    *text,
7457                                     const char    *tooltip_text,
7458                                     const char    *tooltip_private_text,
7459                                     GtkWidget     *icon,
7460                                     GtkSignalFunc  callback,
7461                                     gpointer       user_data );
7462
7463 GtkWidget *gtk_toolbar_prepend_item( GtkToolbar    *toolbar,
7464                                      const char    *text,
7465                                      const char    *tooltip_text,
7466                                      const char    *tooltip_private_text,
7467                                      GtkWidget     *icon,
7468                                      GtkSignalFunc  callback,
7469                                      gpointer       user_data );
7470 </programlisting>
7471
7472 <para>If you want to use gtk_toolbar_insert_item(), the only additional
7473 parameter which must be specified is the position in which the item
7474 should be inserted, thus:</para>
7475
7476 <programlisting role="C">
7477 GtkWidget *gtk_toolbar_insert_item( GtkToolbar    *toolbar,
7478                                     const char    *text,
7479                                     const char    *tooltip_text,
7480                                     const char    *tooltip_private_text,
7481                                     GtkWidget     *icon,
7482                                     GtkSignalFunc  callback,
7483                                     gpointer       user_data,
7484                                     gint           position );
7485 </programlisting>
7486
7487 <para>To simplify adding spaces between toolbar items, you may use the
7488 following functions:</para>
7489
7490 <programlisting role="C">
7491 void gtk_toolbar_append_space( GtkToolbar *toolbar );
7492
7493 void gtk_toolbar_prepend_space( GtkToolbar *toolbar );
7494
7495 void gtk_toolbar_insert_space( GtkToolbar *toolbar,
7496                                gint        position );
7497 </programlisting>
7498
7499 <para>If it's required, the orientation of a toolbar and its style can be
7500 changed "on the fly" using the following functions:</para>
7501
7502 <programlisting role="C">
7503 void gtk_toolbar_set_orientation( GtkToolbar     *toolbar,
7504                                   GtkOrientation  orientation );
7505
7506 void gtk_toolbar_set_style( GtkToolbar      *toolbar,
7507                             GtkToolbarStyle  style );
7508
7509 void gtk_toolbar_set_tooltips( GtkToolbar *toolbar,
7510                                gint        enable );
7511 </programlisting>
7512
7513 <para>Where <literal>orientation</literal> is one of <literal>GTK_ORIENTATION_HORIZONTAL</literal> or
7514 <literal>GTK_ORIENTATION_VERTICAL</literal>. The <literal>style</literal> is used to set
7515 appearance of the toolbar items by using one of
7516 <literal>GTK_TOOLBAR_ICONS</literal>, <literal>GTK_TOOLBAR_TEXT</literal>, or
7517 <literal>GTK_TOOLBAR_BOTH</literal>.</para>
7518
7519 <para>To show some other things that can be done with a toolbar, let's take
7520 the following program (we'll interrupt the listing with some
7521 additional explanations):</para>
7522
7523 <programlisting role="C">
7524 #include &lt;gtk/gtk.h&gt;
7525
7526 /* This function is connected to the Close button or
7527  * closing the window from the WM */
7528 static gboolean delete_event( GtkWidget *widget,
7529                               GdkEvent *event,
7530                               gpointer data )
7531 {
7532   gtk_main_quit ();
7533   return FALSE;
7534 }
7535 </programlisting>
7536
7537 <para>The above beginning seems for sure familiar to you if it's not your first
7538 GTK program. There is one additional thing though, we include a nice XPM
7539 picture to serve as an icon for all of the buttons.</para>
7540
7541 <programlisting role="C">
7542 GtkWidget* close_button; /* This button will emit signal to close
7543                           * application */
7544 GtkWidget* tooltips_button; /* to enable/disable tooltips */
7545 GtkWidget* text_button,
7546          * icon_button,
7547          * both_button; /* radio buttons for toolbar style */
7548 GtkWidget* entry; /* a text entry to show packing any widget into
7549                    * toolbar */
7550 </programlisting>
7551
7552 <para>In fact not all of the above widgets are needed here, but to make things
7553 clearer I put them all together.</para>
7554
7555 <programlisting role="C">
7556 /* that's easy... when one of the buttons is toggled, we just
7557  * check which one is active and set the style of the toolbar
7558  * accordingly
7559  * ATTENTION: our toolbar is passed as data to callback ! */
7560 static void radio_event( GtkWidget *widget,
7561                          gpointer data )
7562 {
7563   if (GTK_TOGGLE_BUTTON (text_button)->active) 
7564     gtk_toolbar_set_style (GTK_TOOLBAR (data), GTK_TOOLBAR_TEXT);
7565   else if (GTK_TOGGLE_BUTTON (icon_button)->active)
7566     gtk_toolbar_set_style (GTK_TOOLBAR (data), GTK_TOOLBAR_ICONS);
7567   else if (GTK_TOGGLE_BUTTON (both_button)->active)
7568     gtk_toolbar_set_style (GTK_TOOLBAR (data), GTK_TOOLBAR_BOTH);
7569 }
7570
7571 /* even easier, just check given toggle button and enable/disable 
7572  * tooltips */
7573 static void toggle_event( GtkWidget *widget,
7574                           gpointer   data )
7575 {
7576   gtk_toolbar_set_tooltips (GTK_TOOLBAR (data),
7577                             GTK_TOGGLE_BUTTON (widget)->active );
7578 }
7579 </programlisting>
7580
7581 <para>The above are just two callback functions that will be called when
7582 one of the buttons on a toolbar is pressed. You should already be
7583 familiar with things like this if you've already used toggle buttons (and
7584 radio buttons).</para>
7585
7586 <programlisting role="C">
7587 int main (int argc, char *argv[])
7588 {
7589   /* Here is our main window (a dialog) and a handle for the handlebox */
7590   GtkWidget* dialog;
7591   GtkWidget* handlebox;
7592
7593   /* Ok, we need a toolbar, an icon with a mask (one for all of 
7594      the buttons) and an icon widget to put this icon in (but 
7595      we'll create a separate widget for each button) */
7596   GtkWidget * toolbar;
7597   GtkWidget * iconw;
7598
7599   /* this is called in all GTK application. */
7600   gtk_init (&amp;argc, &amp;argv);
7601   
7602   /* create a new window with a given title, and nice size */
7603   dialog = gtk_dialog_new ();
7604   gtk_window_set_title (GTK_WINDOW (dialog), "GTKToolbar Tutorial");
7605   gtk_widget_set_size_request (GTK_WIDGET (dialog), 600, 300);
7606   GTK_WINDOW (dialog)->allow_shrink = TRUE;
7607
7608   /* typically we quit if someone tries to close us */
7609   g_signal_connect (G_OBJECT (dialog), "delete_event",
7610                     G_CALLBACK (delete_event), NULL);
7611
7612   /* we need to realize the window because we use pixmaps for 
7613    * items on the toolbar in the context of it */
7614   gtk_widget_realize (dialog);
7615
7616   /* to make it nice we'll put the toolbar into the handle box, 
7617    * so that it can be detached from the main window */
7618   handlebox = gtk_handle_box_new ();
7619   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
7620                       handlebox, FALSE, FALSE, 5);
7621 </programlisting>
7622
7623 <para>The above should be similar to any other GTK application. Just
7624 initialization of GTK, creating the window, etc. There is only one
7625 thing that probably needs some explanation: a handle box. A handle box
7626 is just another box that can be used to pack widgets in to. The
7627 difference between it and typical boxes is that it can be detached
7628 from a parent window (or, in fact, the handle box remains in the
7629 parent, but it is reduced to a very small rectangle, while all of its
7630 contents are reparented to a new freely floating window). It is
7631 usually nice to have a detachable toolbar, so these two widgets occur
7632 together quite often.</para>
7633
7634 <programlisting role="C">
7635   /* toolbar will be horizontal, with both icons and text, and
7636    * with 5pxl spaces between items and finally, 
7637    * we'll also put it into our handlebox */
7638   toolbar = gtk_toolbar_new ();
7639   gtk_toolbar_set_orientation (GTK_TOOLBAR (toolbar), GTK_ORIENTATION_HORIZONTAL);
7640   gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_BOTH);
7641   gtk_container_set_border_width (GTK_CONTAINER (toolbar), 5);
7642   gtk_toolbar_set_space_size (GTK_TOOLBAR (toolbar), 5);
7643   gtk_container_add (GTK_CONTAINER (handlebox), toolbar);
7644 </programlisting>
7645
7646 <para>Well, what we do above is just a straightforward initialization of
7647 the toolbar widget.</para>
7648
7649 <programlisting role="C">
7650   /* our first item is &lt;close&gt; button */
7651   iconw = gtk_image_new_from_file ("gtk.xpm"); /* icon widget */
7652   close_button = 
7653     gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), /* our toolbar */
7654                              "Close",               /* button label */
7655                              "Closes this app",     /* this button's tooltip */
7656                              "Private",             /* tooltip private info */
7657                              iconw,                 /* icon widget */
7658                              GTK_SIGNAL_FUNC (delete_event), /* a signal */
7659                              NULL);
7660   gtk_toolbar_append_space (GTK_TOOLBAR (toolbar)); /* space after item */
7661 </programlisting>
7662
7663 <para>In the above code you see the simplest case: adding a button to
7664 toolbar.  Just before appending a new item, we have to construct an
7665 image widget to serve as an icon for this item; this step will have
7666 to be repeated for each new item. Just after the item we also add a
7667 space, so the following items will not touch each other. As you see
7668 gtk_toolbar_append_item() returns a pointer to our newly created button
7669 widget, so that we can work with it in the normal way.</para>
7670
7671 <programlisting role="C">
7672   /* now, let's make our radio buttons group... */
7673   iconw = gtk_image_new_from_file ("gtk.xpm");
7674   icon_button = gtk_toolbar_append_element (
7675                     GTK_TOOLBAR (toolbar),
7676                     GTK_TOOLBAR_CHILD_RADIOBUTTON, /* a type of element */
7677                     NULL,                          /* pointer to widget */
7678                     "Icon",                        /* label */
7679                     "Only icons in toolbar",       /* tooltip */
7680                     "Private",                     /* tooltip private string */
7681                     iconw,                         /* icon */
7682                     GTK_SIGNAL_FUNC (radio_event), /* signal */
7683                     toolbar);                      /* data for signal */
7684   gtk_toolbar_append_space (GTK_TOOLBAR (toolbar));
7685 </programlisting>
7686
7687 <para>Here we begin creating a radio buttons group. To do this we use
7688 gtk_toolbar_append_element.  In fact, using this function one can also
7689 +add simple items or even spaces (type = <literal>GTK_TOOLBAR_CHILD_SPACE</literal>
7690 or +<literal>GTK_TOOLBAR_CHILD_BUTTON</literal>). In the above case we start
7691 creating a radio group. In creating other radio buttons for this group
7692 a pointer to the previous button in the group is required, so that a
7693 list of buttons can be easily constructed (see the section on <link
7694 linkend="sec-RadioButtons">Radio Buttons</link> earlier in this
7695 tutorial).</para>
7696
7697 <programlisting role="C">
7698   /* following radio buttons refer to previous ones */
7699   iconw = gtk_image_new_from_file ("gtk.xpm");
7700   text_button = 
7701     gtk_toolbar_append_element (GTK_TOOLBAR (toolbar),
7702                                 GTK_TOOLBAR_CHILD_RADIOBUTTON,
7703                                 icon_button,
7704                                 "Text",
7705                                 "Only texts in toolbar",
7706                                 "Private",
7707                                 iconw,
7708                                 GTK_SIGNAL_FUNC (radio_event),
7709                                 toolbar);
7710   gtk_toolbar_append_space (GTK_TOOLBAR (toolbar));
7711                                           
7712   iconw = gtk_image_new_from_file ("gtk.xpm");
7713   both_button = 
7714     gtk_toolbar_append_element (GTK_TOOLBAR (toolbar),
7715                                 GTK_TOOLBAR_CHILD_RADIOBUTTON,
7716                                 text_button,
7717                                 "Both",
7718                                 "Icons and text in toolbar",
7719                                 "Private",
7720                                 iconw,
7721                                 GTK_SIGNAL_FUNC (radio_event),
7722                                 toolbar);
7723   gtk_toolbar_append_space (GTK_TOOLBAR (toolbar));
7724   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (both_button), TRUE);
7725 </programlisting>
7726
7727 <para>In the end we have to set the state of one of the buttons manually
7728 (otherwise they all stay in active state, preventing us from switching
7729 between them).</para>
7730
7731 <programlisting role="C">
7732   /* here we have just a simple toggle button */
7733   iconw = gtk_image_new_from_file ("gtk.xpm");
7734   tooltips_button = 
7735     gtk_toolbar_append_element (GTK_TOOLBAR (toolbar),
7736                                 GTK_TOOLBAR_CHILD_TOGGLEBUTTON,
7737                                 NULL,
7738                                 "Tooltips",
7739                                 "Toolbar with or without tips",
7740                                 "Private",
7741                                 iconw,
7742                                 GTK_SIGNAL_FUNC (toggle_event),
7743                                 toolbar);
7744   gtk_toolbar_append_space (GTK_TOOLBAR (toolbar));
7745   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (tooltips_button), TRUE);
7746 </programlisting>
7747
7748 <para>A toggle button can be created in the obvious way (if one knows how to create
7749 radio buttons already).</para>
7750
7751 <programlisting role="C">
7752   /* to pack a widget into toolbar, we only have to 
7753    * create it and append it with an appropriate tooltip */
7754   entry = gtk_entry_new ();
7755   gtk_toolbar_append_widget (GTK_TOOLBAR (toolbar), 
7756                              entry, 
7757                              "This is just an entry", 
7758                              "Private");
7759
7760   /* well, it isn't created within the toolbar, so we must still show it */
7761   gtk_widget_show (entry);
7762 </programlisting>
7763
7764 <para>As you see, adding any kind of widget to a toolbar is simple. The
7765 one thing you have to remember is that this widget must be shown manually
7766 (contrary to other items which will be shown together with the toolbar).</para>
7767
7768 <programlisting role="C">
7769   /* that's it ! let's show everything. */
7770   gtk_widget_show (toolbar);
7771   gtk_widget_show (handlebox);
7772   gtk_widget_show (dialog);
7773
7774   /* rest in gtk_main and wait for the fun to begin! */
7775   gtk_main ();
7776   
7777   return 0;
7778 }
7779 </programlisting>
7780
7781 <para>So, here we are at the end of toolbar tutorial. Of course, to appreciate
7782 it in full you need also this nice XPM icon, so here it is:</para>
7783
7784 <programlisting role="C">
7785 /* XPM */
7786 static char * gtk_xpm[] = {
7787 "32 39 5 1",
7788 ".      c none",
7789 "+      c black",
7790 "@      c #3070E0",
7791 "#      c #F05050",
7792 "$      c #35E035",
7793 "................+...............",
7794 "..............+++++.............",
7795 "............+++++@@++...........",
7796 "..........+++++@@@@@@++.........",
7797 "........++++@@@@@@@@@@++........",
7798 "......++++@@++++++++@@@++.......",
7799 ".....+++@@@+++++++++++@@@++.....",
7800 "...+++@@@@+++@@@@@@++++@@@@+....",
7801 "..+++@@@@+++@@@@@@@@+++@@@@@++..",
7802 ".++@@@@@@+++@@@@@@@@@@@@@@@@@@++",
7803 ".+#+@@@@@@++@@@@+++@@@@@@@@@@@@+",
7804 ".+##++@@@@+++@@@+++++@@@@@@@@$@.",
7805 ".+###++@@@@+++@@@+++@@@@@++$$$@.",
7806 ".+####+++@@@+++++++@@@@@+@$$$$@.",
7807 ".+#####+++@@@@+++@@@@++@$$$$$$+.",
7808 ".+######++++@@@@@@@++@$$$$$$$$+.",
7809 ".+#######+##+@@@@+++$$$$$$@@$$+.",
7810 ".+###+++##+##+@@++@$$$$$$++$$$+.",
7811 ".+###++++##+##+@@$$$$$$$@+@$$@+.",
7812 ".+###++++++#+++@$$@+@$$@++$$$@+.",
7813 ".+####+++++++#++$$@+@$$++$$$$+..",
7814 ".++####++++++#++$$@+@$++@$$$$+..",
7815 ".+#####+++++##++$$++@+++$$$$$+..",
7816 ".++####+++##+#++$$+++++@$$$$$+..",
7817 ".++####+++####++$$++++++@$$$@+..",
7818 ".+#####++#####++$$+++@++++@$@+..",
7819 ".+#####++#####++$$++@$$@+++$@@..",
7820 ".++####++#####++$$++$$$$$+@$@++.",
7821 ".++####++#####++$$++$$$$$$$$+++.",
7822 ".+++####+#####++$$++$$$$$$$@+++.",
7823 "..+++#########+@$$+@$$$$$$+++...",
7824 "...+++########+@$$$$$$$$@+++....",
7825 ".....+++######+@$$$$$$$+++......",
7826 "......+++#####+@$$$$$@++........",
7827 ".......+++####+@$$$$+++.........",
7828 ".........++###+$$$@++...........",
7829 "..........++##+$@+++............",
7830 "...........+++++++..............",
7831 ".............++++..............."};
7832 </programlisting>
7833
7834 </sect1>
7835
7836 <!-- ----------------------------------------------------------------- -->
7837 <sect1 id="sec-Notebooks">
7838 <title>Notebooks</title>
7839
7840 <para>The NoteBook Widget is a collection of "pages" that overlap each
7841 other, each page contains different information with only one page
7842 visible at a time. This widget has become more common lately in GUI
7843 programming, and it is a good way to show blocks of similar
7844 information that warrant separation in their display.</para>
7845
7846 <para>The first function call you will need to know, as you can probably
7847 guess by now, is used to create a new notebook widget.</para>
7848
7849 <programlisting role="C">
7850 GtkWidget *gtk_notebook_new( void );
7851 </programlisting>
7852
7853 <para>Once the notebook has been created, there are a number of functions
7854 that operate on the notebook widget. Let's look at them individually.</para>
7855
7856 <para>The first one we will look at is how to position the page indicators.
7857 These page indicators or "tabs" as they are referred to, can be
7858 positioned in four ways: top, bottom, left, or right.</para>
7859
7860 <programlisting role="C">
7861 void gtk_notebook_set_tab_pos( GtkNotebook     *notebook,
7862                                GtkPositionType  pos );
7863 </programlisting>
7864
7865 <para>GtkPositionType will be one of the following, which are pretty self
7866 explanatory:</para>
7867 <programlisting role="C">
7868   GTK_POS_LEFT
7869   GTK_POS_RIGHT
7870   GTK_POS_TOP
7871   GTK_POS_BOTTOM
7872 </programlisting>
7873
7874 <para><literal>GTK_POS_TOP</literal> is the default.</para>
7875
7876 <para>Next we will look at how to add pages to the notebook. There are three
7877 ways to add pages to the NoteBook. Let's look at the first two
7878 together as they are quite similar.</para>
7879
7880 <programlisting role="C">
7881 void gtk_notebook_append_page( GtkNotebook *notebook,
7882                                GtkWidget   *child,
7883                                GtkWidget   *tab_label );
7884
7885 void gtk_notebook_prepend_page( GtkNotebook *notebook,
7886                                 GtkWidget   *child,
7887                                 GtkWidget   *tab_label );
7888 </programlisting>
7889
7890 <para>These functions add pages to the notebook by inserting them from the
7891 back of the notebook (append), or the front of the notebook (prepend).
7892 <literal>child</literal> is the widget that is placed within the notebook page, and
7893 <literal>tab_label</literal> is the label for the page being added. The <literal>child</literal>
7894 widget must be created separately, and is typically a set of options
7895 setup witin one of the other container widgets, such as a table.</para>
7896
7897 <para>The final function for adding a page to the notebook contains all of
7898 the properties of the previous two, but it allows you to specify what
7899 position you want the page to be in the notebook.</para>
7900
7901 <programlisting role="C">
7902 void gtk_notebook_insert_page( GtkNotebook *notebook,
7903                                GtkWidget   *child,
7904                                GtkWidget   *tab_label,
7905                                gint         position );
7906 </programlisting>
7907
7908 <para>The parameters are the same as _append_ and _prepend_ except it
7909 contains an extra parameter, <literal>position</literal>.  This parameter is used to
7910 specify what place this page will be inserted into the first page
7911 having position zero.</para>
7912
7913 <para>Now that we know how to add a page, lets see how we can remove a page
7914 from the notebook.</para>
7915
7916 <programlisting role="C">
7917 void gtk_notebook_remove_page( GtkNotebook *notebook,
7918                                gint         page_num );
7919 </programlisting>
7920
7921 <para>This function takes the page specified by <literal>page_num</literal> and removes it
7922 from the widget pointed to by <literal>notebook</literal>.</para>
7923
7924 <para>To find out what the current page is in a notebook use the function:</para>
7925
7926 <programlisting role="C">
7927 gint gtk_notebook_get_current_page( GtkNotebook *notebook );
7928 </programlisting>
7929
7930 <para>These next two functions are simple calls to move the notebook page
7931 forward or backward. Simply provide the respective function call with
7932 the notebook widget you wish to operate on. Note: When the NoteBook is
7933 currently on the last page, and gtk_notebook_next_page() is called, the
7934 notebook will wrap back to the first page. Likewise, if the NoteBook
7935 is on the first page, and gtk_notebook_prev_page() is called, the
7936 notebook will wrap to the last page.</para>
7937
7938 <programlisting role="C">
7939 void gtk_notebook_next_page( GtkNoteBook *notebook );
7940
7941 void gtk_notebook_prev_page( GtkNoteBook *notebook );
7942 </programlisting>
7943
7944 <para>This next function sets the "active" page. If you wish the notebook to
7945 be opened to page 5 for example, you would use this function.  Without
7946 using this function, the notebook defaults to the first page.</para>
7947
7948 <programlisting role="C">
7949 void gtk_notebook_set_current_page( GtkNotebook *notebook,
7950                                     gint         page_num );
7951 </programlisting>
7952
7953 <para>The next two functions add or remove the notebook page tabs and the
7954 notebook border respectively.</para>
7955
7956 <programlisting role="C">
7957 void gtk_notebook_set_show_tabs( GtkNotebook *notebook,
7958                                  gboolean     show_tabs );
7959
7960 void gtk_notebook_set_show_border( GtkNotebook *notebook,
7961                                    gboolean     show_border );
7962 </programlisting>
7963
7964 <para>The next function is useful when the you have a large number of pages,
7965 and the tabs don't fit on the page. It allows the tabs to be scrolled
7966 through using two arrow buttons.</para>
7967
7968 <programlisting role="C">
7969 void gtk_notebook_set_scrollable( GtkNotebook *notebook,
7970                                   gboolean     scrollable );
7971 </programlisting>
7972
7973 <para><literal>show_tabs</literal>, <literal>show_border</literal> and <literal>scrollable</literal> can be either
7974 TRUE or FALSE.</para>
7975
7976 <para>Now let's look at an example, it is expanded from the 
7977 <filename>testgtk.c</filename> code
7978 that comes with the GTK distribution. This small program creates a
7979 window with a notebook and six buttons. The notebook contains 11
7980 pages, added in three different ways, appended, inserted, and
7981 prepended. The buttons allow you rotate the tab positions, add/remove
7982 the tabs and border, remove a page, change pages in both a forward and
7983 backward manner, and exit the program.</para>
7984
7985 <para>
7986 <inlinemediaobject>
7987 <imageobject>
7988 <imagedata fileref="images/notebook.png" format="png">
7989 </imageobject>
7990 </inlinemediaobject>
7991 </para>
7992
7993 <programlisting role="C">
7994 <!-- example-start notebook notebook.c -->
7995
7996 #include &lt;stdio.h&gt;
7997 #include &lt;gtk/gtk.h&gt;
7998
7999 /* This function rotates the position of the tabs */
8000 static void rotate_book( GtkButton   *button,
8001                          GtkNotebook *notebook )
8002 {
8003     gtk_notebook_set_tab_pos (notebook, (notebook-&gt;tab_pos + 1) % 4);
8004 }
8005
8006 /* Add/Remove the page tabs and the borders */
8007 static void tabsborder_book( GtkButton   *button,
8008                              GtkNotebook *notebook )
8009 {
8010     gint tval = FALSE;
8011     gint bval = FALSE;
8012     if (notebook-&gt;show_tabs == 0)
8013             tval = TRUE; 
8014     if (notebook-&gt;show_border == 0)
8015             bval = TRUE;
8016     
8017     gtk_notebook_set_show_tabs (notebook, tval);
8018     gtk_notebook_set_show_border (notebook, bval);
8019 }
8020
8021 /* Remove a page from the notebook */
8022 static void remove_book( GtkButton   *button,
8023                          GtkNotebook *notebook )
8024 {
8025     gint page;
8026     
8027     page = gtk_notebook_get_current_page (notebook);
8028     gtk_notebook_remove_page (notebook, page);
8029     /* Need to refresh the widget -- 
8030      This forces the widget to redraw itself. */
8031     gtk_widget_queue_draw (GTK_WIDGET (notebook));
8032 }
8033
8034 static gboolean delete( GtkWidget *widget,
8035                         GtkWidget *event,
8036                         gpointer   data )
8037 {
8038     gtk_main_quit ();
8039     return FALSE;
8040 }
8041
8042 int main( int argc,
8043           char *argv[] )
8044 {
8045     GtkWidget *window;
8046     GtkWidget *button;
8047     GtkWidget *table;
8048     GtkWidget *notebook;
8049     GtkWidget *frame;
8050     GtkWidget *label;
8051     GtkWidget *checkbutton;
8052     int i;
8053     char bufferf[32];
8054     char bufferl[32];
8055     
8056     gtk_init (&amp;argc, &amp;argv);
8057     
8058     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
8059     
8060     g_signal_connect (G_OBJECT (window), "delete_event",
8061                       G_CALLBACK (delete), NULL);
8062     
8063     gtk_container_set_border_width (GTK_CONTAINER (window), 10);
8064
8065     table = gtk_table_new (3, 6, FALSE);
8066     gtk_container_add (GTK_CONTAINER (window), table);
8067     
8068     /* Create a new notebook, place the position of the tabs */
8069     notebook = gtk_notebook_new ();
8070     gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP);
8071     gtk_table_attach_defaults (GTK_TABLE (table), notebook, 0, 6, 0, 1);
8072     gtk_widget_show (notebook);
8073     
8074     /* Let's append a bunch of pages to the notebook */
8075     for (i = 0; i &lt; 5; i++) {
8076         sprintf(bufferf, "Append Frame %d", i + 1);
8077         sprintf(bufferl, "Page %d", i + 1);
8078         
8079         frame = gtk_frame_new (bufferf);
8080         gtk_container_set_border_width (GTK_CONTAINER (frame), 10);
8081         gtk_widget_set_size_request (frame, 100, 75);
8082         gtk_widget_show (frame);
8083         
8084         label = gtk_label_new (bufferf);
8085         gtk_container_add (GTK_CONTAINER (frame), label);
8086         gtk_widget_show (label);
8087         
8088         label = gtk_label_new (bufferl);
8089         gtk_notebook_append_page (GTK_NOTEBOOK (notebook), frame, label);
8090     }
8091       
8092     /* Now let's add a page to a specific spot */
8093     checkbutton = gtk_check_button_new_with_label ("Check me please!");
8094     gtk_widget_set_size_request (checkbutton, 100, 75);
8095     gtk_widget_show (checkbutton);
8096    
8097     label = gtk_label_new ("Add page");
8098     gtk_notebook_insert_page (GTK_NOTEBOOK (notebook), checkbutton, label, 2);
8099     
8100     /* Now finally let's prepend pages to the notebook */
8101     for (i = 0; i &lt; 5; i++) {
8102         sprintf (bufferf, "Prepend Frame %d", i + 1);
8103         sprintf (bufferl, "PPage %d", i + 1);
8104         
8105         frame = gtk_frame_new (bufferf);
8106         gtk_container_set_border_width (GTK_CONTAINER (frame), 10);
8107         gtk_widget_set_size_request (frame, 100, 75);
8108         gtk_widget_show (frame);
8109         
8110         label = gtk_label_new (bufferf);
8111         gtk_container_add (GTK_CONTAINER (frame), label);
8112         gtk_widget_show (label);
8113         
8114         label = gtk_label_new (bufferl);
8115         gtk_notebook_prepend_page (GTK_NOTEBOOK (notebook), frame, label);
8116     }
8117     
8118     /* Set what page to start at (page 4) */
8119     gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), 3);
8120
8121     /* Create a bunch of buttons */
8122     button = gtk_button_new_with_label ("close");
8123     g_signal_connect_swapped (G_OBJECT (button), "clicked",
8124                               G_CALLBACK (delete), NULL);
8125     gtk_table_attach_defaults (GTK_TABLE (table), button, 0, 1, 1, 2);
8126     gtk_widget_show (button);
8127     
8128     button = gtk_button_new_with_label ("next page");
8129     g_signal_connect_swapped (G_OBJECT (button), "clicked",
8130                               G_CALLBACK (gtk_notebook_next_page),
8131                               G_OBJECT (notebook));
8132     gtk_table_attach_defaults (GTK_TABLE (table), button, 1, 2, 1, 2);
8133     gtk_widget_show (button);
8134     
8135     button = gtk_button_new_with_label ("prev page");
8136     g_signal_connect_swapped (G_OBJECT (button), "clicked",
8137                               G_CALLBACK (gtk_notebook_prev_page),
8138                               G_OBJECT (notebook));
8139     gtk_table_attach_defaults (GTK_TABLE (table), button, 2, 3, 1, 2);
8140     gtk_widget_show (button);
8141     
8142     button = gtk_button_new_with_label ("tab position");
8143     g_signal_connect (G_OBJECT (button), "clicked",
8144                       G_CALLBACK (rotate_book),
8145                       (gpointer) notebook);
8146     gtk_table_attach_defaults (GTK_TABLE (table), button, 3, 4, 1, 2);
8147     gtk_widget_show (button);
8148     
8149     button = gtk_button_new_with_label ("tabs/border on/off");
8150     g_signal_connect (G_OBJECT (button), "clicked",
8151                       G_CALLBACK (tabsborder_book),
8152                       (gpointer) notebook);
8153     gtk_table_attach_defaults (GTK_TABLE (table), button, 4, 5, 1, 2);
8154     gtk_widget_show (button);
8155     
8156     button = gtk_button_new_with_label ("remove page");
8157     g_signal_connect (G_OBJECT (button), "clicked",
8158                       G_CALLBACK (remove_book),
8159                       (gpointer) notebook);
8160     gtk_table_attach_defaults (GTK_TABLE (table), button, 5, 6, 1, 2);
8161     gtk_widget_show (button);
8162     
8163     gtk_widget_show (table);
8164     gtk_widget_show (window);
8165     
8166     gtk_main ();
8167     
8168     return 0;
8169 }
8170 <!-- example-end -->
8171 </programlisting>
8172
8173 <para>I hope this helps you on your way with creating notebooks for your
8174 GTK applications.</para>
8175
8176 </sect1>
8177 </chapter>
8178
8179 <!-- ***************************************************************** -->
8180 <chapter id="ch-MenuWidget">
8181 <title>Menu Widget</title>
8182
8183 <para>There are two ways to create menus: there's the easy way, and there's
8184 the hard way. Both have their uses, but you can usually use the
8185 Itemfactory (the easy way). The "hard" way is to create all the menus
8186 using the calls directly. The easy way is to use the gtk_item_factory
8187 calls. This is much simpler, but there are advantages and
8188 disadvantages to each approach.</para>
8189
8190 <para>The Itemfactory is much easier to use, and to add new menus to,
8191 although writing a few wrapper functions to create menus using the
8192 manual method could go a long way towards usability. With the
8193 Itemfactory, it is not possible to add images or the character '/' to
8194 the menus.</para>
8195
8196 <!-- ----------------------------------------------------------------- -->
8197 <sect1 id="sec-ManualMenuCreation">
8198 <title>Manual Menu Creation</title>
8199
8200 <para>In the true tradition of teaching, we'll show you the hard way
8201 first. <literal>:)</literal></para>
8202
8203 <para>There are three widgets that go into making a menubar and submenus:</para>
8204
8205 <itemizedlist>
8206 <listitem><simpara>a menu item, which is what the user wants to select, e.g.,
8207 "Save"</simpara>
8208 </listitem>
8209 <listitem><simpara>a menu, which acts as a container for the menu items, and</simpara>
8210 </listitem>
8211 <listitem><simpara>a menubar, which is a container for each of the individual
8212 menus.</simpara>
8213 </listitem>
8214 </itemizedlist>
8215
8216 <para>This is slightly complicated by the fact that menu item widgets are
8217 used for two different things. They are both the widgets that are
8218 packed into the menu, and the widget that is packed into the menubar,
8219 which, when selected, activates the menu.</para>
8220
8221 <para>Let's look at the functions that are used to create menus and
8222 menubars.  This first function is used to create a new menubar.</para>
8223
8224 <programlisting role="C">
8225 GtkWidget *gtk_menu_bar_new( void );
8226 </programlisting>
8227
8228 <para>This rather self explanatory function creates a new menubar. You use
8229 gtk_container_add() to pack this into a window, or the box_pack
8230 functions to pack it into a box - the same as buttons.</para>
8231
8232 <programlisting role="C">
8233 GtkWidget *gtk_menu_new( void );
8234 </programlisting>
8235
8236 <para>This function returns a pointer to a new menu; it is never actually
8237 shown (with gtk_widget_show()), it is just a container for the menu
8238 items. I hope this will become more clear when you look at the
8239 example below.</para>
8240
8241 <para>The next three calls are used to create menu items that are packed into
8242 the menu (and menubar).</para>
8243
8244 <programlisting role="C">
8245 GtkWidget *gtk_menu_item_new( void );
8246
8247 GtkWidget *gtk_menu_item_new_with_label( const char *label );
8248
8249 GtkWidget *gtk_menu_item_new_with_mnemnonic( const char *label );
8250 </programlisting>
8251
8252 <para>These calls are used to create the menu items that are to be
8253 displayed.  Remember to differentiate between a "menu" as created with
8254 gtk_menu_new() and a "menu item" as created by the gtk_menu_item_new()
8255 functions. The menu item will be an actual button with an associated
8256 action, whereas a menu will be a container holding menu items.</para>
8257
8258 <para>The gtk_menu_item_new_with_label() and gtk_menu_item_new() functions are just as
8259 you'd expect after reading about the buttons. One creates a new menu
8260 item with a label already packed into it, and the other just creates a
8261 blank menu item.</para>
8262
8263 <para>Once you've created a menu item you have to put it into a menu. This
8264 is done using the function gtk_menu_shelll_append. In order to capture when
8265 the item is selected by the user, we need to connect to the
8266 <literal>activate</literal> signal in the usual way. So, if we wanted to create a
8267 standard <literal>File</literal> menu, with the options <literal>Open</literal>, <literal>Save</literal>, and
8268 <literal>Quit</literal>, the code would look something like:</para>
8269
8270 <programlisting role="C">
8271     file_menu = gtk_menu_new ();    /* Don't need to show menus */
8272
8273     /* Create the menu items */
8274     open_item = gtk_menu_item_new_with_label ("Open");
8275     save_item = gtk_menu_item_new_with_label ("Save");
8276     quit_item = gtk_menu_item_new_with_label ("Quit");
8277
8278     /* Add them to the menu */
8279     gtk_menu_shell_append (GTK_MENU_SHELL (file_menu), open_item);
8280     gtk_menu_shell_append (GTK_MENU_SHELL (file_menu), save_item);
8281     gtk_menu_shell_append (GTK_MENU_SHELL (file_menu), quit_item);
8282
8283     /* Attach the callback functions to the activate signal */
8284     g_signal_connect_swapped (G_OBJECT (open_item), "activate",
8285                               G_CALLBACK (menuitem_response),
8286                               (gpointer) "file.open");
8287     g_signal_connect_swapped (G_OBJECT (save_item), "activate",
8288                               G_CALLBACK (menuitem_response),
8289                               (gpointer) "file.save");
8290
8291     /* We can attach the Quit menu item to our exit function */
8292     g_signal_connect_swapped (G_OBJECT (quit_item), "activate",
8293                               G_CALLBACK (destroy),
8294                               (gpointer) "file.quit");
8295
8296     /* We do need to show menu items */
8297     gtk_widget_show (open_item);
8298     gtk_widget_show (save_item);
8299     gtk_widget_show (quit_item);
8300 </programlisting>
8301
8302 <para>At this point we have our menu. Now we need to create a menubar and a
8303 menu item for the <literal>File</literal> entry, to which we add our menu. The code
8304 looks like this:</para>
8305
8306 <programlisting role="C">
8307     menu_bar = gtk_menu_bar_new ();
8308     gtk_container_add (GTK_CONTAINER (window), menu_bar);
8309     gtk_widget_show (menu_bar);
8310
8311     file_item = gtk_menu_item_new_with_label ("File");
8312     gtk_widget_show (file_item);
8313 </programlisting>
8314
8315 <para>Now we need to associate the menu with <literal>file_item</literal>. This is done
8316 with the function</para>
8317
8318 <programlisting role="C">
8319 void gtk_menu_item_set_submenu( GtkMenuItem *menu_item,
8320                                 GtkWidget   *submenu );
8321 </programlisting>
8322
8323 <para>So, our example would continue with</para>
8324
8325 <programlisting role="C">
8326     gtk_menu_item_set_submenu (GTK_MENU_ITEM (file_item), file_menu);
8327 </programlisting>
8328
8329 <para>All that is left to do is to add the menu to the menubar, which is
8330 accomplished using the function</para>
8331
8332 <programlisting role="C">
8333 void gtk_menu_bar_append( GtkMenuBar *menu_bar,
8334                           GtkWidget  *menu_item );
8335 </programlisting>
8336
8337 <para>which in our case looks like this:</para>
8338
8339 <programlisting role="C">
8340     gtk_menu_bar_append (GTK_MENU_BAR (menu_bar), file_item);
8341 </programlisting>
8342
8343 <para>If we wanted the menu right justified on the menubar, such as help
8344 menus often are, we can use the following function (again on
8345 <literal>file_item</literal> in the current example) before attaching it to the
8346 menubar.</para>
8347
8348 <programlisting role="C">
8349 void gtk_menu_item_right_justify( GtkMenuItem *menu_item );
8350 </programlisting>
8351
8352 <para>Here is a summary of the steps needed to create a menu bar with menus
8353 attached:</para>
8354
8355 <itemizedlist>
8356 <listitem><simpara> Create a new menu using gtk_menu_new()</simpara>
8357 </listitem>
8358
8359 <listitem><simpara> Use multiple calls to gtk_menu_item_new() for each item you
8360 wish to have on your menu. And use gtk_menu_shell_append() to put each of
8361 these new items on to the menu.</simpara>
8362 </listitem>
8363
8364 <listitem><simpara> Create a menu item using gtk_menu_item_new(). This will be the
8365 root of the menu, the text appearing here will be on the menubar
8366 itself.</simpara>
8367 </listitem>
8368
8369 <listitem><simpara>Use gtk_menu_item_set_submenu() to attach the menu to the root
8370 menu item (the one created in the above step).</simpara>
8371 </listitem>
8372
8373 <listitem><simpara> Create a new menubar using gtk_menu_bar_new. This step only
8374 needs to be done once when creating a series of menus on one menu bar.</simpara>
8375 </listitem>
8376
8377 <listitem><simpara> Use gtk_menu_bar_append() to put the root menu onto the menubar.</simpara>
8378 </listitem>
8379 </itemizedlist>
8380
8381 <para>Creating a popup menu is nearly the same. The difference is that the
8382 menu is not posted "automatically" by a menubar, but explicitly by
8383 calling the function gtk_menu_popup() from a button-press event, for
8384 example.  Take these steps:</para>
8385
8386 <itemizedlist>
8387 <listitem><simpara>Create an event handling function. It needs to have the
8388 prototype</simpara>
8389 <programlisting role="C">
8390 static gboolean handler( GtkWidget *widget,
8391                          GdkEvent  *event );
8392 </programlisting>
8393 <simpara>and it will use the event to find out where to pop up the menu.</simpara>
8394 </listitem>
8395
8396 <listitem><simpara>In the event handler, if the event is a mouse button press,
8397 treat <literal>event</literal> as a button event (which it is) and use it as
8398 shown in the sample code to pass information to gtk_menu_popup().</simpara>
8399 </listitem>
8400
8401 <listitem><simpara>Bind that event handler to a widget with</simpara>
8402 <programlisting role="C">
8403     g_signal_connect_swapped (G_OBJECT (widget), "event",
8404                               G_CALLBACK (handler),
8405                               G_OBJECT (menu));
8406 </programlisting>
8407 <simpara>where <literal>widget</literal> is the widget you are binding to,
8408 <literal>handler</literal> is the handling function, and <literal>menu</literal> is a menu
8409 created with gtk_menu_new(). This can be a menu which is also posted
8410 by a menu bar, as shown in the sample code.</simpara>
8411 </listitem>
8412 </itemizedlist>
8413
8414 </sect1>
8415
8416 <!-- ----------------------------------------------------------------- -->
8417 <sect1 id="sec-ManualMenuExample">
8418 <title>Manual Menu Example</title>
8419
8420 <para>That should about do it. Let's take a look at an example to help clarify.</para>
8421
8422 <para>
8423 <inlinemediaobject>
8424 <imageobject>
8425 <imagedata fileref="images/menu.png" format="png">
8426 </imageobject>
8427 </inlinemediaobject>
8428 </para>
8429
8430 <programlisting role="C">
8431 <!-- example-start menu menu.c -->
8432
8433 #include &lt;stdio.h&gt;
8434 #include &lt;gtk/gtk.h&gt;
8435
8436 static gboolean button_press (GtkWidget *, GdkEvent *);
8437 static void menuitem_response (gchar *);
8438
8439 int main( int   argc,
8440           char *argv[] )
8441 {
8442
8443     GtkWidget *window;
8444     GtkWidget *menu;
8445     GtkWidget *menu_bar;
8446     GtkWidget *root_menu;
8447     GtkWidget *menu_items;
8448     GtkWidget *vbox;
8449     GtkWidget *button;
8450     char buf[128];
8451     int i;
8452
8453     gtk_init (&amp;argc, &amp;argv);
8454
8455     /* create a new window */
8456     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
8457     gtk_widget_set_size_request (GTK_WIDGET (window), 200, 100);
8458     gtk_window_set_title (GTK_WINDOW (window), "GTK Menu Test");
8459     g_signal_connect (G_OBJECT (window), "delete_event",
8460                       G_CALLBACK (gtk_main_quit), NULL);
8461
8462     /* Init the menu-widget, and remember -- never
8463      * gtk_show_widget() the menu widget!! 
8464      * This is the menu that holds the menu items, the one that
8465      * will pop up when you click on the "Root Menu" in the app */
8466     menu = gtk_menu_new ();
8467
8468     /* Next we make a little loop that makes three menu-entries for "test-menu".
8469      * Notice the call to gtk_menu_shell_append.  Here we are adding a list of
8470      * menu items to our menu.  Normally, we'd also catch the "clicked"
8471      * signal on each of the menu items and setup a callback for it,
8472      * but it's omitted here to save space. */
8473
8474     for (i = 0; i &lt; 3; i++)
8475         {
8476             /* Copy the names to the buf. */
8477             sprintf (buf, "Test-undermenu - %d", i);
8478
8479             /* Create a new menu-item with a name... */
8480             menu_items = gtk_menu_item_new_with_label (buf);
8481
8482             /* ...and add it to the menu. */
8483             gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_items);
8484
8485             /* Do something interesting when the menuitem is selected */
8486             g_signal_connect_swapped (G_OBJECT (menu_items), "activate",
8487                                       G_CALLBACK (menuitem_response), 
8488                                       (gpointer) g_strdup (buf));
8489
8490             /* Show the widget */
8491             gtk_widget_show (menu_items);
8492         }
8493
8494     /* This is the root menu, and will be the label
8495      * displayed on the menu bar.  There won't be a signal handler attached,
8496      * as it only pops up the rest of the menu when pressed. */
8497     root_menu = gtk_menu_item_new_with_label ("Root Menu");
8498
8499     gtk_widget_show (root_menu);
8500
8501     /* Now we specify that we want our newly created "menu" to be the menu
8502      * for the "root menu" */
8503     gtk_menu_item_set_submenu (GTK_MENU_ITEM (root_menu), menu);
8504
8505     /* A vbox to put a menu and a button in: */
8506     vbox = gtk_vbox_new (FALSE, 0);
8507     gtk_container_add (GTK_CONTAINER (window), vbox);
8508     gtk_widget_show (vbox);
8509
8510     /* Create a menu-bar to hold the menus and add it to our main window */
8511     menu_bar = gtk_menu_bar_new ();
8512     gtk_box_pack_start (GTK_BOX (vbox), menu_bar, FALSE, FALSE, 2);
8513     gtk_widget_show (menu_bar);
8514
8515     /* Create a button to which to attach menu as a popup */
8516     button = gtk_button_new_with_label ("press me");
8517     g_signal_connect_swapped (G_OBJECT (button), "event",
8518                               G_CALLBACK (button_press), 
8519                               G_OBJECT (menu));
8520     gtk_box_pack_end (GTK_BOX (vbox), button, TRUE, TRUE, 2);
8521     gtk_widget_show (button);
8522
8523     /* And finally we append the menu-item to the menu-bar -- this is the
8524      * "root" menu-item I have been raving about =) */
8525     gtk_menu_shell_append (GTK_MENU_SHELL (menu_bar), root_menu);
8526
8527     /* always display the window as the last step so it all splashes on
8528      * the screen at once. */
8529     gtk_widget_show (window);
8530
8531     gtk_main ();
8532
8533     return 0;
8534 }
8535
8536 /* Respond to a button-press by posting a menu passed in as widget.
8537  *
8538  * Note that the "widget" argument is the menu being posted, NOT
8539  * the button that was pressed.
8540  */
8541
8542 static gboolean button_press( GtkWidget *widget,
8543                               GdkEvent *event )
8544 {
8545
8546     if (event-&gt;type == GDK_BUTTON_PRESS) {
8547         GdkEventButton *bevent = (GdkEventButton *) event; 
8548         gtk_menu_popup (GTK_MENU (widget), NULL, NULL, NULL, NULL,
8549                         bevent-&gt;button, bevent-&gt;time);
8550         /* Tell calling code that we have handled this event; the buck
8551          * stops here. */
8552         return TRUE;
8553     }
8554
8555     /* Tell calling code that we have not handled this event; pass it on. */
8556     return FALSE;
8557 }
8558
8559
8560 /* Print a string when a menu item is selected */
8561
8562 static void menuitem_response( gchar *string )
8563 {
8564     printf ("%s\n", string);
8565 }
8566 <!-- example-end -->
8567 </programlisting>
8568
8569 <para>You may also set a menu item to be insensitive and, using an accelerator
8570 table, bind keys to menu functions.</para>
8571
8572 </sect1>
8573
8574 <!-- ----------------------------------------------------------------- -->
8575 <sect1 id="sec-UsingItemFactory">
8576 <title>Using ItemFactory</title>
8577
8578 <para>Now that we've shown you the hard way, here's how you do it using the
8579 gtk_item_factory calls.</para>
8580
8581 <para>ItemFactory creates a menu out of an array of ItemFactory entries. This 
8582 means you can define your menu in its simplest form and then create the
8583 menu/menubar widgets with a minimum of function calls.</para>
8584
8585 <!-- ----------------------------------------------------------------- -->
8586 <sect2 id="sec-ItemFactoryEntries">
8587 <title>ItemFactory entries</title>
8588
8589 <para>At the core of ItemFactory is the ItemFactoryEntry. This structure defines
8590 one menu item, and when an array of these entries is defined a whole
8591 menu is formed. The ItemFactory entry struct definition looks like this:</para>
8592
8593 <programlisting role="C">
8594 struct _GtkItemFactoryEntry
8595 {
8596   gchar *path;
8597   gchar *accelerator;
8598
8599   GtkItemFactoryCallback callback;
8600   guint                  callback_action;
8601
8602   gchar          *item_type;
8603 };
8604 </programlisting>
8605
8606 <para>Each field defines part of the menu item.</para>
8607
8608 <para><literal>*path</literal> is a string which defines both the name and the
8609 path of a menu item, for example, "/File/Open" would be the name of a menu
8610 item which would come under the ItemFactory entry with path "/File". Note however
8611 that "/File/Open" would be displayed in the File menu as "Open". Also note
8612 since the forward slashes are used to define the path of the menu,
8613 they cannot be used as part of the name. A letter preceded by an underscore
8614 indicates an accelerator (shortcut) key once the menu is open.</para>
8615
8616 <para>
8617 <literal>*accelerator</literal> is a string that indicates a key combination
8618 that can be used as a shortcut to that menu item. The string can be made up
8619 of either a single character, or a combination of modifier keys with a single
8620 character. It is case insensitive.</para>
8621
8622
8623 <para>The available modifier keys are:</para>
8624
8625 <programlisting role="C">
8626 "&lt;ALT&gt;                             - alt
8627 "&lt;CTL&gt;" or "&lt;CTRL&gt;" or "&lt;CONTROL&gt;" - control
8628 "&lt;MOD1&gt;" to "&lt;MOD5&gt;"               - modn
8629 "&lt;SHFT&gt;" or "&lt;SHIFT&gt;"              - shift
8630 </programlisting>
8631
8632 <para>Examples:</para>
8633 <programlisting role="C">
8634 "&lt;ConTroL&gt;a"
8635 "&lt;SHFT&gt;&lt;ALT&gt;&lt;CONTROL&gt;X"
8636 </programlisting>
8637
8638 <para>
8639 <literal>callback</literal> is the function that is called when the menu item
8640 emits the "activate" signal. The form of the callback is described
8641 in the <link linkend="sec-ItemFactoryCallback">Callback Description</link>
8642 section.</para>
8643
8644 <para>
8645 The value of <literal>callback_action</literal> is passed to the callback
8646 function. It also affects the function prototype, as shown
8647 in the <link linkend="sec-ItemFactoryCallback">Callback Description</link>
8648 section.</para>
8649
8650 <para>
8651 <literal>item_type</literal> is a string that defines what type of widget is
8652 packed into the menu items container. It can be:</para>
8653
8654 <programlisting role="C">
8655 NULL or "" or "&lt;Item&gt;" - create a simple item
8656 "&lt;Title&gt;"              - create a title item
8657 "&lt;CheckItem&gt;"          - create a check item
8658 "&lt;ToggleItem&gt;"         - create a toggle item
8659 "&lt;RadioItem&gt;"          - create a (root) radio item
8660 "Path"                 - create a sister radio item
8661 "&lt;Tearoff&gt;"            - create a tearoff
8662 "&lt;Separator&gt;"          - create a separator
8663 "&lt;Branch&gt;"             - create an item to hold submenus (optional)
8664 "&lt;LastBranch&gt;"         - create a right justified branch
8665 "&lt;StockItem&gt;"          - create a simple item with a stock image. 
8666                                see <filename>gtkstock.h</filename> for builtin stock items
8667  
8668 </programlisting>
8669
8670 <para>Note that &lt;LastBranch&gt; is only useful for one submenu of
8671 a menubar.</para>
8672
8673 <!-- ----------------------------------------------------------------- -->
8674 <sect3 id="sec-ItemFactoryCallback">
8675 <title>Callback Description</title>
8676
8677 <para>
8678 The callback for an ItemFactory entry can take two forms. If
8679 <literal>callback_action</literal> is zero, it is of the following
8680 form:</para>
8681
8682 <programlisting role="C">
8683 void callback( void )
8684 </programlisting>
8685
8686 <para>otherwise it is of the form:</para>
8687
8688 <programlisting role="C">
8689 void callback( gpointer    callback_data,
8690                guint       callback_action,
8691                GtkWidget  *widget )
8692 </programlisting>
8693
8694 <para>
8695 <literal>callback_data</literal> is a pointer to an arbitrary piece of data and
8696 is set during the call to gtk_item_factory_create_items().</para>
8697
8698 <para>
8699 <literal>callback_action</literal> is the same value as
8700 <literal>callback_action</literal> in the ItemFactory entry.</para>
8701
8702 <para>
8703 <literal>*widget</literal> is a pointer to a menu item widget
8704 (described in <link linkend="sec-ManualMenuCreation">Manual Menu Creation</link>).
8705 </para>
8706 </sect3>
8707
8708 <!-- ----------------------------------------------------------------- -->
8709 <sect3 id="sec-ItemFactoryEntryExamples">
8710 <title>ItemFactory entry examples</title>
8711
8712 <para>Creating a simple menu item:</para>
8713
8714 <programlisting role="C">
8715 GtkItemFactoryEntry entry = {"/_File/_Open...", "&lt;CTRL&gt;O", print_hello,
8716                                 0, "&lt;Item&gt;"};
8717 </programlisting>
8718
8719 <para>This will define a new simple menu entry "/File/Open" (displayed as "Open"),
8720 under the menu entry "/File". It has the accelerator (shortcut) control+'O'
8721 that when clicked calls the function print_hello(). print_hello() is of
8722 the form <literal>void print_hello(void)</literal> since the callback_action
8723 field is zero. When displayed the 'O' in "Open" will be underlined and if the
8724 menu item is visible on the screen pressing 'O' will activate the item. Note
8725 that "File/_Open" could also have been used as the path instead of
8726 "/_File/_Open".</para>
8727
8728 <para>Creating an entry with a more complex callback:</para>
8729
8730 <programlisting role="C">
8731 GtkItemFactoryEntry entry = {"/_View/Display _FPS", NULL, print_state,
8732                                 7,"&lt;CheckItem&gt;"};
8733 </programlisting>
8734
8735 <para>This defines a new menu item displayed as "Display FPS" which is under
8736 the menu item "View". When clicked the function print_state() will be called.
8737 Since <literal>callback_action</literal> is not zero print_state() is of the
8738 form:</para>
8739
8740 <programlisting role="C">
8741 void print_state( gpointer    callback_data,
8742                   guint       callback_action,
8743                   GtkWidget  *widget )
8744 </programlisting>
8745
8746 <para>with <literal>callback_action</literal> equal to 7.</para>
8747
8748 <para>Creating a radio button set:</para>
8749
8750 <programlisting role="C">
8751 GtkItemFactoryEntry entry1 = {"/_View/_Low Resolution", NULL, change_resolution,
8752                                 1, "&lt;RadioButton&gt;"};
8753 GtkItemFactoryEntry entry2 = {"/_View/_High Resolution", NULL, change_resolution,
8754                                 2, "/View/Low Resolution"};
8755 </programlisting>
8756
8757 <para><literal>entry1</literal> defines a lone radio button that when toggled
8758 calls the function change_resolution() with the parameter
8759 <literal>callback_action</literal> equal to 1. change_resolution() is of
8760 the form:</para>
8761
8762 <programlisting role="C">
8763 void change_resolution(gpointer    callback_data,
8764                        guint       callback_action,
8765                        GtkWidget  *widget)
8766 </programlisting>
8767
8768 <para><literal>entry2</literal> defines a radio button that belongs to the
8769 radio group that entry1 belongs to. It calls the same function when toggled
8770 but with the parameter <literal>callback_action</literal> equal to 2. Note that
8771 the item_type of <literal>entry2</literal> is the path of entry1
8772 <emphasis>without</emphasis> the accelerators ('_'). If another radio button was
8773 required in the same group then it would be defined in the same way as
8774 <literal>entry2</literal> was with its <literal>item_type</literal> again
8775 equal to "/View/Low Resolution".</para>
8776 </sect3>
8777
8778 <!-- ----------------------------------------------------------------- -->
8779 <sect3 id="sec-ItemFactoryEntryArrays">
8780 <title>ItemFactoryEntry Arrays</title>
8781
8782 <para>An ItemFactoryEntry on it's own however isn't useful. An array of
8783 entries is what's required to define a menu. Below is an example of how
8784 you'd declare this array.</para>
8785
8786 <programlisting role="C">
8787 static GtkItemFactoryEntry entries[] = {
8788   { "/_File",         NULL,      NULL,         0, "&lt;Branch&gt;" },
8789   { "/File/tear1",    NULL,      NULL,         0, "&lt;Tearoff&gt;" },
8790   { "/File/_New",     "&lt;CTRL&gt;N", new_file,     1, "&lt;Item&gt;" },
8791   { "/File/_Open...", "&lt;CTRL&gt;O", open_file,    1, "&lt;Item&gt;" },
8792   { "/File/sep1",     NULL,      NULL,         0, "&lt;Separator&gt;" },
8793   { "/File/_Quit",    "&lt;CTRL&gt;Q", quit_program, 0, "&lt;StockItem&gt;", GTK_STOCK_QUIT } };
8794 </programlisting>
8795 </sect3>
8796 </sect2>
8797
8798 <!-- ----------------------------------------------------------------- -->
8799 <sect2 id="sec-ItemFactoryCreation">
8800 <title>Creating an ItemFactory</title>
8801
8802 <para>An array of GtkItemFactoryEntry items defines a menu. Once this
8803 array is defined then the item factory can be created. The function that
8804 does this is:</para>
8805
8806 <programlisting role="C">
8807 GtkItemFactory* gtk_item_factory_new( GtkType        container_type,
8808                                       const gchar   *path,
8809                                       GtkAccelGroup *accel_group );
8810 </programlisting>
8811
8812 <para><literal>container_type</literal> can be one of:</para>
8813
8814 <programlisting role="C">
8815 GTK_TYPE_MENU
8816 GTK_TYPE_MENU_BAR
8817 GTK_TYPE_OPTION_MENU
8818 </programlisting>
8819
8820 <para><literal>container_type</literal> defines what type of menu
8821 you want, so when you extract it later it is either a menu (for pop-ups
8822 for instance), a menu bar, or an option menu (like a combo box but with
8823 a menu of pull downs).</para>
8824
8825 <para><literal>path</literal> defines the path of the root of the menu.
8826 Basically it is a unique name for the root of the menu, it must be
8827 surrounded by "&lt;&gt;". This is important for the naming of the
8828 accelerators and should be unique. It should be unique both for each
8829 menu and between each program. For example in a program named 'foo', the
8830 main menu should be called "&lt;FooMain&gt;", and a pop-up menu
8831 "&lt;FooImagePopUp&gt;", or similar. What's important is that they're unique.</para>
8832
8833 <para><literal>accel_group</literal> is a pointer to a gtk_accel_group. The
8834 item factory sets up the accelerator table while generating menus. New
8835 accelerator groups are generated by gtk_accel_group_new().</para>
8836
8837 <para>But this is just the first step. To convert the array of GtkItemFactoryEntry
8838 information into widgets the following function is used:</para>
8839
8840 <programlisting role="C">
8841 void gtk_item_factory_create_items( GtkItemFactory      *ifactory,
8842                                     guint                n_entries,
8843                                     GtkItemFactoryEntry *entries,
8844                                     gpointer             callback_data );
8845 </programlisting>
8846
8847 <para><literal>*ifactory</literal> a pointer to the above created item factory.</para>
8848 <para><literal>n_entries</literal> is the number of entries in the
8849 GtkItemFactoryEntry array.</para>
8850 <para><literal>*entries</literal> is a pointer to the GtkItemFactoryEntry array.</para>
8851 <para><literal>callback_data</literal> is what gets passed to all the callback functions
8852 for all the entries with callback_action != 0.</para>
8853
8854 <para>The accelerator group has now been formed, so you'll probably want
8855 to attach it to the window the menu is in:</para>
8856
8857 <programlisting role="C">
8858 void gtk_window_add_accel_group( GtkWindow     *window,
8859                                  GtkAccelGroup *accel_group);
8860 </programlisting>
8861 </sect2>
8862
8863 <!-- ----------------------------------------------------------------- -->
8864 <sect2 id="sec-UsingMenuandItems">
8865 <title>Making use of the menu and its menu items</title>
8866
8867 <para>The last thing to do is make use of the menu. The following function
8868 extracts the relevant widgets from the ItemFactory:</para>
8869
8870 <programlisting role="C">
8871 GtkWidget* gtk_item_factory_get_widget( GtkItemFactory *ifactory,
8872                                         const gchar    *path );
8873 </programlisting>
8874
8875 <para>For instance if an ItemFactory has two entries "/File" and "/File/New",
8876 using a path of "/File" would retrieve a <emphasis>menu</emphasis> widget from the
8877 ItemFactory. Using a path of "/File/New" would retrieve a
8878 <emphasis>menu item</emphasis> widget. This makes it possible to set the initial state
8879 of menu items. For example to set the default radio
8880 item to the one with the path "/Shape/Oval" then the following code would
8881 be used:</para>
8882
8883 <programlisting role="C">
8884 gtk_check_menu_item_set_active(
8885         GTK_CHECK_MENU_ITEM (gtk_item_factory_get_item (item_factory, "/Shape/Oval")),
8886         TRUE);
8887 </programlisting>
8888
8889 <para>Finally to retrieve the root of the menu use gtk_item_factory_get_item()
8890 with a path of "&lt;main&gt;" (or whatever path was used in
8891 gtk_item_factory_new()). In the case of the ItemFactory being created with
8892 type GTK_TYPE_MENU_BAR this returns a menu bar widget. With type GTK_TYPE_MENU
8893 a menu widget is returned. With type GTK_TYPE_OPTION_MENU an option menu
8894 widget is returned.</para>
8895
8896 <para><emphasis>Remember</emphasis> for an entry defined with path "/_File"
8897 the path here is actually "/File".</para>
8898
8899 <para>Now you have a menubar or menu which can be manipulated in the same
8900 way as shown in the
8901 <link linkend="sec-ManualMenuCreation">Manual Menu Creation</link>
8902 section.</para>
8903 </sect2>
8904 </sect1>
8905
8906 <!-- ----------------------------------------------------------------- -->
8907 <sect1 id="sec-ItemFactoryExample">
8908 <title>Item Factory Example</title>
8909
8910 <para>Here is an example using the GTK item factory.</para>
8911
8912 <programlisting role="C">
8913 <!-- example-start menu itemfactory.c -->
8914
8915 #include &lt;gtk/gtk.h&gt;
8916
8917 /* Obligatory basic callback */
8918 static void print_hello( GtkWidget *w,
8919                          gpointer   data )
8920 {
8921   g_message ("Hello, World!\n");
8922 }
8923
8924 /* For the check button */
8925 static void print_toggle( gpointer   callback_data,
8926                           guint      callback_action,
8927                           GtkWidget *menu_item )
8928 {
8929    g_message ("Check button state - %d\n",
8930               GTK_CHECK_MENU_ITEM (menu_item)-&gt;active);
8931 }
8932
8933 /* For the radio buttons */
8934 static void print_selected( gpointer   callback_data,
8935                             guint      callback_action,
8936                             GtkWidget *menu_item )
8937 {
8938    if(GTK_CHECK_MENU_ITEM(menu_item)-&gt;active)
8939      g_message ("Radio button %d selected\n", callback_action);
8940 }
8941
8942 /* Our menu, an array of GtkItemFactoryEntry structures that defines each menu item */
8943 static GtkItemFactoryEntry menu_items[] = {
8944   { "/_File",         NULL,         NULL,           0, "&lt;Branch&gt;" },
8945   { "/File/_New",     "&lt;control&gt;N", print_hello,    0, "&lt;StockItem&gt;", GTK_STOCK_NEW },
8946   { "/File/_Open",    "&lt;control&gt;O", print_hello,    0, "&lt;StockItem&gt;", GTK_STOCK_OPEN },
8947   { "/File/_Save",    "&lt;control&gt;S", print_hello,    0, "&lt;StockItem&gt;", GTK_STOCK_SAVE },
8948   { "/File/Save _As", NULL,         NULL,           0, "&lt;Item&gt;" },
8949   { "/File/sep1",     NULL,         NULL,           0, "&lt;Separator&gt;" },
8950   { "/File/_Quit",    "&lt;CTRL&gt;Q", gtk_main_quit, 0, "&lt;StockItem&gt;", GTK_STOCK_QUIT },
8951   { "/_Options",      NULL,         NULL,           0, "&lt;Branch&gt;" },
8952   { "/Options/tear",  NULL,         NULL,           0, "&lt;Tearoff&gt;" },
8953   { "/Options/Check", NULL,         print_toggle,   1, "&lt;CheckItem&gt;" },
8954   { "/Options/sep",   NULL,         NULL,           0, "&lt;Separator&gt;" },
8955   { "/Options/Rad1",  NULL,         print_selected, 1, "&lt;RadioItem&gt;" },
8956   { "/Options/Rad2",  NULL,         print_selected, 2, "/Options/Rad1" },
8957   { "/Options/Rad3",  NULL,         print_selected, 3, "/Options/Rad1" },
8958   { "/_Help",         NULL,         NULL,           0, "&lt;LastBranch&gt;" },
8959   { "/_Help/About",   NULL,         NULL,           0, "&lt;Item&gt;" },
8960 };
8961
8962 static gint nmenu_items = sizeof (menu_items) / sizeof (menu_items[0]);
8963
8964 /* Returns a menubar widget made from the above menu */
8965 static GtkWidget *get_menubar_menu( GtkWidget  *window )
8966 {
8967   GtkItemFactory *item_factory;
8968   GtkAccelGroup *accel_group;
8969
8970   /* Make an accelerator group (shortcut keys) */
8971   accel_group = gtk_accel_group_new ();
8972
8973   /* Make an ItemFactory (that makes a menubar) */
8974   item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "&lt;main&gt;",
8975                                        accel_group);
8976
8977   /* This function generates the menu items. Pass the item factory,
8978      the number of items in the array, the array itself, and any
8979      callback data for the the menu items. */
8980   gtk_item_factory_create_items (item_factory, nmenu_items, menu_items, NULL);
8981
8982   /* Attach the new accelerator group to the window. */
8983   gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
8984
8985   /* Finally, return the actual menu bar created by the item factory. */
8986   return gtk_item_factory_get_widget (item_factory, "&lt;main&gt;");
8987 }
8988
8989 /* Popup the menu when the popup button is pressed */
8990 static gboolean popup_cb( GtkWidget *widget,
8991                           GdkEvent *event,
8992                           GtkWidget *menu )
8993 {
8994    GdkEventButton *bevent = (GdkEventButton *)event;
8995   
8996    /* Only take button presses */
8997    if (event-&gt;type != GDK_BUTTON_PRESS)
8998      return FALSE;
8999   
9000    /* Show the menu */
9001    gtk_menu_popup (GTK_MENU(menu), NULL, NULL,
9002                    NULL, NULL, bevent-&gt;button, bevent-&gt;time);
9003   
9004    return TRUE;
9005 }
9006
9007 /* Same as with get_menubar_menu() but just return a button with a signal to
9008    call a popup menu */
9009 GtkWidget *get_popup_menu( void )
9010 {
9011    GtkItemFactory *item_factory;
9012    GtkWidget *button, *menu;
9013   
9014    /* Same as before but don't bother with the accelerators */
9015    item_factory = gtk_item_factory_new (GTK_TYPE_MENU, "&lt;main&gt;",
9016                                         NULL);
9017    gtk_item_factory_create_items (item_factory, nmenu_items, menu_items, NULL);
9018    menu = gtk_item_factory_get_widget (item_factory, "&lt;main&gt;");
9019   
9020    /* Make a button to activate the popup menu */
9021    button = gtk_button_new_with_label ("Popup");
9022    /* Make the menu popup when clicked */
9023    g_signal_connect (G_OBJECT(button),
9024                      "event",
9025                      G_CALLBACK(popup_cb),
9026                      (gpointer) menu);
9027
9028    return button;
9029 }
9030
9031 /* Same again but return an option menu */
9032 GtkWidget *get_option_menu( void )
9033 {
9034    GtkItemFactory *item_factory;
9035    GtkWidget *option_menu;
9036   
9037    /* Same again, not bothering with the accelerators */
9038    item_factory = gtk_item_factory_new (GTK_TYPE_OPTION_MENU, "&lt;main&gt;",
9039                                         NULL);
9040    gtk_item_factory_create_items (item_factory, nmenu_items, menu_items, NULL);
9041    option_menu = gtk_item_factory_get_widget (item_factory, "&lt;main&gt;");
9042
9043    return option_menu;
9044 }
9045
9046 /* You have to start somewhere */
9047 int main( int argc,
9048           char *argv[] )
9049 {
9050   GtkWidget *window;
9051   GtkWidget *main_vbox;
9052   GtkWidget *menubar, *option_menu, *popup_button;
9053  
9054   /* Initialize GTK */
9055   gtk_init (&amp;argc, &amp;argv);
9056  
9057   /* Make a window */
9058   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
9059   g_signal_connect (G_OBJECT (window), "destroy",
9060                     G_CALLBACK (gtk_main_quit),
9061                     NULL);
9062   gtk_window_set_title (GTK_WINDOW(window), "Item Factory");
9063   gtk_widget_set_size_request (GTK_WIDGET(window), 300, 200);
9064  
9065   /* Make a vbox to put the three menus in */
9066   main_vbox = gtk_vbox_new (FALSE, 1);
9067   gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 1);
9068   gtk_container_add (GTK_CONTAINER (window), main_vbox);
9069  
9070   /* Get the three types of menu */
9071   /* Note: all three menus are separately created, so they are not the
9072      same menu */
9073   menubar = get_menubar_menu (window);
9074   popup_button = get_popup_menu ();
9075   option_menu = get_option_menu ();
9076   
9077   /* Pack it all together */
9078   gtk_box_pack_start (GTK_BOX (main_vbox), menubar, FALSE, TRUE, 0);
9079   gtk_box_pack_end (GTK_BOX (main_vbox), popup_button, FALSE, TRUE, 0);
9080   gtk_box_pack_end (GTK_BOX (main_vbox), option_menu, FALSE, TRUE, 0);
9081
9082   /* Show the widgets */
9083   gtk_widget_show_all (window);
9084   
9085   /* Finished! */
9086   gtk_main ();
9087  
9088   return 0;
9089 }
9090 <!-- example-end -->
9091 </programlisting>
9092
9093 </sect1>
9094 </chapter>
9095
9096 <!-- ***************************************************************** -->
9097 <chapter id="ch-UndocWidgets">
9098 <title>Undocumented Widgets</title>
9099
9100 <para>These all require authors! :) Please consider contributing to our
9101 tutorial.</para>
9102
9103 <para>If you must use one of these widgets that are undocumented, I strongly
9104 suggest you take a look at their respective header files in the GTK
9105 distribution. GTK's function names are very descriptive. Once you
9106 have an understanding of how things work, it's not difficult to figure
9107 out how to use a widget simply by looking at its function
9108 declarations. This, along with a few examples from others' code, and
9109 it should be no problem.</para>
9110
9111 <para>When you do come to understand all the functions of a new undocumented
9112 widget, please consider writing a tutorial on it so others may benefit
9113 from your time.</para>
9114
9115 <!-- ----------------------------------------------------------------- -->
9116 <sect1 id="sec-AccelLabel">
9117 <title>Accel Label</title>
9118
9119 <para></para>
9120
9121 </sect1>
9122
9123 <!-- ----------------------------------------------------------------- -->
9124 <sect1 id="sec-OptionMenu">
9125 <title>Option Menu</title>
9126
9127 <para></para>
9128
9129 </sect1>
9130
9131 <!-- ----------------------------------------------------------------- -->
9132 <sect1 id="sec-MenuItems">
9133 <title>Menu Items</title>
9134
9135 <para></para>
9136
9137 <sect2 id="sec-CheckMenuItem">
9138 <title>Check Menu Item</title>
9139
9140 <para></para>
9141 </sect2>
9142
9143 <sect2 id="sec-RadioMenuItem">
9144 <title>Radio Menu Item</title>
9145
9146 <para></para>
9147 </sect2>
9148
9149 <sect2 id="sec-SeparatorMenuItem">
9150 <title>Separator Menu Item</title>
9151
9152 <para></para>
9153 </sect2>
9154
9155 <sect2 id="sec-TearoffMenuItem">
9156 <title>Tearoff Menu Item</title>
9157
9158 <para></para>
9159 </sect2>
9160 </sect1>
9161
9162 <!-- ----------------------------------------------------------------- -->
9163 <sect1 id="sec-Curves">
9164 <title>Curves</title>
9165
9166 <para></para>
9167
9168 </sect1>
9169
9170 <!-- ----------------------------------------------------------------- -->
9171 <sect1 id="sec-DrawingArea">
9172 <title>Drawing Area</title>
9173
9174 <para></para>
9175
9176 </sect1>
9177
9178 <!-- ----------------------------------------------------------------- -->
9179 <sect1 id="sec-FontSelectionDialog">
9180 <title>Font Selection Dialog</title>
9181
9182 <para></para>
9183
9184 </sect1>
9185
9186 <!-- ----------------------------------------------------------------- -->
9187 <sect1 id="sec-MessageDialog">
9188 <title>Message Dialog</title>
9189
9190 <para></para>
9191
9192 </sect1>
9193
9194 <!-- ----------------------------------------------------------------- -->
9195 <sect1 id="sec-GammaCurve">
9196 <title>Gamma Curve</title>
9197
9198 <para></para>
9199
9200 </sect1>
9201
9202 <!-- ----------------------------------------------------------------- -->
9203 <sect1 id="sec-Image">
9204 <title>Image</title>
9205
9206 <para></para>
9207
9208 </sect1>
9209
9210 <!-- ----------------------------------------------------------------- -->
9211 <sect1 id="sec-PlugsAndSockets">
9212 <title>Plugs and Sockets</title>
9213
9214 <para></para>
9215
9216 </sect1>
9217
9218 <!-- ----------------------------------------------------------------- -->
9219 <sect1 id="sec-TreeView">
9220 <title>Tree View</title>
9221
9222 <para></para>
9223
9224 </sect1>
9225
9226 <!-- ----------------------------------------------------------------- -->
9227 <sect1 id="sec-TextView">
9228 <title>Text View</title>
9229
9230 <para></para>
9231
9232 </sect1>
9233 </chapter>
9234
9235 <!-- ***************************************************************** -->
9236 <chapter id="ch-SettingWidgetAttributes">
9237 <title>Setting Widget Attributes</title>
9238
9239 <para>This describes the functions used to operate on widgets. These can be
9240 used to set style, padding, size, etc.</para>
9241
9242 <para>(Maybe I should make a whole section on accelerators.)</para>
9243
9244 <programlisting role="C">
9245 void gtk_widget_activate( GtkWidget *widget );
9246
9247 void gtk_widget_set_name( GtkWidget *widget,
9248                           gchar     *name );
9249
9250 gchar *gtk_widget_get_name( GtkWidget *widget );
9251
9252 void gtk_widget_set_sensitive( GtkWidget *widget,
9253                                gboolean   sensitive );
9254
9255 void gtk_widget_set_style( GtkWidget *widget,
9256                            GtkStyle  *style );
9257                                            
9258 GtkStyle *gtk_widget_get_style( GtkWidget *widget );
9259
9260 GtkStyle *gtk_widget_get_default_style( void );
9261
9262 void gtk_widget_set_size_request( GtkWidget *widget,
9263                                   gint       width,
9264                                   gint       height );
9265
9266 void gtk_widget_grab_focus( GtkWidget *widget );
9267
9268 void gtk_widget_show( GtkWidget *widget );
9269
9270 void gtk_widget_hide( GtkWidget *widget );
9271 </programlisting>
9272
9273 </chapter>
9274
9275 <!-- ***************************************************************** -->
9276 <chapter id="ch-Timeouts">
9277 <title>Timeouts, IO and Idle Functions</title>
9278
9279 <!-- ----------------------------------------------------------------- -->
9280 <sect1 id="sec-Timeouts">
9281 <title>Timeouts</title>
9282
9283 <para>You may be wondering how you make GTK do useful work when in gtk_main.
9284 Well, you have several options. Using the following function you can
9285 create a timeout function that will be called every "interval"
9286 milliseconds.</para>
9287
9288 <programlisting role="C">
9289 gint g_timeout_add (guint32     interval,
9290                     GtkFunction function,
9291                     gpointer    data);
9292 </programlisting>
9293
9294 <para>The first argument is the number of milliseconds between calls to your
9295 function. The second argument is the function you wish to have called,
9296 and the third, the data passed to this callback function. The return
9297 value is an integer "tag" which may be used to stop the timeout by
9298 calling:</para>
9299
9300 <programlisting role="C">
9301 void g_source_remove (gint tag);
9302 </programlisting>
9303
9304 <para>You may also stop the timeout function by returning zero or FALSE from
9305 your callback function. Obviously this means if you want your function
9306 to continue to be called, it should return a non-zero value,
9307 i.e., TRUE.</para>
9308
9309 <para>The declaration of your callback should look something like this:</para>
9310
9311 <programlisting role="C">
9312 gint timeout_callback (gpointer data);
9313 </programlisting>
9314
9315 </sect1>
9316
9317 <!-- ----------------------------------------------------------------- -->
9318 <sect1 id="sec-MonitoringIO">
9319 <title>Monitoring IO</title>
9320
9321 <para>A nifty feature of GDK (the library that underlies GTK), is the
9322 ability to have it check for data on a file descriptor for you (as
9323 returned by open(2) or socket(2)). This is especially useful for
9324 networking applications. The function:</para>
9325
9326 <programlisting role="C">
9327 gint gdk_input_add( gint              source,
9328                     GdkInputCondition condition,
9329                     GdkInputFunction  function,
9330                     gpointer          data );
9331 </programlisting>
9332
9333 <para>Where the first argument is the file descriptor you wish to have
9334 watched, and the second specifies what you want GDK to look for. This
9335 may be one of:</para>
9336
9337 <itemizedlist>
9338 <listitem><simpara><literal>GDK_INPUT_READ</literal> - Call your function when there is data
9339 ready for reading on your file descriptor.</simpara>
9340 </listitem>
9341
9342 <listitem><simpara><literal>GDK_INPUT_WRITE</literal> - Call your function when the file
9343 descriptor is ready for writing.</simpara>
9344 </listitem>
9345 </itemizedlist>
9346
9347 <para>As I'm sure you've figured out already, the third argument is the
9348 function you wish to have called when the above conditions are
9349 satisfied, and the fourth is the data to pass to this function.</para>
9350
9351 <para>The return value is a tag that may be used to stop GDK from monitoring
9352 this file descriptor using the following function.</para>
9353
9354 <programlisting role="C">
9355 void gdk_input_remove( gint tag );
9356 </programlisting>
9357
9358 <para>The callback function should be declared as:</para>
9359
9360 <programlisting role="C">
9361 void input_callback( gpointer          data,
9362                      gint              source, 
9363                      GdkInputCondition condition );
9364 </programlisting>
9365
9366 <para>Where <literal>source</literal> and <literal>condition</literal> are as specified above.</para>
9367
9368 </sect1>
9369
9370 <!-- ----------------------------------------------------------------- -->
9371 <sect1 id="sec-IdleFunctions">
9372 <title>Idle Functions</title>
9373
9374 <para><!-- TODO: Need to check on idle priorities - TRG -->
9375 What if you have a function which you want to be called when nothing
9376 else is happening ?</para>
9377
9378 <programlisting role="C">
9379 gint gtk_idle_add( GtkFunction function,
9380                    gpointer    data );
9381 </programlisting>
9382
9383 <para>This causes GTK to call the specified function whenever nothing else
9384 is happening.</para>
9385
9386 <programlisting role="C">
9387 void gtk_idle_remove( gint tag );
9388 </programlisting>
9389
9390 <para>I won't explain the meaning of the arguments as they follow very much
9391 like the ones above. The function pointed to by the first argument to
9392 gtk_idle_add will be called whenever the opportunity arises. As with
9393 the others, returning FALSE will stop the idle function from being
9394 called.</para>
9395
9396 </sect1>
9397 </chapter>
9398
9399 <!-- ***************************************************************** -->
9400 <chapter id="ch-AdvancedEventsAndSignals">
9401 <title>Advanced Event and Signal Handling</title>
9402
9403 <!-- ----------------------------------------------------------------- -->
9404 <sect1 id="sec-SignalFunctions">
9405 <title>Signal Functions</title>
9406
9407 <!-- ----------------------------------------------------------------- -->
9408 <sect2>
9409 <title>Connecting and Disconnecting Signal Handlers</title>
9410
9411 <programlisting role="C">
9412 gulong g_signal_connect( GObject     *object,
9413                          const gchar *name,
9414                          GCallback    func,
9415                          gpointer     func_data );
9416
9417 gulong g_signal_connect_after( GObject       *object,
9418                                const gchar   *name,
9419                                GCallback      func,
9420                                gpointer       func_data );
9421
9422 gulong g_signal_connect_swapped( GObject       *object,
9423                                  const gchar   *name,
9424                                  GCallback      func,
9425                                  GObject       *slot_object );
9426
9427 void g_signal_handler_disconnect( GObject *object,
9428                                   gulong   handler_id );
9429
9430 void g_signal_handlers_disconnect_by_func( GObject   *object,
9431                                            GCallback  func,
9432                                            gpointer   data );
9433 </programlisting>
9434
9435 </sect2>
9436
9437 <!-- ----------------------------------------------------------------- -->
9438 <sect2>
9439 <title>Blocking and Unblocking Signal Handlers</title>
9440
9441 <programlisting role="C">
9442 void g_signal_handler_block( GObject *object,
9443                              gulong   handler_id);
9444
9445 void g_signal_handlers_block_by_func( GObject   *object,
9446                                       GCallback  func,
9447                                       gpointer   data );
9448
9449 void g_signal_handler_unblock( GObject *object,
9450                                gulong   handler_id );
9451
9452 void g_signal_handler_unblock_by_func( GObject   *object,
9453                                        GCallback  func,
9454                                        gpointer   data );
9455 </programlisting>
9456
9457 </sect2>
9458
9459 <!-- ----------------------------------------------------------------- -->
9460 <sect2>
9461 <title>Emitting and Stopping Signals</title>
9462
9463 <programlisting role="C">
9464 void g_signal_emit( GObject *object,
9465                     guint      signal_id,
9466                     ... );
9467
9468 void g_signal_emit_by_name( GObject     *object,
9469                             const gchar *name,
9470                             ... );
9471
9472 void g_signal_emitv( const GValue *instance_and_params,
9473                      guint         signal_id,
9474                      GQuark        detail,
9475                      GValue       *return_value );
9476
9477 void g_signal_stop_emission( GObject *object,
9478                              guint    signal_id,
9479                              GQuark   detail );
9480
9481 void g_signal_stop_emission_by_name( GObject   *object,
9482                                      const gchar *detailed_signal );
9483 </programlisting>
9484
9485 </sect2>
9486 </sect1>
9487
9488 <!-- ----------------------------------------------------------------- -->
9489 <sect1 id="sec-SignalEmissionAndPropagation">
9490 <title>Signal Emission and Propagation</title>
9491
9492 <para>Signal emission is the process whereby GTK runs all handlers for a
9493 specific object and signal.</para>
9494
9495 <para>First, note that the return value from a signal emission is the return
9496 value of the <emphasis>last</emphasis> handler executed. Since event signals are
9497 all of type <literal>GTK_RUN_LAST</literal>, this will be the default (GTK supplied)
9498 handler, unless you connect with gtk_signal_connect_after().</para>
9499
9500 <para>The way an event (say "button_press_event") is handled, is:</para>
9501
9502 <itemizedlist>
9503 <listitem><simpara>Start with the widget where the event occured.</simpara>
9504 </listitem>
9505
9506 <listitem><simpara>Emit the generic "event" signal. If that signal handler returns
9507 a value of TRUE, stop all processing.</simpara>
9508 </listitem>
9509
9510 <listitem><simpara>Otherwise, emit a specific, "button_press_event" signal. If that
9511 returns TRUE, stop all processing.</simpara>
9512 </listitem>
9513
9514 <listitem><simpara>Otherwise, go to the widget's parent, and repeat the above two
9515 steps.</simpara>
9516 </listitem>
9517
9518 <listitem><simpara>Continue until some signal handler returns TRUE, or until the
9519 top-level widget is reached.</simpara>
9520 </listitem>
9521 </itemizedlist>
9522
9523 <para>Some consequences of the above are:</para>
9524
9525 <itemizedlist>
9526 <listitem><simpara>Your handler's return value will have no effect if there is a
9527 default handler, unless you connect with gtk_signal_connect_after().</simpara>
9528 </listitem>
9529
9530 <listitem><simpara>To prevent the default handler from being run, you need to
9531 connect with gtk_signal_connect() and use
9532 gtk_signal_emit_stop_by_name() - the return value only affects whether
9533 the signal is propagated, not the current emission.</simpara>
9534 </listitem>
9535 </itemizedlist>
9536
9537 </sect1>
9538 </chapter>
9539
9540 <!-- continue GTK+ 2.0 review here -->
9541
9542 <!-- ***************************************************************** -->
9543 <chapter id="ch-ManagingSelections">
9544 <title>Managing Selections</title>
9545
9546 <!-- ----------------------------------------------------------------- -->
9547 <sect1 id="sec-SelectionsOverview">
9548 <title>Overview</title>
9549
9550 <para>One type of interprocess communication supported by X and GTK is
9551 <emphasis>selections</emphasis>. A selection identifies a chunk of data, for
9552 instance, a portion of text, selected by the user in some fashion, for
9553 instance, by dragging with the mouse. Only one application on a
9554 display (the <emphasis>owner</emphasis>) can own a particular selection at one
9555 time, so when a selection is claimed by one application, the previous
9556 owner must indicate to the user that selection has been
9557 relinquished. Other applications can request the contents of a
9558 selection in different forms, called <emphasis>targets</emphasis>. There can be
9559 any number of selections, but most X applications only handle one, the
9560 <emphasis>primary selection</emphasis>.</para>
9561
9562 <para>In most cases, it isn't necessary for a GTK application to deal with
9563 selections itself. The standard widgets, such as the Entry widget,
9564 already have the capability to claim the selection when appropriate
9565 (e.g., when the user drags over text), and to retrieve the contents of
9566 the selection owned by another widget or another application (e.g.,
9567 when the user clicks the second mouse button). However, there may be
9568 cases in which you want to give other widgets the ability to supply
9569 the selection, or you wish to retrieve targets not supported by
9570 default.</para>
9571
9572 <para>A fundamental concept needed to understand selection handling is that
9573 of the <emphasis>atom</emphasis>. An atom is an integer that uniquely identifies a
9574 string (on a certain display). Certain atoms are predefined by the X
9575 server, and in some cases there are constants in <literal>gtk.h</literal>
9576 corresponding to these atoms. For instance the constant
9577 <literal>GDK_PRIMARY_SELECTION</literal> corresponds to the string "PRIMARY".
9578 In other cases, you should use the functions
9579 <literal>gdk_atom_intern()</literal>, to get the atom corresponding to a string,
9580 and <literal>gdk_atom_name()</literal>, to get the name of an atom. Both
9581 selections and targets are identified by atoms.</para>
9582
9583 </sect1>
9584 <!-- ----------------------------------------------------------------- -->
9585 <sect1 id="sec-RetrievingTheSelection">
9586 <title>Retrieving the selection</title>
9587
9588 <para>Retrieving the selection is an asynchronous process. To start the
9589 process, you call:</para>
9590
9591 <programlisting role="C">
9592 gboolean gtk_selection_convert( GtkWidget *widget, 
9593                                 GdkAtom    selection, 
9594                                 GdkAtom    target,
9595                                 guint32    time );
9596 </programlisting>
9597
9598 <para>This <emphasis>converts</emphasis> the selection into the form specified by
9599 <literal>target</literal>. If at all possible, the time field should be the time
9600 from the event that triggered the selection. This helps make sure that
9601 events occur in the order that the user requested them. However, if it
9602 is not available (for instance, if the conversion was triggered by a
9603 "clicked" signal), then you can use the constant
9604 <literal>GDK_CURRENT_TIME</literal>.</para>
9605
9606 <para>When the selection owner responds to the request, a
9607 "selection_received" signal is sent to your application. The handler
9608 for this signal receives a pointer to a <literal>GtkSelectionData</literal>
9609 structure, which is defined as:</para>
9610
9611 <programlisting role="C">
9612 struct _GtkSelectionData
9613 {
9614   GdkAtom selection;
9615   GdkAtom target;
9616   GdkAtom type;
9617   gint    format;
9618   guchar *data;
9619   gint    length;
9620 };
9621 </programlisting>
9622
9623 <para><literal>selection</literal> and <literal>target</literal> are the values you gave in your
9624 <literal>gtk_selection_convert()</literal> call. <literal>type</literal> is an atom that
9625 identifies the type of data returned by the selection owner. Some
9626 possible values are "STRING", a string of latin-1 characters, "ATOM",
9627 a series of atoms, "INTEGER", an integer, etc. Most targets can only
9628 return one type. <literal>format</literal> gives the length of the units (for
9629 instance characters) in bits. Usually, you don't care about this when
9630 receiving data. <literal>data</literal> is a pointer to the returned data, and
9631 <literal>length</literal> gives the length of the returned data, in bytes. If
9632 <literal>length</literal> is negative, then an error occurred and the selection
9633 could not be retrieved. This might happen if no application owned the
9634 selection, or if you requested a target that the application didn't
9635 support. The buffer is actually guaranteed to be one byte longer than
9636 <literal>length</literal>; the extra byte will always be zero, so it isn't
9637 necessary to make a copy of strings just to nul-terminate them.</para>
9638
9639 <para>In the following example, we retrieve the special target "TARGETS",
9640 which is a list of all targets into which the selection can be
9641 converted.</para>
9642
9643 <programlisting role="C">
9644 <!-- example-start selection gettargets.c -->
9645
9646 #include &lt;stdlib.h&gt;
9647 #include &lt;gtk/gtk.h&gt;
9648
9649 static void selection_received( GtkWidget        *widget, 
9650                                 GtkSelectionData *selection_data, 
9651                                 gpointer          data );
9652
9653 /* Signal handler invoked when user clicks on the "Get Targets" button */
9654 static void get_targets( GtkWidget *widget,
9655                          gpointer data )
9656 {
9657   static GdkAtom targets_atom = GDK_NONE;
9658   GtkWidget *window = (GtkWidget *)data;        
9659
9660   /* Get the atom corresponding to the string "TARGETS" */
9661   if (targets_atom == GDK_NONE)
9662     targets_atom = gdk_atom_intern ("TARGETS", FALSE);
9663
9664   /* And request the "TARGETS" target for the primary selection */
9665   gtk_selection_convert (window, GDK_SELECTION_PRIMARY, targets_atom,
9666                          GDK_CURRENT_TIME);
9667 }
9668
9669 /* Signal handler called when the selections owner returns the data */
9670 static void selection_received( GtkWidget        *widget,
9671                                 GtkSelectionData *selection_data, 
9672                                 gpointer          data )
9673 {
9674   GdkAtom *atoms;
9675   GList *item_list;
9676   int i;
9677
9678   /* **** IMPORTANT **** Check to see if retrieval succeeded  */
9679   if (selection_data-&gt;length &lt; 0)
9680     {
9681       g_print ("Selection retrieval failed\n");
9682       return;
9683     }
9684   /* Make sure we got the data in the expected form */
9685   if (selection_data-&gt;type != GDK_SELECTION_TYPE_ATOM)
9686     {
9687       g_print ("Selection \"TARGETS\" was not returned as atoms!\n");
9688       return;
9689     }
9690   
9691   /* Print out the atoms we received */
9692   atoms = (GdkAtom *)selection_data-&gt;data;
9693
9694   item_list = NULL;
9695   for (i = 0; i &lt; selection_data-&gt;length / sizeof(GdkAtom); i++)
9696     {
9697       char *name;
9698       name = gdk_atom_name (atoms[i]);
9699       if (name != NULL)
9700         g_print ("%s\n",name);
9701       else
9702         g_print ("(bad atom)\n");
9703     }
9704
9705   return;
9706 }
9707
9708 int main( int   argc,
9709           char *argv[] )
9710 {
9711   GtkWidget *window;
9712   GtkWidget *button;
9713   
9714   gtk_init (&amp;argc, &amp;argv);
9715
9716   /* Create the toplevel window */
9717
9718   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
9719   gtk_window_set_title (GTK_WINDOW (window), "Event Box");
9720   gtk_container_set_border_width (GTK_CONTAINER (window), 10);
9721
9722   g_signal_connect (G_OBJECT (window), "destroy",
9723                     G_CALLBACK (exit), NULL);
9724
9725   /* Create a button the user can click to get targets */
9726
9727   button = gtk_button_new_with_label ("Get Targets");
9728   gtk_container_add (GTK_CONTAINER (window), button);
9729
9730   g_signal_connect (G_OBJECT (button), "clicked",
9731                     G_CALLBACK (get_targets), (gpointer) window);
9732   g_signal_connect (G_OBJECT (window), "selection_received",
9733                     G_CALLBACK (selection_received), NULL);
9734
9735   gtk_widget_show (button);
9736   gtk_widget_show (window);
9737   
9738   gtk_main ();
9739   
9740   return 0;
9741 }
9742 <!-- example-end -->
9743 </programlisting>
9744
9745 </sect1>
9746 <!-- ----------------------------------------------------------------- -->
9747 <sect1 id="sec-SupplyingTheSelection">
9748 <title>Supplying the selection</title>
9749
9750 <para>Supplying the selection is a bit more complicated. You must register 
9751 handlers that will be called when your selection is requested. For
9752 each selection/target pair you will handle, you make a call to:</para>
9753
9754 <programlisting role="C">
9755 void gtk_selection_add_target( GtkWidget           *widget, 
9756                                GdkAtom              selection,
9757                                GdkAtom              target,
9758                                guint                info );
9759 </programlisting>
9760
9761 <para><literal>widget</literal>, <literal>selection</literal>, and <literal>target</literal> identify the requests
9762 this handler will manage. When a request for a selection is received,
9763 the "selection_get" signal will be called. <literal>info</literal> can be used as an
9764 enumerator to identify the specific target within the callback function.</para>
9765
9766 <para>The callback function has the signature:</para>
9767
9768 <programlisting role="C">
9769 void  "selection_get"( GtkWidget          *widget,
9770                        GtkSelectionData   *selection_data,
9771                        guint               info,
9772                        guint               time );
9773 </programlisting>
9774
9775 <para>The GtkSelectionData is the same as above, but this time, we're
9776 responsible for filling in the fields <literal>type</literal>, <literal>format</literal>,
9777 <literal>data</literal>, and <literal>length</literal>. (The <literal>format</literal> field is actually
9778 important here - the X server uses it to figure out whether the data
9779 needs to be byte-swapped or not. Usually it will be 8 - <emphasis>i.e.</emphasis> a
9780 character - or 32 - <emphasis>i.e.</emphasis> an integer.) This is done by calling the
9781 function:</para>
9782
9783 <programlisting role="C">
9784 void gtk_selection_data_set( GtkSelectionData *selection_data,
9785                              GdkAtom           type,
9786                              gint              format,
9787                              guchar           *data,
9788                              gint              length );
9789 </programlisting>
9790
9791 <para>This function takes care of properly making a copy of the data so that
9792 you don't have to worry about keeping it around. (You should not fill
9793 in the fields of the GtkSelectionData structure by hand.)</para>
9794
9795 <para>When prompted by the user, you claim ownership of the selection by
9796 calling:</para>
9797
9798 <programlisting role="C">
9799 gboolean gtk_selection_owner_set( GtkWidget *widget,
9800                                   GdkAtom    selection,
9801                                   guint32    time );
9802 </programlisting>
9803
9804 <para>If another application claims ownership of the selection, you will
9805 receive a "selection_clear_event".</para>
9806
9807 <para>As an example of supplying the selection, the following program adds
9808 selection functionality to a toggle button. When the toggle button is
9809 depressed, the program claims the primary selection. The only target
9810 supported (aside from certain targets like "TARGETS" supplied by GTK
9811 itself), is the "STRING" target. When this target is requested, a
9812 string representation of the time is returned.</para>
9813
9814 <programlisting role="C">
9815 <!-- example-start selection setselection.c -->
9816
9817 #include &lt;stdlib.h&gt;
9818 #include &lt;gtk/gtk.h&gt;
9819 #include &lt;time.h&gt;
9820 #include &lt;string.h&gt;
9821
9822 GtkWidget *selection_button;
9823 GtkWidget *selection_widget;
9824
9825 /* Callback when the user toggles the selection */
9826 static void selection_toggled( GtkWidget *widget,
9827                                gint      *have_selection )
9828 {
9829   if (GTK_TOGGLE_BUTTON (widget)-&gt;active)
9830     {
9831       *have_selection = gtk_selection_owner_set (selection_widget,
9832                                                  GDK_SELECTION_PRIMARY,
9833                                                  GDK_CURRENT_TIME);
9834       /* if claiming the selection failed, we return the button to
9835          the out state */
9836       if (!*have_selection)
9837         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), FALSE);
9838     }
9839   else
9840     {
9841       if (*have_selection)
9842         {
9843           /* Before clearing the selection by setting the owner to NULL,
9844              we check if we are the actual owner */
9845           if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget-&gt;window)
9846             gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY,
9847                                      GDK_CURRENT_TIME);
9848           *have_selection = FALSE;
9849         }
9850     }
9851 }
9852
9853 /* Called when another application claims the selection */
9854 static gboolean selection_clear( GtkWidget         *widget,
9855                                  GdkEventSelection *event,
9856                                  gint              *have_selection )
9857 {
9858   *have_selection = FALSE;
9859   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (selection_button), FALSE);
9860
9861   return TRUE;
9862 }
9863
9864 /* Supplies the current time as the selection. */
9865 static void selection_handle( GtkWidget        *widget, 
9866                               GtkSelectionData *selection_data,
9867                               guint             info,
9868                               guint             time_stamp,
9869                               gpointer          data )
9870 {
9871   gchar *timestr;
9872   time_t current_time;
9873
9874   current_time = time (NULL);
9875   timestr = asctime (localtime (&amp;current_time)); 
9876   /* When we return a single string, it should not be null terminated.
9877      That will be done for us */
9878
9879   gtk_selection_data_set (selection_data, GDK_SELECTION_TYPE_STRING,
9880                           8, timestr, strlen (timestr));
9881 }
9882
9883 int main( int   argc,
9884           char *argv[] )
9885 {
9886   GtkWidget *window;
9887
9888   static int have_selection = FALSE;
9889   
9890   gtk_init (&amp;argc, &amp;argv);
9891
9892   /* Create the toplevel window */
9893
9894   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
9895   gtk_window_set_title (GTK_WINDOW (window), "Event Box");
9896   gtk_container_set_border_width (GTK_CONTAINER (window), 10);
9897
9898   g_signal_connect (G_OBJECT (window), "destroy",
9899                     G_CALLBACK (exit), NULL);
9900
9901   /* Create a toggle button to act as the selection */
9902
9903   selection_widget = gtk_invisible_new ();
9904   selection_button = gtk_toggle_button_new_with_label ("Claim Selection");
9905   gtk_container_add (GTK_CONTAINER (window), selection_button);
9906   gtk_widget_show (selection_button);
9907
9908   g_signal_connect (G_OBJECT (selection_button), "toggled",
9909                     G_CALLBACK (selection_toggled), (gpointer) &amp;have_selection);
9910   g_signal_connect (G_OBJECT (selection_widget), "selection_clear_event",
9911                     G_CALLBACK (selection_clear), (gpointer) &amp;have_selection);
9912
9913   gtk_selection_add_target (selection_widget,
9914                             GDK_SELECTION_PRIMARY,
9915                             GDK_SELECTION_TYPE_STRING,
9916                             1);
9917   g_signal_connect (G_OBJECT (selection_widget), "selection_get",
9918                     G_CALLBACK (selection_handle), (gpointer) &amp;have_selection);
9919
9920   gtk_widget_show (selection_button);
9921   gtk_widget_show (window);
9922   
9923   gtk_main ();
9924   
9925   return 0;
9926 }
9927 <!-- example-end -->
9928 </programlisting>
9929
9930 </sect1>
9931 </chapter>
9932
9933 <!-- ***************************************************************** -->
9934 <chapter id="ch-DragAngDrop">
9935 <title>Drag-and-drop (DND)</title>
9936
9937 <para>GTK+ has a high level set of functions for doing inter-process
9938 communication via the drag-and-drop system. GTK+ can perform
9939 drag-and-drop on top of the low level Xdnd and Motif drag-and-drop
9940 protocols.</para>
9941
9942 <!-- ----------------------------------------------------------------- -->
9943 <sect1 id="sec-DragAndDropOverview">
9944 <title>Overview</title>
9945
9946 <para>An application capable of GTK+ drag-and-drop first defines and sets up
9947 the GTK+ widget(s) for drag-and-drop. Each widget can be a source
9948 and/or destination for drag-and-drop. Note that these GTK+ widgets must have
9949 an associated X Window, check using GTK_WIDGET_NO_WINDOW(widget)).</para>
9950
9951 <para>Source widgets can send out drag data, thus allowing the user to drag
9952 things off of them, while destination widgets can receive drag data.
9953 Drag-and-drop destinations can limit who they accept drag data from,
9954 e.g. the same application or any application (including itself).</para>
9955
9956 <para>Sending and receiving drop data makes use of GTK+ signals.
9957 Dropping an item to a destination widget requires both a data
9958 request (for the source widget) and data received signal handler (for
9959 the target widget). Additional signal handers can be connected if you
9960 want to know when a drag begins (at the very instant it starts), to
9961 when a drop is made, and when the entire drag-and-drop procedure has
9962 ended (successfully or not).</para>
9963
9964 <para>Your application will need to provide data for source widgets when
9965 requested, that involves having a drag data request signal handler. For
9966 destination widgets they will need a drop data received signal
9967 handler. </para>
9968
9969 <para>So a typical drag-and-drop cycle would look as follows:</para>
9970 <orderedlist>
9971 <listitem><simpara> Drag begins.</simpara>
9972 </listitem>
9973 <listitem><simpara> Drag data request (when a drop occurs).</simpara>
9974 </listitem>
9975 <listitem><simpara> Drop data received (may be on same or different
9976 application).</simpara>
9977 </listitem>
9978 <listitem><simpara> Drag data delete (if the drag was a move).</simpara>
9979 </listitem>
9980 <listitem><simpara> Drag-and-drop procedure done.</simpara>
9981 </listitem>
9982 </orderedlist>
9983
9984 <para>There are a few minor steps that go in between here and there, but we
9985 will get into detail about that later.</para>
9986
9987 </sect1>
9988
9989 <!-- ----------------------------------------------------------------- -->
9990 <sect1 id="sec-DragAndDropProperties">
9991 <title>Properties</title>
9992
9993 <para>Drag data has the following properties:</para>
9994
9995 <itemizedlist>
9996 <listitem><simpara> Drag action type (ie GDK_ACTION_COPY, GDK_ACTION_MOVE).</simpara>
9997 </listitem>
9998
9999 <listitem><simpara> Client specified arbitrary drag-and-drop type (a name and number pair).</simpara>
10000 </listitem>
10001
10002 <listitem><simpara> Sent and received data format type.</simpara>
10003 </listitem>
10004 </itemizedlist>
10005
10006 <para>Drag actions are quite obvious, they specify if the widget can
10007 drag with the specified action(s), e.g. GDK_ACTION_COPY and/or
10008 GDK_ACTION_MOVE. A GDK_ACTION_COPY would be a typical drag-and-drop
10009 without the source data being deleted while GDK_ACTION_MOVE would be
10010 just like GDK_ACTION_COPY but the source data will be 'suggested' to be
10011 deleted after the received signal handler is called. There are
10012 additional drag actions including GDK_ACTION_LINK which you may want to
10013 look into when you get to more advanced levels of drag-and-drop.</para>
10014
10015 <para>The client specified arbitrary drag-and-drop type is much more
10016 flexible, because your application will be defining and checking for
10017 that specifically. You will need to set up your destination widgets to
10018 receive certain drag-and-drop types by specifying a name and/or number.
10019 It would be more reliable to use a name since another application may
10020 just happen to use the same number for an entirely different
10021 meaning.</para>
10022
10023 <para>Sent and received data format types (<emphasis>selection
10024 target</emphasis>) come into play only in your request and received
10025 data handler functions. The term <emphasis>selection target</emphasis>
10026 is somewhat misleading. It is a term adapted from GTK+ selection
10027 (cut/copy and paste). What <emphasis>selection target</emphasis>
10028 actually means is the data's format type (i.e. GdkAtom, integer, or
10029 string) that being sent or received. Your request data handler function
10030 needs to specify the type (<emphasis>selection target</emphasis>) of
10031 data that it sends out and your received data handler needs to handle
10032 the type (<emphasis>selection target</emphasis>) of data
10033 received.</para>
10034
10035 </sect1>
10036
10037 <!-- ----------------------------------------------------------------- -->
10038 <sect1 id="sec-DragAndDropFunctions">
10039 <title>Functions</title>
10040
10041 <!-- ----------------------------------------------------------------- -->
10042 <sect2 id="sec-DNDSourceWidgets">
10043 <title>Setting up the source widget</title>
10044
10045 <para>The function <literal>gtk_drag_source_set()</literal> specifies a
10046 set of target types for a drag operation on a widget.</para>
10047
10048 <programlisting role="C">
10049 void gtk_drag_source_set( GtkWidget            *widget,
10050                           GdkModifierType       start_button_mask,
10051                           const GtkTargetEntry *targets,
10052                           gint                  n_targets,
10053                           GdkDragAction         actions );
10054 </programlisting>
10055
10056 <para>The parameters signify the following:</para>
10057 <itemizedlist>
10058 <listitem><simpara><literal>widget</literal> specifies the drag source
10059 widget</simpara>
10060 </listitem>
10061 <listitem><simpara><literal>start_button_mask</literal> specifies a
10062 bitmask of buttons that can start the drag (e.g. GDK_BUTTON1_MASK)</simpara>
10063 </listitem>
10064 <listitem><simpara><literal>targets</literal> specifies a table of
10065 target data types the drag will support</simpara>
10066 </listitem>
10067 <listitem><simpara><literal>n_targets</literal> specifies the number of
10068 targets above</simpara>
10069 </listitem>
10070 <listitem><simpara><literal>actions</literal> specifies a bitmask of
10071 possible actions for a drag from this window</simpara>
10072 </listitem>
10073 </itemizedlist>
10074
10075 <para>The <literal>targets</literal> parameter is an array of the
10076 following structure:</para>
10077
10078 <programlisting role="C">
10079 struct GtkTargetEntry {
10080    gchar *target;
10081    guint  flags;
10082    guint  info;
10083  };
10084 </programlisting>
10085
10086 <para>The fields specify a string representing the drag type, optional
10087 flags and application assigned integer identifier.</para>
10088
10089 <para>If a widget is no longer required to act as a source for
10090 drag-and-drop operations, the function
10091 <literal>gtk_drag_source_unset()</literal> can be used to remove a set
10092 of drag-and-drop target types.</para>
10093
10094 <programlisting role="C">
10095 void gtk_drag_source_unset( GtkWidget *widget );
10096 </programlisting>
10097
10098 </sect2>
10099
10100 <!-- ----------------------------------------------------------------- -->
10101 <sect2 id="sec-SignalsOnSourceWidgets">
10102 <title>Signals on the source widget:</title>
10103
10104 <para>The source widget is sent the following signals during a
10105 drag-and-drop operation.</para>
10106
10107 <table pgwide="1">
10108 <title>Source widget signals</title>
10109 <tgroup cols="2">
10110 <colspec colname="Name" colwidth="150">
10111 <colspec colname="Prototype">
10112 <tbody>
10113 <row>
10114 <entry align="left" valign="middle">drag_begin</entry>
10115 <entry align="left" valign="middle"><literal>void (*drag_begin)(GtkWidget *widget,
10116 GdkDragContext *dc, gpointer data)</literal></entry>
10117 </row>
10118 <row>
10119 <entry align="left" valign="middle">drag_motion</entry>
10120 <entry align="left" valign="middle"><literal>gboolean (*drag_motion)(GtkWidget *widget,
10121 GdkDragContext *dc, gint x, gint y, guint t, gpointer data)</literal></entry>
10122 </row>
10123 <row>
10124 <entry align="left" valign="middle">drag_data_get</entry>
10125 <entry align="left" valign="middle"><literal>void (*drag_data_get)(GtkWidget *widget,
10126 GdkDragContext *dc, GtkSelectionData *selection_data, guint info, guint t, gpointer data)</literal></entry>
10127 </row>
10128 <row>
10129 <entry align="left" valign="middle">drag_data_delete</entry>
10130 <entry align="left" valign="middle"><literal>void (*drag_data_delete)(GtkWidget *widget,
10131 GdkDragContext *dc, gpointer data)</literal></entry>
10132 </row>
10133 <row>
10134 <entry align="left" valign="middle">drag_drop</entry>
10135 <entry align="left" valign="middle"><literal>gboolean (*drag_drop)(GtkWidget *widget,
10136 GdkDragContext *dc, gint x, gint y, guint t, gpointer data)</literal></entry>
10137 </row>
10138 <row>
10139 <entry align="left" valign="middle">drag_end</entry>
10140 <entry align="left" valign="middle"><literal>void (*drag_end)(GtkWidget *widget,
10141 GdkDragContext *dc, gpointer data)</literal></entry>
10142 </row>
10143 </tbody>
10144 </tgroup>
10145 </table>
10146
10147 </sect2>
10148
10149 <!-- ----------------------------------------------------------------- -->
10150 <sect2 id="sec-DNDDestWidgets">
10151 <title>Setting up a destination widget:</title>
10152
10153 <para> <literal> gtk_drag_dest_set()</literal> specifies
10154 that this widget can receive drops and specifies what types of drops it
10155 can receive.</para>
10156
10157 <para> <literal> gtk_drag_dest_unset()</literal> specifies
10158 that the widget can no longer receive drops.</para>
10159
10160 <programlisting role="C">
10161 void gtk_drag_dest_set( GtkWidget            *widget,
10162                         GtkDestDefaults       flags,
10163                         const GtkTargetEntry *targets,
10164                         gint                  n_targets,
10165                         GdkDragAction         actions );
10166
10167 void gtk_drag_dest_unset( GtkWidget *widget );
10168 </programlisting>
10169
10170 </sect2>
10171
10172 <!-- ----------------------------------------------------------------- -->
10173 <sect2 id="sec-SignalsOnDestWidgets">
10174 <title>Signals on the destination widget:</title>
10175
10176 <para>The destination widget is sent the following signals during a
10177 drag-and-drop operation.</para>
10178
10179 <table pgwide="1">
10180 <title>Destination widget signals</title>
10181 <tgroup cols="2">
10182 <colspec colname="Name" colwidth="150">
10183 <colspec colname="Prototype">
10184 <tbody>
10185 <row>
10186 <entry align="left" valign="middle">drag_data_received</entry>
10187 <entry align="left" valign="middle"><literal>void (*drag_data_received)(GtkWidget *widget,
10188 GdkDragContext *dc, gint x, gint y, GtkSelectionData *selection_data, guint info, guint t,
10189 gpointer data)</literal></entry>
10190 </row>
10191 </tbody>
10192 </tgroup>
10193 </table>
10194
10195 </sect2>
10196 </sect1>
10197 </chapter>
10198
10199 <!-- ***************************************************************** -->
10200 <chapter id="ch-GLib">
10201 <title>GLib</title>
10202
10203 <para>GLib is a lower-level library that provides many useful definitions
10204 and functions available for use when creating GDK and GTK
10205 applications. These include definitions for basic types and their
10206 limits, standard macros, type conversions, byte order, memory
10207 allocation, warnings and assertions, message logging, timers, string
10208 utilities, hook functions, a lexical scanner, dynamic loading of
10209 modules, and automatic string completion. A number of data structures
10210 (and their related operations) are also defined, including memory
10211 chunks, doubly-linked lists, singly-linked lists, hash tables, strings
10212 (which can grow dynamically), string chunks (groups of strings),
10213 arrays (which can grow in size as elements are added), balanced binary
10214 trees, N-ary trees, quarks (a two-way association of a string and a
10215 unique integer identifier), keyed data lists (lists of data elements
10216 accessible by a string or integer id), relations and tuples (tables of
10217 data which can be indexed on any number of fields), and caches.</para>
10218
10219 <para>A summary of some of GLib's capabilities follows; not every function,
10220 data structure, or operation is covered here.  For more complete
10221 information about the GLib routines, see the GLib documentation. One
10222 source of GLib documentation is <ulink url="http://www.gtk.org/">http://www.gtk.org/</ulink>.</para>
10223
10224 <para>If you are using a language other than C, you should consult your
10225 language's binding documentation. In some cases your language may
10226 have equivalent functionality built-in, while in other cases it may
10227 not.</para>
10228
10229 <!-- ----------------------------------------------------------------- -->
10230 <sect1 id="sec-Definitions">
10231 <title>Definitions</title>
10232
10233 <para>Definitions for the extremes of many of the standard types are:</para>
10234
10235 <programlisting role="C">
10236 G_MINFLOAT
10237 G_MAXFLOAT
10238 G_MINDOUBLE
10239 G_MAXDOUBLE
10240 G_MINSHORT
10241 G_MAXSHORT
10242 G_MAXUSHORT
10243 G_MININT
10244 G_MAXINT
10245 G_MAXUINT
10246 G_MINLONG
10247 G_MAXLONG
10248 G_MAXULONG
10249 G_MININT64
10250 G_MAXINT64
10251 G_MAXUINT64
10252 </programlisting>
10253
10254 <para>Also, the following typedefs. The ones left unspecified are dynamically set
10255 depending on the architecture. Remember to avoid counting on the size of a
10256 pointer if you want to be portable! E.g., a pointer on an Alpha is 8
10257 bytes, but 4 on Intel 80x86 family CPUs.</para>
10258
10259 <programlisting role="C">
10260 char   gchar;
10261 short  gshort;
10262 long   glong;
10263 int    gint;
10264 int    gboolean;
10265
10266 unsigned char   guchar;
10267 unsigned short  gushort;
10268 unsigned long   gulong;
10269 unsigned int    guint;
10270
10271 float   gfloat;
10272 double  gdouble;
10273
10274 unsigned int  gsize;
10275 signed int    gssize;
10276
10277 void*       gpointer;
10278 const void* gconstpointer;
10279
10280 gint8
10281 guint8
10282 gint16
10283 guint16
10284 gint32
10285 guint32
10286 gint64
10287 guint64
10288 </programlisting>
10289
10290 </sect1>
10291
10292 <!-- ----------------------------------------------------------------- -->
10293 <sect1 id="sec-DoublyLinkedLists">
10294 <title>Doubly Linked Lists</title>
10295
10296 <para>The following functions are used to create, manage, and destroy
10297 standard doubly linked lists. Each element in the list contains a
10298 piece of data, together with pointers which link to the previous and
10299 next elements in the list. This enables easy movement in either
10300 direction through the list. The data item is of type "gpointer",
10301 which means the data can be a pointer to your real data or (through
10302 casting) a numeric value (but do not assume that int and gpointer have
10303 the same size!). These routines internally allocate list elements in
10304 blocks, which is more efficient than allocating elements individually.</para>
10305
10306 <para>There is no function to specifically create a list. Instead, simply
10307 create a variable of type GList* and set its value to NULL; NULL is
10308 considered to be the empty list.</para>
10309
10310 <para>To add elements to a list, use the g_list_append(), g_list_prepend(),
10311 g_list_insert(), or g_list_insert_sorted() routines. In all cases
10312 they accept a pointer to the beginning of the list, and return the
10313 (possibly changed) pointer to the beginning of the list. Thus, for
10314 all of the operations that add or remove elements, be sure to save the
10315 returned value!</para>
10316
10317 <programlisting role="C">
10318 GList *g_list_append( GList    *list,
10319                       gpointer  data );
10320 </programlisting>
10321
10322 <para>This adds a new element (with value <literal>data</literal>) onto the end of the
10323 list.</para>
10324   
10325 <programlisting role="C">
10326 GList *g_list_prepend( GList    *list,
10327                        gpointer  data );
10328 </programlisting>
10329
10330 <para>This adds a new element (with value <literal>data</literal>) to the beginning of the
10331 list.</para>
10332
10333 <programlisting role="C">
10334 GList *g_list_insert( GList    *list,
10335                       gpointer  data,
10336                       gint      position );
10337 </programlisting>
10338
10339 <para>This inserts a new element (with value data) into the list at the
10340 given position. If position is 0, this is just like g_list_prepend();
10341 if position is less than 0, this is just like g_list_append().</para>
10342
10343 <programlisting role="C">
10344 GList *g_list_remove( GList    *list,
10345                       gpointer  data );
10346 </programlisting>
10347
10348 <para>This removes the element in the list with the value <literal>data</literal>;
10349 if the element isn't there, the list is unchanged.</para>
10350
10351 <programlisting role="C">
10352 void g_list_free( GList *list );
10353 </programlisting>
10354
10355 <para>This frees all of the memory used by a GList. If the list elements
10356 refer to dynamically-allocated memory, then they should be freed
10357 first.</para>
10358
10359 <para>There are many other GLib functions that support doubly linked lists;
10360 see the glib documentation for more information.  Here are a few of
10361 the more useful functions' signatures:</para>
10362
10363 <programlisting role="C">  
10364 GList *g_list_remove_link( GList *list,
10365                            GList *link );
10366
10367 GList *g_list_reverse( GList *list );
10368
10369 GList *g_list_nth( GList *list,
10370                    gint   n );
10371                            
10372 GList *g_list_find( GList    *list,
10373                     gpointer  data );
10374
10375 GList *g_list_last( GList *list );
10376
10377 GList *g_list_first( GList *list );
10378
10379 gint g_list_length( GList *list );
10380
10381 void g_list_foreach( GList    *list,
10382                      GFunc     func,
10383                      gpointer  user_data );
10384 </programlisting>
10385
10386 </sect1>
10387
10388 <!-- ----------------------------------------------------------------- -->
10389 <sect1 id="sec-SinglyLinkedLists">
10390 <title>Singly Linked Lists</title>
10391
10392 <para>Many of the above functions for singly linked lists are identical to the
10393 above. Here is a list of some of their operations:</para>
10394
10395 <programlisting role="C">
10396 GSList *g_slist_append( GSList   *list,
10397                         gpointer  data );
10398                 
10399 GSList *g_slist_prepend( GSList   *list,
10400                          gpointer  data );
10401                              
10402 GSList *g_slist_insert( GSList   *list,
10403                         gpointer  data,
10404                         gint      position );
10405                              
10406 GSList *g_slist_remove( GSList   *list,
10407                         gpointer  data );
10408                              
10409 GSList *g_slist_remove_link( GSList *list,
10410                              GSList *link );
10411                              
10412 GSList *g_slist_reverse( GSList *list );
10413
10414 GSList *g_slist_nth( GSList *list,
10415                      gint    n );
10416                              
10417 GSList *g_slist_find( GSList   *list,
10418                       gpointer  data );
10419                              
10420 GSList *g_slist_last( GSList *list );
10421
10422 gint g_slist_length( GSList *list );
10423
10424 void g_slist_foreach( GSList   *list,
10425                       GFunc     func,
10426                       gpointer  user_data );
10427         
10428 </programlisting>
10429
10430 </sect1>
10431
10432 <!-- ----------------------------------------------------------------- -->
10433 <sect1 id="sec-MemoryManagement">
10434 <title>Memory Management</title>
10435
10436 <programlisting role="C">
10437 gpointer g_malloc( gulong size );
10438 </programlisting>
10439
10440 <para>This is a replacement for malloc(). You do not need to check the return
10441 value as it is done for you in this function. If the memory allocation
10442 fails for whatever reasons, your applications will be terminated.</para>
10443
10444 <programlisting role="C">
10445 gpointer g_malloc0( gulong size );
10446 </programlisting>
10447
10448 <para>Same as above, but zeroes the memory before returning a pointer to it.</para>
10449
10450 <programlisting role="C">
10451 gpointer g_realloc( gpointer mem,
10452                     gulong   size );
10453 </programlisting>
10454
10455 <para>Relocates "size" bytes of memory starting at "mem".  Obviously, the
10456 memory should have been previously allocated.</para>
10457
10458 <programlisting role="C">
10459 void g_free( gpointer mem );
10460 </programlisting>
10461
10462 <para>Frees memory. Easy one. If <literal>mem</literal> is NULL it simply returns.</para>
10463
10464 <programlisting role="C">
10465 void g_mem_profile( void );
10466 </programlisting>
10467
10468 <para>Dumps a profile of used memory, but requires that you add <literal>#define
10469 MEM_PROFILE</literal> to the top of glib/gmem.c and re-make and make install.</para>
10470
10471 <programlisting role="C">
10472 void g_mem_check( gpointer mem );
10473 </programlisting>
10474
10475 <para>Checks that a memory location is valid. Requires you add <literal>#define
10476 MEM_CHECK</literal> to the top of gmem.c and re-make and make install.</para>
10477
10478 </sect1>
10479
10480 <!-- ----------------------------------------------------------------- -->
10481 <sect1 id="sec-Timers">
10482 <title>Timers</title>
10483
10484 <para>Timer functions can be used to time operations (e.g., to see how much
10485 time has elapsed). First, you create a new timer with g_timer_new().
10486 You can then use g_timer_start() to start timing an operation,
10487 g_timer_stop() to stop timing an operation, and g_timer_elapsed() to
10488 determine the elapsed time.</para>
10489
10490 <programlisting role="C">
10491 GTimer *g_timer_new( void );
10492
10493 void g_timer_destroy( GTimer *timer );
10494
10495 void g_timer_start( GTimer  *timer );
10496
10497 void g_timer_stop( GTimer  *timer );
10498
10499 void g_timer_reset( GTimer  *timer );
10500
10501 gdouble g_timer_elapsed( GTimer *timer,
10502                          gulong *microseconds );
10503 </programlisting>
10504
10505 </sect1>
10506
10507 <!-- ----------------------------------------------------------------- -->
10508 <sect1 id="sec-StringHandling">
10509 <title>String Handling</title>
10510
10511 <para>GLib defines a new type called a GString, which is similar to a
10512 standard C string but one that grows automatically. Its string data
10513 is null-terminated. What this gives you is protection from buffer
10514 overflow programming errors within your program. This is a very
10515 important feature, and hence I recommend that you make use of
10516 GStrings. GString itself has a simple public definition:</para>
10517
10518 <programlisting role="C">
10519 struct GString 
10520 {
10521   gchar *str; /* Points to the string's current \0-terminated value. */
10522   gint len; /* Current length */
10523 };
10524 </programlisting>
10525
10526 <para>As you might expect, there are a number of operations you can do with
10527 a GString.</para>
10528
10529 <programlisting role="C">
10530 GString *g_string_new( gchar *init );
10531 </programlisting>
10532
10533 <para>This constructs a GString, copying the string value of <literal>init</literal>
10534 into the GString and returning a pointer to it. NULL may be given as
10535 the argument for an initially empty GString.</para>
10536
10537 <programlisting role="C">
10538 void g_string_free( GString *string,
10539                     gint     free_segment );
10540 </programlisting>
10541
10542 <para>This frees the memory for the given GString. If <literal>free_segment</literal> is
10543 TRUE, then this also frees its character data.</para>
10544
10545 <programlisting role="C">            
10546 GString *g_string_assign( GString     *lval,
10547                           const gchar *rval );
10548 </programlisting>
10549
10550 <para>This copies the characters from rval into lval, destroying the
10551 previous contents of lval. Note that lval will be lengthened as
10552 necessary to hold the string's contents, unlike the standard strcpy()
10553 function.</para>
10554
10555 <para>The rest of these functions should be relatively obvious (the _c
10556 versions accept a character instead of a string):</para>
10557              
10558 <programlisting role="C">            
10559 GString *g_string_truncate( GString *string,
10560                             gint     len );
10561                              
10562 GString *g_string_append( GString *string,
10563                           gchar   *val );
10564                             
10565 GString *g_string_append_c( GString *string,
10566                             gchar    c );
10567         
10568 GString *g_string_prepend( GString *string,
10569                            gchar   *val );
10570                              
10571 GString *g_string_prepend_c( GString *string,
10572                              gchar    c );
10573         
10574 void g_string_sprintf( GString *string,
10575                        gchar   *fmt,
10576                        ...);
10577         
10578 void g_string_sprintfa ( GString *string,
10579                          gchar   *fmt,
10580                          ... );
10581 </programlisting>
10582
10583 </sect1>
10584
10585 <!-- ----------------------------------------------------------------- -->
10586 <sect1 id="sec-UtilityAndErrorFunctions">
10587 <title>Utility and Error Functions</title>
10588
10589 <programlisting role="C">
10590 gchar *g_strdup( const gchar *str );
10591 </programlisting>
10592
10593 <para>Replacement strdup function.  Copies the original strings contents to
10594 newly allocated memory, and returns a pointer to it.</para>
10595
10596 <programlisting role="C">
10597 gchar *g_strerror( gint errnum );
10598 </programlisting>
10599
10600 <para>I recommend using this for all error messages.  It's much nicer, and more
10601 portable than perror() or others.  The output is usually of the form:</para>
10602
10603 <programlisting role="C">
10604 program name:function that failed:file or further description:strerror
10605 </programlisting>
10606
10607 <para>Here's an example of one such call used in our hello_world program:</para>
10608
10609 <programlisting role="C">
10610 g_print("hello_world:open:%s:%s\n", filename, g_strerror(errno));
10611 </programlisting>
10612
10613 <programlisting role="C">
10614 void g_error( gchar *format, ... );
10615 </programlisting>
10616
10617 <para>Prints an error message. The format is just like printf, but it
10618 prepends "** ERROR **: " to your message, and exits the program.  
10619 Use only for fatal errors.</para>
10620
10621 <programlisting role="C">
10622 void g_warning( gchar *format, ... );
10623 </programlisting>
10624
10625 <para>Same as above, but prepends "** WARNING **: ", and does not exit the
10626 program.</para>
10627
10628 <programlisting role="C">
10629 void g_message( gchar *format, ... );
10630 </programlisting>
10631
10632 <para>Prints "message: " prepended to the string you pass in.</para>
10633
10634 <programlisting role="C">
10635 void g_print( gchar *format, ... );
10636 </programlisting>
10637
10638 <para>Replacement for printf().</para>
10639
10640 <para>And our last function:</para>
10641
10642 <programlisting role="C">
10643 gchar *g_strsignal( gint signum );
10644 </programlisting>
10645
10646 <para>Prints out the name of the Unix system signal given the signal number.
10647 Useful in generic signal handling functions.</para>
10648
10649 <para>All of the above are more or less just stolen from glib.h.  If anyone cares
10650 to document any function, just send me an email!</para>
10651
10652 </sect1>
10653 </chapter>
10654
10655 <!-- ***************************************************************** -->
10656 <chapter id="ch-GTKRCFiles">
10657 <title>GTK's rc Files</title>
10658
10659 <para>GTK has its own way of dealing with application defaults, by using rc
10660 files. These can be used to set the colors of just about any widget, and
10661 can also be used to tile pixmaps onto the background of some widgets.  </para>
10662
10663 <!-- ----------------------------------------------------------------- -->
10664 <sect1 id="sec-FunctionsForRCFiles">
10665 <title>Functions For rc Files</title>
10666
10667 <para>When your application starts, you should include a call to:</para>
10668
10669 <programlisting role="C">
10670 void gtk_rc_parse( char *filename );
10671 </programlisting>
10672
10673 <para>Passing in the filename of your rc file. This will cause GTK to parse
10674 this file, and use the style settings for the widget types defined
10675 there.</para>
10676
10677 <para>If you wish to have a special set of widgets that can take on a
10678 different style from others, or any other logical division of widgets,
10679 use a call to:</para>
10680
10681 <programlisting role="C">
10682 void gtk_widget_set_name( GtkWidget *widget,
10683                           gchar     *name );
10684 </programlisting>
10685
10686 <para>Passing your newly created widget as the first argument, and the name
10687 you wish to give it as the second. This will allow you to change the
10688 attributes of this widget by name through the rc file.</para>
10689
10690 <para>If we use a call something like this:</para>
10691
10692 <programlisting role="C">
10693 button = gtk_button_new_with_label ("Special Button");
10694 gtk_widget_set_name (button, "special button");
10695 </programlisting>
10696
10697 <para>Then this button is given the name "special button" and may be addressed by
10698 name in the rc file as "special button.GtkButton".  [<--- Verify ME!]</para>
10699
10700 <para>The example rc file below, sets the properties of the main window, and lets
10701 all children of that main window inherit the style described by the "main
10702 button" style.  The code used in the application is:</para>
10703
10704 <programlisting role="C">
10705 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
10706 gtk_widget_set_name (window, "main window");
10707 </programlisting>
10708
10709 <para>And then the style is defined in the rc file using:</para>
10710
10711 <programlisting role="C">
10712 widget "main window.*GtkButton*" style "main_button"
10713 </programlisting>
10714
10715 <para>Which sets all the Button widgets in the "main window" to the
10716 "main_buttons" style as defined in the rc file.</para>
10717
10718 <para>As you can see, this is a fairly powerful and flexible system.  Use your
10719 imagination as to how best to take advantage of this.</para>
10720
10721 </sect1>
10722
10723 <!-- ----------------------------------------------------------------- -->
10724 <sect1 id="sec-GTKsRCFileFormat">
10725 <title>GTK's rc File Format</title>
10726
10727 <para>The format of the GTK file is illustrated in the example below. This is
10728 the testgtkrc file from the GTK distribution, but I've added a
10729 few comments and things. You may wish to include this explanation in
10730 your application to allow the user to fine tune his application.</para>
10731
10732 <para>There are several directives to change the attributes of a widget.</para>
10733
10734 <itemizedlist>
10735 <listitem><simpara>fg - Sets the foreground color of a widget.</simpara>
10736 </listitem>
10737 <listitem><simpara>bg - Sets the background color of a widget.</simpara>
10738 </listitem>
10739 <listitem><simpara>bg_pixmap - Sets the background of a widget to a tiled pixmap.</simpara>
10740 </listitem>
10741 <listitem><simpara>font - Sets the font to be used with the given widget.</simpara>
10742 </listitem>
10743 </itemizedlist>
10744
10745 <para>In addition to this, there are several states a widget can be in, and you
10746 can set different colors, pixmaps and fonts for each state. These states are:</para>
10747
10748 <itemizedlist>
10749 <listitem><simpara>NORMAL - The normal state of a widget, without the mouse over top of
10750 it, and not being pressed, etc.</simpara>
10751 </listitem>
10752 <listitem><simpara>PRELIGHT - When the mouse is over top of the widget, colors defined
10753 using this state will be in effect.</simpara>
10754 </listitem>
10755 <listitem><simpara>ACTIVE - When the widget is pressed or clicked it will be active, and
10756 the attributes assigned by this tag will be in effect.</simpara>
10757 </listitem>
10758 <listitem><simpara>INSENSITIVE - When a widget is set insensitive, and cannot be
10759 activated, it will take these attributes.</simpara>
10760 </listitem>
10761 <listitem><simpara>SELECTED - When an object is selected, it takes these attributes.</simpara>
10762 </listitem>
10763 </itemizedlist>
10764
10765 <para>When using the "fg" and "bg" keywords to set the colors of widgets, the
10766 format is:</para>
10767
10768 <programlisting role="C">
10769 fg[&lt;STATE>] = { Red, Green, Blue }
10770 </programlisting>
10771
10772 <para>Where STATE is one of the above states (PRELIGHT, ACTIVE, etc), and the Red,
10773 Green and Blue are values in the range of 0 - 1.0,  { 1.0, 1.0, 1.0 } being
10774 white. They must be in float form, or they will register as 0, so a straight 
10775 "1" will not work, it must be "1.0".  A straight "0" is fine because it 
10776 doesn't matter if it's not recognized.  Unrecognized values are set to 0.</para>
10777
10778 <para>bg_pixmap is very similar to the above, except the colors are replaced by a
10779 filename.</para>
10780
10781 <para>pixmap_path is a list of paths separated by ":"'s.  These paths will be
10782 searched for any pixmap you specify.</para>
10783
10784 <para>The font directive is simply:</para>
10785
10786 <programlisting role="C">
10787 font = "&lt;font name>"
10788 </programlisting>
10789
10790 <para>The only hard part is figuring out the font string. Using xfontsel or
10791 a similar utility should help.</para>
10792
10793 <para>The "widget_class" sets the style of a class of widgets. These classes are
10794 listed in the widget overview on the class hierarchy.</para>
10795
10796 <para>The "widget" directive sets a specifically named set of widgets to a
10797 given style, overriding any style set for the given widget class.
10798 These widgets are registered inside the application using the
10799 gtk_widget_set_name() call. This allows you to specify the attributes of a
10800 widget on a per widget basis, rather than setting the attributes of an
10801 entire widget class. I urge you to document any of these special widgets so
10802 users may customize them.</para>
10803
10804 <para>When the keyword <literal>parent</> is used as an attribute, the widget will take on
10805 the attributes of its parent in the application.</para>
10806
10807 <para>When defining a style, you may assign the attributes of a previously defined
10808 style to this new one.</para>
10809
10810 <programlisting role="C">
10811 style "main_button" = "button"
10812 {
10813   font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
10814   bg[PRELIGHT] = { 0.75, 0, 0 }
10815 }
10816 </programlisting>
10817
10818 <para>This example takes the "button" style, and creates a new "main_button" style
10819 simply by changing the font and prelight background color of the "button"
10820 style.</para>
10821
10822 <para>Of course, many of these attributes don't apply to all widgets. It's a
10823 simple matter of common sense really. Anything that could apply, should.</para>
10824
10825 </sect1>
10826
10827 <!-- ----------------------------------------------------------------- -->
10828 <sect1 id="sec-ExampleRCFile">
10829 <title>Example rc file</title>
10830
10831 <programlisting role="C">
10832 # pixmap_path "&lt;dir 1>:&lt;dir 2>:&lt;dir 3>:..."
10833 #
10834 pixmap_path "/usr/include/X11R6/pixmaps:/home/imain/pixmaps"
10835 #
10836 # style &lt;name> [= &lt;name>]
10837 # {
10838 #   &lt;option>
10839 # }
10840 #
10841 # widget &lt;widget_set> style &lt;style_name>
10842 # widget_class &lt;widget_class_set> style &lt;style_name>
10843
10844 # Here is a list of all the possible states.  Note that some do not apply to
10845 # certain widgets.
10846 #
10847 # NORMAL - The normal state of a widget, without the mouse over top of
10848 # it, and not being pressed, etc.
10849 #
10850 # PRELIGHT - When the mouse is over top of the widget, colors defined
10851 # using this state will be in effect.
10852 #
10853 # ACTIVE - When the widget is pressed or clicked it will be active, and
10854 # the attributes assigned by this tag will be in effect.
10855 #
10856 # INSENSITIVE - When a widget is set insensitive, and cannot be
10857 # activated, it will take these attributes.
10858 #
10859 # SELECTED - When an object is selected, it takes these attributes.
10860 #
10861 # Given these states, we can set the attributes of the widgets in each of
10862 # these states using the following directives.
10863 #
10864 # fg - Sets the foreground color of a widget.
10865 # fg - Sets the background color of a widget.
10866 # bg_pixmap - Sets the background of a widget to a tiled pixmap.
10867 # font - Sets the font to be used with the given widget.
10868 #
10869
10870 # This sets a style called "button".  The name is not really important, as
10871 # it is assigned to the actual widgets at the bottom of the file.
10872
10873 style "window"
10874 {
10875   #This sets the padding around the window to the pixmap specified.
10876   #bg_pixmap[&lt;STATE>] = "&lt;pixmap filename>"
10877   bg_pixmap[NORMAL] = "warning.xpm"
10878 }
10879
10880 style "scale"
10881 {
10882   #Sets the foreground color (font color) to red when in the "NORMAL"
10883   #state.
10884   
10885   fg[NORMAL] = { 1.0, 0, 0 }
10886   
10887   #Sets the background pixmap of this widget to that of its parent.
10888   bg_pixmap[NORMAL] = "&lt;parent>"
10889 }
10890
10891 style "button"
10892 {
10893   # This shows all the possible states for a button.  The only one that
10894   # doesn't apply is the SELECTED state.
10895   
10896   fg[PRELIGHT] = { 0, 1.0, 1.0 }
10897   bg[PRELIGHT] = { 0, 0, 1.0 }
10898   bg[ACTIVE] = { 1.0, 0, 0 }
10899   fg[ACTIVE] = { 0, 1.0, 0 }
10900   bg[NORMAL] = { 1.0, 1.0, 0 }
10901   fg[NORMAL] = { .99, 0, .99 }
10902   bg[INSENSITIVE] = { 1.0, 1.0, 1.0 }
10903   fg[INSENSITIVE] = { 1.0, 0, 1.0 }
10904 }
10905
10906 # In this example, we inherit the attributes of the "button" style and then
10907 # override the font and background color when prelit to create a new
10908 # "main_button" style.
10909
10910 style "main_button" = "button"
10911 {
10912   font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
10913   bg[PRELIGHT] = { 0.75, 0, 0 }
10914 }
10915
10916 style "toggle_button" = "button"
10917 {
10918   fg[NORMAL] = { 1.0, 0, 0 }
10919   fg[ACTIVE] = { 1.0, 0, 0 }
10920   
10921   # This sets the background pixmap of the toggle_button to that of its
10922   # parent widget (as defined in the application).
10923   bg_pixmap[NORMAL] = "&lt;parent>"
10924 }
10925
10926 style "text"
10927 {
10928   bg_pixmap[NORMAL] = "marble.xpm"
10929   fg[NORMAL] = { 1.0, 1.0, 1.0 }
10930 }
10931
10932 style "ruler"
10933 {
10934   font = "-adobe-helvetica-medium-r-normal--*-80-*-*-*-*-*-*"
10935 }
10936
10937 # pixmap_path "~/.pixmaps"
10938
10939 # These set the widget types to use the styles defined above.
10940 # The widget types are listed in the class hierarchy, but could probably be
10941 # just listed in this document for the users reference.
10942
10943 widget_class "GtkWindow" style "window"
10944 widget_class "GtkDialog" style "window"
10945 widget_class "GtkFileSelection" style "window"
10946 widget_class "*Gtk*Scale" style "scale"
10947 widget_class "*GtkCheckButton*" style "toggle_button"
10948 widget_class "*GtkRadioButton*" style "toggle_button"
10949 widget_class "*GtkButton*" style "button"
10950 widget_class "*Ruler" style "ruler"
10951 widget_class "*GtkText" style "text"
10952
10953 # This sets all the buttons that are children of the "main window" to
10954 # the main_button style.  These must be documented to be taken advantage of.
10955 widget "main window.*GtkButton*" style "main_button"
10956 </programlisting>
10957
10958 </sect1>
10959 </chapter>
10960
10961 <!-- ***************************************************************** -->
10962 <chapter id="ch-WritingYourOwnWidgets">
10963 <title>Writing Your Own Widgets</title>
10964
10965 <!-- ----------------------------------------------------------------- -->
10966 <sect1 id="sec-WidgetsOverview">
10967 <title>Overview</title>
10968
10969 <para>Although the GTK distribution comes with many types of widgets that
10970 should cover most basic needs, there may come a time when you need to
10971 create your own new widget type. Since GTK uses widget inheritance
10972 extensively, and there is already a widget that is close to what you want,
10973 it is often possible to make a useful new widget type in
10974 just a few lines of code. But before starting work on a new widget, check
10975 around first to make sure that someone has not already written
10976 it. This will prevent duplication of effort and keep the number of
10977 GTK widgets out there to a minimum, which will help keep both the code
10978 and the interface of different applications consistent. As a flip side
10979 to this, once you finish your widget, announce it to the world so
10980 other people can benefit. The best place to do this is probably the
10981 <literal>gtk-list</literal>.</para>
10982
10983 <para>Complete sources for the example widgets are available at the place you 
10984 got this tutorial, or from:</para>
10985
10986 <para><ulink url="http://www.gtk.org/~otaylor/gtk/tutorial/">http://www.gtk.org/~otaylor/gtk/tutorial/</ulink></para>
10987
10988
10989 </sect1>
10990
10991 <!-- ----------------------------------------------------------------- -->
10992 <sect1 id="sec-TheAnatomyOfAWidget">
10993 <title>The Anatomy Of A Widget</title>
10994
10995 <para>In order to create a new widget, it is important to have an
10996 understanding of how GTK objects work. This section is just meant as a
10997 brief overview. See the reference documentation for the details. </para>
10998
10999 <para>GTK widgets are implemented in an object oriented fashion. However,
11000 they are implemented in standard C. This greatly improves portability
11001 and stability over using current generation C++ compilers; however,
11002 it does mean that the widget writer has to pay attention to some of
11003 the implementation details. The information common to all instances of
11004 one class of widgets (e.g., to all Button widgets) is stored in the 
11005 <emphasis>class structure</emphasis>. There is only one copy of this in
11006 which is stored information about the class's signals
11007 (which act like virtual functions in C). To support inheritance, the
11008 first field in the class structure must be a copy of the parent's
11009 class structure. The declaration of the class structure of GtkButtton
11010 looks like:</para>
11011
11012 <programlisting role="C">
11013 struct _GtkButtonClass
11014 {
11015   GtkContainerClass parent_class;
11016
11017   void (* pressed)  (GtkButton *button);
11018   void (* released) (GtkButton *button);
11019   void (* clicked)  (GtkButton *button);
11020   void (* enter)    (GtkButton *button);
11021   void (* leave)    (GtkButton *button);
11022 };
11023 </programlisting>
11024
11025 <para>When a button is treated as a container (for instance, when it is
11026 resized), its class structure can be cast to GtkContainerClass, and
11027 the relevant fields used to handle the signals.</para>
11028
11029 <para>There is also a structure for each widget that is created on a
11030 per-instance basis. This structure has fields to store information that
11031 is different for each instance of the widget. We'll call this
11032 structure the <emphasis>object structure</emphasis>. For the Button class, it looks
11033 like:</para>
11034
11035 <programlisting role="C">
11036 struct _GtkButton
11037 {
11038   GtkContainer container;
11039
11040   GtkWidget *child;
11041
11042   guint in_button : 1;
11043   guint button_down : 1;
11044 };
11045 </programlisting>
11046
11047 <para>Note that, similar to the class structure, the first field is the
11048 object structure of the parent class, so that this structure can be
11049 cast to the parent class' object structure as needed.</para>
11050
11051 </sect1>
11052
11053 <!-- ----------------------------------------------------------------- -->
11054 <sect1 id="sec-CreatingACompositeWidget">
11055 <title>Creating a Composite widget</title>
11056
11057 <!-- ----------------------------------------------------------------- -->
11058 <sect2>
11059 <title>Introduction</title>
11060
11061 <para>One type of widget that you may be interested in creating is a
11062 widget that is merely an aggregate of other GTK widgets. This type of
11063 widget does nothing that couldn't be done without creating new
11064 widgets, but provides a convenient way of packaging user interface
11065 elements for reuse. The FileSelection and ColorSelection widgets in
11066 the standard distribution are examples of this type of widget.</para>
11067
11068 <para>The example widget that we'll create in this section is the Tictactoe
11069 widget, a 3x3 array of toggle buttons which triggers a signal when all
11070 three buttons in a row, column, or on one of the diagonals are
11071 depressed. </para>
11072
11073 <para><emphasis>Note: the full source code for the Tictactoe example described
11074 below is in the <link linkend="sec-Tictactoe">Code Examples Appendix</link>
11075 </emphasis></para>
11076
11077 <para>
11078 <inlinemediaobject>
11079 <imageobject>
11080 <imagedata fileref="images/tictactoe.png" format="png">
11081 </imageobject>
11082 </inlinemediaobject>
11083 </para>
11084
11085 </sect2>
11086
11087 <!-- ----------------------------------------------------------------- -->
11088 <sect2>
11089 <title>Choosing a parent class</title>
11090
11091 <para>The parent class for a composite widget is typically the container
11092 class that holds all of the elements of the composite widget. For
11093 example, the parent class of the FileSelection widget is the
11094 Dialog class. Since our buttons will be arranged in a table, it
11095 is natural to make our parent class the Table class.</para>
11096
11097 </sect2>
11098
11099 <!-- ----------------------------------------------------------------- -->
11100 <sect2>
11101 <title>The header file</title>
11102
11103 <para>Each GObject class has a header file which declares the object and
11104 class structures for that object, along with public functions. 
11105 A couple of features are worth pointing out. To prevent duplicate
11106 definitions, we wrap the entire header file in:</para>
11107
11108 <programlisting role="C">
11109 #ifndef __TICTACTOE_H__
11110 #define __TICTACTOE_H__
11111 .
11112 .
11113 .
11114 #endif /* __TICTACTOE_H__ */
11115 </programlisting>
11116
11117 <para>And to keep C++ programs that include the header file happy, in:</para>
11118
11119 <programlisting role="C">
11120 #include &lt;glib.h&gt;
11121
11122 G_BEGIN_DECLS
11123 .
11124 .
11125 .
11126 G_END_DECLS
11127 </programlisting>
11128
11129 <para>Along with the functions and structures, we declare five standard
11130 macros in our header file, <literal>TICTACTOE_TYPE</literal>,
11131 <literal>TICTACTOE(obj)</literal>,
11132 <literal>TICTACTOE_CLASS(klass)</literal>,
11133 <literal>IS_TICTACTOE(obj)</literal>, and
11134 <literal>IS_TICTACTOE_CLASS(klass)</literal>, which cast a
11135 pointer into a pointer to the object or class structure, and check
11136 if an object is a Tictactoe widget respectively.</para>
11137
11138 </sect2>
11139
11140 <!-- ----------------------------------------------------------------- -->
11141 <sect2>
11142 <title>The <literal>_get_type()</literal> function</title>
11143
11144 <para>We now continue on to the implementation of our widget. A core
11145 function for every object is the function
11146 <literal>WIDGETNAME_get_type()</literal>. This function, when first called, tells
11147 Glib about the new class, and gets an ID that uniquely identifies
11148 the class. Upon subsequent calls, it just returns the ID.</para>
11149
11150 <programlisting role="C">
11151 GType
11152 tictactoe_get_type (void)
11153 {
11154   static GType ttt_type = 0;
11155
11156   if (!ttt_type)
11157     {
11158       static const GTypeInfo ttt_info =
11159       {
11160         sizeof (TictactoeClass),
11161         NULL, /* base_init */
11162         NULL, /* base_finalize */
11163         (GClassInitFunc) tictactoe_class_init,
11164         NULL, /* class_finalize */
11165         NULL, /* class_data */
11166         sizeof (Tictactoe),
11167         0,    /* n_preallocs */
11168         (GInstanceInitFunc) tictactoe_init,
11169       };
11170
11171       ttt_type = g_type_register_static (GTK_TYPE_TABLE,
11172                                          "Tictactoe",
11173                                          &amp;ttt_info,
11174                                          0);
11175     }
11176
11177   return ttt_type;
11178 }
11179 </programlisting>
11180
11181 <para>The GTypeInfo structure has the following definition:</para>
11182
11183 <programlisting role="C">
11184 struct _GTypeInfo
11185 {
11186   /* interface types, classed types, instantiated types */
11187   guint16                class_size;
11188    
11189   GBaseInitFunc          base_init;
11190   GBaseFinalizeFunc      base_finalize;
11191    
11192   /* classed types, instantiated types */
11193   GClassInitFunc         class_init;
11194   GClassFinalizeFunc     class_finalize;
11195   gconstpointer          class_data;
11196    
11197   /* instantiated types */
11198   guint16                instance_size;
11199   guint16                n_preallocs;
11200   GInstanceInitFunc      instance_init;
11201    
11202   /* value handling */
11203   const GTypeValueTable *value_table;
11204 };
11205 </programlisting>
11206
11207 <para>The important fields of this structure are pretty self-explanatory.
11208 We'll ignore the <literal>base_init</literal> and
11209  <literal>base_finalize</literal> as well as the <literal>value_table</literal>
11210 fields here. Once Glib has a correctly filled in copy of
11211 this structure, it knows how to create objects of a particular type. </para>
11212
11213 </sect2>
11214
11215 <!-- ----------------------------------------------------------------- -->
11216 <sect2>
11217 <title>The <literal>_class_init()</literal> function</title>
11218
11219 <para>The <literal>WIDGETNAME_class_init()</literal> function initializes the fields of
11220 the widget's class structure, and sets up any signals for the
11221 class. For our Tictactoe widget it looks like:</para>
11222
11223 <programlisting role="C">
11224 enum {
11225   TICTACTOE_SIGNAL,
11226   LAST_SIGNAL
11227 };
11228
11229
11230 static guint tictactoe_signals[LAST_SIGNAL] = { 0 };
11231
11232 static void
11233 tictactoe_class_init (TictactoeClass *klass)
11234 {
11235   tictactoe_signals[TICTACTOE_SIGNAL] =
11236     g_signal_new ("tictactoe",
11237                   G_TYPE_FROM_CLASS (klass),
11238                   G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
11239                   G_STRUCT_OFFSET (TictactoeClass, tictactoe),
11240                   NULL, NULL,
11241                   g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
11242 }
11243 </programlisting>
11244
11245 <para>Our widget has just one signal, the <literal>tictactoe</literal> signal that is
11246 invoked when a row, column, or diagonal is completely filled in. Not
11247 every composite widget needs signals, so if you are reading this for
11248 the first time, you may want to skip to the next section now, as
11249 things are going to get a bit complicated.</para>
11250
11251 <para>The function:</para>
11252
11253 <programlisting role="C">
11254 guint g_signal_new( const gchar         *signal_name,
11255                     GType                itype,
11256                     GSignalFlags         signal_flags,
11257                     guint                class_offset,
11258                     GSignalAccumulator  *accumulator,
11259                     gpointer             accu_data,
11260                     GSignalCMarshaller  *c_marshaller,
11261                     GType                return_type,
11262                     guint                n_params,
11263                     ...);
11264 </programlisting>
11265
11266 <para>Creates a new signal. The parameters are:</para>
11267
11268 <itemizedlist>
11269 <listitem><simpara> <literal>signal_name</literal>: The name of the signal.</simpara>
11270 </listitem>
11271
11272 <listitem><simpara> <literal>itype</literal>: The ID of the object that this signal applies
11273 to. (It will also apply to that objects descendants.)</simpara>
11274 </listitem>
11275                                                                                 
11276 <listitem><simpara> <literal>signal_flags</literal>: Whether the default handler runs before or after
11277 user handlers and other flags. Usually this will be one of
11278 <literal>G_SIGNAL_RUN_FIRST</literal> or <literal>G_SIGNAL_RUN_LAST</literal>,
11279 although there are other possibilities. The flag
11280 <literal>G_SIGNAL_ACTION</literal> specifies that no extra code needs to
11281 run that performs special pre or post emission adjustments. This means that
11282 the signal can also be emitted from object external code.</simpara>
11283 </listitem>
11284
11285 <listitem><simpara> <literal>class_offset</literal>: The offset within the class structure of
11286 a pointer to the default handler.</simpara>
11287 </listitem>
11288
11289 <listitem><simpara> <literal>accumulator</literal>: For most classes this can
11290 be set to NULL.</simpara></listitem>
11291
11292 <listitem><simpara> <literal>accu_data</literal>: User data that will be handed
11293 to the accumulator function.</simpara></listitem>
11294
11295 <listitem><simpara> <literal>c_marshaller</literal>: A function that is used to invoke the signal
11296 handler. For signal handlers that have no arguments other than the
11297 object that emitted the signal and user data, we can use the
11298 pre-supplied marshaller function <literal>g_cclosure_marshal_VOID__VOID</literal>.</simpara>
11299 </listitem>
11300
11301 <listitem><simpara> <literal>return_type</literal>: The type of the return value.</simpara>
11302 </listitem>
11303
11304 <listitem><simpara> <literal>n_params</literal>: The number of parameters of the signal handler
11305 (other than the two default ones mentioned above)</simpara>
11306 </listitem>
11307
11308 <listitem><simpara> <literal>...</literal>: The types of the parameters.</simpara>
11309 </listitem>
11310 </itemizedlist>
11311
11312 <para>When specifying types, the following standard types can be used:</para>
11313
11314 <programlisting role="C">
11315 G_TYPE_INVALID
11316 G_TYPE_NONE
11317 G_TYPE_INTERFACE
11318 G_TYPE_CHAR
11319 G_TYPE_UCHAR
11320 G_TYPE_BOOLEAN
11321 G_TYPE_INT
11322 G_TYPE_UINT
11323 G_TYPE_LONG
11324 G_TYPE_ULONG
11325 G_TYPE_INT64
11326 G_TYPE_UINT64
11327 G_TYPE_ENUM
11328 G_TYPE_FLAGS
11329 G_TYPE_FLOAT
11330 G_TYPE_DOUBLE
11331 G_TYPE_STRING
11332 G_TYPE_POINTER
11333 G_TYPE_BOXED
11334 G_TYPE_PARAM
11335 G_TYPE_OBJECT
11336 </programlisting>
11337
11338 <para><literal>g_signal_new()</literal> returns a unique integer identifier for the
11339 signal, that we store in the <literal>tictactoe_signals</literal> array, which we
11340 index using an enumeration. (Conventionally, the enumeration elements
11341 are the signal name, uppercased, but here there would be a conflict
11342 with the <literal>TICTACTOE()</literal> macro, so we called it <literal>TICTACTOE_SIGNAL</literal>
11343 instead.</para>
11344
11345 </sect2>
11346
11347 <!-- ----------------------------------------------------------------- -->
11348 <sect2>
11349 <title>The <literal>_init()</literal> function</title>
11350
11351 <para>Each class also needs a function to initialize the object
11352 structure. Usually, this function has the fairly limited role of
11353 setting the fields of the structure to default values. For composite
11354 widgets, however, this function also creates the component widgets.</para>
11355
11356 <programlisting role="C">
11357 static void
11358 tictactoe_init (Tictactoe *ttt)
11359 {
11360   gint i,j;
11361
11362   gtk_table_resize (GTK_TABLE (ttt), 3, 3);
11363   gtk_table_set_homogeneous (GTK_TABLE (ttt), TRUE);
11364
11365   for (i=0;i&lt;3; i++)
11366     for (j=0;j&lt;3; j++)
11367       {
11368         ttt->buttons[i][j] = gtk_toggle_button_new ();
11369         gtk_table_attach_defaults (GTK_TABLE (ttt), ttt->buttons[i][j], 
11370                                    i, i+1, j, j+1);
11371         g_signal_connect (G_OBJECT (ttt->buttons[i][j]), "toggled",
11372                           G_CALLBACK (tictactoe_toggle), ttt);
11373         gtk_widget_set_size_request (ttt->buttons[i][j], 20, 20);
11374         gtk_widget_show (ttt->buttons[i][j]);
11375       }
11376 }
11377 </programlisting>
11378
11379 </sect2>
11380
11381 <!-- ----------------------------------------------------------------- -->
11382 <sect2>
11383 <title>And the rest...</title>
11384
11385 <para>There is one more function that every object (except for abstract
11386 classes like Bin that cannot be instantiated) needs to have - the
11387 function that the user calls to create an object of that type. This is
11388 conventionally called <literal>OBJECTNAME_new()</literal>. In some
11389 widgets, though not for the Tictactoe widgets, this function takes
11390 arguments, and does some setup based on the arguments. The other two
11391 functions are specific to the Tictactoe widget. </para>
11392
11393 <para><literal>tictactoe_clear()</literal> is a public function that resets all the
11394 buttons in the widget to the up position. Note the use of
11395 <literal>g_signal_handlers_block_matched()</literal> to keep our signal handler for
11396 button toggles from being triggered unnecessarily.</para>
11397
11398 <para><literal>tictactoe_toggle()</literal> is the signal handler that is invoked when the
11399 user clicks on a button. It checks to see if there are any winning
11400 combinations that involve the toggled button, and if so, emits
11401 the "tictactoe" signal.</para>
11402
11403 <programlisting role="C">
11404 GtkWidget*
11405 tictactoe_new (void)
11406 {
11407   return GTK_WIDGET ( g_object_new (TICTACTOE_TYPE, NULL));
11408 }
11409
11410 void           
11411 tictactoe_clear (Tictactoe *ttt)
11412 {
11413   int i,j;
11414
11415   for (i=0;i&lt;3;i++)
11416     for (j=0;j&lt;3;j++)
11417       {
11418         g_signal_handlers_block_matched (G_OBJECT (ttt->buttons[i][j]),
11419                                          G_SIGNAL_MATCH_DATA,
11420                                          0, 0, NULL, NULL, ttt);
11421         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ttt->buttons[i][j]),
11422                                      FALSE);
11423         g_signal_handlers_unblock_matched (G_OBJECT (ttt->buttons[i][j]),
11424                                            G_SIGNAL_MATCH_DATA,
11425                                            0, 0, NULL, NULL, ttt);
11426       }
11427 }
11428
11429 static void
11430 tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt)
11431 {
11432   int i,k;
11433
11434   static int rwins[8][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
11435                              { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
11436                              { 0, 1, 2 }, { 0, 1, 2 } };
11437   static int cwins[8][3] = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
11438                              { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
11439                              { 0, 1, 2 }, { 2, 1, 0 } };
11440
11441   int success, found;
11442
11443   for (k=0; k&lt;8; k++)
11444     {
11445       success = TRUE;
11446       found = FALSE;
11447
11448       for (i=0;i&lt;3;i++)
11449         {
11450           success = success &amp;&amp; 
11451             GTK_TOGGLE_BUTTON(ttt->buttons[rwins[k][i]][cwins[k][i]])->active;
11452           found = found ||
11453             ttt->buttons[rwins[k][i]][cwins[k][i]] == widget;
11454         }
11455       
11456       if (success &amp;&amp; found)
11457         {
11458           g_signal_emit (G_OBJECT (ttt), 
11459                          tictactoe_signals[TICTACTOE_SIGNAL], 0);
11460           break;
11461         }
11462     }
11463 }
11464 </programlisting>
11465
11466 <para>And finally, an example program using our Tictactoe widget:</para>
11467
11468 <programlisting role="C">
11469 #include &lt;gtk/gtk.h&gt;
11470 #include "tictactoe.h"
11471
11472 /* Invoked when a row, column or diagonal is completed */
11473 void
11474 win (GtkWidget *widget, gpointer data)
11475 {
11476   g_print ("Yay!\n");
11477   tictactoe_clear (TICTACTOE (widget));
11478 }
11479
11480 int 
11481 main (int argc, char *argv[])
11482 {
11483   GtkWidget *window;
11484   GtkWidget *ttt;
11485   
11486   gtk_init (&amp;argc, &amp;argv);
11487
11488   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
11489   
11490   gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
11491   
11492   g_signal_connect (G_OBJECT (window), "destroy",
11493                     G_CALLBACK (exit), NULL);
11494   
11495   gtk_container_set_border_width (GTK_CONTAINER (window), 10);
11496
11497   /* Create a new Tictactoe widget */
11498   ttt = tictactoe_new ();
11499   gtk_container_add (GTK_CONTAINER (window), ttt);
11500   gtk_widget_show (ttt);
11501
11502   /* And attach to its "tictactoe" signal */
11503   g_signal_connect (G_OBJECT (ttt), "tictactoe",
11504                     G_CALLBACK (win), NULL);
11505
11506   gtk_widget_show (window);
11507   
11508   gtk_main ();
11509   
11510   return 0;
11511 }
11512 </programlisting>
11513
11514 </sect2>
11515 </sect1>
11516
11517 <!-- ----------------------------------------------------------------- -->
11518 <sect1 id="sec-CreatingAWidgetFromScratch">
11519 <title>Creating a widget from scratch</title>
11520
11521 <!-- ----------------------------------------------------------------- -->
11522 <sect2>
11523 <title>Introduction</title>
11524
11525 <para>In this section, we'll learn more about how widgets display themselves
11526 on the screen and interact with events. As an example of this, we'll
11527 create an analog dial widget with a pointer that the user can drag to
11528 set the value.</para>
11529
11530 <para>
11531 <inlinemediaobject>
11532 <imageobject>
11533 <imagedata fileref="images/gtkdial.png" format="png">
11534 </imageobject>
11535 </inlinemediaobject>
11536 </para>
11537
11538 </sect2>
11539
11540 <!-- ----------------------------------------------------------------- -->
11541 <sect2>
11542 <title>Displaying a widget on the screen</title>
11543
11544 <para>There are several steps that are involved in displaying on the screen.
11545 After the widget is created with a call to <literal>WIDGETNAME_new()</literal>,
11546 several more functions are needed:</para>
11547
11548 <itemizedlist>
11549 <listitem><simpara> <literal>WIDGETNAME_realize()</literal> is responsible for creating an X
11550 window for the widget if it has one.</simpara>
11551 </listitem>
11552 <listitem><simpara> <literal>WIDGETNAME_map()</literal> is invoked after the user calls
11553 <literal>gtk_widget_show()</literal>. It is responsible for making sure the widget
11554 is actually drawn on the screen (<emphasis>mapped</emphasis>). For a container class,
11555 it must also make calls to <literal>map()</literal> functions of any child widgets.</simpara>
11556 </listitem>
11557 <listitem><simpara> <literal>WIDGETNAME_draw()</literal> is invoked when <literal>gtk_widget_draw()</literal>
11558 is called for the widget or one of its ancestors. It makes the actual
11559 calls to the drawing functions to draw the widget on the screen. For
11560 container widgets, this function must make calls to
11561 <literal>gtk_widget_draw()</literal> for its child widgets.</simpara>
11562 </listitem>
11563 <listitem><simpara> <literal>WIDGETNAME_expose()</literal> is a handler for expose events for the
11564 widget. It makes the necessary calls to the drawing functions to draw
11565 the exposed portion on the screen. For container widgets, this
11566 function must generate expose events for its child widgets which don't
11567 have their own windows. (If they have their own windows, then X will
11568 generate the necessary expose events.)</simpara>
11569 </listitem>
11570 </itemizedlist>
11571
11572 <para>You might notice that the last two functions are quite similar - each
11573 is responsible for drawing the widget on the screen. In fact many
11574 types of widgets don't really care about the difference between the
11575 two. The default <literal>draw()</literal> function in the widget class simply
11576 generates a synthetic expose event for the redrawn area. However, some
11577 types of widgets can save work by distinguishing between the two
11578 functions. For instance, if a widget has multiple X windows, then
11579 since expose events identify the exposed window, it can redraw only
11580 the affected window, which is not possible for calls to <literal>draw()</literal>.</para>
11581
11582 <para>Container widgets, even if they don't care about the difference for
11583 themselves, can't simply use the default <literal>draw()</literal> function because
11584 their child widgets might care about the difference. However,
11585 it would be wasteful to duplicate the drawing code between the two
11586 functions. The convention is that such widgets have a function called
11587 <literal>WIDGETNAME_paint()</literal> that does the actual work of drawing the
11588 widget, that is then called by the <literal>draw()</literal> and <literal>expose()</literal>
11589 functions.</para>
11590
11591 <para>In our example approach, since the dial widget is not a container
11592 widget, and only has a single window, we can take the simplest
11593 approach and use the default <literal>draw()</literal> function and only implement
11594 an <literal>expose()</literal> function.</para>
11595
11596 </sect2>
11597
11598 <!-- ----------------------------------------------------------------- -->
11599 <sect2>
11600 <title>The origins of the Dial Widget</title>
11601
11602 <para>Just as all land animals are just variants on the first amphibian that
11603 crawled up out of the mud, GTK widgets tend to start off as variants
11604 of some other, previously written widget. Thus, although this section
11605 is entitled "Creating a Widget from Scratch", the Dial widget really
11606 began with the source code for the Range widget. This was picked as a
11607 starting point because it would be nice if our Dial had the same
11608 interface as the Scale widgets which are just specialized descendants
11609 of the Range widget. So, though the source code is presented below in
11610 finished form, it should not be implied that it was written, <emphasis>ab
11611 initio</emphasis> in this fashion. Also, if you aren't yet familiar with
11612 how scale widgets work from the application writer's point of view, it
11613 would be a good idea to look them over before continuing.</para>
11614
11615 </sect2>
11616
11617 <!-- ----------------------------------------------------------------- -->
11618 <sect2>
11619 <title>The Basics</title>
11620
11621 <para>Quite a bit of our widget should look pretty familiar from the
11622 Tictactoe widget. First, we have a header file:</para>
11623
11624 <programlisting role="C">
11625 /* GTK - The GTK+ Toolkit
11626  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
11627  *
11628  * This library is free software; you can redistribute it and/or
11629  * modify it under the terms of the GNU Library General Public
11630  * License as published by the Free Software Foundation; either
11631  * version 2 of the License, or (at your option) any later version.
11632  *
11633  * This library is distributed in the hope that it will be useful,
11634  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11635  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11636  * Library General Public License for more details.
11637  *
11638  * You should have received a copy of the GNU Library General Public
11639  * License along with this library; if not, write to the Free
11640  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
11641  */
11642
11643 #ifndef __GTK_DIAL_H__
11644 #define __GTK_DIAL_H__
11645
11646 #include &lt;gdk/gdk.h&gt;
11647 #include &lt;gtk/gtkadjustment.h&gt;
11648 #include &lt;gtk/gtkwidget.h&gt;
11649
11650
11651 #ifdef __cplusplus
11652 extern "C" {
11653 #endif /* __cplusplus */
11654
11655
11656 #define GTK_DIAL(obj)          GTK_CHECK_CAST (obj, gtk_dial_get_type (), GtkDial)
11657 #define GTK_DIAL_CLASS(klass)  GTK_CHECK_CLASS_CAST (klass, gtk_dial_get_type (), GtkDialClass)
11658 #define GTK_IS_DIAL(obj)       GTK_CHECK_TYPE (obj, gtk_dial_get_type ())
11659
11660
11661 typedef struct _GtkDial        GtkDial;
11662 typedef struct _GtkDialClass   GtkDialClass;
11663
11664 struct _GtkDial
11665 {
11666   GtkWidget widget;
11667
11668   /* update policy (GTK_UPDATE_[CONTINUOUS/DELAYED/DISCONTINUOUS]) */
11669   guint policy : 2;
11670
11671   /* Button currently pressed or 0 if none */
11672   guint8 button;
11673
11674   /* Dimensions of dial components */
11675   gint radius;
11676   gint pointer_width;
11677
11678   /* ID of update timer, or 0 if none */
11679   guint32 timer;
11680
11681   /* Current angle */
11682   gfloat angle;
11683
11684   /* Old values from adjustment stored so we know when something changes */
11685   gfloat old_value;
11686   gfloat old_lower;
11687   gfloat old_upper;
11688
11689   /* The adjustment object that stores the data for this dial */
11690   GtkAdjustment *adjustment;
11691 };
11692
11693 struct _GtkDialClass
11694 {
11695   GtkWidgetClass parent_class;
11696 };
11697
11698
11699 GtkWidget*     gtk_dial_new                    (GtkAdjustment *adjustment);
11700 GtkType        gtk_dial_get_type               (void);
11701 GtkAdjustment* gtk_dial_get_adjustment         (GtkDial      *dial);
11702 void           gtk_dial_set_update_policy      (GtkDial      *dial,
11703                                                 GtkUpdateType  policy);
11704
11705 void           gtk_dial_set_adjustment         (GtkDial      *dial,
11706                                                 GtkAdjustment *adjustment);
11707 #ifdef __cplusplus
11708 }
11709 #endif /* __cplusplus */
11710
11711
11712 #endif /* __GTK_DIAL_H__ */
11713 </programlisting>
11714
11715 <para>Since there is quite a bit more going on in this widget than the last
11716 one, we have more fields in the data structure, but otherwise things
11717 are pretty similar.</para>
11718
11719 <para>Next, after including header files and declaring a few constants,
11720 we have some functions to provide information about the widget
11721 and initialize it:</para>
11722
11723 <programlisting role="C">
11724 #include &lt;math.h&gt;
11725 #include &lt;stdio.h&gt;
11726 #include &lt;gtk/gtkmain.h&gt;
11727 #include &lt;gtk/gtksignal.h&gt;
11728
11729 #include "gtkdial.h"
11730
11731 #define SCROLL_DELAY_LENGTH  300
11732 #define DIAL_DEFAULT_SIZE 100
11733
11734 /* Forward declarations */
11735
11736 [ omitted to save space ]
11737
11738 /* Local data */
11739
11740 static GtkWidgetClass *parent_class = NULL;
11741
11742 GtkType
11743 gtk_dial_get_type ()
11744 {
11745   static GtkType dial_type = 0;
11746
11747   if (!dial_type)
11748     {
11749       static const GtkTypeInfo dial_info =
11750       {
11751         "GtkDial",
11752         sizeof (GtkDial),
11753         sizeof (GtkDialClass),
11754         (GtkClassInitFunc) gtk_dial_class_init,
11755         (GtkObjectInitFunc) gtk_dial_init,
11756         /* reserved_1 */ NULL,
11757         /* reserved_1 */ NULL,
11758         (GtkClassInitFunc) NULL
11759       };
11760
11761       dial_type = gtk_type_unique (GTK_TYPE_WIDGET, &amp;dial_info);
11762     }
11763
11764   return dial_type;
11765 }
11766
11767 static void
11768 gtk_dial_class_init (GtkDialClass *class)
11769 {
11770   GtkObjectClass *object_class;
11771   GtkWidgetClass *widget_class;
11772
11773   object_class = (GtkObjectClass*) class;
11774   widget_class = (GtkWidgetClass*) class;
11775
11776   parent_class = gtk_type_class (gtk_widget_get_type ());
11777
11778   object_class->destroy = gtk_dial_destroy;
11779
11780   widget_class->realize = gtk_dial_realize;
11781   widget_class->expose_event = gtk_dial_expose;
11782   widget_class->size_request = gtk_dial_size_request;
11783   widget_class->size_allocate = gtk_dial_size_allocate;
11784   widget_class->button_press_event = gtk_dial_button_press;
11785   widget_class->button_release_event = gtk_dial_button_release;
11786   widget_class->motion_notify_event = gtk_dial_motion_notify;
11787 }
11788
11789 static void
11790 gtk_dial_init (GtkDial *dial)
11791 {
11792   dial->button = 0;
11793   dial->policy = GTK_UPDATE_CONTINUOUS;
11794   dial->timer = 0;
11795   dial->radius = 0;
11796   dial->pointer_width = 0;
11797   dial->angle = 0.0;
11798   dial->old_value = 0.0;
11799   dial->old_lower = 0.0;
11800   dial->old_upper = 0.0;
11801   dial->adjustment = NULL;
11802 }
11803
11804 GtkWidget*
11805 gtk_dial_new (GtkAdjustment *adjustment)
11806 {
11807   GtkDial *dial;
11808
11809   dial = gtk_type_new (gtk_dial_get_type ());
11810
11811   if (!adjustment)
11812     adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
11813
11814   gtk_dial_set_adjustment (dial, adjustment);
11815
11816   return GTK_WIDGET (dial);
11817 }
11818
11819 static void
11820 gtk_dial_destroy (GtkObject *object)
11821 {
11822   GtkDial *dial;
11823
11824   g_return_if_fail (object != NULL);
11825   g_return_if_fail (GTK_IS_DIAL (object));
11826
11827   dial = GTK_DIAL (object);
11828
11829   if (dial->adjustment)
11830     gtk_object_unref (GTK_OBJECT (dial->adjustment));
11831
11832   if (GTK_OBJECT_CLASS (parent_class)->destroy)
11833     (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
11834 }
11835 </programlisting>
11836
11837 <para>Note that this <literal>init()</literal> function does less than for the Tictactoe
11838 widget, since this is not a composite widget, and the <literal>new()</literal>
11839 function does more, since it now has an argument. Also, note that when
11840 we store a pointer to the Adjustment object, we increment its
11841 reference count, (and correspondingly decrement it when we no longer
11842 use it) so that GTK can keep track of when it can be safely destroyed.</para>
11843
11844 <para>Also, there are a few function to manipulate the widget's options:</para>
11845
11846 <programlisting role="C">
11847 GtkAdjustment*
11848 gtk_dial_get_adjustment (GtkDial *dial)
11849 {
11850   g_return_val_if_fail (dial != NULL, NULL);
11851   g_return_val_if_fail (GTK_IS_DIAL (dial), NULL);
11852
11853   return dial->adjustment;
11854 }
11855
11856 void
11857 gtk_dial_set_update_policy (GtkDial      *dial,
11858                              GtkUpdateType  policy)
11859 {
11860   g_return_if_fail (dial != NULL);
11861   g_return_if_fail (GTK_IS_DIAL (dial));
11862
11863   dial->policy = policy;
11864 }
11865
11866 void
11867 gtk_dial_set_adjustment (GtkDial      *dial,
11868                           GtkAdjustment *adjustment)
11869 {
11870   g_return_if_fail (dial != NULL);
11871   g_return_if_fail (GTK_IS_DIAL (dial));
11872
11873   if (dial->adjustment)
11874     {
11875       gtk_signal_disconnect_by_data (GTK_OBJECT (dial->adjustment), (gpointer) dial);
11876       gtk_object_unref (GTK_OBJECT (dial->adjustment));
11877     }
11878
11879   dial->adjustment = adjustment;
11880   gtk_object_ref (GTK_OBJECT (dial->adjustment));
11881
11882   gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
11883                       (GtkSignalFunc) gtk_dial_adjustment_changed,
11884                       (gpointer) dial);
11885   gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
11886                       (GtkSignalFunc) gtk_dial_adjustment_value_changed,
11887                       (gpointer) dial);
11888
11889   dial->old_value = adjustment->value;
11890   dial->old_lower = adjustment->lower;
11891   dial->old_upper = adjustment->upper;
11892
11893   gtk_dial_update (dial);
11894 }
11895 </programlisting>
11896
11897 </sect2>
11898
11899 <!-- ----------------------------------------------------------------- -->
11900 <sect2>
11901 <title><literal>gtk_dial_realize()</literal></title>
11902
11903 <para>Now we come to some new types of functions. First, we have a function
11904 that does the work of creating the X window. Notice that a mask is
11905 passed to the function <literal>gdk_window_new()</literal> which specifies which fields of
11906 the GdkWindowAttr structure actually have data in them (the remaining
11907 fields will be given default values). Also worth noting is the way the
11908 event mask of the widget is created. We call
11909 <literal>gtk_widget_get_events()</literal> to retrieve the event mask that the user
11910 has specified for this widget (with <literal>gtk_widget_set_events()</literal>), and
11911 add the events that we are interested in ourselves.</para>
11912
11913 <para>After creating the window, we set its style and background, and put a
11914 pointer to the widget in the user data field of the GdkWindow. This
11915 last step allows GTK to dispatch events for this window to the correct
11916 widget.</para>
11917
11918 <programlisting role="C">
11919 static void
11920 gtk_dial_realize (GtkWidget *widget)
11921 {
11922   GtkDial *dial;
11923   GdkWindowAttr attributes;
11924   gint attributes_mask;
11925
11926   g_return_if_fail (widget != NULL);
11927   g_return_if_fail (GTK_IS_DIAL (widget));
11928
11929   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
11930   dial = GTK_DIAL (widget);
11931
11932   attributes.x = widget->allocation.x;
11933   attributes.y = widget->allocation.y;
11934   attributes.width = widget->allocation.width;
11935   attributes.height = widget->allocation.height;
11936   attributes.wclass = GDK_INPUT_OUTPUT;
11937   attributes.window_type = GDK_WINDOW_CHILD;
11938   attributes.event_mask = gtk_widget_get_events (widget) | 
11939     GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | 
11940     GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
11941     GDK_POINTER_MOTION_HINT_MASK;
11942   attributes.visual = gtk_widget_get_visual (widget);
11943   attributes.colormap = gtk_widget_get_colormap (widget);
11944
11945   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
11946   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &amp;attributes, attributes_mask);
11947
11948   widget->style = gtk_style_attach (widget->style, widget->window);
11949
11950   gdk_window_set_user_data (widget->window, widget);
11951
11952   gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
11953 }
11954 </programlisting>
11955
11956 </sect2>
11957
11958 <!-- ----------------------------------------------------------------- -->
11959 <sect2>
11960 <title>Size negotiation</title>
11961
11962 <para>Before the first time that the window containing a widget is
11963 displayed, and whenever the layout of the window changes, GTK asks
11964 each child widget for its desired size. This request is handled by the
11965 function <literal>gtk_dial_size_request()</literal>. Since our widget isn't a
11966 container widget, and has no real constraints on its size, we just
11967 return a reasonable default value.</para>
11968
11969 <programlisting role="C">
11970 static void 
11971 gtk_dial_size_request (GtkWidget      *widget,
11972                        GtkRequisition *requisition)
11973 {
11974   requisition->width = DIAL_DEFAULT_SIZE;
11975   requisition->height = DIAL_DEFAULT_SIZE;
11976 }
11977 </programlisting>
11978
11979 <para>After all the widgets have requested an ideal size, the layout of the
11980 window is computed and each child widget is notified of its actual
11981 size. Usually, this will be at least as large as the requested size,
11982 but if for instance the user has resized the window, it may
11983 occasionally be smaller than the requested size. The size notification
11984 is handled by the function <literal>gtk_dial_size_allocate()</literal>. Notice that
11985 as well as computing the sizes of some component pieces for future
11986 use, this routine also does the grunt work of moving the widget's X
11987 window into the new position and size.</para>
11988
11989 <programlisting role="C">
11990 static void
11991 gtk_dial_size_allocate (GtkWidget     *widget,
11992                         GtkAllocation *allocation)
11993 {
11994   GtkDial *dial;
11995
11996   g_return_if_fail (widget != NULL);
11997   g_return_if_fail (GTK_IS_DIAL (widget));
11998   g_return_if_fail (allocation != NULL);
11999
12000   widget->allocation = *allocation;
12001   if (GTK_WIDGET_REALIZED (widget))
12002     {
12003       dial = GTK_DIAL (widget);
12004
12005       gdk_window_move_resize (widget->window,
12006                               allocation->x, allocation->y,
12007                               allocation->width, allocation->height);
12008
12009       dial->radius = MAX(allocation->width,allocation->height) * 0.45;
12010       dial->pointer_width = dial->radius / 5;
12011     }
12012 }
12013 </programlisting>
12014
12015 </sect2>
12016
12017 <!-- ----------------------------------------------------------------- -->
12018 <sect2>
12019 <title><literal>gtk_dial_expose()</literal></title>
12020
12021 <para>As mentioned above, all the drawing of this widget is done in the
12022 handler for expose events. There's not much to remark on here except
12023 the use of the function <literal>gtk_draw_polygon</literal> to draw the pointer with
12024 three dimensional shading according to the colors stored in the
12025 widget's style.</para>
12026
12027 <programlisting role="C">
12028 static gboolean
12029 gtk_dial_expose( GtkWidget      *widget,
12030                  GdkEventExpose *event )
12031 {
12032   GtkDial *dial;
12033   GdkPoint points[3];
12034   gdouble s,c;
12035   gdouble theta;
12036   gint xc, yc;
12037   gint tick_length;
12038   gint i;
12039
12040   g_return_val_if_fail (widget != NULL, FALSE);
12041   g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
12042   g_return_val_if_fail (event != NULL, FALSE);
12043
12044   if (event->count > 0)
12045     return FALSE;
12046   
12047   dial = GTK_DIAL (widget);
12048
12049   gdk_window_clear_area (widget->window,
12050                          0, 0,
12051                          widget->allocation.width,
12052                          widget->allocation.height);
12053
12054   xc = widget->allocation.width/2;
12055   yc = widget->allocation.height/2;
12056
12057   /* Draw ticks */
12058
12059   for (i=0; i<25; i++)
12060     {
12061       theta = (i*M_PI/18. - M_PI/6.);
12062       s = sin(theta);
12063       c = cos(theta);
12064
12065       tick_length = (i%6 == 0) ? dial->pointer_width : dial->pointer_width/2;
12066       
12067       gdk_draw_line (widget->window,
12068                      widget->style->fg_gc[widget->state],
12069                      xc + c*(dial->radius - tick_length),
12070                      yc - s*(dial->radius - tick_length),
12071                      xc + c*dial->radius,
12072                      yc - s*dial->radius);
12073     }
12074
12075   /* Draw pointer */
12076
12077   s = sin(dial->angle);
12078   c = cos(dial->angle);
12079
12080
12081   points[0].x = xc + s*dial->pointer_width/2;
12082   points[0].y = yc + c*dial->pointer_width/2;
12083   points[1].x = xc + c*dial->radius;
12084   points[1].y = yc - s*dial->radius;
12085   points[2].x = xc - s*dial->pointer_width/2;
12086   points[2].y = yc - c*dial->pointer_width/2;
12087
12088   gtk_draw_polygon (widget->style,
12089                     widget->window,
12090                     GTK_STATE_NORMAL,
12091                     GTK_SHADOW_OUT,
12092                     points, 3,
12093                     TRUE);
12094   
12095   return FALSE;
12096 }
12097 </programlisting>
12098
12099 </sect2>
12100
12101 <!-- ----------------------------------------------------------------- -->
12102 <sect2>
12103 <title>Event handling</title>
12104
12105 <para>The rest of the widget's code handles various types of events, and
12106 isn't too different from what would be found in many GTK
12107 applications. Two types of events can occur - either the user can
12108 click on the widget with the mouse and drag to move the pointer, or
12109 the value of the Adjustment object can change due to some external
12110 circumstance.</para>
12111
12112 <para>When the user clicks on the widget, we check to see if the click was
12113 appropriately near the pointer, and if so, store the button that the
12114 user clicked with in the <literal>button</literal> field of the widget
12115 structure, and grab all mouse events with a call to
12116 <literal>gtk_grab_add()</literal>. Subsequent motion of the mouse causes the
12117 value of the control to be recomputed (by the function
12118 <literal>gtk_dial_update_mouse</literal>). Depending on the policy that has been
12119 set, "value_changed" events are either generated instantly
12120 (<literal>GTK_UPDATE_CONTINUOUS</literal>), after a delay in a timer added with
12121 <literal>g_timeout_add()</literal> (<literal>GTK_UPDATE_DELAYED</literal>), or only when the
12122 button is released (<literal>GTK_UPDATE_DISCONTINUOUS</literal>).</para>
12123
12124 <programlisting role="C">
12125 static gboolean
12126 gtk_dial_button_press( GtkWidget      *widget,
12127                        GdkEventButton *event )
12128 {
12129   GtkDial *dial;
12130   gint dx, dy;
12131   double s, c;
12132   double d_parallel;
12133   double d_perpendicular;
12134
12135   g_return_val_if_fail (widget != NULL, FALSE);
12136   g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
12137   g_return_val_if_fail (event != NULL, FALSE);
12138
12139   dial = GTK_DIAL (widget);
12140
12141   /* Determine if button press was within pointer region - we 
12142      do this by computing the parallel and perpendicular distance of
12143      the point where the mouse was pressed from the line passing through
12144      the pointer */
12145   
12146   dx = event->x - widget->allocation.width / 2;
12147   dy = widget->allocation.height / 2 - event->y;
12148   
12149   s = sin(dial->angle);
12150   c = cos(dial->angle);
12151   
12152   d_parallel = s*dy + c*dx;
12153   d_perpendicular = fabs(s*dx - c*dy);
12154   
12155   if (!dial->button &&
12156       (d_perpendicular < dial->pointer_width/2) &&
12157       (d_parallel > - dial->pointer_width))
12158     {
12159       gtk_grab_add (widget);
12160
12161       dial->button = event->button;
12162
12163       gtk_dial_update_mouse (dial, event->x, event->y);
12164     }
12165
12166   return FALSE;
12167 }
12168
12169 static gboolean
12170 gtk_dial_button_release( GtkWidget      *widget,
12171                          GdkEventButton *event )
12172 {
12173   GtkDial *dial;
12174
12175   g_return_val_if_fail (widget != NULL, FALSE);
12176   g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
12177   g_return_val_if_fail (event != NULL, FALSE);
12178
12179   dial = GTK_DIAL (widget);
12180
12181   if (dial->button == event->button)
12182     {
12183       gtk_grab_remove (widget);
12184
12185       dial->button = 0;
12186
12187       if (dial->policy == GTK_UPDATE_DELAYED)
12188         g_source_remove (dial->timer);
12189       
12190       if ((dial->policy != GTK_UPDATE_CONTINUOUS) &&
12191           (dial->old_value != dial->adjustment->value))
12192         gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
12193     }
12194
12195   return FALSE;
12196 }
12197
12198 static gboolean
12199 gtk_dial_motion_notify( GtkWidget      *widget,
12200                         GdkEventMotion *event )
12201 {
12202   GtkDial *dial;
12203   GdkModifierType mods;
12204   gint x, y, mask;
12205
12206   g_return_val_if_fail (widget != NULL, FALSE);
12207   g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
12208   g_return_val_if_fail (event != NULL, FALSE);
12209
12210   dial = GTK_DIAL (widget);
12211
12212   if (dial->button != 0)
12213     {
12214       x = event->x;
12215       y = event->y;
12216
12217       if (event->is_hint || (event->window != widget->window))
12218         gdk_window_get_pointer (widget->window, &amp;x, &amp;y, &amp;mods);
12219
12220       switch (dial->button)
12221         {
12222         case 1:
12223           mask = GDK_BUTTON1_MASK;
12224           break;
12225         case 2:
12226           mask = GDK_BUTTON2_MASK;
12227           break;
12228         case 3:
12229           mask = GDK_BUTTON3_MASK;
12230           break;
12231         default:
12232           mask = 0;
12233           break;
12234         }
12235
12236       if (mods & mask)
12237         gtk_dial_update_mouse (dial, x,y);
12238     }
12239
12240   return FALSE;
12241 }
12242
12243 static gboolean
12244 gtk_dial_timer( GtkDial *dial )
12245 {
12246   g_return_val_if_fail (dial != NULL, FALSE);
12247   g_return_val_if_fail (GTK_IS_DIAL (dial), FALSE);
12248
12249   if (dial->policy == GTK_UPDATE_DELAYED)
12250     gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
12251
12252   return FALSE;
12253 }
12254
12255 static void
12256 gtk_dial_update_mouse (GtkDial *dial, gint x, gint y)
12257 {
12258   gint xc, yc;
12259   gfloat old_value;
12260
12261   g_return_if_fail (dial != NULL);
12262   g_return_if_fail (GTK_IS_DIAL (dial));
12263
12264   xc = GTK_WIDGET(dial)->allocation.width / 2;
12265   yc = GTK_WIDGET(dial)->allocation.height / 2;
12266
12267   old_value = dial->adjustment->value;
12268   dial->angle = atan2(yc-y, x-xc);
12269
12270   if (dial->angle < -M_PI/2.)
12271     dial->angle += 2*M_PI;
12272
12273   if (dial->angle < -M_PI/6)
12274     dial->angle = -M_PI/6;
12275
12276   if (dial->angle > 7.*M_PI/6.)
12277     dial->angle = 7.*M_PI/6.;
12278
12279   dial->adjustment->value = dial->adjustment->lower + (7.*M_PI/6 - dial->angle) *
12280     (dial->adjustment->upper - dial->adjustment->lower) / (4.*M_PI/3.);
12281
12282   if (dial->adjustment->value != old_value)
12283     {
12284       if (dial->policy == GTK_UPDATE_CONTINUOUS)
12285         {
12286           gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
12287         }
12288       else
12289         {
12290           gtk_widget_draw (GTK_WIDGET(dial), NULL);
12291
12292           if (dial->policy == GTK_UPDATE_DELAYED)
12293             {
12294               if (dial->timer)
12295                 g_source_remove (dial->timer);
12296
12297               dial->timer = g_timeout_add (SCROLL_DELAY_LENGTH,
12298                                            (GtkFunction) gtk_dial_timer,
12299                                            (gpointer) dial);
12300             }
12301         }
12302     }
12303 }
12304 </programlisting>
12305
12306 <para>Changes to the Adjustment by external means are communicated to our
12307 widget by the "changed" and "value_changed" signals. The handlers
12308 for these functions call <literal>gtk_dial_update()</literal> to validate the
12309 arguments, compute the new pointer angle, and redraw the widget (by
12310 calling <literal>gtk_widget_draw()</literal>).</para>
12311
12312 <programlisting role="C">
12313 static void
12314 gtk_dial_update (GtkDial *dial)
12315 {
12316   gfloat new_value;
12317   
12318   g_return_if_fail (dial != NULL);
12319   g_return_if_fail (GTK_IS_DIAL (dial));
12320
12321   new_value = dial->adjustment->value;
12322   
12323   if (new_value < dial->adjustment->lower)
12324     new_value = dial->adjustment->lower;
12325
12326   if (new_value > dial->adjustment->upper)
12327     new_value = dial->adjustment->upper;
12328
12329   if (new_value != dial->adjustment->value)
12330     {
12331       dial->adjustment->value = new_value;
12332       gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
12333     }
12334
12335   dial->angle = 7.*M_PI/6. - (new_value - dial->adjustment->lower) * 4.*M_PI/3. /
12336     (dial->adjustment->upper - dial->adjustment->lower);
12337
12338   gtk_widget_draw (GTK_WIDGET(dial), NULL);
12339 }
12340
12341 static void
12342 gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
12343                               gpointer       data)
12344 {
12345   GtkDial *dial;
12346
12347   g_return_if_fail (adjustment != NULL);
12348   g_return_if_fail (data != NULL);
12349
12350   dial = GTK_DIAL (data);
12351
12352   if ((dial->old_value != adjustment->value) ||
12353       (dial->old_lower != adjustment->lower) ||
12354       (dial->old_upper != adjustment->upper))
12355     {
12356       gtk_dial_update (dial);
12357
12358       dial->old_value = adjustment->value;
12359       dial->old_lower = adjustment->lower;
12360       dial->old_upper = adjustment->upper;
12361     }
12362 }
12363
12364 static void
12365 gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
12366                                     gpointer       data)
12367 {
12368   GtkDial *dial;
12369
12370   g_return_if_fail (adjustment != NULL);
12371   g_return_if_fail (data != NULL);
12372
12373   dial = GTK_DIAL (data);
12374
12375   if (dial->old_value != adjustment->value)
12376     {
12377       gtk_dial_update (dial);
12378
12379       dial->old_value = adjustment->value;
12380     }
12381 }
12382 </programlisting>
12383
12384 </sect2>
12385
12386 <!-- ----------------------------------------------------------------- -->
12387 <sect2>
12388 <title>Possible Enhancements</title>
12389
12390 <para>The Dial widget as we've described it so far runs about 670 lines of
12391 code. Although that might sound like a fair bit, we've really
12392 accomplished quite a bit with that much code, especially since much of
12393 that length is headers and boilerplate. However, there are quite a few
12394 more enhancements that could be made to this widget:</para>
12395
12396 <itemizedlist>
12397 <listitem><simpara> If you try this widget out, you'll find that there is some
12398 flashing as the pointer is dragged around. This is because the entire
12399 widget is erased every time the pointer is moved before being
12400 redrawn. Often, the best way to handle this problem is to draw to an
12401 offscreen pixmap, then copy the final results onto the screen in one
12402 step. (The ProgressBar widget draws itself in this fashion.)</simpara>
12403 </listitem>
12404
12405 <listitem><simpara> The user should be able to use the up and down arrow keys to
12406 increase and decrease the value.</simpara>
12407 </listitem>
12408
12409 <listitem><simpara> It would be nice if the widget had buttons to increase and
12410 decrease the value in small or large steps. Although it would be
12411 possible to use embedded Button widgets for this, we would also like
12412 the buttons to auto-repeat when held down, as the arrows on a
12413 scrollbar do. Most of the code to implement this type of behavior can
12414 be found in the Range widget.</simpara>
12415 </listitem>
12416
12417 <listitem><simpara> The Dial widget could be made into a container widget with a
12418 single child widget positioned at the bottom between the buttons
12419 mentioned above. The user could then add their choice of a label or
12420 entry widget to display the current value of the dial.</simpara>
12421 </listitem>
12422 </itemizedlist>
12423
12424 </sect2>
12425 </sect1>
12426
12427 <!-- ----------------------------------------------------------------- -->
12428 <sect1 id="sec-LearningMore">
12429 <title>Learning More</title>
12430
12431 <para>Only a small part of the many details involved in creating widgets
12432 could be described above. If you want to write your own widgets, the
12433 best source of examples is the GTK source itself. Ask yourself some
12434 questions about the widget you want to write: IS it a Container
12435 widget? Does it have its own window? Is it a modification of an
12436 existing widget? Then find a similar widget, and start making changes.
12437 Good luck!</para>
12438
12439 </sect1>
12440 </chapter>
12441
12442 <!-- ***************************************************************** -->
12443 <chapter id="ch-Scribble">
12444 <title>Scribble, A Simple Example Drawing Program</title>
12445
12446 <!-- ----------------------------------------------------------------- -->
12447 <sect1 id="sec-ScribbleOverview">
12448 <title>Overview</title>
12449
12450 <para>In this section, we will build a simple drawing program. In the
12451 process, we will examine how to handle mouse events, how to draw in a
12452 window, and how to do drawing better by using a backing pixmap. After
12453 creating the simple drawing program, we will extend it by adding
12454 support for XInput devices, such as drawing tablets. GTK provides
12455 support routines which makes getting extended information, such as
12456 pressure and tilt, from such devices quite easy.</para>
12457
12458 <para>
12459 <inlinemediaobject>
12460 <imageobject>
12461 <imagedata fileref="images/scribble.png" format="png">
12462 </imageobject>
12463 </inlinemediaobject>
12464 </para>
12465
12466 </sect1>
12467
12468 <!-- ----------------------------------------------------------------- -->
12469 <sect1 id="sec-EventHandling">
12470 <title>Event Handling</title>
12471
12472 <para>The GTK signals we have already discussed are for high-level actions,
12473 such as a menu item being selected. However, sometimes it is useful to
12474 learn about lower-level occurrences, such as the mouse being moved, or
12475 a key being pressed. There are also GTK signals corresponding to these
12476 low-level <emphasis>events</emphasis>. The handlers for these signals have an
12477 extra parameter which is a pointer to a structure containing
12478 information about the event. For instance, motion event handlers are
12479 passed a pointer to a GdkEventMotion structure which looks (in part)
12480 like:</para>
12481
12482 <programlisting role="C">
12483 struct _GdkEventMotion
12484 {
12485   GdkEventType type;
12486   GdkWindow *window;
12487   guint32 time;
12488   gdouble x;
12489   gdouble y;
12490   ...
12491   guint state;
12492   ...
12493 };
12494 </programlisting>
12495
12496 <para><literal>type</literal> will be set to the event type, in this case
12497 <literal>GDK_MOTION_NOTIFY</literal>, window is the window in which the event
12498 occurred. <literal>x</literal> and <literal>y</literal> give the coordinates of the event.
12499 <literal>state</literal> specifies the modifier state when the event
12500 occurred (that is, it specifies which modifier keys and mouse buttons
12501 were pressed). It is the bitwise OR of some of the following:</para>
12502
12503 <programlisting role="C">
12504 GDK_SHIFT_MASK  
12505 GDK_LOCK_MASK   
12506 GDK_CONTROL_MASK
12507 GDK_MOD1_MASK   
12508 GDK_MOD2_MASK   
12509 GDK_MOD3_MASK   
12510 GDK_MOD4_MASK   
12511 GDK_MOD5_MASK   
12512 GDK_BUTTON1_MASK
12513 GDK_BUTTON2_MASK
12514 GDK_BUTTON3_MASK
12515 GDK_BUTTON4_MASK
12516 GDK_BUTTON5_MASK
12517 </programlisting>
12518
12519 <para>As for other signals, to determine what happens when an event occurs
12520 we call <literal>gtk_signal_connect()</literal>. But we also need let GTK
12521 know which events we want to be notified about. To do this, we call
12522 the function:</para>
12523
12524 <programlisting role="C">
12525 void gtk_widget_set_events (GtkWidget *widget,
12526                             gint      events);
12527 </programlisting>
12528
12529 <para>The second field specifies the events we are interested in. It
12530 is the bitwise OR of constants that specify different types
12531 of events. For future reference the event types are:</para>
12532
12533 <programlisting role="C">
12534 GDK_EXPOSURE_MASK
12535 GDK_POINTER_MOTION_MASK
12536 GDK_POINTER_MOTION_HINT_MASK
12537 GDK_BUTTON_MOTION_MASK     
12538 GDK_BUTTON1_MOTION_MASK    
12539 GDK_BUTTON2_MOTION_MASK    
12540 GDK_BUTTON3_MOTION_MASK    
12541 GDK_BUTTON_PRESS_MASK      
12542 GDK_BUTTON_RELEASE_MASK    
12543 GDK_KEY_PRESS_MASK         
12544 GDK_KEY_RELEASE_MASK       
12545 GDK_ENTER_NOTIFY_MASK      
12546 GDK_LEAVE_NOTIFY_MASK      
12547 GDK_FOCUS_CHANGE_MASK      
12548 GDK_STRUCTURE_MASK         
12549 GDK_PROPERTY_CHANGE_MASK   
12550 GDK_PROXIMITY_IN_MASK      
12551 GDK_PROXIMITY_OUT_MASK     
12552 </programlisting>
12553
12554 <para>There are a few subtle points that have to be observed when calling
12555 <literal>gtk_widget_set_events()</literal>. First, it must be called before the X window
12556 for a GTK widget is created. In practical terms, this means you
12557 should call it immediately after creating the widget. Second, the
12558 widget must have an associated X window. For efficiency, many widget
12559 types do not have their own window, but draw in their parent's window.
12560 These widgets are:</para>
12561
12562 <programlisting role="C">
12563 GtkAlignment
12564 GtkArrow
12565 GtkBin
12566 GtkBox
12567 GtkImage
12568 GtkItem
12569 GtkLabel
12570 GtkPixmap
12571 GtkScrolledWindow
12572 GtkSeparator
12573 GtkTable
12574 GtkAspectFrame
12575 GtkFrame
12576 GtkVBox
12577 GtkHBox
12578 GtkVSeparator
12579 GtkHSeparator
12580 </programlisting>
12581
12582 <para>To capture events for these widgets, you need to use an EventBox
12583 widget. See the section on the <link linkend="sec-EventBox">EventBox</link> widget for details.</para>
12584
12585 <para>For our drawing program, we want to know when the mouse button is
12586 pressed and when the mouse is moved, so we specify
12587 <literal>GDK_POINTER_MOTION_MASK</literal> and <literal>GDK_BUTTON_PRESS_MASK</literal>. We also
12588 want to know when we need to redraw our window, so we specify
12589 <literal>GDK_EXPOSURE_MASK</literal>. Although we want to be notified via a
12590 Configure event when our window size changes, we don't have to specify
12591 the corresponding <literal>GDK_STRUCTURE_MASK</literal> flag, because it is
12592 automatically specified for all windows.</para>
12593
12594 <para>It turns out, however, that there is a problem with just specifying
12595 <literal>GDK_POINTER_MOTION_MASK</literal>. This will cause the server to add a new
12596 motion event to the event queue every time the user moves the mouse.
12597 Imagine that it takes us 0.1 seconds to handle a motion event, but the
12598 X server queues a new motion event every 0.05 seconds. We will soon
12599 get way behind the users drawing. If the user draws for 5 seconds,
12600 it will take us another 5 seconds to catch up after they release 
12601 the mouse button! What we would like is to only get one motion
12602 event for each event we process. The way to do this is to 
12603 specify <literal>GDK_POINTER_MOTION_HINT_MASK</literal>. </para>
12604
12605 <para>When we specify <literal>GDK_POINTER_MOTION_HINT_MASK</literal>, the server sends
12606 us a motion event the first time the pointer moves after entering
12607 our window, or after a button press or release event. Subsequent 
12608 motion events will be suppressed until we explicitly ask for
12609 the position of the pointer using the function:</para>
12610
12611 <programlisting role="C">
12612 GdkWindow*    gdk_window_get_pointer     (GdkWindow       *window,
12613                                           gint            *x,
12614                                           gint            *y,
12615                                           GdkModifierType *mask);
12616 </programlisting>
12617
12618 <para>(There is another function, <literal>gtk_widget_get_pointer()</literal> which
12619 has a simpler interface, but turns out not to be very useful, since
12620 it only retrieves the position of the mouse, not whether the buttons
12621 are pressed.)</para>
12622
12623 <para>The code to set the events for our window then looks like:</para>
12624
12625 <programlisting role="C">
12626   gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
12627                       (GtkSignalFunc) expose_event, NULL);
12628   gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event",
12629                       (GtkSignalFunc) configure_event, NULL);
12630   gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event",
12631                       (GtkSignalFunc) motion_notify_event, NULL);
12632   gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event",
12633                       (GtkSignalFunc) button_press_event, NULL);
12634
12635   gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
12636                          | GDK_LEAVE_NOTIFY_MASK
12637                          | GDK_BUTTON_PRESS_MASK
12638                          | GDK_POINTER_MOTION_MASK
12639                          | GDK_POINTER_MOTION_HINT_MASK);
12640 </programlisting>
12641
12642 <para>We'll save the "expose_event" and "configure_event" handlers for
12643 later. The "motion_notify_event" and "button_press_event" handlers
12644 are pretty simple:</para>
12645
12646 <programlisting role="C">
12647 static gboolean
12648 button_press_event( GtkWidget *widget, GdkEventButton *event )
12649 {
12650   if (event->button == 1 &amp;&amp; pixmap != NULL)
12651       draw_brush (widget, event->x, event->y);
12652
12653   return TRUE;
12654 }
12655
12656 static gboolean
12657 motion_notify_event( GtkWidget *widget, GdkEventMotion *event )
12658 {
12659   int x, y;
12660   GdkModifierType state;
12661
12662   if (event->is_hint)
12663     gdk_window_get_pointer (event->window, &amp;x, &amp;y, &amp;state);
12664   else
12665     {
12666       x = event->x;
12667       y = event->y;
12668       state = event->state;
12669     }
12670     
12671   if (state &amp; GDK_BUTTON1_MASK &amp;&amp; pixmap != NULL)
12672     draw_brush (widget, x, y);
12673   
12674   return TRUE;
12675 }
12676 </programlisting>
12677
12678 </sect1>
12679
12680 <!-- ----------------------------------------------------------------- -->
12681 <sect1 id="sec-TheDrawingAreaWidget">
12682 <title>The DrawingArea Widget, And Drawing</title>
12683
12684 <para>We now turn to the process of drawing on the screen. The 
12685 widget we use for this is the DrawingArea widget. A drawing area
12686 widget is essentially an X window and nothing more. It is a blank
12687 canvas in which we can draw whatever we like. A drawing area
12688 is created using the call:</para>
12689
12690 <programlisting role="C">
12691 GtkWidget* gtk_drawing_area_new        (void);
12692 </programlisting>
12693
12694 <para>A default size for the widget can be specified by calling:</para>
12695
12696 <programlisting role="C">
12697 void       gtk_drawing_area_size       (GtkDrawingArea      *darea,
12698                                         gint                 width,
12699                                         gint                 height);
12700 </programlisting>
12701
12702 <para>This default size can be overridden, as is true for all widgets,
12703 by calling <literal>gtk_widget_set_size_request()</literal>, and that, in turn, can
12704 be overridden if the user manually resizes the the window containing
12705 the drawing area.</para>
12706
12707 <para>It should be noted that when we create a DrawingArea widget, we are
12708 <emphasis>completely</emphasis> responsible for drawing the contents. If our
12709 window is obscured then uncovered, we get an exposure event and must
12710 redraw what was previously hidden.</para>
12711
12712 <para>Having to remember everything that was drawn on the screen so we
12713 can properly redraw it can, to say the least, be a nuisance. In
12714 addition, it can be visually distracting if portions of the
12715 window are cleared, then redrawn step by step. The solution to
12716 this problem is to use an offscreen <emphasis>backing pixmap</emphasis>.
12717 Instead of drawing directly to the screen, we draw to an image
12718 stored in server memory but not displayed, then when the image
12719 changes or new portions of the image are displayed, we copy the
12720 relevant portions onto the screen.</para>
12721
12722 <para>To create an offscreen pixmap, we call the function:</para>
12723
12724 <programlisting role="C">
12725 GdkPixmap* gdk_pixmap_new               (GdkWindow  *window,
12726                                          gint        width,
12727                                          gint        height,
12728                                          gint        depth);
12729 </programlisting>
12730
12731 <para>The <literal>window</literal> parameter specifies a GDK window that this pixmap
12732 takes some of its properties from. <literal>width</literal> and <literal>height</literal>
12733 specify the size of the pixmap. <literal>depth</literal> specifies the <emphasis>color
12734 depth</emphasis>, that is the number of bits per pixel, for the new window.
12735 If the depth is specified as <literal>-1</literal>, it will match the depth
12736 of <literal>window</literal>.</para>
12737
12738 <para>We create the pixmap in our "configure_event" handler. This event
12739 is generated whenever the window changes size, including when it
12740 is originally created.</para>
12741
12742 <programlisting role="C">
12743 /* Backing pixmap for drawing area */
12744 static GdkPixmap *pixmap = NULL;
12745
12746 /* Create a new backing pixmap of the appropriate size */
12747 static gboolean
12748 configure_event( GtkWidget *widget, GdkEventConfigure *event )
12749 {
12750   if (pixmap)
12751     g_object_unref(pixmap);
12752
12753   pixmap = gdk_pixmap_new(widget->window,
12754                           widget->allocation.width,
12755                           widget->allocation.height,
12756                           -1);
12757   gdk_draw_rectangle (pixmap,
12758                       widget->style->white_gc,
12759                       TRUE,
12760                       0, 0,
12761                       widget->allocation.width,
12762                       widget->allocation.height);
12763
12764   return TRUE;
12765 }
12766 </programlisting>
12767
12768 <para>The call to <literal>gdk_draw_rectangle()</literal> clears the pixmap
12769 initially to white. We'll say more about that in a moment.</para>
12770
12771 <para>Our exposure event handler then simply copies the relevant portion
12772 of the pixmap onto the screen (we determine the area we need
12773 to redraw by using the event->area field of the exposure event):</para>
12774
12775 <programlisting role="C">
12776 /* Redraw the screen from the backing pixmap */
12777 static gboolean
12778 expose_event( GtkWidget *widget, GdkEventExpose *event )
12779 {
12780   gdk_draw_drawable(widget->window,
12781                     widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
12782                     pixmap,
12783                     event->area.x, event->area.y,
12784                     event->area.x, event->area.y,
12785                     event->area.width, event->area.height);
12786
12787   return FALSE;
12788 }
12789 </programlisting>
12790
12791 <para>We've now seen how to keep the screen up to date with our pixmap, but
12792 how do we actually draw interesting stuff on our pixmap?  There are a
12793 large number of calls in GTK's GDK library for drawing on
12794 <emphasis>drawables</emphasis>. A drawable is simply something that can be drawn
12795 upon. It can be a window, a pixmap, or a bitmap (a black and white
12796 image).  We've already seen two such calls above,
12797 <literal>gdk_draw_rectangle()</literal> and <literal>gdk_draw_drawable()</literal>. The
12798 complete list is:</para>
12799
12800 <programlisting role="C">
12801 gdk_draw_point ()
12802 gdk_draw_line ()
12803 gdk_draw_rectangle ()
12804 gdk_draw_arc ()
12805 gdk_draw_polygon ()
12806 gdk_draw_pixmap ()
12807 gdk_draw_bitmap ()
12808 gdk_draw_image ()
12809 gdk_draw_points ()
12810 gdk_draw_segments ()
12811 gdk_draw_lines ()
12812 gdk_draw_pixbuf ()
12813 gdk_draw_glyphs ()
12814 gdk_draw_layout_line ()
12815 gdk_draw_layout ()
12816 gdk_draw_layout_line_with_colors ()
12817 gdk_draw_layout_with_colors ()
12818 gdk_draw_glyphs_transformed ()
12819 gdk_draw_glyphs_trapezoids ()
12820 </programlisting>
12821
12822 <para>See the reference documentation or the header file
12823 <literal>&lt;gdk/gdkdrawable.h&gt;</literal> for further details on these functions.
12824 These functions all share the same first two arguments. The first
12825 argument is the drawable to draw upon, the second argument is a
12826 <emphasis>graphics context</emphasis> (GC).</para>
12827
12828 <para>A graphics context encapsulates information about things such as
12829 foreground and background color and line width. GDK has a full set of
12830 functions for creating and modifying graphics contexts, but to keep
12831 things simple we'll just use predefined graphics contexts. Each widget
12832 has an associated style. (Which can be modified in a gtkrc file, see
12833 the section GTK's rc file.) This, among other things, stores a number
12834 of graphics contexts. Some examples of accessing these graphics
12835 contexts are:</para>
12836
12837 <programlisting role="C">
12838 widget->style->white_gc
12839 widget->style->black_gc
12840 widget->style->fg_gc[GTK_STATE_NORMAL]
12841 widget->style->bg_gc[GTK_WIDGET_STATE(widget)]
12842 </programlisting>
12843
12844 <para>The fields <literal>fg_gc</literal>, <literal>bg_gc</literal>, <literal>dark_gc</literal>, and
12845 <literal>light_gc</literal> are indexed by a parameter of type
12846 <literal>GtkStateType</literal> which can take on the values:</para>
12847
12848 <programlisting role="C">
12849 GTK_STATE_NORMAL,
12850 GTK_STATE_ACTIVE,
12851 GTK_STATE_PRELIGHT,
12852 GTK_STATE_SELECTED,
12853 GTK_STATE_INSENSITIVE
12854 </programlisting>
12855
12856 <para>For instance, for <literal>GTK_STATE_SELECTED</literal> the default foreground
12857 color is white and the default background color, dark blue.</para>
12858
12859 <para>Our function <literal>draw_brush()</literal>, which does the actual drawing
12860 on the screen, is then:</para>
12861
12862 <programlisting role="C">
12863 /* Draw a rectangle on the screen */
12864 static void
12865 draw_brush (GtkWidget *widget, gdouble x, gdouble y)
12866 {
12867   GdkRectangle update_rect;
12868
12869   update_rect.x = x - 5;
12870   update_rect.y = y - 5;
12871   update_rect.width = 10;
12872   update_rect.height = 10;
12873   gdk_draw_rectangle (pixmap,
12874                       widget->style->black_gc,
12875                       TRUE,
12876                       update_rect.x, update_rect.y,
12877                       update_rect.width, update_rect.height);
12878   gtk_widget_queue_draw_area (widget,                 
12879                               update_rect.x, update_rect.y,
12880                               update_rect.width, update_rect.height);
12881 }
12882 </programlisting>
12883
12884 <para>After we draw the rectangle representing the brush onto the pixmap,
12885 we call the function:</para>
12886
12887 <programlisting role="C">
12888 void       gtk_widget_queue_draw_area (GtkWidget           *widget,
12889                                        gint                 x,
12890                                        gint                 y,
12891                                        gint                 width,
12892                                        gint                 height)
12893 </programlisting>
12894
12895 <para>which notifies X that the area given by the <literal>x</literal>, 
12896 <literal>y</literal>, <literal>width</literal> and <literal>height</literal> parameters
12897 needs to be updated. X will eventually generate an expose event
12898 (possibly combining the areas passed in several calls to
12899 <literal>gtk_widget_queue_draw_area()</literal>) which will cause our expose event handler
12900 to copy the relevant portions to the screen.</para>
12901
12902 <para>We have now covered the entire drawing program except for a few
12903 mundane details like creating the main window.</para>
12904
12905 </sect1>
12906
12907 <!-- ----------------------------------------------------------------- -->
12908 <sect1 id="sec-AddingXInputSupport">
12909 <title>Adding XInput support</title>
12910
12911 <para>It is now possible to buy quite inexpensive input devices such 
12912 as drawing tablets, which allow drawing with a much greater
12913 ease of artistic expression than does a mouse. The simplest way
12914 to use such devices is simply as a replacement for the mouse,
12915 but that misses out many of the advantages of these devices,
12916 such as:</para>
12917
12918 <itemizedlist>
12919 <listitem><simpara> Pressure sensitivity</simpara>
12920 </listitem>
12921 <listitem><simpara> Tilt reporting</simpara>
12922 </listitem>
12923 <listitem><simpara> Sub-pixel positioning</simpara>
12924 </listitem>
12925 <listitem><simpara> Multiple inputs (for example, a stylus with a point and eraser)</simpara>
12926 </listitem>
12927 </itemizedlist>
12928
12929 <para>For information about the XInput extension, see the <ulink
12930 url="http://www.gtk.org/~otaylor/xinput/howto/index.html">XInput HOWTO</ulink>.</para>
12931
12932 <para>If we examine the full definition of, for example, the GdkEventMotion
12933 structure, we see that it has fields to support extended device
12934 information.</para>
12935
12936 <programlisting role="C">
12937 struct _GdkEventMotion
12938 {
12939   GdkEventType type;
12940   GdkWindow *window;
12941   guint32 time;
12942   gdouble x;
12943   gdouble y;
12944   gdouble pressure;
12945   gdouble xtilt;
12946   gdouble ytilt;
12947   guint state;
12948   gint16 is_hint;
12949   GdkInputSource source;
12950   guint32 deviceid;
12951 };
12952 </programlisting>
12953
12954 <para><literal>pressure</literal> gives the pressure as a floating point number between
12955 0 and 1. <literal>xtilt</literal> and <literal>ytilt</literal> can take on values between 
12956 -1 and 1, corresponding to the degree of tilt in each direction.
12957 <literal>source</literal> and <literal>deviceid</literal> specify the device for which the
12958 event occurred in two different ways. <literal>source</literal> gives some simple
12959 information about the type of device. It can take the enumeration
12960 values:</para>
12961
12962 <programlisting role="C">
12963 GDK_SOURCE_MOUSE
12964 GDK_SOURCE_PEN
12965 GDK_SOURCE_ERASER
12966 GDK_SOURCE_CURSOR
12967 </programlisting>
12968
12969 <para><literal>deviceid</literal> specifies a unique numeric ID for the device. This can
12970 be used to find out further information about the device using the
12971 <literal>gdk_input_list_devices()</literal> call (see below). The special value
12972 <literal>GDK_CORE_POINTER</literal> is used for the core pointer device. (Usually
12973 the mouse.)</para>
12974
12975 <!-- ----------------------------------------------------------------- -->
12976 <sect2>
12977 <title>Enabling extended device information</title>
12978
12979 <para>To let GTK know about our interest in the extended device information,
12980 we merely have to add a single line to our program:</para>
12981
12982 <programlisting role="C">
12983 gtk_widget_set_extension_events (drawing_area, GDK_EXTENSION_EVENTS_CURSOR);
12984 </programlisting>
12985
12986 <para>By giving the value <literal>GDK_EXTENSION_EVENTS_CURSOR</literal> we say that
12987 we are interested in extension events, but only if we don't have
12988 to draw our own cursor. See the section <link
12989 linkend="sec-FurtherSophistications"> Further Sophistications </link> below
12990 for more information about drawing the cursor. We could also 
12991 give the values <literal>GDK_EXTENSION_EVENTS_ALL</literal> if we were willing 
12992 to draw our own cursor, or <literal>GDK_EXTENSION_EVENTS_NONE</literal> to revert
12993 back to the default condition.</para>
12994
12995 <para>This is not completely the end of the story however. By default,
12996 no extension devices are enabled. We need a mechanism to allow
12997 users to enable and configure their extension devices. GTK provides
12998 the InputDialog widget to automate this process. The following
12999 procedure manages an InputDialog widget. It creates the dialog if
13000 it isn't present, and raises it to the top otherwise.</para>
13001
13002 <programlisting role="C">
13003 void
13004 input_dialog_destroy (GtkWidget *w, gpointer data)
13005 {
13006   *((GtkWidget **)data) = NULL;
13007 }
13008
13009 void
13010 create_input_dialog ()
13011 {
13012   static GtkWidget *inputd = NULL;
13013
13014   if (!inputd)
13015     {
13016       inputd = gtk_input_dialog_new();
13017
13018       gtk_signal_connect (GTK_OBJECT(inputd), "destroy",
13019                           (GtkSignalFunc)input_dialog_destroy, &amp;inputd);
13020       gtk_signal_connect_object (GTK_OBJECT(GTK_INPUT_DIALOG(inputd)->close_button),
13021                                  "clicked",
13022                                  (GtkSignalFunc)gtk_widget_hide,
13023                                  GTK_OBJECT(inputd));
13024       gtk_widget_hide ( GTK_INPUT_DIALOG(inputd)->save_button);
13025
13026       gtk_widget_show (inputd);
13027     }
13028   else
13029     {
13030       if (!GTK_WIDGET_MAPPED(inputd))
13031         gtk_widget_show(inputd);
13032       else
13033         gdk_window_raise(inputd->window);
13034     }
13035 }
13036 </programlisting>
13037
13038 <para>(You might want to take note of the way we handle this dialog.  By
13039 connecting to the "destroy" signal, we make sure that we don't keep a
13040 pointer to dialog around after it is destroyed - that could lead to a
13041 segfault.)</para>
13042
13043 <para>The InputDialog has two buttons "Close" and "Save", which by default
13044 have no actions assigned to them. In the above function we make
13045 "Close" hide the dialog, hide the "Save" button, since we don't
13046 implement saving of XInput options in this program.</para>
13047
13048 </sect2>
13049
13050 <!-- ----------------------------------------------------------------- -->
13051 <sect2>
13052 <title>Using extended device information</title>
13053
13054 <para>Once we've enabled the device, we can just use the extended 
13055 device information in the extra fields of the event structures.
13056 In fact, it is always safe to use this information since these
13057 fields will have reasonable default values even when extended
13058 events are not enabled.</para>
13059
13060 <para>Once change we do have to make is to call
13061 <literal>gdk_input_window_get_pointer()</literal> instead of
13062 <literal>gdk_window_get_pointer</literal>. This is necessary because
13063 <literal>gdk_window_get_pointer</literal> doesn't return the extended device
13064 information.</para>
13065
13066 <programlisting role="C">
13067 void gdk_input_window_get_pointer( GdkWindow       *window,
13068                                    guint32         deviceid,
13069                                    gdouble         *x,
13070                                    gdouble         *y,
13071                                    gdouble         *pressure,
13072                                    gdouble         *xtilt,
13073                                    gdouble         *ytilt,
13074                                    GdkModifierType *mask);
13075 </programlisting>
13076
13077 <para>When calling this function, we need to specify the device ID as
13078 well as the window. Usually, we'll get the device ID from the
13079 <literal>deviceid</literal> field of an event structure. Again, this function
13080 will return reasonable values when extension events are not
13081 enabled. (In this case, <literal>event->deviceid</literal> will have the value
13082 <literal>GDK_CORE_POINTER</literal>).</para>
13083
13084 <para>So the basic structure of our button-press and motion event handlers
13085 doesn't change much - we just need to add code to deal with the
13086 extended information.</para>
13087
13088 <programlisting role="C">
13089 static gboolean
13090 button_press_event( GtkWidget *widget, GdkEventButton *event )
13091 {
13092   print_button_press (event->deviceid);
13093   
13094   if (event->button == 1 &amp;&amp; pixmap != NULL)
13095     draw_brush (widget, event->source, event->x, event->y, event->pressure);
13096
13097   return TRUE;
13098 }
13099
13100 static gboolean
13101 motion_notify_event( GtkWidget *widget, GdkEventMotion *event )
13102 {
13103   gdouble x, y;
13104   gdouble pressure;
13105   GdkModifierType state;
13106
13107   if (event->is_hint)
13108     gdk_input_window_get_pointer (event->window, event->deviceid,
13109                                   &amp;x, &amp;y, &amp;pressure, NULL, NULL, &amp;state);
13110   else
13111     {
13112       x = event->x;
13113       y = event->y;
13114       pressure = event->pressure;
13115       state = event->state;
13116     }
13117     
13118   if (state &amp; GDK_BUTTON1_MASK &amp;&amp; pixmap != NULL)
13119     draw_brush (widget, event->source, x, y, pressure);
13120   
13121   return TRUE;
13122 }
13123 </programlisting>
13124
13125 <para>We also need to do something with the new information. Our new
13126 <literal>draw_brush()</literal> function draws with a different color for
13127 each <literal>event->source</literal> and changes the brush size depending
13128 on the pressure.</para>
13129
13130 <programlisting role="C">
13131 /* Draw a rectangle on the screen, size depending on pressure,
13132    and color on the type of device */
13133 static void
13134 draw_brush (GtkWidget *widget, GdkInputSource source,
13135             gdouble x, gdouble y, gdouble pressure)
13136 {
13137   GdkGC *gc;
13138   GdkRectangle update_rect;
13139
13140   switch (source)
13141     {
13142     case GDK_SOURCE_MOUSE:
13143       gc = widget->style->dark_gc[GTK_WIDGET_STATE (widget)];
13144       break;
13145     case GDK_SOURCE_PEN:
13146       gc = widget->style->black_gc;
13147       break;
13148     case GDK_SOURCE_ERASER:
13149       gc = widget->style->white_gc;
13150       break;
13151     default:
13152       gc = widget->style->light_gc[GTK_WIDGET_STATE (widget)];
13153     }
13154
13155   update_rect.x = x - 10 * pressure;
13156   update_rect.y = y - 10 * pressure;
13157   update_rect.width = 20 * pressure;
13158   update_rect.height = 20 * pressure;
13159   gdk_draw_rectangle (pixmap, gc, TRUE,
13160                       update_rect.x, update_rect.y,
13161                       update_rect.width, update_rect.height);
13162   gtk_widget_draw (widget, &amp;update_rect);
13163 }
13164 </programlisting>
13165
13166 </sect2>
13167
13168 <!-- ----------------------------------------------------------------- -->
13169 <sect2>
13170 <title>Finding out more about a device</title>
13171
13172 <para>As an example of how to find out more about a device, our program
13173 will print the name of the device that generates each button
13174 press. To find out the name of a device, we call the function:</para>
13175
13176 <programlisting role="C">
13177 GList *gdk_input_list_devices               (void);
13178 </programlisting>
13179
13180 <para>which returns a GList (a linked list type from the GLib library)
13181 of GdkDeviceInfo structures. The GdkDeviceInfo structure is defined
13182 as:</para>
13183
13184 <programlisting role="C">
13185 struct _GdkDeviceInfo
13186 {
13187   guint32 deviceid;
13188   gchar *name;
13189   GdkInputSource source;
13190   GdkInputMode mode;
13191   gint has_cursor;
13192   gint num_axes;
13193   GdkAxisUse *axes;
13194   gint num_keys;
13195   GdkDeviceKey *keys;
13196 };
13197 </programlisting>
13198
13199 <para>Most of these fields are configuration information that you can ignore
13200 unless you are implementing XInput configuration saving. The fieldwe
13201 are interested in here is <literal>name</literal> which is simply the name that X
13202 assigns to the device. The other field that isn't configuration
13203 information is <literal>has_cursor</literal>. If <literal>has_cursor</literal> is false, then we
13204 we need to draw our own cursor. But since we've specified
13205 <literal>GDK_EXTENSION_EVENTS_CURSOR</literal>, we don't have to worry about this.</para>
13206
13207 <para>Our <literal>print_button_press()</literal> function simply iterates through
13208 the returned list until it finds a match, then prints out
13209 the name of the device.</para>
13210
13211 <programlisting role="C">
13212 static void
13213 print_button_press (guint32 deviceid)
13214 {
13215   GList *tmp_list;
13216
13217   /* gdk_input_list_devices returns an internal list, so we shouldn't
13218      free it afterwards */
13219   tmp_list = gdk_input_list_devices();
13220
13221   while (tmp_list)
13222     {
13223       GdkDeviceInfo *info = (GdkDeviceInfo *)tmp_list->data;
13224
13225       if (info->deviceid == deviceid)
13226         {
13227           printf("Button press on device '%s'\n", info->name);
13228           return;
13229         }
13230
13231       tmp_list = tmp_list->next;
13232     }
13233 }
13234 </programlisting>
13235
13236 <para>That completes the changes to "XInputize" our program.</para>
13237
13238 </sect2>
13239
13240 <!-- ----------------------------------------------------------------- -->
13241 <sect2 id="sec-FurtherSophistications">
13242 <title>Further sophistications</title>
13243
13244 <para>Although our program now supports XInput quite well, it lacks some
13245 features we would want in a full-featured application. First, the user
13246 probably doesn't want to have to configure their device each time they
13247 run the program, so we should allow them to save the device
13248 configuration. This is done by iterating through the return of
13249 <literal>gdk_input_list_devices()</literal> and writing out the configuration to a
13250 file.</para>
13251
13252 <para>To restore the state next time the program is run, GDK provides
13253 functions to change device configuration:</para>
13254
13255 <programlisting role="C">
13256 gdk_input_set_extension_events()
13257 gdk_input_set_source()
13258 gdk_input_set_mode()
13259 gdk_input_set_axes()
13260 gdk_input_set_key()
13261 </programlisting>
13262
13263 <para>(The list returned from <literal>gdk_input_list_devices()</literal> should not be
13264 modified directly.) An example of doing this can be found in the
13265 drawing program gsumi. (Available from <ulink
13266 url="http://www.msc.cornell.edu/~otaylor/gsumi/">http://www.msc.cornell.edu/~otaylor/gsumi/</ulink>) Eventually, it
13267 would be nice to have a standard way of doing this for all
13268 applications. This probably belongs at a slightly higher level than
13269 GTK, perhaps in the GNOME library.</para>
13270
13271 <para>Another major omission that we have mentioned above is the lack of
13272 cursor drawing. Platforms other than XFree86 currently do not allow
13273 simultaneously using a device as both the core pointer and directly by
13274 an application. See the <ulink
13275 url="http://www.msc.cornell.edu/~otaylor/xinput/XInput-HOWTO.html">XInput-HOWTO</ulink> for more information about this. This means that
13276 applications that want to support the widest audience need to draw
13277 their own cursor.</para>
13278
13279 <para>An application that draws its own cursor needs to do two things:
13280 determine if the current device needs a cursor drawn or not, and
13281 determine if the current device is in proximity. (If the current
13282 device is a drawing tablet, it's a nice touch to make the cursor 
13283 disappear when the stylus is lifted from the tablet. When the
13284 device is touching the stylus, that is called "in proximity.")
13285 The first is done by searching the device list, as we did
13286 to find out the device name. The second is achieved by selecting
13287 "proximity_out" events. An example of drawing one's own cursor is
13288 found in the "testinput" program found in the GTK distribution.</para>
13289
13290 </sect2>
13291
13292 </sect1>
13293 </chapter>
13294
13295 <!-- ***************************************************************** -->
13296 <chapter id="ch-Tips">
13297 <title>Tips For Writing GTK Applications</title>
13298
13299 <para>This section is simply a gathering of wisdom, general style guidelines
13300 and hints to creating good GTK applications. Currently this section
13301 is very short, but I hope it will get longer in future editions of
13302 this tutorial.</para>
13303
13304 <para>Use GNU autoconf and automake! They are your friends :) Automake
13305 examines C files, determines how they depend on each other, and
13306 generates a Makefile so the files can be compiled in the correct
13307 order. Autoconf permits automatic configuration of software
13308 installation, handling a large number of system quirks to increase
13309 portability. I am planning to make a quick intro on them here.</para>
13310
13311 <para>When writing C code, use only C comments (beginning with "/*" and
13312 ending with "*/"), and don't use C++-style comments ("//").  Although
13313 many C compilers understand C++ comments, others don't, and the ANSI C
13314 standard does not require that C++-style comments be processed as
13315 comments.</para>
13316
13317 </chapter>
13318
13319 <!-- ***************************************************************** -->
13320 <chapter id="ch-Contributing">
13321 <title>Contributing</title>
13322
13323 <para>This document, like so much other great software out there, was
13324 created for free by volunteers.  If you are at all knowledgeable about
13325 any aspect of GTK that does not already have documentation, please
13326 consider contributing to this document.</para>
13327
13328 <para>If you do decide to contribute, please mail your text to Tony Gale,
13329 <literal><ulink url="mailto:gale@gtk.org">gale@gtk.org</ulink></literal>. Also, be aware that the entirety of this
13330 document is free, and any addition by you provide must also be
13331 free. That is, people may use any portion of your examples in their
13332 programs, and copies of this document may be distributed at will, etc.</para>
13333
13334 <para>Thank you.</para>
13335
13336 </chapter>
13337
13338 <!-- ***************************************************************** -->
13339 <chapter id="ch-Credits">
13340 <title>Credits</title>
13341
13342 <para>We would like to thank the following for their contributions to this text.</para>
13343
13344 <itemizedlist>
13345 <listitem><simpara>Bawer Dagdeviren, <literal><ulink url="mailto:chamele0n@geocities.com">chamele0n@geocities.com</ulink></literal> for the menus tutorial.</simpara>
13346 </listitem>
13347
13348 <listitem><simpara>Raph Levien, <literal><ulink url="mailto:raph@acm.org">raph@acm.org</ulink></literal>
13349 for hello world ala GTK, widget packing, and general all around wisdom.
13350 He's also generously donated a home for this tutorial.</simpara>
13351 </listitem>
13352
13353 <listitem><simpara>Peter Mattis, <literal><ulink url="mailto:petm@xcf.berkeley.edu">petm@xcf.berkeley.edu</ulink></literal> for the simplest GTK program.. 
13354 and the ability to make it :)</simpara>
13355 </listitem>
13356
13357 <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
13358 SGML, and the widget class hierarchy.</simpara>
13359 </listitem>
13360
13361 <listitem><simpara>Mark Crichton <literal><ulink
13362 url="mailto:crichton@expert.cc.purdue.edu">crichton@expert.cc.purdue.edu</ulink></literal> for the menu factory code,
13363 and the table packing tutorial.</simpara>
13364 </listitem>
13365
13366 <listitem><simpara>Owen Taylor <literal><ulink url="mailto:owt1@cornell.edu">owt1@cornell.edu</ulink></literal> for the EventBox widget section (and the
13367 patch to the distro).  He's also responsible for the selections code
13368 and tutorial, as well as the sections on writing your own GTK widgets,
13369 and the example application. Thanks a lot Owen for all you help!</simpara>
13370 </listitem>
13371
13372 <listitem><simpara>Mark VanderBoom <literal><ulink url="mailto:mvboom42@calvin.edu">mvboom42@calvin.edu</ulink></literal> for his wonderful work on the
13373 Notebook, Progress Bar, Dialogs, and File selection widgets.  Thanks a
13374 lot Mark!  You've been a great help.</simpara>
13375 </listitem>
13376
13377 <listitem><simpara>Tim Janik <literal><ulink url="mailto:timj@gtk.org">timj@gtk.org</ulink></literal> for his great job on the Lists
13378 Widget. His excellent work on automatically extracting the widget tree
13379 and signal information from GTK. Thanks Tim :)</simpara>
13380 </listitem>
13381
13382 <listitem><simpara>Rajat Datta <literal><ulink url="mailto:rajat@ix.netcom.com">rajat@ix.netcom.com</ulink>
13383 </literal> for the excellent job on the Pixmap
13384 tutorial.</simpara>
13385 </listitem>
13386
13387 <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>
13388 </listitem>
13389
13390 <listitem><simpara>David Huggins-Daines <literal><ulink
13391 url="mailto:bn711@freenet.carleton.ca">bn711@freenet.carleton.ca</ulink></literal> for the Range Widgets and Tree
13392 Widget sections.</simpara>
13393 </listitem>
13394
13395 <listitem><simpara>Stefan Mars <literal><ulink url="mailto:mars@lysator.liu.se">mars@lysator.liu.se</ulink></literal> for the CList section.</simpara>
13396 </listitem>
13397
13398 <listitem><simpara>David A. Wheeler <literal><ulink url="mailto:dwheeler@ida.org">dwheeler@ida.org</ulink></literal> for portions of the text on GLib
13399 and various tutorial fixups and improvements.
13400 The GLib text was in turn based on material developed by Damon Chaplin
13401 <literal><ulink url="mailto:DAChaplin@msn.com">DAChaplin@msn.com</ulink></literal></simpara>
13402 </listitem>
13403
13404 <listitem><simpara>David King for style checking the entire document.</simpara>
13405 </listitem>
13406 </itemizedlist>
13407
13408 <para>And to all of you who commented on and helped refine this document.</para>
13409
13410 <para>Thanks.</para>
13411
13412 </chapter>
13413
13414 <!-- ***************************************************************** -->
13415 <chapter id="ch-Copyright">
13416 <title>Tutorial Copyright and Permissions Notice</title>
13417
13418 <para>The GTK Tutorial is Copyright (C) 1997 Ian Main. </para>
13419
13420 <para>Copyright (C) 1998-2002 Tony Gale.</para>
13421
13422 <para>Permission is granted to make and distribute verbatim copies of this 
13423 manual provided the copyright notice and this permission notice are 
13424 preserved on all copies.</para>
13425
13426 <para>Permission is granted to copy and distribute modified versions of 
13427 this document under the conditions for verbatim copying, provided that 
13428 this copyright notice is included exactly as in the original,
13429 and that the entire resulting derived work is distributed under 
13430 the terms of a permission notice identical to this one.</para>
13431
13432 <para>Permission is granted to copy and distribute translations of this 
13433 document into another language, under the above conditions for modified 
13434 versions.</para>
13435
13436 <para>If you are intending to incorporate this document into a published 
13437 work, please contact the maintainer, and we will make an effort 
13438 to ensure that you have the most up to date information available.</para>
13439
13440 <para>There is no guarantee that this document lives up to its intended
13441 purpose.  This is simply provided as a free resource.  As such,
13442 the authors and maintainers of the information provided within can
13443 not make any guarantee that the information is even accurate.</para>
13444
13445 </chapter>
13446
13447 <!-- ***************************************************************** -->
13448 <!-- ***************************************************************** -->
13449
13450 <!-- ***************************************************************** -->
13451 <appendix id="app-GTKSignals">
13452 <title>GTK Signals</title>
13453
13454 <para>As GTK is an object oriented widget set, it has a hierarchy of
13455 inheritance. This inheritance mechanism applies for
13456 signals. Therefore, you should refer to the widget hierarchy tree when
13457 using the signals listed in this section.</para>
13458
13459 <!-- ----------------------------------------------------------------- -->
13460 <sect1 id="sec-GtkObject">
13461 <title>GtkObject</title>
13462
13463 <programlisting role="C">
13464 void GtkObject::destroy (GtkObject *,
13465                          gpointer);
13466 </programlisting>
13467
13468 </sect1>
13469
13470 <!-- ----------------------------------------------------------------- -->
13471 <sect1 id="sec-GtkWidget">
13472 <title>GtkWidget</title>
13473
13474 <programlisting role="C">
13475 void GtkWidget::show    (GtkWidget *,
13476                          gpointer);
13477 void GtkWidget::hide    (GtkWidget *,
13478                          gpointer);
13479 void GtkWidget::map     (GtkWidget *,
13480                          gpointer);
13481 void GtkWidget::unmap   (GtkWidget *,
13482                          gpointer);
13483 void GtkWidget::realize (GtkWidget *,
13484                          gpointer);
13485 void GtkWidget::unrealize       (GtkWidget *,
13486                                  gpointer);
13487 void GtkWidget::draw    (GtkWidget *,
13488                          ggpointer,
13489                          gpointer);
13490 void GtkWidget::draw-focus      (GtkWidget *,
13491                                  gpointer);
13492 void GtkWidget::draw-default    (GtkWidget *,
13493                                  gpointer);
13494 void GtkWidget::size-request    (GtkWidget *,
13495                                  ggpointer,
13496                                  gpointer);
13497 void GtkWidget::size-allocate   (GtkWidget *,
13498                                  ggpointer,
13499                                  gpointer);
13500 void GtkWidget::state-changed   (GtkWidget *,
13501                                  GtkStateType,
13502                                  gpointer);
13503 void GtkWidget::parent-set      (GtkWidget *,
13504                                  GtkObject *,
13505                                  gpointer);
13506 void GtkWidget::style-set       (GtkWidget *,
13507                                  GtkStyle *,
13508                                  gpointer);
13509 void GtkWidget::add-accelerator (GtkWidget *,
13510                                  gguint,
13511                                  GtkAccelGroup *,
13512                                  gguint,
13513                                  GdkModifierType,
13514                                  GtkAccelFlags,
13515                                  gpointer);
13516 void GtkWidget::remove-accelerator      (GtkWidget *,
13517                                          GtkAccelGroup *,
13518                                          gguint,
13519                                          GdkModifierType,
13520                                          gpointer);
13521 gboolean GtkWidget::event       (GtkWidget *,
13522                                  GdkEvent *,
13523                                  gpointer);
13524 gboolean GtkWidget::button-press-event  (GtkWidget *,
13525                                          GdkEvent *,
13526                                          gpointer);
13527 gboolean GtkWidget::button-release-event        (GtkWidget *,
13528                                                  GdkEvent *,
13529                                                  gpointer);
13530 gboolean GtkWidget::motion-notify-event (GtkWidget *,
13531                                          GdkEvent *,
13532                                          gpointer);
13533 gboolean GtkWidget::delete-event        (GtkWidget *,
13534                                          GdkEvent *,
13535                                          gpointer);
13536 gboolean GtkWidget::destroy-event       (GtkWidget *,
13537                                          GdkEvent *,
13538                                          gpointer);
13539 gboolean GtkWidget::expose-event        (GtkWidget *,
13540                                          GdkEvent *,
13541                                          gpointer);
13542 gboolean GtkWidget::key-press-event     (GtkWidget *,
13543                                          GdkEvent *,
13544                                          gpointer);
13545 gboolean GtkWidget::key-release-event   (GtkWidget *,
13546                                          GdkEvent *,
13547                                          gpointer);
13548 gboolean GtkWidget::enter-notify-event  (GtkWidget *,
13549                                          GdkEvent *,
13550                                          gpointer);
13551 gboolean GtkWidget::leave-notify-event  (GtkWidget *,
13552                                          GdkEvent *,
13553                                          gpointer);
13554 gboolean GtkWidget::configure-event     (GtkWidget *,
13555                                          GdkEvent *,
13556                                          gpointer);
13557 gboolean GtkWidget::focus-in-event      (GtkWidget *,
13558                                          GdkEvent *,
13559                                          gpointer);
13560 gboolean GtkWidget::focus-out-event     (GtkWidget *,
13561                                          GdkEvent *,
13562                                          gpointer);
13563 gboolean GtkWidget::map-event   (GtkWidget *,
13564                                  GdkEvent *,
13565                                  gpointer);
13566 gboolean GtkWidget::unmap-event (GtkWidget *,
13567                                  GdkEvent *,
13568                                  gpointer);
13569 gboolean GtkWidget::property-notify-event       (GtkWidget *,
13570                                                  GdkEvent *,
13571                                                  gpointer);
13572 gboolean GtkWidget::selection-clear-event       (GtkWidget *,
13573                                                  GdkEvent *,
13574                                                  gpointer);
13575 gboolean GtkWidget::selection-request-event     (GtkWidget *,
13576                                                  GdkEvent *,
13577                                                  gpointer);
13578 gboolean GtkWidget::selection-notify-event      (GtkWidget *,
13579                                                  GdkEvent *,
13580                                                  gpointer);
13581 void GtkWidget::selection-get   (GtkWidget *,
13582                                  GtkSelectionData *,
13583                                  gguint,
13584                                  gpointer);
13585 void GtkWidget::selection-received      (GtkWidget *,
13586                                          GtkSelectionData *,
13587                                          gguint,
13588                                          gpointer);
13589 gboolean GtkWidget::proximity-in-event  (GtkWidget *,
13590                                          GdkEvent *,
13591                                          gpointer);
13592 gboolean GtkWidget::proximity-out-event (GtkWidget *,
13593                                          GdkEvent *,
13594                                          gpointer);
13595 void GtkWidget::drag-begin      (GtkWidget *,
13596                                  GdkDragContext *,
13597                                  gpointer);
13598 void GtkWidget::drag-end        (GtkWidget *,
13599                                  GdkDragContext *,
13600                                  gpointer);
13601 void GtkWidget::drag-data-delete        (GtkWidget *,
13602                                          GdkDragContext *,
13603                                          gpointer);
13604 void GtkWidget::drag-leave      (GtkWidget *,
13605                                  GdkDragContext *,
13606                                  gguint,
13607                                  gpointer);
13608 gboolean GtkWidget::drag-motion (GtkWidget *,
13609                                  GdkDragContext *,
13610                                  ggint,
13611                                  ggint,
13612                                  gguint,
13613                                  gpointer);
13614 gboolean GtkWidget::drag-drop   (GtkWidget *,
13615                                  GdkDragContext *,
13616                                  ggint,
13617                                  ggint,
13618                                  gguint,
13619                                  gpointer);
13620 void GtkWidget::drag-data-get   (GtkWidget *,
13621                                  GdkDragContext *,
13622                                  GtkSelectionData *,
13623                                  gguint,
13624                                  gguint,
13625                                  gpointer);
13626 void GtkWidget::drag-data-received      (GtkWidget *,
13627                                          GdkDragContext *,
13628                                          ggint,
13629                                          ggint,
13630                                          GtkSelectionData *,
13631                                          gguint,
13632                                          gguint,
13633                                          gpointer);
13634 gboolean GtkWidget::client-event        (GtkWidget *,
13635                                          GdkEvent *,
13636                                          gpointer);
13637 gboolean GtkWidget::no-expose-event     (GtkWidget *,
13638                                          GdkEvent *,
13639                                          gpointer);
13640 gboolean GtkWidget::visibility-notify-event     (GtkWidget *,
13641                                                  GdkEvent *,
13642                                                  gpointer);
13643 void GtkWidget::debug-msg       (GtkWidget *,
13644                                  GtkString *,
13645                                  gpointer);
13646 </programlisting>
13647
13648 </sect1>
13649
13650 <!-- ----------------------------------------------------------------- -->
13651 <sect1 id="sec-GtkData">
13652 <title>GtkData</title>
13653
13654 <programlisting role="C">
13655 void GtkData::disconnect        (GtkData *,
13656                                  gpointer);
13657 </programlisting>
13658
13659 </sect1>
13660
13661 <!-- ----------------------------------------------------------------- -->
13662 <sect1 id="sec-GtkContainer">
13663 <title>GtkContainer</title>
13664
13665 <programlisting role="C">
13666 void GtkContainer::add  (GtkContainer *,
13667                          GtkWidget *,
13668                          gpointer);
13669 void GtkContainer::remove       (GtkContainer *,
13670                                  GtkWidget *,
13671                                  gpointer);
13672 void GtkContainer::check-resize (GtkContainer *,
13673                                  gpointer);
13674 GtkDirectionType GtkContainer::focus    (GtkContainer *,
13675                                          GtkDirectionType,
13676                                          gpointer);
13677 void GtkContainer::set-focus-child      (GtkContainer *,
13678                                          GtkWidget *,
13679                                          gpointer);
13680 </programlisting>
13681
13682 </sect1>
13683
13684 <!-- ----------------------------------------------------------------- -->
13685 <sect1 id="sec-GtkCalendar">
13686 <title>GtkCalendar</title>
13687
13688 <programlisting role="C">
13689 void GtkCalendar::month-changed (GtkCalendar *,
13690                                  gpointer);
13691 void GtkCalendar::day-selected  (GtkCalendar *,
13692                                  gpointer);
13693 void GtkCalendar::day-selected-double-click     (GtkCalendar *,
13694                                                  gpointer);
13695 void GtkCalendar::prev-month    (GtkCalendar *,
13696                                  gpointer);
13697 void GtkCalendar::next-month    (GtkCalendar *,
13698                                  gpointer);
13699 void GtkCalendar::prev-year     (GtkCalendar *,
13700                                  gpointer);
13701 void GtkCalendar::next-year     (GtkCalendar *,
13702                                  gpointer);
13703 </programlisting>
13704
13705 </sect1>
13706
13707 <!-- ----------------------------------------------------------------- -->
13708 <sect1 id="sec-GtkEditable">
13709 <title>GtkEditable</title>
13710
13711 <programlisting role="C">
13712 void GtkEditable::changed       (GtkEditable *,
13713                                  gpointer);
13714 void GtkEditable::insert-text   (GtkEditable *,
13715                                  GtkString *,
13716                                  ggint,
13717                                  ggpointer,
13718                                  gpointer);
13719 void GtkEditable::delete-text   (GtkEditable *,
13720                                  ggint,
13721                                  ggint,
13722                                  gpointer);
13723 void GtkEditable::activate      (GtkEditable *,
13724                                  gpointer);
13725 void GtkEditable::set-editable  (GtkEditable *,
13726                                  gboolean,
13727                                  gpointer);
13728 void GtkEditable::move-cursor   (GtkEditable *,
13729                                  ggint,
13730                                  ggint,
13731                                  gpointer);
13732 void GtkEditable::move-word     (GtkEditable *,
13733                                  ggint,
13734                                  gpointer);
13735 void GtkEditable::move-page     (GtkEditable *,
13736                                  ggint,
13737                                  ggint,
13738                                  gpointer);
13739 void GtkEditable::move-to-row   (GtkEditable *,
13740                                  ggint,
13741                                  gpointer);
13742 void GtkEditable::move-to-column        (GtkEditable *,
13743                                          ggint,
13744                                          gpointer);
13745 void GtkEditable::kill-char     (GtkEditable *,
13746                                  ggint,
13747                                  gpointer);
13748 void GtkEditable::kill-word     (GtkEditable *,
13749                                  ggint,
13750                                  gpointer);
13751 void GtkEditable::kill-line     (GtkEditable *,
13752                                  ggint,
13753                                  gpointer);
13754 void GtkEditable::cut-clipboard (GtkEditable *,
13755                                  gpointer);
13756 void GtkEditable::copy-clipboard        (GtkEditable *,
13757                                          gpointer);
13758 void GtkEditable::paste-clipboard       (GtkEditable *,
13759                                          gpointer);
13760 </programlisting>
13761
13762 </sect1>
13763
13764 <!-- ----------------------------------------------------------------- -->
13765 <sect1 id="sec-GtkNotebook">
13766 <title>GtkNotebook</title>
13767
13768 <programlisting role="C">
13769 void GtkNotebook::switch-page   (GtkNotebook *,
13770                                  ggpointer,
13771                                  gguint,
13772                                  gpointer);
13773 </programlisting>
13774
13775 </sect1>
13776
13777 <!-- ----------------------------------------------------------------- -->
13778 <sect1 id="sec-GtkList">
13779 <title>GtkList</title>
13780
13781 <programlisting role="C">
13782 void GtkList::selection-changed (GtkList *,
13783                                  gpointer);
13784 void GtkList::select-child      (GtkList *,
13785                                  GtkWidget *,
13786                                  gpointer);
13787 void GtkList::unselect-child    (GtkList *,
13788                                  GtkWidget *,
13789                                  gpointer);
13790 </programlisting>
13791
13792 </sect1>
13793
13794 <!-- ----------------------------------------------------------------- -->
13795 <sect1 id="sec-GtkMenuShell">
13796 <title>GtkMenuShell</title>
13797
13798 <programlisting role="C">
13799 void GtkMenuShell::deactivate   (GtkMenuShell *,
13800                                  gpointer);
13801 void GtkMenuShell::selection-done       (GtkMenuShell *,
13802                                          gpointer);
13803 void GtkMenuShell::move-current (GtkMenuShell *,
13804                                  GtkMenuDirectionType,
13805                                  gpointer);
13806 void GtkMenuShell::activate-current     (GtkMenuShell *,
13807                                          gboolean,
13808                                          gpointer);
13809 void GtkMenuShell::cancel       (GtkMenuShell *,
13810                                  gpointer);
13811 </programlisting>
13812
13813 </sect1>
13814
13815 <!-- ----------------------------------------------------------------- -->
13816 <sect1 id="sec-GtkToolbar">
13817 <title>GtkToolbar</title>
13818
13819 <programlisting role="C">
13820 void GtkToolbar::orientation-changed    (GtkToolbar *,
13821                                          ggint,
13822                                          gpointer);
13823 void GtkToolbar::style-changed  (GtkToolbar *,
13824                                  ggint,
13825                                  gpointer);
13826 </programlisting>
13827
13828 </sect1>
13829
13830 <!-- ----------------------------------------------------------------- -->
13831 <sect1 id="sec-GtkButton">
13832 <title>GtkButton</title>
13833
13834 <programlisting role="C">
13835 void GtkButton::pressed (GtkButton *,
13836                          gpointer);
13837 void GtkButton::released        (GtkButton *,
13838                                  gpointer);
13839 void GtkButton::clicked (GtkButton *,
13840                          gpointer);
13841 void GtkButton::enter   (GtkButton *,
13842                          gpointer);
13843 void GtkButton::leave   (GtkButton *,
13844                          gpointer);
13845 </programlisting>
13846
13847 </sect1>
13848
13849 <!-- ----------------------------------------------------------------- -->
13850 <sect1 id="sec-GtkItem">
13851 <title>GtkItem</title>
13852
13853 <programlisting role="C">
13854 void GtkItem::select    (GtkItem *,
13855                          gpointer);
13856 void GtkItem::deselect  (GtkItem *,
13857                          gpointer);
13858 void GtkItem::toggle    (GtkItem *,
13859                          gpointer);
13860 </programlisting>
13861
13862 </sect1>
13863
13864 <!-- ----------------------------------------------------------------- -->
13865 <sect1 id="sec-GtkWindow">
13866 <title>GtkWindow</title>
13867
13868 <programlisting role="C">
13869 void GtkWindow::set-focus       (GtkWindow *,
13870                                  ggpointer,
13871                                  gpointer);
13872 </programlisting>
13873
13874 </sect1>
13875
13876 <!-- ----------------------------------------------------------------- -->
13877 <sect1 id="sec-GtkHandleBox">
13878 <title>GtkHandleBox</title>
13879
13880 <programlisting role="C">
13881 void GtkHandleBox::child-attached       (GtkHandleBox *,
13882                                          GtkWidget *,
13883                                          gpointer);
13884 void GtkHandleBox::child-detached       (GtkHandleBox *,
13885                                          GtkWidget *,
13886                                          gpointer);
13887 </programlisting>
13888
13889 </sect1>
13890
13891 <!-- ----------------------------------------------------------------- -->
13892 <sect1 id="sec-GtkToggleButton">
13893 <title>GtkToggleButton</title>
13894
13895 <programlisting role="C">
13896 void GtkToggleButton::toggled   (GtkToggleButton *,
13897                                  gpointer);
13898 </programlisting>
13899
13900 </sect1>
13901
13902 <!-- ----------------------------------------------------------------- -->
13903 <sect1 id="sec-GtkMenuItem">
13904 <title>GtkMenuItem</title>
13905
13906 <programlisting role="C">
13907 void GtkMenuItem::activate      (GtkMenuItem *,
13908                                  gpointer);
13909 void GtkMenuItem::activate-item (GtkMenuItem *,
13910                                  gpointer);
13911 </programlisting>
13912
13913 </sect1>
13914
13915 <!-- ----------------------------------------------------------------- -->
13916 <sect1 id="sec-GtkCheckMenuItem">
13917 <title>GtkCheckMenuItem</title>
13918
13919 <programlisting role="C">
13920 void GtkCheckMenuItem::toggled  (GtkCheckMenuItem *,
13921                                  gpointer);
13922 </programlisting>
13923
13924 </sect1>
13925
13926 <!-- ----------------------------------------------------------------- -->
13927 <sect1 id="sec-GtkInputDialog">
13928 <title>GtkInputDialog</title>
13929
13930 <programlisting role="C">
13931 void GtkInputDialog::enable-device      (GtkInputDialog *,
13932                                          ggint,
13933                                          gpointer);
13934 void GtkInputDialog::disable-device     (GtkInputDialog *,
13935                                          ggint,
13936                                          gpointer);
13937 </programlisting>
13938
13939 </sect1>
13940
13941 <!-- ----------------------------------------------------------------- -->
13942 <sect1 id="sec-GtkColorSelection">
13943 <title>GtkColorSelection</title>
13944
13945 <programlisting role="C">
13946 void GtkColorSelection::color-changed   (GtkColorSelection *,
13947                                          gpointer);
13948 </programlisting>
13949
13950 </sect1>
13951
13952 <!-- ----------------------------------------------------------------- -->
13953 <sect1 id="sec-GtkStatusBar">
13954 <title>GtkStatusBar</title>
13955
13956 <programlisting role="C">
13957 void GtkStatusbar::text-pushed  (GtkStatusbar *,
13958                                  gguint,
13959                                  GtkString *,
13960                                  gpointer);
13961 void GtkStatusbar::text-popped  (GtkStatusbar *,
13962                                  gguint,
13963                                  GtkString *,
13964                                  gpointer);
13965 </programlisting>
13966
13967 </sect1>
13968
13969 <!-- ----------------------------------------------------------------- -->
13970 <sect1 id="sec-GtkCurve">
13971 <title>GtkCurve</title>
13972
13973 <programlisting role="C">
13974 void GtkCurve::curve-type-changed       (GtkCurve *,
13975                                          gpointer);
13976 </programlisting>
13977
13978 </sect1>
13979
13980 <!-- ----------------------------------------------------------------- -->
13981 <sect1 id="sec-GtkAdjustment">
13982 <title>GtkAdjustment</title>
13983
13984 <programlisting role="C">
13985 void GtkAdjustment::changed     (GtkAdjustment *,
13986                                  gpointer);
13987 void GtkAdjustment::value-changed       (GtkAdjustment *,
13988                                          gpointer);
13989 </programlisting>
13990
13991 </sect1>
13992 </appendix>
13993
13994 <!-- ***************************************************************** -->
13995 <appendix id="app-GDKEventTypes">
13996 <title>GDK Event Types</title>
13997
13998 <para>The following data types are passed into event handlers by GTK+. For
13999 each data type listed, the signals that use this data type are listed.</para>
14000
14001 <itemizedlist>
14002 <listitem><simpara>  GdkEvent</simpara>
14003           <itemizedlist>
14004           <listitem><simpara>drag_end_event</simpara>
14005           </listitem>
14006           </itemizedlist>
14007 </listitem>
14008
14009 <listitem><simpara>  GdkEventType<</simpara>
14010 </listitem>
14011
14012 <listitem><simpara>  GdkEventAny</simpara>
14013           <itemizedlist>
14014           <listitem><simpara>delete_event</simpara>
14015           </listitem>
14016           <listitem><simpara>destroy_event</simpara>
14017           </listitem>
14018           <listitem><simpara>map_event</simpara>
14019           </listitem>
14020           <listitem><simpara>unmap_event</simpara>
14021           </listitem>
14022           <listitem><simpara>no_expose_event</simpara>
14023           </listitem>
14024           </itemizedlist>
14025 </listitem>
14026
14027 <listitem><simpara>  GdkEventExpose</simpara>
14028           <itemizedlist>
14029           <listitem><simpara>expose_event</simpara>
14030           </listitem>
14031           </itemizedlist>
14032 </listitem>
14033
14034 <listitem><simpara>  GdkEventNoExpose</simpara>
14035 </listitem>
14036
14037 <listitem><simpara>  GdkEventVisibility</simpara>
14038 </listitem>
14039
14040 <listitem><simpara>  GdkEventMotion</simpara>
14041           <itemizedlist>
14042           <listitem><simpara>motion_notify_event</simpara>
14043           </listitem>
14044           </itemizedlist>
14045 </listitem>
14046 <listitem><simpara>  GdkEventButton</simpara>
14047           <itemizedlist>
14048           <listitem><simpara>button_press_event</simpara>
14049           </listitem>
14050           <listitem><simpara>button_release_event</simpara>
14051           </listitem>
14052           </itemizedlist>
14053 </listitem>
14054
14055 <listitem><simpara>  GdkEventKey</simpara>
14056           <itemizedlist>
14057           <listitem><simpara>key_press_event</simpara>
14058           </listitem>
14059           <listitem><simpara>key_release_event</simpara>
14060           </listitem>
14061           </itemizedlist>
14062 </listitem>
14063
14064 <listitem><simpara>  GdkEventCrossing</simpara>
14065           <itemizedlist>
14066           <listitem><simpara>enter_notify_event</simpara>
14067           </listitem>
14068           <listitem><simpara>leave_notify_event</simpara>
14069           </listitem>
14070           </itemizedlist>
14071 </listitem>
14072
14073 <listitem><simpara>  GdkEventFocus</simpara>
14074           <itemizedlist>
14075           <listitem><simpara>focus_in_event</simpara>
14076           </listitem>
14077           <listitem><simpara>focus_out_event</simpara>
14078           </listitem>
14079           </itemizedlist>
14080 </listitem>
14081
14082 <listitem><simpara>  GdkEventConfigure</simpara>
14083           <itemizedlist>
14084           <listitem><simpara>configure_event</simpara>
14085           </listitem>
14086           </itemizedlist>
14087 </listitem>
14088
14089 <listitem><simpara>  GdkEventProperty</simpara>
14090           <itemizedlist>
14091           <listitem><simpara>property_notify_event</simpara>
14092           </listitem>
14093           </itemizedlist>
14094 </listitem>
14095
14096 <listitem><simpara>  GdkEventSelection</simpara>
14097           <itemizedlist>
14098           <listitem><simpara>selection_clear_event</simpara>
14099           </listitem>
14100           <listitem><simpara>selection_request_event</simpara>
14101           </listitem>
14102           <listitem><simpara>selection_notify_event</simpara>
14103           </listitem>
14104           </itemizedlist>
14105 </listitem>
14106
14107 <listitem><simpara>  GdkEventProximity</simpara>
14108           <itemizedlist>
14109           <listitem><simpara>proximity_in_event</simpara>
14110           </listitem>
14111           <listitem><simpara>proximity_out_event</simpara>
14112           </listitem>
14113           </itemizedlist>
14114 </listitem>
14115
14116 <listitem><simpara>  GdkEventDragBegin</simpara>
14117           <itemizedlist>
14118           <listitem><simpara>drag_begin_event</simpara>
14119           </listitem>
14120           </itemizedlist>
14121 </listitem>
14122
14123 <listitem><simpara>  GdkEventDragRequest</simpara>
14124           <itemizedlist>
14125           <listitem><simpara>drag_request_event</simpara>
14126           </listitem>
14127           </itemizedlist>
14128 </listitem>
14129
14130 <listitem><simpara>  GdkEventDropEnter</simpara>
14131           <itemizedlist>
14132           <listitem><simpara>drop_enter_event</simpara>
14133           </listitem>
14134           </itemizedlist>
14135 </listitem>
14136
14137 <listitem><simpara>  GdkEventDropLeave</simpara>
14138           <itemizedlist>
14139           <listitem><simpara>drop_leave_event</simpara>
14140           </listitem>
14141           </itemizedlist>
14142 </listitem>
14143
14144 <listitem><simpara>  GdkEventDropDataAvailable</simpara>
14145           <itemizedlist>
14146           <listitem><simpara>drop_data_available_event</simpara>
14147           </listitem>
14148           </itemizedlist>
14149 </listitem>
14150
14151 <listitem><simpara>  GdkEventClient</simpara>
14152           <itemizedlist>
14153           <listitem><simpara>client_event</simpara>
14154           </listitem>
14155           </itemizedlist>
14156 </listitem>
14157
14158 <listitem><simpara>  GdkEventOther</simpara>
14159           <itemizedlist>
14160           <listitem><simpara>other_event</simpara>
14161           </listitem>
14162           </itemizedlist>
14163 </listitem>
14164 </itemizedlist>
14165
14166 <para>The data type <literal>GdkEventType</literal> is a special data type that is used by
14167 all the other data types as an indicator of the data type being passed
14168 to the signal handler. As you will see below, each of the event data
14169 structures has a member of this type. It is defined as an enumeration
14170 type as follows:</para>
14171
14172 <programlisting role="C">
14173 typedef enum
14174 {
14175   GDK_NOTHING           = -1,
14176   GDK_DELETE            = 0,
14177   GDK_DESTROY           = 1,
14178   GDK_EXPOSE            = 2,
14179   GDK_MOTION_NOTIFY     = 3,
14180   GDK_BUTTON_PRESS      = 4,
14181   GDK_2BUTTON_PRESS     = 5,
14182   GDK_3BUTTON_PRESS     = 6,
14183   GDK_BUTTON_RELEASE    = 7,
14184   GDK_KEY_PRESS         = 8,
14185   GDK_KEY_RELEASE       = 9,
14186   GDK_ENTER_NOTIFY      = 10,
14187   GDK_LEAVE_NOTIFY      = 11,
14188   GDK_FOCUS_CHANGE      = 12,
14189   GDK_CONFIGURE         = 13,
14190   GDK_MAP               = 14,
14191   GDK_UNMAP             = 15,
14192   GDK_PROPERTY_NOTIFY   = 16,
14193   GDK_SELECTION_CLEAR   = 17,
14194   GDK_SELECTION_REQUEST = 18,
14195   GDK_SELECTION_NOTIFY  = 19,
14196   GDK_PROXIMITY_IN      = 20,
14197   GDK_PROXIMITY_OUT     = 21,
14198   GDK_DRAG_BEGIN        = 22,
14199   GDK_DRAG_REQUEST      = 23,
14200   GDK_DROP_ENTER        = 24,
14201   GDK_DROP_LEAVE        = 25,
14202   GDK_DROP_DATA_AVAIL   = 26,
14203   GDK_CLIENT_EVENT      = 27,
14204   GDK_VISIBILITY_NOTIFY = 28,
14205   GDK_NO_EXPOSE         = 29,
14206   GDK_OTHER_EVENT       = 9999  /* Deprecated, use filters instead */
14207 } GdkEventType;
14208 </programlisting>
14209
14210 <para>The other event type that is different from the others is
14211 <literal>GdkEvent</literal> itself. This is a union of all the other
14212 data types, which allows it to be cast to a specific
14213 event data type within a signal handler.</para>
14214
14215 <!-- Just a big list for now, needs expanding upon - TRG -->
14216 <para>So, the event data types are defined as follows:</para>
14217
14218 <programlisting role="C">
14219 struct _GdkEventAny
14220 {
14221   GdkEventType type;
14222   GdkWindow *window;
14223   gint8 send_event;
14224 };
14225
14226 struct _GdkEventExpose
14227 {
14228   GdkEventType type;
14229   GdkWindow *window;
14230   gint8 send_event;
14231   GdkRectangle area;
14232   gint count; /* If non-zero, how many more events follow. */
14233 };
14234
14235 struct _GdkEventNoExpose
14236 {
14237   GdkEventType type;
14238   GdkWindow *window;
14239   gint8 send_event;
14240   /* XXX: does anyone need the X major_code or minor_code fields? */
14241 };
14242
14243 struct _GdkEventVisibility
14244 {
14245   GdkEventType type;
14246   GdkWindow *window;
14247   gint8 send_event;
14248   GdkVisibilityState state;
14249 };
14250
14251 struct _GdkEventMotion
14252 {
14253   GdkEventType type;
14254   GdkWindow *window;
14255   gint8 send_event;
14256   guint32 time;
14257   gdouble x;
14258   gdouble y;
14259   gdouble pressure;
14260   gdouble xtilt;
14261   gdouble ytilt;
14262   guint state;
14263   gint16 is_hint;
14264   GdkInputSource source;
14265   guint32 deviceid;
14266   gdouble x_root, y_root;
14267 };
14268
14269 struct _GdkEventButton
14270 {
14271   GdkEventType type;
14272   GdkWindow *window;
14273   gint8 send_event;
14274   guint32 time;
14275   gdouble x;
14276   gdouble y;
14277   gdouble pressure;
14278   gdouble xtilt;
14279   gdouble ytilt;
14280   guint state;
14281   guint button;
14282   GdkInputSource source;
14283   guint32 deviceid;
14284   gdouble x_root, y_root;
14285 };
14286
14287 struct _GdkEventKey
14288 {
14289   GdkEventType type;
14290   GdkWindow *window;
14291   gint8 send_event;
14292   guint32 time;
14293   guint state;
14294   guint keyval;
14295   gint length;
14296   gchar *string;
14297 };
14298
14299 struct _GdkEventCrossing
14300 {
14301   GdkEventType type;
14302   GdkWindow *window;
14303   gint8 send_event;
14304   GdkWindow *subwindow;
14305   GdkNotifyType detail;
14306 };
14307
14308 struct _GdkEventFocus
14309 {
14310   GdkEventType type;
14311   GdkWindow *window;
14312   gint8 send_event;
14313   gint16 in;
14314 };
14315
14316 struct _GdkEventConfigure
14317 {
14318   GdkEventType type;
14319   GdkWindow *window;
14320   gint8 send_event;
14321   gint16 x, y;
14322   gint16 width;
14323   gint16 height;
14324 };
14325
14326 struct _GdkEventProperty
14327 {
14328   GdkEventType type;
14329   GdkWindow *window;
14330   gint8 send_event;
14331   GdkAtom atom;
14332   guint32 time;
14333   guint state;
14334 };
14335
14336 struct _GdkEventSelection
14337 {
14338   GdkEventType type;
14339   GdkWindow *window;
14340   gint8 send_event;
14341   GdkAtom selection;
14342   GdkAtom target;
14343   GdkAtom property;
14344   guint32 requestor;
14345   guint32 time;
14346 };
14347
14348 /* This event type will be used pretty rarely. It only is important
14349    for XInput aware programs that are drawing their own cursor */
14350
14351 struct _GdkEventProximity
14352 {
14353   GdkEventType type;
14354   GdkWindow *window;
14355   gint8 send_event;
14356   guint32 time;
14357   GdkInputSource source;
14358   guint32 deviceid;
14359 };
14360
14361 struct _GdkEventDragRequest
14362 {
14363   GdkEventType type;
14364   GdkWindow *window;
14365   gint8 send_event;
14366   guint32 requestor;
14367   union {
14368     struct {
14369       guint protocol_version:4;
14370       guint sendreply:1;
14371       guint willaccept:1;
14372       guint delete_data:1; /* Do *not* delete if link is sent, only
14373                               if data is sent */
14374       guint senddata:1;
14375       guint reserved:22;
14376     } flags;
14377     glong allflags;
14378   } u;
14379   guint8 isdrop; /* This gdk event can be generated by a couple of
14380                     X events - this lets the app know whether the
14381                     drop really occurred or we just set the data */
14382
14383   GdkPoint drop_coords;
14384   gchar *data_type;
14385   guint32 timestamp;
14386 };
14387
14388 struct _GdkEventDragBegin
14389 {
14390   GdkEventType type;
14391   GdkWindow *window;
14392   gint8 send_event;
14393   union {
14394     struct {
14395       guint protocol_version:4;
14396       guint reserved:28;
14397     } flags;
14398     glong allflags;
14399   } u;
14400 };
14401
14402 struct _GdkEventDropEnter
14403 {
14404   GdkEventType type;
14405   GdkWindow *window;
14406   gint8 send_event;
14407   guint32 requestor;
14408   union {
14409     struct {
14410       guint protocol_version:4;
14411       guint sendreply:1;
14412       guint extended_typelist:1;
14413       guint reserved:26;
14414     } flags;
14415     glong allflags;
14416   } u;
14417 };
14418
14419 struct _GdkEventDropLeave
14420 {
14421   GdkEventType type;
14422   GdkWindow *window;
14423   gint8 send_event;
14424   guint32 requestor;
14425   union {
14426     struct {
14427       guint protocol_version:4;
14428       guint reserved:28;
14429     } flags;
14430     glong allflags;
14431   } u;
14432 };
14433
14434 struct _GdkEventDropDataAvailable
14435 {
14436   GdkEventType type;
14437   GdkWindow *window;
14438   gint8 send_event;
14439   guint32 requestor;
14440   union {
14441     struct {
14442       guint protocol_version:4;
14443       guint isdrop:1;
14444       guint reserved:25;
14445     } flags;
14446     glong allflags;
14447   } u;
14448   gchar *data_type; /* MIME type */
14449   gulong data_numbytes;
14450   gpointer data;
14451   guint32 timestamp;
14452   GdkPoint coords;
14453 };
14454
14455 struct _GdkEventClient
14456 {
14457   GdkEventType type;
14458   GdkWindow *window;
14459   gint8 send_event;
14460   GdkAtom message_type;
14461   gushort data_format;
14462   union {
14463     char b[20];
14464     short s[10];
14465     long l[5];
14466   } data;
14467 };
14468
14469 struct _GdkEventOther
14470 {
14471   GdkEventType type;
14472   GdkWindow *window;
14473   gint8 send_event;
14474   GdkXEvent *xevent;
14475 };
14476 </programlisting>
14477
14478 </appendix>
14479
14480 <!-- ***************************************************************** -->
14481 <appendix id="app-CodeExamples">
14482 <title>Code Examples</title>
14483
14484 <para>Below are the code examples that are used in the above text
14485 which are not included in complete form elsewhere.</para>
14486
14487 <!-- ----------------------------------------------------------------- -->
14488 <sect1 id="sec-Tictactoe">
14489 <title>Tictactoe</title>
14490 <!-- ----------------------------------------------------------------- -->
14491 <sect2>
14492 <title>tictactoe.h</title>
14493
14494 <programlisting role="C">
14495 <!-- example-start tictactoe tictactoe.h -->
14496 /* GTK - The GTK+ Toolkit
14497  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
14498  *
14499  * This library is free software; you can redistribute it and/or
14500  * modify it under the terms of the GNU Library General Public
14501  * License as published by the Free Software Foundation; either
14502  * version 2 of the License, or (at your option) any later version.
14503  *
14504  * This library is distributed in the hope that it will be useful,
14505  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14506  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14507  * Library General Public License for more details.
14508  *
14509  * You should have received a copy of the GNU Library General Public
14510  * License along with this library; if not, write to the
14511  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
14512  * Boston, MA 02111-1307, USA.
14513  */
14514 #ifndef __TICTACTOE_H__
14515 #define __TICTACTOE_H__
14516
14517
14518 #include &lt;glib.h&gt;
14519 #include &lt;glib-object.h&gt;
14520 #include &lt;gtk/gtktable.h&gt;
14521
14522
14523 G_BEGIN_DECLS
14524
14525 #define TICTACTOE_TYPE            (tictactoe_get_type ())
14526 #define TICTACTOE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), TICTACTOE_TYPE, Tictactoe))
14527 #define TICTACTOE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), TICTACTOE_TYPE, TictactoeClass))
14528 #define IS_TICTACTOE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TICTACTOE_TYPE))
14529 #define IS_TICTACTOE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TICTACTOE_TYPE))
14530
14531
14532 typedef struct _Tictactoe       Tictactoe;
14533 typedef struct _TictactoeClass  TictactoeClass;
14534
14535 struct _Tictactoe
14536 {
14537   GtkTable table;
14538   
14539   GtkWidget *buttons[3][3];
14540 };
14541
14542 struct _TictactoeClass
14543 {
14544   GtkTableClass parent_class;
14545
14546   void (* tictactoe) (Tictactoe *ttt);
14547 };
14548
14549 GType          tictactoe_get_type        (void);
14550 GtkWidget*     tictactoe_new             (void);
14551 void           tictactoe_clear           (Tictactoe *ttt);
14552
14553 G_END_DECLS
14554
14555 #endif /* __TICTACTOE_H__ */
14556
14557 <!-- example-end -->
14558 </programlisting>
14559
14560 </sect2>
14561
14562 <!-- ----------------------------------------------------------------- -->
14563 <sect2>
14564 <title>tictactoe.c</title>
14565
14566 <programlisting role="C">
14567 <!-- example-start tictactoe tictactoe.c -->
14568
14569 /* GTK - The GTK+ Toolkit
14570  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
14571  *
14572  * This library is free software; you can redistribute it and/or
14573  * modify it under the terms of the GNU Library General Public
14574  * License as published by the Free Software Foundation; either
14575  * version 2 of the License, or (at your option) any later version.
14576  *
14577  * This library is distributed in the hope that it will be useful,
14578  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14579  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14580  * Library General Public License for more details.
14581  *
14582  * You should have received a copy of the GNU Library General Public
14583  * License along with this library; if not, write to the
14584  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
14585  * Boston, MA 02111-1307, USA.
14586  */
14587 #include &lt;gtk/gtksignal.h&gt;
14588 #include &lt;gtk/gtktable.h&gt;
14589 #include &lt;gtk/gtktogglebutton.h&gt;
14590 #include "tictactoe.h"
14591
14592 enum {
14593   TICTACTOE_SIGNAL,
14594   LAST_SIGNAL
14595 };
14596
14597 static void tictactoe_class_init          (TictactoeClass *klass);
14598 static void tictactoe_init                (Tictactoe      *ttt);
14599 static void tictactoe_toggle              (GtkWidget *widget, Tictactoe *ttt);
14600
14601 static guint tictactoe_signals[LAST_SIGNAL] = { 0 };
14602
14603 GType
14604 tictactoe_get_type (void)
14605 {
14606   static GType ttt_type = 0;
14607
14608   if (!ttt_type)
14609     {
14610       static const GTypeInfo ttt_info =
14611       {
14612         sizeof (TictactoeClass),
14613         NULL, /* base_init */
14614         NULL, /* base_finalize */
14615         (GClassInitFunc) tictactoe_class_init,
14616         NULL, /* class_finalize */
14617         NULL, /* class_data */
14618         sizeof (Tictactoe),
14619         0,
14620         (GInstanceInitFunc) tictactoe_init,
14621       };
14622
14623       ttt_type = g_type_register_static (GTK_TYPE_TABLE, "Tictactoe", &amp;ttt_info, 0);
14624     }
14625
14626   return ttt_type;
14627 }
14628
14629 static void
14630 tictactoe_class_init (TictactoeClass *klass)
14631 {
14632   
14633   tictactoe_signals[TICTACTOE_SIGNAL] = g_signal_new ("tictactoe",
14634                                          G_TYPE_FROM_CLASS (klass),
14635                                          G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
14636                                          G_STRUCT_OFFSET (TictactoeClass, tictactoe),
14637                                          NULL, 
14638                                          NULL,                
14639                                          g_cclosure_marshal_VOID__VOID,
14640                                          G_TYPE_NONE, 0);
14641
14642
14643 }
14644
14645 static void
14646 tictactoe_init (Tictactoe *ttt)
14647 {
14648   gint i,j;
14649   
14650   gtk_table_resize (GTK_TABLE (ttt), 3, 3);
14651   gtk_table_set_homogeneous (GTK_TABLE (ttt), TRUE);
14652
14653   for (i=0;i&lt;3; i++)
14654     for (j=0;j&lt;3; j++)      {
14655         ttt-&gt;buttons[i][j] = gtk_toggle_button_new ();
14656         gtk_table_attach_defaults (GTK_TABLE (ttt), ttt-&gt;buttons[i][j], 
14657                                    i, i+1, j, j+1);
14658         g_signal_connect (G_OBJECT (ttt-&gt;buttons[i][j]), "toggled",
14659                           G_CALLBACK (tictactoe_toggle), (gpointer) ttt);
14660         gtk_widget_set_size_request (ttt-&gt;buttons[i][j], 20, 20);
14661         gtk_widget_show (ttt-&gt;buttons[i][j]);
14662       }
14663 }
14664
14665 GtkWidget*
14666 tictactoe_new ()
14667 {
14668   return GTK_WIDGET (g_object_new (tictactoe_get_type (), NULL));
14669 }
14670
14671 void           
14672 tictactoe_clear (Tictactoe *ttt)
14673 {
14674   int i,j;
14675
14676   for (i = 0; i&lt;3; i++)
14677     for (j = 0; j&lt;3; j++)
14678       {
14679         g_signal_handlers_block_matched (G_OBJECT (ttt-&gt;buttons[i][j]), 
14680                                          G_SIGNAL_MATCH_DATA,
14681                                          0, 0, NULL, NULL, ttt);
14682         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ttt-&gt;buttons[i][j]),
14683                                       FALSE);
14684         g_signal_handlers_unblock_matched (G_OBJECT (ttt->buttons[i][j]),
14685                                            G_SIGNAL_MATCH_DATA,
14686                                            0, 0, NULL, NULL, ttt);
14687       }
14688 }
14689
14690 static void
14691 tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt)
14692 {
14693   int i,k;
14694
14695   static int rwins[8][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
14696                              { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
14697                              { 0, 1, 2 }, { 0, 1, 2 } };
14698   static int cwins[8][3] = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
14699                              { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
14700                              { 0, 1, 2 }, { 2, 1, 0 } };
14701
14702   int success, found;
14703
14704   for (k = 0; k&lt;8; k++)
14705     {
14706       success = TRUE;
14707       found = FALSE;
14708
14709       for (i = 0; i&lt;3; i++)
14710         {
14711           success = success &amp;&amp; 
14712             GTK_TOGGLE_BUTTON (ttt-&gt;buttons[rwins[k][i]][cwins[k][i]])-&gt;active;
14713           found = found ||
14714             ttt-&gt;buttons[rwins[k][i]][cwins[k][i]] == widget;
14715         }
14716       
14717       if (success &amp;&amp; found)
14718         {
14719           g_signal_emit (G_OBJECT (ttt), 
14720                          tictactoe_signals[TICTACTOE_SIGNAL], 0);
14721           break;
14722         }
14723     }
14724 }
14725
14726 <!-- example-end -->
14727 </programlisting>
14728
14729 </sect2>
14730
14731 <!-- ----------------------------------------------------------------- -->
14732 <sect2>
14733 <title>ttt_test.c</title>
14734
14735 <programlisting role="C">
14736 <!-- example-start tictactoe ttt_test.c -->
14737
14738 #include &lt;stdlib.h&gt;
14739 #include &lt;gtk/gtk.h&gt;
14740 #include "tictactoe.h"
14741
14742 void win( GtkWidget *widget,
14743           gpointer   data )
14744 {
14745   g_print ("Yay!\n");
14746   tictactoe_clear (TICTACTOE (widget));
14747 }
14748
14749 int main( int   argc,
14750           char *argv[] )
14751 {
14752   GtkWidget *window;
14753   GtkWidget *ttt;
14754   
14755   gtk_init (&amp;argc, &amp;argv);
14756
14757   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
14758   
14759   gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
14760   
14761   g_signal_connect (G_OBJECT (window), "destroy",
14762                     G_CALLBACK (exit), NULL);
14763   
14764   gtk_container_set_border_width (GTK_CONTAINER (window), 10);
14765
14766   ttt = tictactoe_new ();
14767   
14768   gtk_container_add (GTK_CONTAINER (window), ttt);
14769   gtk_widget_show (ttt);
14770
14771   /* And attach to its "tictactoe" signal */
14772   g_signal_connect (G_OBJECT (ttt), "tictactoe",
14773                     G_CALLBACK (win), NULL);
14774
14775   gtk_widget_show (window);
14776   
14777   gtk_main ();
14778   
14779   return 0;
14780 }
14781
14782 <!-- example-end -->
14783 </programlisting>
14784
14785 </sect2>
14786 </sect1>
14787
14788 <!-- ----------------------------------------------------------------- -->
14789 <sect1 id="sec-GtkDial">
14790 <title>GtkDial</title>
14791
14792 <!-- ----------------------------------------------------------------- -->
14793 <sect2>
14794 <title>gtkdial.h</title>
14795
14796 <programlisting role="C">
14797 <!-- example-start gtkdial gtkdial.h -->
14798
14799 /* GTK - The GTK+ Toolkit
14800  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
14801  *
14802  * This library is free software; you can redistribute it and/or
14803  * modify it under the terms of the GNU Library General Public
14804  * License as published by the Free Software Foundation; either
14805  * version 2 of the License, or (at your option) any later version.
14806  *
14807  * This library is distributed in the hope that it will be useful,
14808  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14809  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14810  * Library General Public License for more details.
14811  *
14812  * You should have received a copy of the GNU Library General Public
14813  * License along with this library; if not, write to the
14814  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
14815  * Boston, MA 02111-1307, USA.
14816  */
14817 #ifndef __GTK_DIAL_H__
14818 #define __GTK_DIAL_H__
14819
14820
14821 #include &lt;gdk/gdk.h&gt;
14822 #include &lt;gtk/gtkadjustment.h&gt;
14823 #include &lt;gtk/gtkwidget.h&gt;
14824
14825
14826 #ifdef __cplusplus
14827 extern "C" {
14828 #endif /* __cplusplus */
14829
14830
14831 #define GTK_DIAL(obj)          GTK_CHECK_CAST (obj, gtk_dial_get_type (), GtkDial)
14832 #define GTK_DIAL_CLASS(klass)  GTK_CHECK_CLASS_CAST (klass, gtk_dial_get_type (), GtkDialClass)
14833 #define GTK_IS_DIAL(obj)       GTK_CHECK_TYPE (obj, gtk_dial_get_type ())
14834
14835
14836 typedef struct _GtkDial        GtkDial;
14837 typedef struct _GtkDialClass   GtkDialClass;
14838
14839 struct _GtkDial
14840 {
14841   GtkWidget widget;
14842
14843   /* update policy (GTK_UPDATE_[CONTINUOUS/DELAYED/DISCONTINUOUS]) */
14844   guint policy : 2;
14845
14846   /* Button currently pressed or 0 if none */
14847   guint8 button;
14848
14849   /* Dimensions of dial components */
14850   gint radius;
14851   gint pointer_width;
14852
14853   /* ID of update timer, or 0 if none */
14854   guint32 timer;
14855
14856   /* Current angle */
14857   gfloat angle;
14858   gfloat last_angle;
14859
14860   /* Old values from adjustment stored so we know when something changes */
14861   gfloat old_value;
14862   gfloat old_lower;
14863   gfloat old_upper;
14864
14865   /* The adjustment object that stores the data for this dial */
14866   GtkAdjustment *adjustment;
14867 };
14868
14869 struct _GtkDialClass
14870 {
14871   GtkWidgetClass parent_class;
14872 };
14873
14874
14875 GtkWidget*     gtk_dial_new                    (GtkAdjustment *adjustment);
14876 GtkType        gtk_dial_get_type               (void);
14877 GtkAdjustment* gtk_dial_get_adjustment         (GtkDial      *dial);
14878 void           gtk_dial_set_update_policy      (GtkDial      *dial,
14879                                                 GtkUpdateType  policy);
14880
14881 void           gtk_dial_set_adjustment         (GtkDial      *dial,
14882                                                 GtkAdjustment *adjustment);
14883 #ifdef __cplusplus
14884 }
14885 #endif /* __cplusplus */
14886
14887
14888 #endif /* __GTK_DIAL_H__ */
14889 <!-- example-end -->
14890 </programlisting>
14891
14892 </sect2>
14893
14894 <!-- ----------------------------------------------------------------- -->
14895 <sect2>
14896 <title>gtkdial.c</title>
14897
14898 <programlisting role="C">
14899 <!-- example-start gtkdial gtkdial.c -->
14900
14901 /* GTK - The GTK+ Toolkit
14902  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
14903  *
14904  * This library is free software; you can redistribute it and/or
14905  * modify it under the terms of the GNU Library General Public
14906  * License as published by the Free Software Foundation; either
14907  * version 2 of the License, or (at your option) any later version.
14908  *
14909  * This library is distributed in the hope that it will be useful,
14910  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14911  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14912  * Library General Public License for more details.
14913  *
14914  * You should have received a copy of the GNU Library General Public
14915  * License along with this library; if not, write to the
14916  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
14917  * Boston, MA 02111-1307, USA.
14918  */
14919 #include &lt;math.h&gt;
14920 #include &lt;stdio.h&gt;
14921 #include &lt;gtk/gtkmain.h&gt;
14922 #include &lt;gtk/gtksignal.h&gt;
14923
14924 #include "gtkdial.h"
14925
14926 #define SCROLL_DELAY_LENGTH  300
14927 #define DIAL_DEFAULT_SIZE 100
14928
14929 /* Forward declarations */
14930
14931 static void gtk_dial_class_init               (GtkDialClass     *klass);
14932 static void gtk_dial_init                     (GtkDial          *dial);
14933 static void gtk_dial_destroy                  (GtkObject        *object);
14934 static void gtk_dial_realize                  (GtkWidget        *widget);
14935 static void gtk_dial_size_request             (GtkWidget        *widget,
14936                                                GtkRequisition   *requisition);
14937 static void gtk_dial_size_allocate            (GtkWidget        *widget,
14938                                                GtkAllocation    *allocation);
14939 static gboolean gtk_dial_expose               (GtkWidget        *widget,
14940                                                GdkEventExpose   *event);
14941 static gboolean gtk_dial_button_press         (GtkWidget        *widget,
14942                                                GdkEventButton   *event);
14943 static gboolean gtk_dial_button_release       (GtkWidget        *widget,
14944                                                GdkEventButton   *event);
14945 static gboolean gtk_dial_motion_notify        (GtkWidget        *widget,
14946                                                GdkEventMotion   *event);
14947 static gboolean gtk_dial_timer                (GtkDial          *dial);
14948
14949 static void gtk_dial_update_mouse             (GtkDial *dial, gint x, gint y);
14950 static void gtk_dial_update                   (GtkDial *dial);
14951 static void gtk_dial_adjustment_changed       (GtkAdjustment    *adjustment,
14952                                                 gpointer          data);
14953 static void gtk_dial_adjustment_value_changed (GtkAdjustment    *adjustment,
14954                                                 gpointer          data);
14955
14956 /* Local data */
14957
14958 static GtkWidgetClass *parent_class = NULL;
14959
14960 GType
14961 gtk_dial_get_type ()
14962 {
14963   static GType dial_type = 0;
14964
14965   if (!dial_type)
14966     {
14967       static const GTypeInfo dial_info =
14968       {
14969         sizeof (GtkDialClass),
14970         NULL,
14971         NULL,
14972         (GClassInitFunc) gtk_dial_class_init,
14973         NULL,
14974         NULL,
14975         sizeof (GtkDial),
14976         0,
14977         (GInstanceInitFunc) gtk_dial_init,
14978       };
14979
14980       dial_type = g_type_register_static (GTK_TYPE_WIDGET, "GtkDial", &amp;dial_info, 0);
14981     }
14982
14983   return dial_type;
14984 }
14985
14986 static void
14987 gtk_dial_class_init (GtkDialClass *class)
14988 {
14989   GtkObjectClass *object_class;
14990   GtkWidgetClass *widget_class;
14991
14992   object_class = (GtkObjectClass*) class;
14993   widget_class = (GtkWidgetClass*) class;
14994
14995   parent_class = gtk_type_class (gtk_widget_get_type ());
14996
14997   object_class-&gt;destroy = gtk_dial_destroy;
14998
14999   widget_class-&gt;realize = gtk_dial_realize;
15000   widget_class-&gt;expose_event = gtk_dial_expose;
15001   widget_class-&gt;size_request = gtk_dial_size_request;
15002   widget_class-&gt;size_allocate = gtk_dial_size_allocate;
15003   widget_class-&gt;button_press_event = gtk_dial_button_press;
15004   widget_class-&gt;button_release_event = gtk_dial_button_release;
15005   widget_class-&gt;motion_notify_event = gtk_dial_motion_notify;
15006 }
15007
15008 static void
15009 gtk_dial_init (GtkDial *dial)
15010 {
15011   dial-&gt;button = 0;
15012   dial-&gt;policy = GTK_UPDATE_CONTINUOUS;
15013   dial-&gt;timer = 0;
15014   dial-&gt;radius = 0;
15015   dial-&gt;pointer_width = 0;
15016   dial-&gt;angle = 0.0;
15017   dial-&gt;old_value = 0.0;
15018   dial-&gt;old_lower = 0.0;
15019   dial-&gt;old_upper = 0.0;
15020   dial-&gt;adjustment = NULL;
15021 }
15022
15023 GtkWidget*
15024 gtk_dial_new (GtkAdjustment *adjustment)
15025 {
15026   GtkDial *dial;
15027
15028   dial = g_object_new (gtk_dial_get_type (), NULL);
15029
15030   if (!adjustment)
15031     adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
15032
15033   gtk_dial_set_adjustment (dial, adjustment);
15034
15035   return GTK_WIDGET (dial);
15036 }
15037
15038 static void
15039 gtk_dial_destroy (GtkObject *object)
15040 {
15041   GtkDial *dial;
15042
15043   g_return_if_fail (object != NULL);
15044   g_return_if_fail (GTK_IS_DIAL (object));
15045
15046   dial = GTK_DIAL (object);
15047
15048   if (dial-&gt;adjustment)
15049     {
15050       g_object_unref (GTK_OBJECT (dial-&gt;adjustment));
15051       dial-&gt;adjustment = NULL;
15052     }
15053
15054   if (GTK_OBJECT_CLASS (parent_class)-&gt;destroy)
15055     (* GTK_OBJECT_CLASS (parent_class)-&gt;destroy) (object);
15056 }
15057
15058 GtkAdjustment*
15059 gtk_dial_get_adjustment (GtkDial *dial)
15060 {
15061   g_return_val_if_fail (dial != NULL, NULL);
15062   g_return_val_if_fail (GTK_IS_DIAL (dial), NULL);
15063
15064   return dial-&gt;adjustment;
15065 }
15066
15067 void
15068 gtk_dial_set_update_policy (GtkDial      *dial,
15069                              GtkUpdateType  policy)
15070 {
15071   g_return_if_fail (dial != NULL);
15072   g_return_if_fail (GTK_IS_DIAL (dial));
15073
15074   dial-&gt;policy = policy;
15075 }
15076
15077 void
15078 gtk_dial_set_adjustment (GtkDial      *dial,
15079                           GtkAdjustment *adjustment)
15080 {
15081   g_return_if_fail (dial != NULL);
15082   g_return_if_fail (GTK_IS_DIAL (dial));
15083
15084   if (dial-&gt;adjustment)
15085     {
15086       g_signal_handlers_disconnect_by_func (GTK_OBJECT (dial-&gt;adjustment), NULL, (gpointer) dial);
15087       g_object_unref (GTK_OBJECT (dial-&gt;adjustment));
15088     }
15089
15090   dial-&gt;adjustment = adjustment;
15091   g_object_ref (GTK_OBJECT (dial-&gt;adjustment));
15092
15093   g_signal_connect (GTK_OBJECT (adjustment), "changed",
15094                     GTK_SIGNAL_FUNC (gtk_dial_adjustment_changed),
15095                     (gpointer) dial);
15096   g_signal_connect (GTK_OBJECT (adjustment), "value_changed",
15097                     GTK_SIGNAL_FUNC (gtk_dial_adjustment_value_changed),
15098                     (gpointer) dial);
15099
15100   dial-&gt;old_value = adjustment-&gt;value;
15101   dial-&gt;old_lower = adjustment-&gt;lower;
15102   dial-&gt;old_upper = adjustment-&gt;upper;
15103
15104   gtk_dial_update (dial);
15105 }
15106
15107 static void
15108 gtk_dial_realize (GtkWidget *widget)
15109 {
15110   GtkDial *dial;
15111   GdkWindowAttr attributes;
15112   gint attributes_mask;
15113
15114   g_return_if_fail (widget != NULL);
15115   g_return_if_fail (GTK_IS_DIAL (widget));
15116
15117   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
15118   dial = GTK_DIAL (widget);
15119
15120   attributes.x = widget-&gt;allocation.x;
15121   attributes.y = widget-&gt;allocation.y;
15122   attributes.width = widget-&gt;allocation.width;
15123   attributes.height = widget-&gt;allocation.height;
15124   attributes.wclass = GDK_INPUT_OUTPUT;
15125   attributes.window_type = GDK_WINDOW_CHILD;
15126   attributes.event_mask = gtk_widget_get_events (widget) | 
15127     GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | 
15128     GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
15129     GDK_POINTER_MOTION_HINT_MASK;
15130   attributes.visual = gtk_widget_get_visual (widget);
15131   attributes.colormap = gtk_widget_get_colormap (widget);
15132
15133   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
15134   widget-&gt;window = gdk_window_new (widget-&gt;parent-&gt;window, &amp;attributes, attributes_mask);
15135
15136   widget-&gt;style = gtk_style_attach (widget-&gt;style, widget-&gt;window);
15137
15138   gdk_window_set_user_data (widget-&gt;window, widget);
15139
15140   gtk_style_set_background (widget-&gt;style, widget-&gt;window, GTK_STATE_ACTIVE);
15141 }
15142
15143 static void 
15144 gtk_dial_size_request (GtkWidget      *widget,
15145                        GtkRequisition *requisition)
15146 {
15147   requisition-&gt;width = DIAL_DEFAULT_SIZE;
15148   requisition-&gt;height = DIAL_DEFAULT_SIZE;
15149 }
15150
15151 static void
15152 gtk_dial_size_allocate (GtkWidget     *widget,
15153                         GtkAllocation *allocation)
15154 {
15155   GtkDial *dial;
15156
15157   g_return_if_fail (widget != NULL);
15158   g_return_if_fail (GTK_IS_DIAL (widget));
15159   g_return_if_fail (allocation != NULL);
15160
15161   widget-&gt;allocation = *allocation;
15162   dial = GTK_DIAL (widget);
15163
15164   if (GTK_WIDGET_REALIZED (widget))
15165     {
15166
15167       gdk_window_move_resize (widget-&gt;window,
15168                               allocation-&gt;x, allocation-&gt;y,
15169                               allocation-&gt;width, allocation-&gt;height);
15170
15171     }
15172   dial-&gt;radius = MIN (allocation-&gt;width, allocation-&gt;height) * 0.45;
15173   dial-&gt;pointer_width = dial-&gt;radius / 5;
15174 }
15175
15176 static gboolean
15177 gtk_dial_expose( GtkWidget      *widget,
15178                  GdkEventExpose *event )
15179 {
15180   GtkDial *dial;
15181   GdkPoint points[6];
15182   gdouble s,c;
15183   gdouble theta, last, increment;
15184   GtkStyle      *blankstyle;
15185   gint xc, yc;
15186   gint upper, lower;
15187   gint tick_length;
15188   gint i, inc;
15189
15190   g_return_val_if_fail (widget != NULL, FALSE);
15191   g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
15192   g_return_val_if_fail (event != NULL, FALSE);
15193
15194   if (event-&gt;count &gt; 0)
15195     return FALSE;
15196   
15197   dial = GTK_DIAL (widget);
15198
15199 /*  gdk_window_clear_area (widget-&gt;window,
15200                          0, 0,
15201                          widget-&gt;allocation.width,
15202                          widget-&gt;allocation.height);
15203 */
15204   xc = widget-&gt;allocation.width / 2;
15205   yc = widget-&gt;allocation.height / 2;
15206
15207   upper = dial-&gt;adjustment-&gt;upper;
15208   lower = dial-&gt;adjustment-&gt;lower;
15209
15210   /* Erase old pointer */
15211
15212   s = sin (dial-&gt;last_angle);
15213   c = cos (dial-&gt;last_angle);
15214   dial-&gt;last_angle = dial-&gt;angle;
15215
15216   points[0].x = xc + s*dial-&gt;pointer_width/2;
15217   points[0].y = yc + c*dial-&gt;pointer_width/2;
15218   points[1].x = xc + c*dial-&gt;radius;
15219   points[1].y = yc - s*dial-&gt;radius;
15220   points[2].x = xc - s*dial-&gt;pointer_width/2;
15221   points[2].y = yc - c*dial-&gt;pointer_width/2;
15222   points[3].x = xc - c*dial-&gt;radius/10;
15223   points[3].y = yc + s*dial-&gt;radius/10;
15224   points[4].x = points[0].x;
15225   points[4].y = points[0].y;
15226
15227   blankstyle = gtk_style_new ();
15228   blankstyle-&gt;bg_gc[GTK_STATE_NORMAL] =
15229                 widget-&gt;style-&gt;bg_gc[GTK_STATE_NORMAL];
15230   blankstyle-&gt;dark_gc[GTK_STATE_NORMAL] =
15231                 widget-&gt;style-&gt;bg_gc[GTK_STATE_NORMAL];
15232   blankstyle-&gt;light_gc[GTK_STATE_NORMAL] =
15233                 widget-&gt;style-&gt;bg_gc[GTK_STATE_NORMAL];
15234   blankstyle-&gt;black_gc =
15235                 widget-&gt;style-&gt;bg_gc[GTK_STATE_NORMAL];
15236
15237   gtk_paint_polygon (blankstyle,
15238                     widget-&gt;window,
15239                     GTK_STATE_NORMAL,
15240                     GTK_SHADOW_OUT,
15241                     NULL,
15242                     widget,
15243                     NULL,
15244                     points, 5,
15245                     FALSE);
15246
15247   g_object_unref (blankstyle);
15248
15249
15250   /* Draw ticks */
15251
15252   if ((upper - lower) == 0)
15253     return FALSE;
15254
15255   increment = (100*M_PI) / (dial-&gt;radius*dial-&gt;radius);
15256
15257   inc = (upper - lower);
15258
15259   while (inc &lt; 100) inc *= 10;
15260   while (inc &gt;= 1000) inc /= 10;
15261   last = -1;
15262
15263   for (i = 0; i &lt;= inc; i++)
15264     {
15265       theta = ((gfloat)i*M_PI / (18*inc/24.) - M_PI/6.);
15266
15267       if ((theta - last) &lt; (increment))
15268         continue;     
15269       last = theta;
15270
15271       s = sin (theta);
15272       c = cos (theta);
15273
15274       tick_length = (i%(inc/10) == 0) ? dial-&gt;pointer_width : dial-&gt;pointer_width / 2;
15275
15276       gdk_draw_line (widget-&gt;window,
15277                      widget-&gt;style-&gt;fg_gc[widget-&gt;state],
15278                      xc + c*(dial-&gt;radius - tick_length),
15279                      yc - s*(dial-&gt;radius - tick_length),
15280                      xc + c*dial-&gt;radius,
15281                      yc - s*dial-&gt;radius);
15282     }
15283
15284   /* Draw pointer */
15285
15286   s = sin (dial-&gt;angle);
15287   c = cos (dial-&gt;angle);
15288   dial-&gt;last_angle = dial-&gt;angle;
15289
15290   points[0].x = xc + s*dial-&gt;pointer_width/2;
15291   points[0].y = yc + c*dial-&gt;pointer_width/2;
15292   points[1].x = xc + c*dial-&gt;radius;
15293   points[1].y = yc - s*dial-&gt;radius;
15294   points[2].x = xc - s*dial-&gt;pointer_width/2;
15295   points[2].y = yc - c*dial-&gt;pointer_width/2;
15296   points[3].x = xc - c*dial-&gt;radius/10;
15297   points[3].y = yc + s*dial-&gt;radius/10;
15298   points[4].x = points[0].x;
15299   points[4].y = points[0].y;
15300
15301
15302   gtk_paint_polygon (widget-&gt;style,
15303                     widget-&gt;window,
15304                     GTK_STATE_NORMAL,
15305                     GTK_SHADOW_OUT,
15306                     NULL,
15307                     widget,
15308                     NULL,
15309                     points, 5,
15310                     TRUE);
15311
15312   return FALSE;
15313 }
15314
15315 static gboolean
15316 gtk_dial_button_press( GtkWidget      *widget,
15317                        GdkEventButton *event )
15318 {
15319   GtkDial *dial;
15320   gint dx, dy;
15321   double s, c;
15322   double d_parallel;
15323   double d_perpendicular;
15324
15325   g_return_val_if_fail (widget != NULL, FALSE);
15326   g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
15327   g_return_val_if_fail (event != NULL, FALSE);
15328
15329   dial = GTK_DIAL (widget);
15330
15331   /* Determine if button press was within pointer region - we 
15332      do this by computing the parallel and perpendicular distance of
15333      the point where the mouse was pressed from the line passing through
15334      the pointer */
15335   
15336   dx = event-&gt;x - widget-&gt;allocation.width / 2;
15337   dy = widget-&gt;allocation.height / 2 - event-&gt;y;
15338   
15339   s = sin (dial-&gt;angle);
15340   c = cos (dial-&gt;angle);
15341   
15342   d_parallel = s*dy + c*dx;
15343   d_perpendicular = fabs (s*dx - c*dy);
15344   
15345   if (!dial-&gt;button &amp;&amp;
15346       (d_perpendicular &lt; dial-&gt;pointer_width/2) &amp;&amp;
15347       (d_parallel &gt; - dial-&gt;pointer_width))
15348     {
15349       gtk_grab_add (widget);
15350
15351       dial-&gt;button = event-&gt;button;
15352
15353       gtk_dial_update_mouse (dial, event-&gt;x, event-&gt;y);
15354     }
15355
15356   return FALSE;
15357 }
15358
15359 static gboolean
15360 gtk_dial_button_release( GtkWidget      *widget,
15361                          GdkEventButton *event )
15362 {
15363   GtkDial *dial;
15364
15365   g_return_val_if_fail (widget != NULL, FALSE);
15366   g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
15367   g_return_val_if_fail (event != NULL, FALSE);
15368
15369   dial = GTK_DIAL (widget);
15370
15371   if (dial-&gt;button == event-&gt;button)
15372     {
15373       gtk_grab_remove (widget);
15374
15375       dial-&gt;button = 0;
15376
15377       if (dial-&gt;policy == GTK_UPDATE_DELAYED)
15378         g_source_remove (dial-&gt;timer);
15379       
15380       if ((dial-&gt;policy != GTK_UPDATE_CONTINUOUS) &amp;&amp;
15381           (dial-&gt;old_value != dial-&gt;adjustment-&gt;value))
15382         g_signal_emit_by_name (GTK_OBJECT (dial-&gt;adjustment), "value_changed");
15383     }
15384
15385   return FALSE;
15386 }
15387
15388 static gboolean
15389 gtk_dial_motion_notify( GtkWidget      *widget,
15390                         GdkEventMotion *event )
15391 {
15392   GtkDial *dial;
15393   GdkModifierType mods;
15394   gint x, y, mask;
15395
15396   g_return_val_if_fail (widget != NULL, FALSE);
15397   g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
15398   g_return_val_if_fail (event != NULL, FALSE);
15399
15400   dial = GTK_DIAL (widget);
15401
15402   if (dial-&gt;button != 0)
15403     {
15404       x = event-&gt;x;
15405       y = event-&gt;y;
15406
15407       if (event-&gt;is_hint || (event-&gt;window != widget-&gt;window))
15408         gdk_window_get_pointer (widget-&gt;window, &amp;x, &amp;y, &amp;mods);
15409
15410       switch (dial-&gt;button)
15411         {
15412         case 1:
15413           mask = GDK_BUTTON1_MASK;
15414           break;
15415         case 2:
15416           mask = GDK_BUTTON2_MASK;
15417           break;
15418         case 3:
15419           mask = GDK_BUTTON3_MASK;
15420           break;
15421         default:
15422           mask = 0;
15423           break;
15424         }
15425
15426       if (mods &amp; mask)
15427         gtk_dial_update_mouse (dial, x,y);
15428     }
15429
15430   return FALSE;
15431 }
15432
15433 static gboolean
15434 gtk_dial_timer( GtkDial *dial )
15435 {
15436   g_return_val_if_fail (dial != NULL, FALSE);
15437   g_return_val_if_fail (GTK_IS_DIAL (dial), FALSE);
15438
15439   if (dial-&gt;policy == GTK_UPDATE_DELAYED)
15440     g_signal_emit_by_name (GTK_OBJECT (dial-&gt;adjustment), "value_changed");
15441
15442   return FALSE;
15443 }
15444
15445 static void
15446 gtk_dial_update_mouse( GtkDial *dial, gint x, gint y )
15447 {
15448   gint xc, yc;
15449   gfloat old_value;
15450
15451   g_return_if_fail (dial != NULL);
15452   g_return_if_fail (GTK_IS_DIAL (dial));
15453
15454   xc = GTK_WIDGET(dial)-&gt;allocation.width / 2;
15455   yc = GTK_WIDGET(dial)-&gt;allocation.height / 2;
15456
15457   old_value = dial-&gt;adjustment-&gt;value;
15458   dial-&gt;angle = atan2(yc-y, x-xc);
15459
15460   if (dial-&gt;angle &lt; -M_PI/2.)
15461     dial-&gt;angle += 2*M_PI;
15462
15463   if (dial-&gt;angle &lt; -M_PI/6)
15464     dial-&gt;angle = -M_PI/6;
15465
15466   if (dial-&gt;angle &gt; 7.*M_PI/6.)
15467     dial-&gt;angle = 7.*M_PI/6.;
15468
15469   dial-&gt;adjustment-&gt;value = dial-&gt;adjustment-&gt;lower + (7.*M_PI/6 - dial-&gt;angle) *
15470     (dial-&gt;adjustment-&gt;upper - dial-&gt;adjustment-&gt;lower) / (4.*M_PI/3.);
15471
15472   if (dial-&gt;adjustment-&gt;value != old_value)
15473     {
15474       if (dial-&gt;policy == GTK_UPDATE_CONTINUOUS)
15475         {
15476           g_signal_emit_by_name (GTK_OBJECT (dial-&gt;adjustment), "value_changed");
15477         }
15478       else
15479         {
15480           gtk_widget_queue_draw (GTK_WIDGET (dial));
15481
15482           if (dial-&gt;policy == GTK_UPDATE_DELAYED)
15483             {
15484               if (dial-&gt;timer)
15485                 g_source_remove (dial-&gt;timer);
15486
15487               dial-&gt;timer = g_timeout_add (SCROLL_DELAY_LENGTH,
15488                                            (GtkFunction) gtk_dial_timer,
15489                                            (gpointer) dial);
15490             }
15491         }
15492     }
15493 }
15494
15495 static void
15496 gtk_dial_update (GtkDial *dial)
15497 {
15498   gfloat new_value;
15499   
15500   g_return_if_fail (dial != NULL);
15501   g_return_if_fail (GTK_IS_DIAL (dial));
15502
15503   new_value = dial-&gt;adjustment-&gt;value;
15504   
15505   if (new_value &lt; dial-&gt;adjustment-&gt;lower)
15506     new_value = dial-&gt;adjustment-&gt;lower;
15507
15508   if (new_value &gt; dial-&gt;adjustment-&gt;upper)
15509     new_value = dial-&gt;adjustment-&gt;upper;
15510
15511   if (new_value != dial-&gt;adjustment-&gt;value)
15512     {
15513       dial-&gt;adjustment-&gt;value = new_value;
15514       g_signal_emit_by_name (GTK_OBJECT (dial-&gt;adjustment), "value_changed");
15515     }
15516
15517   dial-&gt;angle = 7.*M_PI/6. - (new_value - dial-&gt;adjustment-&gt;lower) * 4.*M_PI/3. /
15518     (dial-&gt;adjustment-&gt;upper - dial-&gt;adjustment-&gt;lower);
15519
15520   gtk_widget_queue_draw (GTK_WIDGET (dial));
15521 }
15522
15523 static void
15524 gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
15525                               gpointer       data)
15526 {
15527   GtkDial *dial;
15528
15529   g_return_if_fail (adjustment != NULL);
15530   g_return_if_fail (data != NULL);
15531
15532   dial = GTK_DIAL (data);
15533
15534   if ((dial-&gt;old_value != adjustment-&gt;value) ||
15535       (dial-&gt;old_lower != adjustment-&gt;lower) ||
15536       (dial-&gt;old_upper != adjustment-&gt;upper))
15537     {
15538       gtk_dial_update (dial);
15539
15540       dial-&gt;old_value = adjustment-&gt;value;
15541       dial-&gt;old_lower = adjustment-&gt;lower;
15542       dial-&gt;old_upper = adjustment-&gt;upper;
15543     }
15544 }
15545
15546 static void
15547 gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
15548                                     gpointer       data)
15549 {
15550   GtkDial *dial;
15551
15552   g_return_if_fail (adjustment != NULL);
15553   g_return_if_fail (data != NULL);
15554
15555   dial = GTK_DIAL (data);
15556
15557   if (dial-&gt;old_value != adjustment-&gt;value)
15558     {
15559       gtk_dial_update (dial);
15560
15561       dial-&gt;old_value = adjustment-&gt;value;
15562     }
15563 }
15564 <!-- example-end -->
15565 </programlisting>
15566
15567 </sect2>
15568
15569 <!-- ----------------------------------------------------------------- -->
15570 <sect2>
15571 <title>dial_test.c</title>
15572
15573 <programlisting role="C">
15574 <!-- example-start gtkdial dial_test.c -->
15575
15576 #include &lt;stdio.h&gt;
15577 #include &lt;stdlib.h&gt;
15578 #include &lt;gtk/gtk.h&gt;
15579 #include "gtkdial.h"
15580
15581 void value_changed( GtkAdjustment *adjustment,
15582                     GtkWidget     *label )
15583 {
15584   char buffer[16];
15585
15586   sprintf(buffer,"%4.2f",adjustment-&gt;value);
15587   gtk_label_set_text (GTK_LABEL (label), buffer);
15588 }
15589
15590 int main( int   argc,
15591           char *argv[])
15592 {
15593   GtkWidget *window;
15594   GtkAdjustment *adjustment;
15595   GtkWidget *dial;
15596   GtkWidget *frame;
15597   GtkWidget *vbox;
15598   GtkWidget *label;
15599   
15600   gtk_init (&amp;argc, &amp;argv);
15601
15602   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
15603   
15604   gtk_window_set_title (GTK_WINDOW (window), "Dial");
15605   
15606   g_signal_connect (G_OBJECT (window), "destroy",
15607                     G_CALLBACK (exit), NULL);
15608   
15609   gtk_container_set_border_width (GTK_CONTAINER (window), 10);
15610
15611   vbox = gtk_vbox_new (FALSE, 5);
15612   gtk_container_add (GTK_CONTAINER (window), vbox);
15613   gtk_widget_show (vbox);
15614
15615   frame = gtk_frame_new (NULL);
15616   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
15617   gtk_container_add (GTK_CONTAINER (vbox), frame);
15618   gtk_widget_show (frame); 
15619  
15620   adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0, 0, 100, 0.01, 0.1, 0));
15621   
15622   dial = gtk_dial_new (adjustment);
15623   gtk_dial_set_update_policy (GTK_DIAL (dial), GTK_UPDATE_DELAYED);
15624   /*  gtk_widget_set_size_request (dial, 100, 100); */
15625   
15626   gtk_container_add (GTK_CONTAINER (frame), dial);
15627   gtk_widget_show (dial);
15628
15629   label = gtk_label_new ("0.00");
15630   gtk_box_pack_end (GTK_BOX (vbox), label, 0, 0, 0);
15631   gtk_widget_show (label);
15632
15633   g_signal_connect (G_OBJECT (adjustment), "value_changed",
15634                     G_CALLBACK (value_changed), (gpointer) label);
15635   
15636   gtk_widget_show (window);
15637   
15638   gtk_main ();
15639   
15640   return 0;
15641 }
15642 <!-- example-end -->
15643 </programlisting>
15644
15645 </sect2>
15646 </sect1>
15647
15648 <!-- ----------------------------------------------------------------- -->
15649 <sect1 id="sec-Scribble">
15650 <title>Scribble</title>
15651
15652 <!-- ----------------------------------------------------------------- -->
15653 <sect2>
15654 <title>scribble-simple.c</title>
15655
15656 <programlisting role="C">
15657 <!-- example-start scribble-simple scribble-simple.c -->
15658
15659 /* GTK - The GTK+ Toolkit
15660  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
15661  *
15662  * This library is free software; you can redistribute it and/or
15663  * modify it under the terms of the GNU Library General Public
15664  * License as published by the Free Software Foundation; either
15665  * version 2 of the License, or (at your option) any later version.
15666  *
15667  * This library is distributed in the hope that it will be useful,
15668  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15669  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15670  * Library General Public License for more details.
15671  *
15672  * You should have received a copy of the GNU Library General Public
15673  * License along with this library; if not, write to the
15674  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
15675  * Boston, MA 02111-1307, USA.
15676  */
15677
15678 #include &lt;stdlib.h&gt;
15679 #include &lt;gtk/gtk.h&gt;
15680
15681 /* Backing pixmap for drawing area */
15682 static GdkPixmap *pixmap = NULL;
15683
15684 /* Create a new backing pixmap of the appropriate size */
15685 static gboolean configure_event( GtkWidget         *widget,
15686                                  GdkEventConfigure *event )
15687 {
15688   if (pixmap)
15689     g_object_unref (pixmap);
15690
15691   pixmap = gdk_pixmap_new (widget-&gt;window,
15692                            widget-&gt;allocation.width,
15693                            widget-&gt;allocation.height,
15694                            -1);
15695   gdk_draw_rectangle (pixmap,
15696                       widget-&gt;style-&gt;white_gc,
15697                       TRUE,
15698                       0, 0,
15699                       widget-&gt;allocation.width,
15700                       widget-&gt;allocation.height);
15701
15702   return TRUE;
15703 }
15704
15705 /* Redraw the screen from the backing pixmap */
15706 static gboolean expose_event( GtkWidget      *widget,
15707                               GdkEventExpose *event )
15708 {
15709   gdk_draw_drawable (widget-&gt;window,
15710                      widget-&gt;style-&gt;fg_gc[GTK_WIDGET_STATE (widget)],
15711                      pixmap,
15712                      event-&gt;area.x, event-&gt;area.y,
15713                      event-&gt;area.x, event-&gt;area.y,
15714                      event-&gt;area.width, event-&gt;area.height);
15715
15716   return FALSE;
15717 }
15718
15719 /* Draw a rectangle on the screen */
15720 static void draw_brush( GtkWidget *widget,
15721                         gdouble    x,
15722                         gdouble    y)
15723 {
15724   GdkRectangle update_rect;
15725
15726   update_rect.x = x - 5;
15727   update_rect.y = y - 5;
15728   update_rect.width = 10;
15729   update_rect.height = 10;
15730   gdk_draw_rectangle (pixmap,
15731                       widget-&gt;style-&gt;black_gc,
15732                       TRUE,
15733                       update_rect.x, update_rect.y,
15734                       update_rect.width, update_rect.height);
15735   gtk_widget_queue_draw_area (widget, 
15736                               update_rect.x, update_rect.y,
15737                               update_rect.width, update_rect.height);
15738 }
15739
15740 static gboolean button_press_event( GtkWidget      *widget,
15741                                     GdkEventButton *event )
15742 {
15743   if (event-&gt;button == 1 &amp;&amp; pixmap != NULL)
15744     draw_brush (widget, event-&gt;x, event-&gt;y);
15745
15746   return TRUE;
15747 }
15748
15749 static gboolean motion_notify_event( GtkWidget *widget,
15750                                      GdkEventMotion *event )
15751 {
15752   int x, y;
15753   GdkModifierType state;
15754
15755   if (event-&gt;is_hint)
15756     gdk_window_get_pointer (event-&gt;window, &amp;x, &amp;y, &amp;state);
15757   else
15758     {
15759       x = event-&gt;x;
15760       y = event-&gt;y;
15761       state = event-&gt;state;
15762     }
15763     
15764   if (state &amp; GDK_BUTTON1_MASK &amp;&amp; pixmap != NULL)
15765     draw_brush (widget, x, y);
15766   
15767   return TRUE;
15768 }
15769
15770 void quit ()
15771 {
15772   exit (0);
15773 }
15774
15775 int main( int   argc, 
15776           char *argv[] )
15777 {
15778   GtkWidget *window;
15779   GtkWidget *drawing_area;
15780   GtkWidget *vbox;
15781
15782   GtkWidget *button;
15783
15784   gtk_init (&amp;argc, &amp;argv);
15785
15786   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
15787   gtk_widget_set_name (window, "Test Input");
15788
15789   vbox = gtk_vbox_new (FALSE, 0);
15790   gtk_container_add (GTK_CONTAINER (window), vbox);
15791   gtk_widget_show (vbox);
15792
15793   g_signal_connect (G_OBJECT (window), "destroy",
15794                     G_CALLBACK (quit), NULL);
15795
15796   /* Create the drawing area */
15797
15798   drawing_area = gtk_drawing_area_new ();
15799   gtk_widget_set_size_request (GTK_WIDGET (drawing_area), 200, 200);
15800   gtk_box_pack_start (GTK_BOX (vbox), drawing_area, TRUE, TRUE, 0);
15801
15802   gtk_widget_show (drawing_area);
15803
15804   /* Signals used to handle backing pixmap */
15805
15806   g_signal_connect (G_OBJECT (drawing_area), "expose_event",
15807                     G_CALLBACK (expose_event), NULL);
15808   g_signal_connect (G_OBJECT (drawing_area),"configure_event",
15809                     G_CALLBACK (configure_event), NULL);
15810
15811   /* Event signals */
15812
15813   g_signal_connect (G_OBJECT (drawing_area), "motion_notify_event",
15814                     G_CALLBACK (motion_notify_event), NULL);
15815   g_signal_connect (G_OBJECT (drawing_area), "button_press_event",
15816                     G_CALLBACK (button_press_event), NULL);
15817
15818   gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
15819                          | GDK_LEAVE_NOTIFY_MASK
15820                          | GDK_BUTTON_PRESS_MASK
15821                          | GDK_POINTER_MOTION_MASK
15822                          | GDK_POINTER_MOTION_HINT_MASK);
15823
15824   /* .. And a quit button */
15825   button = gtk_button_new_with_label ("Quit");
15826   gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
15827
15828   g_signal_connect_swapped (G_OBJECT (button), "clicked",
15829                             G_CALLBACK (gtk_widget_destroy),
15830                             G_OBJECT (window));
15831   gtk_widget_show (button);
15832
15833   gtk_widget_show (window);
15834
15835   gtk_main ();
15836
15837   return 0;
15838 }
15839 <!-- example-end -->
15840 </programlisting>
15841
15842 </sect2>
15843
15844 <!-- ----------------------------------------------------------------- -->
15845 <sect2>
15846 <title>scribble-xinput.c</title>
15847
15848 <programlisting role="C">
15849 <!-- example-start scribble-xinput scribble-xinput.c -->
15850
15851 /* GTK - The GTK+ Toolkit
15852  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
15853  *
15854  * This library is free software; you can redistribute it and/or
15855  * modify it under the terms of the GNU Library General Public
15856  * License as published by the Free Software Foundation; either
15857  * version 2 of the License, or (at your option) any later version.
15858  *
15859  * This library is distributed in the hope that it will be useful,
15860  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15861  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15862  * Library General Public License for more details.
15863  *
15864  * You should have received a copy of the GNU Library General Public
15865  * License along with this library; if not, write to the
15866  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
15867  * Boston, MA 02111-1307, USA.
15868  */
15869
15870 #include &lt;gtk/gtk.h&gt;
15871
15872 /* Backing pixmap for drawing area */
15873 static GdkPixmap *pixmap = NULL;
15874
15875 /* Create a new backing pixmap of the appropriate size */
15876 static gboolean
15877 configure_event (GtkWidget *widget, GdkEventConfigure *event)
15878 {
15879   if (pixmap)
15880      g_object_unref (pixmap);
15881
15882   pixmap = gdk_pixmap_new (widget-&gt;window,
15883                            widget-&gt;allocation.width,
15884                            widget-&gt;allocation.height,
15885                            -1);
15886   gdk_draw_rectangle (pixmap,
15887                       widget-&gt;style-&gt;white_gc,
15888                       TRUE,
15889                       0, 0,
15890                       widget-&gt;allocation.width,
15891                       widget-&gt;allocation.height);
15892
15893   return TRUE;
15894 }
15895
15896 /* Redraw the screen from the backing pixmap */
15897 static gboolean
15898 expose_event (GtkWidget *widget, GdkEventExpose *event)
15899 {
15900   gdk_draw_drawable (widget-&gt;window,
15901                      widget-&gt;style-&gt;fg_gc[GTK_WIDGET_STATE (widget)],
15902                      pixmap,
15903                      event-&gt;area.x, event-&gt;area.y,
15904                      event-&gt;area.x, event-&gt;area.y,
15905                      event-&gt;area.width, event-&gt;area.height);
15906
15907   return FALSE;
15908 }
15909
15910 /* Draw a rectangle on the screen, size depending on pressure,
15911    and color on the type of device */
15912 static void
15913 draw_brush (GtkWidget *widget, GdkInputSource source,
15914             gdouble x, gdouble y, gdouble pressure)
15915 {
15916   GdkGC *gc;
15917   GdkRectangle update_rect;
15918
15919   switch (source)
15920     {
15921     case GDK_SOURCE_MOUSE:
15922       gc = widget-&gt;style-&gt;dark_gc[GTK_WIDGET_STATE (widget)];
15923       break;
15924     case GDK_SOURCE_PEN:
15925       gc = widget-&gt;style-&gt;black_gc;
15926       break;
15927     case GDK_SOURCE_ERASER:
15928       gc = widget-&gt;style-&gt;white_gc;
15929       break;
15930     default:
15931       gc = widget-&gt;style-&gt;light_gc[GTK_WIDGET_STATE (widget)];
15932     }
15933
15934   update_rect.x = x - 10 * pressure;
15935   update_rect.y = y - 10 * pressure;
15936   update_rect.width = 20 * pressure;
15937   update_rect.height = 20 * pressure;
15938   gdk_draw_rectangle (pixmap, gc, TRUE,
15939                       update_rect.x, update_rect.y,
15940                       update_rect.width, update_rect.height);
15941   gtk_widget_queue_draw_area (widget, 
15942                       update_rect.x, update_rect.y,
15943                       update_rect.width, update_rect.height);
15944 }
15945
15946 static void
15947 print_button_press (GdkDevice *device)
15948 {
15949   g_print ("Button press on device '%s'\n", device-&gt;name);
15950 }
15951
15952 static gboolean
15953 button_press_event (GtkWidget *widget, GdkEventButton *event)
15954 {
15955   print_button_press (event-&gt;device);
15956   
15957   if (event-&gt;button == 1 &amp;&amp; pixmap != NULL) {
15958     gdouble pressure;
15959     gdk_event_get_axis ((GdkEvent *)event, GDK_AXIS_PRESSURE, &amp;pressure);
15960     draw_brush (widget, event-&gt;device-&gt;source, event-&gt;x, event-&gt;y, pressure);
15961   }
15962
15963   return TRUE;
15964 }
15965
15966 static gboolean
15967 motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
15968 {
15969   gdouble x, y;
15970   gdouble pressure;
15971   GdkModifierType state;
15972
15973   if (event-&gt;is_hint) 
15974     {
15975       gdk_device_get_state (event-&gt;device, event-&gt;window, NULL, &amp;state);
15976       gdk_event_get_axis ((GdkEvent *)event, GDK_AXIS_X, &amp;x);
15977       gdk_event_get_axis ((GdkEvent *)event, GDK_AXIS_Y, &amp;y);
15978       gdk_event_get_axis ((GdkEvent *)event, GDK_AXIS_PRESSURE, &amp;pressure);
15979     }
15980   else
15981     {
15982       x = event-&gt;x;
15983       y = event-&gt;y;
15984       gdk_event_get_axis ((GdkEvent *)event, GDK_AXIS_PRESSURE, &amp;pressure);
15985       state = event-&gt;state;
15986     }
15987     
15988   if (state &amp; GDK_BUTTON1_MASK &amp;&amp; pixmap != NULL)
15989     draw_brush (widget, event-&gt;device-&gt;source, x, y, pressure);
15990   
15991   return TRUE;
15992 }
15993
15994 void
15995 input_dialog_destroy (GtkWidget *w, gpointer data)
15996 {
15997   *((GtkWidget **)data) = NULL;
15998 }
15999
16000 void
16001 create_input_dialog ()
16002 {
16003   static GtkWidget *inputd = NULL;
16004
16005   if (!inputd)
16006     {
16007       inputd = gtk_input_dialog_new();
16008
16009       g_signal_connect (G_OBJECT (inputd), "destroy",
16010                         G_CALLBACK (input_dialog_destroy), (gpointer) &amp;inputd);
16011       g_signal_connect_swapped (G_OBJECT (GTK_INPUT_DIALOG (inputd)-&gt;close_button),
16012                                 "clicked",
16013                                 G_CALLBACK (gtk_widget_hide),
16014                                 G_OBJECT (inputd));
16015       gtk_widget_hide (GTK_INPUT_DIALOG (inputd)-&gt;save_button);
16016
16017       gtk_widget_show (inputd);
16018     }
16019   else
16020     {
16021       if (!GTK_WIDGET_MAPPED (inputd))
16022         gtk_widget_show (inputd);
16023       else
16024         gdk_window_raise (inputd-&gt;window);
16025     }
16026 }
16027
16028 void
16029 int
16030 main (int argc, char *argv[])
16031 {
16032   GtkWidget *window;
16033   GtkWidget *drawing_area;
16034   GtkWidget *vbox;
16035
16036   GtkWidget *button;
16037
16038   gtk_init (&amp;argc, &amp;argv);
16039
16040   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
16041   gtk_widget_set_name (window, "Test Input");
16042
16043   vbox = gtk_vbox_new (FALSE, 0);
16044   gtk_container_add (GTK_CONTAINER (window), vbox);
16045   gtk_widget_show (vbox);
16046
16047   g_signal_connect (G_OBJECT (window), "destroy",
16048                     G_CALLBACK (gtk_main_quit), NULL);
16049
16050   /* Create the drawing area */
16051
16052   drawing_area = gtk_drawing_area_new ();
16053   gtk_widget_set_size_request (GTK_WIDGET (drawing_area), 200, 200);
16054   gtk_box_pack_start (GTK_BOX (vbox), drawing_area, TRUE, TRUE, 0);
16055
16056   gtk_widget_show (drawing_area);
16057
16058   /* Signals used to handle backing pixmap */
16059
16060   g_signal_connect (G_OBJECT (drawing_area), "expose_event",
16061                     G_CALLBACK (expose_event), NULL);
16062   g_signal_connect (G_OBJECT(drawing_area),"configure_event",
16063                     G_CALLBACK (configure_event), NULL);
16064
16065   /* Event signals */
16066
16067   g_signal_connect (G_OBJECT (drawing_area), "motion_notify_event",
16068                     G_CALLBACK (motion_notify_event), NULL);
16069   g_signal_connect (G_OBJECT (drawing_area), "button_press_event",
16070                     G_CALLBACK (button_press_event), NULL);
16071
16072   gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
16073                          | GDK_LEAVE_NOTIFY_MASK
16074                          | GDK_BUTTON_PRESS_MASK
16075                          | GDK_POINTER_MOTION_MASK
16076                          | GDK_POINTER_MOTION_HINT_MASK);
16077
16078   /* The following call enables tracking and processing of extension
16079      events for the drawing area */
16080   gtk_widget_set_extension_events (drawing_area, GDK_EXTENSION_EVENTS_CURSOR);
16081
16082   /* .. And some buttons */
16083   button = gtk_button_new_with_label ("Input Dialog");
16084   gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
16085
16086   g_signal_connect (G_OBJECT (button), "clicked",
16087                     G_CALLBACK (create_input_dialog), NULL);
16088   gtk_widget_show (button);
16089
16090   button = gtk_button_new_with_label ("Quit");
16091   gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
16092
16093   g_signal_connect_swapped (G_OBJECT (button), "clicked",
16094                             G_CALLBACK (gtk_widget_destroy),
16095                             G_OBJECT (window));
16096   gtk_widget_show (button);
16097
16098   gtk_widget_show (window);
16099
16100   gtk_main ();
16101
16102   return 0;
16103 }
16104 <!-- example-end -->
16105 </programlisting>
16106
16107 </sect2>
16108 </sect1>
16109
16110 </appendix>
16111 </book>