]> Pileus Git - ~andy/gtk/commitdiff
Initial DocBook version. Lots of cleaning up to do.
authorBST 2000 Tony Gale <gale@dera.gov.uk>
Mon, 17 Jul 2000 13:02:05 +0000 (13:02 +0000)
committerTony Gale <gale@src.gnome.org>
Mon, 17 Jul 2000 13:02:05 +0000 (13:02 +0000)
Mon Jul 17 13:59:29 BST 2000  Tony Gale <gale@dera.gov.uk>

        * docs/tutorial/gtk-tut.sgml: Initial DocBook version. Lots
          of cleaning up to do.

ChangeLog
ChangeLog.pre-2-0
ChangeLog.pre-2-10
ChangeLog.pre-2-2
ChangeLog.pre-2-4
ChangeLog.pre-2-6
ChangeLog.pre-2-8
docs/tutorial/gtk-tut.sgml [new file with mode: 0755]

index 0e64680b04efc77b9ba3fd3584bf7c8122b7639d..5b4b34bef2fc368f526a62f078c07887029ce6a0 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+Mon Jul 17 13:59:29 BST 2000  Tony Gale <gale@dera.gov.uk>
+
+       * docs/tutorial/gtk-tut.sgml: Initial DocBook version. Lots
+         of cleaning up to do.
+
 2000-07-15  Tor Lillqvist  <tml@iki.fi>
 
        * gdk/testgdk.c: New file, quick hack to test backends for
index 0e64680b04efc77b9ba3fd3584bf7c8122b7639d..5b4b34bef2fc368f526a62f078c07887029ce6a0 100644 (file)
@@ -1,3 +1,8 @@
+Mon Jul 17 13:59:29 BST 2000  Tony Gale <gale@dera.gov.uk>
+
+       * docs/tutorial/gtk-tut.sgml: Initial DocBook version. Lots
+         of cleaning up to do.
+
 2000-07-15  Tor Lillqvist  <tml@iki.fi>
 
        * gdk/testgdk.c: New file, quick hack to test backends for
index 0e64680b04efc77b9ba3fd3584bf7c8122b7639d..5b4b34bef2fc368f526a62f078c07887029ce6a0 100644 (file)
@@ -1,3 +1,8 @@
+Mon Jul 17 13:59:29 BST 2000  Tony Gale <gale@dera.gov.uk>
+
+       * docs/tutorial/gtk-tut.sgml: Initial DocBook version. Lots
+         of cleaning up to do.
+
 2000-07-15  Tor Lillqvist  <tml@iki.fi>
 
        * gdk/testgdk.c: New file, quick hack to test backends for
index 0e64680b04efc77b9ba3fd3584bf7c8122b7639d..5b4b34bef2fc368f526a62f078c07887029ce6a0 100644 (file)
@@ -1,3 +1,8 @@
+Mon Jul 17 13:59:29 BST 2000  Tony Gale <gale@dera.gov.uk>
+
+       * docs/tutorial/gtk-tut.sgml: Initial DocBook version. Lots
+         of cleaning up to do.
+
 2000-07-15  Tor Lillqvist  <tml@iki.fi>
 
        * gdk/testgdk.c: New file, quick hack to test backends for
index 0e64680b04efc77b9ba3fd3584bf7c8122b7639d..5b4b34bef2fc368f526a62f078c07887029ce6a0 100644 (file)
@@ -1,3 +1,8 @@
+Mon Jul 17 13:59:29 BST 2000  Tony Gale <gale@dera.gov.uk>
+
+       * docs/tutorial/gtk-tut.sgml: Initial DocBook version. Lots
+         of cleaning up to do.
+
 2000-07-15  Tor Lillqvist  <tml@iki.fi>
 
        * gdk/testgdk.c: New file, quick hack to test backends for
index 0e64680b04efc77b9ba3fd3584bf7c8122b7639d..5b4b34bef2fc368f526a62f078c07887029ce6a0 100644 (file)
@@ -1,3 +1,8 @@
+Mon Jul 17 13:59:29 BST 2000  Tony Gale <gale@dera.gov.uk>
+
+       * docs/tutorial/gtk-tut.sgml: Initial DocBook version. Lots
+         of cleaning up to do.
+
 2000-07-15  Tor Lillqvist  <tml@iki.fi>
 
        * gdk/testgdk.c: New file, quick hack to test backends for
index 0e64680b04efc77b9ba3fd3584bf7c8122b7639d..5b4b34bef2fc368f526a62f078c07887029ce6a0 100644 (file)
@@ -1,3 +1,8 @@
+Mon Jul 17 13:59:29 BST 2000  Tony Gale <gale@dera.gov.uk>
+
+       * docs/tutorial/gtk-tut.sgml: Initial DocBook version. Lots
+         of cleaning up to do.
+
 2000-07-15  Tor Lillqvist  <tml@iki.fi>
 
        * gdk/testgdk.c: New file, quick hack to test backends for
diff --git a/docs/tutorial/gtk-tut.sgml b/docs/tutorial/gtk-tut.sgml
new file mode 100755 (executable)
index 0000000..0fa1ebe
--- /dev/null
@@ -0,0 +1,19364 @@
+<!doctype book PUBLIC "-//OASIS//DTD DocBook V3.1//EN" []>
+<book>
+
+<bookinfo>
+    <date>July 15th 2000</date>
+    <title>GTK+ 1.2 Tutorial</title>
+    <authorgroup>
+      <author>
+       <firstname>Tony</firstname>
+       <surname>Gale</surname>
+      </author>
+      <author>
+       <firstname>Ian</firstname>
+       <surname>Main</surname>
+      </author>
+    </authorgroup>
+    <abstract>
+      <para> This is a tutorial on how to use GTK (the GIMP Toolkit) through its C
+       interface.</para>
+    </abstract>
+  </bookinfo>
+
+<toc></toc>
+
+<!-- ***************************************************************** -->
+<chapter id="ch-Introduction">
+<title>Introduction</title>
+
+<para>GTK (GIMP Toolkit) is a library for creating graphical user
+interfaces. It is licensed using the LGPL license, so you can develop
+open software, free software, or even commercial non-free software
+using GTK without having to spend anything for licenses or royalties.</para>
+
+<para>It's called the GIMP toolkit because it was originally written for
+developing the GNU Image Manipulation Program (GIMP), but GTK has
+now been used in a large number of software projects, including the
+GNU Network Object Model Environment (GNOME) project. GTK is built on
+top of GDK (GIMP Drawing Kit) which is basically a wrapper around the
+low-level functions for accessing the underlying windowing functions
+(Xlib in the case of the X windows system). The primary authors of GTK
+are:</para>
+
+<itemizedlist>
+<listitem><simpara> Peter Mattis <ulink url="mailto:petm@xcf.berkeley.edu">
+petm@xcf.berkeley.edu</ulink></simpara>
+</listitem>
+<listitem><simpara> Spencer Kimball <ulink url="mailto:spencer@xcf.berkeley.edu">
+spencer@xcf.berkeley.edu</ulink></simpara>
+</listitem>
+<listitem><simpara> Josh MacDonald <ulink url="mailto:jmacd@xcf.berkeley.edu">
+jmacd@xcf.berkeley.edu</ulink></simpara>
+</listitem>
+</itemizedlist>
+
+<para>GTK is essentially an object oriented application programmers
+interface (API). Although written completely in C, it is implemented
+using the idea of classes and callback functions (pointers to
+functions).</para>
+
+<para>There is also a third component called GLib which contains a few
+replacements for some standard calls, as well as some additional
+functions for handling linked lists, etc. The replacement functions
+are used to increase GTK's portability, as some of the functions
+implemented here are not available or are nonstandard on other unixes
+such as g_strerror(). Some also contain enhancements to the libc
+versions, such as g_malloc that has enhanced debugging utilities.</para>
+
+<para>This tutorial describes the C interface to GTK. There are GTK
+bindings for many other languages including C++, Guile, Perl, Python,
+TOM, Ada95, Objective C, Free Pascal, and Eiffel. If you intend to
+use another language's bindings to GTK, look at that binding's
+documentation first. In some cases that documentation may describe
+some important conventions (which you should know first) and then
+refer you back to this tutorial. There are also some cross-platform
+APIs (such as wxWindows and V) which use GTK as one of their target
+platforms; again, consult their documentation first.</para>
+
+<para>If you're developing your GTK application in C++, a few extra notes
+are in order. There's a C++ binding to GTK called GTK--, which
+provides a more C++-like interface to GTK; you should probably look
+into this instead. If you don't like that approach for whatever
+reason, there are two alternatives for using GTK. First, you can use
+only the C subset of C++ when interfacing with GTK and then use the C
+interface as described in this tutorial. Second, you can use GTK and
+C++ together by declaring all callbacks as static functions in C++
+classes, and again calling GTK using its C interface. If you choose
+this last approach, you can include as the callback's data value a
+pointer to the object to be manipulated (the so-called "this" value).
+Selecting between these options is simply a matter of preference,
+since in all three approaches you get C++ and GTK. None of these
+approaches requires the use of a specialized preprocessor, so no
+matter what you choose you can use standard C++ with GTK.</para>
+
+<para>This tutorial is an attempt to document as much as possible of GTK,
+but it is by no means complete. This tutorial assumes a good
+understanding of C, and how to create C programs. It would be a great
+benefit for the reader to have previous X programming experience, but
+it shouldn't be necessary. If you are learning GTK as your first
+widget set, please comment on how you found this tutorial, and what
+you had trouble with. There are also C++, Objective C, ADA, Guile and
+other language bindings available, but I don't follow these.</para>
+
+<para>This document is a "work in progress". Please look for updates on
+<ulink url="http://www.gtk.org/">http://www.gtk.org/</ulink>.</para>
+
+<para>I would very much like to hear of any problems you have learning GTK
+from this document, and would appreciate input as to how it may be
+improved. Please see the section on <link linkend="ch-Contributing">Contributing
+</link> for further information.</para>
+
+</chapter>
+
+<!-- ***************************************************************** -->
+<chapter id="ch-GettingStarted">
+<title>Getting Started</title>
+
+<para>The first thing to do, of course, is download the GTK source and
+install it. You can always get the latest version from ftp.gtk.org in
+/pub/gtk. You can also view other sources of GTK information on
+<ulink url="http://www.gtk.org/">http://www.gtk.org/</ulink>. GTK
+uses GNU autoconf for configuration. Once untar'd, type ./configure
+--help to see a list of options.</para>
+
+<para>The GTK source distribution also contains the complete source to all
+of the examples used in this tutorial, along with Makefiles to aid
+compilation.</para>
+
+<para>To begin our introduction to GTK, we'll start with the simplest
+program possible. This program will create a 200x200 pixel window and
+has no way of exiting except to be killed by using the shell.</para>
+
+<programlisting role="C">
+/* example-start base base.c */
+
+#include &lt;gtk/gtk.h&gt;
+
+int main( int   argc,
+          char *argv[] )
+{
+    GtkWidget *window;
+    
+    gtk_init (&amp;argc, &amp;argv);
+    
+    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+    gtk_widget_show  (window);
+    
+    gtk_main ();
+    
+    return(0);
+}
+/* example-end */
+</programlisting>
+
+<para>You can compile the above program with gcc using:</para>
+<para><literallayout>
+<literal>gcc base.c -o base `gtk-config --cflags --libs`</literal>
+</literallayout></para>
+
+<para>The meaning of the unusual compilation options is explained below in
+<link linkend="ch-Compiling">Compiling Hello World</link>.</para>
+
+<para>All programs will of course include gtk/gtk.h which declares the
+variables, functions, structures, etc. that will be used in your GTK
+application.</para>
+
+<para>The next line:</para>
+
+<para><literallayout>
+<literal>gtk_init (&amp;argc, &amp;argv);</literal>
+</literallayout></para>
+
+<para>calls the function gtk_init(gint *argc, gchar ***argv) which will be
+called in all GTK applications. This sets up a few things for us such
+as the default visual and color map and then proceeds to call
+gdk_init(gint *argc, gchar ***argv). This function initializes the
+library for use, sets up default signal handlers, and checks the
+arguments passed to your application on the command line, looking for
+one of the following:</para>
+
+<itemizedlist spacing=Compact>
+<listitem><simpara> <literal>--gtk-module</literal></simpara>
+</listitem>
+<listitem><simpara> <literal>--g-fatal-warnings</literal></simpara>
+</listitem>
+<listitem><simpara> <literal>--gtk-debug</literal></simpara>
+</listitem>
+<listitem><simpara> <literal>--gtk-no-debug</literal></simpara>
+</listitem>
+<listitem><simpara> <literal>--gdk-debug</literal></simpara>
+</listitem>
+<listitem><simpara> <literal>--gdk-no-debug</literal></simpara>
+</listitem>
+<listitem><simpara> <literal>--display</literal></simpara>
+</listitem>
+<listitem><simpara> <literal>--sync</literal></simpara>
+</listitem>
+<listitem><simpara> <literal>--no-xshm</literal></simpara>
+</listitem>
+<listitem><simpara> <literal>--name</literal></simpara>
+</listitem>
+<listitem><simpara> <literal>--class</literal></simpara>
+</listitem>
+</itemizedlist>
+
+<para>It removes these from the argument list, leaving anything it does not
+recognize for your application to parse or ignore. This creates a set
+of standard arguments accepted by all GTK applications.</para>
+
+<para>The next two lines of code create and display a window.</para>
+
+<para><literallayout>
+<literal>  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);</literal>
+<literal>  gtk_widget_show (window);</literal>
+</literallayout></para>
+
+<para>The <literal>GTK_WINDOW_TOPLEVEL</literal> argument specifies that we want the
+window to undergo window manager decoration and placement. Rather than
+create a window of 0x0 size, a window without children is set to
+200x200 by default so you can still manipulate it.</para>
+
+<para>The gtk_widget_show() function lets GTK know that we are done setting
+the attributes of this widget, and that it can display it.</para>
+
+<para>The last line enters the GTK main processing loop.</para>
+
+<para><literallayout>
+<literal>  gtk_main ();</literal>
+</literallayout></para>
+
+<para>gtk_main() is another call you will see in every GTK application.
+When control reaches this point, GTK will sleep waiting for X events
+(such as button or key presses), timeouts, or file IO notifications to
+occur. In our simple example, however, events are ignored.</para>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Hello World in GTK</title>
+
+<para>Now for a program with a widget (a button). It's the classic
+hello world a la GTK.</para>
+
+<programlisting role="C">
+/* example-start helloworld helloworld.c */
+
+#include &lt;gtk/gtk.h&gt;
+
+/* This is a callback function. The data arguments are ignored
+ * in this example. More on callbacks below. */
+void hello( GtkWidget *widget,
+            gpointer   data )
+{
+    g_print ("Hello World\n");
+}
+
+gint delete_event( GtkWidget *widget,
+                   GdkEvent  *event,
+                  gpointer   data )
+{
+    /* If you return FALSE in the "delete_event" signal handler,
+     * GTK will emit the "destroy" signal. Returning TRUE means
+     * you don't want the window to be destroyed.
+     * This is useful for popping up 'are you sure you want to quit?'
+     * type dialogs. */
+
+    g_print ("delete event occurred\n");
+
+    /* Change TRUE to FALSE and the main window will be destroyed with
+     * a "delete_event". */
+
+    return(TRUE);
+}
+
+/* Another callback */
+void destroy( GtkWidget *widget,
+              gpointer   data )
+{
+    gtk_main_quit();
+}
+
+int main( int   argc,
+          char *argv[] )
+{
+    /* GtkWidget is the storage type for widgets */
+    GtkWidget *window;
+    GtkWidget *button;
+    
+    /* This is called in all GTK applications. Arguments are parsed
+     * from the command line and are returned to the application. */
+    gtk_init(&amp;argc, &amp;argv);
+    
+    /* create a new window */
+    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+    
+    /* When the window is given the "delete_event" signal (this is given
+     * by the window manager, usually by the "close" option, or on the
+     * titlebar), we ask it to call the delete_event () function
+     * as defined above. The data passed to the callback
+     * function is NULL and is ignored in the callback function. */
+    gtk_signal_connect (GTK_OBJECT (window), "delete_event",
+                       GTK_SIGNAL_FUNC (delete_event), NULL);
+    
+    /* Here we connect the "destroy" event to a signal handler.  
+     * This event occurs when we call gtk_widget_destroy() on the window,
+     * or if we return FALSE in the "delete_event" callback. */
+    gtk_signal_connect (GTK_OBJECT (window), "destroy",
+                       GTK_SIGNAL_FUNC (destroy), NULL);
+    
+    /* Sets the border width of the window. */
+    gtk_container_set_border_width (GTK_CONTAINER (window), 10);
+    
+    /* Creates a new button with the label "Hello World". */
+    button = gtk_button_new_with_label ("Hello World");
+    
+    /* When the button receives the "clicked" signal, it will call the
+     * function hello() passing it NULL as its argument.  The hello()
+     * function is defined above. */
+    gtk_signal_connect (GTK_OBJECT (button), "clicked",
+                       GTK_SIGNAL_FUNC (hello), NULL);
+    
+    /* This will cause the window to be destroyed by calling
+     * gtk_widget_destroy(window) when "clicked".  Again, the destroy
+     * signal could come from here, or the window manager. */
+    gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+                              GTK_SIGNAL_FUNC (gtk_widget_destroy),
+                              GTK_OBJECT (window));
+    
+    /* This packs the button into the window (a gtk container). */
+    gtk_container_add (GTK_CONTAINER (window), button);
+    
+    /* The final step is to display this newly created widget. */
+    gtk_widget_show (button);
+    
+    /* and the window */
+    gtk_widget_show (window);
+    
+    /* All GTK applications must have a gtk_main(). Control ends here
+     * and waits for an event to occur (like a key press or
+     * mouse event). */
+    gtk_main ();
+    
+    return(0);
+}
+/* example-end */
+</programlisting>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Compiling Hello World</title>
+
+<para>To compile use:</para>
+
+<para><literallayout>
+<literal>gcc -Wall -g helloworld.c -o helloworld `gtk-config --cflags` \</literal>
+<literal>    `gtk-config --libs`</literal>
+</literallayout></para>
+
+<para>This uses the program <literal>gtk-config</literal>, which comes with GTK. This
+program "knows" what compiler switches are needed to compile programs
+that use GTK. <literal>gtk-config --cflags</literal> will output a list of include
+directories for the compiler to look in, and <literal>gtk-config --libs</>
+will output the list of libraries for the compiler to link with and
+the directories to find them in. In the above example they could have
+been combined into a single instance, such as
+<literal>`gtk-config --cflags --libs`</literal>.</para>
+
+<para>Note that the type of single quote used in the compile command above
+is significant.</para>
+
+<para>The libraries that are usually linked in are:</para>
+
+<itemizedlist>
+<listitem><simpara>The GTK library (-lgtk), the widget library, based on top of GDK.</simpara>
+</listitem>
+
+<listitem><simpara>The GDK library (-lgdk), the Xlib wrapper.</simpara>
+</listitem>
+
+<listitem><simpara>The gmodule library (-lgmodule), which is used to load run time
+extensions.</simpara>
+</listitem>
+
+<listitem><simpara>The GLib library (-lglib), containing miscellaneous functions;
+only g_print() is used in this particular example. GTK is built on top
+of glib so you will always require this library. See the section on
+<link linkend="ch-glib">GLib</link> for details.</simpara>
+</listitem>
+
+<listitem><simpara>The Xlib library (-lX11) which is used by GDK.</simpara>
+</listitem>
+
+<listitem><simpara>The Xext library (-lXext). This contains code for shared memory
+pixmaps and other X extensions.</simpara>
+</listitem>
+
+<listitem><simpara>The math library (-lm). This is used by GTK for various
+purposes.</simpara>
+</listitem>
+</itemizedlist>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Theory of Signals and Callbacks</title>
+
+<para>Before we look in detail at <emphasis>helloworld</emphasis>, we'll discuss signals
+and callbacks. GTK is an event driven toolkit, which means it will
+sleep in gtk_main until an event occurs and control is passed to the
+appropriate function.</para>
+
+<para>This passing of control is done using the idea of "signals". (Note
+that these signals are not the same as the Unix system signals, and
+are not implemented using them, although the terminology is almost
+identical.) When an event occurs, such as the press of a mouse button,
+the appropriate signal will be "emitted" by the widget that was
+pressed.  This is how GTK does most of its useful work. There are
+signals that all widgets inherit, such as "destroy", and there are
+signals that are widget specific, such as "toggled" on a toggle
+button.</para>
+
+<para>To make a button perform an action, we set up a signal handler to
+catch these signals and call the appropriate function. This is done by
+using a function such as:</para>
+
+<para><literallayout>
+<literal>gint gtk_signal_connect( GtkObject     *object,
+                         gchar         *name,
+                         GtkSignalFunc  func,
+                         gpointer       func_data );</literal>
+</literallayout></para>
+
+<para>where the first argument is the widget which will be emitting the
+signal, and the second the name of the signal you wish to catch. The
+third is the function you wish to be called when it is caught, and the
+fourth, the data you wish to have passed to this function.</para>
+
+<para>The function specified in the third argument is called a "callback
+function", and should generally be of the form</para>
+
+<para><literallayout>
+<literal>void callback_func( GtkWidget *widget,
+                    gpointer   callback_data );</literal>
+</literallayout></para>
+
+<para>where the first argument will be a pointer to the widget that emitted
+the signal, and the second a pointer to the data given as the last
+argument to the gtk_signal_connect() function as shown above.</para>
+
+<para>Note that the above form for a signal callback function declaration is
+only a general guide, as some widget specific signals generate
+different calling parameters. For example, the CList "select_row"
+signal provides both row and column parameters.</para>
+
+<para>Another call used in the <emphasis>helloworld</emphasis> example, is:</para>
+
+<para><literallayout>
+<literal>gint gtk_signal_connect_object( GtkObject     *object,
+                                gchar         *name,
+                                GtkSignalFunc  func,
+                                GtkObject     *slot_object );</literal>
+</literallayout></para>
+
+<para>gtk_signal_connect_object() is the same as gtk_signal_connect() except
+that the callback function only uses one argument, a pointer to a GTK
+object. So when using this function to connect signals, the callback
+should be of the form</para>
+
+<para><literallayout>
+<literal>void callback_func( GtkObject *object );</literal>
+</literallayout></para>
+
+<para>where the object is usually a widget. We usually don't setup callbacks
+for gtk_signal_connect_object however. They are usually used to call a
+GTK function that accepts a single widget or object as an argument, as
+is the case in our <emphasis>helloworld</emphasis> example.</para>
+
+<para>The purpose of having two functions to connect signals is simply to
+allow the callbacks to have a different number of arguments. Many
+functions in the GTK library accept only a single GtkWidget pointer as
+an argument, so you want to use the gtk_signal_connect_object() for
+these, whereas for your functions, you may need to have additional
+data supplied to the callbacks.</para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Events</title>
+
+<para>In addition to the signal mechanism described above, there is a set
+of <emphasis>events</emphasis> that reflect the X event mechanism. Callbacks may
+also be attached to these events. These events are:</para>
+
+<itemizedlist spacing=Compact>
+<listitem><simpara> event</simpara>
+</listitem>
+<listitem><simpara> button_press_event</simpara>
+</listitem>
+<listitem><simpara> button_release_event</simpara>
+</listitem>
+<listitem><simpara> motion_notify_event</simpara>
+</listitem>
+<listitem><simpara> delete_event</simpara>
+</listitem>
+<listitem><simpara> destroy_event</simpara>
+</listitem>
+<listitem><simpara> expose_event</simpara>
+</listitem>
+<listitem><simpara> key_press_event</simpara>
+</listitem>
+<listitem><simpara> key_release_event</simpara>
+</listitem>
+<listitem><simpara> enter_notify_event</simpara>
+</listitem>
+<listitem><simpara> leave_notify_event</simpara>
+</listitem>
+<listitem><simpara> configure_event</simpara>
+</listitem>
+<listitem><simpara> focus_in_event</simpara>
+</listitem>
+<listitem><simpara> focus_out_event</simpara>
+</listitem>
+<listitem><simpara> map_event</simpara>
+</listitem>
+<listitem><simpara> unmap_event</simpara>
+</listitem>
+<listitem><simpara> property_notify_event</simpara>
+</listitem>
+<listitem><simpara> selection_clear_event</simpara>
+</listitem>
+<listitem><simpara> selection_request_event</simpara>
+</listitem>
+<listitem><simpara> selection_notify_event</simpara>
+</listitem>
+<listitem><simpara> proximity_in_event</simpara>
+</listitem>
+<listitem><simpara> proximity_out_event</simpara>
+</listitem>
+<listitem><simpara> drag_begin_event</simpara>
+</listitem>
+<listitem><simpara> drag_request_event</simpara>
+</listitem>
+<listitem><simpara> drag_end_event</simpara>
+</listitem>
+<listitem><simpara> drop_enter_event</simpara>
+</listitem>
+<listitem><simpara> drop_leave_event</simpara>
+</listitem>
+<listitem><simpara> drop_data_available_event</simpara>
+</listitem>
+<listitem><simpara> other_event</simpara>
+</listitem>
+</itemizedlist>
+
+<para>In order to connect a callback function to one of these events, you
+use the function gtk_signal_connect, as described above, using one of
+the above event names as the <literal>name</literal> parameter. The callback
+function for events has a slightly different form than that for
+signals:</para>
+
+<para><literallayout>
+<literal>void callback_func( GtkWidget *widget,
+                    GdkEvent  *event,
+                    gpointer   callback_data );</literal>
+</literallayout></para>
+
+<para>GdkEvent is a C <literal>union</literal> structure whose type will depend upon which
+of the above events has occurred. In order for us to tell which event
+has been issued each of the possible alternatives has a <literal>type</literal>
+parameter which reflects the event being issued. The other components
+of the event structure will depend upon the type of the
+event. Possible values for the type are:</para>
+
+<programlisting role="C">
+  GDK_NOTHING
+  GDK_DELETE
+  GDK_DESTROY
+  GDK_EXPOSE
+  GDK_MOTION_NOTIFY
+  GDK_BUTTON_PRESS
+  GDK_2BUTTON_PRESS
+  GDK_3BUTTON_PRESS
+  GDK_BUTTON_RELEASE
+  GDK_KEY_PRESS
+  GDK_KEY_RELEASE
+  GDK_ENTER_NOTIFY
+  GDK_LEAVE_NOTIFY
+  GDK_FOCUS_CHANGE
+  GDK_CONFIGURE
+  GDK_MAP
+  GDK_UNMAP
+  GDK_PROPERTY_NOTIFY
+  GDK_SELECTION_CLEAR
+  GDK_SELECTION_REQUEST
+  GDK_SELECTION_NOTIFY
+  GDK_PROXIMITY_IN
+  GDK_PROXIMITY_OUT
+  GDK_DRAG_BEGIN
+  GDK_DRAG_REQUEST
+  GDK_DROP_ENTER
+  GDK_DROP_LEAVE
+  GDK_DROP_DATA_AVAIL
+  GDK_CLIENT_EVENT
+  GDK_VISIBILITY_NOTIFY
+  GDK_NO_EXPOSE
+  GDK_OTHER_EVENT      /* Deprecated, use filters instead */
+</programlisting>
+
+<para>So, to connect a callback function to one of these events we would use
+something like:</para>
+
+<para><literallayout>
+<literal>gtk_signal_connect( GTK_OBJECT(button), "button_press_event",
+                    GTK_SIGNAL_FUNC(button_press_callback), 
+                   NULL);</literal>
+</literallayout></para>
+
+<para>This assumes that <literal>button</literal> is a Button widget. Now, when the
+mouse is over the button and a mouse button is pressed, the function
+<literal>button_press_callback</literal> will be called. This function may be
+declared as:</para>
+
+<para><literallayout>
+<literal>static gint button_press_callback( GtkWidget      *widget, 
+                                   GdkEventButton *event,
+                                   gpointer        data );</literal>
+</literallayout></para>
+
+<para>Note that we can declare the second argument as type
+<literal>GdkEventButton</literal> as we know what type of event will occur for this
+function to be called.</para>
+
+<para>The value returned from this function indicates whether the event
+should be propagated further by the GTK event handling
+mechanism. Returning TRUE indicates that the event has been handled,
+and that it should not propagate further. Returning FALSE continues
+the normal event handling.  See the section on
+<link linkend="ch-AdvEventsAndSignals">Advanced Event and Signal Handling</link> for more details on this
+propagation process.</para>
+
+<para>For details on the GdkEvent data types, see the appendix entitled
+<link linkend="ch-GDKEventTypes">GDK Event Types</link>.</para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Stepping Through Hello World</title>
+
+<para>Now that we know the theory behind this, let's clarify by walking
+through the example <emphasis>helloworld</emphasis> program.</para>
+
+<para>Here is the callback function that will be called when the button is
+"clicked". We ignore both the widget and the data in this example, but
+it is not hard to do things with them. The next example will use the
+data argument to tell us which button was pressed.</para>
+
+<programlisting role="C">
+void hello( GtkWidget *widget,
+            gpointer   data )
+{
+    g_print ("Hello World\n");
+}
+</programlisting>
+
+<para>The next callback is a bit special. The "delete_event" occurs when the
+window manager sends this event to the application. We have a choice
+here as to what to do about these events. We can ignore them, make
+some sort of response, or simply quit the application.</para>
+
+<para>The value you return in this callback lets GTK know what action to
+take.  By returning TRUE, we let it know that we don't want to have
+the "destroy" signal emitted, keeping our application running. By
+returning FALSE, we ask that "destroy" be emitted, which in turn will
+call our "destroy" signal handler.</para>
+
+
+<programlisting role="C">
+gint delete_event( GtkWidget *widget,
+                   GdkEvent  *event,
+                  gpointer   data )
+{
+    g_print ("delete event occurred\n");
+
+    return (TRUE); 
+}
+</programlisting>
+
+<para>Here is another callback function which causes the program to quit by
+calling gtk_main_quit(). This function tells GTK that it is to exit
+from gtk_main when control is returned to it.</para>
+
+<programlisting role="C">
+void destroy( GtkWidget *widget,
+              gpointer   data )
+{
+    gtk_main_quit ();
+}
+</programlisting>
+
+<para>I assume you know about the main() function... yes, as with other
+applications, all GTK applications will also have one of these.</para>
+
+<programlisting role="C">
+int main( int   argc,
+          char *argv[] )
+{
+</programlisting>
+
+<para>This next part declares pointers to a structure of type
+GtkWidget. These are used below to create a window and a button.</para>
+
+<programlisting role="C">
+    GtkWidget *window;
+    GtkWidget *button;
+</programlisting>
+
+<para>Here is our gtk_init again. As before, this initializes the toolkit,
+and parses the arguments found on the command line. Any argument it
+recognizes from the command line, it removes from the list, and
+modifies argc and argv to make it look like they never existed,
+allowing your application to parse the remaining arguments.</para>
+
+<programlisting role="C">
+    gtk_init (&amp;argc, &amp;argv);
+</programlisting>
+
+<para>Create a new window. This is fairly straightforward. Memory is
+allocated for the GtkWidget *window structure so it now points to a
+valid structure. It sets up a new window, but it is not displayed
+until we call gtk_widget_show(window) near the end of our program.</para>
+
+<programlisting role="C">
+    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+</programlisting>
+
+<para>Here are two examples of connecting a signal handler to an object, in
+this case, the window. Here, the "delete_event" and "destroy" signals
+are caught. The first is emitted when we use the window manager to
+kill the window, or when we use the gtk_widget_destroy() call passing
+in the window widget as the object to destroy. The second is emitted
+when, in the "delete_event" handler, we return FALSE.
+The <literal>GTK_OBJECT</literal> and <literal>GTK_SIGNAL_FUNC</literal> are macros that perform
+type casting and checking for us, as well as aid the readability of
+the code.</para>
+
+<programlisting role="C">
+    gtk_signal_connect (GTK_OBJECT (window), "delete_event",
+                        GTK_SIGNAL_FUNC (delete_event), NULL);
+    gtk_signal_connect (GTK_OBJECT (window), "destroy",
+                        GTK_SIGNAL_FUNC (destroy), NULL);
+</programlisting>
+
+<para>This next function is used to set an attribute of a container object.
+This just sets the window so it has a blank area along the inside of
+it 10 pixels wide where no widgets will go. There are other similar
+functions which we will look at in the section on
+<link linkend="ch-SettingWidgetAttributes">Setting Widget Attributes</link></para>
+
+<para>And again, <literal>GTK_CONTAINER</literal> is a macro to perform type casting.</para>
+
+<programlisting role="C">
+    gtk_container_set_border_width (GTK_CONTAINER (window), 10);
+</programlisting>
+
+<para>This call creates a new button. It allocates space for a new GtkWidget
+structure in memory, initializes it, and makes the button pointer
+point to it. It will have the label "Hello World" on it when
+displayed.</para>
+
+<programlisting role="C">
+    button = gtk_button_new_with_label ("Hello World");
+</programlisting>
+
+<para>Here, we take this button, and make it do something useful. We attach
+a signal handler to it so when it emits the "clicked" signal, our
+hello() function is called. The data is ignored, so we simply pass in
+NULL to the hello() callback function. Obviously, the "clicked" signal
+is emitted when we click the button with our mouse pointer.</para>
+
+<programlisting role="C">
+    gtk_signal_connect (GTK_OBJECT (button), "clicked",
+                        GTK_SIGNAL_FUNC (hello), NULL);
+</programlisting>
+
+<para>We are also going to use this button to exit our program. This will
+illustrate how the "destroy" signal may come from either the window
+manager, or our program. When the button is "clicked", same as above,
+it calls the first hello() callback function, and then this one in the
+order they are set up. You may have as many callback functions as you
+need, and all will be executed in the order you connected
+them. Because the gtk_widget_destroy() function accepts only a
+GtkWidget *widget as an argument, we use the
+gtk_signal_connect_object() function here instead of straight
+gtk_signal_connect().</para>
+
+<programlisting role="C">
+    gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+                               GTK_SIGNAL_FUNC (gtk_widget_destroy),
+                               GTK_OBJECT (window));
+</programlisting>
+
+<para>This is a packing call, which will be explained in depth later on in
+<link linkend="ch-PackingWidgets">Packing Widgets</link>. But it is
+fairly easy to understand. It simply tells GTK that the button is to
+be placed in the window where it will be displayed. Note that a GTK
+container can only contain one widget. There are other widgets, that
+are described later, which are designed to layout multiple widgets in
+various ways.
+ </para>
+
+<programlisting role="C">
+    gtk_container_add (GTK_CONTAINER (window), button);
+</programlisting>
+
+<para>Now we have everything set up the way we want it to be. With all the
+signal handlers in place, and the button placed in the window where it
+should be, we ask GTK to "show" the widgets on the screen. The window
+widget is shown last so the whole window will pop up at once rather
+than seeing the window pop up, and then the button form inside of
+it. Although with such a simple example, you'd never notice.</para>
+
+<programlisting role="C">
+    gtk_widget_show (button);
+
+    gtk_widget_show (window);
+</programlisting>
+
+<para>And of course, we call gtk_main() which waits for events to come from
+the X server and will call on the widgets to emit signals when these
+events come.</para>
+
+<programlisting role="C">
+    gtk_main ();
+</programlisting>
+
+<para>And the final return. Control returns here after gtk_quit() is called.</para>
+
+<programlisting role="C">
+    return (0);
+</programlisting>
+
+<para>Now, when we click the mouse button on a GTK button, the widget emits
+a "clicked" signal. In order for us to use this information, our
+program sets up a signal handler to catch that signal, which
+dispatches the function of our choice. In our example, when the button
+we created is "clicked", the hello() function is called with a NULL
+argument, and then the next handler for this signal is called. This
+calls the gtk_widget_destroy() function, passing it the window widget
+as its argument, destroying the window widget. This causes the window
+to emit the "destroy" signal, which is caught, and calls our destroy()
+callback function, which simply exits GTK.</para>
+
+<para>Another course of events is to use the window manager to kill the
+window, which will cause the "delete_event" to be emitted. This will
+call our "delete_event" handler. If we return TRUE here, the window
+will be left as is and nothing will happen. Returning FALSE will cause
+GTK to emit the "destroy" signal which of course calls the "destroy"
+callback, exiting GTK.</para>
+
+</sect1>
+</chapter>
+
+<!-- ***************************************************************** -->
+<chapter id="ch-MovingOn">
+<title>Moving On</title>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Data Types</title>
+
+<para>There are a few things you probably noticed in the previous examples
+that need explaining. The gint, gchar, etc. that you see are typedefs
+to int and char, respectively, that are part of the GLlib system. This
+is done to get around that nasty dependency on the size of simple data
+types when doing calculations.</para>
+
+<para>A good example is "gint32" which will be typedef'd to a 32 bit integer
+for any given platform, whether it be the 64 bit alpha, or the 32 bit
+i386. The typedefs are very straightforward and intuitive. They are
+all defined in glib/glib.h (which gets included from gtk.h).</para>
+
+<para>You'll also notice GTK's ability to use GtkWidget when the function
+calls for an Object. GTK is an object oriented design, and a widget
+is an object.</para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>More on Signal Handlers</title>
+
+<para>Lets take another look at the gtk_signal_connect declaration.</para>
+
+<programlisting role="C">
+gint gtk_signal_connect( GtkObject *object,
+                         gchar *name,
+                         GtkSignalFunc func,
+                         gpointer func_data );
+</programlisting>
+
+<para>Notice the gint return value? This is a tag that identifies your
+callback function. As stated above, you may have as many callbacks per
+signal and per object as you need, and each will be executed in turn,
+in the order they were attached.</para>
+
+<para>This tag allows you to remove this callback from the list by using:</para>
+
+<programlisting role="C">
+void gtk_signal_disconnect( GtkObject *object,
+                            gint id );
+</programlisting>
+
+<para>So, by passing in the widget you wish to remove the handler from, and
+the tag returned by one of the signal_connect functions, you can
+disconnect a signal handler.</para>
+
+<para>You can also temporarily disable signal handlers with the
+gtk_signal_handler_block() and gtk_signal_handler_unblock() family of
+functions.</para>
+
+<programlisting role="C">
+void gtk_signal_handler_block( GtkObject *object,
+                               guint      handler_id );
+
+void gtk_signal_handler_block_by_func( GtkObject     *object,
+                                       GtkSignalFunc  func,
+                                       gpointer       data );
+
+void gtk_signal_handler_block_by_data( GtkObject *object,
+                                       gpointer   data );
+
+void gtk_signal_handler_unblock( GtkObject *object,
+                                 guint      handler_id );
+
+void gtk_signal_handler_unblock_by_func( GtkObject     *object,
+                                         GtkSignalFunc  func,
+                                         gpointer       data );
+
+void gtk_signal_handler_unblock_by_data( GtkObject *object,
+                                         gpointer   data);
+</programlisting>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>An Upgraded Hello World</title>
+
+<para>Let's take a look at a slightly improved <emphasis>helloworld</emphasis> with
+better examples of callbacks. This will also introduce us to our next
+topic, packing widgets.</para>
+
+<programlisting role="C">
+/* example-start helloworld2 helloworld2.c */
+
+#include &lt;gtk/gtk.h&gt;
+
+/* Our new improved callback.  The data passed to this function
+ * is printed to stdout. */
+void callback( GtkWidget *widget,
+               gpointer   data )
+{
+    g_print ("Hello again - %s was pressed\n", (char *) data);
+}
+
+/* another callback */
+gint delete_event( GtkWidget *widget,
+                   GdkEvent  *event,
+                   gpointer   data )
+{
+    gtk_main_quit();
+    return(FALSE);
+}
+
+int main( int   argc,
+          char *argv[] )
+{
+    /* GtkWidget is the storage type for widgets */
+    GtkWidget *window;
+    GtkWidget *button;
+    GtkWidget *box1;
+
+    /* This is called in all GTK applications. Arguments are parsed
+     * from the command line and are returned to the application. */
+    gtk_init (&amp;argc, &amp;argv);
+
+    /* Create a new window */
+    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
+    /* This is a new call, which just sets the title of our
+     * new window to "Hello Buttons!" */
+    gtk_window_set_title (GTK_WINDOW (window), "Hello Buttons!");
+
+    /* Here we just set a handler for delete_event that immediately
+     * exits GTK. */
+    gtk_signal_connect (GTK_OBJECT (window), "delete_event",
+                       GTK_SIGNAL_FUNC (delete_event), NULL);
+
+    /* Sets the border width of the window. */
+    gtk_container_set_border_width (GTK_CONTAINER (window), 10);
+
+    /* We create a box to pack widgets into.  This is described in detail
+     * in the "packing" section. The box is not really visible, it
+     * is just used as a tool to arrange widgets. */
+    box1 = gtk_hbox_new(FALSE, 0);
+
+    /* Put the box into the main window. */
+    gtk_container_add (GTK_CONTAINER (window), box1);
+
+    /* Creates a new button with the label "Button 1". */
+    button = gtk_button_new_with_label ("Button 1");
+    
+    /* Now when the button is clicked, we call the "callback" function
+     * with a pointer to "button 1" as its argument */
+    gtk_signal_connect (GTK_OBJECT (button), "clicked",
+                       GTK_SIGNAL_FUNC (callback), (gpointer) "button 1");
+
+    /* Instead of gtk_container_add, we pack this button into the invisible
+     * box, which has been packed into the window. */
+    gtk_box_pack_start(GTK_BOX(box1), button, TRUE, TRUE, 0);
+
+    /* Always remember this step, this tells GTK that our preparation for
+     * this button is complete, and it can now be displayed. */
+    gtk_widget_show(button);
+
+    /* Do these same steps again to create a second button */
+    button = gtk_button_new_with_label ("Button 2");
+
+    /* Call the same callback function with a different argument,
+     * passing a pointer to "button 2" instead. */
+    gtk_signal_connect (GTK_OBJECT (button), "clicked",
+                       GTK_SIGNAL_FUNC (callback), (gpointer) "button 2");
+
+    gtk_box_pack_start(GTK_BOX(box1), button, TRUE, TRUE, 0);
+
+    /* The order in which we show the buttons is not really important, but I
+     * recommend showing the window last, so it all pops up at once. */
+    gtk_widget_show(button);
+
+    gtk_widget_show(box1);
+
+    gtk_widget_show (window);
+    
+    /* Rest in gtk_main and wait for the fun to begin! */
+    gtk_main ();
+
+    return(0);
+}
+/* example-end */
+</programlisting>
+
+<para>Compile this program using the same linking arguments as our first
+example.  You'll notice this time there is no easy way to exit the
+program, you have to use your window manager or command line to kill
+it. A good exercise for the reader would be to insert a third "Quit"
+button that will exit the program. You may also wish to play with the
+options to gtk_box_pack_start() while reading the next section.  Try
+resizing the window, and observe the behavior.</para>
+
+<para>Just as a side note, there is another useful define for
+gtk_window_new() - <literal>GTK_WINDOW_DIALOG</literal>. This interacts with the
+window manager a little differently and should be used for transient
+windows.</para>
+
+</sect1>
+</chapter>
+
+<!-- ***************************************************************** -->
+<chapter id="ch-PackingWidgets">
+<title>Packing Widgets</title>
+
+<para>When creating an application, you'll want to put more than one widget
+inside a window. Our first <emphasis>helloworld</emphasis> example only used one
+widget so we could simply use a gtk_container_add call to "pack" the
+widget into the window. But when you want to put more than one widget
+into a window, how do you control where that widget is positioned?
+This is where packing comes in.</para>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Theory of Packing Boxes</title>
+
+<para>Most packing is done by creating boxes as in the example above. These
+are invisible widget containers that we can pack our widgets into
+which come in two forms, a horizontal box, and a vertical box. When
+packing widgets into a horizontal box, the objects are inserted
+horizontally from left to right or right to left depending on the call
+used. In a vertical box, widgets are packed from top to bottom or vice
+versa. You may use any combination of boxes inside or beside other
+boxes to create the desired effect.</para>
+
+<para>To create a new horizontal box, we use a call to gtk_hbox_new(), and
+for vertical boxes, gtk_vbox_new(). The gtk_box_pack_start() and
+gtk_box_pack_end() functions are used to place objects inside of these
+containers. The gtk_box_pack_start() function will start at the top
+and work its way down in a vbox, and pack left to right in an hbox.
+gtk_box_pack_end() will do the opposite, packing from bottom to top in
+a vbox, and right to left in an hbox. Using these functions allows us
+to right justify or left justify our widgets and may be mixed in any
+way to achieve the desired effect. We will use gtk_box_pack_start() in
+most of our examples. An object may be another container or a
+widget. In fact, many widgets are actually containers themselves,
+including the button, but we usually only use a label inside a button.</para>
+
+<para>By using these calls, GTK knows where you want to place your widgets
+so it can do automatic resizing and other nifty things. There are also
+a number of options as to how your widgets should be packed. As you
+can imagine, this method gives us a quite a bit of flexibility when
+placing and creating widgets.</para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Details of Boxes</title>
+
+<para>Because of this flexibility, packing boxes in GTK can be confusing at
+first. There are a lot of options, and it's not immediately obvious how
+they all fit together. In the end, however, there are basically five
+different styles.</para>
+
+<para><? <CENTER> >
+<?
+<IMG SRC="gtk_tut_packbox1.gif" VSPACE="15" HSPACE="10" WIDTH="528"
+HEIGHT="235" ALT="Box Packing Example Image">
+>
+<? </CENTER> ></para>
+
+<para>Each line contains one horizontal box (hbox) with several buttons. The
+call to gtk_box_pack is shorthand for the call to pack each of the
+buttons into the hbox. Each of the buttons is packed into the hbox the
+same way (i.e., same arguments to the gtk_box_pack_start() function).</para>
+
+<para>This is the declaration of the gtk_box_pack_start function.</para>
+
+<para><literallayout>
+<literal>void gtk_box_pack_start( GtkBox    *box,
+                         GtkWidget *child,
+                         gint       expand,
+                         gint       fill,
+                         gint       padding );</literal>
+</literallayout></para>
+
+<para>The first argument is the box you are packing the object into, the
+second is the object. The objects will all be buttons for now, so
+we'll be packing buttons into boxes.</para>
+
+<para>The expand argument to gtk_box_pack_start() and gtk_box_pack_end()
+controls whether the widgets are laid out in the box to fill in all
+the extra space in the box so the box is expanded to fill the area
+allotted to it (TRUE); or the box is shrunk to just fit the widgets
+(FALSE). Setting expand to FALSE will allow you to do right and left
+justification of your widgets.  Otherwise, they will all expand to fit
+into the box, and the same effect could be achieved by using only one
+of gtk_box_pack_start or gtk_box_pack_end.</para>
+
+<para>The fill argument to the gtk_box_pack functions control whether the
+extra space is allocated to the objects themselves (TRUE), or as extra
+padding in the box around these objects (FALSE). It only has an effect
+if the expand argument is also TRUE.</para>
+
+<para>When creating a new box, the function looks like this:</para>
+
+<para><literallayout>
+<literal>GtkWidget *gtk_hbox_new (gint homogeneous,
+                         gint spacing);</literal>
+</literallayout></para>
+
+<para>The homogeneous argument to gtk_hbox_new (and the same for
+gtk_vbox_new) controls whether each object in the box has the same
+size (i.e., the same width in an hbox, or the same height in a
+vbox). If it is set, the gtk_box_pack routines function essentially
+as if the <literal>expand</literal> argument was always turned on.</para>
+
+<para>What's the difference between spacing (set when the box is created)
+and padding (set when elements are packed)? Spacing is added between
+objects, and padding is added on either side of an object. The
+following figure should make it clearer:</para>
+
+<para><? <CENTER> >
+<?
+<IMG ALIGN="center" SRC="gtk_tut_packbox2.gif" WIDTH="509"
+HEIGHT="213" VSPACE="15" HSPACE="10"
+ALT="Box Packing Example Image">
+>
+<? </CENTER> ></para>
+
+<para>Here is the code used to create the above images. I've commented it
+fairly heavily so I hope you won't have any problems following
+it. Compile it yourself and play with it.</para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Packing Demonstration Program</title>
+
+<programlisting role="C">
+/* example-start packbox packbox.c */
+
+#include &lt;stdio.h&gt;
+#include &lt;stdlib.h&gt;
+#include "gtk/gtk.h"
+
+gint delete_event( GtkWidget *widget,
+                   GdkEvent  *event,
+                   gpointer   data )
+{
+    gtk_main_quit();
+    return(FALSE);
+}
+
+/* Make a new hbox filled with button-labels. Arguments for the 
+ * variables we're interested are passed in to this function. 
+ * We do not show the box, but do show everything inside. */
+GtkWidget *make_box( gint homogeneous,
+                     gint spacing,
+                    gint expand,
+                    gint fill,
+                    gint padding ) 
+{
+    GtkWidget *box;
+    GtkWidget *button;
+    char padstr[80];
+    
+    /* Create a new hbox with the appropriate homogeneous
+     * and spacing settings */
+    box = gtk_hbox_new (homogeneous, spacing);
+    
+    /* Create a series of buttons with the appropriate settings */
+    button = gtk_button_new_with_label ("gtk_box_pack");
+    gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
+    gtk_widget_show (button);
+    
+    button = gtk_button_new_with_label ("(box,");
+    gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
+    gtk_widget_show (button);
+    
+    button = gtk_button_new_with_label ("button,");
+    gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
+    gtk_widget_show (button);
+    
+    /* Create a button with the label depending on the value of
+     * expand. */
+    if (expand == TRUE)
+           button = gtk_button_new_with_label ("TRUE,");
+    else
+           button = gtk_button_new_with_label ("FALSE,");
+    
+    gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
+    gtk_widget_show (button);
+    
+    /* This is the same as the button creation for "expand"
+     * above, but uses the shorthand form. */
+    button = gtk_button_new_with_label (fill ? "TRUE," : "FALSE,");
+    gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
+    gtk_widget_show (button);
+    
+    sprintf (padstr, "%d);", padding);
+    
+    button = gtk_button_new_with_label (padstr);
+    gtk_box_pack_start (GTK_BOX (box), button, expand, fill, padding);
+    gtk_widget_show (button);
+    
+    return box;
+}
+
+int main( int   argc,
+          char *argv[]) 
+{
+    GtkWidget *window;
+    GtkWidget *button;
+    GtkWidget *box1;
+    GtkWidget *box2;
+    GtkWidget *separator;
+    GtkWidget *label;
+    GtkWidget *quitbox;
+    int which;
+    
+    /* Our init, don't forget this! :) */
+    gtk_init (&amp;argc, &amp;argv);
+    
+    if (argc != 2) {
+       fprintf (stderr, "usage: packbox num, where num is 1, 2, or 3.\n");
+       /* This just does cleanup in GTK and exits with an exit status of 1. */
+       gtk_exit (1);
+    }
+    
+    which = atoi (argv[1]);
+
+    /* Create our window */
+    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
+    /* You should always remember to connect the delete_event signal
+     * to the main window. This is very important for proper intuitive
+     * behavior */
+    gtk_signal_connect (GTK_OBJECT (window), "delete_event",
+                       GTK_SIGNAL_FUNC (delete_event), NULL);
+    gtk_container_set_border_width (GTK_CONTAINER (window), 10);
+    
+    /* We create a vertical box (vbox) to pack the horizontal boxes into.
+     * This allows us to stack the horizontal boxes filled with buttons one
+     * on top of the other in this vbox. */
+    box1 = gtk_vbox_new (FALSE, 0);
+    
+    /* which example to show. These correspond to the pictures above. */
+    switch (which) {
+    case 1:
+       /* create a new label. */
+       label = gtk_label_new ("gtk_hbox_new (FALSE, 0);");
+       
+       /* Align the label to the left side.  We'll discuss this function and 
+        * others in the section on Widget Attributes. */
+       gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
+
+       /* Pack the label into the vertical box (vbox box1).  Remember that 
+        * widgets added to a vbox will be packed one on top of the other in
+        * order. */
+       gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
+       
+       /* Show the label */
+       gtk_widget_show (label);
+       
+       /* Call our make box function - homogeneous = FALSE, spacing = 0,
+        * expand = FALSE, fill = FALSE, padding = 0 */
+       box2 = make_box (FALSE, 0, FALSE, FALSE, 0);
+       gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
+       gtk_widget_show (box2);
+
+       /* Call our make box function - homogeneous = FALSE, spacing = 0,
+        * expand = TRUE, fill = FALSE, padding = 0 */
+       box2 = make_box (FALSE, 0, TRUE, FALSE, 0);
+       gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
+       gtk_widget_show (box2);
+       
+       /* Args are: homogeneous, spacing, expand, fill, padding */
+       box2 = make_box (FALSE, 0, TRUE, TRUE, 0);
+       gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
+       gtk_widget_show (box2);
+       
+       /* Creates a separator, we'll learn more about these later, 
+        * but they are quite simple. */
+       separator = gtk_hseparator_new ();
+       
+        /* Pack the separator into the vbox. Remember each of these
+         * widgets is being packed into a vbox, so they'll be stacked
+        * vertically. */
+       gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
+       gtk_widget_show (separator);
+       
+       /* Create another new label, and show it. */
+       label = gtk_label_new ("gtk_hbox_new (TRUE, 0);");
+       gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
+       gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
+       gtk_widget_show (label);
+       
+       /* Args are: homogeneous, spacing, expand, fill, padding */
+       box2 = make_box (TRUE, 0, TRUE, FALSE, 0);
+       gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
+       gtk_widget_show (box2);
+       
+       /* Args are: homogeneous, spacing, expand, fill, padding */
+       box2 = make_box (TRUE, 0, TRUE, TRUE, 0);
+       gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
+       gtk_widget_show (box2);
+       
+       /* Another new separator. */
+       separator = gtk_hseparator_new ();
+       /* The last 3 arguments to gtk_box_pack_start are:
+        * expand, fill, padding. */
+       gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
+       gtk_widget_show (separator);
+       
+       break;
+
+    case 2:
+
+       /* Create a new label, remember box1 is a vbox as created 
+        * near the beginning of main() */
+       label = gtk_label_new ("gtk_hbox_new (FALSE, 10);");
+       gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
+       gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
+       gtk_widget_show (label);
+       
+       /* Args are: homogeneous, spacing, expand, fill, padding */
+       box2 = make_box (FALSE, 10, TRUE, FALSE, 0);
+       gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
+       gtk_widget_show (box2);
+       
+       /* Args are: homogeneous, spacing, expand, fill, padding */
+       box2 = make_box (FALSE, 10, TRUE, TRUE, 0);
+       gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
+       gtk_widget_show (box2);
+       
+       separator = gtk_hseparator_new ();
+       /* The last 3 arguments to gtk_box_pack_start are:
+        * expand, fill, padding. */
+       gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
+       gtk_widget_show (separator);
+       
+       label = gtk_label_new ("gtk_hbox_new (FALSE, 0);");
+       gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
+       gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 0);
+       gtk_widget_show (label);
+       
+       /* Args are: homogeneous, spacing, expand, fill, padding */
+       box2 = make_box (FALSE, 0, TRUE, FALSE, 10);
+       gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
+       gtk_widget_show (box2);
+       
+       /* Args are: homogeneous, spacing, expand, fill, padding */
+       box2 = make_box (FALSE, 0, TRUE, TRUE, 10);
+       gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
+       gtk_widget_show (box2);
+       
+       separator = gtk_hseparator_new ();
+       /* The last 3 arguments to gtk_box_pack_start are: expand, fill, padding. */
+       gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
+       gtk_widget_show (separator);
+       break;
+    
+    case 3:
+
+        /* This demonstrates the ability to use gtk_box_pack_end() to
+        * right justify widgets. First, we create a new box as before. */
+       box2 = make_box (FALSE, 0, FALSE, FALSE, 0);
+
+       /* Create the label that will be put at the end. */
+       label = gtk_label_new ("end");
+       /* Pack it using gtk_box_pack_end(), so it is put on the right
+        * side of the hbox created in the make_box() call. */
+       gtk_box_pack_end (GTK_BOX (box2), label, FALSE, FALSE, 0);
+       /* Show the label. */
+       gtk_widget_show (label);
+       
+       /* Pack box2 into box1 (the vbox remember ? :) */
+       gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, FALSE, 0);
+       gtk_widget_show (box2);
+       
+       /* A separator for the bottom. */
+       separator = gtk_hseparator_new ();
+       /* This explicitly sets the separator to 400 pixels wide by 5 pixels
+        * high. This is so the hbox we created will also be 400 pixels wide,
+        * and the "end" label will be separated from the other labels in the
+        * hbox. Otherwise, all the widgets in the hbox would be packed as
+        * close together as possible. */
+       gtk_widget_set_usize (separator, 400, 5);
+       /* pack the separator into the vbox (box1) created near the start 
+        * of main() */
+       gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 5);
+       gtk_widget_show (separator);    
+    }
+    
+    /* Create another new hbox.. remember we can use as many as we need! */
+    quitbox = gtk_hbox_new (FALSE, 0);
+    
+    /* Our quit button. */
+    button = gtk_button_new_with_label ("Quit");
+    
+    /* Setup the signal to terminate the program when the button is clicked */
+    gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+                              GTK_SIGNAL_FUNC (gtk_main_quit),
+                              GTK_OBJECT (window));
+    /* Pack the button into the quitbox.
+     * The last 3 arguments to gtk_box_pack_start are:
+     * expand, fill, padding. */
+    gtk_box_pack_start (GTK_BOX (quitbox), button, TRUE, FALSE, 0);
+    /* pack the quitbox into the vbox (box1) */
+    gtk_box_pack_start (GTK_BOX (box1), quitbox, FALSE, FALSE, 0);
+    
+    /* Pack the vbox (box1) which now contains all our widgets, into the
+     * main window. */
+    gtk_container_add (GTK_CONTAINER (window), box1);
+    
+    /* And show everything left */
+    gtk_widget_show (button);
+    gtk_widget_show (quitbox);
+    
+    gtk_widget_show (box1);
+    /* Showing the window last so everything pops up at once. */
+    gtk_widget_show (window);
+    
+    /* And of course, our main function. */
+    gtk_main ();
+
+    /* Control returns here when gtk_main_quit() is called, but not when 
+     * gtk_exit is used. */
+    
+    return(0);
+}
+/* example-end */
+</programlisting>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Packing Using Tables</title>
+
+<para>Let's take a look at another way of packing - Tables. These can be
+extremely useful in certain situations.</para>
+
+<para>Using tables, we create a grid that we can place widgets in. The
+widgets may take up as many spaces as we specify.</para>
+
+<para>The first thing to look at, of course, is the gtk_table_new function:</para>
+
+<para><literallayout>
+<literal>GtkWidget *gtk_table_new( gint rows,
+                          gint columns,
+                          gint homogeneous );</literal>
+</literallayout></para>
+
+<para>The first argument is the number of rows to make in the table, while
+the second, obviously, is the number of columns.</para>
+
+<para>The homogeneous argument has to do with how the table's boxes are
+sized. If homogeneous is TRUE, the table boxes are resized to the size
+of the largest widget in the table. If homogeneous is FALSE, the size
+of a table boxes is dictated by the tallest widget in its same row,
+and the widest widget in its column.</para>
+
+<para>The rows and columns are laid out from 0 to n, where n was the number
+specified in the call to gtk_table_new. So, if you specify rows = 2
+and columns = 2, the layout would look something like this:</para>
+
+<programlisting role="C">
+ 0          1          2
+0+----------+----------+
+ |          |          |
+1+----------+----------+
+ |          |          |
+2+----------+----------+
+</programlisting>
+
+<para>Note that the coordinate system starts in the upper left hand corner.
+To place a widget into a box, use the following function:</para>
+
+<programlisting role="C">
+void gtk_table_attach( GtkTable  *table,
+                       GtkWidget *child,
+                       gint       left_attach,
+                       gint       right_attach,
+                       gint       top_attach,
+                       gint       bottom_attach,
+                       gint       xoptions,
+                       gint       yoptions,
+                       gint       xpadding,
+                       gint       ypadding );
+</programlisting>
+
+<para>The first argument ("table") is the table you've created and the
+second ("child") the widget you wish to place in the table.</para>
+
+<para>The left and right attach arguments specify where to place the widget,
+and how many boxes to use. If you want a button in the lower right
+table entry of our 2x2 table, and want it to fill that entry ONLY,
+left_attach would be = 1, right_attach = 2, top_attach = 1,
+bottom_attach = 2.</para>
+
+<para>Now, if you wanted a widget to take up the whole top row of our 2x2
+table, you'd use left_attach = 0, right_attach = 2, top_attach = 0,
+bottom_attach = 1.</para>
+
+<para>The xoptions and yoptions are used to specify packing options and may
+be bitwise OR'ed together to allow multiple options.</para>
+
+<para>These options are:</para>
+
+<itemizedlist>
+<listitem><simpara><literal>GTK_FILL</literal> - If the table box is larger than the widget, and
+<literal>GTK_FILL</literal> is specified, the widget will expand to use all the room
+available.</simpara>
+</listitem>
+
+<listitem><simpara><literal>GTK_SHRINK</literal> - If the table widget was allocated less space
+then was requested (usually by the user resizing the window), then the
+widgets would normally just be pushed off the bottom of the window and
+disappear. If <literal>GTK_SHRINK</literal> is specified, the widgets will shrink
+with the table.</simpara>
+</listitem>
+
+<listitem><simpara><literal>GTK_EXPAND</literal> - This will cause the table to expand to use up
+any remaining space in the window.</simpara>
+</listitem>
+</itemizedlist>
+
+<para>Padding is just like in boxes, creating a clear area around the widget
+specified in pixels.</para>
+
+<para>gtk_table_attach() has a LOT of options.  So, there's a shortcut:</para>
+
+<para><literallayout>
+<literal>void gtk_table_attach_defaults( GtkTable  *table,
+                                GtkWidget *widget,
+                                gint       left_attach,
+                                gint       right_attach,
+                                gint       top_attach,
+                                gint       bottom_attach );</literal>
+</literallayout></para>
+
+<para>The X and Y options default to <literal>GTK_FILL | GTK_EXPAND</literal>, and X and Y
+padding are set to 0. The rest of the arguments are identical to the
+previous function.</para>
+
+<para>We also have gtk_table_set_row_spacing() and
+gtk_table_set_col_spacing(). These places spacing between the rows at
+the specified row or column.</para>
+
+<para><literallayout>
+<literal>void gtk_table_set_row_spacing( GtkTable *table,
+                                gint      row,
+                                gint      spacing );</literal>
+</literallayout></para>
+
+<para>and</para>
+
+<para><literallayout>
+<literal>void gtk_table_set_col_spacing ( GtkTable *table,
+                                 gint      column,
+                                 gint      spacing );</literal>
+</literallayout></para>
+
+<para>Note that for columns, the space goes to the right of the column, and
+for rows, the space goes below the row.</para>
+
+<para>You can also set a consistent spacing of all rows and/or columns with:</para>
+
+<para><literallayout>
+<literal>void gtk_table_set_row_spacings( GtkTable *table,
+                                 gint      spacing );</literal>
+</literallayout></para>
+
+<para>And,</para>
+
+<para><literallayout>
+<literal>void gtk_table_set_col_spacings( GtkTable *table,
+                                 gint      spacing );</literal>
+</literallayout></para>
+
+<para>Note that with these calls, the last row and last column do not get
+any spacing.</para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Table Packing Example</title>
+
+<para>Here we make a window with three buttons in a 2x2 table.
+The first two buttons will be placed in the upper row.
+A third, quit button, is placed in the lower row, spanning both columns.
+Which means it should look something like this:</para>
+
+<para><? <CENTER> >
+<?
+<IMG SRC="gtk_tut_table.gif" VSPACE="15" HSPACE="10" 
+ALT="Table Packing Example Image" WIDTH="180" HEIGHT="120">
+>
+<? </CENTER> ></para>
+
+<para>Here's the source code:</para>
+
+<programlisting role="C">
+/* example-start table table.c */
+
+#include &lt;gtk/gtk.h&gt;
+
+/* Our callback.
+ * The data passed to this function is printed to stdout */
+void callback( GtkWidget *widget,
+               gpointer   data )
+{
+    g_print ("Hello again - %s was pressed\n", (char *) data);
+}
+
+/* This callback quits the program */
+gint delete_event( GtkWidget *widget,
+                   GdkEvent  *event,
+                   gpointer   data )
+{
+    gtk_main_quit ();
+    return(FALSE);
+}
+
+int main( int   argc,
+          char *argv[] )
+{
+    GtkWidget *window;
+    GtkWidget *button;
+    GtkWidget *table;
+
+    gtk_init (&amp;argc, &amp;argv);
+
+    /* Create a new window */
+    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
+    /* Set the window title */
+    gtk_window_set_title (GTK_WINDOW (window), "Table");
+
+    /* Set a handler for delete_event that immediately
+     * exits GTK. */
+    gtk_signal_connect (GTK_OBJECT (window), "delete_event",
+                        GTK_SIGNAL_FUNC (delete_event), NULL);
+
+    /* Sets the border width of the window. */
+    gtk_container_set_border_width (GTK_CONTAINER (window), 20);
+
+    /* Create a 2x2 table */
+    table = gtk_table_new (2, 2, TRUE);
+
+    /* Put the table in the main window */
+    gtk_container_add (GTK_CONTAINER (window), table);
+
+    /* Create first button */
+    button = gtk_button_new_with_label ("button 1");
+
+    /* When the button is clicked, we call the "callback" function
+     * with a pointer to "button 1" as its argument */
+    gtk_signal_connect (GTK_OBJECT (button), "clicked",
+              GTK_SIGNAL_FUNC (callback), (gpointer) "button 1");
+
+
+    /* Insert button 1 into the upper left quadrant of the table */
+    gtk_table_attach_defaults (GTK_TABLE(table), button, 0, 1, 0, 1);
+
+    gtk_widget_show (button);
+
+    /* Create second button */
+
+    button = gtk_button_new_with_label ("button 2");
+
+    /* When the button is clicked, we call the "callback" function
+     * with a pointer to "button 2" as its argument */
+    gtk_signal_connect (GTK_OBJECT (button), "clicked",
+              GTK_SIGNAL_FUNC (callback), (gpointer) "button 2");
+    /* Insert button 2 into the upper right quadrant of the table */
+    gtk_table_attach_defaults (GTK_TABLE(table), button, 1, 2, 0, 1);
+
+    gtk_widget_show (button);
+
+    /* Create "Quit" button */
+    button = gtk_button_new_with_label ("Quit");
+
+    /* When the button is clicked, we call the "delete_event" function
+     * and the program exits */
+    gtk_signal_connect (GTK_OBJECT (button), "clicked",
+                        GTK_SIGNAL_FUNC (delete_event), NULL);
+
+    /* Insert the quit button into the both 
+     * lower quadrants of the table */
+    gtk_table_attach_defaults (GTK_TABLE(table), button, 0, 2, 1, 2);
+
+    gtk_widget_show (button);
+
+    gtk_widget_show (table);
+    gtk_widget_show (window);
+
+    gtk_main ();
+
+    return 0;
+}
+/* example-end */
+</programlisting>
+
+</sect1>
+</chapter>
+
+<!-- ***************************************************************** -->
+<chapter id="ch-WidgetOverview">
+<title>Widget Overview</title>
+
+<para>The general steps to creating a widget in GTK are:</para>
+<orderedlist>
+<listitem><simpara> gtk_*_new - one of various functions to create a new widget.
+These are all detailed in this section.</simpara>
+</listitem>
+
+<listitem><simpara> Connect all signals and events we wish to use to the
+appropriate handlers.</simpara>
+</listitem>
+
+<listitem><simpara> Set the attributes of the widget.</simpara>
+</listitem>
+
+<listitem><simpara> Pack the widget into a container using the appropriate call
+such as gtk_container_add() or gtk_box_pack_start().</simpara>
+</listitem>
+
+<listitem><simpara> gtk_widget_show() the widget.</simpara>
+</listitem>
+</orderedlist>
+
+<para>gtk_widget_show() lets GTK know that we are done setting the
+attributes of the widget, and it is ready to be displayed. You may
+also use gtk_widget_hide to make it disappear again. The order in
+which you show the widgets is not important, but I suggest showing the
+window last so the whole window pops up at once rather than seeing the
+individual widgets come up on the screen as they're formed. The
+children of a widget (a window is a widget too) will not be displayed
+until the window itself is shown using the gtk_widget_show() function.</para>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> Casting</title>
+
+<para>You'll notice as you go on that GTK uses a type casting system. This
+is always done using macros that both test the ability to cast the
+given item, and perform the cast. Some common ones you will see are:</para>
+
+<programlisting role="C">
+  GTK_WIDGET(widget)
+  GTK_OBJECT(object)
+  GTK_SIGNAL_FUNC(function)
+  GTK_CONTAINER(container)
+  GTK_WINDOW(window)
+  GTK_BOX(box)
+</programlisting>
+
+<para>These are all used to cast arguments in functions. You'll see them in the
+examples, and can usually tell when to use them simply by looking at the
+function's declaration.</para>
+
+<para>As you can see below in the class hierarchy, all GtkWidgets are
+derived from the Object base class. This means you can use a widget
+in any place the function asks for an object - simply use the
+<literal>GTK_OBJECT()</literal> macro.</para>
+
+<para>For example:</para>
+
+<programlisting role="C">
+gtk_signal_connect( GTK_OBJECT(button), "clicked",
+                    GTK_SIGNAL_FUNC(callback_function), callback_data);
+</programlisting>
+
+<para>This casts the button into an object, and provides a cast for the
+function pointer to the callback.</para>
+
+<para>Many widgets are also containers. If you look in the class hierarchy
+below, you'll notice that many widgets derive from the Container
+class. Any one of these widgets may be used with the
+<literal>GTK_CONTAINER</literal> macro to pass them to functions that ask for
+containers.</para>
+
+<para>Unfortunately, these macros are not extensively covered in the
+tutorial, but I recommend taking a look through the GTK header
+files. It can be very educational. In fact, it's not difficult to
+learn how a widget works just by looking at the function declarations.</para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Widget Hierarchy</title>
+
+<para>For your reference, here is the class hierarchy tree used to implement widgets.</para>
+
+<para><literallayout>
+<literal> GtkObject
+  +GtkWidget
+  | +GtkMisc
+  | | +GtkLabel
+  | | | +GtkAccelLabel
+  | | | `GtkTipsQuery
+  | | +GtkArrow
+  | | +GtkImage
+  | | `GtkPixmap
+  | +GtkContainer
+  | | +GtkBin
+  | | | +GtkAlignment
+  | | | +GtkFrame
+  | | | | `GtkAspectFrame
+  | | | +GtkButton
+  | | | | +GtkToggleButton
+  | | | | | `GtkCheckButton
+  | | | | |   `GtkRadioButton
+  | | | | `GtkOptionMenu
+  | | | +GtkItem
+  | | | | +GtkMenuItem
+  | | | | | +GtkCheckMenuItem
+  | | | | | | `GtkRadioMenuItem
+  | | | | | `GtkTearoffMenuItem
+  | | | | +GtkListItem
+  | | | | `GtkTreeItem
+  | | | +GtkWindow
+  | | | | +GtkColorSelectionDialog
+  | | | | +GtkDialog
+  | | | | | `GtkInputDialog
+  | | | | +GtkDrawWindow
+  | | | | +GtkFileSelection
+  | | | | +GtkFontSelectionDialog
+  | | | | `GtkPlug
+  | | | +GtkEventBox
+  | | | +GtkHandleBox
+  | | | +GtkScrolledWindow
+  | | | `GtkViewport
+  | | +GtkBox
+  | | | +GtkButtonBox
+  | | | | +GtkHButtonBox
+  | | | | `GtkVButtonBox
+  | | | +GtkVBox
+  | | | | +GtkColorSelection
+  | | | | `GtkGammaCurve
+  | | | `GtkHBox
+  | | |   +GtkCombo
+  | | |   `GtkStatusbar
+  | | +GtkCList
+  | | | `GtkCTree
+  | | +GtkFixed
+  | | +GtkNotebook
+  | | | `GtkFontSelection
+  | | +GtkPaned
+  | | | +GtkHPaned
+  | | | `GtkVPaned
+  | | +GtkLayout
+  | | +GtkList
+  | | +GtkMenuShell
+  | | | +GtkMenuBar
+  | | | `GtkMenu
+  | | +GtkPacker
+  | | +GtkSocket
+  | | +GtkTable
+  | | +GtkToolbar
+  | | `GtkTree
+  | +GtkCalendar
+  | +GtkDrawingArea
+  | | `GtkCurve
+  | +GtkEditable
+  | | +GtkEntry
+  | | | `GtkSpinButton
+  | | `GtkText
+  | +GtkRuler
+  | | +GtkHRuler
+  | | `GtkVRuler
+  | +GtkRange
+  | | +GtkScale
+  | | | +GtkHScale
+  | | | `GtkVScale
+  | | `GtkScrollbar
+  | |   +GtkHScrollbar
+  | |   `GtkVScrollbar
+  | +GtkSeparator
+  | | +GtkHSeparator
+  | | `GtkVSeparator
+  | +GtkPreview
+  | `GtkProgress
+  |   `GtkProgressBar
+  +GtkData
+  | +GtkAdjustment
+  | `GtkTooltips
+  `GtkItemFactory</literal>
+</literallayout></para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Widgets Without Windows</title>
+
+<para>The following widgets do not have an associated window. If you want to
+capture events, you'll have to use the EventBox. See the section on
+the <link linkend="ch-EventBox">EventBox</link> widget.</para>
+
+<para><literallayout>
+<literal>GtkAlignment
+GtkArrow
+GtkBin
+GtkBox
+GtkImage
+GtkItem
+GtkLabel
+GtkPixmap
+GtkScrolledWindow
+GtkSeparator
+GtkTable
+GtkAspectFrame
+GtkFrame
+GtkVBox
+GtkHBox
+GtkVSeparator
+GtkHSeparator</literal>
+</literallayout></para>
+
+<para>We'll further our exploration of GTK by examining each widget in turn,
+creating a few simple functions to display them. Another good source
+is the testgtk.c program that comes with GTK. It can be found in
+gtk/testgtk.c.</para>
+
+</sect1>
+</chapter>
+
+<!-- ***************************************************************** -->
+<chapter id="ch-ButtonWidget">
+<title>The Button Widget</title>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Normal Buttons</title>
+
+<para>We've almost seen all there is to see of the button widget. It's
+pretty simple. There are however two ways to create a button. You can
+use the gtk_button_new_with_label() to create a button with a label,
+or use gtk_button_new() to create a blank button. It's then up to you
+to pack a label or pixmap into this new button. To do this, create a
+new box, and then pack your objects into this box using the usual
+gtk_box_pack_start, and then use gtk_container_add to pack the box
+into the button.</para>
+
+<para>Here's an example of using gtk_button_new to create a button with a
+picture and a label in it. I've broken up the code to create a box
+from the rest so you can use it in your programs. There are further
+examples of using pixmaps later in the tutorial.</para>
+
+<programlisting role="C">
+/* example-start buttons buttons.c */
+
+#include &lt;gtk/gtk.h&gt;
+
+/* Create a new hbox with an image and a label packed into it
+ * and return the box. */
+
+GtkWidget *xpm_label_box( GtkWidget *parent,
+                          gchar     *xpm_filename,
+                          gchar     *label_text )
+{
+    GtkWidget *box1;
+    GtkWidget *label;
+    GtkWidget *pixmapwid;
+    GdkPixmap *pixmap;
+    GdkBitmap *mask;
+    GtkStyle *style;
+
+    /* Create box for xpm and label */
+    box1 = gtk_hbox_new (FALSE, 0);
+    gtk_container_set_border_width (GTK_CONTAINER (box1), 2);
+
+    /* Get the style of the button to get the
+     * background color. */
+    style = gtk_widget_get_style(parent);
+
+    /* Now on to the xpm stuff */
+    pixmap = gdk_pixmap_create_from_xpm (parent->window, &amp;mask,
+                                        &amp;style->bg[GTK_STATE_NORMAL],
+                                        xpm_filename);
+    pixmapwid = gtk_pixmap_new (pixmap, mask);
+
+    /* Create a label for the button */
+    label = gtk_label_new (label_text);
+
+    /* Pack the pixmap and label into the box */
+    gtk_box_pack_start (GTK_BOX (box1),
+                       pixmapwid, FALSE, FALSE, 3);
+
+    gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 3);
+
+    gtk_widget_show(pixmapwid);
+    gtk_widget_show(label);
+
+    return(box1);
+}
+
+/* Our usual callback function */
+void callback( GtkWidget *widget,
+               gpointer   data )
+{
+    g_print ("Hello again - %s was pressed\n", (char *) data);
+}
+
+int main( int   argc,
+          char *argv[] )
+{
+    /* GtkWidget is the storage type for widgets */
+    GtkWidget *window;
+    GtkWidget *button;
+    GtkWidget *box1;
+
+    gtk_init (&amp;argc, &amp;argv);
+
+    /* Create a new window */
+    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
+    gtk_window_set_title (GTK_WINDOW (window), "Pixmap'd Buttons!");
+
+    /* It's a good idea to do this for all windows. */
+    gtk_signal_connect (GTK_OBJECT (window), "destroy",
+                       GTK_SIGNAL_FUNC (gtk_exit), NULL);
+
+    gtk_signal_connect (GTK_OBJECT (window), "delete_event",
+                       GTK_SIGNAL_FUNC (gtk_exit), NULL);
+
+    /* Sets the border width of the window. */
+    gtk_container_set_border_width (GTK_CONTAINER (window), 10);
+    gtk_widget_realize(window);
+
+    /* Create a new button */
+    button = gtk_button_new ();
+
+    /* Connect the "clicked" signal of the button to our callback */
+    gtk_signal_connect (GTK_OBJECT (button), "clicked",
+                       GTK_SIGNAL_FUNC (callback), (gpointer) "cool button");
+
+    /* This calls our box creating function */
+    box1 = xpm_label_box(window, "info.xpm", "cool button");
+
+    /* Pack and show all our widgets */
+    gtk_widget_show(box1);
+
+    gtk_container_add (GTK_CONTAINER (button), box1);
+
+    gtk_widget_show(button);
+
+    gtk_container_add (GTK_CONTAINER (window), button);
+
+    gtk_widget_show (window);
+
+    /* Rest in gtk_main and wait for the fun to begin! */
+    gtk_main ();
+
+    return(0);
+}
+/* example-end */
+</programlisting>
+
+<para>The xpm_label_box function could be used to pack xpm's and labels into
+any widget that can be a container.</para>
+
+<para>Notice in <literal>xpm_label_box</literal> how there is a call to
+<literal>gtk_widget_get_style</literal>. Every widget has a "style", consisting of
+foreground and background colors for a variety of situations, font
+selection, and other graphics data relevant to a widget. These style
+values are defaulted in each widget, and are required by many GDK
+function calls, such as <literal>gdk_pixmap_create_from_xpm</literal>, which here is
+given the "normal" background color. The style data of widgets may
+be customized, using <link linkend="ch-GTKRCFilesiles">GTK's rc files</link>.</para>
+
+<para>Also notice the call to <literal>gtk_widget_realize</literal> after setting the
+window's border width. This function uses GDK to create the X
+windows related to the widget. The function is automatically called
+when you invoke <literal>gtk_widget_show</literal> for a widget, and so has not been
+shown in earlier examples. But the call to
+<literal>gdk_pixmap_create_from_xpm</literal> requires that its <literal>window</literal> argument
+refer to a real X window, so it is necessary to realize the widget
+before this GDK call.</para>
+
+<para>The Button widget has the following signals:</para>
+
+<itemizedlist>
+<listitem><simpara><literal>pressed</literal> - emitted when pointer button is pressed within
+Button widget</simpara>
+</listitem>
+<listitem><simpara><literal>released</literal> - emitted when pointer button is released within
+Button widget</simpara>
+</listitem>
+<listitem><simpara><literal>clicked</literal> - emitted when pointer button is pressed and then
+released within Button widget</simpara>
+</listitem>
+<listitem><simpara><literal>enter</literal> - emitted when pointer enters Button widget</simpara>
+</listitem>
+<listitem><simpara><literal>leave</literal> - emitted when pointer leaves Button widget</simpara>
+</listitem>
+</itemizedlist>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> Toggle Buttons</title>
+
+<para>Toggle buttons are derived from normal buttons and are very similar,
+except they will always be in one of two states, alternated by a
+click. They may be depressed, and when you click again, they will pop
+back up. Click again, and they will pop back down.</para>
+
+<para>Toggle buttons are the basis for check buttons and radio buttons, as
+such, many of the calls used for toggle buttons are inherited by radio
+and check buttons. I will point these out when we come to them.</para>
+
+<para>Creating a new toggle button:</para>
+
+<programlisting role="C">
+GtkWidget *gtk_toggle_button_new( void );
+
+GtkWidget *gtk_toggle_button_new_with_label( gchar *label );
+</programlisting>
+
+<para>As you can imagine, these work identically to the normal button widget
+calls. The first creates a blank toggle button, and the second, a
+button with a label widget already packed into it.</para>
+
+<para>To retrieve the state of the toggle widget, including radio and check
+buttons, we use a construct as shown in our example below. This tests
+the state of the toggle, by accessing the <literal>active</literal> field of the
+toggle widget's structure, after first using the
+<literal>GTK_TOGGLE_BUTTON</literal> macro to cast the widget pointer into a toggle
+widget pointer. The signal of interest to us emitted by toggle
+buttons (the toggle button, check button, and radio button widgets) is
+the "toggled" signal. To check the state of these buttons, set up a
+signal handler to catch the toggled signal, and access the structure
+to determine its state. The callback will look something like:</para>
+
+<para><literallayout>
+<literal>void toggle_button_callback (GtkWidget *widget, gpointer data)
+{
+    if (GTK_TOGGLE_BUTTON (widget)->active) 
+    {
+        /* If control reaches here, the toggle button is down */
+    
+    } else {
+    
+        /* If control reaches here, the toggle button is up */
+    }
+}</literal>
+</literallayout></para>
+
+<para>To force the state of a toggle button, and its children, the radio and
+check buttons, use this function:</para>
+
+<para><literallayout>
+<literal>void gtk_toggle_button_set_active( GtkToggleButton *toggle_button,
+                                  gint             state );</literal>
+</literallayout></para>
+
+<para>The above call can be used to set the state of the toggle button, and
+its children the radio and check buttons. Passing in your created
+button as the first argument, and a TRUE or FALSE for the second state
+argument to specify whether it should be down (depressed) or up
+(released). Default is up, or FALSE.</para>
+
+<para>Note that when you use the gtk_toggle_button_set_active() function, and
+the state is actually changed, it causes the "clicked" signal to be
+emitted from the button.</para>
+
+<para><literallayout>
+<literal>void gtk_toggle_button_toggled (GtkToggleButton *toggle_button);</literal>
+</literallayout></para>
+
+<para>This simply toggles the button, and emits the "toggled" signal.</para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> Check Buttons</title>
+
+<para>Check buttons inherit many properties and functions from the the
+toggle buttons above, but look a little different. Rather than being
+buttons with text inside them, they are small squares with the text to
+the right of them. These are often used for toggling options on and
+off in applications.</para>
+
+<para>The two creation functions are similar to those of the normal button.</para>
+
+<para><literallayout>
+<literal>GtkWidget *gtk_check_button_new( void );</para>
+
+<para>GtkWidget *gtk_check_button_new_with_label ( gchar *label );</literal>
+</literallayout></para>
+
+<para>The new_with_label function creates a check button with a label beside
+it.</para>
+
+<para>Checking the state of the check button is identical to that of the
+toggle button.</para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1> Radio Buttons <label id="ch-Radio_Buttons"></para>
+
+<para>Radio buttons are similar to check buttons except they are grouped so
+that only one may be selected/depressed at a time. This is good for
+places in your application where you need to select from a short list
+of options.</para>
+
+<para>Creating a new radio button is done with one of these calls:</para>
+
+<para><literallayout>
+<literal>GtkWidget *gtk_radio_button_new( GSList *group );</para>
+
+<para>GtkWidget *gtk_radio_button_new_with_label( GSList *group,
+                                            gchar  *label );</literal>
+</literallayout></para>
+
+<para>You'll notice the extra argument to these calls. They require a group
+to perform their duty properly. The first call to
+gtk_radio_button_new_with_label or gtk_radio_button_new_with_label
+should pass NULL as the first argument. Then create a group using:</para>
+
+<para><literallayout>
+<literal>GSList *gtk_radio_button_group( GtkRadioButton *radio_button );</literal>
+</literallayout></para>
+
+<para>The important thing to remember is that gtk_radio_button_group must be
+called for each new button added to the group, with the previous
+button passed in as an argument. The result is then passed into the
+next call to gtk_radio_button_new or
+gtk_radio_button_new_with_label. This allows a chain of buttons to be
+established. The example below should make this clear.</para>
+
+<para>You can shorten this slightly by using the following syntax, which
+removes the need for a variable to hold the list of buttons. This form
+is used in the example to create the third button:</para>
+
+<para><literallayout>
+<literal>     button2 = gtk_radio_button_new_with_label(
+                 gtk_radio_button_group (GTK_RADIO_BUTTON (button1)),
+                 "button2");</literal>
+</literallayout></para>
+
+<para>It is also a good idea to explicitly set which button should be the
+default depressed button with:</para>
+
+<para><literallayout>
+<literal>void gtk_toggle_button_set_active( GtkToggleButton *toggle_button,
+                                  gint             state );</literal>
+</literallayout></para>
+
+<para>This is described in the section on toggle buttons, and works in
+exactly the same way.  Once the radio buttons are grouped together,
+only one of the group may be active at a time. If the user clicks on
+one radio button, and then on another, the first radio button will
+first emit a "toggled" signal (to report becoming inactive), and then
+the second will emit its "toggled" signal (to report becoming active).</para>
+
+<para>The following example creates a radio button group with three buttons.</para>
+
+<programlisting role="C">
+/* example-start radiobuttons radiobuttons.c */
+
+#include &lt;gtk/gtk.h&gt;
+#include &lt;glib.h&gt;
+
+gint close_application( GtkWidget *widget,
+                        GdkEvent  *event,
+                        gpointer   data )
+{
+  gtk_main_quit();
+  return(FALSE);
+}
+
+int main( int   argc,
+          char *argv[] )
+{
+    GtkWidget *window = NULL;
+    GtkWidget *box1;
+    GtkWidget *box2;
+    GtkWidget *button;
+    GtkWidget *separator;
+    GSList *group;
+  
+    gtk_init(&amp;argc,&amp;argv);    
+      
+    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  
+    gtk_signal_connect (GTK_OBJECT (window), "delete_event",
+                       GTK_SIGNAL_FUNC(close_application),
+                        NULL);
+
+    gtk_window_set_title (GTK_WINDOW (window), "radio buttons");
+    gtk_container_set_border_width (GTK_CONTAINER (window), 0);
+
+    box1 = gtk_vbox_new (FALSE, 0);
+    gtk_container_add (GTK_CONTAINER (window), box1);
+    gtk_widget_show (box1);
+
+    box2 = gtk_vbox_new (FALSE, 10);
+    gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
+    gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
+    gtk_widget_show (box2);
+
+    button = gtk_radio_button_new_with_label (NULL, "button1");
+    gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
+    gtk_widget_show (button);
+
+    group = gtk_radio_button_group (GTK_RADIO_BUTTON (button));
+    button = gtk_radio_button_new_with_label(group, "button2");
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
+    gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
+    gtk_widget_show (button);
+
+    button = gtk_radio_button_new_with_label(
+                gtk_radio_button_group (GTK_RADIO_BUTTON (button)),
+                 "button3");
+    gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
+    gtk_widget_show (button);
+
+    separator = gtk_hseparator_new ();
+    gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
+    gtk_widget_show (separator);
+
+    box2 = gtk_vbox_new (FALSE, 10);
+    gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
+    gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
+    gtk_widget_show (box2);
+
+    button = gtk_button_new_with_label ("close");
+    gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+                               GTK_SIGNAL_FUNC(close_application),
+                               GTK_OBJECT (window));
+    gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
+    GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
+    gtk_widget_grab_default (button);
+    gtk_widget_show (button);
+    gtk_widget_show (window);
+     
+    gtk_main();
+
+    return(0);
+}
+/* example-end */
+</programlisting>
+
+<!-- TODO: check out gtk_radio_button_new_from_widget function - TRG -->
+
+</sect1>
+</chapter>
+
+<!-- ***************************************************************** -->
+<chapter id="ch-Adjustments">
+<title> Adjustments</title>
+
+<para>GTK has various widgets that can be visually adjusted by the user
+using the mouse or the keyboard, such as the range widgets, described
+in the <link linkend="ch-RangeWidgets">Range Widgets</link>
+section. There are also a few widgets that display some adjustable
+portion of a larger area of data, such as the text widget and the
+viewport widget.</para>
+
+<para>Obviously, an application needs to be able to react to changes the
+user makes in range widgets. One way to do this would be to have each
+widget emit its own type of signal when its adjustment changes, and
+either pass the new value to the signal handler, or require it to look
+inside the widget's data structure in order to ascertain the value.
+But you may also want to connect the adjustments of several widgets
+together, so that adjusting one adjusts the others. The most obvious
+example of this is connecting a scrollbar to a panning viewport or a
+scrolling text area. If each widget has its own way of setting or
+getting the adjustment value, then the programmer may have to write
+their own signal handlers to translate between the output of one
+widget's signal and the "input" of another's adjustment setting
+function.</para>
+
+<para>GTK solves this problem using the Adjustment object, which is not a
+widget but a way for widgets to store and pass adjustment information
+in an abstract and flexible form. The most obvious use of Adjustment
+is to store the configuration parameters and values of range widgets,
+such as scrollbars and scale controls. However, since Adjustments are
+derived from Object, they have some special powers beyond those of
+normal data structures. Most importantly, they can emit signals, just
+like widgets, and these signals can be used not only to allow your
+program to react to user input on adjustable widgets, but also to
+propagate adjustment values transparently between adjustable widgets.</para>
+
+<para>You will see how adjustments fit in when you see the other widgets
+that incorporate them:
+<link linkend="ch-ProgressBar">Progress Bars</link>,
+<link linkend="ch-Viewports">Viewports</link>,
+<link linkend="ch-ScrolledWindow">Scrolled Windows</link>, and others.</para>
+
+<para><sect1>
+<title> Creating an Adjustment</title>
+
+<para>Many of the widgets which use adjustment objects do so automatically,
+but some cases will be shown in later examples where you may need to
+create one yourself. You create an adjustment using:</para>
+
+<para><literallayout>
+<literal>GtkObject *gtk_adjustment_new( gfloat value,
+                               gfloat lower,
+                               gfloat upper,
+                               gfloat step_increment,
+                               gfloat page_increment,
+                               gfloat page_size );</literal>
+</literallayout></para>
+
+<para>The <literal>value</literal> argument is the initial value you want to give to the
+adjustment, usually corresponding to the topmost or leftmost position
+of an adjustable widget. The <literal>lower</literal> argument specifies the lowest
+value which the adjustment can hold. The <literal>step_increment</literal> argument
+specifies the "smaller" of the two increments by which the user can
+change the value, while the <literal>page_increment</literal> is the "larger" one.
+The <literal>page_size</literal> argument usually corresponds somehow to the visible
+area of a panning widget. The <literal>upper</literal> argument is used to represent
+the bottom most or right most coordinate in a panning widget's
+child. Therefore it is <emphasis>not</emphasis> always the largest number that
+<literal>value</literal> can take, since the <literal>page_size</literal> of such widgets is
+usually non-zero.</para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> Using Adjustments the Easy Way</title>
+
+<para>The adjustable widgets can be roughly divided into those which use and
+require specific units for these values and those which treat them as
+arbitrary numbers. The group which treats the values as arbitrary
+numbers includes the range widgets (scrollbars and scales, the
+progress bar widget, and the spin button widget). These widgets are
+all the widgets which are typically "adjusted" directly by the user
+with the mouse or keyboard. They will treat the <literal>lower</literal> and
+<literal>upper</literal> values of an adjustment as a range within which the user
+can manipulate the adjustment's <literal>value</literal>. By default, they will only
+modify the <literal>value</literal> of an adjustment.</para>
+
+<para>The other group includes the text widget, the viewport widget, the
+compound list widget, and the scrolled window widget. All of these
+widgets use pixel values for their adjustments. These are also all
+widgets which are typically "adjusted" indirectly using scrollbars.
+While all widgets which use adjustments can either create their own
+adjustments or use ones you supply, you'll generally want to let this
+particular category of widgets create its own adjustments. Usually,
+they will eventually override all the values except the <literal>value</literal>
+itself in whatever adjustments you give them, but the results are, in
+general, undefined (meaning, you'll have to read the source code to
+find out, and it may be different from widget to widget).</para>
+
+<para>Now, you're probably thinking, since text widgets and viewports insist
+on setting everything except the <literal>value</literal> of their adjustments,
+while scrollbars will <emphasis>only</emphasis> touch the adjustment's <literal>value</literal>, if
+you <emphasis>share</emphasis> an adjustment object between a scrollbar and a text
+widget, manipulating the scrollbar will automagically adjust the text
+widget?  Of course it will! Just like this:</para>
+
+<para><literallayout>
+<literal>  /* creates its own adjustments */
+  text = gtk_text_new (NULL, NULL);
+  /* uses the newly-created adjustment for the scrollbar as well */
+  vscrollbar = gtk_vscrollbar_new (GTK_TEXT(text)->vadj);</literal>
+</literallayout></para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> Adjustment Internals</title>
+
+<para>Ok, you say, that's nice, but what if I want to create my own handlers
+to respond when the user adjusts a range widget or a spin button, and
+how do I get at the value of the adjustment in these handlers?  To
+answer these questions and more, let's start by taking a look at
+<literal>struct _GtkAdjustment</literal> itself:</para>
+
+<para><literallayout>
+<literal>struct _GtkAdjustment
+{
+  GtkData data;
+  
+  gfloat lower;
+  gfloat upper;
+  gfloat value;
+  gfloat step_increment;
+  gfloat page_increment;
+  gfloat page_size;
+};     </literal>
+</literallayout></para>
+
+<para>The first thing you should know is that there aren't any handy-dandy
+macros or accessor functions for getting the <literal>value</literal> out of an
+Adjustment, so you'll have to (horror of horrors) do it like a
+<emphasis>real</emphasis> C programmer.  Don't worry - the <literal>GTK_ADJUSTMENT
+(Object)</literal> macro does run-time type checking (as do all the GTK
+type-casting macros, actually).</para>
+
+<para>Since, when you set the <literal>value</literal> of an adjustment, you generally
+want the change to be reflected by every widget that uses this
+adjustment, GTK provides this convenience function to do this:</para>
+
+<para><literallayout>
+<literal>void gtk_adjustment_set_value( GtkAdjustment *adjustment,
+                               gfloat         value );</literal>
+</literallayout></para>
+
+<para>As mentioned earlier, Adjustment is a subclass of Object just
+like all the various widgets, and thus it is able to emit signals.
+This is, of course, why updates happen automagically when you share an
+adjustment object between a scrollbar and another adjustable widget;
+all adjustable widgets connect signal handlers to their adjustment's
+<literal>value_changed</literal> signal, as can your program. Here's the definition
+of this signal in <literal>struct _GtkAdjustmentClass</literal>:</para>
+
+<para><literallayout>
+<literal>  void (* value_changed) (GtkAdjustment *adjustment);</literal>
+</literallayout></para>
+
+<para>The various widgets that use the Adjustment object will emit this
+signal on an adjustment whenever they change its value. This happens
+both when user input causes the slider to move on a range widget, as
+well as when the program explicitly changes the value with
+<literal>gtk_adjustment_set_value()</literal>. So, for example, if you have a scale
+widget, and you want to change the rotation of a picture whenever its
+value changes, you would create a callback like this:</para>
+
+<para><literallayout>
+<literal>void cb_rotate_picture (GtkAdjustment *adj, GtkWidget *picture)
+{
+  set_picture_rotation (picture, adj->value);
+...</literal>
+</literallayout></para>
+
+<para>and connect it to the scale widget's adjustment like this:</para>
+
+<para><literallayout>
+<literal>gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
+                   GTK_SIGNAL_FUNC (cb_rotate_picture), picture);</literal>
+</literallayout></para>
+
+<para>What about when a widget reconfigures the <literal>upper</literal> or <literal>lower</literal>
+fields of its adjustment, such as when a user adds more text to a text
+widget?  In this case, it emits the <literal>changed</literal> signal, which looks
+like this:</para>
+
+<para><literallayout>
+<literal>  void (* changed)     (GtkAdjustment *adjustment);</literal>
+</literallayout></para>
+
+<para>Range widgets typically connect a handler to this signal, which
+changes their appearance to reflect the change - for example, the size
+of the slider in a scrollbar will grow or shrink in inverse proportion
+to the difference between the <literal>lower</literal> and <literal>upper</literal> values of its
+adjustment.</para>
+
+<para>You probably won't ever need to attach a handler to this signal,
+unless you're writing a new type of range widget.  However, if you
+change any of the values in a Adjustment directly, you should emit
+this signal on it to reconfigure whatever widgets are using it, like
+this:</para>
+
+<para><literallayout>
+<literal>gtk_signal_emit_by_name (GTK_OBJECT (adjustment), "changed");</literal>
+</literallayout></para>
+
+<para>Now go forth and adjust!</para>
+
+</sect1>
+</chapter>
+
+<!-- ***************************************************************** -->
+<chapter id="ch-Range Widgets">
+<title>Range Widgets</title>
+
+<para>
+<para>The category of range widgets includes the ubiquitous scrollbar widget
+and the less common "scale" widget. Though these two types of widgets
+are generally used for different purposes, they are quite similar in
+function and implementation. All range widgets share a set of common
+graphic elements, each of which has its own X window and receives
+events. They all contain a "trough" and a "slider" (what is sometimes
+called a "thumbwheel" in other GUI environments). Dragging the slider
+with the pointer moves it back and forth within the trough, while
+clicking in the trough advances the slider towards the location of the
+click, either completely, or by a designated amount, depending on
+which mouse button is used.</para>
+
+<para>As mentioned in <link linkend="ch-Adjustment">Adjustments</link> above,
+all range widgets are associated with an adjustment object, from which
+they calculate the length of the slider and its position within the
+trough. When the user manipulates the slider, the range widget will
+change the value of the adjustment.</para>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> Scrollbar Widgets</title>
+
+<para>These are your standard, run-of-the-mill scrollbars. These should be
+used only for scrolling some other widget, such as a list, a text box,
+or a viewport (and it's generally easier to use the scrolled window
+widget in most cases).  For other purposes, you should use scale
+widgets, as they are friendlier and more featureful.</para>
+
+<para>There are separate types for horizontal and vertical scrollbars.
+There really isn't much to say about these. You create them with the
+following functions, defined in <literal>&lt;gtk/gtkhscrollbar.h&gt;</literal>
+and <literal>&lt;gtk/gtkvscrollbar.h&gt;</literal>:</para>
+
+<para><literallayout>
+<literal>GtkWidget *gtk_hscrollbar_new( GtkAdjustment *adjustment );</para>
+
+<para>GtkWidget *gtk_vscrollbar_new( GtkAdjustment *adjustment );</literal>
+</literallayout></para>
+
+<para>and that's about it (if you don't believe me, look in the header
+files!).  The <literal>adjustment</literal> argument can either be a pointer to an
+existing Adjustment, or NULL, in which case one will be created for
+you. Specifying NULL might actually be useful in this case, if you
+wish to pass the newly-created adjustment to the constructor function
+of some other widget which will configure it for you, such as a text
+widget.</para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> Scale Widgets</title>
+
+<para>Scale widgets are used to allow the user to visually select and
+manipulate a value within a specific range. You might want to use a
+scale widget, for example, to adjust the magnification level on a
+zoomed preview of a picture, or to control the brightness of a color,
+or to specify the number of minutes of inactivity before a screensaver
+takes over the screen.</para>
+
+<!-- ----------------------------------------------------------------- -->
+<sect2>
+<title>Creating a Scale Widget</title>
+
+<para>As with scrollbars, there are separate widget types for horizontal and
+vertical scale widgets. (Most programmers seem to favour horizontal
+scale widgets.) Since they work essentially the same way, there's no
+need to treat them separately here. The following functions, defined
+in <literal>&lt;gtk/gtkvscale.h&gt;</literal> and
+<literal>&lt;gtk/gtkhscale.h&gt;</literal>, create vertical and horizontal scale
+widgets, respectively:</para>
+
+<para><tscreen>
+<verb>
+GtkWidget *gtk_vscale_new( GtkAdjustment *adjustment );</para>
+
+<para>GtkWidget *gtk_hscale_new( GtkAdjustment *adjustment );
+</verb>
+</tscreen></para>
+
+<para>The <literal>adjustment</literal> argument can either be an adjustment which has
+already been created with <literal>gtk_adjustment_new()</literal>, or <literal>NULL</literal>, in
+which case, an anonymous Adjustment is created with all of its
+values set to <literal>0.0</literal> (which isn't very useful in this case). In
+order to avoid confusing yourself, you probably want to create your
+adjustment with a <literal>page_size</literal> of <literal>0.0</literal> so that its <literal>upper</literal>
+value actually corresponds to the highest value the user can select.
+(If you're <emphasis>already</emphasis> thoroughly confused, read the section on <ref
+id="ch-Adjustment"> Adjustments </ulink> again for an explanation of
+what exactly adjustments do and how to create and manipulate them.)</para>
+
+</sect2>
+
+<!-- ----------------------------------------------------------------- -->
+<sect2>
+<title> Functions and Signals (well, functions, at least)</title>
+
+<para>Scale widgets can display their current value as a number beside the
+trough. The default behaviour is to show the value, but you can change
+this with this function:</para>
+
+<para><literallayout>
+<literal>void gtk_scale_set_draw_value( GtkScale *scale,
+                               gint      draw_value );</literal>
+</literallayout></para>
+
+<para>As you might have guessed, <literal>draw_value</literal> is either <literal>TRUE</literal> or
+<literal>FALSE</literal>, with predictable consequences for either one.</para>
+
+<para>The value displayed by a scale widget is rounded to one decimal point
+by default, as is the <literal>value</literal> field in its GtkAdjustment. You can
+change this with:</para>
+
+<para><tscreen>
+<verb>
+void gtk_scale_set_digits( GtkScale *scale,
+                            gint     digits );
+</verb>
+</tscreen></para>
+
+<para>where <literal>digits</literal> is the number of decimal places you want. You can
+set <literal>digits</literal> to anything you like, but no more than 13 decimal
+places will actually be drawn on screen.</para>
+
+<para>Finally, the value can be drawn in different positions
+relative to the trough:</para>
+
+<para><tscreen>
+<verb>
+void gtk_scale_set_value_pos( GtkScale        *scale,
+                              GtkPositionType  pos );
+</verb>
+</tscreen></para>
+
+<para>The argument <literal>pos</literal> is of type <literal>GtkPositionType</literal>, which is
+defined in <literal>&lt;gtk/gtkenums.h&gt;</literal>, and can take one of the
+following values:</para>
+
+<para><literallayout>
+<literal>  GTK_POS_LEFT
+  GTK_POS_RIGHT
+  GTK_POS_TOP
+  GTK_POS_BOTTOM</literal>
+</literallayout></para>
+
+<para>If you position the value on the "side" of the trough (e.g., on the
+top or bottom of a horizontal scale widget), then it will follow the
+slider up and down the trough.</para>
+
+<para>All the preceding functions are defined in
+<literal>&lt;gtk/gtkscale.h&gt;</literal>. The header files for all GTK widgets
+are automatically included when you include
+<literal>&lt;gtk/gtk.h&gt;</literal>. But you should look over the header files
+of all widgets that interest you,</para>
+
+</sect2>
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1> Common Range Functions
+
+<para>The Range widget class is fairly complicated internally, but, like
+all the "base class" widgets, most of its complexity is only
+interesting if you want to hack on it. Also, almost all of the
+functions and signals it defines are only really used in writing
+derived widgets. There are, however, a few useful functions that are
+defined in <literal>&lt;gtk/gtkrange.h&gt;</literal> and will work on all range
+widgets.</para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect2>
+<title> Setting the Update Policy</title>
+
+<para>The "update policy" of a range widget defines at what points during
+user interaction it will change the <literal>value</literal> field of its
+Adjustment and emit the "value_changed" signal on this
+Adjustment. The update policies, defined in
+<literal>&lt;gtk/gtkenums.h&gt;</literal> as type <literal>enum GtkUpdateType</literal>,
+are:</para>
+
+<itemizedlist>
+<listitem><simpara>GTK_UPDATE_POLICY_CONTINUOUS - This is the default. The
+"value_changed" signal is emitted continuously, i.e., whenever the
+slider is moved by even the tiniest amount.
+</item></simpara>
+</listitem>
+<listitem><simpara>GTK_UPDATE_POLICY_DISCONTINUOUS - The "value_changed" signal is
+only emitted once the slider has stopped moving and the user has
+released the mouse button.
+</item></simpara>
+</listitem>
+<listitem><simpara>GTK_UPDATE_POLICY_DELAYED - The "value_changed" signal is emitted
+when the user releases the mouse button, or if the slider stops moving
+for a short period of time.
+</item></simpara>
+</listitem>
+</itemizedlist>
+
+<para>The update policy of a range widget can be set by casting it using the
+<literal>GTK_RANGE (Widget)</literal> macro and passing it to this function:</para>
+
+<para><literallayout>
+<literal>void gtk_range_set_update_policy( GtkRange      *range,
+                                 GtkUpdateType  policy) ;</literal>
+</literallayout></para>
+
+</sect2>
+
+<!-- ----------------------------------------------------------------- -->
+<sect2>
+<title>Getting and Setting Adjustments</title>
+
+<para>Getting and setting the adjustment for a range widget "on the fly" is
+done, predictably, with:</para>
+
+<para><literallayout>
+<literal>GtkAdjustment* gtk_range_get_adjustment( GtkRange *range );</para>
+
+<para>void gtk_range_set_adjustment( GtkRange      *range,
+                               GtkAdjustment *adjustment );</literal>
+</literallayout></para>
+
+<para><literal>gtk_range_get_adjustment()</literal> returns a pointer to the adjustment to
+which <literal>range</literal> is connected.</para>
+
+<para><literal>gtk_range_set_adjustment()</literal> does absolutely nothing if you pass it
+the adjustment that <literal>range</literal> is already using, regardless of whether
+you changed any of its fields or not. If you pass it a new
+Adjustment, it will unreference the old one if it exists (possibly
+destroying it), connect the appropriate signals to the new one, and
+call the private function <literal>gtk_range_adjustment_changed()</literal>, which
+will (or at least, is supposed to...) recalculate the size and/or
+position of the slider and redraw if necessary. As mentioned in the
+section on adjustments, if you wish to reuse the same Adjustment,
+when you modify its values directly, you should emit the "changed"
+signal on it, like this:</para>
+
+<para><literallayout>
+<literal>gtk_signal_emit_by_name (GTK_OBJECT (adjustment), "changed");</literal>
+</literallayout></para>
+</sect2>
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> Key and Mouse bindings</title>
+
+<para>All of the GTK range widgets react to mouse clicks in more or less
+the same way. Clicking button-1 in the trough will cause its
+adjustment's <literal>page_increment</literal> to be added or subtracted from its
+<literal>value</literal>, and the slider to be moved accordingly. Clicking mouse
+button-2 in the trough will jump the slider to the point at which the
+button was clicked. Clicking any button on a scrollbar's arrows will
+cause its adjustment's value to change <literal>step_increment</literal> at a time.</para>
+
+<para>It may take a little while to get used to, but by default, scrollbars
+as well as scale widgets can take the keyboard focus in GTK. If you
+think your users will find this too confusing, you can always disable
+this by unsetting the <literal>GTK_CAN_FOCUS</literal> flag on the scrollbar, like
+this:</para>
+
+<para><literallayout>
+<literal>GTK_WIDGET_UNSET_FLAGS (scrollbar, GTK_CAN_FOCUS);</literal>
+</literallayout></para>
+
+<para>The key bindings (which are, of course, only active when the widget
+has focus) are slightly different between horizontal and vertical
+range widgets, for obvious reasons. They are also not quite the same
+for scale widgets as they are for scrollbars, for somewhat less
+obvious reasons (possibly to avoid confusion between the keys for
+horizontal and vertical scrollbars in scrolled windows, where both
+operate on the same area).</para>
+
+<para><sect2>
+<title> Vertical Range Widgets</title>
+
+<para>All vertical range widgets can be operated with the up and down arrow
+keys, as well as with the <literal>Page Up</literal> and <literal>Page Down</literal> keys. The
+arrows move the slider up and down by <literal>step_increment</literal>, while
+<literal>Page Up</literal> and <literal>Page Down</literal> move it by <literal>page_increment</literal>.</para>
+
+<para>The user can also move the slider all the way to one end or the other
+of the trough using the keyboard. With the VScale widget, this is
+done with the <literal>Home</literal> and <literal>End</literal> keys, whereas with the
+VScrollbar widget, this is done by typing <literal>Control-Page Up</literal>
+and <literal>Control-Page Down</literal>.</para>
+
+<!-- ----------------------------------------------------------------- -->
+<sect2>
+<title> Horizontal Range Widgets</title>
+
+<para>The left and right arrow keys work as you might expect in these
+widgets, moving the slider back and forth by <literal>step_increment</literal>. The
+<literal>Home</literal> and <literal>End</literal> keys move the slider to the ends of the trough.
+For the HScale widget, moving the slider by <literal>page_increment</literal> is
+accomplished with <literal>Control-Left</literal> and <literal>Control-Right</literal>,
+while for HScrollbar, it's done with <literal>Control-Home</literal> and
+<literal>Control-End</literal>.</para>
+
+</sect2>
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1> Example
+
+<para>This example is a somewhat modified version of the "range controls"
+test from <literal>testgtk.c</literal>. It basically puts up a window with three
+range widgets all connected to the same adjustment, and a couple of
+controls for adjusting some of the parameters mentioned above and in
+the section on adjustments, so you can see how they affect the way
+these widgets work for the user.</para>
+
+<programlisting role="C">
+/* example-start rangewidgets rangewidgets.c */
+
+#include &lt;gtk/gtk.h&gt;
+
+GtkWidget *hscale, *vscale;
+
+void cb_pos_menu_select( GtkWidget       *item,
+                         GtkPositionType  pos )
+{
+    /* Set the value position on both scale widgets */
+    gtk_scale_set_value_pos (GTK_SCALE (hscale), pos);
+    gtk_scale_set_value_pos (GTK_SCALE (vscale), pos);
+}
+
+void cb_update_menu_select( GtkWidget     *item,
+                            GtkUpdateType  policy )
+{
+    /* Set the update policy for both scale widgets */
+    gtk_range_set_update_policy (GTK_RANGE (hscale), policy);
+    gtk_range_set_update_policy (GTK_RANGE (vscale), policy);
+}
+
+void cb_digits_scale( GtkAdjustment *adj )
+{
+    /* Set the number of decimal places to which adj->value is rounded */
+    gtk_scale_set_digits (GTK_SCALE (hscale), (gint) adj->value);
+    gtk_scale_set_digits (GTK_SCALE (vscale), (gint) adj->value);
+}
+
+void cb_page_size( GtkAdjustment *get,
+                   GtkAdjustment *set )
+{
+    /* Set the page size and page increment size of the sample
+     * adjustment to the value specified by the "Page Size" scale */
+    set->page_size = get->value;
+    set->page_increment = get->value;
+    /* Now emit the "changed" signal to reconfigure all the widgets that
+     * are attached to this adjustment */
+    gtk_signal_emit_by_name (GTK_OBJECT (set), "changed");
+}
+
+void cb_draw_value( GtkToggleButton *button )
+{
+    /* Turn the value display on the scale widgets off or on depending
+     *  on the state of the checkbutton */
+    gtk_scale_set_draw_value (GTK_SCALE (hscale), button->active);
+    gtk_scale_set_draw_value (GTK_SCALE (vscale), button->active);  
+}
+
+/* Convenience functions */
+
+GtkWidget *make_menu_item( gchar         *name,
+                           GtkSignalFunc  callback,
+                          gpointer       data )
+{
+    GtkWidget *item;
+  
+    item = gtk_menu_item_new_with_label (name);
+    gtk_signal_connect (GTK_OBJECT (item), "activate",
+                        callback, data);
+    gtk_widget_show (item);
+
+    return(item);
+}
+
+void scale_set_default_values( GtkScale *scale )
+{
+    gtk_range_set_update_policy (GTK_RANGE (scale),
+                                 GTK_UPDATE_CONTINUOUS);
+    gtk_scale_set_digits (scale, 1);
+    gtk_scale_set_value_pos (scale, GTK_POS_TOP);
+    gtk_scale_set_draw_value (scale, TRUE);
+}
+
+/* makes the sample window */
+
+void create_range_controls( void )
+{
+    GtkWidget *window;
+    GtkWidget *box1, *box2, *box3;
+    GtkWidget *button;
+    GtkWidget *scrollbar;
+    GtkWidget *separator;
+    GtkWidget *opt, *menu, *item;
+    GtkWidget *label;
+    GtkWidget *scale;
+    GtkObject *adj1, *adj2;
+
+    /* Standard window-creating stuff */
+    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+    gtk_signal_connect (GTK_OBJECT (window), "destroy",
+                        GTK_SIGNAL_FUNC(gtk_main_quit),
+                        NULL);
+    gtk_window_set_title (GTK_WINDOW (window), "range controls");
+
+    box1 = gtk_vbox_new (FALSE, 0);
+    gtk_container_add (GTK_CONTAINER (window), box1);
+    gtk_widget_show (box1);
+
+    box2 = gtk_hbox_new (FALSE, 10);
+    gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
+    gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
+    gtk_widget_show (box2);
+
+    /* value, lower, upper, step_increment, page_increment, page_size */
+    /* Note that the page_size value only makes a difference for
+     * scrollbar widgets, and the highest value you'll get is actually
+     * (upper - page_size). */
+    adj1 = gtk_adjustment_new (0.0, 0.0, 101.0, 0.1, 1.0, 1.0);
+  
+    vscale = gtk_vscale_new (GTK_ADJUSTMENT (adj1));
+    scale_set_default_values (GTK_SCALE (vscale));
+    gtk_box_pack_start (GTK_BOX (box2), vscale, TRUE, TRUE, 0);
+    gtk_widget_show (vscale);
+
+    box3 = gtk_vbox_new (FALSE, 10);
+    gtk_box_pack_start (GTK_BOX (box2), box3, TRUE, TRUE, 0);
+    gtk_widget_show (box3);
+
+    /* Reuse the same adjustment */
+    hscale = gtk_hscale_new (GTK_ADJUSTMENT (adj1));
+    gtk_widget_set_usize (GTK_WIDGET (hscale), 200, 30);
+    scale_set_default_values (GTK_SCALE (hscale));
+    gtk_box_pack_start (GTK_BOX (box3), hscale, TRUE, TRUE, 0);
+    gtk_widget_show (hscale);
+
+    /* Reuse the same adjustment again */
+    scrollbar = gtk_hscrollbar_new (GTK_ADJUSTMENT (adj1));
+    /* Notice how this causes the scales to always be updated
+     * continuously when the scrollbar is moved */
+    gtk_range_set_update_policy (GTK_RANGE (scrollbar), 
+                                 GTK_UPDATE_CONTINUOUS);
+    gtk_box_pack_start (GTK_BOX (box3), scrollbar, TRUE, TRUE, 0);
+    gtk_widget_show (scrollbar);
+
+    box2 = gtk_hbox_new (FALSE, 10);
+    gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
+    gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
+    gtk_widget_show (box2);
+
+    /* A checkbutton to control whether the value is displayed or not */
+    button = gtk_check_button_new_with_label("Display value on scale widgets");
+    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
+    gtk_signal_connect (GTK_OBJECT (button), "toggled",
+                        GTK_SIGNAL_FUNC(cb_draw_value), NULL);
+    gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
+    gtk_widget_show (button);
+  
+    box2 = gtk_hbox_new (FALSE, 10);
+    gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
+
+    /* An option menu to change the position of the value */
+    label = gtk_label_new ("Scale Value Position:");
+    gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0);
+    gtk_widget_show (label);
+  
+    opt = gtk_option_menu_new();
+    menu = gtk_menu_new();
+
+    item = make_menu_item ("Top",
+                           GTK_SIGNAL_FUNC(cb_pos_menu_select),
+                           GINT_TO_POINTER (GTK_POS_TOP));
+    gtk_menu_append (GTK_MENU (menu), item);
+  
+    item = make_menu_item ("Bottom", GTK_SIGNAL_FUNC (cb_pos_menu_select), 
+                           GINT_TO_POINTER (GTK_POS_BOTTOM));
+    gtk_menu_append (GTK_MENU (menu), item);
+  
+    item = make_menu_item ("Left", GTK_SIGNAL_FUNC (cb_pos_menu_select),
+                           GINT_TO_POINTER (GTK_POS_LEFT));
+    gtk_menu_append (GTK_MENU (menu), item);
+  
+    item = make_menu_item ("Right", GTK_SIGNAL_FUNC (cb_pos_menu_select),
+                            GINT_TO_POINTER (GTK_POS_RIGHT));
+    gtk_menu_append (GTK_MENU (menu), item);
+  
+    gtk_option_menu_set_menu (GTK_OPTION_MENU (opt), menu);
+    gtk_box_pack_start (GTK_BOX (box2), opt, TRUE, TRUE, 0);
+    gtk_widget_show (opt);
+
+    gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
+    gtk_widget_show (box2);
+
+    box2 = gtk_hbox_new (FALSE, 10);
+    gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
+
+    /* Yet another option menu, this time for the update policy of the
+     * scale widgets */
+    label = gtk_label_new ("Scale Update Policy:");
+    gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0);
+    gtk_widget_show (label);
+  
+    opt = gtk_option_menu_new();
+    menu = gtk_menu_new();
+  
+    item = make_menu_item ("Continuous",
+                           GTK_SIGNAL_FUNC (cb_update_menu_select),
+                           GINT_TO_POINTER (GTK_UPDATE_CONTINUOUS));
+    gtk_menu_append (GTK_MENU (menu), item);
+  
+    item = make_menu_item ("Discontinuous",
+                            GTK_SIGNAL_FUNC (cb_update_menu_select),
+                            GINT_TO_POINTER (GTK_UPDATE_DISCONTINUOUS));
+    gtk_menu_append (GTK_MENU (menu), item);
+  
+    item = make_menu_item ("Delayed",
+                           GTK_SIGNAL_FUNC (cb_update_menu_select),
+                           GINT_TO_POINTER (GTK_UPDATE_DELAYED));
+    gtk_menu_append (GTK_MENU (menu), item);
+  
+    gtk_option_menu_set_menu (GTK_OPTION_MENU (opt), menu);
+    gtk_box_pack_start (GTK_BOX (box2), opt, TRUE, TRUE, 0);
+    gtk_widget_show (opt);
+  
+    gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
+    gtk_widget_show (box2);
+
+    box2 = gtk_hbox_new (FALSE, 10);
+    gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
+  
+    /* An HScale widget for adjusting the number of digits on the
+     * sample scales. */
+    label = gtk_label_new ("Scale Digits:");
+    gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0);
+    gtk_widget_show (label);
+
+    adj2 = gtk_adjustment_new (1.0, 0.0, 5.0, 1.0, 1.0, 0.0);
+    gtk_signal_connect (GTK_OBJECT (adj2), "value_changed",
+                        GTK_SIGNAL_FUNC (cb_digits_scale), NULL);
+    scale = gtk_hscale_new (GTK_ADJUSTMENT (adj2));
+    gtk_scale_set_digits (GTK_SCALE (scale), 0);
+    gtk_box_pack_start (GTK_BOX (box2), scale, TRUE, TRUE, 0);
+    gtk_widget_show (scale);
+
+    gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
+    gtk_widget_show (box2);
+  
+    box2 = gtk_hbox_new (FALSE, 10);
+    gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
+  
+    /* And, one last HScale widget for adjusting the page size of the
+     * scrollbar. */
+    label = gtk_label_new ("Scrollbar Page Size:");
+    gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 0);
+    gtk_widget_show (label);
+
+    adj2 = gtk_adjustment_new (1.0, 1.0, 101.0, 1.0, 1.0, 0.0);
+    gtk_signal_connect (GTK_OBJECT (adj2), "value_changed",
+                        GTK_SIGNAL_FUNC (cb_page_size), adj1);
+    scale = gtk_hscale_new (GTK_ADJUSTMENT (adj2));
+    gtk_scale_set_digits (GTK_SCALE (scale), 0);
+    gtk_box_pack_start (GTK_BOX (box2), scale, TRUE, TRUE, 0);
+    gtk_widget_show (scale);
+
+    gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
+    gtk_widget_show (box2);
+
+    separator = gtk_hseparator_new ();
+    gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
+    gtk_widget_show (separator);
+
+    box2 = gtk_vbox_new (FALSE, 10);
+    gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
+    gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
+    gtk_widget_show (box2);
+
+    button = gtk_button_new_with_label ("Quit");
+    gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+                               GTK_SIGNAL_FUNC(gtk_main_quit),
+                               NULL);
+    gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
+    GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
+    gtk_widget_grab_default (button);
+    gtk_widget_show (button);
+
+    gtk_widget_show (window);
+}
+
+int main( int   argc,
+          char *argv[] )
+{
+    gtk_init(&amp;argc, &amp;argv);
+
+    create_range_controls();
+
+    gtk_main();
+
+    return(0);
+}
+
+/* example-end */
+</programlisting>
+
+<para>You will notice that the program does not call <literal>gtk_signal_connect</literal>
+for the "delete_event", but only for the "destroy" signal. This will
+still perform the desired function, because an unhandled
+"delete_event" will result in a "destroy" signal being given to the
+window.</para>
+
+</sect1>
+</chapter>
+
+<!-- ***************************************************************** -->
+<chapter id="ch-MiscWidgets">
+<title>Miscellaneous Widgets</title>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Labels</title>
+
+<para>Labels are used a lot in GTK, and are relatively simple. Labels emit
+no signals as they do not have an associated X window. If you need to
+catch signals, or do clipping, place it inside a <link linkend="ch-EventBox">
+EventBox</link> widget or a Button widget.</para>
+
+<para>To create a new label, use:</para>
+
+<para><literallayout>
+<literal>GtkWidget *gtk_label_new( char *str );</literal>
+</literallayout></para>
+
+<para>The sole argument is the string you wish the label to display.</para>
+
+<para>To change the label's text after creation, use the function:</para>
+
+<para><literallayout>
+<literal>void gtk_label_set_text( GtkLabel *label,
+                         char     *str );</literal>
+</literallayout></para>
+
+<para>The first argument is the label you created previously (cast
+using the <literal>GTK_LABEL()</literal> macro), and the second is the new string.</para>
+
+<para>The space needed for the new string will be automatically adjusted if
+needed. You can produce multi-line labels by putting line breaks in
+the label string.</para>
+
+<para>To retrieve the current string, use:</para>
+
+<para><literallayout>
+<literal>void gtk_label_get( GtkLabel  *label,
+                    char     **str );</literal>
+</literallayout></para>
+
+<para>The first argument is the label you've created, and the second,
+the return for the string. Do not free the return string, as it is
+used internally by GTK.</para>
+
+<para>The label text can be justified using:</para>
+
+<para><literallayout>
+<literal>void gtk_label_set_justify( GtkLabel         *label,
+                            GtkJustification  jtype );</literal>
+</literallayout></para>
+
+<para>Values for <literal>jtype</literal> are:</para>
+<para><literallayout>
+<literal>  GTK_JUSTIFY_LEFT
+  GTK_JUSTIFY_RIGHT
+  GTK_JUSTIFY_CENTER (the default)
+  GTK_JUSTIFY_FILL</literal>
+</literallayout></para>
+
+<para>The label widget is also capable of line wrapping the text
+automatically. This can be activated using:</para>
+
+<para><literallayout>
+<literal>void gtk_label_set_line_wrap (GtkLabel *label,
+                              gboolean  wrap);</literal>
+</literallayout></para>
+
+<para>The <literal>wrap</literal> argument takes a TRUE or FALSE value.</para>
+
+<para>If you want your label underlined, then you can set a pattern on the
+label:</para>
+
+<para><literallayout>
+<literal>void       gtk_label_set_pattern   (GtkLabel          *label,
+                                    const gchar       *pattern);</literal>
+</literallayout></para>
+
+<para>The pattern argument indicates how the underlining should look. It
+consists of a string of underscore and space characters. An underscore
+indicates that the corresponding character in the label should be
+underlined. For example, the string <verb/"__     __"/ would underline the
+first two characters and eight and ninth characters.</para>
+
+<para>Below is a short example to illustrate these functions. This example
+makes use of the Frame widget to better demonstrate the label
+styles. You can ignore this for now as the <link linkend="ch-Frames">Frame</link> widget is explained later on.</para>
+
+<programlisting role="C">
+/* example-start label label.c */
+
+int main( int   argc,
+          char *argv[] )
+{
+  static GtkWidget *window = NULL;
+  GtkWidget *hbox;
+  GtkWidget *vbox;
+  GtkWidget *frame;
+  GtkWidget *label;
+
+  /* Initialise GTK */
+  gtk_init(&amp;argc, &amp;argv);
+
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_signal_connect (GTK_OBJECT (window), "destroy",
+                     GTK_SIGNAL_FUNC(gtk_main_quit),
+                     NULL);
+
+  gtk_window_set_title (GTK_WINDOW (window), "Label");
+  vbox = gtk_vbox_new (FALSE, 5);
+  hbox = gtk_hbox_new (FALSE, 5);
+  gtk_container_add (GTK_CONTAINER (window), hbox);
+  gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
+  gtk_container_set_border_width (GTK_CONTAINER (window), 5);
+  
+  frame = gtk_frame_new ("Normal Label");
+  label = gtk_label_new ("This is a Normal label");
+  gtk_container_add (GTK_CONTAINER (frame), label);
+  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
+  
+  frame = gtk_frame_new ("Multi-line Label");
+  label = gtk_label_new ("This is a Multi-line label.\nSecond line\n" \
+                        "Third line");
+  gtk_container_add (GTK_CONTAINER (frame), label);
+  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
+  
+  frame = gtk_frame_new ("Left Justified Label");
+  label = gtk_label_new ("This is a Left-Justified\n" \
+                        "Multi-line label.\nThird      line");
+  gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
+  gtk_container_add (GTK_CONTAINER (frame), label);
+  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
+  
+  frame = gtk_frame_new ("Right Justified Label");
+  label = gtk_label_new ("This is a Right-Justified\nMulti-line label.\n" \
+                        "Fourth line, (j/k)");
+  gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_RIGHT);
+  gtk_container_add (GTK_CONTAINER (frame), label);
+  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
+
+  vbox = gtk_vbox_new (FALSE, 5);
+  gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
+  frame = gtk_frame_new ("Line wrapped label");
+  label = gtk_label_new ("This is an example of a line-wrapped label.  It " \
+                        "should not be taking up the entire             " /* big space to test spacing */\
+                        "width allocated to it, but automatically " \
+                        "wraps the words to fit.  " \
+                        "The time has come, for all good men, to come to " \
+                        "the aid of their party.  " \
+                        "The sixth sheik's six sheep's sick.\n" \
+                        "     It supports multiple paragraphs correctly, " \
+                        "and  correctly   adds "\
+                        "many          extra  spaces. ");
+  gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
+  gtk_container_add (GTK_CONTAINER (frame), label);
+  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
+  
+  frame = gtk_frame_new ("Filled, wrapped label");
+  label = gtk_label_new ("This is an example of a line-wrapped, filled label.  " \
+                        "It should be taking "\
+                        "up the entire              width allocated to it.  " \
+                        "Here is a sentence to prove "\
+                        "my point.  Here is another sentence. "\
+                        "Here comes the sun, do de do de do.\n"\
+                        "    This is a new paragraph.\n"\
+                        "    This is another newer, longer, better " \
+                        "paragraph.  It is coming to an end, "\
+                        "unfortunately.");
+  gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_FILL);
+  gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
+  gtk_container_add (GTK_CONTAINER (frame), label);
+  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
+  
+  frame = gtk_frame_new ("Underlined label");
+  label = gtk_label_new ("This label is underlined!\n"
+                        "This one is underlined in quite a funky fashion");
+  gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
+  gtk_label_set_pattern (GTK_LABEL (label),
+                        "_________________________ _ _________ _ ______     __ _______ ___");
+  gtk_container_add (GTK_CONTAINER (frame), label);
+  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
+  
+  gtk_widget_show_all (window);
+
+  gtk_main ();
+  
+  return(0);
+}
+/* example-end */
+</programlisting>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> Arrows</title>
+
+<para>The Arrow widget draws an arrowhead, facing in a number of possible
+directions and having a number of possible styles. It can be very
+useful when placed on a button in many applications. Like the Label
+widget, it emits no signals.</para>
+
+<para>There are only two functions for manipulating an Arrow widget:</para>
+
+<para><literallayout>
+<literal>GtkWidget *gtk_arrow_new( GtkArrowType   arrow_type,
+                          GtkShadowType  shadow_type );</para>
+
+<para>void gtk_arrow_set( GtkArrow      *arrow,
+                    GtkArrowType   arrow_type,
+                    GtkShadowType  shadow_type );</literal>
+</literallayout></para>
+
+<para>The first creates a new arrow widget with the indicated type and
+appearance. The second allows these values to be altered
+retrospectively. The <literal>arrow_type</literal> argument may take one of the
+following values:</para>
+
+<para><literallayout>
+<literal>  GTK_ARROW_UP
+  GTK_ARROW_DOWN
+  GTK_ARROW_LEFT
+  GTK_ARROW_RIGHT</literal>
+</literallayout></para>
+
+<para>These values obviously indicate the direction in which the arrow will
+point. The <literal>shadow_type</literal> argument may take one of these values:</para>
+
+<para><literallayout>
+<literal>  GTK_SHADOW_IN
+  GTK_SHADOW_OUT (the default)
+  GTK_SHADOW_ETCHED_IN
+  GTK_SHADOW_ETCHED_OUT</literal>
+</literallayout></para>
+
+<para>Here's a brief example to illustrate their use.</para>
+
+<programlisting role="C">
+/* example-start arrow arrow.c */
+
+#include &lt;gtk/gtk.h&gt;
+
+/* Create an Arrow widget with the specified parameters
+ * and pack it into a button */
+GtkWidget *create_arrow_button( GtkArrowType  arrow_type,
+                               GtkShadowType shadow_type )
+{
+  GtkWidget *button;
+  GtkWidget *arrow;
+
+  button = gtk_button_new();
+  arrow = gtk_arrow_new (arrow_type, shadow_type);
+
+  gtk_container_add (GTK_CONTAINER (button), arrow);
+  
+  gtk_widget_show(button);
+  gtk_widget_show(arrow);
+
+  return(button);
+}
+
+int main( int   argc,
+          char *argv[] )
+{
+  /* GtkWidget is the storage type for widgets */
+  GtkWidget *window;
+  GtkWidget *button;
+  GtkWidget *box;
+
+  /* Initialize the toolkit */
+  gtk_init (&amp;argc, &amp;argv);
+
+  /* Create a new window */
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
+  gtk_window_set_title (GTK_WINDOW (window), "Arrow Buttons");
+
+  /* It's a good idea to do this for all windows. */
+  gtk_signal_connect (GTK_OBJECT (window), "destroy",
+                     GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
+
+  /* Sets the border width of the window. */
+  gtk_container_set_border_width (GTK_CONTAINER (window), 10);
+
+  /* Create a box to hold the arrows/buttons */
+  box = gtk_hbox_new (FALSE, 0);
+  gtk_container_set_border_width (GTK_CONTAINER (box), 2);
+  gtk_container_add (GTK_CONTAINER (window), box);
+
+  /* Pack and show all our widgets */
+  gtk_widget_show(box);
+
+  button = create_arrow_button(GTK_ARROW_UP, GTK_SHADOW_IN);
+  gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 3);
+
+  button = create_arrow_button(GTK_ARROW_DOWN, GTK_SHADOW_OUT);
+  gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 3);
+  
+  button = create_arrow_button(GTK_ARROW_LEFT, GTK_SHADOW_ETCHED_IN);
+  gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 3);
+  
+  button = create_arrow_button(GTK_ARROW_RIGHT, GTK_SHADOW_ETCHED_OUT);
+  gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 3);
+  
+  gtk_widget_show (window);
+  
+  /* Rest in gtk_main and wait for the fun to begin! */
+  gtk_main ();
+  
+  return(0);
+}
+/* example-end */
+</programlisting>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>The Tooltips Object</title>
+
+<para>These are the little text strings that pop up when you leave your
+pointer over a button or other widget for a few seconds. They are easy
+to use, so I will just explain them without giving an example. If you
+want to see some code, take a look at the testgtk.c program
+distributed with GTK.</para>
+
+<para>Widgets that do not receive events (widgets that do not have their
+own window) will not work with tooltips.</para>
+
+<para>The first call you will use creates a new tooltip. You only need to do
+this once for a set of tooltips as the <literal>GtkTooltips</literal> object this
+function returns can be used to create multiple tooltips.</para>
+
+<para><literallayout>
+<literal>GtkTooltips *gtk_tooltips_new( void );</literal>
+</literallayout></para>
+
+<para>Once you have created a new tooltip, and the widget you wish to use it
+on, simply use this call to set it:</para>
+
+<para><literallayout>
+<literal>void gtk_tooltips_set_tip( GtkTooltips *tooltips,
+                           GtkWidget   *widget,
+                           const gchar *tip_text,
+                           const gchar *tip_private );</literal>
+</literallayout></para>
+
+<para>The first argument is the tooltip you've already created, followed by
+the widget you wish to have this tooltip pop up for, and the text you
+wish it to say. The last argument is a text string that can be used as
+an identifier when using GtkTipsQuery to implement context sensitive
+help. For now, you can set it to NULL.</para>
+
+<para><!-- TODO: sort out what how to do the context sensitive help --></para>
+
+<para>Here's a short example:</para>
+
+<para><literallayout>
+<literal>GtkTooltips *tooltips;
+GtkWidget *button;
+.
+.
+.
+tooltips = gtk_tooltips_new ();
+button = gtk_button_new_with_label ("button 1");
+.
+.
+.
+gtk_tooltips_set_tip (tooltips, button, "This is button 1", NULL);</literal>
+</literallayout></para>
+
+<para>There are other calls that can be used with tooltips. I will just list
+them with a brief description of what they do.</para>
+
+<para><literallayout>
+<literal>void gtk_tooltips_enable( GtkTooltips *tooltips );</literal>
+</literallayout></para>
+
+<para>Enable a disabled set of tooltips.</para>
+
+<para><literallayout>
+<literal>void gtk_tooltips_disable( GtkTooltips *tooltips );</literal>
+</literallayout></para>
+
+<para>Disable an enabled set of tooltips.</para>
+
+<para><literallayout>
+<literal>void gtk_tooltips_set_delay( GtkTooltips *tooltips,
+                             gint         delay );</para>
+
+<para></verb></tscreen></para>
+
+<para>Sets how many milliseconds you have to hold your pointer over the
+widget before the tooltip will pop up. The default is 500
+milliseconds (half a second).</para>
+
+<para><literallayout>
+<literal>void gtk_tooltips_set_colors( GtkTooltips *tooltips,
+                              GdkColor    *background,
+                              GdkColor    *foreground );</literal>
+</literallayout></para>
+
+<para>Set the foreground and background color of the tooltips.</para>
+
+<para>And that's all the functions associated with tooltips. More than
+you'll ever want to know :-)</para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1> Progress Bars
+
+<para>Progress bars are used to show the status of an operation. They are
+pretty easy to use, as you will see with the code below. But first
+lets start out with the calls to create a new progress bar.</para>
+
+<para>There are two ways to create a progress bar, one simple that takes
+no arguments, and one that takes an Adjustment object as an
+argument. If the former is used, the progress bar creates its own
+adjustment object.</para>
+
+<para><literallayout>
+<literal>GtkWidget *gtk_progress_bar_new( void );</para>
+
+<para>GtkWidget *gtk_progress_bar_new_with_adjustment( GtkAdjustment *adjustment );</literal>
+</literallayout></para>
+
+<para>The second method has the advantage that we can use the adjustment
+object to specify our own range parameters for the progress bar.</para>
+
+<para>The adjustment of a progress object can be changed dynamically using:</para>
+
+<para><literallayout>
+<literal>void gtk_progress_set_adjustment( GtkProgress   *progress,
+                                  GtkAdjustment *adjustment );</literal>
+</literallayout></para>
+
+<para>Now that the progress bar has been created we can use it.</para>
+
+<para><literallayout>
+<literal>void gtk_progress_bar_update( GtkProgressBar *pbar,
+                              gfloat          percentage );</literal>
+</literallayout></para>
+
+<para>The first argument is the progress bar you wish to operate on, and the
+second argument is the amount "completed", meaning the amount the
+progress bar has been filled from 0-100%. This is passed to the
+function as a real number ranging from 0 to 1.</para>
+
+<para>GTK v1.2 has added new functionality to the progress bar that enables
+it to display its value in different ways, and to inform the user of
+its current value and its range.</para>
+
+<para>A progress bar may be set to one of a number of orientations using the
+function</para>
+
+<para><literallayout>
+<literal>void gtk_progress_bar_set_orientation( GtkProgressBar *pbar,
+                                       GtkProgressBarOrientation orientation );</literal>
+</literallayout></para>
+
+<para>The <literal>orientation</literal> argument may take one of the following
+values to indicate the direction in which the progress bar moves:</para>
+
+<para><literallayout>
+<literal>  GTK_PROGRESS_LEFT_TO_RIGHT
+  GTK_PROGRESS_RIGHT_TO_LEFT
+  GTK_PROGRESS_BOTTOM_TO_TOP
+  GTK_PROGRESS_TOP_TO_BOTTOM</literal>
+</literallayout></para>
+
+<para>When used as a measure of how far a process has progressed, the
+ProgressBar can be set to display its value in either a continuous
+or discrete mode. In continuous mode, the progress bar is updated for
+each value. In discrete mode, the progress bar is updated in a number
+of discrete blocks. The number of blocks is also configurable.</para>
+
+<para>The style of a progress bar can be set using the following function.</para>
+
+<para><literallayout>
+<literal>void gtk_progress_bar_set_bar_style( GtkProgressBar      *pbar,
+                                     GtkProgressBarStyle  style );</literal>
+</literallayout></para>
+
+<para>The <literal>style</literal> parameter can take one of two values:</para>
+
+<para><literallayout>
+<literal>  GTK_PROGRESS_CONTINUOUS
+  GTK_PROGRESS_DISCRETE</literal>
+</literallayout></para>
+
+<para>The number of discrete blocks can be set by calling</para>
+
+<para><literallayout>
+<literal>void gtk_progress_bar_set_discrete_blocks( GtkProgressBar *pbar,
+                                           guint           blocks );</literal>
+</literallayout></para>
+
+<para>As well as indicating the amount of progress that has occured, the
+progress bar may be set to just indicate that there is some
+activity. This can be useful in situations where progress cannot be
+measured against a value range. Activity mode is not effected by the
+bar style that is described above, and overrides it. This mode is
+either TRUE or FALSE, and is selected by the following function.</para>
+
+<para><literallayout>
+<literal>void gtk_progress_set_activity_mode( GtkProgress *progress,
+                                     guint        activity_mode );</literal>
+</literallayout></para>
+
+<para>The step size of the activity indicator, and the number of blocks are
+set using the following functions.</para>
+
+<para><literallayout>
+<literal>void gtk_progress_bar_set_activity_step( GtkProgressBar *pbar,
+                                         guint           step );</para>
+
+<para>void gtk_progress_bar_set_activity_blocks( GtkProgressBar *pbar,
+                                           guint           blocks );</literal>
+</literallayout></para>
+
+<para>When in continuous mode, the progress bar can also display a
+configurable text string within its trough, using the following
+function.</para>
+
+<para><literallayout>
+<literal>void gtk_progress_set_format_string( GtkProgress *progress,
+                                     gchar       *format);</literal>
+</literallayout></para>
+
+<para>The <literal>format</literal> argument is similiar to one that would be used in a C
+<literal>printf</literal> statement. The following directives may be used within the
+format string:</para>
+
+<itemizedlist>
+<listitem><simpara> %p - percentage</simpara>
+</listitem>
+<listitem><simpara> %v - value</simpara>
+</listitem>
+<listitem><simpara> %l - lower range value</simpara>
+</listitem>
+<listitem><simpara> %u - upper range value</simpara>
+</listitem>
+</itemizedlist>
+
+<para>The displaying of this text string can be toggled using:</para>
+
+<para><literallayout>
+<literal>void gtk_progress_set_show_text( GtkProgress *progress,
+                                 gint         show_text );</literal>
+</literallayout></para>
+
+<para>The <literal>show_text</literal> argument is a boolean TRUE/FALSE value. The
+appearance of the text can be modified further using:</para>
+
+<para><literallayout>
+<literal>void gtk_progress_set_text_alignment( GtkProgress   *progress,
+                                      gfloat         x_align,
+                                      gfloat         y_align );</literal>
+</literallayout></para>
+
+<para>The <literal>x_align</literal> and <literal>y_align</literal> arguments take values between 0.0
+and 1.0. Their values indicate the position of the text string within
+the trough. Values of 0.0 for both would place the string in the top
+left hand corner; values of 0.5 (the default) centres the text, and
+values of 1.0 places the text in the lower right hand corner.</para>
+
+<para>The current text setting of a progress object can be retrieved using
+the current or a specified adjustment value using the following two
+functions. The character string returned by these functions should be
+freed by the application (using the g_free() function). These
+functions return the formatted string that would be displayed within
+the trough.</para>
+
+<para><literallayout>
+<literal>gchar *gtk_progress_get_current_text( GtkProgress   *progress );</para>
+
+<para>gchar *gtk_progress_get_text_from_value( GtkProgress *progress,
+                                         gfloat       value );</literal>
+</literallayout></para>
+
+<para>There is yet another way to change the range and value of a progress
+object using the following function:</para>
+
+<para><literallayout>
+<literal>void gtk_progress_configure( GtkProgress  *progress,
+                             gfloat        value,
+                             gfloat        min,
+                             gfloat        max );</literal>
+</literallayout></para>
+
+<para>This function provides quite a simple interface to the range and value
+of a progress object.</para>
+
+<para>The remaining functions can be used to get and set the current value
+of a progess object in various types and formats:</para>
+
+<para><literallayout>
+<literal>void gtk_progress_set_percentage( GtkProgress *progress,
+                                  gfloat       percentage );</para>
+
+<para>void gtk_progress_set_value( GtkProgress *progress,
+                             gfloat       value );</para>
+
+<para>gfloat gtk_progress_get_value( GtkProgress *progress );</para>
+
+<para>gfloat gtk_progress_get_current_percentage( GtkProgress *progress );</para>
+
+<para>gfloat gtk_progress_get_percentage_from_value( GtkProgress *progress,
+                                               gfloat       value );</literal>
+</literallayout></para>
+
+<para>These functions are pretty self explanatory. The last function uses
+the the adjustment of the specified progess object to compute the
+percentage value of the given range value.</para>
+
+<para>Progress Bars are usually used with timeouts or other such functions
+(see section on <link linkend="ch-Timeouts">Timeouts, I/O and Idle Functions</link>) to give
+the illusion of multitasking. All will employ the
+gtk_progress_bar_update function in the same manner.</para>
+
+<para>Here is an example of the progress bar, updated using timeouts. This
+code also shows you how to reset the Progress Bar.</para>
+
+<programlisting role="C">
+/* example-start progressbar progressbar.c */
+
+#include &lt;gtk/gtk.h&gt;
+
+typedef struct _ProgressData {
+    GtkWidget *window;
+    GtkWidget *pbar;
+    int timer;
+} ProgressData;
+
+/* Update the value of the progress bar so that we get
+ * some movement */
+gint progress_timeout( gpointer data )
+{
+    gfloat new_val;
+    GtkAdjustment *adj;
+
+    /* Calculate the value of the progress bar using the
+     * value range set in the adjustment object */
+
+    new_val = gtk_progress_get_value( GTK_PROGRESS(data) ) + 1;
+
+    adj = GTK_PROGRESS (data)->adjustment;
+    if (new_val > adj->upper)
+      new_val = adj->lower;
+
+    /* Set the new value */
+    gtk_progress_set_value (GTK_PROGRESS (data), new_val);
+
+    /* As this is a timeout function, return TRUE so that it
+     * continues to get called */
+    return(TRUE);
+} 
+
+/* Callback that toggles the text display within the progress
+ * bar trough */
+void toggle_show_text( GtkWidget    *widget,
+                      ProgressData *pdata )
+{
+    gtk_progress_set_show_text (GTK_PROGRESS (pdata->pbar),
+                                GTK_TOGGLE_BUTTON (widget)->active);
+}
+
+/* Callback that toggles the activity mode of the progress
+ * bar */
+void toggle_activity_mode( GtkWidget    *widget,
+                          ProgressData *pdata )
+{
+    gtk_progress_set_activity_mode (GTK_PROGRESS (pdata->pbar),
+                                    GTK_TOGGLE_BUTTON (widget)->active);
+}
+
+/* Callback that toggles the continuous mode of the progress
+ * bar */
+void set_continuous_mode( GtkWidget    *widget,
+                         ProgressData *pdata )
+{
+    gtk_progress_bar_set_bar_style (GTK_PROGRESS_BAR (pdata->pbar),
+                                    GTK_PROGRESS_CONTINUOUS);
+}
+
+/* Callback that toggles the discrete mode of the progress
+ * bar */
+void set_discrete_mode( GtkWidget    *widget,
+                       ProgressData *pdata )
+{
+    gtk_progress_bar_set_bar_style (GTK_PROGRESS_BAR (pdata->pbar),
+                                    GTK_PROGRESS_DISCRETE);
+}
+/* Clean up allocated memory and remove the timer */
+void destroy_progress( GtkWidget     *widget,
+                      ProgressData *pdata)
+{
+    gtk_timeout_remove (pdata->timer);
+    pdata->timer = 0;
+    pdata->window = NULL;
+    g_free(pdata);
+    gtk_main_quit();
+}
+
+int main( int   argc,
+          char *argv[])
+{
+    ProgressData *pdata;
+    GtkWidget *align;
+    GtkWidget *separator;
+    GtkWidget *table;
+    GtkAdjustment *adj;
+    GtkWidget *button;
+    GtkWidget *check;
+    GtkWidget *vbox;
+
+    gtk_init (&amp;argc, &amp;argv);
+
+    /* Allocate memory for the data that is passwd to the callbacks */
+    pdata = g_malloc( sizeof(ProgressData) );
+  
+    pdata->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+    gtk_window_set_policy (GTK_WINDOW (pdata->window), FALSE, FALSE, TRUE);
+
+    gtk_signal_connect (GTK_OBJECT (pdata->window), "destroy",
+                       GTK_SIGNAL_FUNC (destroy_progress),
+                        pdata);
+    gtk_window_set_title (GTK_WINDOW (pdata->window), "GtkProgressBar");
+    gtk_container_set_border_width (GTK_CONTAINER (pdata->window), 0);
+
+    vbox = gtk_vbox_new (FALSE, 5);
+    gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
+    gtk_container_add (GTK_CONTAINER (pdata->window), vbox);
+    gtk_widget_show(vbox);
+  
+    /* Create a centering alignment object */
+    align = gtk_alignment_new (0.5, 0.5, 0, 0);
+    gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 5);
+    gtk_widget_show(align);
+
+    /* Create a Adjusment object to hold the range of the
+     * progress bar */
+    adj = (GtkAdjustment *) gtk_adjustment_new (0, 1, 150, 0, 0, 0);
+
+    /* Create the GtkProgressBar using the adjustment */
+    pdata->pbar = gtk_progress_bar_new_with_adjustment (adj);
+
+    /* Set the format of the string that can be displayed in the
+     * trough of the progress bar:
+     * %p - percentage
+     * %v - value
+     * %l - lower range value
+     * %u - upper range value */
+    gtk_progress_set_format_string (GTK_PROGRESS (pdata->pbar),
+                                   "%v from [%l-%u] (=%p%%)");
+    gtk_container_add (GTK_CONTAINER (align), pdata->pbar);
+    gtk_widget_show(pdata->pbar);
+
+    /* Add a timer callback to update the value of the progress bar */
+    pdata->timer = gtk_timeout_add (100, progress_timeout, pdata->pbar);
+
+    separator = gtk_hseparator_new ();
+    gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, 0);
+    gtk_widget_show(separator);
+
+    /* rows, columns, homogeneous */
+    table = gtk_table_new (2, 3, FALSE);
+    gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0);
+    gtk_widget_show(table);
+
+    /* Add a check button to select displaying of the trough text */
+    check = gtk_check_button_new_with_label ("Show text");
+    gtk_table_attach (GTK_TABLE (table), check, 0, 1, 0, 1,
+                      GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
+                      5, 5);
+    gtk_signal_connect (GTK_OBJECT (check), "clicked",
+                        GTK_SIGNAL_FUNC (toggle_show_text),
+                        pdata);
+    gtk_widget_show(check);
+
+    /* Add a check button to toggle activity mode */
+    check = gtk_check_button_new_with_label ("Activity mode");
+    gtk_table_attach (GTK_TABLE (table), check, 0, 1, 1, 2,
+                      GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
+                      5, 5);
+    gtk_signal_connect (GTK_OBJECT (check), "clicked",
+                        GTK_SIGNAL_FUNC (toggle_activity_mode),
+                        pdata);
+    gtk_widget_show(check);
+
+    separator = gtk_vseparator_new ();
+    gtk_table_attach (GTK_TABLE (table), separator, 1, 2, 0, 2,
+                      GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
+                      5, 5);
+    gtk_widget_show(separator);
+
+    /* Add a radio button to select continuous display mode */
+    button = gtk_radio_button_new_with_label (NULL, "Continuous");
+    gtk_table_attach (GTK_TABLE (table), button, 2, 3, 0, 1,
+                      GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
+                      5, 5);
+    gtk_signal_connect (GTK_OBJECT (button), "clicked",
+                        GTK_SIGNAL_FUNC (set_continuous_mode),
+                        pdata);
+    gtk_widget_show (button);
+
+    /* Add a radio button to select discrete display mode */
+    button = gtk_radio_button_new_with_label(
+               gtk_radio_button_group (GTK_RADIO_BUTTON (button)),
+               "Discrete");
+    gtk_table_attach (GTK_TABLE (table), button, 2, 3, 1, 2,
+                      GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
+                      5, 5);
+    gtk_signal_connect (GTK_OBJECT (button), "clicked",
+                        GTK_SIGNAL_FUNC (set_discrete_mode),
+                        pdata);
+    gtk_widget_show (button);
+
+    separator = gtk_hseparator_new ();
+    gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, 0);
+    gtk_widget_show(separator);
+
+    /* Add a button to exit the program */
+    button = gtk_button_new_with_label ("close");
+    gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+                               (GtkSignalFunc) gtk_widget_destroy,
+                               GTK_OBJECT (pdata->window));
+    gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
+
+    /* This makes it so the button is the default. */
+    GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
+
+    /* This grabs this button to be the default button. Simply hitting
+     * the "Enter" key will cause this button to activate. */
+    gtk_widget_grab_default (button);
+    gtk_widget_show(button);
+
+    gtk_widget_show (pdata->window);
+
+    gtk_main ();
+    
+    return(0);
+}
+/* example-end */
+</programlisting>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> Dialogs</title>
+
+<para>The Dialog widget is very simple, and is actually just a window with a
+few things pre-packed into it for you. The structure for a Dialog is:</para>
+
+<para><literallayout>
+<literal>struct GtkDialog
+{
+      GtkWindow window;
+    
+      GtkWidget *vbox;
+      GtkWidget *action_area;
+};</literal>
+</literallayout></para>
+
+<para>So you see, it simply creates a window, and then packs a vbox into the
+top, which contains a separator and then an hbox called the
+"action_area".</para>
+
+<para>The Dialog widget can be used for pop-up messages to the user, and
+other similar tasks. It is really basic, and there is only one
+function for the dialog box, which is:</para>
+
+<para><literallayout>
+<literal>GtkWidget *gtk_dialog_new( void );</literal>
+</literallayout></para>
+
+<para>So to create a new dialog box, use,</para>
+
+<para><literallayout>
+<literal>    GtkWidget *window;
+    window = gtk_dialog_new ();</literal>
+</literallayout></para>
+
+<para>This will create the dialog box, and it is now up to you to use it.
+You could pack a button in the action_area by doing something like this:</para>
+
+<para><literallayout>
+<literal>    button = ...
+    gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area),
+                        button, TRUE, TRUE, 0);
+    gtk_widget_show (button);</literal>
+</literallayout></para>
+
+<para>And you could add to the vbox area by packing, for instance, a label 
+in it, try something like this:</para>
+
+<para><literallayout>
+<literal>    label = gtk_label_new ("Dialogs are groovy");
+    gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox),
+                        label, TRUE, TRUE, 0);
+    gtk_widget_show (label);</literal>
+</literallayout></para>
+
+<para>As an example in using the dialog box, you could put two buttons in
+the action_area, a Cancel button and an Ok button, and a label in the
+vbox area, asking the user a question or giving an error etc. Then
+you could attach a different signal to each of the buttons and perform
+the operation the user selects.</para>
+
+<para>If the simple functionality provided by the default vertical and
+horizontal boxes in the two areas doesn't give you enough control for
+your application, then you can simply pack another layout widget into
+the boxes provided. For example, you could pack a table into the
+vertical box.</para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1> Pixmaps
+
+<para>Pixmaps are data structures that contain pictures. These pictures can
+be used in various places, but most commonly as icons on the X
+desktop, or as cursors.</para>
+
+<para>A pixmap which only has 2 colors is called a bitmap, and there are a
+few additional routines for handling this common special case.</para>
+
+<para>To understand pixmaps, it would help to understand how X window
+system works. Under X, applications do not need to be running on the
+same computer that is interacting with the user. Instead, the various
+applications, called "clients", all communicate with a program which
+displays the graphics and handles the keyboard and mouse. This
+program which interacts directly with the user is called a "display
+server" or "X server." Since the communication might take place over
+a network, it's important to keep some information with the X server.
+Pixmaps, for example, are stored in the memory of the X server. This
+means that once pixmap values are set, they don't need to keep getting
+transmitted over the network; instead a command is sent to "display
+pixmap number XYZ here." Even if you aren't using X with GTK
+currently, using constructs such as Pixmaps will make your programs
+work acceptably under X.</para>
+
+<para>To use pixmaps in GTK, we must first build a GdkPixmap structure using
+routines from the GDK layer. Pixmaps can either be created from
+in-memory data, or from data read from a file. We'll go through each
+of the calls to create a pixmap.</para>
+
+<para><literallayout>
+<literal>GdkPixmap *gdk_bitmap_create_from_data( GdkWindow *window,
+                                        gchar     *data,
+                                        gint       width,
+                                        gint       height );</literal>
+</literallayout></para>
+
+<para>This routine is used to create a single-plane pixmap (2 colors) from
+data in memory. Each bit of the data represents whether that pixel is
+off or on. Width and height are in pixels. The GdkWindow pointer is to
+the current window, since a pixmap's resources are meaningful only in
+the context of the screen where it is to be displayed.</para>
+
+<para><literallayout>
+<literal>GdkPixmap *gdk_pixmap_create_from_data( GdkWindow *window,
+                                        gchar     *data,
+                                        gint       width,
+                                        gint       height,
+                                        gint       depth,
+                                        GdkColor  *fg,
+                                        GdkColor  *bg );</literal>
+</literallayout></para>
+
+<para>This is used to create a pixmap of the given depth (number of colors) from
+the bitmap data specified. <literal>fg</literal> and <literal>bg</literal> are the foreground and
+background color to use.</para>
+
+<para><literallayout>
+<literal>GdkPixmap *gdk_pixmap_create_from_xpm( GdkWindow   *window,
+                                       GdkBitmap  **mask,
+                                       GdkColor    *transparent_color,
+                                       const gchar *filename );</literal>
+</literallayout></para>
+
+<para>XPM format is a readable pixmap representation for the X Window
+System. It is widely used and many different utilities are available
+for creating image files in this format. The file specified by
+filename must contain an image in that format and it is loaded into
+the pixmap structure. The mask specifies which bits of the pixmap are
+opaque. All other bits are colored using the color specified by
+transparent_color. An example using this follows below.</para>
+
+<para><literallayout>
+<literal>GdkPixmap *gdk_pixmap_create_from_xpm_d( GdkWindow  *window,
+                                         GdkBitmap **mask,
+                                         GdkColor   *transparent_color,
+                                         gchar     **data );</literal>
+</literallayout></para>
+
+<para>Small images can be incorporated into a program as data in the XPM
+format. A pixmap is created using this data, instead of reading it
+from a file. An example of such data is</para>
+
+<programlisting role="C">
+/* XPM */
+static const char * xpm_data[] = {
+"16 16 3 1",
+"       c None",
+".      c #000000000000",
+"X      c #FFFFFFFFFFFF",
+"                ",
+"   ......       ",
+"   .XXX.X.      ",
+"   .XXX.XX.     ",
+"   .XXX.XXX.    ",
+"   .XXX.....    ",
+"   .XXXXXXX.    ",
+"   .XXXXXXX.    ",
+"   .XXXXXXX.    ",
+"   .XXXXXXX.    ",
+"   .XXXXXXX.    ",
+"   .XXXXXXX.    ",
+"   .XXXXXXX.    ",
+"   .........    ",
+"                ",
+"                "};</literal>
+</literallayout></para>
+
+<para>When we're done using a pixmap and not likely to reuse it again soon,
+it is a good idea to release the resource using
+gdk_pixmap_unref(). Pixmaps should be considered a precious resource,
+because they take up memory in the end-user's X server process. Even
+though the X client you write may run on a powerful "server" computer,
+the user may be running the X server on a small personal computer.</para>
+
+<para>Once we've created a pixmap, we can display it as a GTK widget. We
+must create a GTK pixmap widget to contain the GDK pixmap. This is
+done using</para>
+
+<para><literallayout>
+<literal>GtkWidget *gtk_pixmap_new( GdkPixmap *pixmap,
+                           GdkBitmap *mask );</literal>
+</literallayout></para>
+
+<para>The other pixmap widget calls are</para>
+
+<para><literallayout>
+<literal>guint gtk_pixmap_get_type( void );</para>
+
+<para>void  gtk_pixmap_set( GtkPixmap  *pixmap,
+                      GdkPixmap  *val,
+                      GdkBitmap  *mask );</para>
+
+<para>void  gtk_pixmap_get( GtkPixmap  *pixmap,
+                      GdkPixmap **val,
+                      GdkBitmap **mask);</literal>
+</literallayout></para>
+
+<para>gtk_pixmap_set is used to change the pixmap that the widget is currently
+managing. Val is the pixmap created using GDK.</para>
+
+<para>The following is an example of using a pixmap in a button.</para>
+
+<programlisting role="C">
+/* example-start pixmap pixmap.c */
+
+#include &lt;gtk/gtk.h&gt;
+
+
+/* XPM data of Open-File icon */
+static const char * xpm_data[] = {
+"16 16 3 1",
+"       c None",
+".      c #000000000000",
+"X      c #FFFFFFFFFFFF",
+"                ",
+"   ......       ",
+"   .XXX.X.      ",
+"   .XXX.XX.     ",
+"   .XXX.XXX.    ",
+"   .XXX.....    ",
+"   .XXXXXXX.    ",
+"   .XXXXXXX.    ",
+"   .XXXXXXX.    ",
+"   .XXXXXXX.    ",
+"   .XXXXXXX.    ",
+"   .XXXXXXX.    ",
+"   .XXXXXXX.    ",
+"   .........    ",
+"                ",
+"                "};
+
+
+/* when invoked (via signal delete_event), terminates the application.
+ */
+gint close_application( GtkWidget *widget,
+                        GdkEvent  *event,
+                        gpointer   data )
+{
+    gtk_main_quit();
+    return(FALSE);
+}
+
+
+/* is invoked when the button is clicked.  It just prints a message.
+ */
+void button_clicked( GtkWidget *widget,
+                     gpointer   data ) {
+    g_print( "button clicked\n" );
+}
+
+int main( int   argc,
+          char *argv[] )
+{
+    /* GtkWidget is the storage type for widgets */
+    GtkWidget *window, *pixmapwid, *button;
+    GdkPixmap *pixmap;
+    GdkBitmap *mask;
+    GtkStyle *style;
+    
+    /* create the main window, and attach delete_event signal to terminating
+       the application */
+    gtk_init( &amp;argc, &amp;argv );
+    window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
+    gtk_signal_connect( GTK_OBJECT (window), "delete_event",
+                        GTK_SIGNAL_FUNC (close_application), NULL );
+    gtk_container_set_border_width( GTK_CONTAINER (window), 10 );
+    gtk_widget_show( window );
+
+    /* now for the pixmap from gdk */
+    style = gtk_widget_get_style( window );
+    pixmap = gdk_pixmap_create_from_xpm_d( window->window,  &amp;mask,
+                                           &amp;style->bg[GTK_STATE_NORMAL],
+                                           (gchar **)xpm_data );
+
+    /* a pixmap widget to contain the pixmap */
+    pixmapwid = gtk_pixmap_new( pixmap, mask );
+    gtk_widget_show( pixmapwid );
+
+    /* a button to contain the pixmap widget */
+    button = gtk_button_new();
+    gtk_container_add( GTK_CONTAINER(button), pixmapwid );
+    gtk_container_add( GTK_CONTAINER(window), button );
+    gtk_widget_show( button );
+
+    gtk_signal_connect( GTK_OBJECT(button), "clicked",
+                        GTK_SIGNAL_FUNC(button_clicked), NULL );
+
+    /* show the window */
+    gtk_main ();
+          
+    return 0;
+}
+/* example-end */
+</programlisting>
+
+<para>To load a file from an XPM data file called icon0.xpm in the current
+directory, we would have created the pixmap thus</para>
+
+<para><literallayout>
+<literal>    /* load a pixmap from a file */
+    pixmap = gdk_pixmap_create_from_xpm( window->window, &amp;mask,
+                                         &amp;style->bg[GTK_STATE_NORMAL],
+                                         "./icon0.xpm" );
+    pixmapwid = gtk_pixmap_new( pixmap, mask );
+    gtk_widget_show( pixmapwid );
+    gtk_container_add( GTK_CONTAINER(window), pixmapwid );</literal>
+</literallayout></para>
+
+<para>A disadvantage of using pixmaps is that the displayed object is always
+rectangular, regardless of the image. We would like to create desktops
+and applications with icons that have more natural shapes. For
+example, for a game interface, we would like to have round buttons to
+push. The way to do this is using shaped windows.</para>
+
+<para>A shaped window is simply a pixmap where the background pixels are
+transparent. This way, when the background image is multi-colored, we
+don't overwrite it with a rectangular, non-matching border around our
+icon. The following example displays a full wheelbarrow image on the
+desktop.</para>
+
+<programlisting role="C">
+/* example-start wheelbarrow wheelbarrow.c */
+
+#include &lt;gtk/gtk.h&gt;
+
+/* XPM */
+static char * WheelbarrowFull_xpm[] = {
+"48 48 64 1",
+"       c None",
+".      c #DF7DCF3CC71B",
+"X      c #965875D669A6",
+"o      c #71C671C671C6",
+"O      c #A699A289A699",
+"+      c #965892489658",
+"@      c #8E38410330C2",
+"#      c #D75C7DF769A6",
+"$      c #F7DECF3CC71B",
+"%      c #96588A288E38",
+"&amp;      c #A69992489E79",
+"*      c #8E3886178E38",
+"=      c #104008200820",
+"-      c #596510401040",
+";      c #C71B30C230C2",
+":      c #C71B9A699658",
+">      c #618561856185",
+",      c #20811C712081",
+"<      c #104000000000",
+"1      c #861720812081",
+"2      c #DF7D4D344103",
+"3      c #79E769A671C6",
+"4      c #861782078617",
+"5      c #41033CF34103",
+"6      c #000000000000",
+"7      c #49241C711040",
+"8      c #492445144924",
+"9      c #082008200820",
+"0      c #69A618611861",
+"q      c #B6DA71C65144",
+"w      c #410330C238E3",
+"e      c #CF3CBAEAB6DA",
+"r      c #71C6451430C2",
+"t      c #EFBEDB6CD75C",
+"y      c #28A208200820",
+"u      c #186110401040",
+"i      c #596528A21861",
+"p      c #71C661855965",
+"a      c #A69996589658",
+"s      c #30C228A230C2",
+"d      c #BEFBA289AEBA",
+"f      c #596545145144",
+"g      c #30C230C230C2",
+"h      c #8E3882078617",
+"j      c #208118612081",
+"k      c #38E30C300820",
+"l      c #30C2208128A2",
+"z      c #38E328A238E3",
+"x      c #514438E34924",
+"c      c #618555555965",
+"v      c #30C2208130C2",
+"b      c #38E328A230C2",
+"n      c #28A228A228A2",
+"m      c #41032CB228A2",
+"M      c #104010401040",
+"N      c #492438E34103",
+"B      c #28A2208128A2",
+"V      c #A699596538E3",
+"C      c #30C21C711040",
+"Z      c #30C218611040",
+"A      c #965865955965",
+"S      c #618534D32081",
+"D      c #38E31C711040",
+"F      c #082000000820",
+"                                                ",
+"          .XoO                                  ",
+"         +@#$%o&amp;                                ",
+"         *=-;#::o+                              ",
+"           >,<12#:34                            ",
+"             45671#:X3                          ",
+"               +89<02qwo                        ",
+"e*                >,67;ro                       ",
+"ty>                 459@>+&amp;&amp;                    ",
+"$2u+                  ><ipas8*                  ",
+"%$;=*                *3:.Xa.dfg>                ",
+"Oh$;ya             *3d.a8j,Xe.d3g8+             ",
+" Oh$;ka          *3d$a8lz,,xxc:.e3g54           ",
+"  Oh$;kO       *pd$%svbzz,sxxxxfX..&amp;wn>         ",
+"   Oh$@mO    *3dthwlsslszjzxxxxxxx3:td8M4       ",
+"    Oh$@g&amp; *3d$XNlvvvlllm,mNwxxxxxxxfa.:,B*     ",
+"     Oh$@,Od.czlllllzlmmqV@V#V@fxxxxxxxf:%j5&amp;   ",
+"      Oh$1hd5lllslllCCZrV#r#:#2AxxxxxxxxxcdwM*  ",
+"       OXq6c.%8vvvllZZiqqApA:mq:Xxcpcxxxxxfdc9* ",
+"        2r<6gde3bllZZrVi7S@SV77A::qApxxxxxxfdcM ",
+"        :,q-6MN.dfmZZrrSS:#riirDSAX@Af5xxxxxfevo",
+"         +A26jguXtAZZZC7iDiCCrVVii7Cmmmxxxxxx%3g",
+"          *#16jszN..3DZZZZrCVSA2rZrV7Dmmwxxxx&amp;en",
+"           p2yFvzssXe:fCZZCiiD7iiZDiDSSZwwxx8e*>",
+"           OA1<jzxwwc:$d%NDZZZZCCCZCCZZCmxxfd.B ",
+"            3206Bwxxszx%et.eaAp77m77mmmf3&amp;eeeg* ",
+"             @26MvzxNzvlbwfpdettttttttttt.c,n&amp;  ",
+"             *;16=lsNwwNwgsvslbwwvccc3pcfu<o    ",
+"              p;<69BvwwsszslllbBlllllllu<5+     ",
+"              OS0y6FBlvvvzvzss,u=Blllj=54       ",
+"               c1-699Blvlllllu7k96MMMg4         ",
+"               *10y8n6FjvllllB<166668           ",
+"                S-kg+>666<M<996-y6n<8*          ",
+"                p71=4 m69996kD8Z-66698&amp;&amp;        ",
+"                &amp;i0ycm6n4 ogk17,0<6666g         ",
+"                 N-k-<>     >=01-kuu666>        ",
+"                 ,6ky&amp;      &amp;46-10ul,66,        ",
+"                 Ou0<>       o66y<ulw<66&amp;       ",
+"                  *kk5       >66By7=xu664       ",
+"                   <<M4      466lj<Mxu66o       ",
+"                   *>>       +66uv,zN666*       ",
+"                              566,xxj669        ",
+"                              4666FF666>        ",
+"                               >966666M         ",
+"                                oM6668+         ",
+"                                  *4            ",
+"                                                ",
+"                                                "};
+
+
+/* When invoked (via signal delete_event), terminates the application */
+gint close_application( GtkWidget *widget,
+                        GdkEvent  *event,
+                        gpointer   data )
+{
+    gtk_main_quit();
+    return(FALSE);
+}
+
+int main (int argc,
+          char *argv[] )
+{
+    /* GtkWidget is the storage type for widgets */
+    GtkWidget *window, *pixmap, *fixed;
+    GdkPixmap *gdk_pixmap;
+    GdkBitmap *mask;
+    GtkStyle *style;
+    GdkGC *gc;
+    
+    /* Create the main window, and attach delete_event signal to terminate
+     * the application.  Note that the main window will not have a titlebar
+     * since we're making it a popup. */
+    gtk_init (&amp;argc, &amp;argv);
+    window = gtk_window_new( GTK_WINDOW_POPUP );
+    gtk_signal_connect (GTK_OBJECT (window), "delete_event",
+                        GTK_SIGNAL_FUNC (close_application), NULL);
+    gtk_widget_show (window);
+
+    /* Now for the pixmap and the pixmap widget */
+    style = gtk_widget_get_default_style();
+    gc = style->black_gc;
+    gdk_pixmap = gdk_pixmap_create_from_xpm_d( window->window, &amp;mask,
+                                             &amp;style->bg[GTK_STATE_NORMAL],
+                                             WheelbarrowFull_xpm );
+    pixmap = gtk_pixmap_new( gdk_pixmap, mask );
+    gtk_widget_show( pixmap );
+
+    /* To display the pixmap, we use a fixed widget to place the pixmap */
+    fixed = gtk_fixed_new();
+    gtk_widget_set_usize( fixed, 200, 200 );
+    gtk_fixed_put( GTK_FIXED(fixed), pixmap, 0, 0 );
+    gtk_container_add( GTK_CONTAINER(window), fixed );
+    gtk_widget_show( fixed );
+
+    /* This masks out everything except for the image itself */
+    gtk_widget_shape_combine_mask( window, mask, 0, 0 );
+    
+    /* show the window */
+    gtk_widget_set_uposition( window, 20, 400 );
+    gtk_widget_show( window );
+    gtk_main ();
+          
+    return(0);
+}
+/* example-end */
+</programlisting>
+
+<para>To make the wheelbarrow image sensitive, we could attach the button
+press event signal to make it do something. The following few lines
+would make the picture sensitive to a mouse button being pressed which
+makes the application terminate.</para>
+
+<para><literallayout>
+<literal>    gtk_widget_set_events( window,
+                          gtk_widget_get_events( window ) |
+                          GDK_BUTTON_PRESS_MASK );</para>
+
+<para>   gtk_signal_connect( GTK_OBJECT(window), "button_press_event",
+                       GTK_SIGNAL_FUNC(close_application), NULL );</literal>
+</literallayout></para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Rulers</title>
+
+<para>Ruler widgets are used to indicate the location of the mouse pointer
+in a given window. A window can have a vertical ruler spanning across
+the width and a horizontal ruler spanning down the height. A small
+triangular indicator on the ruler shows the exact location of the
+pointer relative to the ruler.</para>
+
+<para>A ruler must first be created. Horizontal and vertical rulers are
+created using</para>
+
+<para><literallayout>
+<literal>GtkWidget *gtk_hruler_new( void );    /* horizontal ruler */</para>
+
+<para>GtkWidget *gtk_vruler_new( void );    /* vertical ruler   */
+</programlisting>
+
+<para>Once a ruler is created, we can define the unit of measurement. Units
+of measure for rulers can be<literal>GTK_PIXELS</literal>, <literal>GTK_INCHES</literal> or
+<literal>GTK_CENTIMETERS</literal>. This is set using</para>
+
+<para><literallayout>
+<literal>void gtk_ruler_set_metric( GtkRuler      *ruler,
+                           GtkMetricType  metric );</literal>
+</literallayout></para>
+
+<para>The default measure is <literal>GTK_PIXELS</literal>.</para>
+
+<para><literallayout>
+<literal>    gtk_ruler_set_metric( GTK_RULER(ruler), GTK_PIXELS );</literal>
+</literallayout></para>
+
+<para>Other important characteristics of a ruler are how to mark the units
+of scale and where the position indicator is initially placed. These
+are set for a ruler using</para>
+
+<para><literallayout>
+<literal>void gtk_ruler_set_range( GtkRuler *ruler,
+                          gfloat    lower,
+                          gfloat    upper,
+                          gfloat    position,
+                          gfloat    max_size );</literal>
+</literallayout></para>
+
+<para>The lower and upper arguments define the extent of the ruler, and
+max_size is the largest possible number that will be displayed.
+Position defines the initial position of the pointer indicator within
+the ruler.</para>
+
+<para>A vertical ruler can span an 800 pixel wide window thus</para>
+
+<para><literallayout>
+<literal>    gtk_ruler_set_range( GTK_RULER(vruler), 0, 800, 0, 800);</literal>
+</literallayout></para>
+
+<para>The markings displayed on the ruler will be from 0 to 800, with a
+number for every 100 pixels. If instead we wanted the ruler to range
+from 7 to 16, we would code</para>
+
+<para><literallayout>
+<literal>    gtk_ruler_set_range( GTK_RULER(vruler), 7, 16, 0, 20);</literal>
+</literallayout></para>
+
+<para>The indicator on the ruler is a small triangular mark that indicates
+the position of the pointer relative to the ruler. If the ruler is
+used to follow the mouse pointer, the motion_notify_event signal
+should be connected to the motion_notify_event method of the ruler.
+To follow all mouse movements within a window area, we would use</para>
+
+<para><literallayout>
+<literal>#define EVENT_METHOD(i, x) GTK_WIDGET_CLASS(GTK_OBJECT(i)->klass)->x</para>
+
+<para>    gtk_signal_connect_object( GTK_OBJECT(area), "motion_notify_event",
+           (GtkSignalFunc)EVENT_METHOD(ruler, motion_notify_event),
+           GTK_OBJECT(ruler) );</literal>
+</literallayout></para>
+
+<para>The following example creates a drawing area with a horizontal ruler
+above it and a vertical ruler to the left of it. The size of the
+drawing area is 600 pixels wide by 400 pixels high. The horizontal
+ruler spans from 7 to 13 with a mark every 100 pixels, while the
+vertical ruler spans from 0 to 400 with a mark every 100 pixels.
+Placement of the drawing area and the rulers is done using a table.</para>
+
+<programlisting role="C">
+/* example-start rulers rulers.c */
+
+#include &lt;gtk/gtk.h&gt;
+
+#define EVENT_METHOD(i, x) GTK_WIDGET_CLASS(GTK_OBJECT(i)->klass)->x
+
+#define XSIZE  600
+#define YSIZE  400
+
+/* This routine gets control when the close button is clicked */
+gint close_application( GtkWidget *widget,
+                        GdkEvent  *event,
+                        gpointer   data )
+{
+    gtk_main_quit();
+    return(FALSE);
+}
+
+/* The main routine */
+int main( int   argc,
+          char *argv[] ) {
+    GtkWidget *window, *table, *area, *hrule, *vrule;
+
+    /* Initialize GTK and create the main window */
+    gtk_init( &amp;argc, &amp;argv );
+
+    window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
+    gtk_signal_connect (GTK_OBJECT (window), "delete_event",
+            GTK_SIGNAL_FUNC( close_application ), NULL);
+    gtk_container_set_border_width (GTK_CONTAINER (window), 10);
+
+    /* Create a table for placing the ruler and the drawing area */
+    table = gtk_table_new( 3, 2, FALSE );
+    gtk_container_add( GTK_CONTAINER(window), table );
+
+    area = gtk_drawing_area_new();
+    gtk_drawing_area_size( (GtkDrawingArea *)area, XSIZE, YSIZE );
+    gtk_table_attach( GTK_TABLE(table), area, 1, 2, 1, 2,
+                      GTK_EXPAND|GTK_FILL, GTK_FILL, 0, 0 );
+    gtk_widget_set_events( area, GDK_POINTER_MOTION_MASK |
+                                 GDK_POINTER_MOTION_HINT_MASK );
+
+    /* The horizontal ruler goes on top. As the mouse moves across the
+     * drawing area, a motion_notify_event is passed to the
+     * appropriate event handler for the ruler. */
+    hrule = gtk_hruler_new();
+    gtk_ruler_set_metric( GTK_RULER(hrule), GTK_PIXELS );
+    gtk_ruler_set_range( GTK_RULER(hrule), 7, 13, 0, 20 );
+    gtk_signal_connect_object( GTK_OBJECT(area), "motion_notify_event",
+                               (GtkSignalFunc)EVENT_METHOD(hrule,
+                                                        motion_notify_event),
+                               GTK_OBJECT(hrule) );
+    /*  GTK_WIDGET_CLASS(GTK_OBJECT(hrule)->klass)->motion_notify_event, */
+    gtk_table_attach( GTK_TABLE(table), hrule, 1, 2, 0, 1,
+                      GTK_EXPAND|GTK_SHRINK|GTK_FILL, GTK_FILL, 0, 0 );
+    
+    /* The vertical ruler goes on the left. As the mouse moves across
+     * the drawing area, a motion_notify_event is passed to the
+     * appropriate event handler for the ruler. */
+    vrule = gtk_vruler_new();
+    gtk_ruler_set_metric( GTK_RULER(vrule), GTK_PIXELS );
+    gtk_ruler_set_range( GTK_RULER(vrule), 0, YSIZE, 10, YSIZE );
+    gtk_signal_connect_object( GTK_OBJECT(area), "motion_notify_event",
+                               (GtkSignalFunc)
+                                  GTK_WIDGET_CLASS(GTK_OBJECT(vrule)->klass)->
+                                                        motion_notify_event,
+                               GTK_OBJECT(vrule) );
+    gtk_table_attach( GTK_TABLE(table), vrule, 0, 1, 1, 2,
+                      GTK_FILL, GTK_EXPAND|GTK_SHRINK|GTK_FILL, 0, 0 );
+
+    /* Now show everything */
+    gtk_widget_show( area );
+    gtk_widget_show( hrule );
+    gtk_widget_show( vrule );
+    gtk_widget_show( table );
+    gtk_widget_show( window );
+    gtk_main();
+
+    return(0);
+}
+/* example-end */
+</programlisting>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Statusbars</title>
+
+<para>Statusbars are simple widgets used to display a text message. They
+keep a stack of the messages pushed onto them, so that popping the
+current message will re-display the previous text message.</para>
+
+<para>In order to allow different parts of an application to use the same
+statusbar to display messages, the statusbar widget issues Context
+Identifiers which are used to identify different "users". The message
+on top of the stack is the one displayed, no matter what context it is
+in. Messages are stacked in last-in-first-out order, not context
+identifier order.</para>
+
+<para>A statusbar is created with a call to:</para>
+
+<para><literallayout>
+<literal>GtkWidget *gtk_statusbar_new( void );</literal>
+</literallayout></para>
+
+<para>A new Context Identifier is requested using a call to the following 
+function with a short textual description of the context:</para>
+
+<para><literallayout>
+<literal>guint gtk_statusbar_get_context_id( GtkStatusbar *statusbar,
+                                    const gchar  *context_description );</literal>
+</literallayout></para>
+
+<para>There are three functions that can operate on statusbars:</para>
+
+<para><literallayout>
+<literal>guint gtk_statusbar_push( GtkStatusbar *statusbar,
+                          guint         context_id,
+                          gchar        *text );</para>
+
+<para>void gtk_statusbar_pop( GtkStatusbar *statusbar)
+                        guint         context_id );</para>
+
+<para>void gtk_statusbar_remove( GtkStatusbar *statusbar,
+                           guint         context_id,
+                           guint         message_id ); </literal>
+</literallayout></para>
+
+<para>The first, gtk_statusbar_push, is used to add a new message to the
+statusbar.  It returns a Message Identifier, which can be passed later
+to the function gtk_statusbar_remove to remove the message with the
+given Message and Context Identifiers from the statusbar's stack.</para>
+
+<para>The function gtk_statusbar_pop removes the message highest in the
+stack with the given Context Identifier.</para>
+
+<para>The following example creates a statusbar and two buttons, one for
+pushing items onto the statusbar, and one for popping the last item
+back off.</para>
+
+<programlisting role="C">
+/* example-start statusbar statusbar.c */
+
+#include &lt;gtk/gtk.h&gt;
+#include &lt;glib.h&gt;
+
+GtkWidget *status_bar;
+
+void push_item( GtkWidget *widget,
+                gpointer   data )
+{
+  static int count = 1;
+  char buff[20];
+
+  g_snprintf(buff, 20, "Item %d", count++);
+  gtk_statusbar_push( GTK_STATUSBAR(status_bar), GPOINTER_TO_INT(data), buff);
+
+  return;
+}
+
+void pop_item( GtkWidget *widget,
+               gpointer   data )
+{
+  gtk_statusbar_pop( GTK_STATUSBAR(status_bar), GPOINTER_TO_INT(data) );
+  return;
+}
+
+int main( int   argc,
+          char *argv[] )
+{
+
+    GtkWidget *window;
+    GtkWidget *vbox;
+    GtkWidget *button;
+
+    gint context_id;
+
+    gtk_init (&amp;argc, &amp;argv);
+
+    /* create a new window */
+    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+    gtk_widget_set_usize( GTK_WIDGET (window), 200, 100);
+    gtk_window_set_title(GTK_WINDOW (window), "GTK Statusbar Example");
+    gtk_signal_connect(GTK_OBJECT (window), "delete_event",
+                       (GtkSignalFunc) gtk_exit, NULL);
+    vbox = gtk_vbox_new(FALSE, 1);
+    gtk_container_add(GTK_CONTAINER(window), vbox);
+    gtk_widget_show(vbox);
+          
+    status_bar = gtk_statusbar_new();      
+    gtk_box_pack_start (GTK_BOX (vbox), status_bar, TRUE, TRUE, 0);
+    gtk_widget_show (status_bar);
+
+    context_id = gtk_statusbar_get_context_id(
+                          GTK_STATUSBAR(status_bar), "Statusbar example");
+
+    button = gtk_button_new_with_label("push item");
+    gtk_signal_connect(GTK_OBJECT(button), "clicked",
+        GTK_SIGNAL_FUNC (push_item), GINT_TO_POINTER(context_id) );
+    gtk_box_pack_start(GTK_BOX(vbox), button, TRUE, TRUE, 2);
+    gtk_widget_show(button);              
+
+    button = gtk_button_new_with_label("pop last item");
+    gtk_signal_connect(GTK_OBJECT(button), "clicked",
+        GTK_SIGNAL_FUNC (pop_item), GINT_TO_POINTER(context_id) );
+    gtk_box_pack_start(GTK_BOX(vbox), button, TRUE, TRUE, 2);
+    gtk_widget_show(button);
+
+    /* always display the window as the last step so it all splashes on
+     * the screen at once. */
+    gtk_widget_show(window);
+
+    gtk_main ();
+
+    return 0;
+}
+/* example-end */
+</programlisting>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Text Entries</title>
+
+<para>The Entry widget allows text to be typed and displayed in a single line
+text box. The text may be set with function calls that allow new text
+to replace, prepend or append the current contents of the Entry widget.</para>
+
+<para>There are two functions for creating Entry widgets:</para>
+
+<para><literallayout>
+<literal>GtkWidget *gtk_entry_new( void );</para>
+
+<para>GtkWidget *gtk_entry_new_with_max_length( guint16 max );</literal>
+</literallayout></para>
+
+<para>The first just creates a new Entry widget, whilst the second creates a
+new Entry and sets a limit on the length of the text within the Entry.</para>
+
+<para>There are several functions for altering the text which is currently
+within the Entry widget.</para>
+
+<para><literallayout>
+<literal>void gtk_entry_set_text( GtkEntry    *entry,
+                         const gchar *text );</para>
+
+<para>void gtk_entry_append_text( GtkEntry    *entry,
+                            const gchar *text );</para>
+
+<para>void gtk_entry_prepend_text( GtkEntry    *entry,
+                             const gchar *text );</literal>
+</literallayout></para>
+
+<para>The function gtk_entry_set_text sets the contents of the Entry widget,
+replacing the current contents. The functions gtk_entry_append_text
+and gtk_entry_prepend_text allow the current contents to be appended
+and prepended to.</para>
+
+<para>The next function allows the current insertion point to be set.</para>
+
+<para><literallayout>
+<literal>void gtk_entry_set_position( GtkEntry *entry,
+                             gint      position );</literal>
+</literallayout></para>
+
+<para>The contents of the Entry can be retrieved by using a call to the
+following function. This is useful in the callback functions described below.</para>
+
+<para><literallayout>
+<literal>gchar *gtk_entry_get_text( GtkEntry *entry );</literal>
+</literallayout></para>
+
+<para>The value returned by this function is used internally, and must not
+be freed using either free() or g_free()</para>
+
+<para>If we don't want the contents of the Entry to be changed by someone typing
+into it, we can change its editable state.</para>
+
+<para><literallayout>
+<literal>void gtk_entry_set_editable( GtkEntry *entry,
+                             gboolean  editable );</literal>
+</literallayout></para>
+
+<para>The function above allows us to toggle the editable state of the
+Entry widget by passing in a TRUE or FALSE value for the <literal>editable</literal>
+argument.</para>
+
+<para>If we are using the Entry where we don't want the text entered to be
+visible, for example when a password is being entered, we can use the
+following function, which also takes a boolean flag.</para>
+
+<para><literallayout>
+<literal>void gtk_entry_set_visibility( GtkEntry *entry,
+                               gboolean  visible );</literal>
+</literallayout></para>
+
+<para>A region of the text may be set as selected by using the following
+function. This would most often be used after setting some default
+text in an Entry, making it easy for the user to remove it.</para>
+
+<para><literallayout>
+<literal>void gtk_entry_select_region( GtkEntry *entry,
+                              gint      start,
+                              gint      end );</literal>
+</literallayout></para>
+
+<para>If we want to catch when the user has entered text, we can connect to
+the <literal>activate</literal> or <literal>changed</literal> signal. Activate is raised when the
+user hits the enter key within the Entry widget. Changed is raised
+when the text changes at all, e.g., for every character entered or
+removed.</para>
+
+<para>The following code is an example of using an Entry widget.</para>
+
+<programlisting role="C">
+/* example-start entry entry.c */
+
+#include &lt;stdio.h&gt;
+#include &lt;gtk/gtk.h&gt;
+
+void enter_callback( GtkWidget *widget,
+                     GtkWidget *entry )
+{
+  gchar *entry_text;
+  entry_text = gtk_entry_get_text(GTK_ENTRY(entry));
+  printf("Entry contents: %s\n", entry_text);
+}
+
+void entry_toggle_editable( GtkWidget *checkbutton,
+                            GtkWidget *entry )
+{
+  gtk_entry_set_editable(GTK_ENTRY(entry),
+                        GTK_TOGGLE_BUTTON(checkbutton)->active);
+}
+
+void entry_toggle_visibility( GtkWidget *checkbutton,
+                              GtkWidget *entry )
+{
+  gtk_entry_set_visibility(GTK_ENTRY(entry),
+                        GTK_TOGGLE_BUTTON(checkbutton)->active);
+}
+
+int main( int   argc,
+          char *argv[] )
+{
+
+    GtkWidget *window;
+    GtkWidget *vbox, *hbox;
+    GtkWidget *entry;
+    GtkWidget *button;
+    GtkWidget *check;
+
+    gtk_init (&amp;argc, &amp;argv);
+
+    /* create a new window */
+    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+    gtk_widget_set_usize( GTK_WIDGET (window), 200, 100);
+    gtk_window_set_title(GTK_WINDOW (window), "GTK Entry");
+    gtk_signal_connect(GTK_OBJECT (window), "delete_event",
+                       (GtkSignalFunc) gtk_exit, NULL);
+
+    vbox = gtk_vbox_new (FALSE, 0);
+    gtk_container_add (GTK_CONTAINER (window), vbox);
+    gtk_widget_show (vbox);
+
+    entry = gtk_entry_new_with_max_length (50);
+    gtk_signal_connect(GTK_OBJECT(entry), "activate",
+                      GTK_SIGNAL_FUNC(enter_callback),
+                      entry);
+    gtk_entry_set_text (GTK_ENTRY (entry), "hello");
+    gtk_entry_append_text (GTK_ENTRY (entry), " world");
+    gtk_entry_select_region (GTK_ENTRY (entry),
+                            0, GTK_ENTRY(entry)->text_length);
+    gtk_box_pack_start (GTK_BOX (vbox), entry, TRUE, TRUE, 0);
+    gtk_widget_show (entry);
+
+    hbox = gtk_hbox_new (FALSE, 0);
+    gtk_container_add (GTK_CONTAINER (vbox), hbox);
+    gtk_widget_show (hbox);
+                                  
+    check = gtk_check_button_new_with_label("Editable");
+    gtk_box_pack_start (GTK_BOX (hbox), check, TRUE, TRUE, 0);
+    gtk_signal_connect (GTK_OBJECT(check), "toggled",
+                       GTK_SIGNAL_FUNC(entry_toggle_editable), entry);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), TRUE);
+    gtk_widget_show (check);
+    
+    check = gtk_check_button_new_with_label("Visible");
+    gtk_box_pack_start (GTK_BOX (hbox), check, TRUE, TRUE, 0);
+    gtk_signal_connect (GTK_OBJECT(check), "toggled",
+                       GTK_SIGNAL_FUNC(entry_toggle_visibility), entry);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), TRUE);
+    gtk_widget_show (check);
+                                   
+    button = gtk_button_new_with_label ("Close");
+    gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+                              GTK_SIGNAL_FUNC(gtk_exit),
+                              GTK_OBJECT (window));
+    gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);
+    GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
+    gtk_widget_grab_default (button);
+    gtk_widget_show (button);
+    
+    gtk_widget_show(window);
+
+    gtk_main();
+    return(0);
+}
+/* example-end */
+</programlisting>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Spin Buttons</title>
+
+<para>The Spin Button widget is generally used to allow the user to select a
+value from a range of numeric values. It consists of a text
+entry box with up and down arrow buttons attached to the
+side. Selecting one of the buttons causes the value to "spin" up and
+down the range of possible values. The entry box may also be edited
+directly to enter a specific value.</para>
+
+<para>The Spin Button allows the value to have zero or a number of decimal
+places and to be incremented/decremented in configurable steps. The
+action of holding down one of the buttons optionally results in an
+acceleration of change in the value according to how long it is
+depressed.</para>
+
+<para>The Spin Button uses an <link linkend="ch-Adjustment">Adjustment</link>
+object to hold information about the range of values that the spin
+button can take. This makes for a powerful Spin Button widget.</para>
+
+<para>Recall that an adjustment widget is created with the following
+function, which illustrates the information that it holds:</para>
+
+<para><literallayout>
+<literal>GtkObject *gtk_adjustment_new( gfloat value,
+                               gfloat lower,
+                               gfloat upper,
+                               gfloat step_increment,
+                               gfloat page_increment,
+                               gfloat page_size );</literal>
+</literallayout></para>
+
+<para>These attributes of an Adjustment are used by the Spin Button in the
+following way:</para>
+
+<itemizedlist>
+<listitem><simpara> <literal>value</literal>: initial value for the Spin Button</simpara>
+</listitem>
+<listitem><simpara> <literal>lower</literal>: lower range value</simpara>
+</listitem>
+<listitem><simpara> <literal>upper</literal>: upper range value</simpara>
+</listitem>
+<listitem><simpara> <literal>step_increment</literal>: value to increment/decrement when pressing
+mouse button 1 on a button</simpara>
+</listitem>
+<listitem><simpara> <literal>page_increment</literal>: value to increment/decrement when pressing
+mouse button 2 on a button</simpara>
+</listitem>
+<listitem><simpara> <literal>page_size</literal>: unused</simpara>
+</listitem>
+</itemizedlist>
+
+<para>Additionally, mouse button 3 can be used to jump directly to the
+<literal>upper</literal> or <literal>lower</literal> values when used to select one of the
+buttons. Lets look at how to create a Spin Button:</para>
+
+<para><literallayout>
+<literal>GtkWidget *gtk_spin_button_new( GtkAdjustment *adjustment,
+                                gfloat         climb_rate,
+                                guint          digits );</literal>
+</literallayout></para>
+
+<para>The <literal>climb_rate</literal> argument take a value between 0.0 and 1.0 and
+indicates the amount of acceleration that the Spin Button has. The
+<literal>digits</literal> argument specifies the number of decimal places to which
+the value will be displayed.</para>
+
+<para>A Spin Button can be reconfigured after creation using the following
+function:</para>
+
+<para><literallayout>
+<literal>void gtk_spin_button_configure( GtkSpinButton *spin_button,
+                                GtkAdjustment *adjustment,
+                                gfloat         climb_rate,
+                                guint          digits );</literal>
+</literallayout></para>
+
+<para>The <literal>spin_button</literal> argument specifies the Spin Button widget that is
+to be reconfigured. The other arguments are as specified above.</para>
+
+<para>The adjustment can be set and retrieved independantly using the
+following two functions:</para>
+
+<para><literallayout>
+<literal>void gtk_spin_button_set_adjustment( GtkSpinButton  *spin_button,
+                                     GtkAdjustment  *adjustment );</para>
+
+<para>GtkAdjustment *gtk_spin_button_get_adjustment( GtkSpinButton *spin_button );</literal>
+</literallayout></para>
+
+<para>The number of decimal places can also be altered using:</para>
+
+<para><literallayout>
+<literal>void gtk_spin_button_set_digits( GtkSpinButton *spin_button,
+                                 guint          digits) ;</literal>
+</literallayout></para>
+
+<para>The value that a Spin Button is currently displaying can be changed
+using the following function:</para>
+
+<para><literallayout>
+<literal>void gtk_spin_button_set_value( GtkSpinButton *spin_button,
+                                gfloat         value );</literal>
+</literallayout></para>
+
+<para>The current value of a Spin Button can be retrieved as either a
+floating point or integer value with the following functions:</para>
+
+<para><literallayout>
+<literal>gfloat gtk_spin_button_get_value_as_float( GtkSpinButton *spin_button );</para>
+
+<para>gint gtk_spin_button_get_value_as_int( GtkSpinButton *spin_button );</literal>
+</literallayout></para>
+
+<para>If you want to alter the value of a Spin Value relative to its current
+value, then the following function can be used:</para>
+
+<para><literallayout>
+<literal>void gtk_spin_button_spin( GtkSpinButton *spin_button,
+                           GtkSpinType    direction,
+                           gfloat         increment );</literal>
+</literallayout></para>
+
+<para>The <literal>direction</literal> parameter can take one of the following values:</para>
+
+<para><literallayout>
+<literal>  GTK_SPIN_STEP_FORWARD
+  GTK_SPIN_STEP_BACKWARD
+  GTK_SPIN_PAGE_FORWARD
+  GTK_SPIN_PAGE_BACKWARD
+  GTK_SPIN_HOME
+  GTK_SPIN_END
+  GTK_SPIN_USER_DEFINED</literal>
+</literallayout></para>
+
+<para>This function packs in quite a bit of functionality, which I will
+attempt to clearly explain. Many of these settings use values from the
+Adjustment object that is associated with a Spin Button.</para>
+
+<para><literal>GTK_SPIN_STEP_FORWARD</literal> and <literal>GTK_SPIN_STEP_BACKWARD</literal> change the
+value of the Spin Button by the amount specified by <literal>increment</literal>,
+unless <literal>increment</literal> is equal to 0, in which case the value is
+changed by the value of <literal>step_increment</literal> in theAdjustment.</para>
+
+<para><literal>GTK_SPIN_PAGE_FORWARD</literal> and <literal>GTK_SPIN_PAGE_BACKWARD</literal> simply
+alter the value of the Spin Button by <literal>increment</literal>.</para>
+
+<para><literal>GTK_SPIN_HOME</literal> sets the value of the Spin Button to the bottom of
+the Adjustments range.</para>
+
+<para><literal>GTK_SPIN_END</literal> sets the value of the Spin Button to the top of the
+Adjustments range.</para>
+
+<para><literal>GTK_SPIN_USER_DEFINED</literal> simply alters the value of the Spin Button
+by the specified amount.</para>
+
+<para>We move away from functions for setting and retreving the range attributes
+of the Spin Button now, and move onto functions that effect the
+appearance and behaviour of the Spin Button widget itself.</para>
+
+<para>The first of these functions is used to constrain the text box of the
+Spin Button such that it may only contain a numeric value. This
+prevents a user from typing anything other than numeric values into
+the text box of a Spin Button:</para>
+
+<para><literallayout>
+<literal>void gtk_spin_button_set_numeric( GtkSpinButton *spin_button,
+                                  gboolean       numeric );</literal>
+</literallayout></para>
+
+<para>You can set whether a Spin Button will wrap around between the upper
+and lower range values with the following function:</para>
+
+<para><literallayout>
+<literal>void gtk_spin_button_set_wrap( GtkSpinButton *spin_button,
+                               gboolean       wrap );</literal>
+</literallayout></para>
+
+<para>You can set a Spin Button to round the value to the nearest
+<literal>step_increment</literal>, which is set within the Adjustment object used
+with the Spin Button. This is accomplished with the following
+function:</para>
+
+<para><literallayout>
+<literal>void gtk_spin_button_set_snap_to_ticks( GtkSpinButton  *spin_button,
+                                        gboolean        snap_to_ticks );</literal>
+</literallayout></para>
+
+<para>The update policy of a Spin Button can be changed with the following
+function:</para>
+
+<para><literallayout>
+<literal>void gtk_spin_button_set_update_policy( GtkSpinButton  *spin_button,
+                                    GtkSpinButtonUpdatePolicy policy );</literal>
+</literallayout></para>
+
+<para><!-- TODO: find out what this does - TRG --></para>
+
+<para>The possible values of <literal>policy</literal> are either <literal>GTK_UPDATE_ALWAYS</literal> or
+<literal>GTK_UPDATE_IF_VALID</literal>.</para>
+
+<para>These policies affect the behavior of a Spin Button when parsing
+inserted text and syncing its value with the values of the
+Adjustment.</para>
+
+<para>In the case of <literal>GTK_UPDATE_IF_VALID</literal> the Spin Button only value
+gets changed if the text input is a numeric value that is within the
+range specified by the Adjustment. Otherwise the text is reset to the
+current value.</para>
+
+<para>In case of <literal>GTK_UPDATE_ALWAYS</literal> we ignore errors while converting
+text into a numeric value.</para>
+
+<para>The appearance of the buttons used in a Spin Button can be changed
+using the following function:</para>
+
+<para><literallayout>
+<literal>void gtk_spin_button_set_shadow_type( GtkSpinButton *spin_button,
+                                      GtkShadowType  shadow_type );</literal>
+</literallayout></para>
+
+<para>As usual, the <literal>shadow_type</literal> can be one of:</para>
+
+<para><literallayout>
+<literal>  GTK_SHADOW_IN
+  GTK_SHADOW_OUT
+  GTK_SHADOW_ETCHED_IN
+  GTK_SHADOW_ETCHED_OUT</literal>
+</literallayout></para>
+
+<para>Finally, you can explicitly request that a Spin Button update itself:</para>
+
+<para><literallayout>
+<literal>void gtk_spin_button_update( GtkSpinButton  *spin_button );</literal>
+</literallayout></para>
+
+<para>It's example time again.</para>
+
+<programlisting role="C">
+/* example-start spinbutton spinbutton.c */
+
+#include &lt;stdio.h&gt;
+#include &lt;gtk/gtk.h&gt;
+
+static GtkWidget *spinner1;
+
+void toggle_snap( GtkWidget     *widget,
+                 GtkSpinButton *spin )
+{
+  gtk_spin_button_set_snap_to_ticks (spin, GTK_TOGGLE_BUTTON (widget)->active);
+}
+
+void toggle_numeric( GtkWidget *widget,
+                    GtkSpinButton *spin )
+{
+  gtk_spin_button_set_numeric (spin, GTK_TOGGLE_BUTTON (widget)->active);
+}
+
+void change_digits( GtkWidget *widget,
+                   GtkSpinButton *spin )
+{
+  gtk_spin_button_set_digits (GTK_SPIN_BUTTON (spinner1),
+                              gtk_spin_button_get_value_as_int (spin));
+}
+
+void get_value( GtkWidget *widget,
+               gpointer data )
+{
+  gchar buf[32];
+  GtkLabel *label;
+  GtkSpinButton *spin;
+
+  spin = GTK_SPIN_BUTTON (spinner1);
+  label = GTK_LABEL (gtk_object_get_user_data (GTK_OBJECT (widget)));
+  if (GPOINTER_TO_INT (data) == 1)
+    sprintf (buf, "%d", gtk_spin_button_get_value_as_int (spin));
+  else
+    sprintf (buf, "%0.*f", spin->digits,
+             gtk_spin_button_get_value_as_float (spin));
+  gtk_label_set_text (label, buf);
+}
+
+
+int main( int   argc,
+          char *argv[] )
+{
+  GtkWidget *window;
+  GtkWidget *frame;
+  GtkWidget *hbox;
+  GtkWidget *main_vbox;
+  GtkWidget *vbox;
+  GtkWidget *vbox2;
+  GtkWidget *spinner2;
+  GtkWidget *spinner;
+  GtkWidget *button;
+  GtkWidget *label;
+  GtkWidget *val_label;
+  GtkAdjustment *adj;
+
+  /* Initialise GTK */
+  gtk_init(&amp;argc, &amp;argv);
+
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
+  gtk_signal_connect (GTK_OBJECT (window), "destroy",
+                     GTK_SIGNAL_FUNC (gtk_main_quit),
+                     NULL);
+
+  gtk_window_set_title (GTK_WINDOW (window), "Spin Button");
+
+  main_vbox = gtk_vbox_new (FALSE, 5);
+  gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 10);
+  gtk_container_add (GTK_CONTAINER (window), main_vbox);
+  
+  frame = gtk_frame_new ("Not accelerated");
+  gtk_box_pack_start (GTK_BOX (main_vbox), frame, TRUE, TRUE, 0);
+  
+  vbox = gtk_vbox_new (FALSE, 0);
+  gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
+  gtk_container_add (GTK_CONTAINER (frame), vbox);
+  
+  /* Day, month, year spinners */
+  
+  hbox = gtk_hbox_new (FALSE, 0);
+  gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 5);
+  
+  vbox2 = gtk_vbox_new (FALSE, 0);
+  gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
+  
+  label = gtk_label_new ("Day :");
+  gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
+  gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, TRUE, 0);
+  
+  adj = (GtkAdjustment *) gtk_adjustment_new (1.0, 1.0, 31.0, 1.0,
+                                             5.0, 0.0);
+  spinner = gtk_spin_button_new (adj, 0, 0);
+  gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner), TRUE);
+  gtk_spin_button_set_shadow_type (GTK_SPIN_BUTTON (spinner),
+                                  GTK_SHADOW_OUT);
+  gtk_box_pack_start (GTK_BOX (vbox2), spinner, FALSE, TRUE, 0);
+  
+  vbox2 = gtk_vbox_new (FALSE, 0);
+  gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
+  
+  label = gtk_label_new ("Month :");
+  gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
+  gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, TRUE, 0);
+  
+  adj = (GtkAdjustment *) gtk_adjustment_new (1.0, 1.0, 12.0, 1.0,
+                                             5.0, 0.0);
+  spinner = gtk_spin_button_new (adj, 0, 0);
+  gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner), TRUE);
+  gtk_spin_button_set_shadow_type (GTK_SPIN_BUTTON (spinner),
+                                  GTK_SHADOW_ETCHED_IN);
+  gtk_box_pack_start (GTK_BOX (vbox2), spinner, FALSE, TRUE, 0);
+  
+  vbox2 = gtk_vbox_new (FALSE, 0);
+  gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
+  
+  label = gtk_label_new ("Year :");
+  gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
+  gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, TRUE, 0);
+  
+  adj = (GtkAdjustment *) gtk_adjustment_new (1998.0, 0.0, 2100.0,
+                                             1.0, 100.0, 0.0);
+  spinner = gtk_spin_button_new (adj, 0, 0);
+  gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner), FALSE);
+  gtk_spin_button_set_shadow_type (GTK_SPIN_BUTTON (spinner),
+                                  GTK_SHADOW_IN);
+  gtk_widget_set_usize (spinner, 55, 0);
+  gtk_box_pack_start (GTK_BOX (vbox2), spinner, FALSE, TRUE, 0);
+  
+  frame = gtk_frame_new ("Accelerated");
+  gtk_box_pack_start (GTK_BOX (main_vbox), frame, TRUE, TRUE, 0);
+  
+  vbox = gtk_vbox_new (FALSE, 0);
+  gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
+  gtk_container_add (GTK_CONTAINER (frame), vbox);
+  
+  hbox = gtk_hbox_new (FALSE, 0);
+  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 5);
+  
+  vbox2 = gtk_vbox_new (FALSE, 0);
+  gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
+  
+  label = gtk_label_new ("Value :");
+  gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
+  gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, TRUE, 0);
+  
+  adj = (GtkAdjustment *) gtk_adjustment_new (0.0, -10000.0, 10000.0,
+                                             0.5, 100.0, 0.0);
+  spinner1 = gtk_spin_button_new (adj, 1.0, 2);
+  gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner1), TRUE);
+  gtk_widget_set_usize (spinner1, 100, 0);
+  gtk_box_pack_start (GTK_BOX (vbox2), spinner1, FALSE, TRUE, 0);
+  
+  vbox2 = gtk_vbox_new (FALSE, 0);
+  gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 5);
+  
+  label = gtk_label_new ("Digits :");
+  gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
+  gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, TRUE, 0);
+  
+  adj = (GtkAdjustment *) gtk_adjustment_new (2, 1, 5, 1, 1, 0);
+  spinner2 = gtk_spin_button_new (adj, 0.0, 0);
+  gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner2), TRUE);
+  gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
+                     GTK_SIGNAL_FUNC (change_digits),
+                     (gpointer) spinner2);
+  gtk_box_pack_start (GTK_BOX (vbox2), spinner2, FALSE, TRUE, 0);
+  
+  hbox = gtk_hbox_new (FALSE, 0);
+  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 5);
+  
+  button = gtk_check_button_new_with_label ("Snap to 0.5-ticks");
+  gtk_signal_connect (GTK_OBJECT (button), "clicked",
+                     GTK_SIGNAL_FUNC (toggle_snap),
+                     spinner1);
+  gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
+  
+  button = gtk_check_button_new_with_label ("Numeric only input mode");
+  gtk_signal_connect (GTK_OBJECT (button), "clicked",
+                     GTK_SIGNAL_FUNC (toggle_numeric),
+                     spinner1);
+  gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
+  
+  val_label = gtk_label_new ("");
+  
+  hbox = gtk_hbox_new (FALSE, 0);
+  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 5);
+  button = gtk_button_new_with_label ("Value as Int");
+  gtk_object_set_user_data (GTK_OBJECT (button), val_label);
+  gtk_signal_connect (GTK_OBJECT (button), "clicked",
+                     GTK_SIGNAL_FUNC (get_value),
+                     GINT_TO_POINTER (1));
+  gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 5);
+  
+  button = gtk_button_new_with_label ("Value as Float");
+  gtk_object_set_user_data (GTK_OBJECT (button), val_label);
+  gtk_signal_connect (GTK_OBJECT (button), "clicked",
+                     GTK_SIGNAL_FUNC (get_value),
+                     GINT_TO_POINTER (2));
+  gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 5);
+  
+  gtk_box_pack_start (GTK_BOX (vbox), val_label, TRUE, TRUE, 0);
+  gtk_label_set_text (GTK_LABEL (val_label), "0");
+  
+  hbox = gtk_hbox_new (FALSE, 0);
+  gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, TRUE, 0);
+  
+  button = gtk_button_new_with_label ("Close");
+  gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+                            GTK_SIGNAL_FUNC (gtk_widget_destroy),
+                            GTK_OBJECT (window));
+  gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 5);
+
+  gtk_widget_show_all (window);
+
+  /* Enter the event loop */
+  gtk_main ();
+    
+  return(0);
+}
+/* example-end */
+</programlisting>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Combo Box</title>
+
+<para>The combo box is another fairly simple widget that is really just a
+collection of other widgets. From the user's point of view, the widget
+consists of a text entry box and a pull down menu from which the user
+can select one of a set of predefined entries. Alternatively, the user
+can type a different option directly into the text box.</para>
+
+<para>The following extract from the structure that defines a Combo Box
+identifies several of the components:</para>
+
+<para><literallayout>
+<literal>struct _GtkCombo { 
+        GtkHBox hbox; 
+        GtkWidget *entry; 
+        GtkWidget *button;
+        GtkWidget *popup; 
+        GtkWidget *popwin; 
+        GtkWidget *list;
+       ...  };</literal>
+</literallayout></para>
+
+<para>As you can see, the Combo Box has two principal parts that you really
+care about: an entry and a list.</para>
+
+<para>First off, to create a combo box, use:</para>
+
+<para><literallayout>
+<literal>GtkWidget *gtk_combo_new( void );</literal>
+</literallayout></para>
+
+<para>Now, if you want to set the string in the entry section of the combo
+box, this is done by manipulating the <literal>entry</literal> widget directly:</para>
+
+<para><literallayout>
+<literal>    gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), "My String.");</literal>
+</literallayout></para>
+
+<para>To set the values in the popdown list, one uses the function:</para>
+
+<para><literallayout>
+<literal>void gtk_combo_set_popdown_strings( GtkCombo *combo,
+                                    GList    *strings );</literal>
+</literallayout></para>
+
+<para>Before you can do this, you have to assemble a GList of the strings
+that you want. GList is a linked list implementation that is part of
+<link linkend="ch-GLib">GLib</link>, a library supporing GTK. For the
+moment, the quick and dirty explanation is that you need to set up a
+GList pointer, set it equal to NULL, then append strings to it with</para>
+
+<para><literallayout>
+<literal>GList *g_list_append( GList *glist, 
+                      gpointer data );</literal>
+</literallayout></para>
+
+<para>It is important that you set the initial GList pointer to NULL. The
+value returned from the g_list_append function must be used as the new
+pointer to the GList.</para>
+
+<para>Here's a typical code segment for creating a set of options:</para>
+
+<para><literallayout>
+<literal>    GList *glist=NULL;</para>
+
+<para>    glist = g_list_append(glist, "String 1");
+    glist = g_list_append(glist, "String 2");
+    glist = g_list_append(glist, "String 3"); 
+    glist = g_list_append(glist, "String 4");</para>
+
+<para>    gtk_combo_set_popdown_strings( GTK_COMBO(combo), glist) ;</literal>
+</literallayout></para>
+
+<para>The combo widget makes a copy of the strings passed to it in the glist
+structure. As a result, you need to make sure you free the memory used
+by the list if that is appropriate for your application.</para>
+
+<para>At this point you have a working combo box that has been set up.
+There are a few aspects of its behavior that you can change. These
+are accomplished with the functions: </para>
+
+<para><literallayout>
+<literal>void gtk_combo_set_use_arrows( GtkCombo *combo,
+                               gint      val );</para>
+
+<para>void gtk_combo_set_use_arrows_always( GtkCombo *combo,
+                                      gint      val );</para>
+
+<para>void gtk_combo_set_case_sensitive( GtkCombo *combo,
+                                   gint      val );</literal>
+</literallayout></para>
+
+<para><literal>gtk_combo_set_use_arrows()</literal> lets the user change the value in the
+entry using the up/down arrow keys. This doesn't bring up the list, but
+rather replaces the current text in the entry with the next list entry
+(up or down, as your key choice indicates). It does this by searching
+in the list for the item corresponding to the current value in the
+entry and selecting the previous/next item accordingly. Usually in an
+entry the arrow keys are used to change focus (you can do that anyway
+using TAB). Note that when the current item is the last of the list
+and you press arrow-down it changes the focus (the same applies with
+the first item and arrow-up).</para>
+
+<para>If the current value in the entry is not in the list, then the
+function of <literal>gtk_combo_set_use_arrows()</literal> is disabled.</para>
+
+<para><literal>gtk_combo_set_use_arrows_always()</literal> similarly allows the use the
+the up/down arrow keys to cycle through the choices in the dropdown
+list, except that it wraps around the values in the list, completely
+disabling the use of the up and down arrow keys for changing focus.</para>
+
+<para><literal>gtk_combo_set_case_sensitive()</literal> toggles whether or not GTK
+searches for entries in a case sensitive manner. This is used when the
+Combo widget is asked to find a value from the list using the current
+entry in the text box. This completion can be performed in either a
+case sensitive or insensitive manner, depending upon the use of this
+function. The Combo widget can also simply complete the current entry
+if the user presses the key combination MOD-1 and "Tab". MOD-1 is
+often mapped to the "Alt" key, by the <literal>xmodmap</literal> utility. Note,
+however that some window managers also use this key combination, which
+will override its use within GTK.</para>
+
+<para>Now that we have a combo box, tailored to look and act how we want it,
+all that remains is being able to get data from the combo box. This is
+relatively straightforward. The majority of the time, all you are
+going to care about getting data from is the entry. The entry is
+accessed simply by <literal>GTK_ENTRY(GTK_COMBO(combo)->entry)</literal>. The
+two principal things that you are going to want to do with it are
+attach to the activate signal, which indicates that the user has
+pressed the Return or Enter key, and read the text. The first is
+accomplished using something like:</para>
+
+<para><literallayout>
+<literal>    gtk_signal_connect(GTK_OBJECT(GTK_COMB(combo)->entry), "activate",
+                       GTK_SIGNAL_FUNC (my_callback_function), my_data);</literal>
+</literallayout></para>
+
+<para>Getting the text at any arbitrary time is accomplished by simply using
+the entry function:</para>
+
+<para><literallayout>
+<literal>gchar *gtk_entry_get_text(GtkEntry *entry);</literal>
+</literallayout></para>
+
+<para>Such as:</para>
+
+<para><literallayout>
+<literal>    char *string;</para>
+
+<para>    string = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(combo)->entry));</literal>
+</literallayout></para>
+
+<para>That's about all there is to it. There is a function</para>
+
+<para><literallayout>
+<literal>void gtk_combo_disable_activate(GtkCombo *combo);</literal>
+</literallayout></para>
+
+<para>that will disable the activate signal on the entry widget in the combo
+box. Personally, I can't think of why you'd want to use it, but it
+does exist.</para>
+
+<para><!-- There is also a function to set the string on a particular item, void
+gtk_combo_set_item_string(GtkCombo *combo, GtkItem *item, const gchar
+*item_value), but this requires that you have a pointer to the
+appropriate Item. Frankly, I have no idea how to do that.
+--></para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> Calendar</title>
+
+<para>The Calendar widget is an effective way to display and retrieve
+monthly date related information. It is a very simple widget to create
+and work with.</para>
+
+<para>Creating a GtkCalendar widget is a simple as: </para>
+
+<para><literallayout>
+<literal>GtkWidget *gtk_calendar_new();</literal>
+</literallayout></para>
+
+<para>There might be times where you need to change a lot of information
+within this widget and the following functions allow you to make
+multiple change to a Calendar widget without the user seeing multiple
+on-screen updates.</para>
+
+<para><literallayout>
+<literal>void gtk_calendar_freeze( GtkCalendar *Calendar );</para>
+
+<para>void gtk_calendar_thaw  ( GtkCalendar *Calendar );</literal>
+</literallayout></para>
+
+<para>They work just like the freeze/thaw functions of every other
+widget.</para>
+
+<para>The Calendar widget has a few options that allow you to change the way
+the widget both looks and operates by using the function</para>
+
+<para><literallayout>
+<literal>void gtk_calendar_display_options( GtkCalendar               *calendar,
+                                   GtkCalendarDisplayOptions  flags );</literal>
+</literallayout></para>
+
+<para>The <literal>flags</literal> argument can be formed by combining either of the
+following five options using the logical bitwise OR (|) operation:</para>
+
+<itemizedlist>
+<listitem><simpara> GTK_CALENDAR_SHOW_HEADING - this option specifies that
+the month and year should be shown when drawing the calendar.</simpara>
+</listitem>
+<listitem><simpara> GTK_CALENDAR_SHOW_DAY_NAMES - this option specifies that the
+three letter descriptions should be displayed for each day (eg
+Mon,Tue, etc.).</para>
+</simpara>
+</listitem>
+<listitem><simpara> GTK_CALENDAR_NO_MONTH_CHANGE - this option states that the user
+should not and can not change the currently displayed month. This can
+be good if you only need to display a particular month such as if you
+are displaying 12 calendar widgets for every month in a particular
+year.</para>
+</simpara>
+</listitem>
+<listitem><simpara> GTK_CALENDAR_SHOW_WEEK_NUMBERS - this option specifies that the
+number for each week should be displayed down the left side of the
+calendar. (eg. Jan 1 = Week 1,Dec 31 = Week 52).</para>
+</simpara>
+</listitem>
+<listitem><simpara> GTK_CALENDAR_WEEK_START_MONDAY - this option states that the
+calander week will start on Monday instead of Sunday which is the
+default. This only affects the order in which days are displayed from
+left to right.</simpara>
+</listitem>
+</itemizedlist>
+
+<para>The following functions are used to set the the currently displayed
+date:</para>
+<para><literallayout>
+<literal>gint gtk_calendar_select_month( GtkCalendar *calendar, 
+                                guint        month,
+                                guint        year );</para>
+
+<para>void gtk_calendar_select_day( GtkCalendar *calendar,
+                              guint        day );</literal>
+</literallayout></para>
+
+<para>The return value from <literal>gtk_calendar_select_month()</literal> is a boolean
+value indicating whether the selection was successful.</para>
+
+<para>With <literal>gtk_calendar_select_day()</literal> the specified day number is
+selected within the current month, if that is possible. A
+<literal>day</literal> value of 0 will deselect any current selection.</para>
+
+<para>In addition to having a day selected, any number of days in the month
+may be "marked". A marked day is highlighted within the calendar
+display. The following functions are provided to manipulate marked
+days:</para>
+
+<para><literallayout>
+<literal>gint gtk_calendar_mark_day( GtkCalendar *calendar,
+                            guint        day);</para>
+
+<para>gint gtk_calendar_unmark_day( GtkCalendar *calendar,
+                              guint        day);</para>
+
+<para>void gtk_calendar_clear_marks( GtkCalendar *calendar);</literal>
+</literallayout></para>
+
+<para>The currently marked days are stored within an array within the
+GtkCalendar structure. This array is 31 elements long so to test
+whether a particular day is currently marked, you need to access the
+corresponding element of the array (don't forget in C that array
+elements are numbered 0 to n-1). For example:</para>
+
+<para><literallayout>
+<literal>    GtkCalendar *calendar;
+    calendar = gtk_calendar_new();</para>
+
+<para>    ...</para>
+
+<para>    /* Is day 7 marked? */
+    if (calendar->marked_date[7-1])
+       /* day is marked */
+</programlisting>
+
+<para>Note that marks are persistent across month and year changes.</para>
+
+<para>The final Calendar widget function is used to retrieve the currently
+selected date, month and/or year.</para>
+
+<para><literallayout>
+<literal>void gtk_calendar_get_date( GtkCalendar *calendar, 
+                            guint       *year,
+                            guint       *month,
+                            guint       *day );</literal>
+</literallayout></para>
+
+<para>This function requires you to pass the addresses of <literal>guint</literal>
+variables, into which the result will be placed. Passing <literal>NULL</literal> as
+a value will result in the corresponding value not being returned.</para>
+
+<para>The Calendar widget can generate a number of signals indicating date
+selection and change. The names of these signals are self explanatory,
+and are:</para>
+
+<itemizedlist>
+<listitem><simpara> <literal>month_changed</literal></simpara>
+</listitem>
+<listitem><simpara> <literal>day_selected</literal></simpara>
+</listitem>
+<listitem><simpara> <literal>day_selected_double_click</literal></simpara>
+</listitem>
+<listitem><simpara> <literal>prev_month</literal></simpara>
+</listitem>
+<listitem><simpara> <literal>next_month</literal></simpara>
+</listitem>
+<listitem><simpara> <literal>prev_year</literal></simpara>
+</listitem>
+<listitem><simpara> <literal>next_year</literal></simpara>
+</listitem>
+</itemizedlist>
+
+<para>That just leaves us with the need to put all of this together into
+example code.</para>
+
+<para><tscreen><verb> 
+/* example-start calendar calendar.c */
+/*
+ * Copyright (C) 1998 Cesar Miquel, Shawn T. Amundson, Mattias Grönlund
+ * Copyright (C) 2000 Tony Gale
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include &lt;gtk/gtk.h&gt;
+#include &lt;stdio.h&gt;
+#include &lt;string.h&gt;
+#include &lt;time.h&gt;
+
+#define DEF_PAD 10
+#define DEF_PAD_SMALL 5
+
+#define TM_YEAR_BASE 1900
+
+typedef struct _CalendarData {
+  GtkWidget *flag_checkboxes[5];
+  gboolean  settings[5];
+  gchar     *font;
+  GtkWidget *font_dialog;
+  GtkWidget *window;
+  GtkWidget *prev2_sig;
+  GtkWidget *prev_sig;
+  GtkWidget *last_sig;
+  GtkWidget *month;
+} CalendarData;
+
+enum {
+  calendar_show_header,
+  calendar_show_days,
+  calendar_month_change, 
+  calendar_show_week,
+  calendar_monday_first
+};
+
+/*
+ * GtkCalendar
+ */
+
+void calendar_date_to_string( CalendarData *data,
+                             char         *buffer,
+                             gint          buff_len )
+{
+  struct tm tm;
+  time_t time;
+
+  memset (&amp;tm, 0, sizeof (tm));
+  gtk_calendar_get_date (GTK_CALENDAR(data->window),
+                        &amp;tm.tm_year, &amp;tm.tm_mon, &amp;tm.tm_mday);
+  tm.tm_year -= TM_YEAR_BASE;
+  time = mktime(&amp;tm);
+  strftime (buffer, buff_len-1, "%x", gmtime(&amp;time));
+}
+
+void calendar_set_signal_strings( char         *sig_str,
+                                 CalendarData *data)
+{
+  gchar *prev_sig;
+
+  gtk_label_get (GTK_LABEL (data->prev_sig), &amp;prev_sig);
+  gtk_label_set (GTK_LABEL (data->prev2_sig), prev_sig);
+
+  gtk_label_get (GTK_LABEL (data->last_sig), &amp;prev_sig);
+  gtk_label_set (GTK_LABEL (data->prev_sig), prev_sig);
+  gtk_label_set (GTK_LABEL (data->last_sig), sig_str);
+}
+
+void calendar_month_changed( GtkWidget    *widget,
+                             CalendarData *data )
+{
+  char buffer[256] = "month_changed: ";
+
+  calendar_date_to_string (data, buffer+15, 256-15);
+  calendar_set_signal_strings (buffer, data);
+}
+
+void calendar_day_selected( GtkWidget    *widget,
+                            CalendarData *data )
+{
+  char buffer[256] = "day_selected: ";
+
+  calendar_date_to_string (data, buffer+14, 256-14);
+  calendar_set_signal_strings (buffer, data);
+}
+
+void calendar_day_selected_double_click( GtkWidget    *widget,
+                                         CalendarData *data )
+{
+  struct tm tm;
+  char buffer[256] = "day_selected_double_click: ";
+
+  calendar_date_to_string (data, buffer+27, 256-27);
+  calendar_set_signal_strings (buffer, data);
+
+  memset (&amp;tm, 0, sizeof (tm));
+  gtk_calendar_get_date (GTK_CALENDAR(data->window),
+                        &amp;tm.tm_year, &amp;tm.tm_mon, &amp;tm.tm_mday);
+  tm.tm_year -= TM_YEAR_BASE;
+
+  if(GTK_CALENDAR(data->window)->marked_date[tm.tm_mday-1] == 0) {
+    gtk_calendar_mark_day(GTK_CALENDAR(data->window),tm.tm_mday);
+  } else { 
+    gtk_calendar_unmark_day(GTK_CALENDAR(data->window),tm.tm_mday);
+  }
+}
+
+void calendar_prev_month( GtkWidget    *widget,
+                            CalendarData *data )
+{
+  char buffer[256] = "prev_month: ";
+
+  calendar_date_to_string (data, buffer+12, 256-12);
+  calendar_set_signal_strings (buffer, data);
+}
+
+void calendar_next_month( GtkWidget    *widget,
+                            CalendarData *data )
+{
+  char buffer[256] = "next_month: ";
+
+  calendar_date_to_string (data, buffer+12, 256-12);
+  calendar_set_signal_strings (buffer, data);
+}
+
+void calendar_prev_year( GtkWidget    *widget,
+                            CalendarData *data )
+{
+  char buffer[256] = "prev_year: ";
+
+  calendar_date_to_string (data, buffer+11, 256-11);
+  calendar_set_signal_strings (buffer, data);
+}
+
+void calendar_next_year( GtkWidget    *widget,
+                            CalendarData *data )
+{
+  char buffer[256] = "next_year: ";
+
+  calendar_date_to_string (data, buffer+11, 256-11);
+  calendar_set_signal_strings (buffer, data);
+}
+
+
+void calendar_set_flags( CalendarData *calendar )
+{
+  gint i;
+  gint options=0;
+  for (i=0;i<5;i++) 
+    if (calendar->settings[i])
+      {
+       options=options + (1<<i);
+      }
+  if (calendar->window)
+    gtk_calendar_display_options (GTK_CALENDAR (calendar->window), options);
+}
+
+void calendar_toggle_flag( GtkWidget    *toggle,
+                           CalendarData *calendar )
+{
+  gint i;
+  gint j;
+  j=0;
+  for (i=0; i<5; i++)
+    if (calendar->flag_checkboxes[i] == toggle)
+      j = i;
+
+  calendar->settings[j]=!calendar->settings[j];
+  calendar_set_flags(calendar);
+  
+}
+
+void calendar_font_selection_ok( GtkWidget    *button,
+                                 CalendarData *calendar )
+{
+  GtkStyle *style;
+  GdkFont  *font;
+
+  calendar->font = gtk_font_selection_dialog_get_font_name(
+                       GTK_FONT_SELECTION_DIALOG (calendar->font_dialog));
+  if (calendar->window)
+    {
+      font = gtk_font_selection_dialog_get_font(GTK_FONT_SELECTION_DIALOG(calendar->font_dialog));
+      if (font) 
+       {
+         style = gtk_style_copy (gtk_widget_get_style (calendar->window));
+         gdk_font_unref (style->font);
+         style->font = font;
+         gdk_font_ref (style->font);
+         gtk_widget_set_style (calendar->window, style);
+       }
+    }
+}
+
+void calendar_select_font( GtkWidget    *button,
+                           CalendarData *calendar )
+{
+  GtkWidget *window;
+
+  if (!calendar->font_dialog) {
+    window = gtk_font_selection_dialog_new ("Font Selection Dialog");
+    g_return_if_fail(GTK_IS_FONT_SELECTION_DIALOG(window));
+    calendar->font_dialog = window;
+    
+    gtk_window_position (GTK_WINDOW (window), GTK_WIN_POS_MOUSE);
+    
+    gtk_signal_connect (GTK_OBJECT (window), "destroy",
+                       GTK_SIGNAL_FUNC (gtk_widget_destroyed),
+                       &amp;calendar->font_dialog);
+    
+    gtk_signal_connect (GTK_OBJECT (GTK_FONT_SELECTION_DIALOG (window)->ok_button),
+                       "clicked", GTK_SIGNAL_FUNC(calendar_font_selection_ok),
+                       calendar);
+    gtk_signal_connect_object (GTK_OBJECT (GTK_FONT_SELECTION_DIALOG (window)->cancel_button),
+                              "clicked",
+                              GTK_SIGNAL_FUNC (gtk_widget_destroy), 
+                              GTK_OBJECT (calendar->font_dialog));
+  }
+  window=calendar->font_dialog;
+  if (!GTK_WIDGET_VISIBLE (window))
+    gtk_widget_show (window);
+  else
+    gtk_widget_destroy (window);
+
+}
+
+void create_calendar()
+{
+  GtkWidget *window;
+  GtkWidget *vbox, *vbox2, *vbox3;
+  GtkWidget *hbox;
+  GtkWidget *hbbox;
+  GtkWidget *calendar;
+  GtkWidget *toggle;
+  GtkWidget *button;
+  GtkWidget *frame;
+  GtkWidget *separator;
+  GtkWidget *label;
+  GtkWidget *bbox;
+  static CalendarData calendar_data;
+  gint i;
+  
+  struct {
+    char *label;
+  } flags[] =
+    {
+      { "Show Heading" },
+      { "Show Day Names" },
+      { "No Month Change" },
+      { "Show Week Numbers" },
+      { "Week Start Monday" }
+    };
+
+  
+  calendar_data.window = NULL;
+  calendar_data.font = NULL;
+  calendar_data.font_dialog = NULL;
+
+  for (i=0; i<5; i++) {
+    calendar_data.settings[i]=0;
+  }
+
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_window_set_title(GTK_WINDOW(window), "GtkCalendar Example");
+  gtk_container_border_width (GTK_CONTAINER (window), 5);
+  gtk_signal_connect(GTK_OBJECT(window), "destroy",
+                    GTK_SIGNAL_FUNC(gtk_main_quit),
+                    NULL);
+  gtk_signal_connect(GTK_OBJECT(window), "delete-event",
+                    GTK_SIGNAL_FUNC(gtk_false),
+                    NULL);
+
+  gtk_window_set_policy(GTK_WINDOW(window), FALSE, FALSE, TRUE);
+
+  vbox = gtk_vbox_new(FALSE, DEF_PAD);
+  gtk_container_add (GTK_CONTAINER (window), vbox);
+
+  /*
+   * The top part of the window, Calendar, flags and fontsel.
+   */
+
+  hbox = gtk_hbox_new(FALSE, DEF_PAD);
+  gtk_box_pack_start (GTK_BOX(vbox), hbox, TRUE, TRUE, DEF_PAD);
+  hbbox = gtk_hbutton_box_new();
+  gtk_box_pack_start(GTK_BOX(hbox), hbbox, FALSE, FALSE, DEF_PAD);
+  gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_SPREAD);
+  gtk_button_box_set_spacing(GTK_BUTTON_BOX(hbbox), 5);
+
+  /* Calendar widget */
+  frame = gtk_frame_new("Calendar");
+  gtk_box_pack_start(GTK_BOX(hbbox), frame, FALSE, TRUE, DEF_PAD);
+  calendar=gtk_calendar_new();
+  calendar_data.window = calendar;
+  calendar_set_flags(&amp;calendar_data);
+  gtk_calendar_mark_day ( GTK_CALENDAR(calendar), 19); 
+  gtk_container_add( GTK_CONTAINER( frame), calendar);
+  gtk_signal_connect (GTK_OBJECT (calendar), "month_changed", 
+                      GTK_SIGNAL_FUNC (calendar_month_changed),
+                     &amp;calendar_data);
+  gtk_signal_connect (GTK_OBJECT (calendar), "day_selected", 
+                      GTK_SIGNAL_FUNC (calendar_day_selected),
+                     &amp;calendar_data);
+  gtk_signal_connect (GTK_OBJECT (calendar), "day_selected_double_click", 
+                      GTK_SIGNAL_FUNC (calendar_day_selected_double_click),
+                     &amp;calendar_data);
+  gtk_signal_connect (GTK_OBJECT (calendar), "prev_month", 
+                      GTK_SIGNAL_FUNC (calendar_prev_month),
+                     &amp;calendar_data);
+  gtk_signal_connect (GTK_OBJECT (calendar), "next_month", 
+                      GTK_SIGNAL_FUNC (calendar_next_month),
+                     &amp;calendar_data);
+  gtk_signal_connect (GTK_OBJECT (calendar), "prev_year", 
+                      GTK_SIGNAL_FUNC (calendar_prev_year),
+                     &amp;calendar_data);
+  gtk_signal_connect (GTK_OBJECT (calendar), "next_year", 
+                      GTK_SIGNAL_FUNC (calendar_next_year),
+                     &amp;calendar_data);
+
+
+  separator = gtk_vseparator_new ();
+  gtk_box_pack_start (GTK_BOX (hbox), separator, FALSE, TRUE, 0);
+
+  vbox2 = gtk_vbox_new(FALSE, DEF_PAD);
+  gtk_box_pack_start(GTK_BOX(hbox), vbox2, FALSE, FALSE, DEF_PAD);
+  
+  /* Build the Right frame with the flags in */ 
+
+  frame = gtk_frame_new("Flags");
+  gtk_box_pack_start(GTK_BOX(vbox2), frame, TRUE, TRUE, DEF_PAD);
+  vbox3 = gtk_vbox_new(TRUE, DEF_PAD_SMALL);
+  gtk_container_add(GTK_CONTAINER(frame), vbox3);
+
+  for (i = 0; i < 5; i++)
+    {
+      toggle = gtk_check_button_new_with_label(flags[i].label);
+      gtk_signal_connect (GTK_OBJECT (toggle),
+                           "toggled",
+                           GTK_SIGNAL_FUNC(calendar_toggle_flag),
+                           &amp;calendar_data);
+      gtk_box_pack_start (GTK_BOX (vbox3), toggle, TRUE, TRUE, 0);
+      calendar_data.flag_checkboxes[i]=toggle;
+    }
+  /* Build the right font-button */ 
+  button = gtk_button_new_with_label("Font...");
+  gtk_signal_connect (GTK_OBJECT (button),
+                     "clicked",
+                     GTK_SIGNAL_FUNC(calendar_select_font),
+                     &amp;calendar_data);
+  gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0);
+
+  /*
+   *  Build the Signal-event part.
+   */
+
+  frame = gtk_frame_new("Signal events");
+  gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, DEF_PAD);
+
+  vbox2 = gtk_vbox_new(TRUE, DEF_PAD_SMALL);
+  gtk_container_add(GTK_CONTAINER(frame), vbox2);
+  
+  hbox = gtk_hbox_new (FALSE, 3);
+  gtk_box_pack_start (GTK_BOX (vbox2), hbox, FALSE, TRUE, 0);
+  label = gtk_label_new ("Signal:");
+  gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
+  calendar_data.last_sig = gtk_label_new ("");
+  gtk_box_pack_start (GTK_BOX (hbox), calendar_data.last_sig, FALSE, TRUE, 0);
+
+  hbox = gtk_hbox_new (FALSE, 3);
+  gtk_box_pack_start (GTK_BOX (vbox2), hbox, FALSE, TRUE, 0);
+  label = gtk_label_new ("Previous signal:");
+  gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
+  calendar_data.prev_sig = gtk_label_new ("");
+  gtk_box_pack_start (GTK_BOX (hbox), calendar_data.prev_sig, FALSE, TRUE, 0);
+
+  hbox = gtk_hbox_new (FALSE, 3);
+  gtk_box_pack_start (GTK_BOX (vbox2), hbox, FALSE, TRUE, 0);
+  label = gtk_label_new ("Second previous signal:");
+  gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
+  calendar_data.prev2_sig = gtk_label_new ("");
+  gtk_box_pack_start (GTK_BOX (hbox), calendar_data.prev2_sig, FALSE, TRUE, 0);
+
+  bbox = gtk_hbutton_box_new ();
+  gtk_box_pack_start (GTK_BOX (vbox), bbox, FALSE, FALSE, 0);
+  gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
+
+  button = gtk_button_new_with_label ("Close");
+  gtk_signal_connect (GTK_OBJECT (button), "clicked", 
+                     GTK_SIGNAL_FUNC (gtk_main_quit), 
+                     NULL);
+  gtk_container_add (GTK_CONTAINER (bbox), button);
+  GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
+  gtk_widget_grab_default (button);
+
+  gtk_widget_show_all(window);
+}
+
+
+int main(int   argc,
+         char *argv[] )
+{
+  gtk_set_locale ();
+  gtk_init (&amp;argc, &amp;argv);
+
+  create_calendar();
+
+  gtk_main();
+
+  return(0);
+}
+/* example-end */
+</programlisting>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> Color Selection</title>
+
+<para>The color selection widget is, not surprisingly, a widget for
+interactive selection of colors. This composite widget lets the user
+select a color by manipulating RGB (Red, Green, Blue) and HSV (Hue,
+Saturation, Value) triples.  This is done either by adjusting single
+values with sliders or entries, or by picking the desired color from a
+hue-saturation wheel/value bar.  Optionally, the opacity of the color
+can also be set.</para>
+
+<para>The color selection widget currently emits only one signal,
+"color_changed", which is emitted whenever the current color in the
+widget changes, either when the user changes it or if it's set
+explicitly through gtk_color_selection_set_color().</para>
+
+<para>Lets have a look at what the color selection widget has to offer
+us. The widget comes in two flavours: gtk_color_selection and
+gtk_color_selection_dialog.</para>
+
+<para><literallayout>
+<literal>GtkWidget *gtk_color_selection_new( void );
+</verb></tscreen>
+       
+You'll probably not be using this constructor directly. It creates an
+orphan ColorSelection widget which you'll have to parent
+yourself. The ColorSelection widget inherits from the VBox
+widget.</para>
+
+<para><tscreen><verb> 
+GtkWidget *gtk_color_selection_dialog_new( const gchar *title );</literal>
+</literallayout></para>
+
+<para>This is the most common color selection constructor. It creates a
+ColorSelectionDialog. It consists of a Frame containing a
+ColorSelection widget, an HSeparator and an HBox with three buttons,
+"Ok", "Cancel" and "Help". You can reach these buttons by accessing
+the "ok_button", "cancel_button" and "help_button" widgets in the
+ColorSelectionDialog structure,
+(i.e., <literal>GTK_COLOR_SELECTION_DIALOG(colorseldialog)->ok_button</literal>)).</para>
+
+<para><literallayout>
+<literal>void gtk_color_selection_set_update_policy( GtkColorSelection *colorsel, 
+                                            GtkUpdateType      policy );</literal>
+</literallayout></para>
+
+<para>This function sets the update policy. The default policy is
+<literal>GTK_UPDATE_CONTINUOUS</literal> which means that the current color is
+updated continuously when the user drags the sliders or presses the
+mouse and drags in the hue-saturation wheel or value bar. If you
+experience performance problems, you may want to set the policy to
+<literal>GTK_UPDATE_DISCONTINUOUS</literal> or <literal>GTK_UPDATE_DELAYED</literal>.</para>
+
+<para><literallayout>
+<literal>void gtk_color_selection_set_opacity( GtkColorSelection *colorsel,
+                                      gint               use_opacity );</literal>
+</literallayout></para>
+
+<para>The color selection widget supports adjusting the opacity of a color
+(also known as the alpha channel). This is disabled by
+default. Calling this function with use_opacity set to TRUE enables
+opacity. Likewise, use_opacity set to FALSE will disable opacity.</para>
+
+<para><literallayout>
+<literal>void gtk_color_selection_set_color( GtkColorSelection *colorsel,
+                                    gdouble           *color );</literal>
+</literallayout></para>
+
+<para>You can set the current color explicitly by calling this function with
+a pointer to an array of colors (gdouble). The length of the array
+depends on whether opacity is enabled or not. Position 0 contains the
+red component, 1 is green, 2 is blue and opacity is at position 3
+(only if opacity is enabled, see
+gtk_color_selection_set_opacity()). All values are between 0.0 and
+1.0.</para>
+
+<para><literallayout>
+<literal>void gtk_color_selection_get_color( GtkColorSelection *colorsel,
+                                    gdouble           *color );</literal>
+</literallayout></para>
+
+<para>When you need to query the current color, typically when you've
+received a "color_changed" signal, you use this function. Color is a
+pointer to the array of colors to fill in. See the
+gtk_color_selection_set_color() function for the description of this
+array.</para>
+
+<para><!-- Need to do a whole section on DnD - TRG
+Drag and drop
+-------------</para>
+
+<para>The color sample areas (right under the hue-saturation wheel) supports
+drag and drop. The type of drag and drop is "application/x-color". The
+message data consists of an array of 4 (or 5 if opacity is enabled)
+gdouble values, where the value at position 0 is 0.0 (opacity on) or
+1.0 (opacity off) followed by the red, green and blue values at
+positions 1,2 and 3 respectively.  If opacity is enabled, the opacity
+is passed in the value at position 4.
+--></para>
+
+<para>Here's a simple example demonstrating the use of the
+ColorSelectionDialog. The program displays a window containing a
+drawing area. Clicking on it opens a color selection dialog, and
+changing the color in the color selection dialog changes the
+background color.</para>
+
+<programlisting role="C">
+/* example-start colorsel colorsel.c */
+
+#include &lt;glib.h&gt;
+#include &lt;gdk/gdk.h&gt;
+#include &lt;gtk/gtk.h&gt;
+
+GtkWidget *colorseldlg = NULL;
+GtkWidget *drawingarea = NULL;
+
+/* Color changed handler */
+
+void color_changed_cb( GtkWidget         *widget,
+                       GtkColorSelection *colorsel )
+{
+  gdouble color[3];
+  GdkColor gdk_color;
+  GdkColormap *colormap;
+
+  /* Get drawingarea colormap */
+
+  colormap = gdk_window_get_colormap (drawingarea->window);
+
+  /* Get current color */
+
+  gtk_color_selection_get_color (colorsel,color);
+
+  /* Fit to a unsigned 16 bit integer (0..65535) and
+   * insert into the GdkColor structure */
+
+  gdk_color.red = (guint16)(color[0]*65535.0);
+  gdk_color.green = (guint16)(color[1]*65535.0);
+  gdk_color.blue = (guint16)(color[2]*65535.0);
+
+  /* Allocate color */
+
+  gdk_color_alloc (colormap, &amp;gdk_color);
+
+  /* Set window background color */
+
+  gdk_window_set_background (drawingarea->window, &amp;gdk_color);
+
+  /* Clear window */
+
+  gdk_window_clear (drawingarea->window);
+}
+
+/* Drawingarea event handler */
+
+gint area_event( GtkWidget *widget,
+                 GdkEvent  *event,
+                 gpointer   client_data )
+{
+  gint handled = FALSE;
+  GtkWidget *colorsel;
+
+  /* Check if we've received a button pressed event */
+
+  if (event->type == GDK_BUTTON_PRESS &amp;&amp; colorseldlg == NULL)
+    {
+      /* Yes, we have an event and there's no colorseldlg yet! */
+
+      handled = TRUE;
+
+      /* Create color selection dialog */
+
+      colorseldlg = gtk_color_selection_dialog_new("Select background color");
+
+      /* Get the ColorSelection widget */
+
+      colorsel = GTK_COLOR_SELECTION_DIALOG(colorseldlg)->colorsel;
+
+      /* Connect to the "color_changed" signal, set the client-data
+       * to the colorsel widget */
+
+      gtk_signal_connect(GTK_OBJECT(colorsel), "color_changed",
+        (GtkSignalFunc)color_changed_cb, (gpointer)colorsel);
+
+      /* Show the dialog */
+
+      gtk_widget_show(colorseldlg);
+    }
+
+  return handled;
+}
+
+/* Close down and exit handler */
+
+gint destroy_window( GtkWidget *widget,
+                     GdkEvent  *event,
+                     gpointer   client_data )
+{
+  gtk_main_quit ();
+  return(TRUE);
+}
+
+/* Main */
+
+gint main( gint   argc,
+           gchar *argv[] )
+{
+  GtkWidget *window;
+
+  /* Initialize the toolkit, remove gtk-related commandline stuff */
+
+  gtk_init (&amp;argc,&amp;argv);
+
+  /* Create toplevel window, set title and policies */
+
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_window_set_title (GTK_WINDOW(window), "Color selection test");
+  gtk_window_set_policy (GTK_WINDOW(window), TRUE, TRUE, TRUE);
+
+  /* Attach to the "delete" and "destroy" events so we can exit */
+
+  gtk_signal_connect (GTK_OBJECT(window), "delete_event",
+    (GtkSignalFunc)destroy_window, (gpointer)window);
+  
+  /* Create drawingarea, set size and catch button events */
+
+  drawingarea = gtk_drawing_area_new ();
+
+  gtk_drawing_area_size (GTK_DRAWING_AREA(drawingarea), 200, 200);
+
+  gtk_widget_set_events (drawingarea, GDK_BUTTON_PRESS_MASK);
+
+  gtk_signal_connect (GTK_OBJECT(drawingarea), "event", 
+    (GtkSignalFunc)area_event, (gpointer)drawingarea);
+  
+  /* Add drawingarea to window, then show them both */
+
+  gtk_container_add (GTK_CONTAINER(window), drawingarea);
+
+  gtk_widget_show (drawingarea);
+  gtk_widget_show (window);
+  
+  /* Enter the gtk main loop (this never returns) */
+
+  gtk_main ();
+
+  /* Satisfy grumpy compilers */
+
+  return(0);
+}
+/* example-end */
+</programlisting>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> File Selections</title>
+
+<para>The file selection widget is a quick and simple way to display a File
+dialog box. It comes complete with Ok, Cancel, and Help buttons, a
+great way to cut down on programming time.</para>
+
+<para>To create a new file selection box use:</para>
+
+<para><literallayout>
+<literal>GtkWidget *gtk_file_selection_new( gchar *title );</literal>
+</literallayout></para>
+
+<para>To set the filename, for example to bring up a specific directory, or
+give a default filename, use this function:</para>
+
+<para><literallayout>
+<literal>void gtk_file_selection_set_filename( GtkFileSelection *filesel,
+                                      gchar            *filename );</literal>
+</literallayout></para>
+
+<para>To grab the text that the user has entered or clicked on, use this 
+function:</para>
+
+<para><literallayout>
+<literal>gchar *gtk_file_selection_get_filename( GtkFileSelection *filesel );</literal>
+</literallayout></para>
+
+<para>There are also pointers to the widgets contained within the file 
+selection widget. These are:</para>
+
+<para><literallayout>
+<literal>  dir_list
+  file_list
+  selection_entry
+  selection_text
+  main_vbox
+  ok_button
+  cancel_button
+  help_button
+</verb></tscreen>
+Most likely you will want to use the ok_button, cancel_button, and
+help_button pointers in signaling their use.</para>
+
+<para>Included here is an example stolen from testgtk.c, modified to run on
+its own. As you will see, there is nothing much to creating a file
+selection widget. While in this example the Help button appears on the
+screen, it does nothing as there is not a signal attached to it.</para>
+
+<programlisting role="C">
+/* example-start filesel filesel.c */
+
+#include &lt;gtk/gtk.h&gt;
+
+/* Get the selected filename and print it to the console */
+void file_ok_sel( GtkWidget        *w,
+                  GtkFileSelection *fs )
+{
+    g_print ("%s\n", gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs)));
+}
+
+void destroy( GtkWidget *widget,
+              gpointer   data )
+{
+    gtk_main_quit ();
+}
+
+int main( int   argc,
+          char *argv[] )
+{
+    GtkWidget *filew;
+    
+    gtk_init (&amp;argc, &amp;argv);
+    
+    /* Create a new file selection widget */
+    filew = gtk_file_selection_new ("File selection");
+    
+    gtk_signal_connect (GTK_OBJECT (filew), "destroy",
+                       (GtkSignalFunc) destroy, &amp;filew);
+    /* Connect the ok_button to file_ok_sel function */
+    gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (filew)->ok_button),
+                       "clicked", (GtkSignalFunc) file_ok_sel, filew );
+    
+    /* Connect the cancel_button to destroy the widget */
+    gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION
+                                            (filew)->cancel_button),
+                              "clicked", (GtkSignalFunc) gtk_widget_destroy,
+                              GTK_OBJECT (filew));
+    
+    /* Lets set the filename, as if this were a save dialog, and we are giving
+     a default filename */
+    gtk_file_selection_set_filename (GTK_FILE_SELECTION(filew), 
+                                    "penguin.png");
+    
+    gtk_widget_show(filew);
+    gtk_main ();
+    return 0;
+}
+/* example-end */
+</programlisting>
+
+</sect1>
+</chapter>
+
+<!-- ***************************************************************** -->
+<chapter id="ch-ContainerWidgets">
+<title>Container Widgets</title>
+
+<!-- ----------------------------------------------------------------- -->   
+<sect1>The EventBox
+<p> 
+Some GTK widgets don't have associated X windows, so they just draw on
+their parents. Because of this, they cannot receive events and if they
+are incorrectly sized, they don't clip so you can get messy
+overwriting, etc. If you require more from these widgets, the EventBox
+is for you.</para>
+
+<para>At first glance, the EventBox widget might appear to be totally
+useless. It draws nothing on the screen and responds to no
+events. However, it does serve a function - it provides an X window
+for its child widget. This is important as many GTK widgets do not
+have an associated X window. Not having an X window saves memory and
+improves performance, but also has some drawbacks. A widget without an
+X window cannot receive events, and does not perform any clipping on
+its contents. Although the name <emphasis>EventBox</emphasis> emphasizes the
+event-handling function, the widget can also be used for clipping.
+(and more, see the example below).</para>
+
+<para>To create a new EventBox widget, use:</para>
+
+<para><literallayout>
+<literal>GtkWidget *gtk_event_box_new( void );</literal>
+</literallayout></para>
+
+<para>A child widget can then be added to this EventBox:</para>
+
+<para><literallayout>
+<literal>    gtk_container_add( GTK_CONTAINER(event_box), child_widget );</literal>
+</literallayout></para>
+
+<para>The following example demonstrates both uses of an EventBox - a label
+is created that is clipped to a small box, and set up so that a
+mouse-click on the label causes the program to exit. Resizing the
+window reveals varying amounts of the label.</para>
+
+<programlisting role="C">
+/* example-start eventbox eventbox.c */
+
+#include &lt;gtk/gtk.h&gt;
+
+int main( int argc,
+          char *argv[] )
+{
+    GtkWidget *window;
+    GtkWidget *event_box;
+    GtkWidget *label;
+    
+    gtk_init (&amp;argc, &amp;argv);
+    
+    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+    
+    gtk_window_set_title (GTK_WINDOW (window), "Event Box");
+    
+    gtk_signal_connect (GTK_OBJECT (window), "destroy",
+                       GTK_SIGNAL_FUNC (gtk_exit), NULL);
+    
+    gtk_container_set_border_width (GTK_CONTAINER (window), 10);
+    
+    /* Create an EventBox and add it to our toplevel window */
+    
+    event_box = gtk_event_box_new ();
+    gtk_container_add (GTK_CONTAINER(window), event_box);
+    gtk_widget_show (event_box);
+    
+    /* Create a long label */
+    
+    label = gtk_label_new ("Click here to quit, quit, quit, quit, quit");
+    gtk_container_add (GTK_CONTAINER (event_box), label);
+    gtk_widget_show (label);
+    
+    /* Clip it short. */
+    gtk_widget_set_usize (label, 110, 20);
+    
+    /* And bind an action to it */
+    gtk_widget_set_events (event_box, GDK_BUTTON_PRESS_MASK);
+    gtk_signal_connect (GTK_OBJECT(event_box), "button_press_event",
+                       GTK_SIGNAL_FUNC (gtk_exit), NULL);
+    
+    /* Yet one more thing you need an X window for ... */
+    
+    gtk_widget_realize (event_box);
+    gdk_window_set_cursor (event_box->window, gdk_cursor_new (GDK_HAND1));
+    
+    gtk_widget_show (window);
+    
+    gtk_main ();
+    
+    return(0);
+}
+/* example-end */
+</programlisting>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->   
+<sect1>The Alignment widget
+
+<para>The alignment widget allows you to place a widget within its window at
+a position and size relative to the size of the Alignment widget
+itself. For example, it can be very useful for centering a widget
+within the window.</para>
+
+<para>There are only two functions associated with the Alignment widget:</para>
+
+<para><literallayout>
+<literal>GtkWidget* gtk_alignment_new( gfloat xalign,
+                              gfloat yalign,
+                              gfloat xscale,
+                              gfloat yscale );</para>
+
+<para>void gtk_alignment_set( GtkAlignment *alignment,
+                        gfloat        xalign,
+                        gfloat        yalign,
+                        gfloat        xscale,
+                        gfloat        yscale );</literal>
+</literallayout></para>
+
+<para>The first function creates a new Alignment widget with the specified
+parameters. The second function allows the alignment paramters of an
+exisiting Alignment widget to be altered.</para>
+
+<para>All four alignment parameters are floating point numbers which can
+range from 0.0 to 1.0. The <literal>xalign</literal> and <literal>yalign</literal> arguments
+affect the position of the widget placed within the Alignment
+widget. The <literal>xscale</literal> and <literal>yscale</literal> arguments effect the amount of
+space allocated to the widget.</para>
+
+<para>A child widget can be added to this Alignment widget using:</para>
+
+<para><literallayout>
+<literal>    gtk_container_add( GTK_CONTAINER(alignment), child_widget );</literal>
+</literallayout></para>
+
+<para>For an example of using an Alignment widget, refer to the example for
+the <link linkend="ch-ProgressBar">Progress Bar</link> widget.</para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> Fixed Container</title>
+
+<para>The Fixed container allows you to place widgets at a fixed position
+within it's window, relative to it's upper left hand corner. The
+position of the widgets can be changed dynamically.</para>
+
+<para>There are only three functions associated with the fixed widget:</para>
+
+<para><literallayout>
+<literal>GtkWidget* gtk_fixed_new( void );</para>
+
+<para>void gtk_fixed_put( GtkFixed  *fixed,
+                    GtkWidget *widget,
+                    gint16     x,
+                    gint16     y );</para>
+
+<para>void gtk_fixed_move( GtkFixed  *fixed,
+                     GtkWidget *widget,
+                     gint16     x,
+                     gint16     y );</literal>
+</literallayout></para>
+
+<para>The function <literal>gtk_fixed_new</literal> allows you to create a new Fixed
+container.</para>
+
+<para><literal>gtk_fixed_put</literal> places <literal>widget</literal> in the container <literal>fixed</literal> at
+the position specified by <literal>x</literal> and <literal>y</literal>.</para>
+
+<para><literal>gtk_fixed_move</literal> allows the specified widget to be moved to a new
+position.</para>
+
+<para>The following example illustrates how to use the Fixed Container.</para>
+
+<programlisting role="C">
+/* example-start fixed fixed.c */
+
+#include &lt;gtk/gtk.h&gt;
+
+/* I'm going to be lazy and use some global variables to
+ * store the position of the widget within the fixed
+ * container */
+gint x=50;
+gint y=50;
+
+/* This callback function moves the button to a new position
+ * in the Fixed container. */
+void move_button( GtkWidget *widget,
+                  GtkWidget *fixed )
+{
+  x = (x+30)%300;
+  y = (y+50)%300;
+  gtk_fixed_move( GTK_FIXED(fixed), widget, x, y); 
+}
+
+int main( int   argc,
+          char *argv[] )
+{
+  /* GtkWidget is the storage type for widgets */
+  GtkWidget *window;
+  GtkWidget *fixed;
+  GtkWidget *button;
+  gint i;
+
+  /* Initialise GTK */
+  gtk_init(&amp;argc, &amp;argv);
+    
+  /* Create a new window */
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_window_set_title(GTK_WINDOW(window), "Fixed Container");
+
+  /* Here we connect the "destroy" event to a signal handler */ 
+  gtk_signal_connect (GTK_OBJECT (window), "destroy",
+                     GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
+  /* Sets the border width of the window. */
+  gtk_container_set_border_width (GTK_CONTAINER (window), 10);
+
+  /* Create a Fixed Container */
+  fixed = gtk_fixed_new();
+  gtk_container_add(GTK_CONTAINER(window), fixed);
+  gtk_widget_show(fixed);
+  
+  for (i = 1 ; i <= 3 ; i++) {
+    /* Creates a new button with the label "Press me" */
+    button = gtk_button_new_with_label ("Press me");
+  
+    /* When the button receives the "clicked" signal, it will call the
+     * function move_button() passing it the Fixed Container as its
+     * argument. */
+    gtk_signal_connect (GTK_OBJECT (button), "clicked",
+                       GTK_SIGNAL_FUNC (move_button), fixed);
+  
+    /* This packs the button into the fixed containers window. */
+    gtk_fixed_put (GTK_FIXED (fixed), button, i*50, i*50);
+  
+    /* The final step is to display this newly created widget. */
+    gtk_widget_show (button);
+  }
+
+  /* Display the window */
+  gtk_widget_show (window);
+    
+  /* Enter the event loop */
+  gtk_main ();
+    
+  return(0);
+}
+/* example-end */
+</programlisting>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> Layout Container</title>
+
+<para>The Layout container is similar to the Fixed container except that it
+implements an infinite (where infinity is less than 2^32) scrolling
+area. The X window system has a limitation where windows can be at
+most 32767 pixels wide or tall. The Layout container gets around this
+limitation by doing some exotic stuff using window and bit gravities,
+so that you can have smooth scrolling even when you have many child
+widgets in your scrolling area.</para>
+
+<para>A Layout container is created using:</para>
+
+<para><literallayout>
+<literal>GtkWidget *gtk_layout_new( GtkAdjustment *hadjustment,
+                           GtkAdjustment *vadjustment );</literal>
+</literallayout></para>
+
+<para>As you can see, you can optionally specify the Adjustment objects that
+the Layout widget will use for its scrolling.</para>
+
+<para>You can add and move widgets in the Layout container using the
+following two functions:</para>
+
+<para><literallayout>
+<literal>void gtk_layout_put( GtkLayout *layout,
+                     GtkWidget *widget,
+                     gint       x,
+                     gint       y );</para>
+
+<para>void gtk_layout_move( GtkLayout *layout,
+                      GtkWidget *widget,
+                      gint       x,
+                      gint       y );</literal>
+</literallayout></para>
+
+<para>The size of the Layout container can be set using the next function:</para>
+
+<para><literallayout>
+<literal>void gtk_layout_set_size( GtkLayout *layout,
+                          guint      width,
+                          guint      height );</literal>
+</literallayout></para>
+
+<para>Layout containers are one of the very few widgets in the GTK widget
+set that actively repaint themselves on screen as they are changed
+using the above functions (the vast majority of widgets queue
+requests which are then processed when control returns to the
+<literal>gtk_main()</literal> function).</para>
+
+<para>When you want to make a large number of changes to a Layout container,
+you can use the following two functions to disable and re-enable this
+repainting functionality:</para>
+
+<para><literallayout>
+<literal>void gtk_layout_freeze( GtkLayout *layout );</para>
+
+<para>void gtk_layout_thaw( GtkLayout *layout );</literal>
+</literallayout></para>
+
+<para>The final four functions for use with Layout widgets are for
+manipulating the horizontal and vertical adjustment widgets:</para>
+
+<para><literallayout>
+<literal>GtkAdjustment* gtk_layout_get_hadjustment( GtkLayout *layout );</para>
+
+<para>GtkAdjustment* gtk_layout_get_vadjustment( GtkLayout *layout );</para>
+
+<para>void gtk_layout_set_hadjustment( GtkLayout     *layout,
+                                 GtkAdjustment *adjustment );</para>
+
+<para>void gtk_layout_set_vadjustment( GtkLayout     *layout,
+                                 GtkAdjustment *adjustment);</literal>
+</literallayout></para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1> Frames
+
+<para>Frames can be used to enclose one or a group of widgets with a box
+which can optionally be labelled. The position of the label and the
+style of the box can be altered to suit.</para>
+
+<para>A Frame can be created with the following function:</para>
+
+<para><literallayout>
+<literal>GtkWidget *gtk_frame_new( const gchar *label );</literal>
+</literallayout></para>
+
+<para>The label is by default placed in the upper left hand corner of the
+frame. A value of NULL for the <literal>label</literal> argument will result in no
+label being displayed. The text of the label can be changed using the
+next function.</para>
+
+<para><literallayout>
+<literal>void gtk_frame_set_label( GtkFrame    *frame,
+                          const gchar *label );</literal>
+</literallayout></para>
+
+<para>The position of the label can be changed using this function:</para>
+
+<para><literallayout>
+<literal>void gtk_frame_set_label_align( GtkFrame *frame,
+                                gfloat    xalign,
+                                gfloat    yalign );</literal>
+</literallayout></para>
+
+<para><literal>xalign</literal> and <literal>yalign</literal> take values between 0.0 and 1.0. <literal>xalign</literal>
+indicates the position of the label along the top horizontal of the
+frame. <literal>yalign</literal> is not currently used. The default value of xalign
+is 0.0 which places the label at the left hand end of the frame.</para>
+
+<para>The next function alters the style of the box that is used to outline
+the frame.</para>
+
+<para><literallayout>
+<literal>void gtk_frame_set_shadow_type( GtkFrame      *frame,
+                                GtkShadowType  type);</literal>
+</literallayout></para>
+
+<para>The <literal>type</literal> argument can take one of the following values:</para>
+<para><literallayout>
+<literal>  GTK_SHADOW_NONE
+  GTK_SHADOW_IN
+  GTK_SHADOW_OUT
+  GTK_SHADOW_ETCHED_IN (the default)
+  GTK_SHADOW_ETCHED_OUT</literal>
+</literallayout></para>
+
+<para>The following code example illustrates the use of the Frame widget.</para>
+
+<programlisting role="C">
+/* example-start frame frame.c */
+
+#include &lt;gtk/gtk.h&gt;
+
+int main( int   argc,
+          char *argv[] )
+{
+  /* GtkWidget is the storage type for widgets */
+  GtkWidget *window;
+  GtkWidget *frame;
+  GtkWidget *button;
+  gint i;
+
+  /* Initialise GTK */
+  gtk_init(&amp;argc, &amp;argv);
+    
+  /* Create a new window */
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_window_set_title(GTK_WINDOW(window), "Frame Example");
+
+  /* Here we connect the "destroy" event to a signal handler */ 
+  gtk_signal_connect (GTK_OBJECT (window), "destroy",
+                     GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
+
+  gtk_widget_set_usize(window, 300, 300);
+  /* Sets the border width of the window. */
+  gtk_container_set_border_width (GTK_CONTAINER (window), 10);
+
+  /* Create a Frame */
+  frame = gtk_frame_new(NULL);
+  gtk_container_add(GTK_CONTAINER(window), frame);
+
+  /* Set the frame's label */
+  gtk_frame_set_label( GTK_FRAME(frame), "GTK Frame Widget" );
+
+  /* Align the label at the right of the frame */
+  gtk_frame_set_label_align( GTK_FRAME(frame), 1.0, 0.0);
+
+  /* Set the style of the frame */
+  gtk_frame_set_shadow_type( GTK_FRAME(frame), GTK_SHADOW_ETCHED_OUT);
+
+  gtk_widget_show(frame);
+  
+  /* Display the window */
+  gtk_widget_show (window);
+    
+  /* Enter the event loop */
+  gtk_main ();
+    
+  return(0);
+}
+/* example-end */
+
+<para></verb></tscreen></para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->   
+<sect1>
+<title> Aspect Frames</title>
+
+<para>The aspect frame widget is like a frame widget, except that it also
+enforces the aspect ratio (that is, the ratio of the width to the
+height) of the child widget to have a certain value, adding extra
+space if necessary. This is useful, for instance, if you want to
+preview a larger image. The size of the preview should vary when the
+user resizes the window, but the aspect ratio needs to always match
+the original image.
+  
+To create a new aspect frame use:
+   </para>
+<para><literallayout>
+<literal>GtkWidget *gtk_aspect_frame_new( const gchar *label,
+                                 gfloat       xalign,
+                                 gfloat       yalign,
+                                 gfloat       ratio,
+                                 gint         obey_child);
+</verb></tscreen>
+   
+<literal>xalign</literal> and <literal>yalign</literal> specify alignment as with Alignment
+widgets. If <literal>obey_child</literal> is true, the aspect ratio of a child
+widget will match the aspect ratio of the ideal size it requests.
+Otherwise, it is given by <literal>ratio</literal>.
+   
+To change the options of an existing aspect frame, you can use:
+   </para>
+<para><literallayout>
+<literal>void gtk_aspect_frame_set( GtkAspectFrame *aspect_frame,
+                           gfloat          xalign,
+                           gfloat          yalign,
+                           gfloat          ratio,
+                           gint            obey_child);
+</verb></tscreen>
+   
+As an example, the following program uses an AspectFrame to present a
+drawing area whose aspect ratio will always be 2:1, no matter how the
+user resizes the top-level window.
+   </para>
+<para><literallayout>
+<literal>/* example-start aspectframe aspectframe.c */
+
+#include &lt;gtk/gtk.h&gt;
+   
+int main( int argc,
+          char *argv[] )
+{
+    GtkWidget *window;
+    GtkWidget *aspect_frame;
+    GtkWidget *drawing_area;
+    gtk_init (&amp;argc, &amp;argv);
+   
+    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+    gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
+    gtk_signal_connect (GTK_OBJECT (window), "destroy",
+                        GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
+    gtk_container_set_border_width (GTK_CONTAINER (window), 10);
+   
+    /* Create an aspect_frame and add it to our toplevel window */
+   
+    aspect_frame = gtk_aspect_frame_new ("2x1", /* label */
+                                         0.5, /* center x */
+                                         0.5, /* center y */
+                                         2, /* xsize/ysize = 2 */
+                                         FALSE /* ignore child's aspect */);
+   
+    gtk_container_add (GTK_CONTAINER(window), aspect_frame);
+    gtk_widget_show (aspect_frame);
+   
+    /* Now add a child widget to the aspect frame */
+   
+    drawing_area = gtk_drawing_area_new ();
+   
+    /* Ask for a 200x200 window, but the AspectFrame will give us a 200x100
+     * window since we are forcing a 2x1 aspect ratio */
+    gtk_widget_set_usize (drawing_area, 200, 200);
+    gtk_container_add (GTK_CONTAINER(aspect_frame), drawing_area);
+    gtk_widget_show (drawing_area);
+   
+    gtk_widget_show (window);
+    gtk_main ();
+    return 0;
+}
+/* example-end */
+</programlisting>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->   
+<sect1>
+<title> Paned Window Widgets</title>
+
+<para>The paned window widgets are useful when you want to divide an area
+into two parts, with the relative size of the two parts controlled by
+the user. A groove is drawn between the two portions with a handle
+that the user can drag to change the ratio. The division can either be
+horizontal (HPaned) or vertical (VPaned).
+   
+To create a new paned window, call one of:
+   </para>
+<para><literallayout>
+<literal>GtkWidget *gtk_hpaned_new (void);</para>
+
+<para>GtkWidget *gtk_vpaned_new (void);</literal>
+</literallayout></para>
+
+<para>After creating the paned window widget, you need to add child widgets
+to its two halves. To do this, use the functions:
+   </para>
+<para><literallayout>
+<literal>void gtk_paned_add1 (GtkPaned *paned, GtkWidget *child);</para>
+
+<para>void gtk_paned_add2 (GtkPaned *paned, GtkWidget *child);
+</verb></tscreen>
+   
+<literal>gtk_paned_add1()</literal> adds the child widget to the left or top half of
+the paned window. <literal>gtk_paned_add2()</literal> adds the child widget to the
+right or bottom half of the paned window.</para>
+
+<para>A paned widget can be changed visually using the following two
+functions.</para>
+
+<para><literallayout>
+<literal>void gtk_paned_set_handle_size( GtkPaned *paned,
+                                guint16   size);</para>
+
+<para>void gtk_paned_set_gutter_size( GtkPaned *paned,
+                                guint16   size);</literal>
+</literallayout></para>
+
+<para>The first of these sets the size of the handle and the second sets the
+size of the gutter that is between the two parts of the paned window.</para>
+
+<para>As an example, we will create part of the user interface of an
+imaginary email program. A window is divided into two portions
+vertically, with the top portion being a list of email messages and
+the bottom portion the text of the email message. Most of the program
+is pretty straightforward. A couple of points to note: text can't be
+added to a Text widget until it is realized. This could be done by
+calling <literal>gtk_widget_realize()</literal>, but as a demonstration of an
+alternate technique, we connect a handler to the "realize" signal to
+add the text. Also, we need to add the <literal>GTK_SHRINK</literal> option to some
+of the items in the table containing the text window and its
+scrollbars, so that when the bottom portion is made smaller, the
+correct portions shrink instead of being pushed off the bottom of the
+window.</para>
+
+<programlisting role="C">
+/* example-start paned paned.c */
+
+#include &lt;stdio.h&gt;
+#include &lt;gtk/gtk.h&gt;
+   
+/* Create the list of "messages" */
+GtkWidget *create_list( void )
+{
+
+    GtkWidget *scrolled_window;
+    GtkWidget *list;
+    GtkWidget *list_item;
+   
+    int i;
+    char buffer[16];
+   
+    /* Create a new scrolled window, with scrollbars only if needed */
+    scrolled_window = gtk_scrolled_window_new (NULL, NULL);
+    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
+                                   GTK_POLICY_AUTOMATIC, 
+                                   GTK_POLICY_AUTOMATIC);
+   
+    /* Create a new list and put it in the scrolled window */
+    list = gtk_list_new ();
+    gtk_scrolled_window_add_with_viewport (
+               GTK_SCROLLED_WINDOW (scrolled_window), list);
+    gtk_widget_show (list);
+   
+    /* Add some messages to the window */
+    for (i=0; i<10; i++) {
+
+       sprintf(buffer,"Message #%d",i);
+       list_item = gtk_list_item_new_with_label (buffer);
+       gtk_container_add (GTK_CONTAINER(list), list_item);
+       gtk_widget_show (list_item);
+
+    }
+   
+    return scrolled_window;
+}
+   
+/* Add some text to our text widget - this is a callback that is invoked
+when our window is realized. We could also force our window to be
+realized with gtk_widget_realize, but it would have to be part of
+a hierarchy first */
+
+void realize_text( GtkWidget *text,
+                   gpointer data )
+{
+    gtk_text_freeze (GTK_TEXT (text));
+    gtk_text_insert (GTK_TEXT (text), NULL, &amp;text->style->black, NULL,
+    "From: pathfinder@nasa.gov\n"
+    "To: mom@nasa.gov\n"
+    "Subject: Made it!\n"
+    "\n"
+    "We just got in this morning. The weather has been\n"
+    "great - clear but cold, and there are lots of fun sights.\n"
+    "Sojourner says hi. See you soon.\n"
+    " -Path\n", -1);
+   
+    gtk_text_thaw (GTK_TEXT (text));
+}
+   
+/* Create a scrolled text area that displays a "message" */
+GtkWidget *create_text( void )
+{
+    GtkWidget *table;
+    GtkWidget *text;
+    GtkWidget *hscrollbar;
+    GtkWidget *vscrollbar;
+   
+    /* Create a table to hold the text widget and scrollbars */
+    table = gtk_table_new (2, 2, FALSE);
+   
+    /* Put a text widget in the upper left hand corner. Note the use of
+     * GTK_SHRINK in the y direction */
+    text = gtk_text_new (NULL, NULL);
+    gtk_table_attach (GTK_TABLE (table), text, 0, 1, 0, 1,
+                     GTK_FILL | GTK_EXPAND,
+                     GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0);
+    gtk_widget_show (text);
+   
+    /* Put a HScrollbar in the lower left hand corner */
+    hscrollbar = gtk_hscrollbar_new (GTK_TEXT (text)->hadj);
+    gtk_table_attach (GTK_TABLE (table), hscrollbar, 0, 1, 1, 2,
+                     GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
+    gtk_widget_show (hscrollbar);
+   
+    /* And a VScrollbar in the upper right */
+    vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj);
+    gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1,
+                     GTK_FILL, GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0);
+    gtk_widget_show (vscrollbar);
+   
+    /* Add a handler to put a message in the text widget when it is realized */
+    gtk_signal_connect (GTK_OBJECT (text), "realize",
+                       GTK_SIGNAL_FUNC (realize_text), NULL);
+   
+    return table;
+}
+   
+int main( int   argc,
+          char *argv[] )
+{
+    GtkWidget *window;
+    GtkWidget *vpaned;
+    GtkWidget *list;
+    GtkWidget *text;
+
+    gtk_init (&amp;argc, &amp;argv);
+   
+    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+    gtk_window_set_title (GTK_WINDOW (window), "Paned Windows");
+    gtk_signal_connect (GTK_OBJECT (window), "destroy",
+                       GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
+    gtk_container_set_border_width (GTK_CONTAINER (window), 10);
+    gtk_widget_set_usize (GTK_WIDGET(window), 450, 400);
+
+    /* create a vpaned widget and add it to our toplevel window */
+   
+    vpaned = gtk_vpaned_new ();
+    gtk_container_add (GTK_CONTAINER(window), vpaned);
+    gtk_paned_set_handle_size (GTK_PANED(vpaned),
+                               10);
+    gtk_paned_set_gutter_size (GTK_PANED(vpaned),
+                               15);                       
+    gtk_widget_show (vpaned);
+   
+    /* Now create the contents of the two halves of the window */
+   
+    list = create_list ();
+    gtk_paned_add1 (GTK_PANED(vpaned), list);
+    gtk_widget_show (list);
+   
+    text = create_text ();
+    gtk_paned_add2 (GTK_PANED(vpaned), text);
+    gtk_widget_show (text);
+    gtk_widget_show (window);
+    gtk_main ();
+    return 0;
+}
+/* example-end */
+</programlisting>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>Viewports
+
+<para>It is unlikely that you will ever need to use the Viewport widget
+directly. You are much more likely to use the
+<link linkend="ch-ScrolledWindow">Scrolled Window</link> widget which
+itself uses the Viewport.</para>
+
+<para>A viewport widget allows you to place a larger widget within it such
+that you can view a part of it at a time. It uses
+<link linkend="ch-Adjustment">Adjustments</link> to define the area that
+is currently in view.</para>
+
+<para>A Viewport is created with the function</para>
+
+<para><literallayout>
+<literal>GtkWidget *gtk_viewport_new( GtkAdjustment *hadjustment,
+                             GtkAdjustment *vadjustment );</literal>
+</literallayout></para>
+
+<para>As you can see you can specify the horizontal and vertical Adjustments
+that the widget is to use when you create the widget. It will create
+its own if you pass NULL as the value of the arguments.</para>
+
+<para>You can get and set the adjustments after the widget has been created
+using the following four functions:</para>
+
+<para><literallayout>
+<literal>GtkAdjustment *gtk_viewport_get_hadjustment (GtkViewport *viewport );</para>
+
+<para>GtkAdjustment *gtk_viewport_get_vadjustment (GtkViewport *viewport );</para>
+
+<para>void gtk_viewport_set_hadjustment( GtkViewport   *viewport,
+                                   GtkAdjustment *adjustment );</para>
+
+<para>void gtk_viewport_set_vadjustment( GtkViewport   *viewport,
+                                   GtkAdjustment *adjustment );</literal>
+</literallayout></para>
+
+<para>The only other viewport function is used to alter its appearance:</para>
+
+<para><literallayout>
+<literal>void gtk_viewport_set_shadow_type( GtkViewport   *viewport,
+                                   GtkShadowType  type );</literal>
+</literallayout></para>
+
+<para>Possible values for the <literal>type</literal> parameter are:</para>
+<para><literallayout>
+<literal>  GTK_SHADOW_NONE,
+  GTK_SHADOW_IN,
+  GTK_SHADOW_OUT,
+  GTK_SHADOW_ETCHED_IN,
+  GTK_SHADOW_ETCHED_OUT
+</verb></tscreen>
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>Scrolled Windows
+
+<para>Scrolled windows are used to create a scrollable area with another
+widget inside it. You may insert any type of widget into a scrolled
+window, and it will be accessible regardless of the size by using the
+scrollbars.</para>
+
+<para>The following function is used to create a new scrolled window.</para>
+
+<para><literallayout>
+<literal>GtkWidget *gtk_scrolled_window_new( GtkAdjustment *hadjustment,
+                                    GtkAdjustment *vadjustment );</literal>
+</literallayout></para>
+
+<para>Where the first argument is the adjustment for the horizontal
+direction, and the second, the adjustment for the vertical direction.
+These are almost always set to NULL.</para>
+
+<para><literallayout>
+<literal>void gtk_scrolled_window_set_policy( GtkScrolledWindow *scrolled_window,
+                                     GtkPolicyType      hscrollbar_policy,
+                                     GtkPolicyType      vscrollbar_policy );</literal>
+</literallayout></para>
+
+<para>This sets the policy to be used with respect to the scrollbars.
+The first argument is the scrolled window you wish to change. The second
+sets the policy for the horizontal scrollbar, and the third the policy for 
+the vertical scrollbar.</para>
+
+<para>The policy may be one of <literal>GTK_POLICY_AUTOMATIC</literal> or
+<literal>GTK_POLICY_ALWAYS</literal>. <literal>GTK_POLICY_AUTOMATIC</literal> will automatically
+decide whether you need scrollbars, whereas <literal>GTK_POLICY_ALWAYS</literal>
+will always leave the scrollbars there.</para>
+
+<para>You can then place your object into the scrolled window using the
+following function.</para>
+
+<para><literallayout>
+<literal>void gtk_scrolled_window_add_with_viewport( GtkScrolledWindow *scrolled_window,
+                                            GtkWidget         *child);</literal>
+</literallayout></para>
+
+<para>Here is a simple example that packs a table eith 100 toggle buttons
+into a scrolled window. I've only commented on the parts that may be
+new to you.</para>
+
+<programlisting role="C">
+/* example-start scrolledwin scrolledwin.c */
+
+#include &lt;stdio.h&gt;
+#include &lt;gtk/gtk.h&gt;
+
+void destroy( GtkWidget *widget,
+              gpointer   data )
+{
+    gtk_main_quit();
+}
+
+int main( int   argc,
+          char *argv[] )
+{
+    static GtkWidget *window;
+    GtkWidget *scrolled_window;
+    GtkWidget *table;
+    GtkWidget *button;
+    char buffer[32];
+    int i, j;
+    
+    gtk_init (&amp;argc, &amp;argv);
+    
+    /* Create a new dialog window for the scrolled window to be
+     * packed into.  */
+    window = gtk_dialog_new ();
+    gtk_signal_connect (GTK_OBJECT (window), "destroy",
+                       (GtkSignalFunc) destroy, NULL);
+    gtk_window_set_title (GTK_WINDOW (window), "GtkScrolledWindow example");
+    gtk_container_set_border_width (GTK_CONTAINER (window), 0);
+    gtk_widget_set_usize(window, 300, 300);
+    
+    /* create a new scrolled window. */
+    scrolled_window = gtk_scrolled_window_new (NULL, NULL);
+    
+    gtk_container_set_border_width (GTK_CONTAINER (scrolled_window), 10);
+    
+    /* the policy is one of GTK_POLICY AUTOMATIC, or GTK_POLICY_ALWAYS.
+     * GTK_POLICY_AUTOMATIC will automatically decide whether you need
+     * scrollbars, whereas GTK_POLICY_ALWAYS will always leave the scrollbars
+     * there.  The first one is the horizontal scrollbar, the second, 
+     * the vertical. */
+    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
+                                    GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
+    /* The dialog window is created with a vbox packed into it. */                                                             
+    gtk_box_pack_start (GTK_BOX (GTK_DIALOG(window)->vbox), scrolled_window, 
+                       TRUE, TRUE, 0);
+    gtk_widget_show (scrolled_window);
+    
+    /* create a table of 10 by 10 squares. */
+    table = gtk_table_new (10, 10, FALSE);
+    
+    /* set the spacing to 10 on x and 10 on y */
+    gtk_table_set_row_spacings (GTK_TABLE (table), 10);
+    gtk_table_set_col_spacings (GTK_TABLE (table), 10);
+    
+    /* pack the table into the scrolled window */
+    gtk_scrolled_window_add_with_viewport (
+                   GTK_SCROLLED_WINDOW (scrolled_window), table);
+    gtk_widget_show (table);
+    
+    /* this simply creates a grid of toggle buttons on the table
+     * to demonstrate the scrolled window. */
+    for (i = 0; i < 10; i++)
+       for (j = 0; j < 10; j++) {
+          sprintf (buffer, "button (%d,%d)\n", i, j);
+         button = gtk_toggle_button_new_with_label (buffer);
+         gtk_table_attach_defaults (GTK_TABLE (table), button,
+                                    i, i+1, j, j+1);
+          gtk_widget_show (button);
+       }
+    
+    /* Add a "close" button to the bottom of the dialog */
+    button = gtk_button_new_with_label ("close");
+    gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+                              (GtkSignalFunc) gtk_widget_destroy,
+                              GTK_OBJECT (window));
+    
+    /* this makes it so the button is the default. */
+    
+    GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
+    gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), button, TRUE, TRUE, 0);
+    
+    /* This grabs this button to be the default button. Simply hitting
+     * the "Enter" key will cause this button to activate. */
+    gtk_widget_grab_default (button);
+    gtk_widget_show (button);
+    
+    gtk_widget_show (window);
+    
+    gtk_main();
+    
+    return(0);
+}
+/* example-end */
+</programlisting>
+
+<para>Try playing with resizing the window. You'll notice how the scrollbars
+react. You may also wish to use the gtk_widget_set_usize() call to set
+the default size of the window or other widgets.</para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->   
+<sect1>
+<title>Button Boxes</title>
+
+<para>Button Boxes are a convenient way to quickly layout a group of
+buttons. They come in both horizontal and vertical flavours. You
+create a new Button Box with one of the following calls, which create
+a horizontal or vertical box, respectively:</para>
+
+<para><literallayout>
+<literal>GtkWidget *gtk_hbutton_box_new( void );</para>
+
+<para>GtkWidget *gtk_vbutton_box_new( void );</literal>
+</literallayout></para>
+
+<para>The only attributes pertaining to button boxes effect how the buttons
+are laid out. You can change the spacing between the buttons with:</para>
+
+<para><literallayout>
+<literal>void gtk_hbutton_box_set_spacing_default( gint spacing );</para>
+
+<para>void gtk_vbutton_box_set_spacing_default( gint spacing );</literal>
+</literallayout></para>
+
+<para>Similarly, the current spacing values can be queried using:</para>
+
+<para><literallayout>
+<literal>gint gtk_hbutton_box_get_spacing_default( void );</para>
+
+<para>gint gtk_vbutton_box_get_spacing_default( void );</literal>
+</literallayout></para>
+
+<para>The second attribute that we can access effects the layout of the
+buttons within the box. It is set using one of:</para>
+
+<para><literallayout>
+<literal>void gtk_hbutton_box_set_layout_default( GtkButtonBoxStyle layout );</para>
+
+<para>void gtk_vbutton_box_set_layout_default( GtkButtonBoxStyle layout );</literal>
+</literallayout></para>
+
+<para>The <literal>layout</literal> argument can take one of the following values:</para>
+
+<para><literallayout>
+<literal>  GTK_BUTTONBOX_DEFAULT_STYLE
+  GTK_BUTTONBOX_SPREAD
+  GTK_BUTTONBOX_EDGE
+  GTK_BUTTONBOX_START
+  GTK_BUTTONBOX_END</literal>
+</literallayout></para>
+
+<para>The current layout setting can be retrieved using:</para>
+
+<para><literallayout>
+<literal>GtkButtonBoxStyle gtk_hbutton_box_get_layout_default( void );</para>
+
+<para>GtkButtonBoxStyle gtk_vbutton_box_get_layout_default( void );</literal>
+</literallayout></para>
+
+<para>Buttons are added to a Button Box using the usual function:</para>
+
+<para><literallayout>
+<literal>    gtk_container_add( GTK_CONTAINER(button_box), child_widget );</literal>
+</literallayout></para>
+
+<para>Here's an example that illustrates all the different layout settings
+for Button Boxes.</para>
+
+<programlisting role="C">
+/* example-start buttonbox buttonbox.c */
+
+#include &lt;gtk/gtk.h&gt;
+
+/* Create a Button Box with the specified parameters */
+GtkWidget *create_bbox( gint  horizontal,
+                        char *title,
+                        gint  spacing,
+                        gint  child_w,
+                        gint  child_h,
+                        gint  layout )
+{
+  GtkWidget *frame;
+  GtkWidget *bbox;
+  GtkWidget *button;
+
+  frame = gtk_frame_new (title);
+
+  if (horizontal)
+    bbox = gtk_hbutton_box_new ();
+  else
+    bbox = gtk_vbutton_box_new ();
+
+  gtk_container_set_border_width (GTK_CONTAINER (bbox), 5);
+  gtk_container_add (GTK_CONTAINER (frame), bbox);
+
+  /* Set the appearance of the Button Box */
+  gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), layout);
+  gtk_button_box_set_spacing (GTK_BUTTON_BOX (bbox), spacing);
+  gtk_button_box_set_child_size (GTK_BUTTON_BOX (bbox), child_w, child_h);
+
+  button = gtk_button_new_with_label ("OK");
+  gtk_container_add (GTK_CONTAINER (bbox), button);
+
+  button = gtk_button_new_with_label ("Cancel");
+  gtk_container_add (GTK_CONTAINER (bbox), button);
+
+  button = gtk_button_new_with_label ("Help");
+  gtk_container_add (GTK_CONTAINER (bbox), button);
+
+  return(frame);
+}
+
+int main( int   argc,
+          char *argv[] )
+{
+  static GtkWidget* window = NULL;
+  GtkWidget *main_vbox;
+  GtkWidget *vbox;
+  GtkWidget *hbox;
+  GtkWidget *frame_horz;
+  GtkWidget *frame_vert;
+
+  /* Initialize GTK */
+  gtk_init( &amp;argc, &amp;argv );
+
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_window_set_title (GTK_WINDOW (window), "Button Boxes");
+
+  gtk_signal_connect (GTK_OBJECT (window), "destroy",
+                     GTK_SIGNAL_FUNC(gtk_main_quit),
+                     NULL);
+
+  gtk_container_set_border_width (GTK_CONTAINER (window), 10);
+
+  main_vbox = gtk_vbox_new (FALSE, 0);
+  gtk_container_add (GTK_CONTAINER (window), main_vbox);
+
+  frame_horz = gtk_frame_new ("Horizontal Button Boxes");
+  gtk_box_pack_start (GTK_BOX (main_vbox), frame_horz, TRUE, TRUE, 10);
+
+  vbox = gtk_vbox_new (FALSE, 0);
+  gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
+  gtk_container_add (GTK_CONTAINER (frame_horz), vbox);
+
+  gtk_box_pack_start (GTK_BOX (vbox),
+          create_bbox (TRUE, "Spread (spacing 40)", 40, 85, 20, GTK_BUTTONBOX_SPREAD),
+                     TRUE, TRUE, 0);
+
+  gtk_box_pack_start (GTK_BOX (vbox),
+          create_bbox (TRUE, "Edge (spacing 30)", 30, 85, 20, GTK_BUTTONBOX_EDGE),
+                     TRUE, TRUE, 5);
+
+  gtk_box_pack_start (GTK_BOX (vbox),
+           create_bbox (TRUE, "Start (spacing 20)", 20, 85, 20, GTK_BUTTONBOX_START),
+                     TRUE, TRUE, 5);
+
+  gtk_box_pack_start (GTK_BOX (vbox),
+          create_bbox (TRUE, "End (spacing 10)", 10, 85, 20, GTK_BUTTONBOX_END),
+                     TRUE, TRUE, 5);
+
+  frame_vert = gtk_frame_new ("Vertical Button Boxes");
+  gtk_box_pack_start (GTK_BOX (main_vbox), frame_vert, TRUE, TRUE, 10);
+
+  hbox = gtk_hbox_new (FALSE, 0);
+  gtk_container_set_border_width (GTK_CONTAINER (hbox), 10);
+  gtk_container_add (GTK_CONTAINER (frame_vert), hbox);
+
+  gtk_box_pack_start (GTK_BOX (hbox),
+           create_bbox (FALSE, "Spread (spacing 5)", 5, 85, 20, GTK_BUTTONBOX_SPREAD),
+                     TRUE, TRUE, 0);
+
+  gtk_box_pack_start (GTK_BOX (hbox),
+           create_bbox (FALSE, "Edge (spacing 30)", 30, 85, 20, GTK_BUTTONBOX_EDGE),
+                     TRUE, TRUE, 5);
+
+  gtk_box_pack_start (GTK_BOX (hbox),
+           create_bbox (FALSE, "Start (spacing 20)", 20, 85, 20, GTK_BUTTONBOX_START),
+                     TRUE, TRUE, 5);
+
+  gtk_box_pack_start (GTK_BOX (hbox),
+           create_bbox (FALSE, "End (spacing 20)", 20, 85, 20, GTK_BUTTONBOX_END),
+                     TRUE, TRUE, 5);
+
+  gtk_widget_show_all (window);
+
+  /* Enter the event loop */
+  gtk_main ();
+    
+  return(0);
+}
+/* example-end */
+</programlisting>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->   
+<sect1>
+<title>Toolbar</title>
+
+<para>Toolbars are usually used to group some number of widgets in order to
+simplify customization of their look and layout. Typically a toolbar
+consists of buttons with icons, labels and tooltips, but any other
+widget can also be put inside a toolbar. Finally, items can be
+arranged horizontally or vertically and buttons can be displayed with
+icons, labels, or both.</para>
+
+<para>Creating a toolbar is (as one may already suspect) done with the
+following function:</para>
+
+<para><literallayout>
+<literal>GtkWidget *gtk_toolbar_new( GtkOrientation orientation,
+                            GtkToolbarStyle  style );</literal>
+</literallayout></para>
+
+<para>where orientation may be one of:</para>
+
+<para><literallayout>
+<literal>  GTK_ORIENTATION_HORIZONTAL    
+  GTK_ORIENTATION_VERTICAL</literal>
+</literallayout></para>
+
+<para>and style one of:</para>
+
+<para><literallayout>
+<literal>  GTK_TOOLBAR_TEXT
+  GTK_TOOLBAR_ICONS
+  GTK_TOOLBAR_BOTH</literal>
+</literallayout></para>
+
+<para>The style applies to all the buttons created with the `item' functions
+(not to buttons inserted into toolbar as separate widgets).</para>
+
+<para>After creating a toolbar one can append, prepend and insert items
+(that means simple text strings) or elements (that means any widget
+types) into the toolbar. To describe an item we need a label text, a
+tooltip text, a private tooltip text, an icon for the button and a
+callback function for it. For example, to append or prepend an item
+you may use the following functions:</para>
+
+<para><literallayout>
+<literal>GtkWidget *gtk_toolbar_append_item( GtkToolbar    *toolbar,
+                                    const char    *text,
+                                    const char    *tooltip_text,
+                                    const char    *tooltip_private_text,
+                                    GtkWidget     *icon,
+                                    GtkSignalFunc  callback,
+                                    gpointer       user_data );</para>
+
+<para>GtkWidget *gtk_toolbar_prepend_item( GtkToolbar    *toolbar,
+                                     const char    *text,
+                                     const char    *tooltip_text,
+                                     const char    *tooltip_private_text,
+                                     GtkWidget     *icon,
+                                     GtkSignalFunc  callback,
+                                     gpointer       user_data );</literal>
+</literallayout></para>
+
+<para>If you want to use gtk_toolbar_insert_item, the only additional
+parameter which must be specified is the position in which the item
+should be inserted, thus:</para>
+
+<para><literallayout>
+<literal>GtkWidget *gtk_toolbar_insert_item( GtkToolbar    *toolbar,
+                                    const char    *text,
+                                    const char    *tooltip_text,
+                                    const char    *tooltip_private_text,
+                                    GtkWidget     *icon,
+                                    GtkSignalFunc  callback,
+                                    gpointer       user_data,
+                                    gint           position );</literal>
+</literallayout></para>
+
+<para>To simplify adding spaces between toolbar items, you may use the
+following functions:</para>
+
+<para><literallayout>
+<literal>void gtk_toolbar_append_space( GtkToolbar *toolbar );</para>
+
+<para>void gtk_toolbar_prepend_space( GtkToolbar *toolbar );</para>
+
+<para>void gtk_toolbar_insert_space( GtkToolbar *toolbar,
+                               gint        position );
+ </literal>
+</literallayout></para>
+
+<para>While the size of the added space can be set globally for a
+whole toolbar with the function:</para>
+
+<para><literallayout>
+<literal>void gtk_toolbar_set_space_size( GtkToolbar *toolbar,
+                                 gint        space_size) ;</literal>
+</literallayout></para>
+
+<para>If it's required, the orientation of a toolbar and its style can be
+changed "on the fly" using the following functions:</para>
+
+<para><literallayout>
+<literal>void gtk_toolbar_set_orientation( GtkToolbar     *toolbar,
+                                  GtkOrientation  orientation );</para>
+
+<para>void gtk_toolbar_set_style( GtkToolbar      *toolbar,
+                            GtkToolbarStyle  style );</para>
+
+<para>void gtk_toolbar_set_tooltips( GtkToolbar *toolbar,
+                               gint        enable );</literal>
+</literallayout></para>
+
+<para>Where <literal>orientation</literal> is one of <literal>GTK_ORIENTATION_HORIZONTAL</literal> or
+<literal>GTK_ORIENTATION_VERTICAL</literal>. The <literal>style</literal> is used to set
+appearance of the toolbar items by using one of
+<literal>GTK_TOOLBAR_ICONS</literal>, <literal>GTK_TOOLBAR_TEXT</literal>, or
+<literal>GTK_TOOLBAR_BOTH</literal>.</para>
+
+<para>To show some other things that can be done with a toolbar, let's take
+the following program (we'll interrupt the listing with some
+additional explanations):</para>
+
+<para><literallayout>
+<literal>#include &lt;gtk/gtk.h&gt;</para>
+
+<para>#include "gtk.xpm"</para>
+
+<para>/* This function is connected to the Close button or
+ * closing the window from the WM */
+gint delete_event (GtkWidget *widget, GdkEvent *event, gpointer data)
+{
+  gtk_main_quit ();
+  return(FALSE);
+}</literal>
+</literallayout></para>
+
+<para>The above beginning seems for sure familiar to you if it's not your first
+GTK program. There is one additional thing though, we include a nice XPM
+picture to serve as an icon for all of the buttons.</para>
+
+<para><literallayout>
+<literal>GtkWidget* close_button; /* This button will emit signal to close
+                          * application */
+GtkWidget* tooltips_button; /* to enable/disable tooltips */
+GtkWidget* text_button,
+         * icon_button,
+         * both_button; /* radio buttons for toolbar style */
+GtkWidget* entry; /* a text entry to show packing any widget into
+                   * toolbar */
+</programlisting>
+
+<para>In fact not all of the above widgets are needed here, but to make things
+clearer I put them all together.</para>
+
+<programlisting role="C">
+/* that's easy... when one of the buttons is toggled, we just
+ * check which one is active and set the style of the toolbar
+ * accordingly
+ * ATTENTION: our toolbar is passed as data to callback ! */
+void radio_event (GtkWidget *widget, gpointer data)
+{
+  if (GTK_TOGGLE_BUTTON (text_button)->active) 
+    gtk_toolbar_set_style(GTK_TOOLBAR ( data ), GTK_TOOLBAR_TEXT);
+  else if (GTK_TOGGLE_BUTTON (icon_button)->active)
+    gtk_toolbar_set_style(GTK_TOOLBAR ( data ), GTK_TOOLBAR_ICONS);
+  else if (GTK_TOGGLE_BUTTON (both_button)->active)
+    gtk_toolbar_set_style(GTK_TOOLBAR ( data ), GTK_TOOLBAR_BOTH);
+}</para>
+
+<para>/* even easier, just check given toggle button and enable/disable 
+ * tooltips */
+void toggle_event (GtkWidget *widget, gpointer data)
+{
+  gtk_toolbar_set_tooltips (GTK_TOOLBAR ( data ),
+                            GTK_TOGGLE_BUTTON (widget)->active );
+}</literal>
+</literallayout></para>
+
+<para>The above are just two callback functions that will be called when
+one of the buttons on a toolbar is pressed. You should already be
+familiar with things like this if you've already used toggle buttons (and
+radio buttons).</para>
+
+<para><literallayout>
+<literal>int main (int argc, char *argv[])
+{
+  /* Here is our main window (a dialog) and a handle for the handlebox */
+  GtkWidget* dialog;
+  GtkWidget* handlebox;</para>
+
+<para>  /* Ok, we need a toolbar, an icon with a mask (one for all of 
+     the buttons) and an icon widget to put this icon in (but 
+     we'll create a separate widget for each button) */
+  GtkWidget * toolbar;
+  GdkPixmap * icon;
+  GdkBitmap * mask;
+  GtkWidget * iconw;</para>
+
+<para>  /* this is called in all GTK application. */
+  gtk_init (&amp;argc, &amp;argv);
+  
+  /* create a new window with a given title, and nice size */
+  dialog = gtk_dialog_new ();
+  gtk_window_set_title ( GTK_WINDOW ( dialog ) , "GTKToolbar Tutorial");
+  gtk_widget_set_usize( GTK_WIDGET ( dialog ) , 600 , 300 );
+  GTK_WINDOW ( dialog ) ->allow_shrink = TRUE;</para>
+
+<para>  /* typically we quit if someone tries to close us */
+  gtk_signal_connect ( GTK_OBJECT ( dialog ), "delete_event",
+                       GTK_SIGNAL_FUNC ( delete_event ), NULL);</para>
+
+<para>  /* we need to realize the window because we use pixmaps for 
+   * items on the toolbar in the context of it */
+  gtk_widget_realize ( dialog );</para>
+
+<para>  /* to make it nice we'll put the toolbar into the handle box, 
+   * so that it can be detached from the main window */
+  handlebox = gtk_handle_box_new ();
+  gtk_box_pack_start ( GTK_BOX ( GTK_DIALOG(dialog)->vbox ),
+                       handlebox, FALSE, FALSE, 5 );</literal>
+</literallayout></para>
+
+<para>The above should be similar to any other GTK application. Just
+initialization of GTK, creating the window, etc. There is only one
+thing that probably needs some explanation: a handle box. A handle box
+is just another box that can be used to pack widgets in to. The
+difference between it and typical boxes is that it can be detached
+from a parent window (or, in fact, the handle box remains in the
+parent, but it is reduced to a very small rectangle, while all of its
+contents are reparented to a new freely floating window). It is
+usually nice to have a detachable toolbar, so these two widgets occur
+together quite often.</para>
+
+<para><literallayout>
+<literal>  /* toolbar will be horizontal, with both icons and text, and
+   * with 5pxl spaces between items and finally, 
+   * we'll also put it into our handlebox */
+  toolbar = gtk_toolbar_new ( GTK_ORIENTATION_HORIZONTAL,
+                              GTK_TOOLBAR_BOTH );
+  gtk_container_set_border_width ( GTK_CONTAINER ( toolbar ) , 5 );
+  gtk_toolbar_set_space_size ( GTK_TOOLBAR ( toolbar ), 5 );
+  gtk_container_add ( GTK_CONTAINER ( handlebox ) , toolbar );</para>
+
+<para>  /* now we create icon with mask: we'll reuse it to create
+   * icon widgets for toolbar items */
+  icon = gdk_pixmap_create_from_xpm_d ( dialog->window, &amp;mask,
+      &amp;dialog->style->white, gtk_xpm );</literal>
+</literallayout></para>
+
+<para>Well, what we do above is just a straightforward initialization of
+the toolbar widget and creation of a GDK pixmap with its mask. If you
+want to know something more about using pixmaps, refer to GDK
+documentation or to the <link linkend="ch-Pixmaps">Pixmaps</link> section
+earlier in this tutorial.</para>
+
+<para><literallayout>
+<literal>  /* our first item is <close> button */
+  iconw = gtk_pixmap_new ( icon, mask ); /* icon widget */
+  close_button = 
+    gtk_toolbar_append_item ( GTK_TOOLBAR (toolbar), /* our toolbar */
+                              "Close",               /* button label */
+                              "Closes this app",     /* this button's tooltip */
+                              "Private",             /* tooltip private info */
+                              iconw,                 /* icon widget */
+                              GTK_SIGNAL_FUNC (delete_event), /* a signal */
+                               NULL );
+  gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) ); /* space after item */
+</programlisting>
+
+<para>In the above code you see the simplest case: adding a button to
+toolbar.  Just before appending a new item, we have to construct a
+pixmap widget to serve as an icon for this item; this step will have
+to be repeated for each new item. Just after the item we also add a
+space, so the following items will not touch each other. As you see
+gtk_toolbar_append_item returns a pointer to our newly created button
+widget, so that we can work with it in the normal way.</para>
+
+<para><literallayout>
+<literal>  /* now, let's make our radio buttons group... */
+  iconw = gtk_pixmap_new ( icon, mask );
+  icon_button = gtk_toolbar_append_element(
+                    GTK_TOOLBAR(toolbar),
+                    GTK_TOOLBAR_CHILD_RADIOBUTTON, /* a type of element */
+                    NULL,                          /* pointer to widget */
+                    "Icon",                        /* label */
+                    "Only icons in toolbar",       /* tooltip */
+                    "Private",                     /* tooltip private string */
+                    iconw,                         /* icon */
+                    GTK_SIGNAL_FUNC (radio_event), /* signal */
+                    toolbar);                      /* data for signal */
+  gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) );</literal>
+</literallayout></para>
+
+<para>Here we begin creating a radio buttons group. To do this we use
+gtk_toolbar_append_element.  In fact, using this function one can also
++add simple items or even spaces (type = <literal>GTK_TOOLBAR_CHILD_SPACE</literal>
+or +<literal>GTK_TOOLBAR_CHILD_BUTTON</literal>). In the above case we start
+creating a radio group. In creating other radio buttons for this group
+a pointer to the previous button in the group is required, so that a
+list of buttons can be easily constructed (see the section on <ref
+id="ch-Radio_Buttons"> Radio Buttons </ulink> earlier in this
+tutorial).</para>
+
+<para><literallayout>
+<literal>  /* following radio buttons refer to previous ones */
+  iconw = gtk_pixmap_new ( icon, mask );
+  text_button = 
+    gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
+                               GTK_TOOLBAR_CHILD_RADIOBUTTON,
+                               icon_button,
+                               "Text",
+                               "Only texts in toolbar",
+                               "Private",
+                               iconw,
+                               GTK_SIGNAL_FUNC (radio_event),
+                               toolbar);
+  gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) );
+                                          
+  iconw = gtk_pixmap_new ( icon, mask );
+  both_button = 
+    gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
+                               GTK_TOOLBAR_CHILD_RADIOBUTTON,
+                               text_button,
+                               "Both",
+                               "Icons and text in toolbar",
+                               "Private",
+                               iconw,
+                               GTK_SIGNAL_FUNC (radio_event),
+                               toolbar);
+  gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) );
+  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(both_button),TRUE);</literal>
+</literallayout></para>
+
+<para>In the end we have to set the state of one of the buttons manually
+(otherwise they all stay in active state, preventing us from switching
+between them).</para>
+
+<para><literallayout>
+<literal>  /* here we have just a simple toggle button */
+  iconw = gtk_pixmap_new ( icon, mask );
+  tooltips_button = 
+    gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
+                               GTK_TOOLBAR_CHILD_TOGGLEBUTTON,
+                               NULL,
+                               "Tooltips",
+                               "Toolbar with or without tips",
+                               "Private",
+                               iconw,
+                               GTK_SIGNAL_FUNC (toggle_event),
+                               toolbar);
+  gtk_toolbar_append_space ( GTK_TOOLBAR ( toolbar ) );
+  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tooltips_button),TRUE);</literal>
+</literallayout></para>
+
+<para>A toggle button can be created in the obvious way (if one knows how to create
+radio buttons already).</para>
+
+<para><literallayout>
+<literal>  /* to pack a widget into toolbar, we only have to 
+   * create it and append it with an appropriate tooltip */
+  entry = gtk_entry_new ();
+  gtk_toolbar_append_widget( GTK_TOOLBAR (toolbar), 
+                             entry, 
+                             "This is just an entry", 
+                             "Private" );</para>
+
+<para>  /* well, it isn't created within thetoolbar, so we must still show it */
+  gtk_widget_show ( entry );</literal>
+</literallayout></para>
+
+<para>As you see, adding any kind of widget to a toolbar is simple. The
+one thing you have to remember is that this widget must be shown manually
+(contrary to other items which will be shown together with the toolbar).</para>
+
+<para><literallayout>
+<literal>  /* that's it ! let's show everything. */
+  gtk_widget_show ( toolbar );
+  gtk_widget_show (handlebox);
+  gtk_widget_show ( dialog );</para>
+
+<para>  /* rest in gtk_main and wait for the fun to begin! */
+  gtk_main ();
+  
+  return 0;
+}</literal>
+</literallayout></para>
+
+<para>So, here we are at the end of toolbar tutorial. Of course, to appreciate
+it in full you need also this nice XPM icon, so here it is:</para>
+
+<programlisting role="C">
+/* XPM */
+static char * gtk_xpm[] = {
+"32 39 5 1",
+".      c none",
+"+      c black",
+"@      c #3070E0",
+"#      c #F05050",
+"$      c #35E035",
+"................+...............",
+"..............+++++.............",
+"............+++++@@++...........",
+"..........+++++@@@@@@++.........",
+"........++++@@@@@@@@@@++........",
+"......++++@@++++++++@@@++.......",
+".....+++@@@+++++++++++@@@++.....",
+"...+++@@@@+++@@@@@@++++@@@@+....",
+"..+++@@@@+++@@@@@@@@+++@@@@@++..",
+".++@@@@@@+++@@@@@@@@@@@@@@@@@@++",
+".+#+@@@@@@++@@@@+++@@@@@@@@@@@@+",
+".+##++@@@@+++@@@+++++@@@@@@@@$@.",
+".+###++@@@@+++@@@+++@@@@@++$$$@.",
+".+####+++@@@+++++++@@@@@+@$$$$@.",
+".+#####+++@@@@+++@@@@++@$$$$$$+.",
+".+######++++@@@@@@@++@$$$$$$$$+.",
+".+#######+##+@@@@+++$$$$$$@@$$+.",
+".+###+++##+##+@@++@$$$$$$++$$$+.",
+".+###++++##+##+@@$$$$$$$@+@$$@+.",
+".+###++++++#+++@$$@+@$$@++$$$@+.",
+".+####+++++++#++$$@+@$$++$$$$+..",
+".++####++++++#++$$@+@$++@$$$$+..",
+".+#####+++++##++$$++@+++$$$$$+..",
+".++####+++##+#++$$+++++@$$$$$+..",
+".++####+++####++$$++++++@$$$@+..",
+".+#####++#####++$$+++@++++@$@+..",
+".+#####++#####++$$++@$$@+++$@@..",
+".++####++#####++$$++$$$$$+@$@++.",
+".++####++#####++$$++$$$$$$$$+++.",
+".+++####+#####++$$++$$$$$$$@+++.",
+"..+++#########+@$$+@$$$$$$+++...",
+"...+++########+@$$$$$$$$@+++....",
+".....+++######+@$$$$$$$+++......",
+"......+++#####+@$$$$$@++........",
+".......+++####+@$$$$+++.........",
+".........++###+$$$@++...........",
+"..........++##+$@+++............",
+"...........+++++++..............",
+".............++++..............."};</literal>
+</literallayout></para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> Notebooks</title>
+
+<para>The NoteBook Widget is a collection of "pages" that overlap each
+other, each page contains different information with only one page
+visible at a time. This widget has become more common lately in GUI
+programming, and it is a good way to show blocks of similar
+information that warrant separation in their display.</para>
+
+<para>The first function call you will need to know, as you can probably
+guess by now, is used to create a new notebook widget.</para>
+
+<para><literallayout>
+<literal>GtkWidget *gtk_notebook_new( void );</literal>
+</literallayout></para>
+
+<para>Once the notebook has been created, there are a number of functions
+that operate on the notebook widget. Let's look at them individually.</para>
+
+<para>The first one we will look at is how to position the page indicators.
+These page indicators or "tabs" as they are referred to, can be
+positioned in four ways: top, bottom, left, or right.</para>
+
+<para><literallayout>
+<literal>void gtk_notebook_set_tab_pos( GtkNotebook     *notebook,
+                               GtkPositionType  pos );</literal>
+</literallayout></para>
+
+<para>GtkPositionType will be one of the following, which are pretty self
+explanatory:</para>
+<para><literallayout>
+<literal>  GTK_POS_LEFT
+  GTK_POS_RIGHT
+  GTK_POS_TOP
+  GTK_POS_BOTTOM</literal>
+</literallayout></para>
+
+<para><literal>GTK_POS_TOP</literal> is the default.</para>
+
+<para>Next we will look at how to add pages to the notebook. There are three
+ways to add pages to the NoteBook. Let's look at the first two
+together as they are quite similar.</para>
+
+<para><literallayout>
+<literal>void gtk_notebook_append_page( GtkNotebook *notebook,
+                               GtkWidget   *child,
+                               GtkWidget   *tab_label );</para>
+
+<para>void gtk_notebook_prepend_page( GtkNotebook *notebook,
+                                GtkWidget   *child,
+                                GtkWidget   *tab_label );</literal>
+</literallayout></para>
+
+<para>These functions add pages to the notebook by inserting them from the
+back of the notebook (append), or the front of the notebook (prepend).
+<literal>child</literal> is the widget that is placed within the notebook page, and
+<literal>tab_label</literal> is the label for the page being added. The <literal>child</literal>
+widget must be created separately, and is typically a set of options
+setup witin one of the other container widgets, such as a table.</para>
+
+<para>The final function for adding a page to the notebook contains all of
+the properties of the previous two, but it allows you to specify what
+position you want the page to be in the notebook.</para>
+
+<para><literallayout>
+<literal>void gtk_notebook_insert_page( GtkNotebook *notebook,
+                               GtkWidget   *child,
+                               GtkWidget   *tab_label,
+                               gint         position );</literal>
+</literallayout></para>
+
+<para>The parameters are the same as _append_ and _prepend_ except it
+contains an extra parameter, <literal>position</literal>.  This parameter is used to
+specify what place this page will be inserted into the first page
+having position zero.</para>
+
+<para>Now that we know how to add a page, lets see how we can remove a page
+from the notebook.</para>
+
+<para><literallayout>
+<literal>void gtk_notebook_remove_page( GtkNotebook *notebook,
+                               gint         page_num );</literal>
+</literallayout></para>
+
+<para>This function takes the page specified by <literal>page_num</literal> and removes it
+from the widget pointed to by <literal>notebook</literal>.</para>
+
+<para>To find out what the current page is in a notebook use the function:</para>
+
+<para><literallayout>
+<literal>gint gtk_notebook_get_current_page( GtkNotebook *notebook );</literal>
+</literallayout></para>
+
+<para>These next two functions are simple calls to move the notebook page
+forward or backward. Simply provide the respective function call with
+the notebook widget you wish to operate on. Note: When the NoteBook is
+currently on the last page, and gtk_notebook_next_page is called, the
+notebook will wrap back to the first page. Likewise, if the NoteBook
+is on the first page, and gtk_notebook_prev_page is called, the
+notebook will wrap to the last page.</para>
+
+<para><literallayout>
+<literal>void gtk_notebook_next_page( GtkNoteBook *notebook );</para>
+
+<para>void gtk_notebook_prev_page( GtkNoteBook *notebook );</literal>
+</literallayout></para>
+
+<para>This next function sets the "active" page. If you wish the notebook to
+be opened to page 5 for example, you would use this function.  Without
+using this function, the notebook defaults to the first page.</para>
+
+<para><literallayout>
+<literal>void gtk_notebook_set_page( GtkNotebook *notebook,
+                            gint         page_num );</literal>
+</literallayout></para>
+
+<para>The next two functions add or remove the notebook page tabs and the
+notebook border respectively.</para>
+
+<para><literallayout>
+<literal>void gtk_notebook_set_show_tabs( GtkNotebook *notebook,
+                                 gboolean     show_tabs);</para>
+
+<para>void gtk_notebook_set_show_border( GtkNotebook *notebook,
+                                   gboolean     show_border );</literal>
+</literallayout></para>
+
+<para>The next function is useful when the you have a large number of pages,
+and the tabs don't fit on the page. It allows the tabs to be scrolled
+through using two arrow buttons.</para>
+
+<para><literallayout>
+<literal>void gtk_notebook_set_scrollable( GtkNotebook *notebook,
+                                  gboolean     scrollable );</literal>
+</literallayout></para>
+
+<para><literal>show_tabs</literal>, <literal>show_border</literal> and <literal>scrollable</literal> can be either
+TRUE or FALSE.</para>
+
+<para>Now let's look at an example, it is expanded from the testgtk.c code
+that comes with the GTK distribution. This small program creates a
+window with a notebook and six buttons. The notebook contains 11
+pages, added in three different ways, appended, inserted, and
+prepended. The buttons allow you rotate the tab positions, add/remove
+the tabs and border, remove a page, change pages in both a forward and
+backward manner, and exit the program.</para>
+
+<programlisting role="C">
+/* example-start notebook notebook.c */
+
+#include &lt;stdio.h&gt;
+#include &lt;gtk/gtk.h&gt;
+
+/* This function rotates the position of the tabs */
+void rotate_book( GtkButton   *button,
+                  GtkNotebook *notebook )
+{
+    gtk_notebook_set_tab_pos (notebook, (notebook->tab_pos +1) %4);
+}
+
+/* Add/Remove the page tabs and the borders */
+void tabsborder_book( GtkButton   *button,
+                      GtkNotebook *notebook )
+{
+    gint tval = FALSE;
+    gint bval = FALSE;
+    if (notebook->show_tabs == 0)
+           tval = TRUE; 
+    if (notebook->show_border == 0)
+           bval = TRUE;
+    
+    gtk_notebook_set_show_tabs (notebook, tval);
+    gtk_notebook_set_show_border (notebook, bval);
+}
+
+/* Remove a page from the notebook */
+void remove_book( GtkButton   *button,
+                  GtkNotebook *notebook )
+{
+    gint page;
+    
+    page = gtk_notebook_get_current_page(notebook);
+    gtk_notebook_remove_page (notebook, page);
+    /* Need to refresh the widget -- 
+     This forces the widget to redraw itself. */
+    gtk_widget_draw(GTK_WIDGET(notebook), NULL);
+}
+
+gint delete( GtkWidget *widget,
+             GtkWidget *event,
+             gpointer   data )
+{
+    gtk_main_quit();
+    return(FALSE);
+}
+
+int main( int argc,
+          char *argv[] )
+{
+    GtkWidget *window;
+    GtkWidget *button;
+    GtkWidget *table;
+    GtkWidget *notebook;
+    GtkWidget *frame;
+    GtkWidget *label;
+    GtkWidget *checkbutton;
+    int i;
+    char bufferf[32];
+    char bufferl[32];
+    
+    gtk_init (&amp;argc, &amp;argv);
+    
+    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+    
+    gtk_signal_connect (GTK_OBJECT (window), "delete_event",
+                       GTK_SIGNAL_FUNC (delete), NULL);
+    
+    gtk_container_set_border_width (GTK_CONTAINER (window), 10);
+
+    table = gtk_table_new(3,6,FALSE);
+    gtk_container_add (GTK_CONTAINER (window), table);
+    
+    /* Create a new notebook, place the position of the tabs */
+    notebook = gtk_notebook_new ();
+    gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP);
+    gtk_table_attach_defaults(GTK_TABLE(table), notebook, 0,6,0,1);
+    gtk_widget_show(notebook);
+    
+    /* Let's append a bunch of pages to the notebook */
+    for (i=0; i < 5; i++) {
+       sprintf(bufferf, "Append Frame %d", i+1);
+       sprintf(bufferl, "Page %d", i+1);
+       
+       frame = gtk_frame_new (bufferf);
+       gtk_container_set_border_width (GTK_CONTAINER (frame), 10);
+       gtk_widget_set_usize (frame, 100, 75);
+       gtk_widget_show (frame);
+       
+       label = gtk_label_new (bufferf);
+       gtk_container_add (GTK_CONTAINER (frame), label);
+       gtk_widget_show (label);
+       
+       label = gtk_label_new (bufferl);
+       gtk_notebook_append_page (GTK_NOTEBOOK (notebook), frame, label);
+    }
+      
+    /* Now let's add a page to a specific spot */
+    checkbutton = gtk_check_button_new_with_label ("Check me please!");
+    gtk_widget_set_usize(checkbutton, 100, 75);
+    gtk_widget_show (checkbutton);
+   
+    label = gtk_label_new ("Add page");
+    gtk_notebook_insert_page (GTK_NOTEBOOK (notebook), checkbutton, label, 2);
+    
+    /* Now finally let's prepend pages to the notebook */
+    for (i=0; i < 5; i++) {
+       sprintf(bufferf, "Prepend Frame %d", i+1);
+       sprintf(bufferl, "PPage %d", i+1);
+       
+       frame = gtk_frame_new (bufferf);
+       gtk_container_set_border_width (GTK_CONTAINER (frame), 10);
+       gtk_widget_set_usize (frame, 100, 75);
+       gtk_widget_show (frame);
+       
+       label = gtk_label_new (bufferf);
+       gtk_container_add (GTK_CONTAINER (frame), label);
+       gtk_widget_show (label);
+       
+       label = gtk_label_new (bufferl);
+       gtk_notebook_prepend_page (GTK_NOTEBOOK(notebook), frame, label);
+    }
+    
+    /* Set what page to start at (page 4) */
+    gtk_notebook_set_page (GTK_NOTEBOOK(notebook), 3);
+
+    /* Create a bunch of buttons */
+    button = gtk_button_new_with_label ("close");
+    gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+                              GTK_SIGNAL_FUNC (delete), NULL);
+    gtk_table_attach_defaults(GTK_TABLE(table), button, 0,1,1,2);
+    gtk_widget_show(button);
+    
+    button = gtk_button_new_with_label ("next page");
+    gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+                              (GtkSignalFunc) gtk_notebook_next_page,
+                              GTK_OBJECT (notebook));
+    gtk_table_attach_defaults(GTK_TABLE(table), button, 1,2,1,2);
+    gtk_widget_show(button);
+    
+    button = gtk_button_new_with_label ("prev page");
+    gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+                              (GtkSignalFunc) gtk_notebook_prev_page,
+                              GTK_OBJECT (notebook));
+    gtk_table_attach_defaults(GTK_TABLE(table), button, 2,3,1,2);
+    gtk_widget_show(button);
+    
+    button = gtk_button_new_with_label ("tab position");
+    gtk_signal_connect (GTK_OBJECT (button), "clicked",
+                        (GtkSignalFunc) rotate_book,
+                       GTK_OBJECT(notebook));
+    gtk_table_attach_defaults(GTK_TABLE(table), button, 3,4,1,2);
+    gtk_widget_show(button);
+    
+    button = gtk_button_new_with_label ("tabs/border on/off");
+    gtk_signal_connect (GTK_OBJECT (button), "clicked",
+                        (GtkSignalFunc) tabsborder_book,
+                        GTK_OBJECT (notebook));
+    gtk_table_attach_defaults(GTK_TABLE(table), button, 4,5,1,2);
+    gtk_widget_show(button);
+    
+    button = gtk_button_new_with_label ("remove page");
+    gtk_signal_connect (GTK_OBJECT (button), "clicked",
+                        (GtkSignalFunc) remove_book,
+                        GTK_OBJECT(notebook));
+    gtk_table_attach_defaults(GTK_TABLE(table), button, 5,6,1,2);
+    gtk_widget_show(button);
+    
+    gtk_widget_show(table);
+    gtk_widget_show(window);
+    
+    gtk_main ();
+    
+    return(0);
+}
+/* example-end */
+</programlisting>
+
+<para>I hope this helps you on your way with creating notebooks for your
+GTK applications.</para>
+
+</sect1>
+</chapter>
+
+<!-- ***************************************************************** -->
+<chapter id="ch-CListWidget">
+<title>CList Widget</title>
+
+<!-- ----------------------------------------------------------------- -->
+
+<para>The CList widget has replaced the List widget (which is still
+available).</para>
+
+<para>The CList widget is a multi-column list widget that is capable of
+handling literally thousands of rows of information. Each column can
+optionally have a title, which itself is optionally active, allowing
+us to bind a function to its selection.</para>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Creating a CList widget</title>
+
+<para>Creating a CList is quite straightforward, once you have learned
+about widgets in general. It provides the almost standard two ways,
+that is the hard way, and the easy way. But before we create it, there
+is one thing we should figure out beforehand: how many columns should
+it have?</para>
+
+<para>Not all columns have to be visible and can be used to store data that
+is related to a certain cell in the list.</para>
+
+<para><literallayout>
+<literal>GtkWidget *gtk_clist_new ( gint columns );</para>
+
+<para>GtkWidget *gtk_clist_new_with_titles( gint   columns,
+                                      gchar *titles[] );</literal>
+</literallayout></para>
+
+<para>The first form is very straightforward, the second might require some
+explanation. Each column can have a title associated with it, and this
+title can be a label or a button that reacts when we click on it. If
+we use the second form, we must provide pointers to the title texts,
+and the number of pointers should equal the number of columns
+specified. Of course we can always use the first form, and manually
+add titles later.</para>
+
+<para>Note: The CList widget does not have its own scrollbars and should
+be placed within a ScrolledWindow widget if your require this
+functionality. This is a change from the GTK 1.0 implementation.</para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Modes of operation</title>
+
+<para>There are several attributes that can be used to alter the behaviour of
+a CList. First there is</para>
+
+<para><literallayout>
+<literal>void gtk_clist_set_selection_mode( GtkCList         *clist,
+                                   GtkSelectionMode  mode );</literal>
+</literallayout></para>
+
+<para>which, as the name implies, sets the selection mode of the
+CList. The first argument is the CList widget, and the second
+specifies the cell selection mode (they are defined in gtkenums.h). At
+the time of this writing, the following modes are available to us:</para>
+
+<itemizedlist>
+<listitem><simpara> <literal>GTK_SELECTION_SINGLE</literal> - The selection is either NULL or contains
+a GList pointer for a single selected item.</para>
+</simpara>
+</listitem>
+<listitem><simpara> <literal>GTK_SELECTION_BROWSE</literal> - The selection is NULL if the list
+contains no widgets or insensitive ones only, otherwise it contains a
+GList pointer for one GList structure, and therefore exactly one list
+item.</para>
+</simpara>
+</listitem>
+<listitem><simpara> <literal>GTK_SELECTION_MULTIPLE</literal> - The selection is NULL if no list items
+are selected or a GList pointer for the first selected item. That in
+turn points to a GList structure for the second selected item and so
+on. This is currently the <bf>default</bf> for the CList widget.</para>
+</simpara>
+</listitem>
+<listitem><simpara> <literal>GTK_SELECTION_EXTENDED</literal> - The selection is always NULL.</simpara>
+</listitem>
+</itemizedlist>
+
+<para>Others might be added in later revisions of GTK.</para>
+
+<para>We can also define what the border of the CList widget should look
+like. It is done through</para>
+
+<para><literallayout>
+<literal>void gtk_clist_set_shadow_type( GtkCList      *clist,
+                                GtkShadowType  border );</literal>
+</literallayout></para>
+
+<para>The possible values for the second argument are</para>
+
+<para><literallayout>
+<literal>  GTK_SHADOW_NONE
+  GTK_SHADOW_IN
+  GTK_SHADOW_OUT
+  GTK_SHADOW_ETCHED_IN
+  GTK_SHADOW_ETCHED_OUT</literal>
+</literallayout></para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Working with titles</title>
+
+<para>When you create a CList widget, you will also get a set of title
+buttons automatically. They live in the top of the CList window, and
+can act either as normal buttons that respond to being pressed, or
+they can be passive, in which case they are nothing more than a
+title. There are four different calls that aid us in setting the
+status of the title buttons.</para>
+
+<para><literallayout>
+<literal>void gtk_clist_column_title_active( GtkCList *clist,
+                                     gint     column );</para>
+
+<para>void gtk_clist_column_title_passive( GtkCList *clist,
+                                     gint      column );</para>
+
+<para>void gtk_clist_column_titles_active( GtkCList *clist );</para>
+
+<para>void gtk_clist_column_titles_passive( GtkCList *clist );</literal>
+</literallayout></para>
+
+<para>An active title is one which acts as a normal button, a passive one is
+just a label. The first two calls above will activate/deactivate the
+title button above the specific column, while the last two calls
+activate/deactivate all title buttons in the supplied clist widget.</para>
+
+<para>But of course there are those cases when we don't want them at all,
+and so they can be hidden and shown at will using the following two
+calls.</para>
+
+<para><literallayout>
+<literal>void gtk_clist_column_titles_show( GtkCList *clist );</para>
+
+<para>void gtk_clist_column_titles_hide( GtkCList *clist );</literal>
+</literallayout></para>
+
+<para>For titles to be really useful we need a mechanism to set and change
+them, and this is done using</para>
+
+<para><literallayout>
+<literal>void gtk_clist_set_column_title( GtkCList *clist,
+                                 gint      column,
+                                 gchar    *title );</literal>
+</literallayout></para>
+
+<para>Note that only the title of one column can be set at a time, so if all
+the titles are known from the beginning, then I really suggest using
+gtk_clist_new_with_titles (as described above) to set them. It saves
+you coding time, and makes your program smaller. There are some cases
+where getting the job done the manual way is better, and that's when
+not all titles will be text. CList provides us with title buttons
+that can in fact incorporate whole widgets, for example a pixmap. It's
+all done through</para>
+
+<para><literallayout>
+<literal>void gtk_clist_set_column_widget( GtkCList  *clist,
+                                  gint       column,
+                                  GtkWidget *widget );</literal>
+</literallayout></para>
+
+<para>which should require no special explanation.</para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Manipulating the list itself</title>
+
+<para>It is possible to change the justification for a column, and it is
+done through</para>
+
+<para><literallayout>
+<literal>void gtk_clist_set_column_justification( GtkCList         *clist,
+                                         gint              column,
+                                         GtkJustification  justification );</literal>
+</literallayout></para>
+
+<para>The GtkJustification type can take the following values:</para>
+
+<itemizedlist>
+<listitem><simpara><literal>GTK_JUSTIFY_LEFT</literal> - The text in the column will begin from the
+left edge.</para>
+</simpara>
+</listitem>
+<listitem><simpara><literal>GTK_JUSTIFY_RIGHT</literal> - The text in the column will begin from the
+right edge.</para>
+</simpara>
+</listitem>
+<listitem><simpara><literal>GTK_JUSTIFY_CENTER</literal> - The text is placed in the center of the
+column.</para>
+</simpara>
+</listitem>
+<listitem><simpara><literal>GTK_JUSTIFY_FILL</literal> - The text will use up all available space in
+the column. It is normally done by inserting extra blank spaces
+between words (or between individual letters if it's a single
+word). Much in the same way as any ordinary WYSIWYG text editor.</simpara>
+</listitem>
+</itemizedlist>
+
+<para>The next function is a very important one, and should be standard in
+the setup of all CList widgets. When the list is created, the width
+of the various columns are chosen to match their titles, and since
+this is seldom the right width we have to set it using</para>
+
+<para><literallayout>
+<literal>void gtk_clist_set_column_width( GtkCList *clist,
+                                 gint      column,
+                                 gint      width );</literal>
+</literallayout></para>
+
+<para>Note that the width is given in pixels and not letters. The same goes
+for the height of the cells in the columns, but as the default value
+is the height of the current font this isn't as critical to the
+application. Still, it is done through</para>
+
+<para><literallayout>
+<literal>void gtk_clist_set_row_height( GtkCList *clist,
+                               gint      height );</literal>
+</literallayout></para>
+
+<para>Again, note that the height is given in pixels.</para>
+
+<para>We can also move the list around without user interaction, however, it
+does require that we know what we are looking for. Or in other words,
+we need the row and column of the item we want to scroll to.</para>
+
+<para><literallayout>
+<literal>void gtk_clist_moveto( GtkCList *clist,
+                       gint      row,
+                       gint      column,
+                       gfloat    row_align,
+                       gfloat    col_align );</literal>
+</literallayout></para>
+
+<para>The gfloat row_align is pretty important to understand. It's a value
+between 0.0 and 1.0, where 0.0 means that we should scroll the list so
+the row appears at the top, while if the value of row_align is 1.0,
+the row will appear at the bottom instead. All other values between
+0.0 and 1.0 are also valid and will place the row between the top and
+the bottom. The last argument, gfloat col_align works in the same way,
+though 0.0 marks left and 1.0 marks right instead.</para>
+
+<para>Depending on the application's needs, we don't have to scroll to an
+item that is already visible to us. So how do we know if it is
+visible? As usual, there is a function to find that out as well.</para>
+
+<para><literallayout>
+<literal>GtkVisibility gtk_clist_row_is_visible( GtkCList *clist,
+                                        gint      row );</literal>
+</literallayout></para>
+
+<para>The return value is is one of the following:</para>
+
+<para><literallayout>
+<literal>  GTK_VISIBILITY_NONE
+  GTK_VISIBILITY_PARTIAL
+  GTK_VISIBILITY_FULL</literal>
+</literallayout></para>
+
+<para>Note that it will only tell us if a row is visible. Currently there is
+no way to determine this for a column. We can get partial information
+though, because if the return is <literal>GTK_VISIBILITY_PARTIAL</literal>, then
+some of it is hidden, but we don't know if it is the row that is being
+cut by the lower edge of the listbox, or if the row has columns that
+are outside.</para>
+
+<para>We can also change both the foreground and background colors of a
+particular row. This is useful for marking the row selected by the
+user, and the two functions that is used to do it are</para>
+
+<para><literallayout>
+<literal>void gtk_clist_set_foreground( GtkCList *clist,
+                               gint      row,
+                               GdkColor *color );</para>
+
+<para>void gtk_clist_set_background( GtkCList *clist,
+                               gint      row,
+                               GdkColor *color );</literal>
+</literallayout></para>
+
+<para>Please note that the colors must have been previously allocated.</para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Adding rows to the list</title>
+
+<para>We can add rows in three ways. They can be prepended or appended to
+the list using</para>
+
+<para><literallayout>
+<literal>gint gtk_clist_prepend( GtkCList *clist,
+                        gchar    *text[] );</para>
+
+<para>gint gtk_clist_append( GtkCList *clist,
+                       gchar    *text[] );</literal>
+</literallayout></para>
+
+<para>The return value of these two functions indicate the index of the row
+that was just added. We can insert a row at a given place using</para>
+
+<para><literallayout>
+<literal>void gtk_clist_insert( GtkCList *clist,
+                       gint      row,
+                       gchar    *text[] );</literal>
+</literallayout></para>
+
+<para>In these calls we have to provide a collection of pointers that are
+the texts we want to put in the columns. The number of pointers should
+equal the number of columns in the list. If the text[] argument is
+NULL, then there will be no text in the columns of the row. This is
+useful, for example, if we want to add pixmaps instead (something that
+has to be done manually).</para>
+
+<para>Also, please note that the numbering of both rows and columns start at 0.</para>
+
+<para>To remove an individual row we use</para>
+
+<para><literallayout>
+<literal>void gtk_clist_remove( GtkCList *clist,
+                       gint      row );</literal>
+</literallayout></para>
+
+<para>There is also a call that removes all rows in the list. This is a lot
+faster than calling gtk_clist_remove once for each row, which is the
+only alternative.</para>
+
+<para><literallayout>
+<literal>void gtk_clist_clear( GtkCList *clist );</literal>
+</literallayout></para>
+
+<para>There are also two convenience functions that should be used when a
+lot of changes have to be made to the list. This is to prevent the
+list flickering while being repeatedly updated, which may be highly
+annoying to the user. So instead it is a good idea to freeze the list,
+do the updates to it, and finally thaw it which causes the list to be
+updated on the screen.</para>
+
+<para><literallayout>
+<literal>void gtk_clist_freeze( GtkCList * clist );</para>
+
+<para>void gtk_clist_thaw( GtkCList * clist );</literal>
+</literallayout></para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Setting text and pixmaps in the cells</title>
+
+<para>A cell can contain a pixmap, text or both. To set them the following
+functions are used.</para>
+
+<para><literallayout>
+<literal>void gtk_clist_set_text( GtkCList    *clist,
+                         gint         row,
+                         gint         column,
+                         const gchar *text );</para>
+
+<para>void gtk_clist_set_pixmap( GtkCList  *clist,
+                           gint       row,
+                           gint       column,
+                           GdkPixmap *pixmap,
+                           GdkBitmap *mask );</para>
+
+<para>void gtk_clist_set_pixtext( GtkCList  *clist,
+                            gint       row,
+                            gint       column,
+                            gchar     *text,
+                            guint8     spacing,
+                            GdkPixmap *pixmap,
+                            GdkBitmap *mask );</literal>
+</literallayout></para>
+
+<para>It's quite straightforward. All the calls have the CList as the first
+argument, followed by the row and column of the cell, followed by the
+data to be set. The <literal>spacing</literal> argument in gtk_clist_set_pixtext is
+the number of pixels between the pixmap and the beginning of the
+text. In all cases the data is copied into the widget.</para>
+
+<para>To read back the data, we instead use</para>
+
+<para><literallayout>
+<literal>gint gtk_clist_get_text( GtkCList  *clist,
+                         gint       row,
+                         gint       column,
+                         gchar    **text );</para>
+
+<para>gint gtk_clist_get_pixmap( GtkCList   *clist,
+                           gint        row,
+                           gint        column,
+                           GdkPixmap **pixmap,
+                           GdkBitmap **mask );</para>
+
+<para>gint gtk_clist_get_pixtext( GtkCList   *clist,
+                            gint        row,
+                            gint        column,
+                            gchar     **text,
+                            guint8     *spacing,
+                            GdkPixmap **pixmap,
+                            GdkBitmap **mask );</literal>
+</literallayout></para>
+
+<para>The returned pointers are all pointers to the data stored within the
+widget, so the referenced data should not be modified or released. It
+isn't necessary to read it all back in case you aren't interested. Any
+of the pointers that are meant for return values (all except the
+clist) can be NULL. So if we want to read back only the text from a
+cell that is of type pixtext, then we would do the following, assuming
+that clist, row and column already exist:</para>
+
+<para><literallayout>
+<literal>gchar *mytext;</para>
+
+<para>gtk_clist_get_pixtext(clist, row, column, &amp;mytext, NULL, NULL, NULL);</literal>
+</literallayout></para>
+
+<para>There is one more call that is related to what's inside a cell in the
+clist, and that's</para>
+
+<para><literallayout>
+<literal>GtkCellType gtk_clist_get_cell_type( GtkCList *clist,
+                                     gint      row,
+                                     gint      column );</literal>
+</literallayout></para>
+
+<para>which returns the type of data in a cell. The return value is one of</para>
+
+<para><literallayout>
+<literal>  GTK_CELL_EMPTY
+  GTK_CELL_TEXT
+  GTK_CELL_PIXMAP
+  GTK_CELL_PIXTEXT
+  GTK_CELL_WIDGET</literal>
+</literallayout></para>
+
+<para>There is also a function that will let us set the indentation, both
+vertical and horizontal, of a cell. The indentation value is of type
+gint, given in pixels, and can be both positive and negative.</para>
+
+<para><literallayout>
+<literal>void gtk_clist_set_shift( GtkCList *clist,
+                          gint      row,
+                          gint      column,
+                          gint      vertical,
+                          gint      horizontal );</literal>
+</literallayout></para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Storing data pointers</title>
+
+<para>With a CList it is possible to set a data pointer for a row. This
+pointer will not be visible for the user, but is merely a convenience
+for the programmer to associate a row with a pointer to some
+additional data.</para>
+
+<para>The functions should be fairly self-explanatory by now.</para>
+
+<para><literallayout>
+<literal>void gtk_clist_set_row_data( GtkCList *clist,
+                             gint      row,
+                             gpointer  data );</para>
+
+<para>void gtk_clist_set_row_data_full( GtkCList         *clist,
+                                  gint              row,
+                                  gpointer          data,
+                                  GtkDestroyNotify  destroy );</para>
+
+<para>gpointer gtk_clist_get_row_data( GtkCList *clist,
+                                 gint      row );</para>
+
+<para>gint gtk_clist_find_row_from_data( GtkCList *clist,
+                                   gpointer  data );</literal>
+</literallayout></para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Working with selections</title>
+
+<para>There are also functions available that let us force the (un)selection
+of a row. These are</para>
+
+<para><literallayout>
+<literal>void gtk_clist_select_row( GtkCList *clist,
+                           gint      row,
+                           gint      column );</para>
+
+<para>void gtk_clist_unselect_row( GtkCList *clist,
+                             gint      row,
+                             gint      column );</literal>
+</literallayout></para>
+
+<para>And also a function that will take x and y coordinates (for example,
+read from the mousepointer), and map that onto the list, returning the
+corresponding row and column.</para>
+
+<para><literallayout>
+<literal>gint gtk_clist_get_selection_info( GtkCList *clist,
+                                   gint      x,
+                                   gint      y,
+                                   gint     *row,
+                                   gint     *column );</literal>
+</literallayout></para>
+
+<para>When we detect something of interest (it might be movement of the
+pointer, a click somewhere in the list) we can read the pointer
+coordinates and find out where in the list the pointer is. Cumbersome?
+Luckily, there is a simpler way...</para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>The signals that bring it together</title>
+
+<para>As with all other widgets, there are a few signals that can be used. The
+CList widget is derived from the Container widget, and so has all the
+same signals, but also adds the following:</para>
+
+<itemizedlist>
+<listitem><simpara>select_row - This signal will send the following information, in
+order: GtkCList *clist, gint row, gint column, GtkEventButton *event</para>
+</simpara>
+</listitem>
+<listitem><simpara>unselect_row - When the user unselects a row, this signal is
+activated. It sends the same information as select_row</para>
+</simpara>
+</listitem>
+<listitem><simpara>click_column - Send GtkCList *clist, gint column</simpara>
+</listitem>
+</itemizedlist>
+
+<para>So if we want to connect a callback to select_row, the callback
+function would be declared like this</para>
+
+<para><literallayout>
+<literal>void select_row_callback(GtkWidget *widget,
+                         gint row,
+                        gint column,
+                         GdkEventButton *event,
+                        gpointer data);</literal>
+</literallayout></para>
+
+<para>The callback is connected as usual with</para>
+
+<para><literallayout>
+<literal>gtk_signal_connect(GTK_OBJECT( clist),
+                  "select_row"
+                  GTK_SIGNAL_FUNC(select_row_callback),
+                  NULL);</literal>
+</literallayout></para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>A CList example</title>
+
+</para>
+<para><literallayout>
+<literal>/* example-start clist clist.c */
+
+#include &lt;gtk/gtk.h&gt;
+
+/* User clicked the "Add List" button. */
+void button_add_clicked( gpointer data )
+{
+    int indx;
+    /* Something silly to add to the list. 4 rows of 2 columns each */
+    gchar *drink[4][2] = { { "Milk",    "3 Oz" },
+                           { "Water",   "6 l" },
+                           { "Carrots", "2" },
+                           { "Snakes",  "55" } };
+
+    /* Here we do the actual adding of the text. It's done once for
+     * each row.
+     */
+    for ( indx=0 ; indx < 4 ; indx++ )
+       gtk_clist_append( (GtkCList *) data, drink[indx]);
+
+    return;
+}
+
+/* User clicked the "Clear List" button. */
+void button_clear_clicked( gpointer data )
+{
+    /* Clear the list using gtk_clist_clear. This is much faster than
+     * calling gtk_clist_remove once for each row.
+     */
+    gtk_clist_clear( (GtkCList *) data);
+
+    return;
+}
+
+/* The user clicked the "Hide/Show titles" button. */
+void button_hide_show_clicked( gpointer data )
+{
+    /* Just a flag to remember the status. 0 = currently visible */
+    static short int flag = 0;
+
+    if (flag == 0)
+    {
+        /* Hide the titles and set the flag to 1 */
+       gtk_clist_column_titles_hide((GtkCList *) data);
+       flag++;
+    }
+    else
+    {
+        /* Show the titles and reset flag to 0 */
+       gtk_clist_column_titles_show((GtkCList *) data);
+       flag--;
+    }
+
+    return;
+}
+
+/* If we come here, then the user has selected a row in the list. */
+void selection_made( GtkWidget      *clist,
+                     gint            row,
+                     gint            column,
+                    GdkEventButton *event,
+                     gpointer        data )
+{
+    gchar *text;
+
+    /* Get the text that is stored in the selected row and column
+     * which was clicked in. We will receive it as a pointer in the
+     * argument text.
+     */
+    gtk_clist_get_text(GTK_CLIST(clist), row, column, &amp;text);
+
+    /* Just prints some information about the selected row */
+    g_print("You selected row %d. More specifically you clicked in "
+            "column %d, and the text in this cell is %s\n\n",
+           row, column, text);
+
+    return;
+}
+
+int main( int    argc,
+          gchar *argv[] )
+{                                  
+    GtkWidget *window;
+    GtkWidget *vbox, *hbox;
+    GtkWidget *scrolled_window, *clist;
+    GtkWidget *button_add, *button_clear, *button_hide_show;    
+    gchar *titles[2] = { "Ingredients", "Amount" };
+
+    gtk_init(&amp;argc, &amp;argv);
+    
+    window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
+    gtk_widget_set_usize(GTK_WIDGET(window), 300, 150);
+
+    gtk_window_set_title(GTK_WINDOW(window), "GtkCList Example");
+    gtk_signal_connect(GTK_OBJECT(window),
+                      "destroy",
+                      GTK_SIGNAL_FUNC(gtk_main_quit),
+                      NULL);
+    
+    vbox=gtk_vbox_new(FALSE, 5);
+    gtk_container_set_border_width(GTK_CONTAINER(vbox), 5);
+    gtk_container_add(GTK_CONTAINER(window), vbox);
+    gtk_widget_show(vbox);
+    
+    /* Create a scrolled window to pack the CList widget into */
+    scrolled_window = gtk_scrolled_window_new (NULL, NULL);
+    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
+                                    GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
+
+    gtk_box_pack_start(GTK_BOX(vbox), scrolled_window, TRUE, TRUE, 0);
+    gtk_widget_show (scrolled_window);
+
+    /* Create the CList. For this example we use 2 columns */
+    clist = gtk_clist_new_with_titles( 2, titles);
+
+    /* When a selection is made, we want to know about it. The callback
+     * used is selection_made, and its code can be found further down */
+    gtk_signal_connect(GTK_OBJECT(clist), "select_row",
+                      GTK_SIGNAL_FUNC(selection_made),
+                      NULL);
+
+    /* It isn't necessary to shadow the border, but it looks nice :) */
+    gtk_clist_set_shadow_type (GTK_CLIST(clist), GTK_SHADOW_OUT);
+
+    /* What however is important, is that we set the column widths as
+     * they will never be right otherwise. Note that the columns are
+     * numbered from 0 and up (to 1 in this case).
+     */
+    gtk_clist_set_column_width (GTK_CLIST(clist), 0, 150);
+
+    /* Add the CList widget to the vertical box and show it. */
+    gtk_container_add(GTK_CONTAINER(scrolled_window), clist);
+    gtk_widget_show(clist);
+
+    /* Create the buttons and add them to the window. See the button
+     * tutorial for more examples and comments on this.
+     */
+    hbox = gtk_hbox_new(FALSE, 0);
+    gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0);
+    gtk_widget_show(hbox);
+
+    button_add = gtk_button_new_with_label("Add List");
+    button_clear = gtk_button_new_with_label("Clear List");
+    button_hide_show = gtk_button_new_with_label("Hide/Show titles");
+
+    gtk_box_pack_start(GTK_BOX(hbox), button_add, TRUE, TRUE, 0);
+    gtk_box_pack_start(GTK_BOX(hbox), button_clear, TRUE, TRUE, 0);
+    gtk_box_pack_start(GTK_BOX(hbox), button_hide_show, TRUE, TRUE, 0);
+
+    /* Connect our callbacks to the three buttons */
+    gtk_signal_connect_object(GTK_OBJECT(button_add), "clicked",
+                             GTK_SIGNAL_FUNC(button_add_clicked),
+                             (gpointer) clist);
+    gtk_signal_connect_object(GTK_OBJECT(button_clear), "clicked",
+                             GTK_SIGNAL_FUNC(button_clear_clicked),
+                             (gpointer) clist);
+    gtk_signal_connect_object(GTK_OBJECT(button_hide_show), "clicked",
+                             GTK_SIGNAL_FUNC(button_hide_show_clicked),
+                             (gpointer) clist);
+
+    gtk_widget_show(button_add);
+    gtk_widget_show(button_clear);
+    gtk_widget_show(button_hide_show);
+
+    /* The interface is completely set up so we show the window and
+     * enter the gtk_main loop.
+     */
+    gtk_widget_show(window);
+    gtk_main();
+    
+    return(0);
+}
+/* example-end */
+</programlisting>
+
+</sect1>
+</chapter>
+
+<!-- ***************************************************************** -->
+<chapter id="ch-CTreeWidget">
+<title>CTree Widget</title>
+
+<!-- ----------------------------------------------------------------- -->
+<p>            
+The CTree widget is derived from the CList widget. It is designed to
+display hierarchically-organised data. The tree is displayed
+vertically, and branches of the tree can be clapsed and expanded as
+required by the user.</para>
+
+<para>This section of the tutorial is under development.
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> Creating a CTree</title>
+
+<para>A CTree, being derived from CList, can have multiple columns. These
+columns optionally have titles that are displayed along the top of
+the CTree widget. Hence there are two functions for creating a new
+CTree widget:</para>
+
+<para><literallayout>
+<literal>GtkWidget *gtk_ctree_new_with_titles( gint   columns, 
+                                      gint   tree_column,
+                                      gchar *titles[] );</para>
+
+<para>GtkWidget *gtk_ctree_new( gint columns, 
+                          gint tree_column );</literal>
+</literallayout></para>
+
+<para>The <literal>columns</literal> argument specifies the number of columns that the
+CTree will contain. The <literal>tree_column</literal> argumnet specifies which of
+those columns is to contain the tree. Columns are numbered starting
+from 0.</para>
+
+<para>With the first funtion above, the <literal>titles</literal> argument contains an
+array of strings that contain the captions for the column headings. A
+typical code fragment using the <literal>gtk_ctree_new_with_titles()</literal>
+function would be:</para>
+
+<para><literallayout>
+<literal>    /* CTree column titles /*
+    char *titles[] = { "Location" , "Description" };
+    GtkWidget *ctree;</para>
+
+<para>    ctree = gtk_ctree_new_with_titles(2, 0, titles);</literal>
+</literallayout></para>
+
+<para>This would create a new CTree with two columns entitled "Location"
+and "Description", with the first column containing the tree.</para>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> Adding and Removing nodes</title>
+
+<para>The items in a CTree are termed <emphasis>nodes</emphasis>. Nodes are inserted
+into a CTree in such a way as to create a hierarchy (although the
+order of insertion is not critical). The following function is used to
+insert a node:</para>
+
+<para><literallayout>
+<literal>GtkCTreeNode *gtk_ctree_insert_node( GtkCTree     *ctree,
+                                     GtkCTreeNode *parent, 
+                                     GtkCTreeNode *sibling,
+                                     gchar        *text[],
+                                     guint8        spacing,
+                                     GdkPixmap    *pixmap_closed,
+                                     GdkBitmap    *mask_closed,
+                                     GdkPixmap    *pixmap_opened,
+                                     GdkBitmap    *mask_opened,
+                                     gboolean      is_leaf,
+                                     gboolean      expanded );</literal>
+</literallayout></para>
+
+<para>This function looks a little daunting, but that is merely due to the
+power of the CTreee widget. Not all of the parameters above are
+required. </para>
+
+<para>The CTree widget allows you to specify pixmaps to display in each
+node. For branch nodes, you can specify different pixmaps for when the
+branch is collapsed or expanded. This gives a nice visual feedback to
+the user, but it is optional so you don't have to specify pixmaps.</para>
+
+<para>Lets have a quick look at all of the parameters:</para>
+
+<itemizedlist>
+<listitem><simpara> <literal>ctree</literal> - the CTree widget we are manipulating</simpara>
+</listitem>
+<listitem><simpara> <literal>parent</literal> - the parent node of the one we are inserting. May
+                     be <literal>NULL</literal> for a root-level (i.e. initial)
+                    node.</simpara>
+</listitem>
+<listitem><simpara> <literal>sibling</literal> - a sibling of the node we are inserting. May be
+                      <literal>NULL</literal> if there are no siblings.</simpara>
+</listitem>
+<listitem><simpara> <literal>text</literal> - the textual contents of each column in the tree for
+                   this node. This array <bf>must</bf> have an entry
+                  for each column, even if it is an empty string.</simpara>
+</listitem>
+<listitem><simpara> <literal>spacing</literal> - specifies the padding between the nodes pixmap
+                      and text elements, if a pixmap is provided</simpara>
+</listitem>
+<listitem><simpara> <literal>pixmap_closed</literal> - a pixmap to display for a collapsed branch
+                            node and for a leaf node.</simpara>
+</listitem>
+<listitem><simpara> <literal>mask_closed</literal> - a bitmap mask for the above pixmap.</simpara>
+</listitem>
+<listitem><simpara> <literal>pixmap_opened</literal> - a pixmap to display for an expanded
+                            branch node.</simpara>
+</listitem>
+<listitem><simpara> <literal>mask_opened</literal> - a bitmap mask for the above pixmap.</simpara>
+</listitem>
+<listitem><simpara> <literal>is_leaf</literal> - indicates whether this is a leaf or branch node.</simpara>
+</listitem>
+<listitem><simpara> <literal>expanded</literal> - indicates whether a branch node is initially
+                       expanded or collapsed.</simpara>
+</listitem>
+</itemizedlist>
+
+<para>An object pointer of type GtkCTreeNode is returned by the
+gtk_ctree_insert_node() function. This object pointer is used to
+reference the node when manipulating it. The node pointer is also
+supplied by many of the CTree signals to identify which node the
+signal pertains to.</para>
+
+<para>To remove a node for a CTree, the following function is provided:</para>
+
+<para><literallayout>
+<literal>void gtk_ctree_remove_node( GtkCTree     *ctree, 
+                            GtkCTreeNode *node );</literal>
+</literallayout></para>
+
+<para>As you can see, you merely need to specify a CTree and the node to
+remove.</para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> Setting CTree Attributes</title>
+
+<para>There are a number of functions that set options that pertain to a
+CTree instance as a whole (rather than to a particular node). The
+first group set padding attributes that effect how the widget is drawn:</para>
+
+<para><literallayout>
+<literal>void gtk_ctree_set_indent( GtkCTree *ctree, 
+                           gint      indent );</para>
+
+<para>void gtk_ctree_set_spacing( GtkCTree *ctree, 
+                            gint      spacing );</literal>
+</literallayout></para>
+
+<para>The function <literal>gtk_ctree_set_indent()</literal> sets how far a new branch is
+indented in relation to it's parent. The default is 20.</para>
+
+<para>The function <literal>gtk_ctree_set_spacing()</literal> sets how far a node is
+horizontally padded from the vertical line that is drawn linking the
+nodes of each branch. The default is 5.</para>
+
+<para>The next two functions affect the style of the lines and expander that
+are drawn to represent the tree structure. An expander is a grpahical
+component that the user can select to expand and collapse a branch of
+the tree.</para>
+
+<para><literallayout>
+<literal>void gtk_ctree_set_line_style( GtkCTree          *ctree, 
+                               GtkCTreeLineStyle  line_style );</para>
+
+<para>void gtk_ctree_set_expander_style( GtkCTree              *ctree, 
+                                   GtkCTreeExpanderStyle  expander_style );</literal>
+</literallayout></para>
+
+<para>The function <literal>gtk_ctree_set_line_style()</literal> is used to select the style
+of line that is drawn between nodes of the tree. The parameter
+<literal>line_style</literal> can be one of:</para>
+
+<para><literallayout>
+<literal> GTK_CTREE_LINES_NONE
+ GTK_CTREE_LINES_SOLID
+ GTK_CTREE_LINES_DOTTED
+ GTK_CTREE_LINES_TABBED</literal>
+</literallayout></para>
+
+<para>The function <literal>gtk_ctree_set_expander_style()</literal> is used to select
+the style of branch expander, and the parameter <literal>expander_style</literal>
+can be one of:</para>
+
+<para><literallayout>
+<literal> GTK_CTREE_EXPANDER_NONE
+ GTK_CTREE_EXPANDER_SQUARE
+ GTK_CTREE_EXPANDER_TRIANGLE
+ GTK_CTREE_EXPANDER_CIRCULAR</literal>
+</literallayout></para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> Utilizing row data</title>
+
+<para>The CTree widget allows you to associate data with each node of the
+tree. This is most often used in callback functions, such as when a
+row is selected.</para>
+
+<para>Although only a single data element can be stored for each row, this
+data element can be any variable or data structure, which indirectly
+allows a set of data to be referenced.</para>
+
+<para>There are two functions for setting row data:</para>
+
+<para><literallayout>
+<literal>void gtk_ctree_node_set_row_data( GtkCTree     *ctree,
+                                  GtkCTreeNode *node,
+                                  gpointer      data );</para>
+
+<para>void gtk_ctree_node_set_row_data_full( GtkCTree         *ctree,
+                                      GtkCTreeNode     *node,
+                                       gpointer          data,
+                                       GtkDestroyNotify  destroy );</literal>
+</literallayout></para>
+
+<para>The function <literal>gtk_ctree_node_set_row_data()</literal> simply takes as
+arguments pointers to the CTree, node and data.</para>
+
+<para>The function <literal>gtk_ctree_node_set_row_data_full()</literal> takes an
+additional parameter, <literal>destroy</literal>. This parameter is a pointer to a
+function that will be called when the row is destroyed. Typically,
+this function would take responsibility for freeing the memory used by
+the row data. This function should take the form:</para>
+
+<para><literallayout>
+<literal>void destroy_func( gpointer data );</literal>
+</literallayout></para>
+
+<para>The paramter passed to this function will be the row data.</para>
+
+</sect1>
+</chapter>
+
+<!-- ***************************************************************** -->
+<chapter id="ch-TreeWidget">
+<title>Tree Widget</title>
+
+<!-- ----------------------------------------------------------------- -->
+
+<para>The purpose of tree widgets is to display hierarchically-organized
+data. The Tree widget itself is a vertical container for widgets of
+type TreeItem. Tree itself is not terribly different from
+CList - both are derived directly from Container, and the
+Container methods work in the same way on Tree widgets as on
+CList widgets. The difference is that Tree widgets can be nested
+within other Tree widgets. We'll see how to do this shortly.</para>
+
+<para>The Tree widget has its own window, and defaults to a white
+background, as does CList. Also, most of the Tree methods work in
+the same way as the corresponding CList ones. However, Tree is
+not derived from CList, so you cannot use them interchangeably.</para>
+
+<para>
+<sect1>
+<title> Creating a Tree</title>
+
+<para>A Tree is created in the usual way, using:</para>
+
+<para><literallayout>
+<literal>GtkWidget *gtk_tree_new( void );</literal>
+</literallayout></para>
+
+<para>Like the CList widget, a Tree will simply keep growing as more
+items are added to it, as well as when subtrees are expanded.  For
+this reason, they are almost always packed into a
+ScrolledWindow. You might want to use gtk_widget_set_usize() on the
+scrolled window to ensure that it is big enough to see the tree's
+items, as the default size for ScrolledWindow is quite small.</para>
+
+<para>Now that you have a tree, you'll probably want to add some items to
+it.  <link linkend="ch-TreeItemWidget">The Tree Item Widget</link> below
+explains the gory details of TreeItem. For now, it'll suffice to
+create one, using:</para>
+
+<para><literallayout>
+<literal>GtkWidget *gtk_tree_item_new_with_label( gchar *label );</literal>
+</literallayout></para>
+
+<para>You can then add it to the tree using one of the following (see
+<link linkend="ch-TreeFunctions">Functions and Macros</link>
+below for more options):</para>
+
+<para><literallayout>
+<literal>void gtk_tree_append( GtkTree    *tree,
+                       GtkWidget *tree_item );</para>
+
+<para>void gtk_tree_prepend( GtkTree   *tree,
+                       GtkWidget *tree_item );</literal>
+</literallayout></para>
+
+<para>Note that you must add items to a Tree one at a time - there is no
+equivalent to gtk_list_*_items().</para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> Adding a Subtree</title>
+
+<para>A subtree is created like any other Tree widget. A subtree is added
+to another tree beneath a tree item, using:</para>
+
+<para><literallayout>
+<literal>void gtk_tree_item_set_subtree( GtkTreeItem *tree_item,
+                                GtkWidget   *subtree );</literal>
+</literallayout></para>
+
+<para>You do not need to call gtk_widget_show() on a subtree before or after
+adding it to a TreeItem. However, you <emphasis>must</emphasis> have added the
+TreeItem in question to a parent tree before calling
+gtk_tree_item_set_subtree(). This is because, technically, the parent
+of the subtree is <emphasis>not</emphasis> the GtkTreeItem which "owns" it, but
+rather the GtkTree which holds that GtkTreeItem.</para>
+
+<para>When you add a subtree to a TreeItem, a plus or minus sign appears
+beside it, which the user can click on to "expand" or "collapse" it,
+meaning, to show or hide its subtree. TreeItems are collapsed by
+default. Note that when you collapse a TreeItem, any selected
+items in its subtree remain selected, which may not be what the user
+expects.</para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> Handling the Selection List</title>
+
+<para>As with CList, the Tree type has a <literal>selection</literal> field, and
+it is possible to control the behaviour of the tree (somewhat) by
+setting the selection type using:</para>
+
+<para><literallayout>
+<literal>void gtk_tree_set_selection_mode( GtkTree          *tree,
+                                  GtkSelectionMode  mode );</literal>
+</literallayout></para>
+
+<para>The semantics associated with the various selection modes are
+described in the section on the CList widget. As with the CList
+widget, the "select_child", "unselect_child" (not really - see <ref
+id="ch-Tree_Signals"> Signals </ulink> below for an explanation),
+and "selection_changed" signals are emitted when list items are
+selected or unselected. However, in order to take advantage of these
+signals, you need to know <emphasis>which</emphasis> Tree widget they will be
+emitted by, and where to find the list of selected items.</para>
+
+<para>This is a source of potential confusion. The best way to explain this
+is that though all Tree widgets are created equal, some are more equal
+than others. All Tree widgets have their own X window, and can
+therefore receive events such as mouse clicks (if their TreeItems or
+their children don't catch them first!). However, to make
+<literal>GTK_SELECTION_SINGLE</literal> and <literal>GTK_SELECTION_BROWSE</literal> selection
+types behave in a sane manner, the list of selected items is specific
+to the topmost Tree widget in a hierarchy, known as the "root tree".</para>
+
+<para>Thus, accessing the <literal>selection</literal> field directly in an arbitrary
+Tree widget is not a good idea unless you <emphasis>know</emphasis> it's the root
+tree. Instead, use the <literal>GTK_TREE_SELECTION (Tree)</literal> macro, which
+gives the root tree's selection list as a GList pointer. Of course,
+this list can include items that are not in the subtree in question if
+the selection type is <literal>GTK_SELECTION_MULTIPLE</literal>.</para>
+
+<para>Finally, the "select_child" (and "unselect_child", in theory) signals
+are emitted by all trees, but the "selection_changed" signal is only
+emitted by the root tree. Consequently, if you want to handle the
+"select_child" signal for a tree and all its subtrees, you will have
+to call gtk_signal_connect() for every subtree.</para>
+
+<para><sect1>
+<title> Tree Widget Internals</title>
+
+<para>The Tree's struct definition looks like this:</para>
+
+<para><literallayout>
+<literal>struct _GtkTree
+{
+  GtkContainer container;</para>
+
+<para>  GList *children;
+  
+  GtkTree* root_tree; /* owner of selection list */
+  GtkWidget* tree_owner;
+  GList *selection;
+  guint level;
+  guint indent_value;
+  guint current_indent;
+  guint selection_mode : 2;
+  guint view_mode : 1;
+  guint view_line : 1;
+};</literal>
+</literallayout></para>
+
+<para>The perils associated with accessing the <literal>selection</literal> field
+directly have already been mentioned. The other important fields of
+the struct can also be accessed with handy macros or class functions.
+<literal>GTK_IS_ROOT_TREE (Tree)</literal> returns a boolean value which
+indicates whether a tree is the root tree in a Tree hierarchy, while
+<literal>GTK_TREE_ROOT_TREE (Tree)</literal> returns the root tree, an object of
+type GtkTree (so, remember to cast it using <literal>GTK_WIDGET (Tree)</literal> if
+you want to use one of the gtk_widget_*() functions on it).</para>
+
+<para>Instead of directly accessing the children field of a Tree widget,
+it's probably best to cast it using >tt/GTK_CONTAINER (Tree)/, and
+pass it to the gtk_container_children() function. This creates a
+duplicate of the original list, so it's advisable to free it up using
+g_list_free() after you're done with it, or to iterate on it
+destructively, like this:</para>
+
+<para><literallayout>
+<literal>    children = gtk_container_children (GTK_CONTAINER (tree));
+    while (children) {
+      do_something_nice (GTK_TREE_ITEM (children->data));
+      children = g_list_remove_link (children, children);
+}</literal>
+</literallayout></para>
+
+<para>The <literal>tree_owner</literal> field is defined only in subtrees, where it
+points to the TreeItem widget which holds the tree in question.
+The <literal>level</literal> field indicates how deeply nested a particular tree
+is; root trees have level 0, and each successive level of subtrees has
+a level one greater than the parent level. This field is set only
+after a Tree widget is actually mapped (i.e. drawn on the screen).</para>
+
+<para>
+<!-- ----------------------------------------------------------------- -->
+<sect2> Signals
+
+<para><literallayout>
+<literal>void selection_changed( GtkTree *tree );</literal>
+</literallayout></para>
+
+<para>This signal will be emitted whenever the <literal>selection</literal> field of a
+Tree has changed. This happens when a child of the Tree is
+selected or deselected.</para>
+
+<para><literallayout>
+<literal>void select_child( GtkTree   *tree,
+                   GtkWidget *child );</literal>
+</literallayout></para>
+
+<para>This signal is emitted when a child of the Tree is about to get
+selected. This happens on calls to gtk_tree_select_item(),
+gtk_tree_select_child(), on <emphasis>all</emphasis> button presses and calls to
+gtk_tree_item_toggle() and gtk_item_toggle().  It may sometimes be
+indirectly triggered on other occasions where children get added to or
+removed from the Tree.</para>
+
+<para><literallayout>
+<literal>void unselect_child (GtkTree   *tree,
+                     GtkWidget *child);</literal>
+</literallayout></para>
+
+<para>This signal is emitted when a child of the Tree is about to get
+deselected. As of GTK 1.0.4, this seems to only occur on calls to
+gtk_tree_unselect_item() or gtk_tree_unselect_child(), and perhaps on
+other occasions, but <emphasis>not</emphasis> when a button press deselects a
+child, nor on emission of the "toggle" signal by gtk_item_toggle().</para>
+
+<para><sect2> Functions and Macros<label id="ch-Tree_Functions"></para>
+
+<para><literallayout>
+<literal>guint gtk_tree_get_type( void );</literal>
+</literallayout></para>
+
+<para>Returns the "GtkTree" type identifier.</para>
+
+<para><literallayout>
+<literal>GtkWidget* gtk_tree_new( void );</literal>
+</literallayout></para>
+
+<para>Create a new Tree object. The new widget is returned as a pointer to a
+GtkWidget object. NULL is returned on failure.</para>
+
+<para><literallayout>
+<literal>void gtk_tree_append( GtkTree   *tree,
+                      GtkWidget *tree_item );</literal>
+</literallayout></para>
+
+<para>Append a tree item to a Tree.</para>
+
+<para><literallayout>
+<literal>void gtk_tree_prepend( GtkTree   *tree,
+                       GtkWidget *tree_item );</literal>
+</literallayout></para>
+
+<para>Prepend a tree item to a Tree.</para>
+
+<para><literallayout>
+<literal>void gtk_tree_insert( GtkTree   *tree,
+                      GtkWidget *tree_item,
+                      gint       position );</literal>
+</literallayout></para>
+
+<para>Insert a tree item into a Tree at the position in the list
+specified by <literal>position.</literal></para>
+
+<para><literallayout>
+<literal>void gtk_tree_remove_items( GtkTree *tree,
+                            GList   *items );</literal>
+</literallayout></para>
+
+<para>Remove a list of items (in the form of a GList *) from a Tree.
+Note that removing an item from a tree dereferences (and thus usually)
+destroys it <emphasis>and</emphasis> its subtree, if it has one, <emphasis>and</emphasis> all
+subtrees in that subtree. If you want to remove only one item, you
+can use gtk_container_remove().</para>
+
+<para><literallayout>
+<literal>void gtk_tree_clear_items( GtkTree *tree,
+                           gint     start,
+                           gint     end );</literal>
+</literallayout></para>
+
+<para>Remove the items from position <literal>start</literal> to position <literal>end</literal>
+from a Tree. The same warning about dereferencing applies here, as
+gtk_tree_clear_items() simply constructs a list and passes it to
+gtk_tree_remove_items().</para>
+
+<para><literallayout>
+<literal>void gtk_tree_select_item( GtkTree *tree,
+                           gint     item );</literal>
+</literallayout></para>
+
+<para>Emits the "select_item" signal for the child at position
+<literal>item</literal>, thus selecting the child (unless you unselect it in a
+signal handler).</para>
+
+<para><literallayout>
+<literal>void gtk_tree_unselect_item( GtkTree *tree,
+                             gint     item );</literal>
+</literallayout></para>
+
+<para>Emits the "unselect_item" signal for the child at position
+<literal>item</literal>, thus unselecting the child.</para>
+
+<para><literallayout>
+<literal>void gtk_tree_select_child( GtkTree   *tree,
+                            GtkWidget *tree_item );</literal>
+</literallayout></para>
+
+<para>Emits the "select_item" signal for the child <literal>tree_item</literal>, thus
+selecting it.</para>
+
+<para><literallayout>
+<literal>void gtk_tree_unselect_child( GtkTree   *tree,
+                              GtkWidget *tree_item );</literal>
+</literallayout></para>
+
+<para>Emits the "unselect_item" signal for the child <literal>tree_item</literal>,
+thus unselecting it.</para>
+
+<para><literallayout>
+<literal>gint gtk_tree_child_position( GtkTree   *tree,
+                              GtkWidget *child );</literal>
+</literallayout></para>
+
+<para>Returns the position in the tree of <literal>child</literal>, unless
+<literal>child</literal> is not in the tree, in which case it returns -1.</para>
+
+<para><literallayout>
+<literal>void gtk_tree_set_selection_mode( GtkTree          *tree,
+                                  GtkSelectionMode  mode );</literal>
+</literallayout></para>
+
+<para>Sets the selection mode, which can be one of <literal>GTK_SELECTION_SINGLE</literal> (the
+default), <literal>GTK_SELECTION_BROWSE</literal>, <literal>GTK_SELECTION_MULTIPLE</literal>, or
+<literal>GTK_SELECTION_EXTENDED</literal>. This is only defined for root trees, which
+makes sense, since the root tree "owns" the selection. Setting it for
+subtrees has no effect at all; the value is simply ignored.</para>
+
+<para><literallayout>
+<literal>void gtk_tree_set_view_mode( GtkTree         *tree,
+                             GtkTreeViewMode  mode ); </literal>
+</literallayout></para>
+
+<para>Sets the "view mode", which can be either <literal>GTK_TREE_VIEW_LINE</literal> (the
+default) or <literal>GTK_TREE_VIEW_ITEM</literal>.  The view mode propagates from a
+tree to its subtrees, and can't be set exclusively to a subtree (this
+is not exactly true - see the example code comments).</para>
+
+<para>The term "view mode" is rather ambiguous - basically, it controls the
+way the highlight is drawn when one of a tree's children is selected.
+If it's <literal>GTK_TREE_VIEW_LINE</literal>, the entire TreeItem widget is
+highlighted, while for <literal>GTK_TREE_VIEW_ITEM</literal>, only the child widget
+(i.e., usually the label) is highlighted.</para>
+
+<para><literallayout>
+<literal>void gtk_tree_set_view_lines( GtkTree *tree,
+                              guint    flag );</literal>
+</literallayout></para>
+
+<para>Controls whether connecting lines between tree items are drawn.
+<literal>flag</literal> is either TRUE, in which case they are, or FALSE, in
+which case they aren't.</para>
+
+<para><literallayout>
+<literal>GtkTree *GTK_TREE (gpointer obj);</literal>
+</literallayout></para>
+
+<para>Cast a generic pointer to "GtkTree *".</para>
+
+<para><literallayout>
+<literal>GtkTreeClass *GTK_TREE_CLASS (gpointer class);</literal>
+</literallayout></para>
+
+<para>Cast a generic pointer to "GtkTreeClass *".</para>
+
+<para><literallayout>
+<literal>gint GTK_IS_TREE (gpointer obj);</literal>
+</literallayout></para>
+
+<para>Determine if a generic pointer refers to a "GtkTree" object.</para>
+
+<para><literallayout>
+<literal>gint GTK_IS_ROOT_TREE (gpointer obj)</literal>
+</literallayout></para>
+
+<para>Determine if a generic pointer refers to a "GtkTree" object
+<emphasis>and</emphasis> is a root tree. Though this will accept any pointer, the
+results of passing it a pointer that does not refer to a Tree are
+undefined and possibly harmful.</para>
+
+<para><literallayout>
+<literal>GtkTree *GTK_TREE_ROOT_TREE (gpointer obj)</literal>
+</literallayout></para>
+
+<para>Return the root tree of a pointer to a "GtkTree" object. The above
+warning applies.</para>
+
+<para><literallayout>
+<literal>GList *GTK_TREE_SELECTION( gpointer obj)</literal>
+</literallayout></para>
+
+<para>Return the selection list of the root tree of a "GtkTree" object. The
+above warning applies here, too.</para>
+
+<para><sect1> Tree Item Widget<label id="ch-Tree_Item_Widget"></para>
+
+<para>The TreeItem widget, like CListItem, is derived from Item,
+which in turn is derived from Bin.  Therefore, the item itself is a
+generic container holding exactly one child widget, which can be of
+any type. The TreeItem widget has a number of extra fields, but
+the only one we need be concerned with is the <literal>subtree</literal> field.</para>
+
+<para>The definition for the TreeItem struct looks like this:</para>
+
+<para><literallayout>
+<literal>struct _GtkTreeItem
+{
+  GtkItem item;</para>
+
+<para>  GtkWidget *subtree;
+  GtkWidget *pixmaps_box;
+  GtkWidget *plus_pix_widget, *minus_pix_widget;</para>
+
+<para>  GList *pixmaps;                /* pixmap node for this items color depth */</para>
+
+<para>  guint expanded : 1;
+};</literal>
+</literallayout></para>
+
+<para>The <literal>pixmaps_box</literal> field is an EventBox which catches clicks on
+the plus/minus symbol which controls expansion and collapsing. The
+<literal>pixmaps</literal> field points to an internal data structure. Since
+you can always obtain the subtree of a TreeItem in a (relatively)
+type-safe manner with the <literal>GTK_TREE_ITEM_SUBTREE (Item)</literal> macro,
+it's probably advisable never to touch the insides of a TreeItem
+unless you <emphasis>really</emphasis> know what you're doing.</para>
+
+<para>Since it is directly derived from an Item it can be treated as such by
+using the <literal>GTK_ITEM (TreeItem)</literal> macro. A TreeItem usually holds a
+label, so the convenience function gtk_list_item_new_with_label() is
+provided. The same effect can be achieved using code like the
+following, which is actually copied verbatim from
+gtk_tree_item_new_with_label():</para>
+
+<para><literallayout>
+<literal>tree_item = gtk_tree_item_new ();
+label_widget = gtk_label_new (label);
+gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5);</para>
+
+<para>gtk_container_add (GTK_CONTAINER (tree_item), label_widget);
+gtk_widget_show (label_widget);</literal>
+</literallayout></para>
+
+<para>As one is not forced to add a Label to a TreeItem, you could
+also add an HBox or an Arrow, or even a Notebook (though your
+app will likely be quite unpopular in this case) to the TreeItem.</para>
+
+<para>If you remove all the items from a subtree, it will be destroyed and
+unparented, unless you reference it beforehand, and the TreeItem
+which owns it will be collapsed. So, if you want it to stick around,
+do something like the following:</para>
+
+<para><literallayout>
+<literal>gtk_widget_ref (tree);
+owner = GTK_TREE(tree)->tree_owner;
+gtk_container_remove (GTK_CONTAINER(tree), item);
+if (tree->parent == NULL){
+  gtk_tree_item_expand (GTK_TREE_ITEM(owner));
+  gtk_tree_item_set_subtree (GTK_TREE_ITEM(owner), tree);
+}
+else
+  gtk_widget_unref (tree);</literal>
+</literallayout></para>
+
+<para>Finally, drag-n-drop <emphasis>does</emphasis> work with TreeItems. You just
+have to make sure that the TreeItem you want to make into a drag
+item or a drop site has not only been added to a Tree, but that
+each successive parent widget has a parent itself, all the way back to
+a toplevel or dialog window, when you call gtk_widget_dnd_drag_set()
+or gtk_widget_dnd_drop_set().  Otherwise, strange things will happen.</para>
+
+<para><sect2>
+<title> Signals</title>
+
+<para>TreeItem inherits the "select", "deselect", and "toggle" signals
+from Item. In addition, it adds two signals of its own, "expand"
+and "collapse".</para>
+
+<para><literallayout>
+<literal>void select( GtkItem *tree_item );</literal>
+</literallayout></para>
+
+<para>This signal is emitted when an item is about to be selected, either
+after it has been clicked on by the user, or when the program calls
+gtk_tree_item_select(), gtk_item_select(), or gtk_tree_select_child().</para>
+
+<para><literallayout>
+<literal>void deselect( GtkItem *tree_item );</literal>
+</literallayout></para>
+
+<para>This signal is emitted when an item is about to be unselected, either
+after it has been clicked on by the user, or when the program calls
+gtk_tree_item_deselect() or gtk_item_deselect(). In the case of
+TreeItems, it is also emitted by gtk_tree_unselect_child(), and
+sometimes gtk_tree_select_child().</para>
+
+<para><literallayout>
+<literal>void toggle( GtkItem *tree_item );</literal>
+</literallayout></para>
+
+<para>This signal is emitted when the program calls gtk_item_toggle().  The
+effect it has when emitted on a TreeItem is to call
+gtk_tree_select_child() (and never gtk_tree_unselect_child()) on the
+item's parent tree, if the item has a parent tree.  If it doesn't,
+then the highlight is reversed on the item.</para>
+
+<para><literallayout>
+<literal>void expand( GtkTreeItem *tree_item );</literal>
+</literallayout></para>
+
+<para>This signal is emitted when the tree item's subtree is about to be
+expanded, that is, when the user clicks on the plus sign next to the
+item, or when the program calls gtk_tree_item_expand().</para>
+
+<para><literallayout>
+<literal>void collapse( GtkTreeItem *tree_item );</literal>
+</literallayout></para>
+
+<para>This signal is emitted when the tree item's subtree is about to be
+collapsed, that is, when the user clicks on the minus sign next to the
+item, or when the program calls gtk_tree_item_collapse().</para>
+
+<para><sect2>
+<title> Functions and Macros</title>
+
+<para><literallayout>
+<literal>guint gtk_tree_item_get_type( void );</literal>
+</literallayout></para>
+
+<para>Returns the "GtkTreeItem" type identifier.</para>
+
+<para><literallayout>
+<literal>GtkWidget* gtk_tree_item_new( void );</literal>
+</literallayout></para>
+
+<para>Create a new TreeItem object. The new widget is returned as a
+pointer to a GtkWidget object. NULL is returned on failure.</para>
+
+<para><literallayout>
+<literal>GtkWidget* gtk_tree_item_new_with_label (gchar       *label);</literal>
+</literallayout></para>
+
+<para>Create a new TreeItem object, having a single GtkLabel as the sole
+child. The new widget is returned as a pointer to a GtkWidget
+object. NULL is returned on failure.</para>
+
+<para><literallayout>
+<literal>void gtk_tree_item_select( GtkTreeItem *tree_item );</literal>
+</literallayout></para>
+
+<para>This function is basically a wrapper around a call to
+<literal>gtk_item_select (GTK_ITEM (tree_item))</literal> which will emit the
+select signal.</para>
+
+<para><literallayout>
+<literal>void gtk_tree_item_deselect( GtkTreeItem *tree_item );</literal>
+</literallayout></para>
+
+<para>This function is basically a wrapper around a call to
+gtk_item_deselect (GTK_ITEM (tree_item)) which will emit the deselect
+signal.</para>
+
+<para><literallayout>
+<literal>void gtk_tree_item_set_subtree( GtkTreeItem *tree_item,
+                                GtkWidget   *subtree );</literal>
+</literallayout></para>
+
+<para>This function adds a subtree to tree_item, showing it if tree_item is
+expanded, or hiding it if tree_item is collapsed. Again, remember that
+the tree_item must have already been added to a tree for this to work.</para>
+
+<para><literallayout>
+<literal>void gtk_tree_item_remove_subtree( GtkTreeItem *tree_item );</literal>
+</literallayout></para>
+
+<para>This removes all of tree_item's subtree's children (thus unreferencing
+and destroying it, any of its children's subtrees, and so on...), then
+removes the subtree itself, and hides the plus/minus sign.</para>
+
+<para><literallayout>
+<literal>void gtk_tree_item_expand( GtkTreeItem *tree_item );</literal>
+</literallayout></para>
+
+<para>This emits the "expand" signal on tree_item, which expands it.</para>
+
+<para><literallayout>
+<literal>void gtk_tree_item_collapse( GtkTreeItem *tree_item );</literal>
+</literallayout></para>
+
+<para>This emits the "collapse" signal on tree_item, which collapses it.</para>
+
+<para><literallayout>
+<literal>GtkTreeItem *GTK_TREE_ITEM (gpointer obj)</literal>
+</literallayout></para>
+
+<para>Cast a generic pointer to "GtkTreeItem *".</para>
+
+<para><literallayout>
+<literal>GtkTreeItemClass *GTK_TREE_ITEM_CLASS (gpointer obj)</literal>
+</literallayout></para>
+
+<para>Cast a generic pointer to "GtkTreeItemClass".</para>
+
+<para><literallayout>
+<literal>gint GTK_IS_TREE_ITEM (gpointer obj)</literal>
+</literallayout></para>
+
+<para>Determine if a generic pointer refers to a "GtkTreeItem" object.
+ </para>
+<para><literallayout>
+<literal>GtkWidget GTK_TREE_ITEM_SUBTREE (gpointer obj)</literal>
+</literallayout></para>
+
+<para>Returns a tree item's subtree (<literal>obj</literal> should point to a
+"GtkTreeItem" object).</para>
+
+<para><sect1>
+<title> Tree Example</title>
+
+<para>This is somewhat like the tree example in testgtk.c, but a lot less
+complete (although much better commented).  It puts up a window with a
+tree, and connects all the signals for the relevant objects, so you
+can see when they are emitted.</para>
+
+<programlisting role="C">
+/* example-start tree tree.c */
+
+#include &lt;gtk/gtk.h&gt;
+
+/* for all the GtkItem:: and GtkTreeItem:: signals */
+static void cb_itemsignal( GtkWidget *item,
+                           gchar     *signame )
+{
+  gchar *name;
+  GtkLabel *label;
+
+  /* It's a Bin, so it has one child, which we know to be a
+     label, so get that */
+  label = GTK_LABEL (GTK_BIN (item)->child);
+  /* Get the text of the label */
+  gtk_label_get (label, &amp;name);
+  /* Get the level of the tree which the item is in */
+  g_print ("%s called for item %s->%p, level %d\n", signame, name,
+          item, GTK_TREE (item->parent)->level);
+}
+
+/* Note that this is never called */
+static void cb_unselect_child( GtkWidget *root_tree,
+                               GtkWidget *child,
+                               GtkWidget *subtree )
+{
+  g_print ("unselect_child called for root tree %p, subtree %p, child %p\n",
+          root_tree, subtree, child);
+}
+
+/* Note that this is called every time the user clicks on an item,
+   whether it is already selected or not. */
+static void cb_select_child (GtkWidget *root_tree, GtkWidget *child,
+                            GtkWidget *subtree)
+{
+  g_print ("select_child called for root tree %p, subtree %p, child %p\n",
+          root_tree, subtree, child);
+}
+
+static void cb_selection_changed( GtkWidget *tree )
+{
+  GList *i;
+  
+  g_print ("selection_change called for tree %p\n", tree);
+  g_print ("selected objects are:\n");
+
+  i = GTK_TREE_SELECTION(tree);
+  while (i){
+    gchar *name;
+    GtkLabel *label;
+    GtkWidget *item;
+
+    /* Get a GtkWidget pointer from the list node */
+    item = GTK_WIDGET (i->data);
+    label = GTK_LABEL (GTK_BIN (item)->child);
+    gtk_label_get (label, &amp;name);
+    g_print ("\t%s on level %d\n", name, GTK_TREE
+            (item->parent)->level);
+    i = i->next;
+  }
+}
+
+int main( int   argc,
+          char *argv[] )
+{
+  GtkWidget *window, *scrolled_win, *tree;
+  static gchar *itemnames[] = {"Foo", "Bar", "Baz", "Quux",
+                              "Maurice"};
+  gint i;
+
+  gtk_init (&amp;argc, &amp;argv);
+
+  /* a generic toplevel window */
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_signal_connect (GTK_OBJECT(window), "delete_event",
+                     GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
+  gtk_container_set_border_width (GTK_CONTAINER(window), 5);
+
+  /* A generic scrolled window */
+  scrolled_win = gtk_scrolled_window_new (NULL, NULL);
+  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
+                                 GTK_POLICY_AUTOMATIC,
+                                 GTK_POLICY_AUTOMATIC);
+  gtk_widget_set_usize (scrolled_win, 150, 200);
+  gtk_container_add (GTK_CONTAINER(window), scrolled_win);
+  gtk_widget_show (scrolled_win);
+  
+  /* Create the root tree */
+  tree = gtk_tree_new();
+  g_print ("root tree is %p\n", tree);
+  /* connect all GtkTree:: signals */
+  gtk_signal_connect (GTK_OBJECT(tree), "select_child",
+                     GTK_SIGNAL_FUNC(cb_select_child), tree);
+  gtk_signal_connect (GTK_OBJECT(tree), "unselect_child",
+                     GTK_SIGNAL_FUNC(cb_unselect_child), tree);
+  gtk_signal_connect (GTK_OBJECT(tree), "selection_changed",
+                     GTK_SIGNAL_FUNC(cb_selection_changed), tree);
+  /* Add it to the scrolled window */
+  gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW(scrolled_win),
+                                         tree);
+  /* Set the selection mode */
+  gtk_tree_set_selection_mode (GTK_TREE(tree),
+                              GTK_SELECTION_MULTIPLE);
+  /* Show it */
+  gtk_widget_show (tree);
+
+  for (i = 0; i < 5; i++){
+    GtkWidget *subtree, *item;
+    gint j;
+
+    /* Create a tree item */
+    item = gtk_tree_item_new_with_label (itemnames[i]);
+    /* Connect all GtkItem:: and GtkTreeItem:: signals */
+    gtk_signal_connect (GTK_OBJECT(item), "select",
+                       GTK_SIGNAL_FUNC(cb_itemsignal), "select");
+    gtk_signal_connect (GTK_OBJECT(item), "deselect",
+                       GTK_SIGNAL_FUNC(cb_itemsignal), "deselect");
+    gtk_signal_connect (GTK_OBJECT(item), "toggle",
+                       GTK_SIGNAL_FUNC(cb_itemsignal), "toggle");
+    gtk_signal_connect (GTK_OBJECT(item), "expand",
+                       GTK_SIGNAL_FUNC(cb_itemsignal), "expand");
+    gtk_signal_connect (GTK_OBJECT(item), "collapse",
+                       GTK_SIGNAL_FUNC(cb_itemsignal), "collapse");
+    /* Add it to the parent tree */
+    gtk_tree_append (GTK_TREE(tree), item);
+    /* Show it - this can be done at any time */
+    gtk_widget_show (item);
+    /* Create this item's subtree */
+    subtree = gtk_tree_new();
+    g_print ("-> item %s->%p, subtree %p\n", itemnames[i], item,
+            subtree);
+
+    /* This is still necessary if you want these signals to be called
+       for the subtree's children.  Note that selection_change will be 
+       signalled for the root tree regardless. */
+    gtk_signal_connect (GTK_OBJECT(subtree), "select_child",
+                       GTK_SIGNAL_FUNC(cb_select_child), subtree);
+    gtk_signal_connect (GTK_OBJECT(subtree), "unselect_child",
+                       GTK_SIGNAL_FUNC(cb_unselect_child), subtree);
+    /* This has absolutely no effect, because it is completely ignored 
+       in subtrees */
+    gtk_tree_set_selection_mode (GTK_TREE(subtree),
+                                GTK_SELECTION_SINGLE);
+    /* Neither does this, but for a rather different reason - the
+       view_mode and view_line values of a tree are propagated to
+       subtrees when they are mapped.  So, setting it later on would
+       actually have a (somewhat unpredictable) effect */
+    gtk_tree_set_view_mode (GTK_TREE(subtree), GTK_TREE_VIEW_ITEM);
+    /* Set this item's subtree - note that you cannot do this until
+       AFTER the item has been added to its parent tree! */
+    gtk_tree_item_set_subtree (GTK_TREE_ITEM(item), subtree);
+
+    for (j = 0; j < 5; j++){
+      GtkWidget *subitem;
+
+      /* Create a subtree item, in much the same way */
+      subitem = gtk_tree_item_new_with_label (itemnames[j]);
+      /* Connect all GtkItem:: and GtkTreeItem:: signals */
+      gtk_signal_connect (GTK_OBJECT(subitem), "select",
+                         GTK_SIGNAL_FUNC(cb_itemsignal), "select");
+      gtk_signal_connect (GTK_OBJECT(subitem), "deselect",
+                         GTK_SIGNAL_FUNC(cb_itemsignal), "deselect");
+      gtk_signal_connect (GTK_OBJECT(subitem), "toggle",
+                         GTK_SIGNAL_FUNC(cb_itemsignal), "toggle");
+      gtk_signal_connect (GTK_OBJECT(subitem), "expand",
+                         GTK_SIGNAL_FUNC(cb_itemsignal), "expand");
+      gtk_signal_connect (GTK_OBJECT(subitem), "collapse",
+                         GTK_SIGNAL_FUNC(cb_itemsignal), "collapse");
+      g_print ("-> -> item %s->%p\n", itemnames[j], subitem);
+      /* Add it to its parent tree */
+      gtk_tree_append (GTK_TREE(subtree), subitem);
+      /* Show it */
+      gtk_widget_show (subitem);
+    }
+  }
+
+  /* Show the window and loop endlessly */
+  gtk_widget_show (window);
+  gtk_main();
+  return 0;
+}
+/* example-end */
+</programlisting>
+
+</sect1>
+</chapter>
+
+<!-- ***************************************************************** -->
+<chapter id="ch-MenuWidget">
+<title>Menu Widget</title>
+
+<para>There are two ways to create menus: there's the easy way, and there's
+the hard way. Both have their uses, but you can usually use the
+Itemfactory (the easy way). The "hard" way is to create all the menus
+using the calls directly. The easy way is to use the gtk_item_factory
+calls. This is much simpler, but there are advantages and
+disadvantages to each approach.</para>
+
+<para>The Itemfactory is much easier to use, and to add new menus to,
+although writing a few wrapper functions to create menus using the
+manual method could go a long way towards usability. With the
+Itemfactory, it is not possible to add images or the character '/' to
+the menus.</para>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Manual Menu Creation</title>
+
+<para>In the true tradition of teaching, we'll show you the hard way
+first. <literal>:)</></para>
+
+<para>There are three widgets that go into making a menubar and submenus:
+<itemizedlist>
+<listitem><simpara>a menu item, which is what the user wants to select, e.g.,
+"Save"</simpara>
+</listitem>
+<listitem><simpara>a menu, which acts as a container for the menu items, and</simpara>
+</listitem>
+<listitem><simpara>a menubar, which is a container for each of the individual
+menus.</simpara>
+</listitem>
+</itemizedlist>
+
+<para>This is slightly complicated by the fact that menu item widgets are
+used for two different things. They are both the widgets that are
+packed into the menu, and the widget that is packed into the menubar,
+which, when selected, activates the menu.</para>
+
+<para>Let's look at the functions that are used to create menus and
+menubars.  This first function is used to create a new menubar.</para>
+
+<para><tscreen>
+<verb>
+GtkWidget *gtk_menu_bar_new( void );
+</verb>
+</tscreen></para>
+
+<para>This rather self explanatory function creates a new menubar. You use
+gtk_container_add to pack this into a window, or the box_pack
+functions to pack it into a box - the same as buttons.</para>
+
+<para><literallayout>
+<literal>GtkWidget *gtk_menu_new( void );</literal>
+</literallayout></para>
+
+<para>This function returns a pointer to a new menu; it is never actually
+shown (with gtk_widget_show), it is just a container for the menu
+items. I hope this will become more clear when you look at the
+example below.</para>
+
+<para>The next two calls are used to create menu items that are packed into
+the menu (and menubar).</para>
+
+<para><literallayout>
+<literal>GtkWidget *gtk_menu_item_new( void );</literal>
+</literallayout></para>
+
+<para>and</para>
+
+<para><literallayout>
+<literal>GtkWidget *gtk_menu_item_new_with_label( const char *label );</literal>
+</literallayout></para>
+
+<para>These calls are used to create the menu items that are to be
+displayed.  Remember to differentiate between a "menu" as created with
+gtk_menu_new and a "menu item" as created by the gtk_menu_item_new
+functions. The menu item will be an actual button with an associated
+action, whereas a menu will be a container holding menu items.</para>
+
+<para>The gtk_menu_new_with_label and gtk_menu_new functions are just as
+you'd expect after reading about the buttons. One creates a new menu
+item with a label already packed into it, and the other just creates a
+blank menu item.</para>
+
+<para>Once you've created a menu item you have to put it into a menu. This
+is done using the function gtk_menu_append. In order to capture when
+the item is selected by the user, we need to connect to the
+<literal>activate</literal> signal in the usual way. So, if we wanted to create a
+standard <literal>File</literal> menu, with the options <literal>Open</literal>, <literal>Save</literal>, and
+<literal>Quit</literal>, the code would look something like:</para>
+
+<para><literallayout>
+<literal>    file_menu = gtk_menu_new ();    /* Don't need to show menus */</para>
+
+<para>    /* Create the menu items */
+    open_item = gtk_menu_item_new_with_label ("Open");
+    save_item = gtk_menu_item_new_with_label ("Save");
+    quit_item = gtk_menu_item_new_with_label ("Quit");</para>
+
+<para>    /* Add them to the menu */
+    gtk_menu_append (GTK_MENU (file_menu), open_item);
+    gtk_menu_append (GTK_MENU (file_menu), save_item);
+    gtk_menu_append (GTK_MENU (file_menu), quit_item);</para>
+
+<para>    /* Attach the callback functions to the activate signal */
+    gtk_signal_connect_object (GTK_OBJECT (open_items), "activate",
+                               GTK_SIGNAL_FUNC (menuitem_response),
+                               (gpointer) "file.open");
+    gtk_signal_connect_object (GTK_OBJECT (save_items), "activate",
+                               GTK_SIGNAL_FUNC (menuitem_response),
+                               (gpointer) "file.save");</para>
+
+<para>    /* We can attach the Quit menu item to our exit function */
+    gtk_signal_connect_object (GTK_OBJECT (quit_items), "activate",
+                               GTK_SIGNAL_FUNC (destroy),
+                               (gpointer) "file.quit");</para>
+
+<para>    /* We do need to show menu items */
+    gtk_widget_show (open_item);
+    gtk_widget_show (save_item);
+    gtk_widget_show (quit_item);</literal>
+</literallayout></para>
+
+<para>At this point we have our menu. Now we need to create a menubar and a
+menu item for the <literal>File</literal> entry, to which we add our menu. The code
+looks like this:</para>
+
+<para><literallayout>
+<literal>    menu_bar = gtk_menu_bar_new ();
+    gtk_container_add (GTK_CONTAINER (window), menu_bar);
+    gtk_widget_show (menu_bar);</para>
+
+<para>    file_item = gtk_menu_item_new_with_label ("File");
+    gtk_widget_show (file_item);</literal>
+</literallayout></para>
+
+<para>Now we need to associate the menu with <literal>file_item</literal>. This is done
+with the function</para>
+
+<para><tscreen>
+void gtk_menu_item_set_submenu( GtkMenuItem *menu_item,
+                                GtkWidget   *submenu );
+</tscreen></para>
+
+<para>So, our example would continue with</para>
+
+<para><literallayout>
+<literal>    gtk_menu_item_set_submenu (GTK_MENU_ITEM (file_item), file_menu);</literal>
+</literallayout></para>
+
+<para>All that is left to do is to add the menu to the menubar, which is
+accomplished using the function</para>
+
+<para><tscreen>
+void gtk_menu_bar_append( GtkMenuBar *menu_bar,
+                          GtkWidget  *menu_item );
+</tscreen></para>
+
+<para>which in our case looks like this:</para>
+
+<para><literallayout>
+<literal>    gtk_menu_bar_append (GTK_MENU_BAR (menu_bar), file_item);</literal>
+</literallayout></para>
+
+<para>If we wanted the menu right justified on the menubar, such as help
+menus often are, we can use the following function (again on
+<literal>file_item</literal> in the current example) before attaching it to the
+menubar.</para>
+
+<para><literallayout>
+<literal>void gtk_menu_item_right_justify( GtkMenuItem *menu_item );</literal>
+</literallayout></para>
+
+<para>Here is a summary of the steps needed to create a menu bar with menus
+attached:</para>
+
+<itemizedlist>
+<listitem><simpara> Create a new menu using gtk_menu_new()</simpara>
+</listitem>
+<listitem><simpara> Use multiple calls to gtk_menu_item_new() for each item you
+wish to have on your menu. And use gtk_menu_append() to put each of
+these new items on to the menu.</simpara>
+</listitem>
+<listitem><simpara> Create a menu item using gtk_menu_item_new(). This will be the
+root of the menu, the text appearing here will be on the menubar
+itself.</simpara>
+</listitem>
+<listitem><simpara>Use gtk_menu_item_set_submenu() to attach the menu to the root
+menu item (the one created in the above step).</simpara>
+</listitem>
+<listitem><simpara> Create a new menubar using gtk_menu_bar_new. This step only
+needs to be done once when creating a series of menus on one menu bar.</simpara>
+</listitem>
+<listitem><simpara> Use gtk_menu_bar_append() to put the root menu onto the menubar.</simpara>
+</listitem>
+</itemizedlist>
+
+<para>Creating a popup menu is nearly the same. The difference is that the
+menu is not posted "automatically" by a menubar, but explicitly by
+calling the function gtk_menu_popup() from a button-press event, for
+example.  Take these steps:</para>
+
+<itemizedlist>
+<listitem><simpara>Create an event handling function. It needs to have the
+prototype
+<tscreen>
+static gint handler (GtkWidget *widget,
+                     GdkEvent  *event);
+</tscreen>
+and it will use the event to find out where to pop up the menu.</simpara>
+</listitem>
+<listitem><simpara>In the event handler, if the event is a mouse button press,
+treat <literal>event</literal> as a button event (which it is) and use it as
+shown in the sample code to pass information to gtk_menu_popup().</simpara>
+</listitem>
+<listitem><simpara>Bind that event handler to a widget with
+<tscreen>
+    gtk_signal_connect_object (GTK_OBJECT (widget), "event",
+                               GTK_SIGNAL_FUNC (handler),
+                               GTK_OBJECT (menu));
+</tscreen>
+where <literal>widget</literal> is the widget you are binding to,
+<literal>handler</literal> is the handling function, and <literal>menu</literal> is a menu
+created with gtk_menu_new(). This can be a menu which is also posted
+by a menu bar, as shown in the sample code.</simpara>
+</listitem>
+</itemizedlist>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Manual Menu Example</title>
+
+<para>That should about do it. Let's take a look at an example to help clarify.</para>
+
+<programlisting role="C">
+/* example-start menu menu.c */
+
+#include &lt;stdio.h&gt;
+#include &lt;gtk/gtk.h&gt;
+
+static gint button_press (GtkWidget *, GdkEvent *);
+static void menuitem_response (gchar *);
+
+int main( int   argc,
+          char *argv[] )
+{
+
+    GtkWidget *window;
+    GtkWidget *menu;
+    GtkWidget *menu_bar;
+    GtkWidget *root_menu;
+    GtkWidget *menu_items;
+    GtkWidget *vbox;
+    GtkWidget *button;
+    char buf[128];
+    int i;
+
+    gtk_init (&amp;argc, &amp;argv);
+
+    /* create a new window */
+    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+    gtk_widget_set_usize (GTK_WIDGET (window), 200, 100);
+    gtk_window_set_title (GTK_WINDOW (window), "GTK Menu Test");
+    gtk_signal_connect (GTK_OBJECT (window), "delete_event",
+                        (GtkSignalFunc) gtk_main_quit, NULL);
+
+    /* Init the menu-widget, and remember -- never
+     * gtk_show_widget() the menu widget!! 
+     * This is the menu that holds the menu items, the one that
+     * will pop up when you click on the "Root Menu" in the app */
+    menu = gtk_menu_new ();
+
+    /* Next we make a little loop that makes three menu-entries for "test-menu".
+     * Notice the call to gtk_menu_append.  Here we are adding a list of
+     * menu items to our menu.  Normally, we'd also catch the "clicked"
+     * signal on each of the menu items and setup a callback for it,
+     * but it's omitted here to save space. */
+
+    for (i = 0; i < 3; i++)
+        {
+            /* Copy the names to the buf. */
+            sprintf (buf, "Test-undermenu - %d", i);
+
+            /* Create a new menu-item with a name... */
+            menu_items = gtk_menu_item_new_with_label (buf);
+
+            /* ...and add it to the menu. */
+            gtk_menu_append (GTK_MENU (menu), menu_items);
+
+           /* Do something interesting when the menuitem is selected */
+           gtk_signal_connect_object (GTK_OBJECT (menu_items), "activate",
+               GTK_SIGNAL_FUNC (menuitem_response), (gpointer) g_strdup (buf));
+
+            /* Show the widget */
+            gtk_widget_show (menu_items);
+        }
+
+    /* This is the root menu, and will be the label
+     * displayed on the menu bar.  There won't be a signal handler attached,
+     * as it only pops up the rest of the menu when pressed. */
+    root_menu = gtk_menu_item_new_with_label ("Root Menu");
+
+    gtk_widget_show (root_menu);
+
+    /* Now we specify that we want our newly created "menu" to be the menu
+     * for the "root menu" */
+    gtk_menu_item_set_submenu (GTK_MENU_ITEM (root_menu), menu);
+
+    /* A vbox to put a menu and a button in: */
+    vbox = gtk_vbox_new (FALSE, 0);
+    gtk_container_add (GTK_CONTAINER (window), vbox);
+    gtk_widget_show (vbox);
+
+    /* Create a menu-bar to hold the menus and add it to our main window */
+    menu_bar = gtk_menu_bar_new ();
+    gtk_box_pack_start (GTK_BOX (vbox), menu_bar, FALSE, FALSE, 2);
+    gtk_widget_show (menu_bar);
+
+    /* Create a button to which to attach menu as a popup */
+    button = gtk_button_new_with_label ("press me");
+    gtk_signal_connect_object (GTK_OBJECT (button), "event",
+       GTK_SIGNAL_FUNC (button_press), GTK_OBJECT (menu));
+    gtk_box_pack_end (GTK_BOX (vbox), button, TRUE, TRUE, 2);
+    gtk_widget_show (button);
+
+    /* And finally we append the menu-item to the menu-bar -- this is the
+     * "root" menu-item I have been raving about =) */
+    gtk_menu_bar_append (GTK_MENU_BAR (menu_bar), root_menu);
+
+    /* always display the window as the last step so it all splashes on
+     * the screen at once. */
+    gtk_widget_show (window);
+
+    gtk_main ();
+
+    return(0);
+}
+
+/* Respond to a button-press by posting a menu passed in as widget.
+ *
+ * Note that the "widget" argument is the menu being posted, NOT
+ * the button that was pressed.
+ */
+
+static gint button_press( GtkWidget *widget,
+                          GdkEvent *event )
+{
+
+    if (event->type == GDK_BUTTON_PRESS) {
+        GdkEventButton *bevent = (GdkEventButton *) event; 
+        gtk_menu_popup (GTK_MENU (widget), NULL, NULL, NULL, NULL,
+                        bevent->button, bevent->time);
+        /* Tell calling code that we have handled this event; the buck
+         * stops here. */
+        return TRUE;
+    }
+
+    /* Tell calling code that we have not handled this event; pass it on. */
+    return FALSE;
+}
+
+
+/* Print a string when a menu item is selected */
+
+static void menuitem_response( gchar *string )
+{
+    printf ("%s\n", string);
+}
+/* example-end */
+</programlisting>
+
+<para>You may also set a menu item to be insensitive and, using an accelerator
+table, bind keys to menu functions.</para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Using ItemFactory</title>
+
+<para>Now that we've shown you the hard way, here's how you do it using the
+gtk_item_factory calls.</para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Item Factory Example</title>
+
+<para>Here is an example using the GTK item factory.</para>
+
+<programlisting role="C">
+/* example-start menu itemfactory.c */
+
+#include &lt;gtk/gtk.h&gt;
+#include &lt;strings.h&gt;
+
+/* Obligatory basic callback */
+static void print_hello( GtkWidget *w,
+                         gpointer   data )
+{
+  g_message ("Hello, World!\n");
+}
+
+/* This is the GtkItemFactoryEntry structure used to generate new menus.
+   Item 1: The menu path. The letter after the underscore indicates an
+           accelerator key once the menu is open.
+   Item 2: The accelerator key for the entry
+   Item 3: The callback function.
+   Item 4: The callback action.  This changes the parameters with
+           which the function is called.  The default is 0.
+   Item 5: The item type, used to define what kind of an item it is.
+           Here are the possible values:
+
+           NULL               -> "<Item>"
+           ""                 -> "<Item>"
+           "<Title>"          -> create a title item
+           "<Item>"           -> create a simple item
+           "<CheckItem>"      -> create a check item
+           "<ToggleItem>"     -> create a toggle item
+           "<RadioItem>"      -> create a radio item
+           <path>             -> path of a radio item to link against
+           "<Separator>"      -> create a separator
+           "<Branch>"         -> create an item to hold sub items (optional)
+           "<LastBranch>"     -> create a right justified branch 
+*/
+
+static GtkItemFactoryEntry menu_items[] = {
+  { "/_File",         NULL,         NULL, 0, "<Branch>" },
+  { "/File/_New",     "<control>N", print_hello, 0, NULL },
+  { "/File/_Open",    "<control>O", print_hello, 0, NULL },
+  { "/File/_Save",    "<control>S", print_hello, 0, NULL },
+  { "/File/Save _As", NULL,         NULL, 0, NULL },
+  { "/File/sep1",     NULL,         NULL, 0, "<Separator>" },
+  { "/File/Quit",     "<control>Q", gtk_main_quit, 0, NULL },
+  { "/_Options",      NULL,         NULL, 0, "<Branch>" },
+  { "/Options/Test",  NULL,         NULL, 0, NULL },
+  { "/_Help",         NULL,         NULL, 0, "<LastBranch>" },
+  { "/_Help/About",   NULL,         NULL, 0, NULL },
+};
+
+
+void get_main_menu( GtkWidget  *window,
+                    GtkWidget **menubar )
+{
+  GtkItemFactory *item_factory;
+  GtkAccelGroup *accel_group;
+  gint nmenu_items = sizeof (menu_items) / sizeof (menu_items[0]);
+
+  accel_group = gtk_accel_group_new ();
+
+  /* This function initializes the item factory.
+     Param 1: The type of menu - can be GTK_TYPE_MENU_BAR, GTK_TYPE_MENU,
+              or GTK_TYPE_OPTION_MENU.
+     Param 2: The path of the menu.
+     Param 3: A pointer to a gtk_accel_group.  The item factory sets up
+              the accelerator table while generating menus.
+  */
+
+  item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "<main>", 
+                                      accel_group);
+
+  /* This function generates the menu items. Pass the item factory,
+     the number of items in the array, the array itself, and any
+     callback data for the the menu items. */
+  gtk_item_factory_create_items (item_factory, nmenu_items, menu_items, NULL);
+
+  /* Attach the new accelerator group to the window. */
+  gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
+
+  if (menubar)
+    /* Finally, return the actual menu bar created by the item factory. */ 
+    *menubar = gtk_item_factory_get_widget (item_factory, "<main>");
+}
+
+int main( int argc,
+          char *argv[] )
+{
+  GtkWidget *window;
+  GtkWidget *main_vbox;
+  GtkWidget *menubar;
+  
+  gtk_init (&amp;argc, &amp;argv);
+  
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_signal_connect (GTK_OBJECT (window), "destroy", 
+                     GTK_SIGNAL_FUNC (gtk_main_quit), 
+                     "WM destroy");
+  gtk_window_set_title (GTK_WINDOW(window), "Item Factory");
+  gtk_widget_set_usize (GTK_WIDGET(window), 300, 200);
+  
+  main_vbox = gtk_vbox_new (FALSE, 1);
+  gtk_container_border_width (GTK_CONTAINER (main_vbox), 1);
+  gtk_container_add (GTK_CONTAINER (window), main_vbox);
+  gtk_widget_show (main_vbox);
+  
+  get_main_menu (window, &amp;menubar);
+  gtk_box_pack_start (GTK_BOX (main_vbox), menubar, FALSE, TRUE, 0);
+  gtk_widget_show (menubar);
+  
+  gtk_widget_show (window);
+  gtk_main ();
+  
+  return(0);
+}
+/* example-end */
+</programlisting>
+
+<para>
+For now, there's only this example. An explanation and lots 'o' comments
+will follow later.</para>
+
+</sect1>
+</chapter>
+
+<!-- ***************************************************************** -->
+<chapter id="ch-TextWidget">
+<title>Text Widget</title>
+
+<para>The Text widget allows multiple lines of text to be displayed and
+edited. It supports both multi-colored and multi-font text, allowing
+them to be mixed in any way we wish. It also has a wide set of key
+based text editing commands, which are compatible with Emacs.</para>
+
+<para>The text widget supports full cut-and-paste facilities, including the
+use of double- and triple-click to select a word and a whole line,
+respectively.</para>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Creating and Configuring a Text box</title>
+
+<para>There is only one function for creating a new Text widget.</para>
+
+<para><literallayout>
+<literal>GtkWidget *gtk_text_new( GtkAdjustment *hadj,
+                         GtkAdjustment *vadj );</literal>
+</literallayout></para>
+
+<para>The arguments allow us to give the Text widget pointers to Adjustments
+that can be used to track the viewing position of the widget. Passing
+NULL values to either or both of these arguments will cause the
+gtk_text_new function to create its own.</para>
+
+<para><literallayout>
+<literal>void gtk_text_set_adjustments( GtkText       *text,
+                               GtkAdjustment *hadj,
+                               GtkAdjustment *vadj );</literal>
+</literallayout></para>
+
+<para>The above function allows the horizontal and vertical adjustments of a
+text widget to be changed at any time.</para>
+
+<para>The text widget will not automatically create its own scrollbars when
+the amount of text to be displayed is too long for the display
+window. We therefore have to create and add them to the display layout
+ourselves.</para>
+
+<para><literallayout>
+<literal>  vscrollbar = gtk_vscrollbar_new (GTK_TEXT(text)->vadj);
+  gtk_box_pack_start(GTK_BOX(hbox), vscrollbar, FALSE, FALSE, 0);
+  gtk_widget_show (vscrollbar);</literal>
+</literallayout></para>
+
+<para>The above code snippet creates a new vertical scrollbar, and attaches
+it to the vertical adjustment of the text widget, <literal>text</literal>. It then
+packs it into a box in the normal way.</para>
+
+<para>Note, currently the Text widget does not support horizontal
+scrollbars.</para>
+
+<para>There are two main ways in which a Text widget can be used: to allow
+the user to edit a body of text, or to allow us to display multiple
+lines of text to the user. In order for us to switch between these
+modes of operation, the text widget has the following function:</para>
+
+<para><literallayout>
+<literal>void gtk_text_set_editable( GtkText *text,
+                            gint     editable );</literal>
+</literallayout></para>
+
+<para>The <literal>editable</literal> argument is a TRUE or FALSE value that specifies
+whether the user is permitted to edit the contents of the Text
+widget. When the text widget is editable, it will display a cursor at
+the current insertion point.</para>
+
+<para>You are not, however, restricted to just using the text widget in
+these two modes. You can toggle the editable state of the text widget
+at any time, and can insert text at any time.</para>
+
+<para>The text widget wraps lines of text that are too long to fit onto a
+single line of the display window. Its default behaviour is to break
+words across line breaks. This can be changed using the next function:</para>
+
+<para><literallayout>
+<literal>void gtk_text_set_word_wrap( GtkText *text,
+                             gint     word_wrap );</literal>
+</literallayout></para>
+
+<para>Using this function allows us to specify that the text widget should
+wrap long lines on word boundaries. The <literal>word_wrap</literal> argument is a
+TRUE or FALSE value.</para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>Text Manipulation
+<P>
+The current insertion point of a Text widget can be set using</para>
+<para><literallayout>
+<literal>void gtk_text_set_point( GtkText *text,
+                         guint    index );</literal>
+</literallayout></para>
+
+<para>where <literal>index</literal> is the position to set the insertion point.</para>
+
+<para>Analogous to this is the function for getting the current insertion
+point:</para>
+
+<para><literallayout>
+<literal>guint gtk_text_get_point( GtkText *text );</literal>
+</literallayout></para>
+
+<para>A function that is useful in combination with the above two functions
+is</para>
+
+<para><literallayout>
+<literal>guint gtk_text_get_length( GtkText *text );</literal>
+</literallayout></para>
+
+<para>which returns the current length of the Text widget. The length is the
+number of characters that are within the text block of the widget,
+including characters such as newline, which marks the end of
+lines.</para>
+
+<para>In order to insert text at the current insertion point of a Text
+widget, the function gtk_text_insert is used, which also allows us to
+specify background and foreground colors and a font for the text.</para>
+
+<para><literallayout>
+<literal>void gtk_text_insert( GtkText    *text,
+                      GdkFont    *font,
+                      GdkColor   *fore,
+                      GdkColor   *back,
+                      const char *chars,
+                      gint        length );</literal>
+</literallayout></para>
+
+<para>Passing a value of <literal>NULL</literal> in as the value for the foreground color,
+background color or font will result in the values set within the
+widget style to be used. Using a value of <literal>-1</literal> for the length
+parameter will result in the whole of the text string given being
+inserted.</para>
+
+<para>The text widget is one of the few within GTK that redraws itself
+dynamically, outside of the gtk_main function. This means that all
+changes to the contents of the text widget take effect
+immediately. This may be undesirable when performing multiple changes
+to the text widget. In order to allow us to perform multiple updates
+to the text widget without it continuously redrawing, we can freeze
+the widget, which temporarily stops it from automatically redrawing
+itself every time it is changed. We can then thaw the widget after our
+updates are complete.</para>
+
+<para>The following two functions perform this freeze and thaw action:</para>
+
+<para><literallayout>
+<literal>void gtk_text_freeze( GtkText *text );</para>
+
+<para>void gtk_text_thaw( GtkText *text );         </literal>
+</literallayout></para>
+
+<para>Text is deleted from the text widget relative to the current insertion
+point by the following two functions. The return value is a TRUE or
+FALSE indicator of whether the operation was successful.</para>
+
+<para><literallayout>
+<literal>gint gtk_text_backward_delete( GtkText *text,
+                               guint    nchars );</para>
+
+<para>gint gtk_text_forward_delete ( GtkText *text,
+                               guint    nchars );</literal>
+</literallayout></para>
+
+<para>If you want to retrieve the contents of the text widget, then the
+macro <literal>GTK_TEXT_INDEX(t, index)</literal> allows you to retrieve the
+character at position <literal>index</literal> within the text widget <literal>t</literal>.</para>
+
+<para>To retrieve larger blocks of text, we can use the function</para>
+
+<para><literallayout>
+<literal>gchar *gtk_editable_get_chars( GtkEditable *editable,
+                               gint         start_pos,
+                               gint         end_pos );   </literal>
+</literallayout></para>
+
+<para>This is a function of the parent class of the text widget. A value of
+-1 as <literal>end_pos</literal> signifies the end of the text. The index of the
+text starts at 0.</para>
+
+<para>The function allocates a new chunk of memory for the text block, so
+don't forget to free it with a call to g_free when you have finished
+with it.
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Keyboard Shortcuts</title>
+
+<para>The text widget has a number of pre-installed keyboard shortcuts for
+common editing, motion and selection functions. These are accessed
+using Control and Alt key combinations.</para>
+
+<para>In addition to these, holding down the Control key whilst using cursor
+key movement will move the cursor by words rather than
+characters. Holding down Shift whilst using cursor movement will
+extend the selection.</para>
+
+<para><sect2>
+<title>Motion Shortcuts</title>
+
+<itemizedlist>
+<listitem><simpara> Ctrl-A   Beginning of line</simpara>
+</listitem>
+<listitem><simpara> Ctrl-E   End of line</simpara>
+</listitem>
+<listitem><simpara> Ctrl-N   Next Line</simpara>
+</listitem>
+<listitem><simpara> Ctrl-P   Previous Line</simpara>
+</listitem>
+<listitem><simpara> Ctrl-B   Backward one character</simpara>
+</listitem>
+<listitem><simpara> Ctrl-F   Forward one character</simpara>
+</listitem>
+<listitem><simpara> Alt-B    Backward one word</simpara>
+</listitem>
+<listitem><simpara> Alt-F    Forward one word</simpara>
+</listitem>
+</itemizedlist>
+
+<para><sect2>
+<title>Editing Shortcuts</title>
+
+<itemizedlist>
+<listitem><simpara> Ctrl-H   Delete Backward Character (Backspace)</simpara>
+</listitem>
+<listitem><simpara> Ctrl-D   Delete Forward Character (Delete)</simpara>
+</listitem>
+<listitem><simpara> Ctrl-W   Delete Backward Word</simpara>
+</listitem>
+<listitem><simpara> Alt-D    Delete Forward Word</simpara>
+</listitem>
+<listitem><simpara> Ctrl-K   Delete to end of line</simpara>
+</listitem>
+<listitem><simpara> Ctrl-U   Delete line</simpara>
+</listitem>
+</itemizedlist>
+
+<para><sect2>
+<title>Selection Shortcuts</title>
+
+<itemizedlist>
+<listitem><simpara> Ctrl-X   Cut to clipboard</simpara>
+</listitem>
+<listitem><simpara> Ctrl-C   Copy to clipboard</simpara>
+</listitem>
+<listitem><simpara> Ctrl-V   Paste from clipboard</simpara>
+</listitem>
+</itemizedlist>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>A GtkText Example</title>
+
+<programlisting role="C">
+/* example-start text text.c */
+
+/* text.c */
+
+#include &lt;stdio.h&gt;
+#include &lt;gtk/gtk.h&gt;
+
+void text_toggle_editable (GtkWidget *checkbutton,
+                          GtkWidget *text)
+{
+  gtk_text_set_editable(GTK_TEXT(text),
+                       GTK_TOGGLE_BUTTON(checkbutton)->active);
+}
+
+void text_toggle_word_wrap (GtkWidget *checkbutton,
+                           GtkWidget *text)
+{
+  gtk_text_set_word_wrap(GTK_TEXT(text),
+                        GTK_TOGGLE_BUTTON(checkbutton)->active);
+}
+
+void close_application( GtkWidget *widget,
+                        gpointer   data )
+{
+       gtk_main_quit();
+}
+
+int main( int argc,
+          char *argv[] )
+{
+  GtkWidget *window;
+  GtkWidget *box1;
+  GtkWidget *box2;
+  GtkWidget *hbox;
+  GtkWidget *button;
+  GtkWidget *check;
+  GtkWidget *separator;
+  GtkWidget *table;
+  GtkWidget *vscrollbar;
+  GtkWidget *text;
+  GdkColormap *cmap;
+  GdkColor color;
+  GdkFont *fixed_font;
+
+  FILE *infile;
+
+  gtk_init (&amp;argc, &amp;argv);
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_widget_set_usize (window, 600, 500);
+  gtk_window_set_policy (GTK_WINDOW(window), TRUE, TRUE, FALSE);  
+  gtk_signal_connect (GTK_OBJECT (window), "destroy",
+                     GTK_SIGNAL_FUNC(close_application),
+                     NULL);
+  gtk_window_set_title (GTK_WINDOW (window), "Text Widget Example");
+  gtk_container_set_border_width (GTK_CONTAINER (window), 0);
+  
+  
+  box1 = gtk_vbox_new (FALSE, 0);
+  gtk_container_add (GTK_CONTAINER (window), box1);
+  gtk_widget_show (box1);
+  
+  
+  box2 = gtk_vbox_new (FALSE, 10);
+  gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
+  gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
+  gtk_widget_show (box2);
+  
+  
+  table = gtk_table_new (2, 2, FALSE);
+  gtk_table_set_row_spacing (GTK_TABLE (table), 0, 2);
+  gtk_table_set_col_spacing (GTK_TABLE (table), 0, 2);
+  gtk_box_pack_start (GTK_BOX (box2), table, TRUE, TRUE, 0);
+  gtk_widget_show (table);
+  
+  /* Create the GtkText widget */
+  text = gtk_text_new (NULL, NULL);
+  gtk_text_set_editable (GTK_TEXT (text), TRUE);
+  gtk_table_attach (GTK_TABLE (table), text, 0, 1, 0, 1,
+                   GTK_EXPAND | GTK_SHRINK | GTK_FILL,
+                   GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
+  gtk_widget_show (text);
+
+  /* Add a vertical scrollbar to the GtkText widget */
+  vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj);
+  gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1,
+                   GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
+  gtk_widget_show (vscrollbar);
+
+  /* Get the system color map and allocate the color red */
+  cmap = gdk_colormap_get_system();
+  color.red = 0xffff;
+  color.green = 0;
+  color.blue = 0;
+  if (!gdk_color_alloc(cmap, &amp;color)) {
+    g_error("couldn't allocate color");
+  }
+
+  /* Load a fixed font */
+  fixed_font = gdk_font_load ("-misc-fixed-medium-r-*-*-*-140-*-*-*-*-*-*");
+
+  /* Realizing a widget creates a window for it,
+   * ready for us to insert some text */
+  gtk_widget_realize (text);
+
+  /* Freeze the text widget, ready for multiple updates */
+  gtk_text_freeze (GTK_TEXT (text));
+  
+  /* Insert some colored text */
+  gtk_text_insert (GTK_TEXT (text), NULL, &amp;text->style->black, NULL,
+                  "Supports ", -1);
+  gtk_text_insert (GTK_TEXT (text), NULL, &amp;color, NULL,
+                  "colored ", -1);
+  gtk_text_insert (GTK_TEXT (text), NULL, &amp;text->style->black, NULL,
+                  "text and different ", -1);
+  gtk_text_insert (GTK_TEXT (text), fixed_font, &amp;text->style->black, NULL,
+                  "fonts\n\n", -1);
+  
+  /* Load the file text.c into the text window */
+
+  infile = fopen("text.c", "r");
+  
+  if (infile) {
+    char buffer[1024];
+    int nchars;
+    
+    while (1)
+      {
+       nchars = fread(buffer, 1, 1024, infile);
+       gtk_text_insert (GTK_TEXT (text), fixed_font, NULL,
+                        NULL, buffer, nchars);
+       
+       if (nchars < 1024)
+         break;
+      }
+    
+    fclose (infile);
+  }
+
+  /* Thaw the text widget, allowing the updates to become visible */  
+  gtk_text_thaw (GTK_TEXT (text));
+  
+  hbox = gtk_hbutton_box_new ();
+  gtk_box_pack_start (GTK_BOX (box2), hbox, FALSE, FALSE, 0);
+  gtk_widget_show (hbox);
+
+  check = gtk_check_button_new_with_label("Editable");
+  gtk_box_pack_start (GTK_BOX (hbox), check, FALSE, FALSE, 0);
+  gtk_signal_connect (GTK_OBJECT(check), "toggled",
+                     GTK_SIGNAL_FUNC(text_toggle_editable), text);
+  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), TRUE);
+  gtk_widget_show (check);
+  check = gtk_check_button_new_with_label("Wrap Words");
+  gtk_box_pack_start (GTK_BOX (hbox), check, FALSE, TRUE, 0);
+  gtk_signal_connect (GTK_OBJECT(check), "toggled",
+                     GTK_SIGNAL_FUNC(text_toggle_word_wrap), text);
+  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), FALSE);
+  gtk_widget_show (check);
+
+  separator = gtk_hseparator_new ();
+  gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
+  gtk_widget_show (separator);
+
+  box2 = gtk_vbox_new (FALSE, 10);
+  gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
+  gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
+  gtk_widget_show (box2);
+  
+  button = gtk_button_new_with_label ("close");
+  gtk_signal_connect (GTK_OBJECT (button), "clicked",
+                     GTK_SIGNAL_FUNC(close_application),
+                     NULL);
+  gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
+  GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
+  gtk_widget_grab_default (button);
+  gtk_widget_show (button);
+
+  gtk_widget_show (window);
+
+  gtk_main ();
+  
+  return(0);       
+}
+/* example-end */
+</programlisting>
+
+</sect1>
+</chapter>
+
+<!-- ***************************************************************** -->
+<chapter id="ch-UndocWidgets">
+<title>Undocumented Widgets</title>
+
+<para>These all require authors! :) Please consider contributing to our
+tutorial.</para>
+
+<para>If you must use one of these widgets that are undocumented, I strongly
+suggest you take a look at their respective header files in the GTK
+distribution. GTK's function names are very descriptive. Once you
+have an understanding of how things work, it's not difficult to figure
+out how to use a widget simply by looking at its function
+declarations. This, along with a few examples from others' code, and
+it should be no problem.</para>
+
+<para>When you do come to understand all the functions of a new undocumented
+widget, please consider writing a tutorial on it so others may benefit
+from your time.</para>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> CTree</title>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> Curves</title>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> Drawing Area</title>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> Font Selection Dialog</title>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> Gamma Curve</title>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> Image</title>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> Packer</title>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> Plugs and Sockets</title>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> Preview</title>
+
+<!--
+
+<para>(This may need to be rewritten to follow the style of the rest of the tutorial)</para>
+
+<para><tscreen><verb></para>
+
+<para>Previews serve a number of purposes in GIMP/GTK. The most important one is
+this. High quality images may take up to tens of megabytes of memory - easily!
+Any operation on an image that big is bound to take a long time. If it takes
+you 5-10 trial-and-errors (i.e., 10-20 steps, since you have to revert after
+you make an error) to choose the desired modification, it make take you
+literally hours to make the right one - if you don't run out of memory
+first. People who have spent hours in color darkrooms know the feeling.
+Previews to the rescue!</para>
+
+<para>But the annoyance of the delay is not the only issue. Oftentimes it is
+helpful to compare the Before and After versions side-by-side or at least
+back-to-back. If you're working with big images and 10 second delays,
+obtaining the Before and After impressions is, to say the least, difficult.
+For 30M images (4"x6", 600dpi, 24 bit) the side-by-side comparison is right
+out for most people, while back-to-back is more like back-to-1001, 1002,
+..., 1010-back! Previews to the rescue!</para>
+
+<para>But there's more. Previews allow for side-by-side pre-previews. In other
+words, you write a plug-in (e.g., the filterpack simulation) which would have
+a number of here's-what-it-would-look-like-if-you-were-to-do-this previews.
+An approach like this acts as a sort of a preview palette and is very
+effective for subtle changes. Let's go previews!</para>
+
+<para>There's more. For certain plug-ins real-time image-specific human
+intervention maybe necessary. In the SuperNova plug-in, for example, the
+user is asked to enter the coordinates of the center of the future
+supernova. The easiest way to do this, really, is to present the user with a
+preview and ask him to interactively select the spot. Let's go previews!</para>
+
+<para>Finally, a couple of misc uses. One can use previews even when not working
+with big images. For example, they are useful when rendering complicated
+patterns. (Just check out the venerable Diffraction plug-in + many other
+ones!) As another example, take a look at the colormap rotation plug-in
+(work in progress). You can also use previews for little logos inside you
+plug-ins and even for an image of yourself, The Author. Let's go previews!</para>
+
+<para>When Not to Use Previews</para>
+
+<para>Don't use previews for graphs, drawing, etc. GDK is much faster for that. Use
+previews only for rendered images!</para>
+
+<para>Let's go previews!</para>
+
+<para>You can stick a preview into just about anything. In a vbox, an hbox, a
+table, a button, etc. But they look their best in tight frames around them.
+Previews by themselves do not have borders and look flat without them. (Of
+course, if the flat look is what you want...) Tight frames provide the
+necessary borders.</para>
+
+<para>                               [Image][Image]</para>
+
+<para>Previews in many ways are like any other widgets in GTK (whatever that
+means) except they possess an additional feature: they need to be filled with
+some sort of an image! First, we will deal exclusively with the GTK aspect
+of previews and then we'll discuss how to fill them.</para>
+
+<para>GtkWidget *preview!</para>
+
+<para>Without any ado:</para>
+
+<para>                              /* Create a preview widget,
+                              set its size, an show it */
+GtkWidget *preview;
+preview=gtk_preview_new(GTK_PREVIEW_COLOR)
+                              /*Other option:
+                              GTK_PREVIEW_GRAYSCALE);*/
+gtk_preview_size (GTK_PREVIEW (preview), WIDTH, HEIGHT);
+gtk_widget_show(preview);
+my_preview_rendering_function(preview);</para>
+
+<para>Oh yeah, like I said, previews look good inside frames, so how about:</para>
+
+<para>GtkWidget *create_a_preview(int        Width,
+                            int        Height,
+                            int        Colorfulness)
+{
+  GtkWidget *preview;
+  GtkWidget *frame;
+  
+  frame = gtk_frame_new(NULL);
+  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
+  gtk_container_set_border_width (GTK_CONTAINER(frame),0);
+  gtk_widget_show(frame);</para>
+
+<para>  preview=gtk_preview_new (Colorfulness?GTK_PREVIEW_COLOR
+                                       :GTK_PREVIEW_GRAYSCALE);
+  gtk_preview_size (GTK_PREVIEW (preview), Width, Height);
+  gtk_container_add(GTK_CONTAINER(frame),preview);
+  gtk_widget_show(preview);</para>
+
+<para>  my_preview_rendering_function(preview);
+  return frame;
+}</para>
+
+<para>That's my basic preview. This routine returns the "parent" frame so you can
+place it somewhere else in your interface. Of course, you can pass the
+parent frame to this routine as a parameter. In many situations, however,
+the contents of the preview are changed continually by your application. In
+this case you may want to pass a pointer to the preview to a
+"create_a_preview()" and thus have control of it later.</para>
+
+<para>One more important note that may one day save you a lot of time. Sometimes
+it is desirable to label you preview. For example, you may label the preview
+containing the original image as "Original" and the one containing the
+modified image as "Less Original". It might occur to you to pack the
+preview along with the appropriate label into a vbox. The unexpected caveat
+is that if the label is wider than the preview (which may happen for a
+variety of reasons unforseeable to you, from the dynamic decision on the
+size of the preview to the size of the font) the frame expands and no longer
+fits tightly over the preview. The same problem can probably arise in other
+situations as well.</para>
+
+<para>                                   [Image]</para>
+
+<para>The solution is to place the preview and the label into a 2x1 table and by
+attaching them with the following parameters (this is one possible variations
+of course. The key is no GTK_FILL in the second attachment):</para>
+
+<para>gtk_table_attach(GTK_TABLE(table),label,0,1,0,1,
+                 0,
+                 GTK_EXPAND|GTK_FILL,
+                 0,0);
+gtk_table_attach(GTK_TABLE(table),frame,0,1,1,2,
+                 GTK_EXPAND,
+                 GTK_EXPAND,
+                 0,0);</para>
+
+<para>
+And here's the result:</para>
+
+<para>                                   [Image]</para>
+
+<para>Misc</para>
+
+<para>Making a preview clickable is achieved most easily by placing it in a
+button. It also adds a nice border around the preview and you may not even
+need to place it in a frame. See the Filter Pack Simulation plug-in for an
+example.</para>
+
+<para>This is pretty much it as far as GTK is concerned.</para>
+
+<para>Filling In a Preview</para>
+
+<para>In order to familiarize ourselves with the basics of filling in previews,
+let's create the following pattern (contrived by trial and error):</para>
+
+<para>                                   [Image]</para>
+
+<para>void
+my_preview_rendering_function(GtkWidget     *preview)
+{
+#define SIZE 100
+#define HALF (SIZE/2)</para>
+
+<para>  guchar *row=(guchar *) malloc(3*SIZE); /* 3 bits per dot */
+  gint i, j;                             /* Coordinates    */
+  double r, alpha, x, y;</para>
+
+<para>  if (preview==NULL) return; /* I usually add this when I want */
+                             /* to avoid silly crashes. You    */
+                             /* should probably make sure that */
+                             /* everything has been nicely     */
+                             /* initialized!                   */
+  for (j=0; j < ABS(cos(2*alpha)) ) { /* Are we inside the shape?  */
+                                         /* glib.h contains ABS(x).   */
+        row[i*3+0] = sqrt(1-r)*255;      /* Define Red                */
+        row[i*3+1] = 128;                /* Define Green              */
+        row[i*3+2] = 224;                /* Define Blue               */
+      }                                  /* "+0" is for alignment!    */
+      else {
+        row[i*3+0] = r*255;
+        row[i*3+1] = ABS(sin((float)i/SIZE*2*PI))*255;
+        row[i*3+2] = ABS(sin((float)j/SIZE*2*PI))*255;
+      }
+    }
+    gtk_preview_draw_row( GTK_PREVIEW(preview),row,0,j,SIZE);
+    /* Insert "row" into "preview" starting at the point with  */
+    /* coordinates (0,j) first column, j_th row extending SIZE */
+    /* pixels to the right */
+  }</para>
+
+<para>  free(row); /* save some space */
+  gtk_widget_draw(preview,NULL); /* what does this do? */
+  gdk_flush(); /* or this? */
+}</para>
+
+<para>Non-GIMP users can have probably seen enough to do a lot of things already.
+For the GIMP users I have a few pointers to add.</para>
+
+<para>Image Preview</para>
+
+<para>It is probably wise to keep a reduced version of the image around with just
+enough pixels to fill the preview. This is done by selecting every n'th
+pixel where n is the ratio of the size of the image to the size of the
+preview. All further operations (including filling in the previews) are then
+performed on the reduced number of pixels only. The following is my
+implementation of reducing the image. (Keep in mind that I've had only basic
+C!)</para>
+
+<para>(UNTESTED CODE ALERT!!!)</para>
+
+<para>typedef struct {
+  gint      width;
+  gint      height;
+  gint      bbp;
+  guchar    *rgb;
+  guchar    *mask;
+} ReducedImage;</para>
+
+<para>enum {
+  SELECTION_ONLY,
+  SELECTION_IN_CONTEXT,
+  ENTIRE_IMAGE
+};</para>
+
+<para>ReducedImage *Reduce_The_Image(GDrawable *drawable,
+                               GDrawable *mask,
+                               gint LongerSize,
+                               gint Selection)
+{
+  /* This function reduced the image down to the the selected preview size */
+  /* The preview size is determine by LongerSize, i.e., the greater of the  */
+  /* two dimensions. Works for RGB images only!                            */
+  gint RH, RW;          /* Reduced height and reduced width                */
+  gint width, height;   /* Width and Height of the area being reduced      */
+  gint bytes=drawable->bpp;
+  ReducedImage *temp=(ReducedImage *)malloc(sizeof(ReducedImage));</para>
+
+<para>  guchar *tempRGB, *src_row, *tempmask, *src_mask_row,R,G,B;
+  gint i, j, whichcol, whichrow, x1, x2, y1, y2;
+  GPixelRgn srcPR, srcMask;
+  gint NoSelectionMade=TRUE; /* Assume that we're dealing with the entire  */
+                             /* image.                                     */</para>
+
+<para>  gimp_drawable_mask_bounds (drawable->id, &amp;x1, &amp;y1, &amp;x2, &amp;y2);
+  width  = x2-x1;
+  height = y2-y1;
+  /* If there's a SELECTION, we got its bounds!)</para>
+
+<para>  if (width != drawable->width &amp;&amp; height != drawable->height)
+    NoSelectionMade=FALSE;
+  /* Become aware of whether the user has made an active selection   */
+  /* This will become important later, when creating a reduced mask. */</para>
+
+<para>  /* If we want to preview the entire image, overrule the above!  */
+  /* Of course, if no selection has been made, this does nothing! */
+  if (Selection==ENTIRE_IMAGE) {
+    x1=0;
+    x2=drawable->width;
+    y1=0;
+    y2=drawable->height;
+  }</para>
+
+<para>  /* If we want to preview a selection with some surrounding area we */
+  /* have to expand it a little bit. Consider it a bit of a riddle. */
+  if (Selection==SELECTION_IN_CONTEXT) {
+    x1=MAX(0,                x1-width/2.0);
+    x2=MIN(drawable->width,  x2+width/2.0);
+    y1=MAX(0,                y1-height/2.0);
+    y2=MIN(drawable->height, y2+height/2.0);
+  }</para>
+
+<para>  /* How we can determine the width and the height of the area being */
+  /* reduced.                                                        */
+  width  = x2-x1;
+  height = y2-y1;</para>
+
+<para>  /* The lines below determine which dimension is to be the longer   */
+  /* side. The idea borrowed from the supernova plug-in. I suspect I */
+  /* could've thought of it myself, but the truth must be told.      */
+  /* Plagiarism stinks!                                               */
+  if (width>height) {
+    RW=LongerSize;
+    RH=(float) height * (float) LongerSize/ (float) width;
+  }
+  else {
+    RH=LongerSize;
+    RW=(float)width * (float) LongerSize/ (float) height;
+  }</para>
+
+<para>  /* The entire image is stretched into a string! */
+  tempRGB   = (guchar *) malloc(RW*RH*bytes);
+  tempmask  = (guchar *) malloc(RW*RH);</para>
+
+<para>  gimp_pixel_rgn_init (&amp;srcPR, drawable, x1, y1, width, height,
+                       FALSE, FALSE);
+  gimp_pixel_rgn_init (&amp;srcMask, mask, x1, y1, width, height,
+                       FALSE, FALSE);</para>
+
+<para>  /* Grab enough to save a row of image and a row of mask. */
+  src_row       = (guchar *) malloc (width*bytes);
+  src_mask_row  = (guchar *) malloc (width);</para>
+
+<para>  for (i=0; i < RH; i++) {
+    whichrow=(float)i*(float)height/(float)RH;
+    gimp_pixel_rgn_get_row (&amp;srcPR, src_row, x1, y1+whichrow, width);
+    gimp_pixel_rgn_get_row (&amp;srcMask, src_mask_row, x1, y1+whichrow, width);</para>
+
+<para>    for (j=0; j < RW; j++) {
+      whichcol=(float)j*(float)width/(float)RW;</para>
+
+<para>      /* No selection made = each point is completely selected! */
+      if (NoSelectionMade)
+        tempmask[i*RW+j]=255;
+      else
+        tempmask[i*RW+j]=src_mask_row[whichcol];</para>
+
+<para>      /* Add the row to the one long string which now contains the image! */
+      tempRGB[i*RW*bytes+j*bytes+0]=src_row[whichcol*bytes+0];
+      tempRGB[i*RW*bytes+j*bytes+1]=src_row[whichcol*bytes+1];
+      tempRGB[i*RW*bytes+j*bytes+2]=src_row[whichcol*bytes+2];</para>
+
+<para>      /* Hold on to the alpha as well */
+      if (bytes==4)
+        tempRGB[i*RW*bytes+j*bytes+3]=src_row[whichcol*bytes+3];
+    }
+  }
+  temp->bpp=bytes;
+  temp->width=RW;
+  temp->height=RH;
+  temp->rgb=tempRGB;
+  temp->mask=tempmask;
+  return temp;
+}</para>
+
+<para>The following is a preview function which used the same ReducedImage type!
+Note that it uses fakes transparency (if one is present by means of
+fake_transparency which is defined as follows:</para>
+
+<para>gint fake_transparency(gint i, gint j)
+{
+  if ( ((i%20)- 10) * ((j%20)- 10)>0   )
+    return 64;
+  else
+    return 196;
+}</para>
+
+<para>Now here's the preview function:</para>
+
+<para>void
+my_preview_render_function(GtkWidget     *preview,
+                           gint          changewhat,
+                           gint          changewhich)
+{
+  gint Inten, bytes=drawable->bpp;
+  gint i, j, k;
+  float partial;
+  gint RW=reduced->width;
+  gint RH=reduced->height;
+  guchar *row=malloc(bytes*RW);;</para>
+
+<para>
+  for (i=0; i < RH; i++) {
+    for (j=0; j < RW; j++) {</para>
+
+<para>      row[j*3+0] = reduced->rgb[i*RW*bytes + j*bytes + 0];
+      row[j*3+1] = reduced->rgb[i*RW*bytes + j*bytes + 1];
+      row[j*3+2] = reduced->rgb[i*RW*bytes + j*bytes + 2];</para>
+
+<para>      if (bytes==4)
+        for (k=0; k<3; k++) {
+          float transp=reduced->rgb[i*RW*bytes+j*bytes+3]/255.0;
+          row[3*j+k]=transp*a[3*j+k]+(1-transp)*fake_transparency(i,j);
+        }
+    }
+    gtk_preview_draw_row( GTK_PREVIEW(preview),row,0,i,RW);
+  }</para>
+
+<para>  free(a);
+  gtk_widget_draw(preview,NULL);
+  gdk_flush();
+}</para>
+
+<para>Applicable Routines</para>
+
+<para>guint           gtk_preview_get_type           (void);
+/* No idea */
+void            gtk_preview_uninit             (void);
+/* No idea */
+GtkWidget*      gtk_preview_new                (GtkPreviewType   type);
+/* Described above */
+void            gtk_preview_size               (GtkPreview      *preview,
+                                                gint             width,
+                                                gint             height);
+/* Allows you to resize an existing preview.    */
+/* Apparently there's a bug in GTK which makes  */
+/* this process messy. A way to clean up a mess */
+/* is to manually resize the window containing  */
+/* the preview after resizing the preview.      */</para>
+
+<para>void            gtk_preview_put                (GtkPreview      *preview,
+                                                GdkWindow       *window,
+                                                GdkGC           *gc,
+                                                gint             srcx,
+                                                gint             srcy,
+                                                gint             destx,
+                                                gint             desty,
+                                                gint             width,
+                                                gint             height);
+/* No idea */</para>
+
+<para>void            gtk_preview_put_row            (GtkPreview      *preview,
+                                                guchar          *src,
+                                                guchar          *dest,
+                                                gint             x,
+                                                gint             y,
+                                                gint             w);
+/* No idea */</para>
+
+<para>void            gtk_preview_draw_row           (GtkPreview      *preview,
+                                                guchar          *data,
+                                                gint             x,
+                                                gint             y,
+                                                gint             w);
+/* Described in the text */</para>
+
+<para>void            gtk_preview_set_expand         (GtkPreview      *preview,
+                                                gint             expand);
+/* No idea */</para>
+
+<para>/* No clue for any of the below but    */
+/* should be standard for most widgets */
+void            gtk_preview_set_gamma          (double           gamma);
+void            gtk_preview_set_color_cube     (guint            nred_shades,
+                                                guint            ngreen_shades,
+                                                guint            nblue_shades,
+                                                guint            ngray_shades);
+void            gtk_preview_set_install_cmap   (gint             install_cmap);
+void            gtk_preview_set_reserved       (gint             nreserved);
+GdkVisual*      gtk_preview_get_visual         (void);
+GdkColormap*    gtk_preview_get_cmap           (void);
+GtkPreviewInfo* gtk_preview_get_info           (void);</para>
+
+<para>That's all, folks!</para>
+
+<para></verb></tscreen></para>
+
+-->
+
+</sect1>
+</chapter>
+
+<!-- ***************************************************************** -->
+<chapter id="ch-SettingWidgetAttributes">
+<title>Setting Widget Attributes</title>
+
+<para>This describes the functions used to operate on widgets. These can be
+used to set style, padding, size, etc.</para>
+
+<para>(Maybe I should make a whole section on accelerators.)</para>
+
+<para><literallayout>
+<literal>void gtk_widget_install_accelerator( GtkWidget           *widget,
+                                     GtkAcceleratorTable *table,
+                                     gchar               *signal_name,
+                                     gchar                key,
+                                     guint8               modifiers );</para>
+
+<para>void gtk_widget_remove_accelerator ( GtkWidget           *widget,
+                                     GtkAcceleratorTable *table,
+                                     gchar               *signal_name);</para>
+
+<para>void gtk_widget_activate( GtkWidget *widget );</para>
+
+<para>void gtk_widget_set_name( GtkWidget *widget,
+                          gchar     *name );</para>
+
+<para>gchar *gtk_widget_get_name( GtkWidget *widget );</para>
+
+<para>void gtk_widget_set_sensitive( GtkWidget *widget,
+                               gint       sensitive );</para>
+
+<para>void gtk_widget_set_style( GtkWidget *widget,
+                           GtkStyle  *style );
+                                          
+GtkStyle *gtk_widget_get_style( GtkWidget *widget );</para>
+
+<para>GtkStyle *gtk_widget_get_default_style( void );</para>
+
+<para>void gtk_widget_set_uposition( GtkWidget *widget,
+                               gint       x,
+                               gint       y );</para>
+
+<para>void gtk_widget_set_usize( GtkWidget *widget,
+                           gint       width,
+                           gint       height );</para>
+
+<para>void gtk_widget_grab_focus( GtkWidget *widget );</para>
+
+<para>void gtk_widget_show( GtkWidget *widget );</para>
+
+<para>void gtk_widget_hide( GtkWidget *widget );</literal>
+</literallayout></para>
+
+</chapter>
+
+<!-- ***************************************************************** -->
+<chapter id="ch-Timeouts">
+<title>Timeouts, IO and Idle Functions</title>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Timeouts</title>
+
+<para>You may be wondering how you make GTK do useful work when in gtk_main.
+Well, you have several options. Using the following function you can
+create a timeout function that will be called every "interval"
+milliseconds.</para>
+
+<para><literallayout>
+<literal>gint gtk_timeout_add( guint32     interval,
+                      GtkFunction function,
+                      gpointer    data );</literal>
+</literallayout></para>
+
+<para>The first argument is the number of milliseconds between calls to your
+function. The second argument is the function you wish to have called,
+and the third, the data passed to this callback function. The return
+value is an integer "tag" which may be used to stop the timeout by
+calling:</para>
+
+<para><literallayout>
+<literal>void gtk_timeout_remove( gint tag );</literal>
+</literallayout></para>
+
+<para>You may also stop the timeout function by returning zero or FALSE from
+your callback function. Obviously this means if you want your function
+to continue to be called, it should return a non-zero value,
+i.e., TRUE.</para>
+
+<para>The declaration of your callback should look something like this:</para>
+
+<para><literallayout>
+<literal>gint timeout_callback( gpointer data );</literal>
+</literallayout></para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Monitoring IO</title>
+
+<para>A nifty feature of GDK (the library that underlies GTK), is the
+ability to have it check for data on a file descriptor for you (as
+returned by open(2) or socket(2)). This is especially useful for
+networking applications. The function:</para>
+
+<para><literallayout>
+<literal>gint gdk_input_add( gint              source,
+                    GdkInputCondition condition,
+                    GdkInputFunction  function,
+                    gpointer          data );</literal>
+</literallayout></para>
+
+<para>Where the first argument is the file descriptor you wish to have
+watched, and the second specifies what you want GDK to look for. This
+may be one of:</para>
+
+<itemizedlist>
+<listitem><simpara><literal>GDK_INPUT_READ</literal> - Call your function when there is data
+ready for reading on your file descriptor.</para>
+</simpara>
+</listitem>
+<listitem><simpara>><literal>GDK_INPUT_WRITE</literal> - Call your function when the file
+descriptor is ready for writing.</simpara>
+</listitem>
+</itemizedlist>
+
+<para>As I'm sure you've figured out already, the third argument is the
+function you wish to have called when the above conditions are
+satisfied, and the fourth is the data to pass to this function.</para>
+
+<para>The return value is a tag that may be used to stop GDK from monitoring
+this file descriptor using the following function.</para>
+
+<para><literallayout>
+<literal>void gdk_input_remove( gint tag );</literal>
+</literallayout></para>
+
+<para>The callback function should be declared as:</para>
+
+<para><literallayout>
+<literal>void input_callback( gpointer          data,
+                     gint              source, 
+                     GdkInputCondition condition );</literal>
+</literallayout></para>
+
+<para>Where <literal>source</literal> and <literal>condition</literal> are as specified above.</para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Idle Functions</title>
+
+<para><!-- TODO: Need to check on idle priorities - TRG -->
+What if you have a function which you want to be called when nothing
+else is happening ?</para>
+
+<para><literallayout>
+<literal>gint gtk_idle_add( GtkFunction function,
+                   gpointer    data );</literal>
+</literallayout></para>
+
+<para>This causes GTK to call the specified function whenever nothing else
+is happening.</para>
+
+<para><literallayout>
+<literal>void gtk_idle_remove( gint tag );</literal>
+</literallayout></para>
+
+<para>I won't explain the meaning of the arguments as they follow very much
+like the ones above. The function pointed to by the first argument to
+gtk_idle_add will be called whenever the opportunity arises. As with
+the others, returning FALSE will stop the idle function from being
+called.</para>
+
+</sect1>
+</chapter>
+
+<!-- ***************************************************************** -->
+<chapter id="ch-AdvancedEventsAndSignals">
+<title>Advanced Event and Signal Handling</title>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Signal Functions</title>
+
+<!-- ----------------------------------------------------------------- -->
+<sect2>
+<title>Connecting and Disconnecting Signal Handlers</title>
+
+</para>
+<para><literallayout>
+<literal>guint gtk_signal_connect( GtkObject     *object,
+                          const gchar   *name,
+                          GtkSignalFunc  func,
+                          gpointer       func_data );</para>
+
+<para>guint gtk_signal_connect_after( GtkObject     *object,
+                                const gchar   *name,
+                                GtkSignalFunc  func,
+                                gpointer       func_data );</para>
+
+<para>guint gtk_signal_connect_object( GtkObject     *object,
+                                 const gchar   *name,
+                                 GtkSignalFunc  func,
+                                 GtkObject     *slot_object );</para>
+
+<para>guint gtk_signal_connect_object_after( GtkObject     *object,
+                                       const gchar   *name,
+                                       GtkSignalFunc  func,
+                                       GtkObject     *slot_object );</para>
+
+<para>guint gtk_signal_connect_full( GtkObject          *object,
+                               const gchar        *name,
+                               GtkSignalFunc       func,
+                               GtkCallbackMarshal  marshal,
+                               gpointer            data,
+                               GtkDestroyNotify    destroy_func,
+                               gint                object_signal,
+                               gint                after );</para>
+
+<para>guint gtk_signal_connect_interp( GtkObject          *object,
+                                 const gchar        *name,
+                                 GtkCallbackMarshal  func,
+                                 gpointer            data,
+                                 GtkDestroyNotify    destroy_func,
+                                 gint                after );</para>
+
+<para>void gtk_signal_connect_object_while_alive( GtkObject     *object,
+                                            const gchar   *signal,
+                                            GtkSignalFunc  func,
+                                            GtkObject     *alive_object );</para>
+
+<para>void gtk_signal_connect_while_alive( GtkObject     *object,
+                                     const gchar   *signal,
+                                     GtkSignalFunc  func,
+                                     gpointer       func_data,
+                                     GtkObject     *alive_object );</para>
+
+<para>void gtk_signal_disconnect( GtkObject *object,
+                            guint      handler_id );</para>
+
+<para>void gtk_signal_disconnect_by_func( GtkObject     *object,
+                                    GtkSignalFunc  func,
+                                    gpointer       data );</literal>
+</literallayout></para>
+
+</sect2>
+
+<!-- ----------------------------------------------------------------- -->
+<sect2>
+<title>Blocking and Unblocking Signal Handlers</title>
+
+<para><literallayout>
+<literal>void gtk_signal_handler_block( GtkObject *object,
+                               guint      handler_id);</para>
+
+<para>void gtk_signal_handler_block_by_func( GtkObject     *object,
+                                       GtkSignalFunc  func,
+                                       gpointer       data );</para>
+
+<para>void gtk_signal_handler_block_by_data( GtkObject *object,
+                                       gpointer   data );</para>
+
+<para>void gtk_signal_handler_unblock( GtkObject *object,
+                                 guint      handler_id );</para>
+
+<para>void gtk_signal_handler_unblock_by_func( GtkObject     *object,
+                                         GtkSignalFunc  func,
+                                         gpointer       data );</para>
+
+<para>void gtk_signal_handler_unblock_by_data( GtkObject *object,
+                                         gpointer   data );</literal>
+</literallayout></para>
+
+</sect2>
+
+<!-- ----------------------------------------------------------------- -->
+<sect2>
+<title>Emitting and Stopping Signals</title>
+
+<para><literallayout>
+<literal>void gtk_signal_emit( GtkObject *object,
+                      guint      signal_id,
+                      ... );</para>
+
+<para>void gtk_signal_emit_by_name( GtkObject   *object,
+                              const gchar *name,
+                              ... );</para>
+
+<para>void gtk_signal_emitv( GtkObject *object,
+                       guint      signal_id,
+                       GtkArg    *params );</para>
+
+<para>void gtk_signal_emitv_by_name( GtkObject   *object,
+                               const gchar *name,
+                               GtkArg      *params );</para>
+
+<para>guint gtk_signal_n_emissions( GtkObject *object,
+                              guint      signal_id );</para>
+
+<para>guint gtk_signal_n_emissions_by_name( GtkObject   *object,
+                                      const gchar *name );</para>
+
+<para>void gtk_signal_emit_stop( GtkObject *object,
+                           guint      signal_id );</para>
+
+<para>void gtk_signal_emit_stop_by_name( GtkObject   *object,
+                                   const gchar *name );</literal>
+</literallayout></para>
+
+</sect2>
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Signal Emission and Propagation</title>
+
+<para>Signal emission is the process whereby GTK runs all handlers for a
+specific object and signal.</para>
+
+<para>First, note that the return value from a signal emission is the return
+value of the <emphasis>last</emphasis> handler executed. Since event signals are
+all of type <literal>GTK_RUN_LAST</literal>, this will be the default (GTK supplied)
+handler, unless you connect with gtk_signal_connect_after().</para>
+
+<para>The way an event (say "button_press_event") is handled, is:
+<itemizedlist>
+<listitem><simpara>Start with the widget where the event occured.</para>
+</simpara>
+</listitem>
+<listitem><simpara>Emit the generic "event" signal. If that signal handler returns
+a value of TRUE, stop all processing.</para>
+</simpara>
+</listitem>
+<listitem><simpara>Otherwise, emit a specific, "button_press_event" signal. If that
+returns TRUE, stop all processing.</para>
+</simpara>
+</listitem>
+<listitem><simpara>Otherwise, go to the widget's parent, and repeat the above two
+steps.</para>
+</simpara>
+</listitem>
+<listitem><simpara>Continue until some signal handler returns TRUE, or until the
+top-level widget is reached.</simpara>
+</listitem>
+</itemizedlist>
+
+<para>Some consequences of the above are:
+<itemizedlist>
+<listitem><simpara>Your handler's return value will have no effect if there is a
+default handler, unless you connect with gtk_signal_connect_after().</para>
+</simpara>
+</listitem>
+<listitem><simpara>To prevent the default handler from being run, you need to
+connect with gtk_signal_connect() and use
+gtk_signal_emit_stop_by_name() - the return value only affects whether
+the signal is propagated, not the current emission.</simpara>
+</listitem>
+</itemizedlist>
+
+</sect1>
+</chapter>
+
+<!-- ***************************************************************** -->
+<chapter id="ch-ManagingSelections">
+<title>Managing Selections</title>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> Overview</title>
+
+<para>One type of interprocess communication supported by X and GTK is
+<emphasis>selections</emphasis>. A selection identifies a chunk of data, for
+instance, a portion of text, selected by the user in some fashion, for
+instance, by dragging with the mouse. Only one application on a
+display (the <emphasis>owner</emphasis>) can own a particular selection at one
+time, so when a selection is claimed by one application, the previous
+owner must indicate to the user that selection has been
+relinquished. Other applications can request the contents of a
+selection in different forms, called <emphasis>targets</emphasis>. There can be
+any number of selections, but most X applications only handle one, the
+<emphasis>primary selection</emphasis>.</para>
+
+<para>In most cases, it isn't necessary for a GTK application to deal with
+selections itself. The standard widgets, such as the Entry widget,
+already have the capability to claim the selection when appropriate
+(e.g., when the user drags over text), and to retrieve the contents of
+the selection owned by another widget or another application (e.g.,
+when the user clicks the second mouse button). However, there may be
+cases in which you want to give other widgets the ability to supply
+the selection, or you wish to retrieve targets not supported by
+default.</para>
+
+<para>A fundamental concept needed to understand selection handling is that
+of the <emphasis>atom</emphasis>. An atom is an integer that uniquely identifies a
+string (on a certain display). Certain atoms are predefined by the X
+server, and in some cases there are constants in <literal>gtk.h</literal>
+corresponding to these atoms. For instance the constant
+<literal>GDK_PRIMARY_SELECTION</literal> corresponds to the string "PRIMARY".
+In other cases, you should use the functions
+<literal>gdk_atom_intern()</literal>, to get the atom corresponding to a string,
+and <literal>gdk_atom_name()</literal>, to get the name of an atom. Both
+selections and targets are identified by atoms.</para>
+
+</sect1>
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> Retrieving the selection</title>
+
+<para>Retrieving the selection is an asynchronous process. To start the
+process, you call:</para>
+
+<para><literallayout>
+<literal>gint gtk_selection_convert( GtkWidget *widget, 
+                            GdkAtom    selection, 
+                            GdkAtom    target,
+                            guint32    time );
+</verb</tscreen></para>
+
+<para>This <emphasis>converts</emphasis> the selection into the form specified by
+<literal>target</literal>. If at all possible, the time field should be the time
+from the event that triggered the selection. This helps make sure that
+events occur in the order that the user requested them. However, if it
+is not available (for instance, if the conversion was triggered by a
+"clicked" signal), then you can use the constant
+<literal>GDK_CURRENT_TIME</literal>.</para>
+
+<para>When the selection owner responds to the request, a
+"selection_received" signal is sent to your application. The handler
+for this signal receives a pointer to a <literal>GtkSelectionData</literal>
+structure, which is defined as:</para>
+
+<para><literallayout>
+<literal>struct _GtkSelectionData
+{
+  GdkAtom selection;
+  GdkAtom target;
+  GdkAtom type;
+  gint    format;
+  guchar *data;
+  gint    length;
+};</literal>
+</literallayout></para>
+
+<para><literal>selection</literal> and <literal>target</literal> are the values you gave in your
+<literal>gtk_selection_convert()</literal> call. <literal>type</literal> is an atom that
+identifies the type of data returned by the selection owner. Some
+possible values are "STRING", a string of latin-1 characters, "ATOM",
+a series of atoms, "INTEGER", an integer, etc. Most targets can only
+return one type. <literal>format</literal> gives the length of the units (for
+instance characters) in bits. Usually, you don't care about this when
+receiving data. <literal>data</literal> is a pointer to the returned data, and
+<literal>length</literal> gives the length of the returned data, in bytes. If
+<literal>length</literal> is negative, then an error occurred and the selection
+could not be retrieved. This might happen if no application owned the
+selection, or if you requested a target that the application didn't
+support. The buffer is actually guaranteed to be one byte longer than
+<literal>length</literal>; the extra byte will always be zero, so it isn't
+necessary to make a copy of strings just to null terminate them.</para>
+
+<para>In the following example, we retrieve the special target "TARGETS",
+which is a list of all targets into which the selection can be
+converted.</para>
+
+<programlisting role="C">
+/* example-start selection gettargets.c */
+
+#include &lt;gtk/gtk.h&gt;
+
+void selection_received( GtkWidget        *widget, 
+                         GtkSelectionData *selection_data, 
+                         gpointer          data );
+
+/* Signal handler invoked when user clicks on the "Get Targets" button */
+void get_targets( GtkWidget *widget,
+                  gpointer data )
+{
+  static GdkAtom targets_atom = GDK_NONE;
+
+  /* Get the atom corresponding to the string "TARGETS" */
+  if (targets_atom == GDK_NONE)
+    targets_atom = gdk_atom_intern ("TARGETS", FALSE);
+
+  /* And request the "TARGETS" target for the primary selection */
+  gtk_selection_convert (widget, GDK_SELECTION_PRIMARY, targets_atom,
+                        GDK_CURRENT_TIME);
+}
+
+/* Signal handler called when the selections owner returns the data */
+void selection_received( GtkWidget        *widget,
+                         GtkSelectionData *selection_data, 
+                        gpointer          data )
+{
+  GdkAtom *atoms;
+  GList *item_list;
+  int i;
+
+  /* **** IMPORTANT **** Check to see if retrieval succeeded  */
+  if (selection_data->length < 0)
+    {
+      g_print ("Selection retrieval failed\n");
+      return;
+    }
+  /* Make sure we got the data in the expected form */
+  if (selection_data->type != GDK_SELECTION_TYPE_ATOM)
+    {
+      g_print ("Selection \"TARGETS\" was not returned as atoms!\n");
+      return;
+    }
+  
+  /* Print out the atoms we received */
+  atoms = (GdkAtom *)selection_data->data;
+
+  item_list = NULL;
+  for (i=0; i<selection_data->length/sizeof(GdkAtom); i++)
+    {
+      char *name;
+      name = gdk_atom_name (atoms[i]);
+      if (name != NULL)
+       g_print ("%s\n",name);
+      else
+       g_print ("(bad atom)\n");
+    }
+
+  return;
+}
+
+int main( int   argc,
+          char *argv[] )
+{
+  GtkWidget *window;
+  GtkWidget *button;
+  
+  gtk_init (&amp;argc, &amp;argv);
+
+  /* Create the toplevel window */
+
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_window_set_title (GTK_WINDOW (window), "Event Box");
+  gtk_container_set_border_width (GTK_CONTAINER (window), 10);
+
+  gtk_signal_connect (GTK_OBJECT (window), "destroy",
+                     GTK_SIGNAL_FUNC (gtk_exit), NULL);
+
+  /* Create a button the user can click to get targets */
+
+  button = gtk_button_new_with_label ("Get Targets");
+  gtk_container_add (GTK_CONTAINER (window), button);
+
+  gtk_signal_connect (GTK_OBJECT(button), "clicked",
+                     GTK_SIGNAL_FUNC (get_targets), NULL);
+  gtk_signal_connect (GTK_OBJECT(button), "selection_received",
+                     GTK_SIGNAL_FUNC (selection_received), NULL);
+
+  gtk_widget_show (button);
+  gtk_widget_show (window);
+  
+  gtk_main ();
+  
+  return 0;
+}
+/* example-end */
+</programlisting>
+
+</sect1>
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> Supplying the selection </title>
+
+<para>Supplying the selection is a bit more complicated. You must register 
+handlers that will be called when your selection is requested. For
+each selection/target pair you will handle, you make a call to:</para>
+
+<para><literallayout>
+<literal>void gtk_selection_add_target (GtkWidget           *widget, 
+                               GdkAtom              selection,
+                               GdkAtom              target,
+                               guint                info);</literal>
+</literallayout></para>
+
+<para><literal>widget</literal>, <literal>selection</literal>, and <literal>target</literal> identify the requests
+this handler will manage. When a request for a selection is received,
+the "selection_get" signal will be called. <literal>info</literal> can be used as an
+enumerator to identify the specific target within the callback function.</para>
+
+<para>The callback function has the signature:</para>
+
+<para><literallayout>
+<literal>void  "selection_get" (GtkWidget          *widget,
+                       GtkSelectionData   *selection_data,
+                       guint               info,
+                       guint               time);</literal>
+</literallayout></para>
+
+<para>The GtkSelectionData is the same as above, but this time, we're
+responsible for filling in the fields <literal>type</literal>, <literal>format</literal>,
+<literal>data</literal>, and <literal>length</literal>. (The <literal>format</literal> field is actually
+important here - the X server uses it to figure out whether the data
+needs to be byte-swapped or not. Usually it will be 8 - <emphasis>i.e.</emphasis> a
+character - or 32 - <emphasis>i.e.</emphasis> a. integer.) This is done by calling the
+function:</para>
+
+<para><literallayout>
+<literal>void gtk_selection_data_set( GtkSelectionData *selection_data,
+                             GdkAtom           type,
+                             gint              format,
+                             guchar           *data,
+                             gint              length );</literal>
+</literallayout></para>
+
+<para>This function takes care of properly making a copy of the data so that
+you don't have to worry about keeping it around. (You should not fill
+in the fields of the GtkSelectionData structure by hand.)</para>
+
+<para>When prompted by the user, you claim ownership of the selection by
+calling:</para>
+
+<para><literallayout>
+<literal>gint gtk_selection_owner_set( GtkWidget *widget,
+                              GdkAtom    selection,
+                              guint32    time );</literal>
+</literallayout></para>
+
+<para>If another application claims ownership of the selection, you will
+receive a "selection_clear_event".</para>
+
+<para>As an example of supplying the selection, the following program adds
+selection functionality to a toggle button. When the toggle button is
+depressed, the program claims the primary selection. The only target
+supported (aside from certain targets like "TARGETS" supplied by GTK
+itself), is the "STRING" target. When this target is requested, a
+string representation of the time is returned.</para>
+
+<programlisting role="C">
+/* example-start selection setselection.c */
+
+#include &lt;gtk/gtk.h&gt;
+#include &lt;time.h&gt;
+
+/* Callback when the user toggles the selection */
+void selection_toggled( GtkWidget *widget,
+                        gint      *have_selection )
+{
+  if (GTK_TOGGLE_BUTTON(widget)->active)
+    {
+      *have_selection = gtk_selection_owner_set (widget,
+                                                GDK_SELECTION_PRIMARY,
+                                                GDK_CURRENT_TIME);
+      /* if claiming the selection failed, we return the button to
+        the out state */
+      if (!*have_selection)
+       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(widget), FALSE);
+    }
+  else
+    {
+      if (*have_selection)
+       {
+         /* Before clearing the selection by setting the owner to NULL,
+            we check if we are the actual owner */
+         if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window)
+           gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY,
+                                    GDK_CURRENT_TIME);
+         *have_selection = FALSE;
+       }
+    }
+}
+
+/* Called when another application claims the selection */
+gint selection_clear( GtkWidget         *widget,
+                      GdkEventSelection *event,
+                      gint              *have_selection )
+{
+  *have_selection = FALSE;
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(widget), FALSE);
+
+  return TRUE;
+}
+
+/* Supplies the current time as the selection. */
+void selection_handle( GtkWidget        *widget, 
+                       GtkSelectionData *selection_data,
+                       guint             info,
+                       guint             time_stamp,
+                       gpointer          data )
+{
+  gchar *timestr;
+  time_t current_time;
+
+  current_time = time(NULL);
+  timestr = asctime (localtime(&amp;current_time)); 
+  /* When we return a single string, it should not be null terminated.
+     That will be done for us */
+
+  gtk_selection_data_set (selection_data, GDK_SELECTION_TYPE_STRING,
+                         8, timestr, strlen(timestr));
+}
+
+int main( int   argc,
+          char *argv[] )
+{
+  GtkWidget *window;
+  GtkWidget *selection_button;
+
+  static int have_selection = FALSE;
+  
+  gtk_init (&amp;argc, &amp;argv);
+
+  /* Create the toplevel window */
+
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_window_set_title (GTK_WINDOW (window), "Event Box");
+  gtk_container_set_border_width (GTK_CONTAINER (window), 10);
+
+  gtk_signal_connect (GTK_OBJECT (window), "destroy",
+                     GTK_SIGNAL_FUNC (gtk_exit), NULL);
+
+  /* Create a toggle button to act as the selection */
+
+  selection_button = gtk_toggle_button_new_with_label ("Claim Selection");
+  gtk_container_add (GTK_CONTAINER (window), selection_button);
+  gtk_widget_show (selection_button);
+
+  gtk_signal_connect (GTK_OBJECT(selection_button), "toggled",
+                     GTK_SIGNAL_FUNC (selection_toggled), &amp;have_selection);
+  gtk_signal_connect (GTK_OBJECT(selection_button), "selection_clear_event",
+                     GTK_SIGNAL_FUNC (selection_clear), &amp;have_selection);
+
+  gtk_selection_add_target (selection_button,
+                           GDK_SELECTION_PRIMARY,
+                           GDK_SELECTION_TYPE_STRING,
+                           1);
+  gtk_signal_connect (GTK_OBJECT(selection_button), "selection_get",
+                     GTK_SIGNAL_FUNC (selection_handle), &amp;have_selection);
+
+  gtk_widget_show (selection_button);
+  gtk_widget_show (window);
+  
+  gtk_main ();
+  
+  return 0;
+}
+/* example-end */
+</programlisting>
+
+</sect1>
+</chapter>
+
+<!-- ***************************************************************** -->
+<chapter id="ch-GLib">
+<title>GLib</title>
+
+<para>GLib is a lower-level library that provides many useful definitions
+and functions available for use when creating GDK and GTK
+applications. These include definitions for basic types and their
+limits, standard macros, type conversions, byte order, memory
+allocation, warnings and assertions, message logging, timers, string
+utilities, hook functions, a lexical scanner, dynamic loading of
+modules, and automatic string completion. A number of data structures
+(and their related operations) are also defined, including memory
+chunks, doubly-linked lists, singly-linked lists, hash tables, strings
+(which can grow dynamically), string chunks (groups of strings),
+arrays (which can grow in size as elements are added), balanced binary
+trees, N-ary trees, quarks (a two-way association of a string and a
+unique integer identifier), keyed data lists (lists of data elements
+accessible by a string or integer id), relations and tuples (tables of
+data which can be indexed on any number of fields), and caches.</para>
+
+<para>A summary of some of GLib's capabilities follows; not every function,
+data structure, or operation is covered here.  For more complete
+information about the GLib routines, see the GLib documentation. One
+source of GLib documentation is <ulink url="http://www.gtk.org/"> http://www.gtk.org/ </ulink>.</para>
+
+<para>If you are using a language other than C, you should consult your
+language's binding documentation. In some cases your language may
+have equivalent functionality built-in, while in other cases it may
+not.</para>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Definitions</title>
+
+<para>Definitions for the extremes of many of the standard types are:</para>
+
+<para><literallayout>
+<literal>G_MINFLOAT
+G_MAXFLOAT
+G_MINDOUBLE
+G_MAXDOUBLE
+G_MINSHORT
+G_MAXSHORT
+G_MININT
+G_MAXINT
+G_MINLONG
+G_MAXLONG</literal>
+</literallayout></para>
+
+<para>Also, the following typedefs. The ones left unspecified are dynamically set
+depending on the architecture. Remember to avoid counting on the size of a
+pointer if you want to be portable! E.g., a pointer on an Alpha is 8
+bytes, but 4 on Intel 80x86 family CPUs.</para>
+
+<para><literallayout>
+<literal>char   gchar;
+short  gshort;
+long   glong;
+int    gint;
+char   gboolean;</para>
+
+<para>unsigned char   guchar;
+unsigned short  gushort;
+unsigned long   gulong;
+unsigned int    guint;</para>
+
+<para>float   gfloat;
+double  gdouble;
+long double gldouble;</para>
+
+<para>void* gpointer;</para>
+
+<para>gint8
+guint8
+gint16
+guint16
+gint32
+guint32</literal>
+</literallayout></para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Doubly Linked Lists</title>
+
+<para>The following functions are used to create, manage, and destroy
+standard doubly linked lists. Each element in the list contains a
+piece of data, together with pointers which link to the previous and
+next elements in the list. This enables easy movement in either
+direction through the list. The data item is of type "gpointer",
+which means the data can be a pointer to your real data or (through
+casting) a numeric value (but do not assume that int and gpointer have
+the same size!). These routines internally allocate list elements in
+blocks, which is more efficient than allocating elements individually.</para>
+
+<para>There is no function to specifically create a list. Instead, simply
+create a variable of type GList* and set its value to NULL; NULL is
+considered to be the empty list.</para>
+
+<para>To add elements to a list, use the g_list_append(), g_list_prepend(),
+g_list_insert(), or g_list_insert_sorted() routines. In all cases
+they accept a pointer to the beginning of the list, and return the
+(possibly changed) pointer to the beginning of the list. Thus, for
+all of the operations that add or remove elements, be sure to save the
+returned value!</para>
+
+<para><literallayout>
+<literal>GList *g_list_append( GList    *list,
+                      gpointer  data );</literal>
+</literallayout></para>
+
+<para>This adds a new element (with value <literal>data</literal>) onto the end of the
+list.
+  
+<tscreen><verb>           
+GList *g_list_prepend( GList    *list,
+                       gpointer  data );</literal>
+</literallayout></para>
+
+<para>This adds a new element (with value <literal>data</literal>) to the beginning of the
+list.</para>
+
+<para><tscreen><verb>          
+GList *g_list_insert( GList    *list,
+                      gpointer  data,
+                      gint      position );</para>
+
+<para></verb></tscreen></para>
+
+<para>This inserts a new element (with value data) into the list at the
+given position. If position is 0, this is just like g_list_prepend();
+if position is less than 0, this is just like g_list_append().</para>
+
+<para><literallayout>
+<literal>GList *g_list_remove( GList    *list,
+                      gpointer  data );</literal>
+</literallayout></para>
+
+<para>This removes the element in the list with the value <literal>data</literal>;
+if the element isn't there, the list is unchanged.</para>
+
+<para><literallayout>
+<literal>void g_list_free( GList *list );</literal>
+</literallayout></para>
+
+<para>This frees all of the memory used by a GList. If the list elements
+refer to dynamically-allocated memory, then they should be freed
+first.</para>
+
+<para>There are many other GLib functions that support doubly linked lists;
+see the glib documentation for more information.  Here are a few of
+the more useful functions' signatures:</para>
+
+<para><tscreen><verb>             
+GList *g_list_remove_link( GList *list,
+                           GList *link );</para>
+
+<para>GList *g_list_reverse( GList *list );</para>
+
+<para>GList *g_list_nth( GList *list,
+                   gint   n );
+                          
+GList *g_list_find( GList    *list,
+                    gpointer  data );</para>
+
+<para>GList *g_list_last( GList *list );</para>
+
+<para>GList *g_list_first( GList *list );</para>
+
+<para>gint g_list_length( GList *list );</para>
+
+<para>void g_list_foreach( GList    *list,
+                     GFunc     func,
+                     gpointer  user_data );
+</verb></tscreen>
+</para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Singly Linked Lists</title>
+
+<para>Many of the above functions for singly linked lists are identical to the
+above. Here is a list of some of their operations:</para>
+
+<para><literallayout>
+<literal>GSList *g_slist_append( GSList   *list,
+                        gpointer  data );
+               
+GSList *g_slist_prepend( GSList   *list,
+                         gpointer  data );
+                            
+GSList *g_slist_insert( GSList   *list,
+                        gpointer  data,
+                       gint      position );
+                            
+GSList *g_slist_remove( GSList   *list,
+                        gpointer  data );
+                            
+GSList *g_slist_remove_link( GSList *list,
+                             GSList *link );
+                            
+GSList *g_slist_reverse( GSList *list );</para>
+
+<para>GSList *g_slist_nth( GSList *list,
+                     gint    n );
+                            
+GSList *g_slist_find( GSList   *list,
+                      gpointer  data );
+                            
+GSList *g_slist_last( GSList *list );</para>
+
+<para>gint g_slist_length( GSList *list );</para>
+
+<para>void g_slist_foreach( GSList   *list,
+                      GFunc     func,
+                      gpointer  user_data );
+       </literal>
+</literallayout></para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Memory Management</title>
+
+<para><literallayout>
+<literal>gpointer g_malloc( gulong size );</literal>
+</literallayout></para>
+
+<para>This is a replacement for malloc(). You do not need to check the return
+value as it is done for you in this function. If the memory allocation
+fails for whatever reasons, your applications will be terminated.</para>
+
+<para><literallayout>
+<literal>gpointer g_malloc0( gulong size );</literal>
+</literallayout></para>
+
+<para>Same as above, but zeroes the memory before returning a pointer to it.</para>
+
+<para><literallayout>
+<literal>gpointer g_realloc( gpointer mem,
+                    gulong   size );</literal>
+</literallayout></para>
+
+<para>Relocates "size" bytes of memory starting at "mem".  Obviously, the
+memory should have been previously allocated.</para>
+
+<para><literallayout>
+<literal>void g_free( gpointer mem );</literal>
+</literallayout></para>
+
+<para>Frees memory. Easy one. If <literal>mem</literal> is NULL it simply returns.</para>
+
+<para><literallayout>
+<literal>void g_mem_profile( void );</literal>
+</literallayout></para>
+
+<para>Dumps a profile of used memory, but requires that you add <literal>#define
+MEM_PROFILE</literal> to the top of glib/gmem.c and re-make and make install.</para>
+
+<para><literallayout>
+<literal>void g_mem_check( gpointer mem );</literal>
+</literallayout></para>
+
+<para>Checks that a memory location is valid. Requires you add <literal>#define
+MEM_CHECK</literal> to the top of gmem.c and re-make and make install.</para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Timers</title>
+
+<para>Timer functions can be used to time operations (e.g., to see how much
+time has elapsed). First, you create a new timer with g_timer_new().
+You can then use g_timer_start() to start timing an operation,
+g_timer_stop() to stop timing an operation, and g_timer_elapsed() to
+determine the elapsed time.</para>
+
+<para><literallayout>
+<literal>GTimer *g_timer_new( void );</para>
+
+<para>void g_timer_destroy( GTimer *timer );</para>
+
+<para>void g_timer_start( GTimer  *timer );</para>
+
+<para>void g_timer_stop( GTimer  *timer );</para>
+
+<para>void g_timer_reset( GTimer  *timer );</para>
+
+<para>gdouble g_timer_elapsed( GTimer *timer,
+                         gulong *microseconds );
+</verb></tscreen>                       </para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>String Handling</title>
+
+<para>GLib defines a new type called a GString, which is similar to a
+standard C string but one that grows automatically. Its string data
+is null-terminated. What this gives you is protection from buffer
+overflow programming errors within your program. This is a very
+important feature, and hence I recommend that you make use of
+GStrings. GString itself has a simple public definition:</para>
+
+<para><literallayout>
+<literal>struct GString 
+{
+  gchar *str; /* Points to the string's current \0-terminated value. */
+  gint len; /* Current length */
+};</literal>
+</literallayout></para>
+
+<para>As you might expect, there are a number of operations you can do with
+a GString.</para>
+
+<para><literallayout>
+<literal>GString *g_string_new( gchar *init );</literal>
+</literallayout></para>
+
+<para>This constructs a GString, copying the string value of <literal>init</literal>
+into the GString and returning a pointer to it. NULL may be given as
+the argument for an initially empty GString.
+<tscreen><verb></para>
+
+<para>void g_string_free( GString *string,
+                    gint     free_segment );</literal>
+</literallayout></para>
+
+<para>This frees the memory for the given GString. If <literal>free_segment</literal> is
+TRUE, then this also frees its character data.</para>
+
+<para><literallayout>
+<literal>                           
+GString *g_string_assign( GString     *lval,
+                          const gchar *rval );</literal>
+</literallayout></para>
+
+<para>This copies the characters from rval into lval, destroying the
+previous contents of lval. Note that lval will be lengthened as
+necessary to hold the string's contents, unlike the standard strcpy()
+function.</para>
+
+<para>The rest of these functions should be relatively obvious (the _c
+versions accept a character instead of a string):</para>
+
+<para><tscreen><verb>               
+GString *g_string_truncate( GString *string,
+                            gint     len );
+                            
+GString *g_string_append( GString *string,
+                          gchar   *val );
+                           
+GString *g_string_append_c( GString *string,
+                            gchar    c );
+       
+GString *g_string_prepend( GString *string,
+                           gchar   *val );
+                            
+GString *g_string_prepend_c( GString *string,
+                             gchar    c );
+       
+void g_string_sprintf( GString *string,
+                       gchar   *fmt,
+                       ...);
+       
+void g_string_sprintfa ( GString *string,
+                         gchar   *fmt,
+                         ... );
+</verb></tscreen>
+</para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Utility and Error Functions</title>
+
+<para><literallayout>
+<literal>gchar *g_strdup( const gchar *str );</literal>
+</literallayout></para>
+
+<para>Replacement strdup function.  Copies the original strings contents to
+newly allocated memory, and returns a pointer to it.</para>
+
+<para><literallayout>
+<literal>gchar *g_strerror( gint errnum );</literal>
+</literallayout></para>
+
+<para>I recommend using this for all error messages.  It's much nicer, and more
+portable than perror() or others.  The output is usually of the form:</para>
+
+<para><literallayout>
+<literal>program name:function that failed:file or further description:strerror</literal>
+</literallayout></para>
+
+<para>Here's an example of one such call used in our hello_world program:</para>
+
+<para><literallayout>
+<literal>g_print("hello_world:open:%s:%s\n", filename, g_strerror(errno));</literal>
+</literallayout></para>
+
+<para><literallayout>
+<literal>void g_error( gchar *format, ... );</literal>
+</literallayout></para>
+
+<para>Prints an error message. The format is just like printf, but it
+prepends "** ERROR **: " to your message, and exits the program.  
+Use only for fatal errors.</para>
+
+<para><literallayout>
+<literal>void g_warning( gchar *format, ... );</literal>
+</literallayout></para>
+
+<para>Same as above, but prepends "** WARNING **: ", and does not exit the
+program.</para>
+
+<para><literallayout>
+<literal>void g_message( gchar *format, ... );</literal>
+</literallayout></para>
+
+<para>Prints "message: " prepended to the string you pass in.</para>
+
+<para><literallayout>
+<literal>void g_print( gchar *format, ... );</literal>
+</literallayout></para>
+
+<para>Replacement for printf().</para>
+
+<para>And our last function:</para>
+
+<para><literallayout>
+<literal>gchar *g_strsignal( gint signum );</literal>
+</literallayout></para>
+
+<para>Prints out the name of the Unix system signal given the signal number.
+Useful in generic signal handling functions.</para>
+
+<para>All of the above are more or less just stolen from glib.h.  If anyone cares
+to document any function, just send me an email!</para>
+
+</sect1>
+</chapter>
+
+<!-- ***************************************************************** -->
+<chapter id="ch-GTKRCFiles">
+<title>GTK's rc Files</title>
+
+<para>GTK has its own way of dealing with application defaults, by using rc
+files. These can be used to set the colors of just about any widget, and
+can also be used to tile pixmaps onto the background of some widgets.  </para>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Functions For rc Files </title>
+
+<para>When your application starts, you should include a call to:</para>
+
+<para><literallayout>
+<literal>void gtk_rc_parse( char *filename );</literal>
+</literallayout></para>
+
+<para>Passing in the filename of your rc file. This will cause GTK to parse
+this file, and use the style settings for the widget types defined
+there.</para>
+
+<para>If you wish to have a special set of widgets that can take on a
+different style from others, or any other logical division of widgets,
+use a call to:</para>
+
+<para><literallayout>
+<literal>void gtk_widget_set_name( GtkWidget *widget,
+                          gchar     *name );</literal>
+</literallayout></para>
+
+<para>Passing your newly created widget as the first argument, and the name
+you wish to give it as the second. This will allow you to change the
+attributes of this widget by name through the rc file.</para>
+
+<para>If we use a call something like this:</para>
+
+<para><literallayout>
+<literal>button = gtk_button_new_with_label ("Special Button");
+gtk_widget_set_name (button, "special button");</literal>
+</literallayout></para>
+
+<para>Then this button is given the name "special button" and may be addressed by
+name in the rc file as "special button.GtkButton".  [<--- Verify ME!]</para>
+
+<para>The example rc file below, sets the properties of the main window, and lets
+all children of that main window inherit the style described by the "main
+button" style.  The code used in the application is:</para>
+
+<para><literallayout>
+<literal>window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+gtk_widget_set_name (window, "main window");</literal>
+</literallayout></para>
+
+<para>And then the style is defined in the rc file using:</para>
+
+<para><literallayout>
+<literal>widget "main window.*GtkButton*" style "main_button"</literal>
+</literallayout></para>
+
+<para>Which sets all the Button widgets in the "main window" to the
+"main_buttons" style as defined in the rc file.</para>
+
+<para>As you can see, this is a fairly powerful and flexible system.  Use your
+imagination as to how best to take advantage of this.</para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>GTK's rc File Format</title>
+
+<para>The format of the GTK file is illustrated in the example below. This is
+the testgtkrc file from the GTK distribution, but I've added a
+few comments and things. You may wish to include this explanation in
+your application to allow the user to fine tune his application.</para>
+
+<para>There are several directives to change the attributes of a widget.</para>
+
+<itemizedlist>
+<listitem><simpara>fg - Sets the foreground color of a widget.</simpara>
+</listitem>
+<listitem><simpara>bg - Sets the background color of a widget.</simpara>
+</listitem>
+<listitem><simpara>bg_pixmap - Sets the background of a widget to a tiled pixmap.</simpara>
+</listitem>
+<listitem><simpara>font - Sets the font to be used with the given widget.</simpara>
+</listitem>
+</itemizedlist>
+
+<para>In addition to this, there are several states a widget can be in, and you
+can set different colors, pixmaps and fonts for each state. These states are:</para>
+
+<itemizedlist>
+<listitem><simpara>NORMAL - The normal state of a widget, without the mouse over top of
+it, and not being pressed, etc.</simpara>
+</listitem>
+<listitem><simpara>PRELIGHT - When the mouse is over top of the widget, colors defined
+using this state will be in effect.</simpara>
+</listitem>
+<listitem><simpara>ACTIVE - When the widget is pressed or clicked it will be active, and
+the attributes assigned by this tag will be in effect.</simpara>
+</listitem>
+<listitem><simpara>INSENSITIVE - When a widget is set insensitive, and cannot be
+activated, it will take these attributes.</simpara>
+</listitem>
+<listitem><simpara>SELECTED - When an object is selected, it takes these attributes.</simpara>
+</listitem>
+</itemizedlist>
+
+<para>When using the "fg" and "bg" keywords to set the colors of widgets, the
+format is:</para>
+
+<para><literallayout>
+<literal>fg[<STATE>] = { Red, Green, Blue }</literal>
+</literallayout></para>
+
+<para>Where STATE is one of the above states (PRELIGHT, ACTIVE, etc), and the Red,
+Green and Blue are values in the range of 0 - 1.0,  { 1.0, 1.0, 1.0 } being
+white. They must be in float form, or they will register as 0, so a straight 
+"1" will not work, it must be "1.0".  A straight "0" is fine because it 
+doesn't matter if it's not recognized.  Unrecognized values are set to 0.</para>
+
+<para>bg_pixmap is very similar to the above, except the colors are replaced by a
+filename.</para>
+
+<para>pixmap_path is a list of paths separated by ":"'s.  These paths will be
+searched for any pixmap you specify.</para>
+
+<para>The font directive is simply:</para>
+<para><literallayout>
+<literal>font = "<font name>"</literal>
+</literallayout></para>
+
+<para>The only hard part is figuring out the font string. Using xfontsel or
+a similar utility should help.</para>
+
+<para>The "widget_class" sets the style of a class of widgets. These classes are
+listed in the widget overview on the class hierarchy.</para>
+
+<para>The "widget" directive sets a specifically named set of widgets to a
+given style, overriding any style set for the given widget class.
+These widgets are registered inside the application using the
+gtk_widget_set_name() call. This allows you to specify the attributes of a
+widget on a per widget basis, rather than setting the attributes of an
+entire widget class. I urge you to document any of these special widgets so
+users may customize them.</para>
+
+<para>When the keyword <literal>parent</> is used as an attribute, the widget will take on
+the attributes of its parent in the application.</para>
+
+<para>When defining a style, you may assign the attributes of a previously defined
+style to this new one.</para>
+
+<para><literallayout>
+<literal>style "main_button" = "button"
+{
+  font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
+  bg[PRELIGHT] = { 0.75, 0, 0 }
+}</literal>
+</literallayout></para>
+
+<para>This example takes the "button" style, and creates a new "main_button" style
+simply by changing the font and prelight background color of the "button"
+style.</para>
+
+<para>Of course, many of these attributes don't apply to all widgets. It's a
+simple matter of common sense really. Anything that could apply, should.</para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Example rc file</title>
+
+<para><literallayout>
+<literal># pixmap_path "<dir 1>:<dir 2>:<dir 3>:..."
+#
+pixmap_path "/usr/include/X11R6/pixmaps:/home/imain/pixmaps"
+#
+# style <name> [= <name>]
+# {
+#   <option>
+# }
+#
+# widget <widget_set> style <style_name>
+# widget_class <widget_class_set> style <style_name></para>
+
+<para>
+# Here is a list of all the possible states.  Note that some do not apply to
+# certain widgets.
+#
+# NORMAL - The normal state of a widget, without the mouse over top of
+# it, and not being pressed, etc.
+#
+# PRELIGHT - When the mouse is over top of the widget, colors defined
+# using this state will be in effect.
+#
+# ACTIVE - When the widget is pressed or clicked it will be active, and
+# the attributes assigned by this tag will be in effect.
+#
+# INSENSITIVE - When a widget is set insensitive, and cannot be
+# activated, it will take these attributes.
+#
+# SELECTED - When an object is selected, it takes these attributes.
+#
+# Given these states, we can set the attributes of the widgets in each of
+# these states using the following directives.
+#
+# fg - Sets the foreground color of a widget.
+# fg - Sets the background color of a widget.
+# bg_pixmap - Sets the background of a widget to a tiled pixmap.
+# font - Sets the font to be used with the given widget.
+#</para>
+
+<para># This sets a style called "button".  The name is not really important, as
+# it is assigned to the actual widgets at the bottom of the file.</para>
+
+<para>style "window"
+{
+  #This sets the padding around the window to the pixmap specified.
+  #bg_pixmap[<STATE>] = "<pixmap filename>"
+  bg_pixmap[NORMAL] = "warning.xpm"
+}</para>
+
+<para>style "scale"
+{
+  #Sets the foreground color (font color) to red when in the "NORMAL"
+  #state.
+  
+  fg[NORMAL] = { 1.0, 0, 0 }
+  
+  #Sets the background pixmap of this widget to that of its parent.
+  bg_pixmap[NORMAL] = "<parent>"
+}</para>
+
+<para>style "button"
+{
+  # This shows all the possible states for a button.  The only one that
+  # doesn't apply is the SELECTED state.
+  
+  fg[PRELIGHT] = { 0, 1.0, 1.0 }
+  bg[PRELIGHT] = { 0, 0, 1.0 }
+  bg[ACTIVE] = { 1.0, 0, 0 }
+  fg[ACTIVE] = { 0, 1.0, 0 }
+  bg[NORMAL] = { 1.0, 1.0, 0 }
+  fg[NORMAL] = { .99, 0, .99 }
+  bg[INSENSITIVE] = { 1.0, 1.0, 1.0 }
+  fg[INSENSITIVE] = { 1.0, 0, 1.0 }
+}</para>
+
+<para># In this example, we inherit the attributes of the "button" style and then
+# override the font and background color when prelit to create a new
+# "main_button" style.</para>
+
+<para>style "main_button" = "button"
+{
+  font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
+  bg[PRELIGHT] = { 0.75, 0, 0 }
+}</para>
+
+<para>style "toggle_button" = "button"
+{
+  fg[NORMAL] = { 1.0, 0, 0 }
+  fg[ACTIVE] = { 1.0, 0, 0 }
+  
+  # This sets the background pixmap of the toggle_button to that of its
+  # parent widget (as defined in the application).
+  bg_pixmap[NORMAL] = "<parent>"
+}</para>
+
+<para>style "text"
+{
+  bg_pixmap[NORMAL] = "marble.xpm"
+  fg[NORMAL] = { 1.0, 1.0, 1.0 }
+}</para>
+
+<para>style "ruler"
+{
+  font = "-adobe-helvetica-medium-r-normal--*-80-*-*-*-*-*-*"
+}</para>
+
+<para># pixmap_path "~/.pixmaps"</para>
+
+<para># These set the widget types to use the styles defined above.
+# The widget types are listed in the class hierarchy, but could probably be
+# just listed in this document for the users reference.</para>
+
+<para>widget_class "GtkWindow" style "window"
+widget_class "GtkDialog" style "window"
+widget_class "GtkFileSelection" style "window"
+widget_class "*Gtk*Scale" style "scale"
+widget_class "*GtkCheckButton*" style "toggle_button"
+widget_class "*GtkRadioButton*" style "toggle_button"
+widget_class "*GtkButton*" style "button"
+widget_class "*Ruler" style "ruler"
+widget_class "*GtkText" style "text"</para>
+
+<para># This sets all the buttons that are children of the "main window" to
+# the main_button style.  These must be documented to be taken advantage of.
+widget "main window.*GtkButton*" style "main_button"</literal>
+</literallayout></para>
+
+</sect1>
+</chapter>
+
+<!-- ***************************************************************** -->
+<chapter id="ch-WritingYourOwnWidgets">
+<title>Writing Your Own Widgets </title>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> Overview</title>
+
+<para>Although the GTK distribution comes with many types of widgets that
+should cover most basic needs, there may come a time when you need to
+create your own new widget type. Since GTK uses widget inheritance
+extensively, and there is already a widget that is close to what you want,
+it is often possible to make a useful new widget type in
+just a few lines of code. But before starting work on a new widget, check
+around first to make sure that someone has not already written
+it. This will prevent duplication of effort and keep the number of
+GTK widgets out there to a minimum, which will help keep both the code
+and the interface of different applications consistent. As a flip side
+to this, once you finish your widget, announce it to the world so
+other people can benefit. The best place to do this is probably the
+<literal>gtk-list</literal>.</para>
+
+<para>Complete sources for the example widgets are available at the place you 
+got this tutorial, or from:</para>
+
+<para><ulink url="http://www.gtk.org/~otaylor/gtk/tutorial/"> http://www.gtk.org/~otaylor/gtk/tutorial/ </ulink></para>
+
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> The Anatomy Of A Widget</title>
+
+<para>In order to create a new widget, it is important to have an
+understanding of how GTK objects work. This section is just meant as a
+brief overview. See the reference documentation for the details. </para>
+
+<para>GTK widgets are implemented in an object oriented fashion. However,
+they are implemented in standard C. This greatly improves portability
+and stability over using current generation C++ compilers; however,
+it does mean that the widget writer has to pay attention to some of
+the implementation details. The information common to all instances of
+one class of widgets (e.g., to all Button widgets) is stored in the 
+<emphasis>class structure</emphasis>. There is only one copy of this in
+which is stored information about the class's signals
+(which act like virtual functions in C). To support inheritance, the
+first field in the class structure must be a copy of the parent's
+class structure. The declaration of the class structure of GtkButtton
+looks like:</para>
+
+<para><literallayout>
+<literal>struct _GtkButtonClass
+{
+  GtkContainerClass parent_class;</para>
+
+<para>  void (* pressed)  (GtkButton *button);
+  void (* released) (GtkButton *button);
+  void (* clicked)  (GtkButton *button);
+  void (* enter)    (GtkButton *button);
+  void (* leave)    (GtkButton *button);
+};</literal>
+</literallayout></para>
+
+<para>When a button is treated as a container (for instance, when it is
+resized), its class structure can be cast to GtkContainerClass, and
+the relevant fields used to handle the signals.</para>
+
+<para>There is also a structure for each widget that is created on a
+per-instance basis. This structure has fields to store information that
+is different for each instance of the widget. We'll call this
+structure the <emphasis>object structure</emphasis>. For the Button class, it looks
+like:</para>
+
+<para><literallayout>
+<literal>struct _GtkButton
+{
+  GtkContainer container;</para>
+
+<para>  GtkWidget *child;</para>
+
+<para>  guint in_button : 1;
+  guint button_down : 1;
+};</literal>
+</literallayout></para>
+
+<para>Note that, similar to the class structure, the first field is the
+object structure of the parent class, so that this structure can be
+cast to the parent class' object structure as needed.</para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> Creating a Composite widget</title>
+
+<!-- ----------------------------------------------------------------- -->
+<sect2>
+<title> Introduction</title>
+
+<para>One type of widget that you may be interested in creating is a
+widget that is merely an aggregate of other GTK widgets. This type of
+widget does nothing that couldn't be done without creating new
+widgets, but provides a convenient way of packaging user interface
+elements for reuse. The FileSelection and ColorSelection widgets in
+the standard distribution are examples of this type of widget.</para>
+
+<para>The example widget that we'll create in this section is the Tictactoe
+widget, a 3x3 array of toggle buttons which triggers a signal when all
+three buttons in a row, column, or on one of the diagonals are
+depressed. </para>
+
+</sect2>
+
+<!-- ----------------------------------------------------------------- -->
+<sect2>
+<title> Choosing a parent class</title>
+
+<para>The parent class for a composite widget is typically the container
+class that holds all of the elements of the composite widget. For
+example, the parent class of the FileSelection widget is the
+Dialog class. Since our buttons will be arranged in a table, it
+might seem natural to make our parent class the Table
+class. Unfortunately, this turns out not to work. The creation of a
+widget is divided among two functions - a <literal>WIDGETNAME_new()</literal>
+function that the user calls, and a <literal>WIDGETNAME_init()</literal> function
+which does the basic work of initializing the widget which is
+independent of the arguments passed to the <literal>_new()</literal>
+function. Descendant widgets only call the <literal>_init</literal> function of
+their parent widget. But this division of labor doesn't work well for
+tables, which when created need to know the number of rows and
+columns in the table. Unless we want to duplicate most of the
+functionality of <literal>gtk_table_new()</literal> in our Tictactoe widget, we had
+best avoid deriving it from Table. For that reason, we derive it
+from VBox instead, and stick our table inside the VBox.</para>
+
+</sect2>
+
+<!-- ----------------------------------------------------------------- -->
+<sect2>
+<title> The header file</title>
+
+<para>Each widget class has a header file which declares the object and
+class structures for that widget, along with public functions. 
+A couple of features are worth pointing out. To prevent duplicate
+definitions, we wrap the entire header file in:</para>
+
+<para><literallayout>
+<literal>#ifndef __TICTACTOE_H__
+#define __TICTACTOE_H__
+.
+.
+.
+#endif /* __TICTACTOE_H__ */
+</programlisting>
+
+<para>And to keep C++ programs that include the header file happy, in:</para>
+
+<para><literallayout>
+<literal>#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+.
+.
+.
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+</programlisting>
+
+<para>Along with the functions and structures, we declare three standard
+macros in our header file, <literal>TICTACTOE(obj)</literal>,
+<literal>TICTACTOE_CLASS(klass)</literal>, and <literal>IS_TICTACTOE(obj)</literal>, which cast a
+pointer into a pointer to the object or class structure, and check
+if an object is a Tictactoe widget respectively.</para>
+
+<para>Here is the complete header file:</para>
+
+<programlisting role="C">
+/* tictactoe.h */</para>
+
+<para>#ifndef __TICTACTOE_H__
+#define __TICTACTOE_H__</para>
+
+<para>#include &lt;gdk/gdk.h&gt;
+#include &lt;gtk/gtkvbox.h&gt;</para>
+
+<para>#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */</para>
+
+<para>#define TICTACTOE(obj)          GTK_CHECK_CAST (obj, tictactoe_get_type (), Tictactoe)
+#define TICTACTOE_CLASS(klass)  GTK_CHECK_CLASS_CAST (klass, tictactoe_get_type (), TictactoeClass)
+#define IS_TICTACTOE(obj)       GTK_CHECK_TYPE (obj, tictactoe_get_type ())</para>
+
+<para>
+typedef struct _Tictactoe       Tictactoe;
+typedef struct _TictactoeClass  TictactoeClass;</para>
+
+<para>struct _Tictactoe
+{
+  GtkVBox vbox;
+  
+  GtkWidget *buttons[3][3];
+};</para>
+
+<para>struct _TictactoeClass
+{
+  GtkVBoxClass parent_class;</para>
+
+<para>  void (* tictactoe) (Tictactoe *ttt);
+};</para>
+
+<para>guint          tictactoe_get_type        (void);
+GtkWidget*     tictactoe_new             (void);
+void          tictactoe_clear           (Tictactoe *ttt);</para>
+
+<para>#ifdef __cplusplus
+}
+#endif /* __cplusplus */</para>
+
+<para>#endif /* __TICTACTOE_H__ */</para>
+
+<para></verb></tscreen></para>
+
+</sect2>
+
+<!-- ----------------------------------------------------------------- -->
+<sect2> The <literal>_get_type()</literal> function.</para>
+
+<para>We now continue on to the implementation of our widget. A core
+function for every widget is the function
+<literal>WIDGETNAME_get_type()</literal>. This function, when first called, tells
+GTK about the widget class, and gets an ID that uniquely identifies
+the widget class. Upon subsequent calls, it just returns the ID.</para>
+
+<para><literallayout>
+<literal>guint
+tictactoe_get_type ()
+{
+  static guint ttt_type = 0;</para>
+
+<para>  if (!ttt_type)
+    {
+      GtkTypeInfo ttt_info =
+      {
+       "Tictactoe",
+       sizeof (Tictactoe),
+       sizeof (TictactoeClass),
+       (GtkClassInitFunc) tictactoe_class_init,
+       (GtkObjectInitFunc) tictactoe_init,
+       (GtkArgSetFunc) NULL,
+        (GtkArgGetFunc) NULL
+      };</para>
+
+<para>      ttt_type = gtk_type_unique (gtk_vbox_get_type (), &amp;ttt_info);
+    }</para>
+
+<para>  return ttt_type;
+}</literal>
+</literallayout></para>
+
+<para>The GtkTypeInfo structure has the following definition:</para>
+
+<para><literallayout>
+<literal>struct _GtkTypeInfo
+{
+  gchar *type_name;
+  guint object_size;
+  guint class_size;
+  GtkClassInitFunc class_init_func;
+  GtkObjectInitFunc object_init_func;
+  GtkArgSetFunc arg_set_func;
+  GtkArgGetFunc arg_get_func;
+};</literal>
+</literallayout></para>
+
+<para>The fields of this structure are pretty self-explanatory. We'll ignore
+the <literal>arg_set_func</literal> and <literal>arg_get_func</literal> fields here: they have an important, 
+but as yet largely
+unimplemented, role in allowing widget options to be conveniently set
+from interpreted languages. Once GTK has a correctly filled in copy of
+this structure, it knows how to create objects of a particular widget
+type. </para>
+
+</sect2>
+
+<!-- ----------------------------------------------------------------- -->
+<sect2> The <literal>_class_init()</literal> function</para>
+
+<para>The <literal>WIDGETNAME_class_init()</literal> function initializes the fields of
+the widget's class structure, and sets up any signals for the
+class. For our Tictactoe widget it looks like:</para>
+
+<para><tscreen><verb></para>
+
+<para>enum {
+  TICTACTOE_SIGNAL,
+  LAST_SIGNAL
+};</para>
+
+<para>static gint tictactoe_signals[LAST_SIGNAL] = { 0 };</para>
+
+<para>static void
+tictactoe_class_init (TictactoeClass *class)
+{
+  GtkObjectClass *object_class;</para>
+
+<para>  object_class = (GtkObjectClass*) class;
+  
+  tictactoe_signals[TICTACTOE_SIGNAL] = gtk_signal_new ("tictactoe",
+                                        GTK_RUN_FIRST,
+                                        object_class->type,
+                                        GTK_SIGNAL_OFFSET (TictactoeClass, tictactoe),
+                                        gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);</para>
+
+<para>
+  gtk_object_class_add_signals (object_class, tictactoe_signals, LAST_SIGNAL);</para>
+
+<para>  class->tictactoe = NULL;
+}</literal>
+</literallayout></para>
+
+<para>Our widget has just one signal, the <literal>tictactoe</literal> signal that is
+invoked when a row, column, or diagonal is completely filled in. Not
+every composite widget needs signals, so if you are reading this for
+the first time, you may want to skip to the next section now, as
+things are going to get a bit complicated.</para>
+
+<para>The function:</para>
+
+<para><literallayout>
+<literal>gint gtk_signal_new( const gchar         *name,
+                     GtkSignalRunType     run_type,
+                     GtkType              object_type,
+                     gint                 function_offset,
+                     GtkSignalMarshaller  marshaller,
+                     GtkType              return_val,
+                     guint                nparams,
+                     ...);</literal>
+</literallayout></para>
+
+<para>Creates a new signal. The parameters are:</para>
+
+<itemizedlist>
+<listitem><simpara> <literal>name</literal>: The name of the signal.</simpara>
+</listitem>
+<listitem><simpara> <literal>run_type</literal>: Whether the default handler runs before or after
+user handlers. Usually this will be <literal>GTK_RUN_FIRST</literal>, or <literal>GTK_RUN_LAST</literal>,
+although there are other possibilities.</simpara>
+</listitem>
+<listitem><simpara> <literal>object_type</literal>: The ID of the object that this signal applies
+to. (It will also apply to that objects descendants.)</simpara>
+</listitem>
+<listitem><simpara> <literal>function_offset</literal>: The offset within the class structure of
+a pointer to the default handler.</simpara>
+</listitem>
+<listitem><simpara> <literal>marshaller</literal>: A function that is used to invoke the signal
+handler. For signal handlers that have no arguments other than the
+object that emitted the signal and user data, we can use the
+pre-supplied marshaller function <literal>gtk_signal_default_marshaller</literal>.</simpara>
+</listitem>
+<listitem><simpara> <literal>return_val</literal>: The type of the return val.</simpara>
+</listitem>
+<listitem><simpara> <literal>nparams</literal>: The number of parameters of the signal handler
+(other than the two default ones mentioned above)</simpara>
+</listitem>
+<listitem><simpara> <literal>...</literal>: The types of the parameters.</simpara>
+</listitem>
+</itemizedlist>
+
+<para>When specifying types, the <literal>GtkType</literal> enumeration is used:</para>
+
+<para><literallayout>
+<literal>typedef enum
+{
+  GTK_TYPE_INVALID,
+  GTK_TYPE_NONE,
+  GTK_TYPE_CHAR,
+  GTK_TYPE_BOOL,
+  GTK_TYPE_INT,
+  GTK_TYPE_UINT,
+  GTK_TYPE_LONG,
+  GTK_TYPE_ULONG,
+  GTK_TYPE_FLOAT,
+  GTK_TYPE_DOUBLE,
+  GTK_TYPE_STRING,
+  GTK_TYPE_ENUM,
+  GTK_TYPE_FLAGS,
+  GTK_TYPE_BOXED,
+  GTK_TYPE_FOREIGN,
+  GTK_TYPE_CALLBACK,
+  GTK_TYPE_ARGS,</para>
+
+<para>  GTK_TYPE_POINTER,</para>
+
+<para>  /* it'd be great if the next two could be removed eventually */
+  GTK_TYPE_SIGNAL,
+  GTK_TYPE_C_CALLBACK,</para>
+
+<para>  GTK_TYPE_OBJECT</para>
+
+<para>} GtkFundamentalType;</literal>
+</literallayout></para>
+
+<para><literal>gtk_signal_new()</literal> returns a unique integer identifier for the
+signal, that we store in the <literal>tictactoe_signals</literal> array, which we
+index using an enumeration. (Conventionally, the enumeration elements
+are the signal name, uppercased, but here there would be a conflict
+with the <literal>TICTACTOE()</literal> macro, so we called it <literal>TICTACTOE_SIGNAL</literal>
+instead.</para>
+
+<para>After creating our signals, we need to tell GTK to associate our
+signals with the Tictactoe class. We do that by calling
+<literal>gtk_object_class_add_signals()</literal>. We then set the pointer which
+points to the default handler for the "tictactoe" signal to NULL,
+indicating that there is no default action.</para>
+
+</sect2>
+
+<!-- ----------------------------------------------------------------- -->
+<sect2> The <literal>_init()</literal> function.</para>
+
+<para>Each widget class also needs a function to initialize the object
+structure. Usually, this function has the fairly limited role of
+setting the fields of the structure to default values. For composite
+widgets, however, this function also creates the component widgets.</para>
+
+<para><literallayout>
+<literal>static void
+tictactoe_init (Tictactoe *ttt)
+{
+  GtkWidget *table;
+  gint i,j;
+  
+  table = gtk_table_new (3, 3, TRUE);
+  gtk_container_add (GTK_CONTAINER(ttt), table);
+  gtk_widget_show (table);</para>
+
+<para>  for (i=0;i<3; i++)
+    for (j=0;j<3; j++)
+      {
+       ttt->buttons[i][j] = gtk_toggle_button_new ();
+       gtk_table_attach_defaults (GTK_TABLE(table), ttt->buttons[i][j], 
+                                  i, i+1, j, j+1);
+       gtk_signal_connect (GTK_OBJECT (ttt->buttons[i][j]), "toggled",
+                           GTK_SIGNAL_FUNC (tictactoe_toggle), ttt);
+       gtk_widget_set_usize (ttt->buttons[i][j], 20, 20);
+       gtk_widget_show (ttt->buttons[i][j]);
+      }
+}</literal>
+</literallayout></para>
+
+</sect2>
+
+<!-- ----------------------------------------------------------------- -->
+<sect2>
+<title> And the rest...</title>
+
+<para>There is one more function that every widget (except for base widget
+types like Bin that cannot be instantiated) needs to have - the
+function that the user calls to create an object of that type. This is
+conventionally called <literal>WIDGETNAME_new()</literal>. In some
+widgets, though not for the Tictactoe widgets, this function takes
+arguments, and does some setup based on the arguments. The other two
+functions are specific to the Tictactoe widget. </para>
+
+<para><literal>tictactoe_clear()</literal> is a public function that resets all the
+buttons in the widget to the up position. Note the use of
+<literal>gtk_signal_handler_block_by_data()</literal> to keep our signal handler for
+button toggles from being triggered unnecessarily.</para>
+
+<para><literal>tictactoe_toggle()</literal> is the signal handler that is invoked when the
+user clicks on a button. It checks to see if there are any winning
+combinations that involve the toggled button, and if so, emits
+the "tictactoe" signal.</para>
+
+<para><tscreen><verb>  
+GtkWidget*
+tictactoe_new ()
+{
+  return GTK_WIDGET ( gtk_type_new (tictactoe_get_type ()));
+}</para>
+
+<para>void            
+tictactoe_clear (Tictactoe *ttt)
+{
+  int i,j;</para>
+
+<para>  for (i=0;i<3;i++)
+    for (j=0;j<3;j++)
+      {
+       gtk_signal_handler_block_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
+       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ttt->buttons[i][j]),
+                                    FALSE);
+       gtk_signal_handler_unblock_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
+      }
+}</para>
+
+<para>static void
+tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt)
+{
+  int i,k;</para>
+
+<para>  static int rwins[8][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
+                            { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
+                            { 0, 1, 2 }, { 0, 1, 2 } };
+  static int cwins[8][3] = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
+                            { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
+                            { 0, 1, 2 }, { 2, 1, 0 } };</para>
+
+<para>  int success, found;</para>
+
+<para>  for (k=0; k<8; k++)
+    {
+      success = TRUE;
+      found = FALSE;</para>
+
+<para>      for (i=0;i<3;i++)
+       {
+         success = success &amp;&amp; 
+           GTK_TOGGLE_BUTTON(ttt->buttons[rwins[k][i]][cwins[k][i]])->active;
+         found = found ||
+           ttt->buttons[rwins[k][i]][cwins[k][i]] == widget;
+       }
+      
+      if (success &amp;&amp; found)
+       {
+         gtk_signal_emit (GTK_OBJECT (ttt), 
+                          tictactoe_signals[TICTACTOE_SIGNAL]);
+         break;
+       }
+    }
+}</literal>
+</literallayout></para>
+
+<para>And finally, an example program using our Tictactoe widget:</para>
+
+<para><literallayout>
+<literal>#include &lt;gtk/gtk.h&gt;
+#include "tictactoe.h"</para>
+
+<para>/* Invoked when a row, column or diagonal is completed */
+void
+win (GtkWidget *widget, gpointer data)
+{
+  g_print ("Yay!\n");
+  tictactoe_clear (TICTACTOE (widget));
+}</para>
+
+<para>int 
+main (int argc, char *argv[])
+{
+  GtkWidget *window;
+  GtkWidget *ttt;
+  
+  gtk_init (&amp;argc, &amp;argv);</para>
+
+<para>  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  
+  gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
+  
+  gtk_signal_connect (GTK_OBJECT (window), "destroy",
+                     GTK_SIGNAL_FUNC (gtk_exit), NULL);
+  
+  gtk_container_set_border_width (GTK_CONTAINER (window), 10);</para>
+
+<para>  /* Create a new Tictactoe widget */
+  ttt = tictactoe_new ();
+  gtk_container_add (GTK_CONTAINER (window), ttt);
+  gtk_widget_show (ttt);</para>
+
+<para>  /* And attach to its "tictactoe" signal */
+  gtk_signal_connect (GTK_OBJECT (ttt), "tictactoe",
+                     GTK_SIGNAL_FUNC (win), NULL);</para>
+
+<para>  gtk_widget_show (window);
+  
+  gtk_main ();
+  
+  return 0;
+}</para>
+
+</verb></tscreen>
+
+</sect2>
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> Creating a widget from scratch.</title>
+
+<!-- ----------------------------------------------------------------- -->
+<sect2>
+<title> Introduction</title>
+
+<para>In this section, we'll learn more about how widgets display themselves
+on the screen and interact with events. As an example of this, we'll
+create an analog dial widget with a pointer that the user can drag to
+set the value.</para>
+
+</sect2>
+
+<!-- ----------------------------------------------------------------- -->
+<sect2>
+<title> Displaying a widget on the screen</title>
+
+<para>There are several steps that are involved in displaying on the screen.
+After the widget is created with a call to <literal>WIDGETNAME_new()</literal>,
+several more functions are needed:</para>
+
+<itemizedlist>
+<listitem><simpara> <literal>WIDGETNAME_realize()</literal> is responsible for creating an X
+window for the widget if it has one.</simpara>
+</listitem>
+<listitem><simpara> <literal>WIDGETNAME_map()</literal> is invoked after the user calls
+<literal>gtk_widget_show()</literal>. It is responsible for making sure the widget
+is actually drawn on the screen (<emphasis>mapped</emphasis>). For a container class,
+it must also make calls to <literal>map()</literal>> functions of any child widgets.</simpara>
+</listitem>
+<listitem><simpara> <literal>WIDGETNAME_draw()</literal> is invoked when <literal>gtk_widget_draw()</literal>
+is called for the widget or one of its ancestors. It makes the actual
+calls to the drawing functions to draw the widget on the screen. For
+container widgets, this function must make calls to
+<literal>gtk_widget_draw()</literal> for its child widgets.</simpara>
+</listitem>
+<listitem><simpara> <literal>WIDGETNAME_expose()</literal> is a handler for expose events for the
+widget. It makes the necessary calls to the drawing functions to draw
+the exposed portion on the screen. For container widgets, this
+function must generate expose events for its child widgets which don't
+have their own windows. (If they have their own windows, then X will
+generate the necessary expose events.)</simpara>
+</listitem>
+</itemizedlist>
+
+<para>You might notice that the last two functions are quite similar - each
+is responsible for drawing the widget on the screen. In fact many
+types of widgets don't really care about the difference between the
+two. The default <literal>draw()</literal> function in the widget class simply
+generates a synthetic expose event for the redrawn area. However, some
+types of widgets can save work by distinguishing between the two
+functions. For instance, if a widget has multiple X windows, then
+since expose events identify the exposed window, it can redraw only
+the affected window, which is not possible for calls to <literal>draw()</literal>.</para>
+
+<para>Container widgets, even if they don't care about the difference for
+themselves, can't simply use the default <literal>draw()</literal> function because
+their child widgets might care about the difference. However,
+it would be wasteful to duplicate the drawing code between the two
+functions. The convention is that such widgets have a function called
+<literal>WIDGETNAME_paint()</literal> that does the actual work of drawing the
+widget, that is then called by the <literal>draw()</literal> and <literal>expose()</literal>
+functions.</para>
+
+<para>In our example approach, since the dial widget is not a container
+widget, and only has a single window, we can take the simplest
+approach and use the default <literal>draw()</literal> function and only implement
+an <literal>expose()</literal> function.</para>
+
+</sect2>
+
+<!-- ----------------------------------------------------------------- -->
+<sect2>
+<title> The origins of the Dial Widget</title>
+
+<para>Just as all land animals are just variants on the first amphibian that
+crawled up out of the mud, GTK widgets tend to start off as variants
+of some other, previously written widget. Thus, although this section
+is entitled "Creating a Widget from Scratch", the Dial widget really
+began with the source code for the Range widget. This was picked as a
+starting point because it would be nice if our Dial had the same
+interface as the Scale widgets which are just specialized descendants
+of the Range widget. So, though the source code is presented below in
+finished form, it should not be implied that it was written, <emphasis>ab
+initio</emphasis> in this fashion. Also, if you aren't yet familiar with
+how scale widgets work from the application writer's point of view, it
+would be a good idea to look them over before continuing.</para>
+
+</sect2>
+
+<!-- ----------------------------------------------------------------- -->
+<sect2>
+<title> The Basics</title>
+
+<para>Quite a bit of our widget should look pretty familiar from the
+Tictactoe widget. First, we have a header file:</para>
+
+<programlisting role="C">
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */</para>
+
+<para>#ifndef __GTK_DIAL_H__
+#define __GTK_DIAL_H__</para>
+
+<para>#include &lt;gdk/gdk.h&gt;
+#include &lt;gtk/gtkadjustment.h&gt;
+#include &lt;gtk/gtkwidget.h&gt;</para>
+
+<para>
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */</para>
+
+<para>
+#define GTK_DIAL(obj)          GTK_CHECK_CAST (obj, gtk_dial_get_type (), GtkDial)
+#define GTK_DIAL_CLASS(klass)  GTK_CHECK_CLASS_CAST (klass, gtk_dial_get_type (), GtkDialClass)
+#define GTK_IS_DIAL(obj)       GTK_CHECK_TYPE (obj, gtk_dial_get_type ())</para>
+
+<para>
+typedef struct _GtkDial        GtkDial;
+typedef struct _GtkDialClass   GtkDialClass;</para>
+
+<para>struct _GtkDial
+{
+  GtkWidget widget;</para>
+
+<para>  /* update policy (GTK_UPDATE_[CONTINUOUS/DELAYED/DISCONTINUOUS]) */
+  guint policy : 2;</para>
+
+<para>  /* Button currently pressed or 0 if none */
+  guint8 button;</para>
+
+<para>  /* Dimensions of dial components */
+  gint radius;
+  gint pointer_width;</para>
+
+<para>  /* ID of update timer, or 0 if none */
+  guint32 timer;</para>
+
+<para>  /* Current angle */
+  gfloat angle;</para>
+
+<para>  /* Old values from adjustment stored so we know when something changes */
+  gfloat old_value;
+  gfloat old_lower;
+  gfloat old_upper;</para>
+
+<para>  /* The adjustment object that stores the data for this dial */
+  GtkAdjustment *adjustment;
+};</para>
+
+<para>struct _GtkDialClass
+{
+  GtkWidgetClass parent_class;
+};</para>
+
+<para>
+GtkWidget*     gtk_dial_new                    (GtkAdjustment *adjustment);
+guint          gtk_dial_get_type               (void);
+GtkAdjustment* gtk_dial_get_adjustment         (GtkDial      *dial);
+void           gtk_dial_set_update_policy      (GtkDial      *dial,
+                                               GtkUpdateType  policy);</para>
+
+<para>void           gtk_dial_set_adjustment         (GtkDial      *dial,
+                                               GtkAdjustment *adjustment);
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */</para>
+
+<para>
+#endif /* __GTK_DIAL_H__ */
+</programlisting>
+
+<para>Since there is quite a bit more going on in this widget than the last
+one, we have more fields in the data structure, but otherwise things
+are pretty similar.</para>
+
+<para>Next, after including header files and declaring a few constants,
+we have some functions to provide information about the widget
+and initialize it:</para>
+
+<para><literallayout>
+<literal>#include &lt;math.h&gt;
+#include &lt;stdio.h&gt;
+#include &lt;gtk/gtkmain.h&gt;
+#include &lt;gtk/gtksignal.h&gt;</para>
+
+<para>#include "gtkdial.h"</para>
+
+<para>#define SCROLL_DELAY_LENGTH  300
+#define DIAL_DEFAULT_SIZE 100</para>
+
+<para>/* Forward declarations */</para>
+
+<para>[ omitted to save space ]</para>
+
+<para>/* Local data */</para>
+
+<para>static GtkWidgetClass *parent_class = NULL;</para>
+
+<para>guint
+gtk_dial_get_type ()
+{
+  static guint dial_type = 0;</para>
+
+<para>  if (!dial_type)
+    {
+      GtkTypeInfo dial_info =
+      {
+       "GtkDial",
+       sizeof (GtkDial),
+       sizeof (GtkDialClass),
+       (GtkClassInitFunc) gtk_dial_class_init,
+       (GtkObjectInitFunc) gtk_dial_init,
+       (GtkArgSetFunc) NULL,
+        (GtkArgGetFunc) NULL,
+      };</para>
+
+<para>      dial_type = gtk_type_unique (gtk_widget_get_type (), &amp;dial_info);
+    }</para>
+
+<para>  return dial_type;
+}</para>
+
+<para>static void
+gtk_dial_class_init (GtkDialClass *class)
+{
+  GtkObjectClass *object_class;
+  GtkWidgetClass *widget_class;</para>
+
+<para>  object_class = (GtkObjectClass*) class;
+  widget_class = (GtkWidgetClass*) class;</para>
+
+<para>  parent_class = gtk_type_class (gtk_widget_get_type ());</para>
+
+<para>  object_class->destroy = gtk_dial_destroy;</para>
+
+<para>  widget_class->realize = gtk_dial_realize;
+  widget_class->expose_event = gtk_dial_expose;
+  widget_class->size_request = gtk_dial_size_request;
+  widget_class->size_allocate = gtk_dial_size_allocate;
+  widget_class->button_press_event = gtk_dial_button_press;
+  widget_class->button_release_event = gtk_dial_button_release;
+  widget_class->motion_notify_event = gtk_dial_motion_notify;
+}</para>
+
+<para>static void
+gtk_dial_init (GtkDial *dial)
+{
+  dial->button = 0;
+  dial->policy = GTK_UPDATE_CONTINUOUS;
+  dial->timer = 0;
+  dial->radius = 0;
+  dial->pointer_width = 0;
+  dial->angle = 0.0;
+  dial->old_value = 0.0;
+  dial->old_lower = 0.0;
+  dial->old_upper = 0.0;
+  dial->adjustment = NULL;
+}</para>
+
+<para>GtkWidget*
+gtk_dial_new (GtkAdjustment *adjustment)
+{
+  GtkDial *dial;</para>
+
+<para>  dial = gtk_type_new (gtk_dial_get_type ());</para>
+
+<para>  if (!adjustment)
+    adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);</para>
+
+<para>  gtk_dial_set_adjustment (dial, adjustment);</para>
+
+<para>  return GTK_WIDGET (dial);
+}</para>
+
+<para>static void
+gtk_dial_destroy (GtkObject *object)
+{
+  GtkDial *dial;</para>
+
+<para>  g_return_if_fail (object != NULL);
+  g_return_if_fail (GTK_IS_DIAL (object));</para>
+
+<para>  dial = GTK_DIAL (object);</para>
+
+<para>  if (dial->adjustment)
+    gtk_object_unref (GTK_OBJECT (dial->adjustment));</para>
+
+<para>  if (GTK_OBJECT_CLASS (parent_class)->destroy)
+    (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
+}</literal>
+</literallayout></para>
+
+<para>Note that this <literal>init()</literal> function does less than for the Tictactoe
+widget, since this is not a composite widget, and the <literal>new()</literal>
+function does more, since it now has an argument. Also, note that when
+we store a pointer to the Adjustment object, we increment its
+reference count, (and correspondingly decrement it when we no longer
+use it) so that GTK can keep track of when it can be safely destroyed.</para>
+
+<para>
+<para>Also, there are a few function to manipulate the widget's options:</para>
+
+<para><literallayout>
+<literal>GtkAdjustment*
+gtk_dial_get_adjustment (GtkDial *dial)
+{
+  g_return_val_if_fail (dial != NULL, NULL);
+  g_return_val_if_fail (GTK_IS_DIAL (dial), NULL);</para>
+
+<para>  return dial->adjustment;
+}</para>
+
+<para>void
+gtk_dial_set_update_policy (GtkDial      *dial,
+                            GtkUpdateType  policy)
+{
+  g_return_if_fail (dial != NULL);
+  g_return_if_fail (GTK_IS_DIAL (dial));</para>
+
+<para>  dial->policy = policy;
+}</para>
+
+<para>void
+gtk_dial_set_adjustment (GtkDial      *dial,
+                         GtkAdjustment *adjustment)
+{
+  g_return_if_fail (dial != NULL);
+  g_return_if_fail (GTK_IS_DIAL (dial));</para>
+
+<para>  if (dial->adjustment)
+    {
+      gtk_signal_disconnect_by_data (GTK_OBJECT (dial->adjustment), (gpointer) dial);
+      gtk_object_unref (GTK_OBJECT (dial->adjustment));
+    }</para>
+
+<para>  dial->adjustment = adjustment;
+  gtk_object_ref (GTK_OBJECT (dial->adjustment));</para>
+
+<para>  gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
+                     (GtkSignalFunc) gtk_dial_adjustment_changed,
+                     (gpointer) dial);
+  gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
+                     (GtkSignalFunc) gtk_dial_adjustment_value_changed,
+                     (gpointer) dial);</para>
+
+<para>  dial->old_value = adjustment->value;
+  dial->old_lower = adjustment->lower;
+  dial->old_upper = adjustment->upper;</para>
+
+<para>  gtk_dial_update (dial);
+}</literal>
+</literallayout></para>
+
+<para><sect2> <literal>gtk_dial_realize()</literal></para>
+
+<para>
+<para>Now we come to some new types of functions. First, we have a function
+that does the work of creating the X window. Notice that a mask is
+passed to the function <literal>gdk_window_new()</literal> which specifies which fields of
+the GdkWindowAttr structure actually have data in them (the remaining
+fields will be given default values). Also worth noting is the way the
+event mask of the widget is created. We call
+<literal>gtk_widget_get_events()</literal> to retrieve the event mask that the user
+has specified for this widget (with <literal>gtk_widget_set_events()</literal>), and
+add the events that we are interested in ourselves.</para>
+
+<para>
+<para>After creating the window, we set its style and background, and put a
+pointer to the widget in the user data field of the GdkWindow. This
+last step allows GTK to dispatch events for this window to the correct
+widget.</para>
+
+<para><literallayout>
+<literal>static void
+gtk_dial_realize (GtkWidget *widget)
+{
+  GtkDial *dial;
+  GdkWindowAttr attributes;
+  gint attributes_mask;</para>
+
+<para>  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_DIAL (widget));</para>
+
+<para>  GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
+  dial = GTK_DIAL (widget);</para>
+
+<para>  attributes.x = widget->allocation.x;
+  attributes.y = widget->allocation.y;
+  attributes.width = widget->allocation.width;
+  attributes.height = widget->allocation.height;
+  attributes.wclass = GDK_INPUT_OUTPUT;
+  attributes.window_type = GDK_WINDOW_CHILD;
+  attributes.event_mask = gtk_widget_get_events (widget) | 
+    GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | 
+    GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
+    GDK_POINTER_MOTION_HINT_MASK;
+  attributes.visual = gtk_widget_get_visual (widget);
+  attributes.colormap = gtk_widget_get_colormap (widget);</para>
+
+<para>  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+  widget->window = gdk_window_new (widget->parent->window, &amp;attributes, attributes_mask);</para>
+
+<para>  widget->style = gtk_style_attach (widget->style, widget->window);</para>
+
+<para>  gdk_window_set_user_data (widget->window, widget);</para>
+
+<para>  gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
+}</literal>
+</literallayout></para>
+
+<para><sect2>
+<title> Size negotiation</title>
+
+<para>
+<para>Before the first time that the window containing a widget is
+displayed, and whenever the layout of the window changes, GTK asks
+each child widget for its desired size. This request is handled by the
+function <literal>gtk_dial_size_request()</literal>. Since our widget isn't a
+container widget, and has no real constraints on its size, we just
+return a reasonable default value.</para>
+
+<para><literallayout>
+<literal>static void 
+gtk_dial_size_request (GtkWidget      *widget,
+                      GtkRequisition *requisition)
+{
+  requisition->width = DIAL_DEFAULT_SIZE;
+  requisition->height = DIAL_DEFAULT_SIZE;
+}</literal>
+</literallayout></para>
+
+<para>
+<para>After all the widgets have requested an ideal size, the layout of the
+window is computed and each child widget is notified of its actual
+size. Usually, this will be at least as large as the requested size,
+but if for instance the user has resized the window, it may
+occasionally be smaller than the requested size. The size notification
+is handled by the function <literal>gtk_dial_size_allocate()</literal>. Notice that
+as well as computing the sizes of some component pieces for future
+use, this routine also does the grunt work of moving the widget's X
+window into the new position and size.</para>
+
+<para><literallayout>
+<literal>static void
+gtk_dial_size_allocate (GtkWidget     *widget,
+                       GtkAllocation *allocation)
+{
+  GtkDial *dial;</para>
+
+<para>  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_DIAL (widget));
+  g_return_if_fail (allocation != NULL);</para>
+
+<para>  widget->allocation = *allocation;
+  if (GTK_WIDGET_REALIZED (widget))
+    {
+      dial = GTK_DIAL (widget);</para>
+
+<para>      gdk_window_move_resize (widget->window,
+                             allocation->x, allocation->y,
+                             allocation->width, allocation->height);</para>
+
+<para>      dial->radius = MAX(allocation->width,allocation->height) * 0.45;
+      dial->pointer_width = dial->radius / 5;
+    }
+}
+</verb></tscreen>.</para>
+
+</sect2>
+
+<!-- ----------------------------------------------------------------- -->
+<sect2> <literal>gtk_dial_expose()</literal></para>
+
+<para>
+<para>As mentioned above, all the drawing of this widget is done in the
+handler for expose events. There's not much to remark on here except
+the use of the function <literal>gtk_draw_polygon</literal> to draw the pointer with
+three dimensional shading according to the colors stored in the
+widget's style.</para>
+
+<para><literallayout>
+<literal>static gint
+gtk_dial_expose (GtkWidget      *widget,
+                GdkEventExpose *event)
+{
+  GtkDial *dial;
+  GdkPoint points[3];
+  gdouble s,c;
+  gdouble theta;
+  gint xc, yc;
+  gint tick_length;
+  gint i;</para>
+
+<para>  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);</para>
+
+<para>  if (event->count > 0)
+    return FALSE;
+  
+  dial = GTK_DIAL (widget);</para>
+
+<para>  gdk_window_clear_area (widget->window,
+                        0, 0,
+                        widget->allocation.width,
+                        widget->allocation.height);</para>
+
+<para>  xc = widget->allocation.width/2;
+  yc = widget->allocation.height/2;</para>
+
+<para>  /* Draw ticks */</para>
+
+<para>  for (i=0; i<25; i++)
+    {
+      theta = (i*M_PI/18. - M_PI/6.);
+      s = sin(theta);
+      c = cos(theta);</para>
+
+<para>      tick_length = (i%6 == 0) ? dial->pointer_width : dial->pointer_width/2;
+      
+      gdk_draw_line (widget->window,
+                    widget->style->fg_gc[widget->state],
+                    xc + c*(dial->radius - tick_length),
+                    yc - s*(dial->radius - tick_length),
+                    xc + c*dial->radius,
+                    yc - s*dial->radius);
+    }</para>
+
+<para>  /* Draw pointer */</para>
+
+<para>  s = sin(dial->angle);
+  c = cos(dial->angle);</para>
+
+<para>
+  points[0].x = xc + s*dial->pointer_width/2;
+  points[0].y = yc + c*dial->pointer_width/2;
+  points[1].x = xc + c*dial->radius;
+  points[1].y = yc - s*dial->radius;
+  points[2].x = xc - s*dial->pointer_width/2;
+  points[2].y = yc - c*dial->pointer_width/2;</para>
+
+<para>  gtk_draw_polygon (widget->style,
+                   widget->window,
+                   GTK_STATE_NORMAL,
+                   GTK_SHADOW_OUT,
+                   points, 3,
+                   TRUE);
+  
+  return FALSE;
+}</literal>
+</literallayout></para>
+
+</sect2>
+
+<!-- ----------------------------------------------------------------- -->
+<sect2>
+<title> Event handling</title>
+
+<para>The rest of the widget's code handles various types of events, and
+isn't too different from what would be found in many GTK
+applications. Two types of events can occur - either the user can
+click on the widget with the mouse and drag to move the pointer, or
+the value of the Adjustment object can change due to some external
+circumstance. </para>
+
+<para>When the user clicks on the widget, we check to see if the click was
+appropriately near the pointer, and if so, store the button that the
+user clicked with in the <literal>button</literal> field of the widget
+structure, and grab all mouse events with a call to
+<literal>gtk_grab_add()</literal>. Subsequent motion of the mouse causes the
+value of the control to be recomputed (by the function
+<literal>gtk_dial_update_mouse</literal>). Depending on the policy that has been
+set, "value_changed" events are either generated instantly
+(<literal>GTK_UPDATE_CONTINUOUS</literal>), after a delay in a timer added with
+<literal>gtk_timeout_add()</literal> (<literal>GTK_UPDATE_DELAYED</literal>), or only when the
+button is released (<literal>GTK_UPDATE_DISCONTINUOUS</literal>).</para>
+
+<para><literallayout>
+<literal>static gint
+gtk_dial_button_press (GtkWidget      *widget,
+                      GdkEventButton *event)
+{
+  GtkDial *dial;
+  gint dx, dy;
+  double s, c;
+  double d_parallel;
+  double d_perpendicular;</para>
+
+<para>  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);</para>
+
+<para>  dial = GTK_DIAL (widget);</para>
+
+<para>  /* Determine if button press was within pointer region - we 
+     do this by computing the parallel and perpendicular distance of
+     the point where the mouse was pressed from the line passing through
+     the pointer */
+  
+  dx = event->x - widget->allocation.width / 2;
+  dy = widget->allocation.height / 2 - event->y;
+  
+  s = sin(dial->angle);
+  c = cos(dial->angle);
+  
+  d_parallel = s*dy + c*dx;
+  d_perpendicular = fabs(s*dx - c*dy);
+  
+  if (!dial->button &&
+      (d_perpendicular < dial->pointer_width/2) &&
+      (d_parallel > - dial->pointer_width))
+    {
+      gtk_grab_add (widget);</para>
+
+<para>      dial->button = event->button;</para>
+
+<para>      gtk_dial_update_mouse (dial, event->x, event->y);
+    }</para>
+
+<para>  return FALSE;
+}</para>
+
+<para>static gint
+gtk_dial_button_release (GtkWidget      *widget,
+                         GdkEventButton *event)
+{
+  GtkDial *dial;</para>
+
+<para>  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);</para>
+
+<para>  dial = GTK_DIAL (widget);</para>
+
+<para>  if (dial->button == event->button)
+    {
+      gtk_grab_remove (widget);</para>
+
+<para>      dial->button = 0;</para>
+
+<para>      if (dial->policy == GTK_UPDATE_DELAYED)
+       gtk_timeout_remove (dial->timer);
+      
+      if ((dial->policy != GTK_UPDATE_CONTINUOUS) &&
+         (dial->old_value != dial->adjustment->value))
+       gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
+    }</para>
+
+<para>  return FALSE;
+}</para>
+
+<para>static gint
+gtk_dial_motion_notify (GtkWidget      *widget,
+                        GdkEventMotion *event)
+{
+  GtkDial *dial;
+  GdkModifierType mods;
+  gint x, y, mask;</para>
+
+<para>  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);</para>
+
+<para>  dial = GTK_DIAL (widget);</para>
+
+<para>  if (dial->button != 0)
+    {
+      x = event->x;
+      y = event->y;</para>
+
+<para>      if (event->is_hint || (event->window != widget->window))
+       gdk_window_get_pointer (widget->window, &amp;x, &amp;y, &amp;mods);</para>
+
+<para>      switch (dial->button)
+       {
+       case 1:
+         mask = GDK_BUTTON1_MASK;
+         break;
+       case 2:
+         mask = GDK_BUTTON2_MASK;
+         break;
+       case 3:
+         mask = GDK_BUTTON3_MASK;
+         break;
+       default:
+         mask = 0;
+         break;
+       }</para>
+
+<para>      if (mods & mask)
+       gtk_dial_update_mouse (dial, x,y);
+    }</para>
+
+<para>  return FALSE;
+}</para>
+
+<para>static gint
+gtk_dial_timer (GtkDial *dial)
+{
+  g_return_val_if_fail (dial != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_DIAL (dial), FALSE);</para>
+
+<para>  if (dial->policy == GTK_UPDATE_DELAYED)
+    gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");</para>
+
+<para>  return FALSE;
+}</para>
+
+<para>static void
+gtk_dial_update_mouse (GtkDial *dial, gint x, gint y)
+{
+  gint xc, yc;
+  gfloat old_value;</para>
+
+<para>  g_return_if_fail (dial != NULL);
+  g_return_if_fail (GTK_IS_DIAL (dial));</para>
+
+<para>  xc = GTK_WIDGET(dial)->allocation.width / 2;
+  yc = GTK_WIDGET(dial)->allocation.height / 2;</para>
+
+<para>  old_value = dial->adjustment->value;
+  dial->angle = atan2(yc-y, x-xc);</para>
+
+<para>  if (dial->angle < -M_PI/2.)
+    dial->angle += 2*M_PI;</para>
+
+<para>  if (dial->angle < -M_PI/6)
+    dial->angle = -M_PI/6;</para>
+
+<para>  if (dial->angle > 7.*M_PI/6.)
+    dial->angle = 7.*M_PI/6.;</para>
+
+<para>  dial->adjustment->value = dial->adjustment->lower + (7.*M_PI/6 - dial->angle) *
+    (dial->adjustment->upper - dial->adjustment->lower) / (4.*M_PI/3.);</para>
+
+<para>  if (dial->adjustment->value != old_value)
+    {
+      if (dial->policy == GTK_UPDATE_CONTINUOUS)
+       {
+         gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
+       }
+      else
+       {
+         gtk_widget_draw (GTK_WIDGET(dial), NULL);</para>
+
+<para>   if (dial->policy == GTK_UPDATE_DELAYED)
+           {
+             if (dial->timer)
+               gtk_timeout_remove (dial->timer);</para>
+
+<para>       dial->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
+                                            (GtkFunction) gtk_dial_timer,
+                                            (gpointer) dial);
+           }
+       }
+    }
+}</literal>
+</literallayout></para>
+
+<para>Changes to the Adjustment by external means are communicated to our
+widget by the "changed" and "value_changed" signals. The handlers
+for these functions call <literal>gtk_dial_update()</literal> to validate the
+arguments, compute the new pointer angle, and redraw the widget (by
+calling <literal>gtk_widget_draw()</literal>).</para>
+
+<para><literallayout>
+<literal>static void
+gtk_dial_update (GtkDial *dial)
+{
+  gfloat new_value;
+  
+  g_return_if_fail (dial != NULL);
+  g_return_if_fail (GTK_IS_DIAL (dial));</para>
+
+<para>  new_value = dial->adjustment->value;
+  
+  if (new_value < dial->adjustment->lower)
+    new_value = dial->adjustment->lower;</para>
+
+<para>  if (new_value > dial->adjustment->upper)
+    new_value = dial->adjustment->upper;</para>
+
+<para>  if (new_value != dial->adjustment->value)
+    {
+      dial->adjustment->value = new_value;
+      gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
+    }</para>
+
+<para>  dial->angle = 7.*M_PI/6. - (new_value - dial->adjustment->lower) * 4.*M_PI/3. /
+    (dial->adjustment->upper - dial->adjustment->lower);</para>
+
+<para>  gtk_widget_draw (GTK_WIDGET(dial), NULL);
+}</para>
+
+<para>static void
+gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
+                             gpointer       data)
+{
+  GtkDial *dial;</para>
+
+<para>  g_return_if_fail (adjustment != NULL);
+  g_return_if_fail (data != NULL);</para>
+
+<para>  dial = GTK_DIAL (data);</para>
+
+<para>  if ((dial->old_value != adjustment->value) ||
+      (dial->old_lower != adjustment->lower) ||
+      (dial->old_upper != adjustment->upper))
+    {
+      gtk_dial_update (dial);</para>
+
+<para>      dial->old_value = adjustment->value;
+      dial->old_lower = adjustment->lower;
+      dial->old_upper = adjustment->upper;
+    }
+}</para>
+
+<para>static void
+gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
+                                   gpointer       data)
+{
+  GtkDial *dial;</para>
+
+<para>  g_return_if_fail (adjustment != NULL);
+  g_return_if_fail (data != NULL);</para>
+
+<para>  dial = GTK_DIAL (data);</para>
+
+<para>  if (dial->old_value != adjustment->value)
+    {
+      gtk_dial_update (dial);</para>
+
+<para>      dial->old_value = adjustment->value;
+    }
+}</literal>
+</literallayout></para>
+
+</sect2>
+
+<!-- ----------------------------------------------------------------- -->
+<sect2>
+<title> Possible Enhancements</title>
+
+<para>The Dial widget as we've described it so far runs about 670 lines of
+code. Although that might sound like a fair bit, we've really
+accomplished quite a bit with that much code, especially since much of
+that length is headers and boilerplate. However, there are quite a few
+more enhancements that could be made to this widget:</para>
+
+<itemizedlist>
+<listitem><simpara> If you try this widget out, you'll find that there is some
+flashing as the pointer is dragged around. This is because the entire
+widget is erased every time the pointer is moved before being
+redrawn. Often, the best way to handle this problem is to draw to an
+offscreen pixmap, then copy the final results onto the screen in one
+step. (The ProgressBar widget draws itself in this fashion.)</para>
+</simpara>
+</listitem>
+<listitem><simpara> The user should be able to use the up and down arrow keys to
+increase and decrease the value.</para>
+</simpara>
+</listitem>
+<listitem><simpara> It would be nice if the widget had buttons to increase and
+decrease the value in small or large steps. Although it would be
+possible to use embedded Button widgets for this, we would also like
+the buttons to auto-repeat when held down, as the arrows on a
+scrollbar do. Most of the code to implement this type of behavior can
+be found in the Range widget.</para>
+</simpara>
+</listitem>
+<listitem><simpara> The Dial widget could be made into a container widget with a
+single child widget positioned at the bottom between the buttons
+mentioned above. The user could then add their choice of a label or
+entry widget to display the current value of the dial.</para>
+
+<para></itemizedlist>
+
+</sect2>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> Learning More</title>
+
+<para>
+<para>Only a small part of the many details involved in creating widgets
+could be described above. If you want to write your own widgets, the
+best source of examples is the GTK source itself. Ask yourself some
+questions about the widget you want to write: IS it a Container
+widget? Does it have its own window? Is it a modification of an
+existing widget? Then find a similar widget, and start making changes.
+Good luck!</para>
+
+</sect1>
+</chapter>
+
+<!-- ***************************************************************** -->
+<chapter id="ch-Scribble">
+<title>Scribble, A Simple Example Drawing Program</title>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> Overview</title>
+
+<para>In this section, we will build a simple drawing program. In the
+process, we will examine how to handle mouse events, how to draw in a
+window, and how to do drawing better by using a backing pixmap. After
+creating the simple drawing program, we will extend it by adding
+support for XInput devices, such as drawing tablets. GTK provides
+support routines which makes getting extended information, such as
+pressure and tilt, from such devices quite easy.</para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> Event Handling</title>
+
+<para>The GTK signals we have already discussed are for high-level actions,
+such as a menu item being selected. However, sometimes it is useful to
+learn about lower-level occurrences, such as the mouse being moved, or
+a key being pressed. There are also GTK signals corresponding to these
+low-level <emphasis>events</emphasis>. The handlers for these signals have an
+extra parameter which is a pointer to a structure containing
+information about the event. For instance, motion event handlers are
+passed a pointer to a GdkEventMotion structure which looks (in part)
+like:</para>
+
+<para><literallayout>
+<literal>struct _GdkEventMotion
+{
+  GdkEventType type;
+  GdkWindow *window;
+  guint32 time;
+  gdouble x;
+  gdouble y;
+  ...
+  guint state;
+  ...
+};</literal>
+</literallayout></para>
+
+<para><literal>type</literal> will be set to the event type, in this case
+<literal>GDK_MOTION_NOTIFY</literal>, window is the window in which the event
+occurred. <literal>x</literal> and <literal>y</literal> give the coordinates of the event.
+<literal>state</literal> specifies the modifier state when the event
+occurred (that is, it specifies which modifier keys and mouse buttons
+were pressed). It is the bitwise OR of some of the following:</para>
+
+<para><literallayout>
+<literal>GDK_SHIFT_MASK  
+GDK_LOCK_MASK   
+GDK_CONTROL_MASK
+GDK_MOD1_MASK   
+GDK_MOD2_MASK   
+GDK_MOD3_MASK   
+GDK_MOD4_MASK   
+GDK_MOD5_MASK   
+GDK_BUTTON1_MASK
+GDK_BUTTON2_MASK
+GDK_BUTTON3_MASK
+GDK_BUTTON4_MASK
+GDK_BUTTON5_MASK</literal>
+</literallayout></para>
+
+<para>As for other signals, to determine what happens when an event occurs
+we call <literal>gtk_signal_connect()</literal>. But we also need let GTK
+know which events we want to be notified about. To do this, we call
+the function:</para>
+
+<para><literallayout>
+<literal>void gtk_widget_set_events (GtkWidget *widget,
+                            gint      events);</literal>
+</literallayout></para>
+
+<para>The second field specifies the events we are interested in. It
+is the bitwise OR of constants that specify different types
+of events. For future reference the event types are:</para>
+
+<para><literallayout>
+<literal>GDK_EXPOSURE_MASK
+GDK_POINTER_MOTION_MASK
+GDK_POINTER_MOTION_HINT_MASK
+GDK_BUTTON_MOTION_MASK     
+GDK_BUTTON1_MOTION_MASK    
+GDK_BUTTON2_MOTION_MASK    
+GDK_BUTTON3_MOTION_MASK    
+GDK_BUTTON_PRESS_MASK      
+GDK_BUTTON_RELEASE_MASK    
+GDK_KEY_PRESS_MASK         
+GDK_KEY_RELEASE_MASK       
+GDK_ENTER_NOTIFY_MASK      
+GDK_LEAVE_NOTIFY_MASK      
+GDK_FOCUS_CHANGE_MASK      
+GDK_STRUCTURE_MASK         
+GDK_PROPERTY_CHANGE_MASK   
+GDK_PROXIMITY_IN_MASK      
+GDK_PROXIMITY_OUT_MASK     </literal>
+</literallayout></para>
+
+<para>There are a few subtle points that have to be observed when calling
+<literal>gtk_widget_set_events()</literal>. First, it must be called before the X window
+for a GTK widget is created. In practical terms, this means you
+should call it immediately after creating the widget. Second, the
+widget must have an associated X window. For efficiency, many widget
+types do not have their own window, but draw in their parent's window.
+These widgets are:</para>
+
+<para><literallayout>
+<literal>GtkAlignment
+GtkArrow
+GtkBin
+GtkBox
+GtkImage
+GtkItem
+GtkLabel
+GtkPixmap
+GtkScrolledWindow
+GtkSeparator
+GtkTable
+GtkAspectFrame
+GtkFrame
+GtkVBox
+GtkHBox
+GtkVSeparator
+GtkHSeparator</literal>
+</literallayout></para>
+
+<para>To capture events for these widgets, you need to use an EventBox
+widget. See the section on the <link linkend="ch-EventBox">EventBox</link> widget for details.</para>
+
+<para>For our drawing program, we want to know when the mouse button is
+pressed and when the mouse is moved, so we specify
+<literal>GDK_POINTER_MOTION_MASK</literal> and <literal>GDK_BUTTON_PRESS_MASK</literal>. We also
+want to know when we need to redraw our window, so we specify
+<literal>GDK_EXPOSURE_MASK</literal>. Although we want to be notified via a
+Configure event when our window size changes, we don't have to specify
+the corresponding <literal>GDK_STRUCTURE_MASK</literal> flag, because it is
+automatically specified for all windows.</para>
+
+<para>It turns out, however, that there is a problem with just specifying
+<literal>GDK_POINTER_MOTION_MASK</literal>. This will cause the server to add a new
+motion event to the event queue every time the user moves the mouse.
+Imagine that it takes us 0.1 seconds to handle a motion event, but the
+X server queues a new motion event every 0.05 seconds. We will soon
+get way behind the users drawing. If the user draws for 5 seconds,
+it will take us another 5 seconds to catch up after they release 
+the mouse button! What we would like is to only get one motion
+event for each event we process. The way to do this is to 
+specify <literal>GDK_POINTER_MOTION_HINT_MASK</literal>. </para>
+
+<para>When we specify <literal>GDK_POINTER_MOTION_HINT_MASK</literal>, the server sends
+us a motion event the first time the pointer moves after entering
+our window, or after a button press or release event. Subsequent 
+motion events will be suppressed until we explicitly ask for
+the position of the pointer using the function:</para>
+
+<para><literallayout>
+<literal>GdkWindow*    gdk_window_get_pointer     (GdkWindow       *window,
+                                         gint            *x,
+                                         gint            *y,
+                                         GdkModifierType *mask);</literal>
+</literallayout></para>
+
+<para>(There is another function, <literal>gtk_widget_get_pointer()</literal> which
+has a simpler interface, but turns out not to be very useful, since
+it only retrieves the position of the mouse, not whether the buttons
+are pressed.)</para>
+
+<para>The code to set the events for our window then looks like:</para>
+
+<para><literallayout>
+<literal>  gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
+                     (GtkSignalFunc) expose_event, NULL);
+  gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event",
+                     (GtkSignalFunc) configure_event, NULL);
+  gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event",
+                     (GtkSignalFunc) motion_notify_event, NULL);
+  gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event",
+                     (GtkSignalFunc) button_press_event, NULL);</para>
+
+<para>  gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
+                        | GDK_LEAVE_NOTIFY_MASK
+                        | GDK_BUTTON_PRESS_MASK
+                        | GDK_POINTER_MOTION_MASK
+                        | GDK_POINTER_MOTION_HINT_MASK);</literal>
+</literallayout></para>
+
+<para>We'll save the "expose_event" and "configure_event" handlers for
+later. The "motion_notify_event" and "button_press_event" handlers
+are pretty simple:</para>
+
+<para><literallayout>
+<literal>static gint
+button_press_event (GtkWidget *widget, GdkEventButton *event)
+{
+  if (event->button == 1 &amp;&amp; pixmap != NULL)
+      draw_brush (widget, event->x, event->y);</para>
+
+<para>  return TRUE;
+}</para>
+
+<para>static gint
+motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
+{
+  int x, y;
+  GdkModifierType state;</para>
+
+<para>  if (event->is_hint)
+    gdk_window_get_pointer (event->window, &amp;x, &amp;y, &amp;state);
+  else
+    {
+      x = event->x;
+      y = event->y;
+      state = event->state;
+    }
+    
+  if (state &amp; GDK_BUTTON1_MASK &amp;&amp; pixmap != NULL)
+    draw_brush (widget, x, y);
+  
+  return TRUE;
+}</literal>
+</literallayout></para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> The DrawingArea Widget, And Drawing</title>
+
+<para>We now turn to the process of drawing on the screen. The 
+widget we use for this is the DrawingArea widget. A drawing area
+widget is essentially an X window and nothing more. It is a blank
+canvas in which we can draw whatever we like. A drawing area
+is created using the call:</para>
+
+<para><literallayout>
+<literal>GtkWidget* gtk_drawing_area_new        (void);</literal>
+</literallayout></para>
+
+<para>A default size for the widget can be specified by calling:</para>
+
+<para><literallayout>
+<literal>void       gtk_drawing_area_size       (GtkDrawingArea      *darea,
+                                       gint                 width,
+                                       gint                 height);</literal>
+</literallayout></para>
+
+<para>This default size can be overridden, as is true for all widgets,
+by calling <literal>gtk_widget_set_usize()</literal>, and that, in turn, can
+be overridden if the user manually resizes the the window containing
+the drawing area.</para>
+
+<para>It should be noted that when we create a DrawingArea widget, we are
+<emphasis>completely</emphasis> responsible for drawing the contents. If our
+window is obscured then uncovered, we get an exposure event and must
+redraw what was previously hidden.</para>
+
+<para>Having to remember everything that was drawn on the screen so we
+can properly redraw it can, to say the least, be a nuisance. In
+addition, it can be visually distracting if portions of the
+window are cleared, then redrawn step by step. The solution to
+this problem is to use an offscreen <emphasis>backing pixmap</emphasis>.
+Instead of drawing directly to the screen, we draw to an image
+stored in server memory but not displayed, then when the image
+changes or new portions of the image are displayed, we copy the
+relevant portions onto the screen.</para>
+
+<para>To create an offscreen pixmap, we call the function:</para>
+
+<para><literallayout>
+<literal>GdkPixmap* gdk_pixmap_new               (GdkWindow  *window,
+                                        gint        width,
+                                        gint        height,
+                                        gint        depth);</literal>
+</literallayout></para>
+
+<para>The <literal>window</literal> parameter specifies a GDK window that this pixmap
+takes some of its properties from. <literal>width</literal> and <literal>height</literal>
+specify the size of the pixmap. <literal>depth</literal> specifies the <emphasis>color
+depth</emphasis>, that is the number of bits per pixel, for the new window.
+If the depth is specified as <literal>-1</literal>, it will match the depth
+of <literal>window</literal>.</para>
+
+<para>We create the pixmap in our "configure_event" handler. This event
+is generated whenever the window changes size, including when it
+is originally created.</para>
+
+<programlisting role="C">
+/* Backing pixmap for drawing area */
+static GdkPixmap *pixmap = NULL;</para>
+
+<para>/* Create a new backing pixmap of the appropriate size */
+static gint
+configure_event (GtkWidget *widget, GdkEventConfigure *event)
+{
+  if (pixmap)
+    gdk_pixmap_unref(pixmap);</para>
+
+<para>  pixmap = gdk_pixmap_new(widget->window,
+                         widget->allocation.width,
+                         widget->allocation.height,
+                         -1);
+  gdk_draw_rectangle (pixmap,
+                     widget->style->white_gc,
+                     TRUE,
+                     0, 0,
+                     widget->allocation.width,
+                     widget->allocation.height);</para>
+
+<para>  return TRUE;
+}</literal>
+</literallayout></para>
+
+<para>The call to <literal>gdk_draw_rectangle()</literal> clears the pixmap
+initially to white. We'll say more about that in a moment.</para>
+
+<para>Our exposure event handler then simply copies the relevant portion
+of the pixmap onto the screen (we determine the area we need
+to redraw by using the event->area field of the exposure event):</para>
+
+<programlisting role="C">
+/* Redraw the screen from the backing pixmap */
+static gint
+expose_event (GtkWidget *widget, GdkEventExpose *event)
+{
+  gdk_draw_pixmap(widget->window,
+                 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
+                 pixmap,
+                 event->area.x, event->area.y,
+                 event->area.x, event->area.y,
+                 event->area.width, event->area.height);</para>
+
+<para>  return FALSE;
+}</literal>
+</literallayout></para>
+
+<para>We've now seen how to keep the screen up to date with our pixmap, but
+how do we actually draw interesting stuff on our pixmap?  There are a
+large number of calls in GTK's GDK library for drawing on
+<emphasis>drawables</emphasis>. A drawable is simply something that can be drawn
+upon. It can be a window, a pixmap, or a bitmap (a black and white
+image).  We've already seen two such calls above,
+<literal>gdk_draw_rectangle()</literal> and <literal>gdk_draw_pixmap()</literal>. The
+complete list is:</para>
+
+<para><literallayout>
+<literal>gdk_draw_line ()
+gdk_draw_rectangle ()
+gdk_draw_arc ()
+gdk_draw_polygon ()
+gdk_draw_string ()
+gdk_draw_text ()
+gdk_draw_pixmap ()
+gdk_draw_bitmap ()
+gdk_draw_image ()
+gdk_draw_points ()
+gdk_draw_segments ()</literal>
+</literallayout></para>
+
+<para>See the reference documentation or the header file
+<literal>&lt;gdk/gdk.h&gt;</literal> for further details on these functions.
+These functions all share the same first two arguments. The first
+argument is the drawable to draw upon, the second argument is a
+<emphasis>graphics context</emphasis> (GC). </para>
+
+<para>A graphics context encapsulates information about things such as
+foreground and background color and line width. GDK has a full set of
+functions for creating and modifying graphics contexts, but to keep
+things simple we'll just use predefined graphics contexts. Each widget
+has an associated style. (Which can be modified in a gtkrc file, see
+the section GTK's rc file.) This, among other things, stores a number
+of graphics contexts. Some examples of accessing these graphics
+contexts are:</para>
+
+<para><literallayout>
+<literal>widget->style->white_gc
+widget->style->black_gc
+widget->style->fg_gc[GTK_STATE_NORMAL]
+widget->style->bg_gc[GTK_WIDGET_STATE(widget)]</literal>
+</literallayout></para>
+
+<para>The fields <literal>fg_gc</literal>, <literal>bg_gc</literal>, <literal>dark_gc</literal>, and
+<literal>light_gc</literal> are indexed by a parameter of type
+<literal>GtkStateType</literal> which can take on the values:</para>
+
+<para><literallayout>
+<literal>GTK_STATE_NORMAL,
+GTK_STATE_ACTIVE,
+GTK_STATE_PRELIGHT,
+GTK_STATE_SELECTED,
+GTK_STATE_INSENSITIVE</literal>
+</literallayout></para>
+
+<para>For instance, for <literal>GTK_STATE_SELECTED</literal> the default foreground
+color is white and the default background color, dark blue.</para>
+
+<para>Our function <literal>draw_brush()</literal>, which does the actual drawing
+on the screen, is then:</para>
+
+<programlisting role="C">
+/* Draw a rectangle on the screen */
+static void
+draw_brush (GtkWidget *widget, gdouble x, gdouble y)
+{
+  GdkRectangle update_rect;</para>
+
+<para>  update_rect.x = x - 5;
+  update_rect.y = y - 5;
+  update_rect.width = 10;
+  update_rect.height = 10;
+  gdk_draw_rectangle (pixmap,
+                     widget->style->black_gc,
+                     TRUE,
+                     update_rect.x, update_rect.y,
+                     update_rect.width, update_rect.height);
+  gtk_widget_draw (widget, &amp;update_rect);
+}</literal>
+</literallayout></para>
+
+<para>After we draw the rectangle representing the brush onto the pixmap,
+we call the function:</para>
+
+<para><literallayout>
+<literal>void       gtk_widget_draw                (GtkWidget           *widget,
+                                          GdkRectangle        *area);</literal>
+</literallayout></para>
+
+<para>which notifies X that the area given by the <literal>area</literal> parameter
+needs to be updated. X will eventually generate an expose event
+(possibly combining the areas passed in several calls to
+<literal>gtk_widget_draw()</literal>) which will cause our expose event handler
+to copy the relevant portions to the screen.</para>
+
+<para>We have now covered the entire drawing program except for a few
+mundane details like creating the main window.</para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> Adding XInput support</title>
+
+<para>It is now possible to buy quite inexpensive input devices such 
+as drawing tablets, which allow drawing with a much greater
+ease of artistic expression than does a mouse. The simplest way
+to use such devices is simply as a replacement for the mouse,
+but that misses out many of the advantages of these devices,
+such as:</para>
+
+<itemizedlist>
+<listitem><simpara> Pressure sensitivity</simpara>
+</listitem>
+<listitem><simpara> Tilt reporting</simpara>
+</listitem>
+<listitem><simpara> Sub-pixel positioning</simpara>
+</listitem>
+<listitem><simpara> Multiple inputs (for example, a stylus with a point and eraser)</simpara>
+</listitem>
+</itemizedlist>
+
+<para>For information about the XInput extension, see the <ulink
+url="http://www.msc.cornell.edu/~otaylor/xinput/XInput-HOWTO.html"> XInput-HOWTO </ulink>.</para>
+
+<para>If we examine the full definition of, for example, the GdkEventMotion
+structure, we see that it has fields to support extended device
+information.</para>
+
+<para><literallayout>
+<literal>struct _GdkEventMotion
+{
+  GdkEventType type;
+  GdkWindow *window;
+  guint32 time;
+  gdouble x;
+  gdouble y;
+  gdouble pressure;
+  gdouble xtilt;
+  gdouble ytilt;
+  guint state;
+  gint16 is_hint;
+  GdkInputSource source;
+  guint32 deviceid;
+};</literal>
+</literallayout></para>
+
+<para><literal>pressure</literal> gives the pressure as a floating point number between
+0 and 1. <literal>xtilt</literal> and <literal>ytilt</literal> can take on values between 
+-1 and 1, corresponding to the degree of tilt in each direction.
+<literal>source</literal> and <literal>deviceid</literal> specify the device for which the
+event occurred in two different ways. <literal>source</literal> gives some simple
+information about the type of device. It can take the enumeration
+values:</para>
+
+<para><literallayout>
+<literal>GDK_SOURCE_MOUSE
+GDK_SOURCE_PEN
+GDK_SOURCE_ERASER
+GDK_SOURCE_CURSOR</literal>
+</literallayout></para>
+
+<para><literal>deviceid</literal> specifies a unique numeric ID for the device. This can
+be used to find out further information about the device using the
+<literal>gdk_input_list_devices()</literal> call (see below). The special value
+<literal>GDK_CORE_POINTER</literal> is used for the core pointer device. (Usually
+the mouse.)</para>
+
+<para><sect2>
+<title> Enabling extended device information</title>
+
+<para>To let GTK know about our interest in the extended device information,
+we merely have to add a single line to our program:</para>
+
+<para><literallayout>
+<literal>gtk_widget_set_extension_events (drawing_area, GDK_EXTENSION_EVENTS_CURSOR);</literal>
+</literallayout></para>
+
+<para>By giving the value <literal>GDK_EXTENSION_EVENTS_CURSOR</literal> we say that
+we are interested in extension events, but only if we don't have
+to draw our own cursor. See the section <ref
+id="ch-Further_Sophistications"> Further Sophistications </ulink> below
+for more information about drawing the cursor. We could also 
+give the values <literal>GDK_EXTENSION_EVENTS_ALL</literal> if we were willing 
+to draw our own cursor, or <literal>GDK_EXTENSION_EVENTS_NONE</literal> to revert
+back to the default condition.</para>
+
+<para>This is not completely the end of the story however. By default,
+no extension devices are enabled. We need a mechanism to allow
+users to enable and configure their extension devices. GTK provides
+the InputDialog widget to automate this process. The following
+procedure manages an InputDialog widget. It creates the dialog if
+it isn't present, and raises it to the top otherwise.</para>
+
+<para><literallayout>
+<literal>void
+input_dialog_destroy (GtkWidget *w, gpointer data)
+{
+  *((GtkWidget **)data) = NULL;
+}</para>
+
+<para>void
+create_input_dialog ()
+{
+  static GtkWidget *inputd = NULL;</para>
+
+<para>  if (!inputd)
+    {
+      inputd = gtk_input_dialog_new();</para>
+
+<para>      gtk_signal_connect (GTK_OBJECT(inputd), "destroy",
+                         (GtkSignalFunc)input_dialog_destroy, &amp;inputd);
+      gtk_signal_connect_object (GTK_OBJECT(GTK_INPUT_DIALOG(inputd)->close_button),
+                                "clicked",
+                                (GtkSignalFunc)gtk_widget_hide,
+                                GTK_OBJECT(inputd));
+      gtk_widget_hide ( GTK_INPUT_DIALOG(inputd)->save_button);</para>
+
+<para>      gtk_widget_show (inputd);
+    }
+  else
+    {
+      if (!GTK_WIDGET_MAPPED(inputd))
+       gtk_widget_show(inputd);
+      else
+       gdk_window_raise(inputd->window);
+    }
+}</literal>
+</literallayout></para>
+
+<para>(You might want to take note of the way we handle this dialog.  By
+connecting to the "destroy" signal, we make sure that we don't keep a
+pointer to dialog around after it is destroyed - that could lead to a
+segfault.)</para>
+
+<para>The InputDialog has two buttons "Close" and "Save", which by default
+have no actions assigned to them. In the above function we make
+"Close" hide the dialog, hide the "Save" button, since we don't
+implement saving of XInput options in this program.</para>
+
+<para><sect2>
+<title> Using extended device information</title>
+
+<para>Once we've enabled the device, we can just use the extended 
+device information in the extra fields of the event structures.
+In fact, it is always safe to use this information since these
+fields will have reasonable default values even when extended
+events are not enabled.</para>
+
+<para>Once change we do have to make is to call
+<literal>gdk_input_window_get_pointer()</literal> instead of
+<literal>gdk_window_get_pointer</literal>. This is necessary because
+<literal>gdk_window_get_pointer</literal> doesn't return the extended device
+information.</para>
+
+<para><literallayout>
+<literal>void gdk_input_window_get_pointer( GdkWindow       *window,
+                                   guint32         deviceid,
+                                   gdouble         *x,
+                                   gdouble         *y,
+                                   gdouble         *pressure,
+                                   gdouble         *xtilt,
+                                   gdouble         *ytilt,
+                                   GdkModifierType *mask);</literal>
+</literallayout></para>
+
+<para>When calling this function, we need to specify the device ID as
+well as the window. Usually, we'll get the device ID from the
+<literal>deviceid</literal> field of an event structure. Again, this function
+will return reasonable values when extension events are not
+enabled. (In this case, <literal>event->deviceid</literal> will have the value
+<literal>GDK_CORE_POINTER</literal>).</para>
+
+<para>So the basic structure of our button-press and motion event handlers
+doesn't change much - we just need to add code to deal with the
+extended information.</para>
+
+<para><literallayout>
+<literal>static gint
+button_press_event (GtkWidget *widget, GdkEventButton *event)
+{
+  print_button_press (event->deviceid);
+  
+  if (event->button == 1 &amp;&amp; pixmap != NULL)
+    draw_brush (widget, event->source, event->x, event->y, event->pressure);</para>
+
+<para>  return TRUE;
+}</para>
+
+<para>static gint
+motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
+{
+  gdouble x, y;
+  gdouble pressure;
+  GdkModifierType state;</para>
+
+<para>  if (event->is_hint)
+    gdk_input_window_get_pointer (event->window, event->deviceid,
+                                 &amp;x, &amp;y, &amp;pressure, NULL, NULL, &amp;state);
+  else
+    {
+      x = event->x;
+      y = event->y;
+      pressure = event->pressure;
+      state = event->state;
+    }
+    
+  if (state &amp; GDK_BUTTON1_MASK &amp;&amp; pixmap != NULL)
+    draw_brush (widget, event->source, x, y, pressure);
+  
+  return TRUE;
+}</literal>
+</literallayout></para>
+
+<para>We also need to do something with the new information. Our new
+<literal>draw_brush()</literal> function draws with a different color for
+each <literal>event->source</literal> and changes the brush size depending
+on the pressure.</para>
+
+<programlisting role="C">
+/* Draw a rectangle on the screen, size depending on pressure,
+   and color on the type of device */
+static void
+draw_brush (GtkWidget *widget, GdkInputSource source,
+           gdouble x, gdouble y, gdouble pressure)
+{
+  GdkGC *gc;
+  GdkRectangle update_rect;</para>
+
+<para>  switch (source)
+    {
+    case GDK_SOURCE_MOUSE:
+      gc = widget->style->dark_gc[GTK_WIDGET_STATE (widget)];
+      break;
+    case GDK_SOURCE_PEN:
+      gc = widget->style->black_gc;
+      break;
+    case GDK_SOURCE_ERASER:
+      gc = widget->style->white_gc;
+      break;
+    default:
+      gc = widget->style->light_gc[GTK_WIDGET_STATE (widget)];
+    }</para>
+
+<para>  update_rect.x = x - 10 * pressure;
+  update_rect.y = y - 10 * pressure;
+  update_rect.width = 20 * pressure;
+  update_rect.height = 20 * pressure;
+  gdk_draw_rectangle (pixmap, gc, TRUE,
+                     update_rect.x, update_rect.y,
+                     update_rect.width, update_rect.height);
+  gtk_widget_draw (widget, &amp;update_rect);
+}</literal>
+</literallayout></para>
+
+<para><sect2>
+<title> Finding out more about a device</title>
+
+<para>As an example of how to find out more about a device, our program
+will print the name of the device that generates each button
+press. To find out the name of a device, we call the function:</para>
+
+<para><literallayout>
+<literal>GList *gdk_input_list_devices               (void);</literal>
+</literallayout></para>
+
+<para>which returns a GList (a linked list type from the GLib library)
+of GdkDeviceInfo structures. The GdkDeviceInfo structure is defined
+as:</para>
+
+<para><literallayout>
+<literal>struct _GdkDeviceInfo
+{
+  guint32 deviceid;
+  gchar *name;
+  GdkInputSource source;
+  GdkInputMode mode;
+  gint has_cursor;
+  gint num_axes;
+  GdkAxisUse *axes;
+  gint num_keys;
+  GdkDeviceKey *keys;
+};</literal>
+</literallayout></para>
+
+<para>Most of these fields are configuration information that you can ignore
+unless you are implementing XInput configuration saving. The fieldwe
+are interested in here is <literal>name</literal> which is simply the name that X
+assigns to the device. The other field that isn't configuration
+information is <literal>has_cursor</literal>. If <literal>has_cursor</literal> is false, then we
+we need to draw our own cursor. But since we've specified
+<literal>GDK_EXTENSION_EVENTS_CURSOR</literal>, we don't have to worry about this.</para>
+
+<para>Our <literal>print_button_press()</literal> function simply iterates through
+the returned list until it finds a match, then prints out
+the name of the device.</para>
+
+<para><literallayout>
+<literal>static void
+print_button_press (guint32 deviceid)
+{
+  GList *tmp_list;</para>
+
+<para>  /* gdk_input_list_devices returns an internal list, so we shouldn't
+     free it afterwards */
+  tmp_list = gdk_input_list_devices();</para>
+
+<para>  while (tmp_list)
+    {
+      GdkDeviceInfo *info = (GdkDeviceInfo *)tmp_list->data;</para>
+
+<para>      if (info->deviceid == deviceid)
+       {
+         printf("Button press on device '%s'\n", info->name);
+         return;
+       }</para>
+
+<para>      tmp_list = tmp_list->next;
+    }
+}</literal>
+</literallayout></para>
+
+<para>That completes the changes to "XInputize" our program.</para>
+
+<para><sect2> Further sophistications <label id="ch-Further_Sophistications"></para>
+
+<para>Although our program now supports XInput quite well, it lacks some
+features we would want in a full-featured application. First, the user
+probably doesn't want to have to configure their device each time they
+run the program, so we should allow them to save the device
+configuration. This is done by iterating through the return of
+<literal>gdk_input_list_devices()</literal> and writing out the configuration to a
+file.</para>
+
+<para>To restore the state next time the program is run, GDK provides
+functions to change device configuration:</para>
+
+<para><literallayout>
+<literal>gdk_input_set_extension_events()
+gdk_input_set_source()
+gdk_input_set_mode()
+gdk_input_set_axes()
+gdk_input_set_key()</literal>
+</literallayout></para>
+
+<para>(The list returned from <literal>gdk_input_list_devices()</literal> should not be
+modified directly.) An example of doing this can be found in the
+drawing program gsumi. (Available from <ulink
+url="http://www.msc.cornell.edu/~otaylor/gsumi/"> http://www.msc.cornell.edu/~otaylor/gsumi/ </ulink>) Eventually, it
+would be nice to have a standard way of doing this for all
+applications. This probably belongs at a slightly higher level than
+GTK, perhaps in the GNOME library.</para>
+
+<para>Another major omission that we have mentioned above is the lack of
+cursor drawing. Platforms other than XFree86 currently do not allow
+simultaneously using a device as both the core pointer and directly by
+an application. See the <url
+url="http://www.msc.cornell.edu/~otaylor/xinput/XInput-HOWTO.html"> XInput-HOWTO </ulink> for more information about this. This means that
+applications that want to support the widest audience need to draw
+their own cursor.</para>
+
+<para>An application that draws its own cursor needs to do two things:
+determine if the current device needs a cursor drawn or not, and
+determine if the current device is in proximity. (If the current
+device is a drawing tablet, it's a nice touch to make the cursor 
+disappear when the stylus is lifted from the tablet. When the
+device is touching the stylus, that is called "in proximity.")
+The first is done by searching the device list, as we did
+to find out the device name. The second is achieved by selecting
+"proximity_out" events. An example of drawing one's own cursor is
+found in the "testinput" program found in the GTK distribution.</para>
+
+</sect1>
+</chapter>
+
+<!-- ***************************************************************** -->
+<chapter id="ch-Tips">
+<title>Tips For Writing GTK Applications</title>
+
+<para>This section is simply a gathering of wisdom, general style guidelines
+and hints to creating good GTK applications. Currently this section
+is very short, but I hope it will get longer in future editions of
+this tutorial.</para>
+
+<para>Use GNU autoconf and automake! They are your friends :) Automake
+examines C files, determines how they depend on each other, and
+generates a Makefile so the files can be compiled in the correct
+order. Autoconf permits automatic configuration of software
+installation, handling a large number of system quirks to increase
+portability. I am planning to make a quick intro on them here.</para>
+
+<para>When writing C code, use only C comments (beginning with "/*" and
+ending with "*/"), and don't use C++-style comments ("//").  Although
+many C compilers understand C++ comments, others don't, and the ANSI C
+standard does not require that C++-style comments be processed as
+comments.</para>
+
+</chapter>
+
+<!-- ***************************************************************** -->
+<chapter id="ch-Contributing">
+<title>Contributing</title>
+
+<para>This document, like so much other great software out there, was
+created for free by volunteers.  If you are at all knowledgeable about
+any aspect of GTK that does not already have documentation, please
+consider contributing to this document.</para>
+
+<para>If you do decide to contribute, please mail your text to Tony Gale,
+<literal><ulink url="mailto:gale@gtk.org"> gale@gtk.org </ulink></literal>. Also, be aware that the entirety of this
+document is free, and any addition by you provide must also be
+free. That is, people may use any portion of your examples in their
+programs, and copies of this document may be distributed at will, etc.</para>
+
+<para>Thank you.</para>
+
+</chapter>
+
+<!-- ***************************************************************** -->
+<chapter id="ch-Credits">
+<title>Credits</title>
+
+<para>We would like to thank the following for their contributions to this text.</para>
+
+<itemizedlist>
+<listitem><simpara>Bawer Dagdeviren, <literal><ulink url="mailto:chamele0n@geocities.com"> chamele0n@geocities.com </ulink></literal> for the menus tutorial.                        </para>
+</simpara>
+</listitem>
+<listitem><simpara>Raph Levien, <literal><ulink url="mailto:raph@acm.org"> raph@acm.org </ulink></literal>
+for hello world ala GTK, widget packing, and general all around wisdom.
+He's also generously donated a home for this tutorial.</para>
+</simpara>
+</listitem>
+<listitem><simpara>Peter Mattis, <literal><ulink url="mailto:petm@xcf.berkeley.edu"> petm@xcf.berkeley.edu </ulink></literal> for the simplest GTK program.. 
+and the ability to make it :)</para>
+</simpara>
+</listitem>
+<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
+SGML, and the widget class hierarchy.</para>
+</simpara>
+</listitem>
+<listitem><simpara>Mark Crichton <literal><ulink
+url="mailto:crichton@expert.cc.purdue.edu"> crichton@expert.cc.purdue.edu </ulink></literal> for the menu factory code,
+and the table packing tutorial.</para>
+</simpara>
+</listitem>
+<listitem><simpara>Owen Taylor <literal><ulink url="mailto:owt1@cornell.edu"> owt1@cornell.edu </ulink></literal> for the EventBox widget section (and the
+patch to the distro).  He's also responsible for the selections code
+and tutorial, as well as the sections on writing your own GTK widgets,
+and the example application. Thanks a lot Owen for all you help!</para>
+</simpara>
+</listitem>
+<listitem><simpara>Mark VanderBoom <literal><ulink url="mailto:mvboom42@calvin.edu"> mvboom42@calvin.edu </ulink></literal> for his wonderful work on the
+Notebook, Progress Bar, Dialogs, and File selection widgets.  Thanks a
+lot Mark!  You've been a great help.</para>
+</simpara>
+</listitem>
+<listitem><simpara>Tim Janik <literal><ulink url="mailto:timj@gtk.org"> timj@psynet.net </ulink></literal> for his great job on the Lists
+Widget. His excellent work on automatically extracting the widget tree
+and signal information from GTK. Thanks Tim :)</para>
+</simpara>
+</listitem>
+<listitem><simpara>Rajat Datta <literal><ulink url="mailto:rajat@ix.netcom.com"
+name="rajat@ix.netcom.com"</literal> for the excellent job on the Pixmap
+tutorial.</para>
+</simpara>
+</listitem>
+<listitem><simpara>Michael K. Johnson <literal><ulink url="mailto:johnsonm@redhat.com"> johnsonm@redhat.com </ulink></literal> for info and code for popup menus.</para>
+</simpara>
+</listitem>
+<listitem><simpara>David Huggins-Daines <literal><ulink
+url="mailto:bn711@freenet.carleton.ca"> bn711@freenet.carleton.ca </ulink></literal> for the Range Widgets and Tree
+Widget sections.</para>
+</simpara>
+</listitem>
+<listitem><simpara>Stefan Mars <literal><ulink url="mailto:mars@lysator.liu.se"> mars@lysator.liu.se </ulink></literal> for the CList section.</para>
+</simpara>
+</listitem>
+<listitem><simpara>David A. Wheeler <literal><ulink url="mailto:dwheeler@ida.org"> dwheeler@ida.org </ulink></literal> for portions of the text on GLib
+and various tutorial fixups and improvements.
+The GLib text was in turn based on material developed by Damon Chaplin
+<literal><ulink url="mailto:DAChaplin@msn.com"> DAChaplin@msn.com </ulink></literal></para>
+</simpara>
+</listitem>
+<listitem><simpara>David King for style checking the entire document.</simpara>
+</listitem>
+</itemizedlist>
+
+<para>And to all of you who commented on and helped refine this document.</para>
+
+<para>Thanks.</para>
+
+</chapter>
+
+<!-- ***************************************************************** -->
+<chapter id="ch-Copyright">
+<title>Tutorial Copyright and Permissions Notice</title>
+
+<para>
+<para>The GTK Tutorial is Copyright (C) 1997 Ian Main. </para>
+
+<para>Copyright (C) 1998-1999 Tony Gale.</para>
+
+<para>Permission is granted to make and distribute verbatim copies of this 
+manual provided the copyright notice and this permission notice are 
+preserved on all copies.</para>
+
+<para>Permission is granted to copy and distribute modified versions of 
+this document under the conditions for verbatim copying, provided that 
+this copyright notice is included exactly as in the original,
+and that the entire resulting derived work is distributed under 
+the terms of a permission notice identical to this one.
+<P>Permission is granted to copy and distribute translations of this 
+document into another language, under the above conditions for modified 
+versions.</para>
+
+<para>If you are intending to incorporate this document into a published 
+work, please contact the maintainer, and we will make an effort 
+to ensure that you have the most up to date information available.</para>
+
+<para>There is no guarantee that this document lives up to its intended
+purpose.  This is simply provided as a free resource.  As such,
+the authors and maintainers of the information provided within can
+not make any guarantee that the information is even accurate.</para>
+
+</chapter>
+
+<!-- ***************************************************************** -->
+<!-- ***************************************************************** -->
+
+<!-- ***************************************************************** -->
+<appendix id="app_GTKSignals">
+<title>GTK Signals</title>
+
+<para>As GTK is an object oriented widget set, it has a hierarchy of
+inheritance. This inheritance mechanism applies for
+signals. Therefore, you should refer to the widget hierarchy tree when
+using the signals listed in this section.</para>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>GtkObject</title>
+
+<para><literallayout>
+<literal>void GtkObject::destroy       (GtkObject *,
+                                gpointer);</literal>
+</literallayout></para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>GtkWidget</title>
+
+<para><tscreen><verb></para>
+
+<para>void GtkWidget::show     (GtkWidget *,
+                        gpointer);
+void GtkWidget::hide   (GtkWidget *,
+                        gpointer);
+void GtkWidget::map    (GtkWidget *,
+                        gpointer);
+void GtkWidget::unmap  (GtkWidget *,
+                        gpointer);
+void GtkWidget::realize        (GtkWidget *,
+                                gpointer);
+void GtkWidget::unrealize      (GtkWidget *,
+                                gpointer);
+void GtkWidget::draw   (GtkWidget *,
+                        ggpointer,
+                        gpointer);
+void GtkWidget::draw-focus     (GtkWidget *,
+                                gpointer);
+void GtkWidget::draw-default   (GtkWidget *,
+                                gpointer);
+void GtkWidget::size-request   (GtkWidget *,
+                                ggpointer,
+                                gpointer);
+void GtkWidget::size-allocate  (GtkWidget *,
+                                ggpointer,
+                                gpointer);
+void GtkWidget::state-changed  (GtkWidget *,
+                                GtkStateType,
+                                gpointer);
+void GtkWidget::parent-set     (GtkWidget *,
+                                GtkObject *,
+                                gpointer);
+void GtkWidget::style-set      (GtkWidget *,
+                                GtkStyle *,
+                                gpointer);
+void GtkWidget::add-accelerator        (GtkWidget *,
+                                        gguint,
+                                        GtkAccelGroup *,
+                                        gguint,
+                                        GdkModifierType,
+                                        GtkAccelFlags,
+                                        gpointer);
+void GtkWidget::remove-accelerator     (GtkWidget *,
+                                        GtkAccelGroup *,
+                                        gguint,
+                                        GdkModifierType,
+                                        gpointer);
+gboolean GtkWidget::event      (GtkWidget *,
+                                GdkEvent *,
+                                gpointer);
+gboolean GtkWidget::button-press-event (GtkWidget *,
+                                        GdkEvent *,
+                                        gpointer);
+gboolean GtkWidget::button-release-event       (GtkWidget *,
+                                                GdkEvent *,
+                                                gpointer);
+gboolean GtkWidget::motion-notify-event        (GtkWidget *,
+                                                GdkEvent *,
+                                                gpointer);
+gboolean GtkWidget::delete-event       (GtkWidget *,
+                                        GdkEvent *,
+                                        gpointer);
+gboolean GtkWidget::destroy-event      (GtkWidget *,
+                                        GdkEvent *,
+                                        gpointer);
+gboolean GtkWidget::expose-event       (GtkWidget *,
+                                        GdkEvent *,
+                                        gpointer);
+gboolean GtkWidget::key-press-event    (GtkWidget *,
+                                        GdkEvent *,
+                                        gpointer);
+gboolean GtkWidget::key-release-event  (GtkWidget *,
+                                        GdkEvent *,
+                                        gpointer);
+gboolean GtkWidget::enter-notify-event (GtkWidget *,
+                                        GdkEvent *,
+                                        gpointer);
+gboolean GtkWidget::leave-notify-event (GtkWidget *,
+                                        GdkEvent *,
+                                        gpointer);
+gboolean GtkWidget::configure-event    (GtkWidget *,
+                                        GdkEvent *,
+                                        gpointer);
+gboolean GtkWidget::focus-in-event     (GtkWidget *,
+                                        GdkEvent *,
+                                        gpointer);
+gboolean GtkWidget::focus-out-event    (GtkWidget *,
+                                        GdkEvent *,
+                                        gpointer);
+gboolean GtkWidget::map-event  (GtkWidget *,
+                                GdkEvent *,
+                                gpointer);
+gboolean GtkWidget::unmap-event        (GtkWidget *,
+                                        GdkEvent *,
+                                        gpointer);
+gboolean GtkWidget::property-notify-event      (GtkWidget *,
+                                                GdkEvent *,
+                                                gpointer);
+gboolean GtkWidget::selection-clear-event      (GtkWidget *,
+                                                GdkEvent *,
+                                                gpointer);
+gboolean GtkWidget::selection-request-event    (GtkWidget *,
+                                                GdkEvent *,
+                                                gpointer);
+gboolean GtkWidget::selection-notify-event     (GtkWidget *,
+                                                GdkEvent *,
+                                                gpointer);
+void GtkWidget::selection-get  (GtkWidget *,
+                                GtkSelectionData *,
+                                gguint,
+                                gpointer);
+void GtkWidget::selection-received     (GtkWidget *,
+                                        GtkSelectionData *,
+                                        gguint,
+                                        gpointer);
+gboolean GtkWidget::proximity-in-event (GtkWidget *,
+                                        GdkEvent *,
+                                        gpointer);
+gboolean GtkWidget::proximity-out-event        (GtkWidget *,
+                                                GdkEvent *,
+                                                gpointer);
+void GtkWidget::drag-begin     (GtkWidget *,
+                                GdkDragContext *,
+                                gpointer);
+void GtkWidget::drag-end       (GtkWidget *,
+                                GdkDragContext *,
+                                gpointer);
+void GtkWidget::drag-data-delete       (GtkWidget *,
+                                        GdkDragContext *,
+                                        gpointer);
+void GtkWidget::drag-leave     (GtkWidget *,
+                                GdkDragContext *,
+                                gguint,
+                                gpointer);
+gboolean GtkWidget::drag-motion        (GtkWidget *,
+                                        GdkDragContext *,
+                                        ggint,
+                                        ggint,
+                                        gguint,
+                                        gpointer);
+gboolean GtkWidget::drag-drop  (GtkWidget *,
+                                GdkDragContext *,
+                                ggint,
+                                ggint,
+                                gguint,
+                                gpointer);
+void GtkWidget::drag-data-get  (GtkWidget *,
+                                GdkDragContext *,
+                                GtkSelectionData *,
+                                gguint,
+                                gguint,
+                                gpointer);
+void GtkWidget::drag-data-received     (GtkWidget *,
+                                        GdkDragContext *,
+                                        ggint,
+                                        ggint,
+                                        GtkSelectionData *,
+                                        gguint,
+                                        gguint,
+                                        gpointer);
+gboolean GtkWidget::client-event       (GtkWidget *,
+                                        GdkEvent *,
+                                        gpointer);
+gboolean GtkWidget::no-expose-event    (GtkWidget *,
+                                        GdkEvent *,
+                                        gpointer);
+gboolean GtkWidget::visibility-notify-event    (GtkWidget *,
+                                                GdkEvent *,
+                                                gpointer);
+void GtkWidget::debug-msg      (GtkWidget *,
+                                GtkString *,
+                                gpointer);</literal>
+</literallayout></para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>GtkData</title>
+
+<para><literallayout>
+<literal>void GtkData::disconnect      (GtkData *,
+                                gpointer);</literal>
+</literallayout></para>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>GtkContainer</title>
+
+<para><literallayout>
+<literal>void GtkContainer::add        (GtkContainer *,
+                        GtkWidget *,
+                        gpointer);
+void GtkContainer::remove      (GtkContainer *,
+                                GtkWidget *,
+                                gpointer);
+void GtkContainer::check-resize        (GtkContainer *,
+                                        gpointer);
+GtkDirectionType GtkContainer::focus   (GtkContainer *,
+                                        GtkDirectionType,
+                                        gpointer);
+void GtkContainer::set-focus-child     (GtkContainer *,
+                                        GtkWidget *,
+                                        gpointer);</literal>
+</literallayout></para>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>GtkCalendar</title>
+
+<para><literallayout>
+<literal>void GtkCalendar::month-changed       (GtkCalendar *,
+                                        gpointer);
+void GtkCalendar::day-selected (GtkCalendar *,
+                                gpointer);
+void GtkCalendar::day-selected-double-click    (GtkCalendar *,
+                                                gpointer);
+void GtkCalendar::prev-month   (GtkCalendar *,
+                                gpointer);
+void GtkCalendar::next-month   (GtkCalendar *,
+                                gpointer);
+void GtkCalendar::prev-year    (GtkCalendar *,
+                                gpointer);
+void GtkCalendar::next-year    (GtkCalendar *,
+                                gpointer);</literal>
+</literallayout></para>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>GtkEditable</title>
+
+<para><literallayout>
+<literal>void GtkEditable::changed     (GtkEditable *,
+                                gpointer);
+void GtkEditable::insert-text  (GtkEditable *,
+                                GtkString *,
+                                ggint,
+                                ggpointer,
+                                gpointer);
+void GtkEditable::delete-text  (GtkEditable *,
+                                ggint,
+                                ggint,
+                                gpointer);
+void GtkEditable::activate     (GtkEditable *,
+                                gpointer);
+void GtkEditable::set-editable (GtkEditable *,
+                                gboolean,
+                                gpointer);
+void GtkEditable::move-cursor  (GtkEditable *,
+                                ggint,
+                                ggint,
+                                gpointer);
+void GtkEditable::move-word    (GtkEditable *,
+                                ggint,
+                                gpointer);
+void GtkEditable::move-page    (GtkEditable *,
+                                ggint,
+                                ggint,
+                                gpointer);
+void GtkEditable::move-to-row  (GtkEditable *,
+                                ggint,
+                                gpointer);
+void GtkEditable::move-to-column       (GtkEditable *,
+                                        ggint,
+                                        gpointer);
+void GtkEditable::kill-char    (GtkEditable *,
+                                ggint,
+                                gpointer);
+void GtkEditable::kill-word    (GtkEditable *,
+                                ggint,
+                                gpointer);
+void GtkEditable::kill-line    (GtkEditable *,
+                                ggint,
+                                gpointer);
+void GtkEditable::cut-clipboard        (GtkEditable *,
+                                        gpointer);
+void GtkEditable::copy-clipboard       (GtkEditable *,
+                                        gpointer);
+void GtkEditable::paste-clipboard      (GtkEditable *,
+                                        gpointer);</literal>
+</literallayout></para>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>GtkTipsQuery</title>
+
+<para><literallayout>
+<literal>void GtkTipsQuery::start-query        (GtkTipsQuery *,
+                                gpointer);
+void GtkTipsQuery::stop-query  (GtkTipsQuery *,
+                                gpointer);
+void GtkTipsQuery::widget-entered      (GtkTipsQuery *,
+                                        GtkWidget *,
+                                        GtkString *,
+                                        GtkString *,
+                                        gpointer);
+gboolean GtkTipsQuery::widget-selected (GtkTipsQuery *,
+                                        GtkWidget *,
+                                        GtkString *,
+                                        GtkString *,
+                                        GdkEvent *,
+                                        gpointer);</literal>
+</literallayout></para>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>GtkCList</title>
+
+<para><literallayout>
+<literal>void GtkCList::select-row     (GtkCList *,
+                                ggint,
+                                ggint,
+                                GdkEvent *,
+                                gpointer);
+void GtkCList::unselect-row    (GtkCList *,
+                                ggint,
+                                ggint,
+                                GdkEvent *,
+                                gpointer);
+void GtkCList::row-move        (GtkCList *,
+                                ggint,
+                                ggint,
+                                gpointer);
+void GtkCList::click-column    (GtkCList *,
+                                ggint,
+                                gpointer);
+void GtkCList::resize-column   (GtkCList *,
+                                ggint,
+                                ggint,
+                                gpointer);
+void GtkCList::toggle-focus-row        (GtkCList *,
+                                        gpointer);
+void GtkCList::select-all      (GtkCList *,
+                                gpointer);
+void GtkCList::unselect-all    (GtkCList *,
+                                gpointer);
+void GtkCList::undo-selection  (GtkCList *,
+                                gpointer);
+void GtkCList::start-selection (GtkCList *,
+                                gpointer);
+void GtkCList::end-selection   (GtkCList *,
+                                gpointer);
+void GtkCList::toggle-add-mode (GtkCList *,
+                                gpointer);
+void GtkCList::extend-selection        (GtkCList *,
+                                        GtkScrollType,
+                                        ggfloat,
+                                        gboolean,
+                                        gpointer);
+void GtkCList::scroll-vertical (GtkCList *,
+                                GtkScrollType,
+                                ggfloat,
+                                gpointer);
+void GtkCList::scroll-horizontal       (GtkCList *,
+                                        GtkScrollType,
+                                        ggfloat,
+                                        gpointer);
+void GtkCList::abort-column-resize     (GtkCList *,
+                                        gpointer);</literal>
+</literallayout></para>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>GtkNotebook</title>
+
+<para><literallayout>
+<literal>void GtkNotebook::switch-page (GtkNotebook *,
+                                ggpointer,
+                                gguint,
+                                gpointer);</para>
+
+<para></verb></tscreen></para>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>GtkList</title>
+
+<para><literallayout>
+<literal>void GtkList::selection-changed       (GtkList *,
+                                        gpointer);
+void GtkList::select-child     (GtkList *,
+                                GtkWidget *,
+                                gpointer);
+void GtkList::unselect-child   (GtkList *,
+                                GtkWidget *,
+                                gpointer);</literal>
+</literallayout></para>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>GtkMenuShell</title>
+
+<para><literallayout>
+<literal>void GtkMenuShell::deactivate (GtkMenuShell *,
+                                gpointer);
+void GtkMenuShell::selection-done      (GtkMenuShell *,
+                                        gpointer);
+void GtkMenuShell::move-current        (GtkMenuShell *,
+                                        GtkMenuDirectionType,
+                                        gpointer);
+void GtkMenuShell::activate-current    (GtkMenuShell *,
+                                        gboolean,
+                                        gpointer);
+void GtkMenuShell::cancel      (GtkMenuShell *,
+                                gpointer);</literal>
+</literallayout></para>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>GtkToolbar</title>
+
+<para><literallayout>
+<literal>void GtkToolbar::orientation-changed  (GtkToolbar *,
+                                        ggint,
+                                        gpointer);
+void GtkToolbar::style-changed (GtkToolbar *,
+                                ggint,
+                                gpointer);</literal>
+</literallayout></para>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>GtkTree</title>
+
+<para><literallayout>
+<literal>void GtkTree::selection-changed       (GtkTree *,
+                                        gpointer);
+void GtkTree::select-child     (GtkTree *,
+                                GtkWidget *,
+                                gpointer);
+void GtkTree::unselect-child   (GtkTree *,
+                                GtkWidget *,
+                                gpointer);</literal>
+</literallayout></para>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>GtkButton</title>
+
+<para><literallayout>
+<literal>void GtkButton::pressed       (GtkButton *,
+                                gpointer);
+void GtkButton::released       (GtkButton *,
+                                gpointer);
+void GtkButton::clicked        (GtkButton *,
+                                gpointer);
+void GtkButton::enter  (GtkButton *,
+                        gpointer);
+void GtkButton::leave  (GtkButton *,
+                        gpointer);</literal>
+</literallayout></para>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>GtkItem</title>
+
+<para><literallayout>
+<literal>void GtkItem::select  (GtkItem *,
+                        gpointer);
+void GtkItem::deselect (GtkItem *,
+                        gpointer);
+void GtkItem::toggle   (GtkItem *,
+                        gpointer);</literal>
+</literallayout></para>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>GtkWindow</title>
+
+<para><literallayout>
+<literal>void GtkWindow::set-focus     (GtkWindow *,
+                                ggpointer,
+                                gpointer);</literal>
+</literallayout></para>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>GtkHandleBox</title>
+
+<para><literallayout>
+<literal>void GtkHandleBox::child-attached     (GtkHandleBox *,
+                                        GtkWidget *,
+                                        gpointer);
+void GtkHandleBox::child-detached      (GtkHandleBox *,
+                                        GtkWidget *,
+                                        gpointer);</literal>
+</literallayout></para>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>GtkToggleButton</title>
+
+<para><literallayout>
+<literal>void GtkToggleButton::toggled (GtkToggleButton *,
+                                gpointer);</para>
+
+<para></verb></tscreen></para>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>GtkMenuItem</title>
+
+<para><literallayout>
+<literal>void GtkMenuItem::activate    (GtkMenuItem *,
+                                gpointer);
+void GtkMenuItem::activate-item        (GtkMenuItem *,
+                                        gpointer);</literal>
+</literallayout></para>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>GtkListItem</title>
+
+<para><literallayout>
+<literal>void GtkListItem::toggle-focus-row    (GtkListItem *,
+                                        gpointer);
+void GtkListItem::select-all   (GtkListItem *,
+                                gpointer);
+void GtkListItem::unselect-all (GtkListItem *,
+                                gpointer);
+void GtkListItem::undo-selection       (GtkListItem *,
+                                        gpointer);
+void GtkListItem::start-selection      (GtkListItem *,
+                                        gpointer);
+void GtkListItem::end-selection        (GtkListItem *,
+                                        gpointer);
+void GtkListItem::toggle-add-mode      (GtkListItem *,
+                                        gpointer);
+void GtkListItem::extend-selection     (GtkListItem *,
+                                        GtkEnum,
+                                        ggfloat,
+                                        gboolean,
+                                        gpointer);
+void GtkListItem::scroll-vertical      (GtkListItem *,
+                                        GtkEnum,
+                                        ggfloat,
+                                        gpointer);
+void GtkListItem::scroll-horizontal    (GtkListItem *,
+                                        GtkEnum,
+                                        ggfloat,
+                                        gpointer);</literal>
+</literallayout></para>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>GtkTreeItem</title>
+
+<para><literallayout>
+<literal>void GtkTreeItem::collapse    (GtkTreeItem *,
+                                gpointer);
+void GtkTreeItem::expand       (GtkTreeItem *,
+                                gpointer);</literal>
+</literallayout></para>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>GtkCheckMenuItem</title>
+
+<para><literallayout>
+<literal>void GtkCheckMenuItem::toggled        (GtkCheckMenuItem *,
+                                gpointer);</literal>
+</literallayout></para>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>GtkInputDialog</title>
+
+<para><literallayout>
+<literal>void GtkInputDialog::enable-device    (GtkInputDialog *,
+                                        ggint,
+                                        gpointer);
+void GtkInputDialog::disable-device    (GtkInputDialog *,
+                                        ggint,
+                                        gpointer);</literal>
+</literallayout></para>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>GtkColorSelection</title>
+
+<para><literallayout>
+<literal>void GtkColorSelection::color-changed (GtkColorSelection *,
+                                        gpointer);</literal>
+</literallayout></para>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>GtkStatusBar</title>
+
+<para><literallayout>
+<literal>void GtkStatusbar::text-pushed        (GtkStatusbar *,
+                                gguint,
+                                GtkString *,
+                                gpointer);
+void GtkStatusbar::text-popped (GtkStatusbar *,
+                                gguint,
+                                GtkString *,
+                                gpointer);</literal>
+</literallayout></para>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>GtkCTree</title>
+
+<para><literallayout>
+<literal>void GtkCTree::tree-select-row        (GtkCTree *,
+                                GtkCTreeNode *,
+                                ggint,
+                                gpointer);
+void GtkCTree::tree-unselect-row       (GtkCTree *,
+                                        GtkCTreeNode *,
+                                        ggint,
+                                        gpointer);
+void GtkCTree::tree-expand     (GtkCTree *,
+                                GtkCTreeNode *,
+                                gpointer);
+void GtkCTree::tree-collapse   (GtkCTree *,
+                                ggpointer,
+                                gpointer);
+void GtkCTree::tree-move       (GtkCTree *,
+                                GtkCTreeNode *,
+                                GtkCTreeNode *,
+                                GtkCTreeNode *,
+                                gpointer);
+void GtkCTree::change-focus-row-expansion      (GtkCTree *,
+                                                GtkCTreeExpansionType,
+                                                gpointer);</literal>
+</literallayout></para>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>GtkCurve</title>
+
+<para><literallayout>
+<literal>void GtkCurve::curve-type-changed     (GtkCurve *,
+                                        gpointer);</literal>
+</literallayout></para>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>GtkAdjustment
+
+<para><literallayout>
+<literal>void GtkAdjustment::changed   (GtkAdjustment *,
+                                gpointer);
+void GtkAdjustment::value-changed      (GtkAdjustment *,
+                                        gpointer);</literal>
+</literallayout></para>
+
+</chapter>
+
+<!-- ***************************************************************** -->
+<appendix id="GDKEventTypes">
+<title>GDK Event Types</title>
+
+<para>The following data types are passed into event handlers by GTK+. For
+each data type listed, the signals that use this data type are listed.</para>
+
+<itemizedlist>
+<listitem><simpara>  GdkEvent
+          <itemizedlist>
+          <listitem><simpara>drag_end_event</simpara>
+         </listitem>
+          </itemizedlist>
+</simpara>
+</listitem>
+<listitem><simpara>  GdkEventType</para>
+</simpara>
+</listitem>
+<listitem><simpara>  GdkEventAny
+          <itemizedlist>
+          <listitem><simpara>delete_event</simpara>
+         </listitem>
+          <listitem><simpara>destroy_event</simpara>
+         </listitem>
+          <listitem><simpara>map_event</simpara>
+         </listitem>
+          <listitem><simpara>unmap_event</simpara>
+         </listitem>
+          <listitem><simpara>no_expose_event</simpara>
+         </listitem>
+          </itemizedlist>
+</simpara>
+</listitem>
+<listitem><simpara>  GdkEventExpose
+          <itemizedlist>
+          <listitem><simpara>expose_event</simpara>
+         </listitem>
+          </itemizedlist>
+</simpara>
+</listitem>
+<listitem><simpara>  GdkEventNoExpose</para>
+</simpara>
+</listitem>
+<listitem><simpara>  GdkEventVisibility</para>
+</simpara>
+</listitem>
+<listitem><simpara>  GdkEventMotion
+          <itemizedlist>
+          <listitem><simpara>motion_notify_event</simpara>
+         </listitem>
+         </itemizedlist>
+</simpara>
+</listitem>
+<listitem><simpara>  GdkEventButton
+          <itemizedlist>
+          <listitem><simpara>button_press_event</simpara>
+         </listitem>
+         <listitem><simpara>button_release_event</simpara>
+         </listitem>
+         </itemizedlist>
+</simpara>
+</listitem>
+<listitem><simpara>  GdkEventKey
+          <itemizedlist>
+          <listitem><simpara>key_press_event</simpara>
+         </listitem>
+          <listitem><simpara>key_release_event</simpara>
+         </listitem>
+         </itemizedlist>
+</simpara>
+</listitem>
+<listitem><simpara>  GdkEventCrossing
+          <itemizedlist>
+          <listitem><simpara>enter_notify_event</simpara>
+         </listitem>
+          <listitem><simpara>leave_notify_event</simpara>
+         </listitem>
+         </itemizedlist>
+</simpara>
+</listitem>
+<listitem><simpara>  GdkEventFocus
+          <itemizedlist>
+          <listitem><simpara>focus_in_event</simpara>
+         </listitem>
+          <listitem><simpara>focus_out_event</simpara>
+         </listitem>
+         </itemizedlist>
+</simpara>
+</listitem>
+<listitem><simpara>  GdkEventConfigure
+          <itemizedlist>
+          <listitem><simpara>configure_event</simpara>
+         </listitem>
+         </itemizedlist>
+</simpara>
+</listitem>
+<listitem><simpara>  GdkEventProperty
+          <itemizedlist>
+          <listitem><simpara>property_notify_event</simpara>
+         </listitem>
+         </itemizedlist>
+</simpara>
+</listitem>
+<listitem><simpara>  GdkEventSelection
+          <itemizedlist>
+          <listitem><simpara>selection_clear_event</simpara>
+         </listitem>
+          <listitem><simpara>selection_request_event</simpara>
+         </listitem>
+          <listitem><simpara>selection_notify_event</simpara>
+         </listitem>
+         </itemizedlist>
+</simpara>
+</listitem>
+<listitem><simpara>  GdkEventProximity
+          <itemizedlist>
+          <listitem><simpara>proximity_in_event</simpara>
+         </listitem>
+          <listitem><simpara>proximity_out_event</simpara>
+         </listitem>
+         </itemizedlist>
+</simpara>
+</listitem>
+<listitem><simpara>  GdkEventDragBegin
+          <itemizedlist>
+          <listitem><simpara>drag_begin_event</simpara>
+         </listitem>
+         </itemizedlist>
+</simpara>
+</listitem>
+<listitem><simpara>  GdkEventDragRequest
+          <itemizedlist>
+          <listitem><simpara>drag_request_event</simpara>
+         </listitem>
+         </itemizedlist>
+</simpara>
+</listitem>
+<listitem><simpara>  GdkEventDropEnter
+          <itemizedlist>
+          <listitem><simpara>drop_enter_event</simpara>
+         </listitem>
+         </itemizedlist>
+</simpara>
+</listitem>
+<listitem><simpara>  GdkEventDropLeave
+          <itemizedlist>
+          <listitem><simpara>drop_leave_event</simpara>
+         </listitem>
+         </itemizedlist>
+</simpara>
+</listitem>
+<listitem><simpara>  GdkEventDropDataAvailable
+          <itemizedlist>
+          <listitem><simpara>drop_data_available_event</simpara>
+         </listitem>
+         </itemizedlist>
+</simpara>
+</listitem>
+<listitem><simpara>  GdkEventClient
+          <itemizedlist>
+          <listitem><simpara>client_event</simpara>
+         </listitem>
+         </itemizedlist>
+</simpara>
+</listitem>
+<listitem><simpara>  GdkEventOther
+          <itemizedlist>
+          <listitem><simpara>other_event</simpara>
+         </listitem>
+         </itemizedlist></simpara>
+</listitem>
+</itemizedlist>
+
+<para>The data type <literal>GdkEventType</literal> is a special data type that is used by
+all the other data types as an indicator of the data type being passed
+to the signal handler. As you will see below, each of the event data
+structures has a member of this type. It is defined as an enumeration
+type as follows:</para>
+
+<para><literallayout>
+<literal>typedef enum
+{
+  GDK_NOTHING           = -1,
+  GDK_DELETE            = 0,
+  GDK_DESTROY           = 1,
+  GDK_EXPOSE            = 2,
+  GDK_MOTION_NOTIFY     = 3,
+  GDK_BUTTON_PRESS      = 4,
+  GDK_2BUTTON_PRESS     = 5,
+  GDK_3BUTTON_PRESS     = 6,
+  GDK_BUTTON_RELEASE    = 7,
+  GDK_KEY_PRESS         = 8,
+  GDK_KEY_RELEASE       = 9,
+  GDK_ENTER_NOTIFY      = 10,
+  GDK_LEAVE_NOTIFY      = 11,
+  GDK_FOCUS_CHANGE      = 12,
+  GDK_CONFIGURE         = 13,
+  GDK_MAP               = 14,
+  GDK_UNMAP             = 15,
+  GDK_PROPERTY_NOTIFY   = 16,
+  GDK_SELECTION_CLEAR   = 17,
+  GDK_SELECTION_REQUEST = 18,
+  GDK_SELECTION_NOTIFY  = 19,
+  GDK_PROXIMITY_IN      = 20,
+  GDK_PROXIMITY_OUT     = 21,
+  GDK_DRAG_BEGIN        = 22,
+  GDK_DRAG_REQUEST      = 23,
+  GDK_DROP_ENTER        = 24,
+  GDK_DROP_LEAVE        = 25,
+  GDK_DROP_DATA_AVAIL   = 26,
+  GDK_CLIENT_EVENT      = 27,
+  GDK_VISIBILITY_NOTIFY = 28,
+  GDK_NO_EXPOSE         = 29,
+  GDK_OTHER_EVENT       = 9999  /* Deprecated, use filters instead */
+} GdkEventType;</literal>
+</literallayout></para>
+
+<para>The other event type that is different from the others is
+<literal>GdkEvent</literal> itself. This is a union of all the other
+data types, which allows it to be cast to a specific
+event data type within a signal handler.</para>
+
+<para><!-- Just a big list for now, needs expanding upon - TRG -->
+So, the event data types are defined as follows:</para>
+
+<para><literallayout>
+<literal>struct _GdkEventAny
+{
+  GdkEventType type;
+  GdkWindow *window;
+  gint8 send_event;
+};</para>
+
+<para>struct _GdkEventExpose
+{
+  GdkEventType type;
+  GdkWindow *window;
+  gint8 send_event;
+  GdkRectangle area;
+  gint count; /* If non-zero, how many more events follow. */
+};</para>
+
+<para>struct _GdkEventNoExpose
+{
+  GdkEventType type;
+  GdkWindow *window;
+  gint8 send_event;
+  /* XXX: does anyone need the X major_code or minor_code fields? */
+};</para>
+
+<para>struct _GdkEventVisibility
+{
+  GdkEventType type;
+  GdkWindow *window;
+  gint8 send_event;
+  GdkVisibilityState state;
+};</para>
+
+<para>struct _GdkEventMotion
+{
+  GdkEventType type;
+  GdkWindow *window;
+  gint8 send_event;
+  guint32 time;
+  gdouble x;
+  gdouble y;
+  gdouble pressure;
+  gdouble xtilt;
+  gdouble ytilt;
+  guint state;
+  gint16 is_hint;
+  GdkInputSource source;
+  guint32 deviceid;
+  gdouble x_root, y_root;
+};</para>
+
+<para>struct _GdkEventButton
+{
+  GdkEventType type;
+  GdkWindow *window;
+  gint8 send_event;
+  guint32 time;
+  gdouble x;
+  gdouble y;
+  gdouble pressure;
+  gdouble xtilt;
+  gdouble ytilt;
+  guint state;
+  guint button;
+  GdkInputSource source;
+  guint32 deviceid;
+  gdouble x_root, y_root;
+};</para>
+
+<para>struct _GdkEventKey
+{
+  GdkEventType type;
+  GdkWindow *window;
+  gint8 send_event;
+  guint32 time;
+  guint state;
+  guint keyval;
+  gint length;
+  gchar *string;
+};</para>
+
+<para>struct _GdkEventCrossing
+{
+  GdkEventType type;
+  GdkWindow *window;
+  gint8 send_event;
+  GdkWindow *subwindow;
+  GdkNotifyType detail;
+};</para>
+
+<para>struct _GdkEventFocus
+{
+  GdkEventType type;
+  GdkWindow *window;
+  gint8 send_event;
+  gint16 in;
+};</para>
+
+<para>struct _GdkEventConfigure
+{
+  GdkEventType type;
+  GdkWindow *window;
+  gint8 send_event;
+  gint16 x, y;
+  gint16 width;
+  gint16 height;
+};</para>
+
+<para>struct _GdkEventProperty
+{
+  GdkEventType type;
+  GdkWindow *window;
+  gint8 send_event;
+  GdkAtom atom;
+  guint32 time;
+  guint state;
+};</para>
+
+<para>struct _GdkEventSelection
+{
+  GdkEventType type;
+  GdkWindow *window;
+  gint8 send_event;
+  GdkAtom selection;
+  GdkAtom target;
+  GdkAtom property;
+  guint32 requestor;
+  guint32 time;
+};</para>
+
+<para>/* This event type will be used pretty rarely. It only is important
+   for XInput aware programs that are drawing their own cursor */</para>
+
+<para>struct _GdkEventProximity
+{
+  GdkEventType type;
+  GdkWindow *window;
+  gint8 send_event;
+  guint32 time;
+  GdkInputSource source;
+  guint32 deviceid;
+};</para>
+
+<para>struct _GdkEventDragRequest
+{
+  GdkEventType type;
+  GdkWindow *window;
+  gint8 send_event;
+  guint32 requestor;
+  union {
+    struct {
+      guint protocol_version:4;
+      guint sendreply:1;
+      guint willaccept:1;
+      guint delete_data:1; /* Do *not* delete if link is sent, only
+                              if data is sent */
+      guint senddata:1;
+      guint reserved:22;
+    } flags;
+    glong allflags;
+  } u;
+  guint8 isdrop; /* This gdk event can be generated by a couple of
+                    X events - this lets the app know whether the
+                    drop really occurred or we just set the data */</para>
+
+<para>  GdkPoint drop_coords;
+  gchar *data_type;
+  guint32 timestamp;
+};</para>
+
+<para>struct _GdkEventDragBegin
+{
+  GdkEventType type;
+  GdkWindow *window;
+  gint8 send_event;
+  union {
+    struct {
+      guint protocol_version:4;
+      guint reserved:28;
+    } flags;
+    glong allflags;
+  } u;
+};</para>
+
+<para>struct _GdkEventDropEnter
+{
+  GdkEventType type;
+  GdkWindow *window;
+  gint8 send_event;
+  guint32 requestor;
+  union {
+    struct {
+      guint protocol_version:4;
+      guint sendreply:1;
+      guint extended_typelist:1;
+      guint reserved:26;
+    } flags;
+    glong allflags;
+  } u;
+};</para>
+
+<para>struct _GdkEventDropLeave
+{
+  GdkEventType type;
+  GdkWindow *window;
+  gint8 send_event;
+  guint32 requestor;
+  union {
+    struct {
+      guint protocol_version:4;
+      guint reserved:28;
+    } flags;
+    glong allflags;
+  } u;
+};</para>
+
+<para>struct _GdkEventDropDataAvailable
+{
+  GdkEventType type;
+  GdkWindow *window;
+  gint8 send_event;
+  guint32 requestor;
+  union {
+    struct {
+      guint protocol_version:4;
+      guint isdrop:1;
+      guint reserved:25;
+    } flags;
+    glong allflags;
+  } u;
+  gchar *data_type; /* MIME type */
+  gulong data_numbytes;
+  gpointer data;
+  guint32 timestamp;
+  GdkPoint coords;
+};</para>
+
+<para>struct _GdkEventClient
+{
+  GdkEventType type;
+  GdkWindow *window;
+  gint8 send_event;
+  GdkAtom message_type;
+  gushort data_format;
+  union {
+    char b[20];
+    short s[10];
+    long l[5];
+  } data;
+};</para>
+
+<para>struct _GdkEventOther
+{
+  GdkEventType type;
+  GdkWindow *window;
+  gint8 send_event;
+  GdkXEvent *xevent;
+};</literal>
+</literallayout></para>
+
+</chapter>
+
+<!-- ***************************************************************** -->
+<appendix id="app_CodeExamples">
+<title> Code Examples</title>
+
+<para>Below are the code examples that are used in the above text
+which are not included in complete form elsewhere.</para>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Tictactoe</title>
+<!-- ----------------------------------------------------------------- -->
+<sect2>
+<title>tictactoe.h</title>
+
+<programlisting role="C">
+/* example-start tictactoe tictactoe.h */
+
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef __TICTACTOE_H__
+#define __TICTACTOE_H__
+
+
+#include &lt;gdk/gdk.h&gt;
+#include &lt;gtk/gtkvbox.h&gt;
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define TICTACTOE(obj)          GTK_CHECK_CAST (obj, tictactoe_get_type (), Tictactoe)
+#define TICTACTOE_CLASS(klass)  GTK_CHECK_CLASS_CAST (klass, tictactoe_get_type (), TictactoeClass)
+#define IS_TICTACTOE(obj)       GTK_CHECK_TYPE (obj, tictactoe_get_type ())
+
+
+typedef struct _Tictactoe       Tictactoe;
+typedef struct _TictactoeClass  TictactoeClass;
+
+struct _Tictactoe
+{
+  GtkVBox vbox;
+  
+  GtkWidget *buttons[3][3];
+};
+
+struct _TictactoeClass
+{
+  GtkVBoxClass parent_class;
+
+  void (* tictactoe) (Tictactoe *ttt);
+};
+
+guint          tictactoe_get_type        (void);
+GtkWidget*     tictactoe_new             (void);
+void          tictactoe_clear           (Tictactoe *ttt);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __TICTACTOE_H__ */
+
+/* example-end */
+</programlisting>
+
+</sect2>
+
+<!-- ----------------------------------------------------------------- -->
+<sect2>
+<title>tictactoe.c</title>
+
+<programlisting role="C">
+/* example-start tictactoe tictactoe.c */
+
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#include "gtk/gtksignal.h"
+#include "gtk/gtktable.h"
+#include "gtk/gtktogglebutton.h"
+#include "tictactoe.h"
+
+enum {
+  TICTACTOE_SIGNAL,
+  LAST_SIGNAL
+};
+
+static void tictactoe_class_init          (TictactoeClass *klass);
+static void tictactoe_init                (Tictactoe      *ttt);
+static void tictactoe_toggle              (GtkWidget *widget, Tictactoe *ttt);
+
+static gint tictactoe_signals[LAST_SIGNAL] = { 0 };
+
+guint
+tictactoe_get_type ()
+{
+  static guint ttt_type = 0;
+
+  if (!ttt_type)
+    {
+      GtkTypeInfo ttt_info =
+      {
+       "Tictactoe",
+       sizeof (Tictactoe),
+       sizeof (TictactoeClass),
+       (GtkClassInitFunc) tictactoe_class_init,
+       (GtkObjectInitFunc) tictactoe_init,
+        (GtkArgSetFunc) NULL,
+        (GtkArgGetFunc) NULL
+      };
+
+      ttt_type = gtk_type_unique (gtk_vbox_get_type (), &amp;ttt_info);
+    }
+
+  return ttt_type;
+}
+
+static void
+tictactoe_class_init (TictactoeClass *class)
+{
+  GtkObjectClass *object_class;
+
+  object_class = (GtkObjectClass*) class;
+  
+  tictactoe_signals[TICTACTOE_SIGNAL] = gtk_signal_new ("tictactoe",
+                                        GTK_RUN_FIRST,
+                                        object_class->type,
+                                        GTK_SIGNAL_OFFSET (TictactoeClass,
+                                                            tictactoe),
+                                        gtk_signal_default_marshaller,
+                                         GTK_TYPE_NONE, 0);
+
+
+  gtk_object_class_add_signals (object_class, tictactoe_signals, LAST_SIGNAL);
+
+  class->tictactoe = NULL;
+}
+
+static void
+tictactoe_init (Tictactoe *ttt)
+{
+  GtkWidget *table;
+  gint i,j;
+  
+  table = gtk_table_new (3, 3, TRUE);
+  gtk_container_add (GTK_CONTAINER(ttt), table);
+  gtk_widget_show (table);
+
+  for (i=0;i<3; i++)
+    for (j=0;j<3; j++)
+      {
+       ttt->buttons[i][j] = gtk_toggle_button_new ();
+       gtk_table_attach_defaults (GTK_TABLE(table), ttt->buttons[i][j], 
+                                  i, i+1, j, j+1);
+       gtk_signal_connect (GTK_OBJECT (ttt->buttons[i][j]), "toggled",
+                           GTK_SIGNAL_FUNC (tictactoe_toggle), ttt);
+       gtk_widget_set_usize (ttt->buttons[i][j], 20, 20);
+       gtk_widget_show (ttt->buttons[i][j]);
+      }
+}
+
+GtkWidget*
+tictactoe_new ()
+{
+  return GTK_WIDGET ( gtk_type_new (tictactoe_get_type ()));
+}
+
+void          
+tictactoe_clear (Tictactoe *ttt)
+{
+  int i,j;
+
+  for (i=0;i<3;i++)
+    for (j=0;j<3;j++)
+      {
+       gtk_signal_handler_block_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
+       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ttt->buttons[i][j]),
+                                    FALSE);
+       gtk_signal_handler_unblock_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
+      }
+}
+
+static void
+tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt)
+{
+  int i,k;
+
+  static int rwins[8][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
+                            { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
+                            { 0, 1, 2 }, { 0, 1, 2 } };
+  static int cwins[8][3] = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
+                            { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
+                            { 0, 1, 2 }, { 2, 1, 0 } };
+
+  int success, found;
+
+  for (k=0; k<8; k++)
+    {
+      success = TRUE;
+      found = FALSE;
+
+      for (i=0;i<3;i++)
+       {
+         success = success &amp;&amp; 
+           GTK_TOGGLE_BUTTON(ttt->buttons[rwins[k][i]][cwins[k][i]])->active;
+         found = found ||
+           ttt->buttons[rwins[k][i]][cwins[k][i]] == widget;
+       }
+      
+      if (success &amp;&amp; found)
+       {
+         gtk_signal_emit (GTK_OBJECT (ttt), 
+                          tictactoe_signals[TICTACTOE_SIGNAL]);
+         break;
+       }
+    }
+}
+
+/* example-end */
+</programlisting>
+
+</sect2>
+
+<!-- ----------------------------------------------------------------- -->
+<sect2>
+<title>ttt_test.c</title>
+
+<programlisting role="C">
+/* example-start tictactoe ttt_test.c */
+
+#include &lt;gtk/gtk.h&gt;
+#include "tictactoe.h"
+
+void win( GtkWidget *widget,
+          gpointer   data )
+{
+  g_print ("Yay!\n");
+  tictactoe_clear (TICTACTOE (widget));
+}
+
+int main( int   argc,
+          char *argv[] )
+{
+  GtkWidget *window;
+  GtkWidget *ttt;
+  
+  gtk_init (&amp;argc, &amp;argv);
+
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  
+  gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
+  
+  gtk_signal_connect (GTK_OBJECT (window), "destroy",
+                     GTK_SIGNAL_FUNC (gtk_exit), NULL);
+  
+  gtk_container_set_border_width (GTK_CONTAINER (window), 10);
+
+  ttt = tictactoe_new ();
+  
+  gtk_container_add (GTK_CONTAINER (window), ttt);
+  gtk_widget_show (ttt);
+
+  gtk_signal_connect (GTK_OBJECT (ttt), "tictactoe",
+                     GTK_SIGNAL_FUNC (win), NULL);
+
+  gtk_widget_show (window);
+  
+  gtk_main ();
+  
+  return 0;
+}
+
+/* example-end */
+</programlisting>
+
+</sect2>
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> GtkDial</title>
+
+<!-- ----------------------------------------------------------------- -->
+<sect2>
+<title> gtkdial.h</title>
+
+<programlisting role="C">
+/* example-start gtkdial gtkdial.h */
+
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef __GTK_DIAL_H__
+#define __GTK_DIAL_H__
+
+
+#include &lt;gdk/gdk.h&gt;
+#include &lt;gtk/gtkadjustment.h&gt;
+#include &lt;gtk/gtkwidget.h&gt;
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+#define GTK_DIAL(obj)          GTK_CHECK_CAST (obj, gtk_dial_get_type (), GtkDial)
+#define GTK_DIAL_CLASS(klass)  GTK_CHECK_CLASS_CAST (klass, gtk_dial_get_type (), GtkDialClass)
+#define GTK_IS_DIAL(obj)       GTK_CHECK_TYPE (obj, gtk_dial_get_type ())
+
+
+typedef struct _GtkDial        GtkDial;
+typedef struct _GtkDialClass   GtkDialClass;
+
+struct _GtkDial
+{
+  GtkWidget widget;
+
+  /* update policy (GTK_UPDATE_[CONTINUOUS/DELAYED/DISCONTINUOUS]) */
+  guint policy : 2;
+
+  /* Button currently pressed or 0 if none */
+  guint8 button;
+
+  /* Dimensions of dial components */
+  gint radius;
+  gint pointer_width;
+
+  /* ID of update timer, or 0 if none */
+  guint32 timer;
+
+  /* Current angle */
+  gfloat angle;
+  gfloat last_angle;
+
+  /* Old values from adjustment stored so we know when something changes */
+  gfloat old_value;
+  gfloat old_lower;
+  gfloat old_upper;
+
+  /* The adjustment object that stores the data for this dial */
+  GtkAdjustment *adjustment;
+};
+
+struct _GtkDialClass
+{
+  GtkWidgetClass parent_class;
+};
+
+
+GtkWidget*     gtk_dial_new                    (GtkAdjustment *adjustment);
+guint          gtk_dial_get_type               (void);
+GtkAdjustment* gtk_dial_get_adjustment         (GtkDial      *dial);
+void           gtk_dial_set_update_policy      (GtkDial      *dial,
+                                               GtkUpdateType  policy);
+
+void           gtk_dial_set_adjustment         (GtkDial      *dial,
+                                               GtkAdjustment *adjustment);
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GTK_DIAL_H__ */
+/* example-end */
+</programlisting>
+
+</sect2>
+
+<!-- ----------------------------------------------------------------- -->
+<sect2>
+<title> gtkdial.c</title>
+
+<programlisting role="C">
+/* example-start gtkdial gtkdial.c */
+
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#include &lt;math.h&gt;
+#include &lt;stdio.h&gt;
+#include &lt;gtk/gtkmain.h&gt;
+#include &lt;gtk/gtksignal.h&gt;
+
+#include "gtkdial.h"
+
+#define SCROLL_DELAY_LENGTH  300
+#define DIAL_DEFAULT_SIZE 100
+
+/* Forward declarations */
+
+static void gtk_dial_class_init               (GtkDialClass    *klass);
+static void gtk_dial_init                     (GtkDial         *dial);
+static void gtk_dial_destroy                  (GtkObject        *object);
+static void gtk_dial_realize                  (GtkWidget        *widget);
+static void gtk_dial_size_request             (GtkWidget      *widget,
+                                              GtkRequisition *requisition);
+static void gtk_dial_size_allocate            (GtkWidget     *widget,
+                                              GtkAllocation *allocation);
+static gint gtk_dial_expose                   (GtkWidget        *widget,
+                                               GdkEventExpose   *event);
+static gint gtk_dial_button_press             (GtkWidget        *widget,
+                                               GdkEventButton   *event);
+static gint gtk_dial_button_release           (GtkWidget        *widget,
+                                               GdkEventButton   *event);
+static gint gtk_dial_motion_notify            (GtkWidget        *widget,
+                                               GdkEventMotion   *event);
+static gint gtk_dial_timer                    (GtkDial         *dial);
+
+static void gtk_dial_update_mouse             (GtkDial *dial, gint x, gint y);
+static void gtk_dial_update                   (GtkDial *dial);
+static void gtk_dial_adjustment_changed       (GtkAdjustment    *adjustment,
+                                               gpointer          data);
+static void gtk_dial_adjustment_value_changed (GtkAdjustment    *adjustment,
+                                               gpointer          data);
+
+/* Local data */
+
+static GtkWidgetClass *parent_class = NULL;
+
+guint
+gtk_dial_get_type ()
+{
+  static guint dial_type = 0;
+
+  if (!dial_type)
+    {
+      GtkTypeInfo dial_info =
+      {
+       "GtkDial",
+       sizeof (GtkDial),
+       sizeof (GtkDialClass),
+       (GtkClassInitFunc) gtk_dial_class_init,
+       (GtkObjectInitFunc) gtk_dial_init,
+       (GtkArgSetFunc) NULL,
+       (GtkArgGetFunc) NULL,
+      };
+
+      dial_type = gtk_type_unique (gtk_widget_get_type (), &amp;dial_info);
+    }
+
+  return dial_type;
+}
+
+static void
+gtk_dial_class_init (GtkDialClass *class)
+{
+  GtkObjectClass *object_class;
+  GtkWidgetClass *widget_class;
+
+  object_class = (GtkObjectClass*) class;
+  widget_class = (GtkWidgetClass*) class;
+
+  parent_class = gtk_type_class (gtk_widget_get_type ());
+
+  object_class->destroy = gtk_dial_destroy;
+
+  widget_class->realize = gtk_dial_realize;
+  widget_class->expose_event = gtk_dial_expose;
+  widget_class->size_request = gtk_dial_size_request;
+  widget_class->size_allocate = gtk_dial_size_allocate;
+  widget_class->button_press_event = gtk_dial_button_press;
+  widget_class->button_release_event = gtk_dial_button_release;
+  widget_class->motion_notify_event = gtk_dial_motion_notify;
+}
+
+static void
+gtk_dial_init (GtkDial *dial)
+{
+  dial->button = 0;
+  dial->policy = GTK_UPDATE_CONTINUOUS;
+  dial->timer = 0;
+  dial->radius = 0;
+  dial->pointer_width = 0;
+  dial->angle = 0.0;
+  dial->old_value = 0.0;
+  dial->old_lower = 0.0;
+  dial->old_upper = 0.0;
+  dial->adjustment = NULL;
+}
+
+GtkWidget*
+gtk_dial_new (GtkAdjustment *adjustment)
+{
+  GtkDial *dial;
+
+  dial = gtk_type_new (gtk_dial_get_type ());
+
+  if (!adjustment)
+    adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
+
+  gtk_dial_set_adjustment (dial, adjustment);
+
+  return GTK_WIDGET (dial);
+}
+
+static void
+gtk_dial_destroy (GtkObject *object)
+{
+  GtkDial *dial;
+
+  g_return_if_fail (object != NULL);
+  g_return_if_fail (GTK_IS_DIAL (object));
+
+  dial = GTK_DIAL (object);
+
+  if (dial->adjustment)
+    gtk_object_unref (GTK_OBJECT (dial->adjustment));
+
+  if (GTK_OBJECT_CLASS (parent_class)->destroy)
+    (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
+}
+
+GtkAdjustment*
+gtk_dial_get_adjustment (GtkDial *dial)
+{
+  g_return_val_if_fail (dial != NULL, NULL);
+  g_return_val_if_fail (GTK_IS_DIAL (dial), NULL);
+
+  return dial->adjustment;
+}
+
+void
+gtk_dial_set_update_policy (GtkDial      *dial,
+                            GtkUpdateType  policy)
+{
+  g_return_if_fail (dial != NULL);
+  g_return_if_fail (GTK_IS_DIAL (dial));
+
+  dial->policy = policy;
+}
+
+void
+gtk_dial_set_adjustment (GtkDial      *dial,
+                         GtkAdjustment *adjustment)
+{
+  g_return_if_fail (dial != NULL);
+  g_return_if_fail (GTK_IS_DIAL (dial));
+
+  if (dial->adjustment)
+    {
+      gtk_signal_disconnect_by_data (GTK_OBJECT (dial->adjustment), (gpointer) dial);
+      gtk_object_unref (GTK_OBJECT (dial->adjustment));
+    }
+
+  dial->adjustment = adjustment;
+  gtk_object_ref (GTK_OBJECT (dial->adjustment));
+
+  gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
+                     (GtkSignalFunc) gtk_dial_adjustment_changed,
+                     (gpointer) dial);
+  gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
+                     (GtkSignalFunc) gtk_dial_adjustment_value_changed,
+                     (gpointer) dial);
+
+  dial->old_value = adjustment->value;
+  dial->old_lower = adjustment->lower;
+  dial->old_upper = adjustment->upper;
+
+  gtk_dial_update (dial);
+}
+
+static void
+gtk_dial_realize (GtkWidget *widget)
+{
+  GtkDial *dial;
+  GdkWindowAttr attributes;
+  gint attributes_mask;
+
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_DIAL (widget));
+
+  GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
+  dial = GTK_DIAL (widget);
+
+  attributes.x = widget->allocation.x;
+  attributes.y = widget->allocation.y;
+  attributes.width = widget->allocation.width;
+  attributes.height = widget->allocation.height;
+  attributes.wclass = GDK_INPUT_OUTPUT;
+  attributes.window_type = GDK_WINDOW_CHILD;
+  attributes.event_mask = gtk_widget_get_events (widget) | 
+    GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | 
+    GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
+    GDK_POINTER_MOTION_HINT_MASK;
+  attributes.visual = gtk_widget_get_visual (widget);
+  attributes.colormap = gtk_widget_get_colormap (widget);
+
+  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+  widget->window = gdk_window_new (widget->parent->window, &amp;attributes, attributes_mask);
+
+  widget->style = gtk_style_attach (widget->style, widget->window);
+
+  gdk_window_set_user_data (widget->window, widget);
+
+  gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
+}
+
+static void 
+gtk_dial_size_request (GtkWidget      *widget,
+                      GtkRequisition *requisition)
+{
+  requisition->width = DIAL_DEFAULT_SIZE;
+  requisition->height = DIAL_DEFAULT_SIZE;
+}
+
+static void
+gtk_dial_size_allocate (GtkWidget     *widget,
+                       GtkAllocation *allocation)
+{
+  GtkDial *dial;
+
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_DIAL (widget));
+  g_return_if_fail (allocation != NULL);
+
+  widget->allocation = *allocation;
+  dial = GTK_DIAL (widget);
+
+  if (GTK_WIDGET_REALIZED (widget))
+    {
+
+      gdk_window_move_resize (widget->window,
+                             allocation->x, allocation->y,
+                             allocation->width, allocation->height);
+
+    }
+  dial->radius = MIN(allocation->width,allocation->height) * 0.45;
+  dial->pointer_width = dial->radius / 5;
+}
+
+static gint
+gtk_dial_expose (GtkWidget      *widget,
+                GdkEventExpose *event)
+{
+  GtkDial *dial;
+  GdkPoint points[6];
+  gdouble s,c;
+  gdouble theta, last, increment;
+  GtkStyle      *blankstyle;
+  gint xc, yc;
+  gint upper, lower;
+  gint tick_length;
+  gint i, inc;
+
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
+
+  if (event->count > 0)
+    return FALSE;
+  
+  dial = GTK_DIAL (widget);
+
+/*  gdk_window_clear_area (widget->window,
+                        0, 0,
+                        widget->allocation.width,
+                        widget->allocation.height);
+*/
+  xc = widget->allocation.width/2;
+  yc = widget->allocation.height/2;
+
+  upper = dial->adjustment->upper;
+  lower = dial->adjustment->lower;
+
+  /* Erase old pointer */
+
+  s = sin(dial->last_angle);
+  c = cos(dial->last_angle);
+  dial->last_angle = dial->angle;
+
+  points[0].x = xc + s*dial->pointer_width/2;
+  points[0].y = yc + c*dial->pointer_width/2;
+  points[1].x = xc + c*dial->radius;
+  points[1].y = yc - s*dial->radius;
+  points[2].x = xc - s*dial->pointer_width/2;
+  points[2].y = yc - c*dial->pointer_width/2;
+  points[3].x = xc - c*dial->radius/10;
+  points[3].y = yc + s*dial->radius/10;
+  points[4].x = points[0].x;
+  points[4].y = points[0].y;
+
+  blankstyle = gtk_style_new ();
+  blankstyle->bg_gc[GTK_STATE_NORMAL] =
+                widget->style->bg_gc[GTK_STATE_NORMAL];
+  blankstyle->dark_gc[GTK_STATE_NORMAL] =
+                widget->style->bg_gc[GTK_STATE_NORMAL];
+  blankstyle->light_gc[GTK_STATE_NORMAL] =
+                widget->style->bg_gc[GTK_STATE_NORMAL];
+  blankstyle->black_gc =
+                widget->style->bg_gc[GTK_STATE_NORMAL];
+
+  gtk_draw_polygon (blankstyle,
+                    widget->window,
+                    GTK_STATE_NORMAL,
+                    GTK_SHADOW_OUT,
+                    points, 5,
+                    FALSE);
+
+  gtk_style_unref(blankstyle);
+
+
+  /* Draw ticks */
+
+  if ((upper - lower) == 0)
+    return;
+
+  increment = (100*M_PI)/(dial->radius*dial->radius);
+
+  inc = (upper - lower);
+
+  while (inc < 100) inc *=10;
+  while (inc >= 1000) inc /=10;
+  last = -1;
+
+  for (i=0; i<=inc; i++)
+    {
+      theta = ((gfloat)i*M_PI/(18*inc/24.) - M_PI/6.);
+
+      if ((theta - last) < (increment))
+       continue;     
+      last = theta;
+
+      s = sin(theta);
+      c = cos(theta);
+
+      tick_length = (i%(inc/10) == 0) ? dial->pointer_width : dial->pointer_width/2;
+
+      gdk_draw_line (widget->window,
+                     widget->style->fg_gc[widget->state],
+                     xc + c*(dial->radius - tick_length),
+                     yc - s*(dial->radius - tick_length),
+                     xc + c*dial->radius,
+                     yc - s*dial->radius);
+    }
+
+  /* Draw pointer */
+
+  s = sin(dial->angle);
+  c = cos(dial->angle);
+  dial->last_angle = dial->angle;
+
+  points[0].x = xc + s*dial->pointer_width/2;
+  points[0].y = yc + c*dial->pointer_width/2;
+  points[1].x = xc + c*dial->radius;
+  points[1].y = yc - s*dial->radius;
+  points[2].x = xc - s*dial->pointer_width/2;
+  points[2].y = yc - c*dial->pointer_width/2;
+  points[3].x = xc - c*dial->radius/10;
+  points[3].y = yc + s*dial->radius/10;
+  points[4].x = points[0].x;
+  points[4].y = points[0].y;
+
+
+  gtk_draw_polygon (widget->style,
+                   widget->window,
+                   GTK_STATE_NORMAL,
+                   GTK_SHADOW_OUT,
+                   points, 5,
+                   TRUE);
+
+  return FALSE;
+}
+
+static gint
+gtk_dial_button_press (GtkWidget      *widget,
+                      GdkEventButton *event)
+{
+  GtkDial *dial;
+  gint dx, dy;
+  double s, c;
+  double d_parallel;
+  double d_perpendicular;
+
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
+
+  dial = GTK_DIAL (widget);
+
+  /* Determine if button press was within pointer region - we 
+     do this by computing the parallel and perpendicular distance of
+     the point where the mouse was pressed from the line passing through
+     the pointer */
+  
+  dx = event->x - widget->allocation.width / 2;
+  dy = widget->allocation.height / 2 - event->y;
+  
+  s = sin(dial->angle);
+  c = cos(dial->angle);
+  
+  d_parallel = s*dy + c*dx;
+  d_perpendicular = fabs(s*dx - c*dy);
+  
+  if (!dial->button &amp;&amp;
+      (d_perpendicular < dial->pointer_width/2) &amp;&amp;
+      (d_parallel > - dial->pointer_width))
+    {
+      gtk_grab_add (widget);
+
+      dial->button = event->button;
+
+      gtk_dial_update_mouse (dial, event->x, event->y);
+    }
+
+  return FALSE;
+}
+
+static gint
+gtk_dial_button_release (GtkWidget      *widget,
+                         GdkEventButton *event)
+{
+  GtkDial *dial;
+
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
+
+  dial = GTK_DIAL (widget);
+
+  if (dial->button == event->button)
+    {
+      gtk_grab_remove (widget);
+
+      dial->button = 0;
+
+      if (dial->policy == GTK_UPDATE_DELAYED)
+       gtk_timeout_remove (dial->timer);
+      
+      if ((dial->policy != GTK_UPDATE_CONTINUOUS) &amp;&amp;
+         (dial->old_value != dial->adjustment->value))
+       gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
+    }
+
+  return FALSE;
+}
+
+static gint
+gtk_dial_motion_notify (GtkWidget      *widget,
+                        GdkEventMotion *event)
+{
+  GtkDial *dial;
+  GdkModifierType mods;
+  gint x, y, mask;
+
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
+
+  dial = GTK_DIAL (widget);
+
+  if (dial->button != 0)
+    {
+      x = event->x;
+      y = event->y;
+
+      if (event->is_hint || (event->window != widget->window))
+       gdk_window_get_pointer (widget->window, &amp;x, &amp;y, &amp;mods);
+
+      switch (dial->button)
+       {
+       case 1:
+         mask = GDK_BUTTON1_MASK;
+         break;
+       case 2:
+         mask = GDK_BUTTON2_MASK;
+         break;
+       case 3:
+         mask = GDK_BUTTON3_MASK;
+         break;
+       default:
+         mask = 0;
+         break;
+       }
+
+      if (mods &amp; mask)
+       gtk_dial_update_mouse (dial, x,y);
+    }
+
+  return FALSE;
+}
+
+static gint
+gtk_dial_timer (GtkDial *dial)
+{
+  g_return_val_if_fail (dial != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_DIAL (dial), FALSE);
+
+  if (dial->policy == GTK_UPDATE_DELAYED)
+    gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
+
+  return FALSE;
+}
+
+static void
+gtk_dial_update_mouse (GtkDial *dial, gint x, gint y)
+{
+  gint xc, yc;
+  gfloat old_value;
+
+  g_return_if_fail (dial != NULL);
+  g_return_if_fail (GTK_IS_DIAL (dial));
+
+  xc = GTK_WIDGET(dial)->allocation.width / 2;
+  yc = GTK_WIDGET(dial)->allocation.height / 2;
+
+  old_value = dial->adjustment->value;
+  dial->angle = atan2(yc-y, x-xc);
+
+  if (dial->angle < -M_PI/2.)
+    dial->angle += 2*M_PI;
+
+  if (dial->angle < -M_PI/6)
+    dial->angle = -M_PI/6;
+
+  if (dial->angle > 7.*M_PI/6.)
+    dial->angle = 7.*M_PI/6.;
+
+  dial->adjustment->value = dial->adjustment->lower + (7.*M_PI/6 - dial->angle) *
+    (dial->adjustment->upper - dial->adjustment->lower) / (4.*M_PI/3.);
+
+  if (dial->adjustment->value != old_value)
+    {
+      if (dial->policy == GTK_UPDATE_CONTINUOUS)
+       {
+         gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
+       }
+      else
+       {
+         gtk_widget_draw (GTK_WIDGET(dial), NULL);
+
+         if (dial->policy == GTK_UPDATE_DELAYED)
+           {
+             if (dial->timer)
+               gtk_timeout_remove (dial->timer);
+
+             dial->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
+                                            (GtkFunction) gtk_dial_timer,
+                                            (gpointer) dial);
+           }
+       }
+    }
+}
+
+static void
+gtk_dial_update (GtkDial *dial)
+{
+  gfloat new_value;
+  
+  g_return_if_fail (dial != NULL);
+  g_return_if_fail (GTK_IS_DIAL (dial));
+
+  new_value = dial->adjustment->value;
+  
+  if (new_value < dial->adjustment->lower)
+    new_value = dial->adjustment->lower;
+
+  if (new_value > dial->adjustment->upper)
+    new_value = dial->adjustment->upper;
+
+  if (new_value != dial->adjustment->value)
+    {
+      dial->adjustment->value = new_value;
+      gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
+    }
+
+  dial->angle = 7.*M_PI/6. - (new_value - dial->adjustment->lower) * 4.*M_PI/3. /
+    (dial->adjustment->upper - dial->adjustment->lower);
+
+  gtk_widget_draw (GTK_WIDGET(dial), NULL);
+}
+
+static void
+gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
+                             gpointer       data)
+{
+  GtkDial *dial;
+
+  g_return_if_fail (adjustment != NULL);
+  g_return_if_fail (data != NULL);
+
+  dial = GTK_DIAL (data);
+
+  if ((dial->old_value != adjustment->value) ||
+      (dial->old_lower != adjustment->lower) ||
+      (dial->old_upper != adjustment->upper))
+    {
+      gtk_dial_update (dial);
+
+      dial->old_value = adjustment->value;
+      dial->old_lower = adjustment->lower;
+      dial->old_upper = adjustment->upper;
+    }
+}
+
+static void
+gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
+                                   gpointer       data)
+{
+  GtkDial *dial;
+
+  g_return_if_fail (adjustment != NULL);
+  g_return_if_fail (data != NULL);
+
+  dial = GTK_DIAL (data);
+
+  if (dial->old_value != adjustment->value)
+    {
+      gtk_dial_update (dial);
+
+      dial->old_value = adjustment->value;
+    }
+}
+/* example-end */
+
+<para></verb></tscreen></para>
+
+</sect2>
+
+<!-- ----------------------------------------------------------------- -->
+<sect2>
+<title> dial_test.c</title>
+
+<para><literallayout>
+<literal>#include &lt;stdio.h&gt;
+#include &lt;gtk/gtk.h&gt;
+#include "gtkdial.h"
+
+void value_changed( GtkAdjustment *adjustment,
+                    GtkWidget     *label )
+{
+  char buffer[16];
+
+  sprintf(buffer,"%4.2f",adjustment->value);
+  gtk_label_set (GTK_LABEL (label), buffer);
+}
+
+int main( int   argc,
+          char *argv[])
+{
+  GtkWidget *window;
+  GtkAdjustment *adjustment;
+  GtkWidget *dial;
+  GtkWidget *frame;
+  GtkWidget *vbox;
+  GtkWidget *label;
+  
+  gtk_init (&amp;argc, &amp;argv);
+
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  
+  gtk_window_set_title (GTK_WINDOW (window), "Dial");
+  
+  gtk_signal_connect (GTK_OBJECT (window), "destroy",
+                     GTK_SIGNAL_FUNC (gtk_exit), NULL);
+  
+  gtk_container_border_width (GTK_CONTAINER (window), 10);
+
+  vbox = gtk_vbox_new (FALSE, 5);
+  gtk_container_add (GTK_CONTAINER (window), vbox);
+  gtk_widget_show(vbox);
+
+  frame = gtk_frame_new (NULL);
+  gtk_frame_set_shadow_type (GTK_FRAME(frame), GTK_SHADOW_IN);
+  gtk_container_add (GTK_CONTAINER (vbox), frame);
+  gtk_widget_show (frame); 
+  adjustment = GTK_ADJUSTMENT(gtk_adjustment_new (0, 0, 100, 0.01, 0.1, 0));
+  
+  dial = gtk_dial_new(adjustment);
+  gtk_dial_set_update_policy (GTK_DIAL(dial), GTK_UPDATE_DELAYED);
+  /*  gtk_widget_set_usize (dial, 100, 100); */
+  
+  gtk_container_add (GTK_CONTAINER (frame), dial);
+  gtk_widget_show (dial);
+
+  label = gtk_label_new("0.00");
+  gtk_box_pack_end (GTK_BOX(vbox), label, 0, 0, 0);
+  gtk_widget_show (label);
+
+  gtk_signal_connect (GTK_OBJECT(adjustment), "value_changed",
+                     GTK_SIGNAL_FUNC (value_changed), label);
+  
+  gtk_widget_show (window);
+  
+  gtk_main ();
+  
+  return 0;
+}</para>
+
+<para></verb></tscreen></para>
+
+</sect2>
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> Scribble</title>
+
+<!-- ----------------------------------------------------------------- -->
+<sect2>
+<title> scribble-simple.c</title>
+
+<programlisting role="C">
+/* example-start scribble-simple scribble-simple.c */
+
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include &lt;gtk/gtk.h&gt;
+
+/* Backing pixmap for drawing area */
+static GdkPixmap *pixmap = NULL;
+
+/* Create a new backing pixmap of the appropriate size */
+static gint configure_event( GtkWidget         *widget,
+                             GdkEventConfigure *event )
+{
+  if (pixmap)
+    gdk_pixmap_unref(pixmap);
+
+  pixmap = gdk_pixmap_new(widget->window,
+                         widget->allocation.width,
+                         widget->allocation.height,
+                         -1);
+  gdk_draw_rectangle (pixmap,
+                     widget->style->white_gc,
+                     TRUE,
+                     0, 0,
+                     widget->allocation.width,
+                     widget->allocation.height);
+
+  return TRUE;
+}
+
+/* Redraw the screen from the backing pixmap */
+static gint expose_event( GtkWidget      *widget,
+                          GdkEventExpose *event )
+{
+  gdk_draw_pixmap(widget->window,
+                 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
+                 pixmap,
+                 event->area.x, event->area.y,
+                 event->area.x, event->area.y,
+                 event->area.width, event->area.height);
+
+  return FALSE;
+}
+
+/* Draw a rectangle on the screen */
+static void draw_brush( GtkWidget *widget,
+                        gdouble    x,
+                        gdouble    y)
+{
+  GdkRectangle update_rect;
+
+  update_rect.x = x - 5;
+  update_rect.y = y - 5;
+  update_rect.width = 10;
+  update_rect.height = 10;
+  gdk_draw_rectangle (pixmap,
+                     widget->style->black_gc,
+                     TRUE,
+                     update_rect.x, update_rect.y,
+                     update_rect.width, update_rect.height);
+  gtk_widget_draw (widget, &amp;update_rect);
+}
+
+static gint button_press_event( GtkWidget      *widget,
+                                GdkEventButton *event )
+{
+  if (event->button == 1 &amp;&amp; pixmap != NULL)
+    draw_brush (widget, event->x, event->y);
+
+  return TRUE;
+}
+
+static gint motion_notify_event( GtkWidget *widget,
+                                 GdkEventMotion *event )
+{
+  int x, y;
+  GdkModifierType state;
+
+  if (event->is_hint)
+    gdk_window_get_pointer (event->window, &amp;x, &amp;y, &amp;state);
+  else
+    {
+      x = event->x;
+      y = event->y;
+      state = event->state;
+    }
+    
+  if (state &amp; GDK_BUTTON1_MASK &amp;&amp; pixmap != NULL)
+    draw_brush (widget, x, y);
+  
+  return TRUE;
+}
+
+void quit ()
+{
+  gtk_exit (0);
+}
+
+int main( int   argc, 
+          char *argv[] )
+{
+  GtkWidget *window;
+  GtkWidget *drawing_area;
+  GtkWidget *vbox;
+
+  GtkWidget *button;
+
+  gtk_init (&amp;argc, &amp;argv);
+
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_widget_set_name (window, "Test Input");
+
+  vbox = gtk_vbox_new (FALSE, 0);
+  gtk_container_add (GTK_CONTAINER (window), vbox);
+  gtk_widget_show (vbox);
+
+  gtk_signal_connect (GTK_OBJECT (window), "destroy",
+                     GTK_SIGNAL_FUNC (quit), NULL);
+
+  /* Create the drawing area */
+
+  drawing_area = gtk_drawing_area_new ();
+  gtk_drawing_area_size (GTK_DRAWING_AREA (drawing_area), 200, 200);
+  gtk_box_pack_start (GTK_BOX (vbox), drawing_area, TRUE, TRUE, 0);
+
+  gtk_widget_show (drawing_area);
+
+  /* Signals used to handle backing pixmap */
+
+  gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
+                     (GtkSignalFunc) expose_event, NULL);
+  gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event",
+                     (GtkSignalFunc) configure_event, NULL);
+
+  /* Event signals */
+
+  gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event",
+                     (GtkSignalFunc) motion_notify_event, NULL);
+  gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event",
+                     (GtkSignalFunc) button_press_event, NULL);
+
+  gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
+                        | GDK_LEAVE_NOTIFY_MASK
+                        | GDK_BUTTON_PRESS_MASK
+                        | GDK_POINTER_MOTION_MASK
+                        | GDK_POINTER_MOTION_HINT_MASK);
+
+  /* .. And a quit button */
+  button = gtk_button_new_with_label ("Quit");
+  gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
+
+  gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+                            GTK_SIGNAL_FUNC (gtk_widget_destroy),
+                            GTK_OBJECT (window));
+  gtk_widget_show (button);
+
+  gtk_widget_show (window);
+
+  gtk_main ();
+
+  return 0;
+}
+/* example-end */
+</programlisting>
+
+</sect2>
+
+<!-- ----------------------------------------------------------------- -->
+<sect2>
+<title> scribble-xinput.c</title>
+
+<programlisting role="C">
+/* example-start scribble-xinput scribble-xinput.c */
+
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include &lt;gtk/gtk.h&gt;
+
+/* Backing pixmap for drawing area */
+static GdkPixmap *pixmap = NULL;
+
+/* Create a new backing pixmap of the appropriate size */
+static gint
+configure_event (GtkWidget *widget, GdkEventConfigure *event)
+{
+  if (pixmap)
+     gdk_pixmap_unref(pixmap);
+
+  pixmap = gdk_pixmap_new(widget->window,
+                          widget->allocation.width,
+                          widget->allocation.height,
+                          -1);
+  gdk_draw_rectangle (pixmap,
+                      widget->style->white_gc,
+                      TRUE,
+                      0, 0,
+                      widget->allocation.width,
+                      widget->allocation.height);
+
+  return TRUE;
+}
+
+/* Redraw the screen from the backing pixmap */
+static gint
+expose_event (GtkWidget *widget, GdkEventExpose *event)
+{
+  gdk_draw_pixmap(widget->window,
+                  widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
+                  pixmap,
+                  event->area.x, event->area.y,
+                  event->area.x, event->area.y,
+                  event->area.width, event->area.height);
+
+  return FALSE;
+}
+
+/* Draw a rectangle on the screen, size depending on pressure,
+   and color on the type of device */
+static void
+draw_brush (GtkWidget *widget, GdkInputSource source,
+            gdouble x, gdouble y, gdouble pressure)
+{
+  GdkGC *gc;
+  GdkRectangle update_rect;
+
+  switch (source)
+    {
+    case GDK_SOURCE_MOUSE:
+      gc = widget->style->dark_gc[GTK_WIDGET_STATE (widget)];
+      break;
+    case GDK_SOURCE_PEN:
+      gc = widget->style->black_gc;
+      break;
+    case GDK_SOURCE_ERASER:
+      gc = widget->style->white_gc;
+      break;
+    default:
+      gc = widget->style->light_gc[GTK_WIDGET_STATE (widget)];
+    }
+
+  update_rect.x = x - 10 * pressure;
+  update_rect.y = y - 10 * pressure;
+  update_rect.width = 20 * pressure;
+  update_rect.height = 20 * pressure;
+  gdk_draw_rectangle (pixmap, gc, TRUE,
+                      update_rect.x, update_rect.y,
+                      update_rect.width, update_rect.height);
+  gtk_widget_draw (widget, &amp;update_rect);
+}
+
+static void
+print_button_press (guint32 deviceid)
+{
+  GList *tmp_list;
+
+  /* gdk_input_list_devices returns an internal list, so we shouldn't
+     free it afterwards */
+  tmp_list = gdk_input_list_devices();
+
+  while (tmp_list)
+    {
+      GdkDeviceInfo *info = (GdkDeviceInfo *)tmp_list->data;
+
+      if (info->deviceid == deviceid)
+        {
+          g_print("Button press on device '%s'\n", info->name);
+          return;
+        }
+
+      tmp_list = tmp_list->next;
+    }
+}
+
+static gint
+button_press_event (GtkWidget *widget, GdkEventButton *event)
+{
+  print_button_press (event->deviceid);
+  
+  if (event->button == 1 &amp;&amp; pixmap != NULL)
+    draw_brush (widget, event->source, event->x, event->y, event->pressure);
+
+  return TRUE;
+}
+
+static gint
+motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
+{
+  gdouble x, y;
+  gdouble pressure;
+  GdkModifierType state;
+
+  if (event->is_hint)
+    gdk_input_window_get_pointer (event->window, event->deviceid,
+                                  &amp;x, &amp;y, &amp;pressure,
+                                 NULL, NULL, &amp;state);
+  else
+    {
+      x = event->x;
+      y = event->y;
+      pressure = event->pressure;
+      state = event->state;
+    }
+    
+  if (state &amp; GDK_BUTTON1_MASK &amp;&amp; pixmap != NULL)
+    draw_brush (widget, event->source, x, y, pressure);
+  
+  return TRUE;
+}
+
+void
+input_dialog_destroy (GtkWidget *w, gpointer data)
+{
+  *((GtkWidget **)data) = NULL;
+}
+
+void
+create_input_dialog ()
+{
+  static GtkWidget *inputd = NULL;
+
+  if (!inputd)
+    {
+      inputd = gtk_input_dialog_new();
+
+      gtk_signal_connect (GTK_OBJECT(inputd), "destroy",
+                          (GtkSignalFunc)input_dialog_destroy, &amp;inputd);
+      gtk_signal_connect_object (GTK_OBJECT(GTK_INPUT_DIALOG(inputd)->close_button),
+                                 "clicked",
+                                 (GtkSignalFunc)gtk_widget_hide,
+                                 GTK_OBJECT(inputd));
+      gtk_widget_hide ( GTK_INPUT_DIALOG(inputd)->save_button);
+
+      gtk_widget_show (inputd);
+    }
+  else
+    {
+      if (!GTK_WIDGET_MAPPED(inputd))
+        gtk_widget_show(inputd);
+      else
+        gdk_window_raise(inputd->window);
+    }
+}
+
+void
+quit ()
+{
+  gtk_exit (0);
+}
+
+int
+main (int argc, char *argv[])
+{
+  GtkWidget *window;
+  GtkWidget *drawing_area;
+  GtkWidget *vbox;
+
+  GtkWidget *button;
+
+  gtk_init (&amp;argc, &amp;argv);
+
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_widget_set_name (window, "Test Input");
+
+  vbox = gtk_vbox_new (FALSE, 0);
+  gtk_container_add (GTK_CONTAINER (window), vbox);
+  gtk_widget_show (vbox);
+
+  gtk_signal_connect (GTK_OBJECT (window), "destroy",
+                      GTK_SIGNAL_FUNC (quit), NULL);
+
+  /* Create the drawing area */
+
+  drawing_area = gtk_drawing_area_new ();
+  gtk_drawing_area_size (GTK_DRAWING_AREA (drawing_area), 200, 200);
+  gtk_box_pack_start (GTK_BOX (vbox), drawing_area, TRUE, TRUE, 0);
+
+  gtk_widget_show (drawing_area);
+
+  /* Signals used to handle backing pixmap */
+
+  gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
+                      (GtkSignalFunc) expose_event, NULL);
+  gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event",
+                      (GtkSignalFunc) configure_event, NULL);
+
+  /* Event signals */
+
+  gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event",
+                      (GtkSignalFunc) motion_notify_event, NULL);
+  gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event",
+                      (GtkSignalFunc) button_press_event, NULL);
+
+  gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
+                         | GDK_LEAVE_NOTIFY_MASK
+                         | GDK_BUTTON_PRESS_MASK
+                         | GDK_POINTER_MOTION_MASK
+                         | GDK_POINTER_MOTION_HINT_MASK);
+
+  /* The following call enables tracking and processing of extension
+     events for the drawing area */
+  gtk_widget_set_extension_events (drawing_area, GDK_EXTENSION_EVENTS_CURSOR);
+
+  /* .. And some buttons */
+  button = gtk_button_new_with_label ("Input Dialog");
+  gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
+
+  gtk_signal_connect (GTK_OBJECT (button), "clicked",
+                      GTK_SIGNAL_FUNC (create_input_dialog), NULL);
+  gtk_widget_show (button);
+
+  button = gtk_button_new_with_label ("Quit");
+  gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
+
+  gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+                             GTK_SIGNAL_FUNC (gtk_widget_destroy),
+                             GTK_OBJECT (window));
+  gtk_widget_show (button);
+
+  gtk_widget_show (window);
+
+  gtk_main ();
+
+  return 0;
+}
+/* example-end */
+</programlisting>
+
+</sect2>
+</sect1>
+</chapter>
+
+<!-- ***************************************************************** -->
+<appendix id="app_ListWidget">
+<title>List Widget</title>
+
+<para>NOTE: The List widget has been superseded by the CList widget. It is
+detailed here just for completeness.</para>
+
+<para>The List widget is designed to act as a vertical container for
+widgets that should be of the type ListItem.</para>
+
+<para>A List widget has its own window to receive events and its own
+background color which is usually white. As it is directly derived
+from a Container it can be treated as such by using the
+GTK_CONTAINER(List) macro, see the Container widget for more on
+this. One should already be familiar with the usage of a GList and
+its related functions g_list_*() to be able to use the List widget
+to it full extent.</para>
+
+<para>There is one field inside the structure definition of the List
+widget that will be of greater interest to us, this is:</para>
+
+<para><literallayout>
+<literal>struct _GtkList
+{
+  ...
+  GList *selection;
+  guint selection_mode;
+  ...
+}; </literal>
+</literallayout></para>
+
+<para>The selection field of a List points to a linked list of all items
+that are currently selected, or NULL if the selection is empty.  So to
+learn about the current selection we read the GTK_LIST()->selection
+field, but do not modify it since the internal fields are maintained
+by the gtk_list_*() functions.</para>
+
+<para>The selection_mode of the List determines the selection facilities
+of a List and therefore the contents of the GTK_LIST()->selection
+field. The selection_mode may be one of the following:</para>
+
+<itemizedlist>
+<listitem><simpara> <literal>GTK_SELECTION_SINGLE</literal> - The selection is either NULL
+                        or contains a GList pointer
+                        for a single selected item.</simpara>
+</listitem>
+<listitem><simpara> <literal>GTK_SELECTION_BROWSE</literal> -  The selection is NULL if the list
+                        contains no widgets or insensitive
+                        ones only, otherwise it contains
+                        a GList pointer for one GList
+                        structure, and therefore exactly
+                        one list item.</simpara>
+</listitem>
+<listitem><simpara> <literal>GTK_SELECTION_MULTIPLE</literal> -  The selection is NULL if no list
+                        items are selected or a GList pointer
+                        for the first selected item. That
+                        in turn points to a GList structure
+                        for the second selected item and so
+                        on.</simpara>
+</listitem>
+<listitem><simpara> <literal>GTK_SELECTION_EXTENDED</literal> - The selection is always NULL.</simpara>
+</listitem>
+</itemizedlist>
+
+<para>The default is <literal>GTK_SELECTION_MULTIPLE</literal>.</para>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title>Signals</title>
+
+<para><literallayout>
+<literal>void selection_changed( GtkList *list );</literal>
+</literallayout></para>
+
+<para>This signal will be invoked whenever the selection field of a List
+has changed. This happens when a child of thekList got selected or
+deselected.</para>
+
+<para><literallayout>
+<literal>void select_child( GtkList   *list,
+                   GtkWidget *child);</literal>
+</literallayout></para>
+
+<para>This signal is invoked when a child of the List is about to get
+selected. This happens mainly on calls to gtk_list_select_item(),
+gtk_list_select_child(), button presses and sometimes indirectly
+triggered on some else occasions where children get added to or
+removed from the List.</para>
+
+<para><literallayout>
+<literal>void unselect_child( GtkList   *list,
+                     GtkWidget *child );</literal>
+</literallayout></para>
+
+<para>This signal is invoked when a child of the List is about to get
+deselected. This happens mainly on calls to gtk_list_unselect_item(),
+gtk_list_unselect_child(), button presses and sometimes indirectly
+triggered on some else occasions where children get added to or
+removed from the List.</para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> Functions</title>
+
+<para><literallayout>
+<literal>guint gtk_list_get_type( void );</literal>
+</literallayout></para>
+
+<para>Returns the "GtkList" type identifier.</para>
+
+<para><literallayout>
+<literal>GtkWidget *gtk_list_new( void );</literal>
+</literallayout></para>
+
+<para>Create a new List object. The new widget is returned as a pointer
+to a GtkWidget object. NULL is returned on failure.</para>
+
+<para><literallayout>
+<literal>void gtk_list_insert_items( GtkList *list,
+                            GList   *items,
+                            gint     position );</literal>
+</literallayout></para>
+
+<para>Insert list items into the list, starting at <literal>position</literal>.
+<literal>items</literal> is a doubly linked list where each nodes data pointer is
+expected to point to a newly created ListItem. The GList nodes of
+<literal>items</literal> are taken over by the list.</para>
+
+<para><literallayout>
+<literal>void gtk_list_append_items( GtkList *list,
+                            GList   *items);</literal>
+</literallayout></para>
+
+<para>Insert list items just like gtk_list_insert_items() at the end of the
+list. The GList nodes of <literal>items</literal> are taken over by the list.</para>
+
+<para><literallayout>
+<literal>void gtk_list_prepend_items( GtkList *list,
+                             GList   *items);</literal>
+</literallayout></para>
+
+<para>Insert list items just like gtk_list_insert_items() at the very
+beginning of the list. The GList nodes of <literal>items</literal> are taken over by
+the list.</para>
+
+<para><literallayout>
+<literal>void gtk_list_remove_items( GtkList *list,
+                            GList   *items);</literal>
+</literallayout></para>
+
+<para>Remove list items from the list. <literal>items</literal> is a doubly linked list
+where each nodes data pointer is expected to point to a direct child
+of list. It is the callers responsibility to make a call to
+g_list_free(items) afterwards. Also the caller has to destroy the list
+items himself.</para>
+
+<para><literallayout>
+<literal>void gtk_list_clear_items( GtkList *list,
+                           gint start,
+                           gint end );</literal>
+</literallayout></para>
+
+<para>Remove and destroy list items from the list. A widget is affected if
+its current position within the list is in the range specified by
+<literal>start</literal> and <literal>end</literal>.</para>
+
+<para><literallayout>
+<literal>void gtk_list_select_item( GtkList *list,
+                           gint     item );</literal>
+</literallayout></para>
+
+<para>Invoke the select_child signal for a list item specified through its
+current position within the list.</para>
+
+<para><literallayout>
+<literal>void gtk_list_unselect_item( GtkList *list,
+                             gint     item);</literal>
+</literallayout></para>
+
+<para>Invoke the unselect_child signal for a list item specified through its
+current position within the list.</para>
+
+<para><literallayout>
+<literal>void gtk_list_select_child( GtkList *list,
+                            GtkWidget *child);</literal>
+</literallayout></para>
+
+<para>Invoke the select_child signal for the specified child.</para>
+
+<para><literallayout>
+<literal>void gtk_list_unselect_child( GtkList   *list,
+                              GtkWidget *child);</literal>
+</literallayout></para>
+
+<para>Invoke the unselect_child signal for the specified child.</para>
+
+<para><literallayout>
+<literal>gint gtk_list_child_position( GtkList *list,
+                              GtkWidget *child);</literal>
+</literallayout></para>
+
+<para>Return the position of <literal>child</literal> within the list. "-1" is returned on
+failure.</para>
+
+<para><literallayout>
+<literal>void gtk_list_set_selection_mode( GtkList         *list,
+                                  GtkSelectionMode mode );</literal>
+</literallayout></para>
+
+<para>Set the selection mode MODE which can be of GTK_SELECTION_SINGLE,
+GTK_SELECTION_BROWSE, GTK_SELECTION_MULTIPLE or
+GTK_SELECTION_EXTENDED.</para>
+
+<para><literallayout>
+<literal>GtkList *GTK_LIST( gpointer obj );</literal>
+</literallayout></para>
+
+<para>Cast a generic pointer to "GtkList *".</para>
+
+<para><literallayout>
+<literal>GtkListClass *GTK_LIST_CLASS( gpointer class);</literal>
+</literallayout></para>
+
+<para>Cast a generic pointer to "GtkListClass *". </para>
+
+<para><literallayout>
+<literal>gint GTK_IS_LIST( gpointer obj);</literal>
+</literallayout></para>
+
+<para>Determine if a generic pointer refers to a "GtkList" object.</para>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> Example</title>
+
+<para>Following is an example program that will print out the changes of the
+selection of a List, and lets you "arrest" list items into a prison
+by selecting them with the rightmost mouse button.</para>
+
+<programlisting role="C">
+/* example-start list list.c */
+
+/* Include the GTK header files
+ * Include stdio.h, we need that for the printf() function
+ */
+#include &lt;gtk/gtk.h&gt;
+#include &lt;stdio.h&gt;
+
+/* This is our data identification string to store
+ * data in list items
+ */
+const gchar *list_item_data_key="list_item_data";
+
+
+/* prototypes for signal handler that we are going to connect
+ * to the List widget
+ */
+static void  sigh_print_selection( GtkWidget *gtklist,
+                                   gpointer   func_data);
+
+static void  sigh_button_event( GtkWidget      *gtklist,
+                                GdkEventButton *event,
+                                GtkWidget      *frame );
+
+
+/* Main function to set up the user interface */
+
+gint main( int    argc,
+           gchar *argv[] )
+{                                  
+    GtkWidget *separator;
+    GtkWidget *window;
+    GtkWidget *vbox;
+    GtkWidget *scrolled_window;
+    GtkWidget *frame;
+    GtkWidget *gtklist;
+    GtkWidget *button;
+    GtkWidget *list_item;
+    GList *dlist;
+    guint i;
+    gchar buffer[64];
+    
+    
+    /* Initialize GTK (and subsequently GDK) */
+
+    gtk_init(&amp;argc, &amp;argv);
+    
+    
+    /* Create a window to put all the widgets in
+     * connect gtk_main_quit() to the "destroy" event of
+     * the window to handle window manager close-window-events
+     */
+    window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
+    gtk_window_set_title(GTK_WINDOW(window), "GtkList Example");
+    gtk_signal_connect(GTK_OBJECT(window),
+                      "destroy",
+                      GTK_SIGNAL_FUNC(gtk_main_quit),
+                      NULL);
+    
+    
+    /* Inside the window we need a box to arrange the widgets
+     * vertically */
+    vbox=gtk_vbox_new(FALSE, 5);
+    gtk_container_set_border_width(GTK_CONTAINER(vbox), 5);
+    gtk_container_add(GTK_CONTAINER(window), vbox);
+    gtk_widget_show(vbox);
+    
+    /* This is the scrolled window to put the List widget inside */
+    scrolled_window=gtk_scrolled_window_new(NULL, NULL);
+    gtk_widget_set_usize(scrolled_window, 250, 150);
+    gtk_container_add(GTK_CONTAINER(vbox), scrolled_window);
+    gtk_widget_show(scrolled_window);
+    
+    /* Create thekList widget.
+     * Connect the sigh_print_selection() signal handler
+     * function to the "selection_changed" signal of the List
+     * to print out the selected items each time the selection
+     * has changed */
+    gtklist=gtk_list_new();
+    gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW(scrolled_window),
+                                           gtklist);
+    gtk_widget_show(gtklist);
+    gtk_signal_connect(GTK_OBJECT(gtklist),
+                      "selection_changed",
+                      GTK_SIGNAL_FUNC(sigh_print_selection),
+                      NULL);
+    
+    /* We create a "Prison" to put a list item in ;) */
+    frame=gtk_frame_new("Prison");
+    gtk_widget_set_usize(frame, 200, 50);
+    gtk_container_set_border_width(GTK_CONTAINER(frame), 5);
+    gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT);
+    gtk_container_add(GTK_CONTAINER(vbox), frame);
+    gtk_widget_show(frame);
+    
+    /* Connect the sigh_button_event() signal handler to the List
+     * which will handle the "arresting" of list items
+     */
+    gtk_signal_connect(GTK_OBJECT(gtklist),
+                      "button_release_event",
+                      GTK_SIGNAL_FUNC(sigh_button_event),
+                      frame);
+    
+    /* Create a separator */
+    separator=gtk_hseparator_new();
+    gtk_container_add(GTK_CONTAINER(vbox), separator);
+    gtk_widget_show(separator);
+    
+    /* Finally create a button and connect its "clicked" signal
+     * to the destruction of the window */
+    button=gtk_button_new_with_label("Close");
+    gtk_container_add(GTK_CONTAINER(vbox), button);
+    gtk_widget_show(button);
+    gtk_signal_connect_object(GTK_OBJECT(button),
+                             "clicked",
+                             GTK_SIGNAL_FUNC(gtk_widget_destroy),
+                             GTK_OBJECT(window));
+    
+    
+    /* Now we create 5 list items, each having its own
+     * label and add them to the List using gtk_container_add()
+     * Also we query the text string from the label and
+     * associate it with the list_item_data_key for each list item
+     */
+    for (i=0; i<5; i++) {
+       GtkWidget       *label;
+       gchar           *string;
+       
+       sprintf(buffer, "ListItemContainer with Label #%d", i);
+       label=gtk_label_new(buffer);
+       list_item=gtk_list_item_new();
+       gtk_container_add(GTK_CONTAINER(list_item), label);
+       gtk_widget_show(label);
+       gtk_container_add(GTK_CONTAINER(gtklist), list_item);
+       gtk_widget_show(list_item);
+       gtk_label_get(GTK_LABEL(label), &amp;string);
+       gtk_object_set_data(GTK_OBJECT(list_item),
+                           list_item_data_key,
+                           string);
+    }
+    /* Here, we are creating another 5 labels, this time
+     * we use gtk_list_item_new_with_label() for the creation
+     * we can't query the text string from the label because
+     * we don't have the labels pointer and therefore
+     * we just associate the list_item_data_key of each
+     * list item with the same text string.
+     * For adding of the list items we put them all into a doubly
+     * linked list (GList), and then add them by a single call to
+     * gtk_list_append_items().
+     * Because we use g_list_prepend() to put the items into the
+     * doubly linked list, their order will be descending (instead
+     * of ascending when using g_list_append())
+     */
+    dlist=NULL;
+    for (; i<10; i++) {
+       sprintf(buffer, "List Item with Label %d", i);
+       list_item=gtk_list_item_new_with_label(buffer);
+       dlist=g_list_prepend(dlist, list_item);
+       gtk_widget_show(list_item);
+       gtk_object_set_data(GTK_OBJECT(list_item),
+                           list_item_data_key,
+                           "ListItem with integrated Label");
+    }
+    gtk_list_append_items(GTK_LIST(gtklist), dlist);
+    
+    /* Finally we want to see the window, don't we? ;) */
+    gtk_widget_show(window);
+    
+    /* Fire up the main event loop of gtk */
+    gtk_main();
+    
+    /* We get here after gtk_main_quit() has been called which
+     * happens if the main window gets destroyed
+     */
+    return(0);
+}
+
+/* This is the signal handler that got connected to button
+ * press/release events of the List
+ */
+void sigh_button_event( GtkWidget      *gtklist,
+                        GdkEventButton *event,
+                        GtkWidget      *frame )
+{
+    /* We only do something if the third (rightmost mouse button
+     * was released
+     */
+    if (event->type==GDK_BUTTON_RELEASE &amp;&amp;
+       event->button==3) {
+       GList           *dlist, *free_list;
+       GtkWidget       *new_prisoner;
+       
+       /* Fetch the currently selected list item which
+        * will be our next prisoner ;)
+        */
+       dlist=GTK_LIST(gtklist)->selection;
+       if (dlist)
+               new_prisoner=GTK_WIDGET(dlist->data);
+       else
+               new_prisoner=NULL;
+       
+       /* Look for already imprisoned list items, we
+        * will put them back into the list.
+        * Remember to free the doubly linked list that
+        * gtk_container_children() returns
+        */
+       dlist=gtk_container_children(GTK_CONTAINER(frame));
+       free_list=dlist;
+       while (dlist) {
+           GtkWidget       *list_item;
+           
+           list_item=dlist->data;
+           
+           gtk_widget_reparent(list_item, gtklist);
+           
+           dlist=dlist->next;
+       }
+       g_list_free(free_list);
+       
+       /* If we have a new prisoner, remove him from the
+        * List and put him into the frame "Prison".
+        * We need to unselect the item first.
+        */
+       if (new_prisoner) {
+           GList   static_dlist;
+           
+           static_dlist.data=new_prisoner;
+           static_dlist.next=NULL;
+           static_dlist.prev=NULL;
+           
+           gtk_list_unselect_child(GTK_LIST(gtklist),
+                                   new_prisoner);
+           gtk_widget_reparent(new_prisoner, frame);
+       }
+    }
+}
+
+/* This is the signal handler that gets called if List
+ * emits the "selection_changed" signal
+ */
+void sigh_print_selection( GtkWidget *gtklist,
+                           gpointer   func_data )
+{
+    GList   *dlist;
+    
+    /* Fetch the doubly linked list of selected items
+     * of the List, remember to treat this as read-only!
+     */
+    dlist=GTK_LIST(gtklist)->selection;
+    
+    /* If there are no selected items there is nothing more
+     * to do than just telling the user so
+     */
+    if (!dlist) {
+       g_print("Selection cleared\n");
+       return;
+    }
+    /* Ok, we got a selection and so we print it
+     */
+    g_print("The selection is a ");
+    
+    /* Get the list item from the doubly linked list
+     * and then query the data associated with list_item_data_key.
+     * We then just print it */
+    while (dlist) {
+       GtkObject       *list_item;
+       gchar           *item_data_string;
+       
+       list_item=GTK_OBJECT(dlist->data);
+       item_data_string=gtk_object_get_data(list_item,
+                                            list_item_data_key);
+       g_print("%s ", item_data_string);
+       
+       dlist=dlist->next;
+    }
+    g_print("\n");
+}
+/* example-end */
+</programlisting>
+
+</sect1>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> List Item Widget</title>
+
+<para>The ListItem widget is designed to act as a container holding up to
+one child, providing functions for selection/deselection just like the
+List widget requires them for its children.</para>
+
+<para>A ListItem has its own window to receive events and has its own
+background color which is usually white.</para>
+
+<para>As it is directly derived from an Item it can be treated as such by
+using the GTK_ITEM(ListItem) macro, see the Item widget for more on
+this. Usually a ListItem just holds a label to identify, e.g., a
+filename within a List -- therefore the convenience function
+gtk_list_item_new_with_label() is provided. The same effect can be
+achieved by creating a Label on its own, setting its alignment to
+xalign=0 and yalign=0.5 with a subsequent container addition to the
+ListItem.</para>
+
+<para>As one is not forced to add a GtkLabel to a GtkListItem, you could
+also add a GtkVBox or a GtkArrow etc. to the GtkListItem.</para>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> Signals</title>
+
+<para>AkListItem does not create new signals on its own, but inherits
+the signals of a Item.</para>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> Functions</title>
+
+<para><literallayout>
+<literal>guint gtk_list_item_get_type( void );</literal>
+</literallayout></para>
+
+<para>Returns the "GtkListItem" type identifier.</para>
+
+<para><literallayout>
+<literal>GtkWidget *gtk_list_item_new( void );</literal>
+</literallayout></para>
+
+<para>Create a new ListItem object. The new widget is returned as a
+pointer to a GtkWidget object. NULL is returned on failure.</para>
+
+<para><literallayout>
+<literal>GtkWidget *gtk_list_item_new_with_label( gchar *label );</literal>
+</literallayout></para>
+
+<para>Create a new ListItem object, having a single GtkLabel as the sole
+child. The new widget is returned as a pointer to a GtkWidget
+object. NULL is returned on failure.</para>
+
+<para><literallayout>
+<literal>void gtk_list_item_select( GtkListItem *list_item );</literal>
+</literallayout></para>
+
+<para>This function is basically a wrapper around a call to gtk_item_select
+(GTK_ITEM (list_item)) which will emit the select signal.  *Note
+GtkItem::, for more info.</para>
+
+<para><literallayout>
+<literal>void gtk_list_item_deselect( GtkListItem *list_item );</literal>
+</literallayout></para>
+
+<para>This function is basically a wrapper around a call to
+gtk_item_deselect (GTK_ITEM (list_item)) which will emit the deselect
+signal.  *Note GtkItem::, for more info.</para>
+
+<para><literallayout>
+<literal>GtkListItem *GTK_LIST_ITEM( gpointer obj );</literal>
+</literallayout></para>
+
+<para>Cast a generic pointer to "GtkListItem *".</para>
+
+<para><literallayout>
+<literal>GtkListItemClass *GTK_LIST_ITEM_CLASS( gpointer class );</literal>
+</literallayout></para>
+
+<para>Cast a generic pointer to GtkListItemClass*. *Note Standard Macros::,
+for more info.</para>
+
+<para><literallayout>
+<literal>gint GTK_IS_LIST_ITEM( gpointer obj );</literal>
+</literallayout></para>
+
+<para>Determine if a generic pointer refers to a `GtkListItem' object.
+*Note Standard Macros::, for more info.
+<!-- ----------------------------------------------------------------- -->
+<sect1>
+<title> Example</title>
+
+<para>Please see the List example on this, which covers the usage of a
+ListItem as well.</para>
+
+      </sect1>
+    </chapter>
\ No newline at end of file