<!doctype book PUBLIC "-//OASIS//DTD DocBook V3.1//EN" [
<!notation PNG system "PNG">
<!entity % local.notation.class "| PNG">
]>
<book id="gtk-tut">

<bookinfo>
    <date>January 24th, 2003</date>
    <title>GTK+ 2.0 Tutorial</title>
    <authorgroup>
      <author>
        <firstname>Tony</firstname>
        <surname>Gale</surname>
      </author>
      <author>
        <firstname>Ian</firstname>
        <surname>Main</surname>
      </author>
      <author>
	<firstname>&amp; the GTK team</firstname>
      </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-TutorialDownload">
<title>Tutorial Availability</title>

<para>A copy of this tutorial in SGML and HTML is distributed with each
source code release of GTK+. For binary distributions, please check with
your vendor.</para>

<para>A copy is available online for reference at <ulink 
url="http://www.gtk.org/tutorial/">http://www.gtk.org/tutorial</ulink>.</para>

<para>A packaged verion of this tutorial is available from
<ulink url="ftp://ftp.gtk.org/pub/gtk/tutorial/">
ftp://ftp.gtk.org/pub/gtk/tutorial</ulink> which contains the tutorial in
various different formats. This
package is primary for those people wanting to have the tutorial
available for offline reference and for printing.</para>

</chapter>

<!-- ***************************************************************** -->
<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), and gdk-pixbuf, a library for
client-side image manipulation.
</para>
<para>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 currently maintained by:</para>

<itemizedlist>
<listitem><simpara> Owen Taylor <ulink url="mailto:otaylor@redhat.com">
otaylor@redhat.com</ulink></simpara>
</listitem>
<listitem><simpara> Tim Janik <ulink url="mailto:timj@gtk.org">
timj@gtk.org</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>In version 2.0, GLib has picked up the type system which forms the
foundation for GTK's class hierarchy, the signal system which is used
throughout GTK, a thread API which abstracts the different native thread APIs 
of the various platforms and a facility for loading modules.
</para>

<para>As the last component, GTK uses the Pango library for internationalized
text output.
</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, Eiffel, Java and C#. 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 <ulink 
url="ftp://ftp.gtk.org/pub/gtk">ftp.gtk.org</ulink>. 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 
<literal>./configure --help</literal> 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>

<para>
<inlinemediaobject>
<imageobject>
<imagedata fileref="images/base.png" format="png">
</imageobject>
</inlinemediaobject>
</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 `pkg-config --cflags --libs gtk+-2.0`</literal>
</literallayout></para>

<para>The meaning of the unusual compilation options is explained below in
<link linkend="sec-Compiling">Compiling Hello World</link>.</para>

<para>All programs will of course include <filename>gtk/gtk.h</filename> which 
declares the variables, functions, structures, etc. that will be used in your GTK
application.</para>

<para>The next line:</para>

<programlisting role="C">
gtk_init (&amp;argc, &amp;argv);
</programlisting>

<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>--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>

<programlisting role="C">
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  gtk_widget_show (window);
</programlisting>

<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>

<programlisting role="C">
  gtk_main ();
</programlisting>

<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 id="sec-HelloWorld">
<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>

<para>
<inlinemediaobject>
<imageobject>
<imagedata fileref="images/helloworld.png" format="png">
</imageobject>
</inlinemediaobject>
</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. */
static void hello( GtkWidget *widget,
                   gpointer   data )
{
    g_print ("Hello World\n");
}

static gboolean 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 */
static 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. */
    g_signal_connect (G_OBJECT (window), "delete_event",
		      G_CALLBACK (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. */
    g_signal_connect (G_OBJECT (window), "destroy",
		      G_CALLBACK (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. */
    g_signal_connect (G_OBJECT (button), "clicked",
		      G_CALLBACK (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. */
    g_signal_connect_swapped (G_OBJECT (button), "clicked",
			      G_CALLBACK (gtk_widget_destroy),
                              G_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 id="sec-Compiling">
<title>Compiling Hello World</title>

<para>To compile use:</para>

<para><literallayout>
<literal>gcc -Wall -g helloworld.c -o helloworld `pkg-config --cflags gtk+-2.0` \</literal>
<literal>    `pkg-config --libs gtk+-2.0`</literal>
</literallayout></para>

<para>This uses the program <literal>pkg-config</literal>, which can be obtained from
<ulink url="http://www.freedesktop.org">www.freedesktop.org</ulink>. This program 
reads the <filename>.pc</filename> which comes with GTK to determine what 
compiler switches are needed to compile programs that use GTK. 
<literal>pkg-config --cflags gtk+-2.0</literal> will output a list of include
directories for the compiler to look in, and 
<literal>pkg-config --libs gtk+-2.0</literal>
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>pkg-config --cflags --libs gtk+-2.0</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 (<literal>-lgtk</literal>), the widget library, 
based on top of GDK.</simpara>
</listitem>

<listitem><simpara>The GDK library (<literal>-lgdk</literal>), the Xlib wrapper.</simpara>
</listitem>

<listitem><simpara>The gdk-pixbuf library (<literal>-lgdk_pixbuf</literal>), the image 
manipulation library.</simpara>
</listitem>

<listitem><simpara>The Pango library (<literal>-lpango</literal>) for internationalized 
text.</simpara>
</listitem>

<listitem><simpara>The gobject library (<literal>-lgobject</literal>), containing the
type system on which GTK is based.</simpara>
</listitem>

<listitem><simpara>The gmodule library (<literal>-lgmodule</literal>), which is used 
to load run time extensions.</simpara>
</listitem>

<listitem><simpara>The GLib library (<literal>-lglib</literal>), 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 (<literal>-lX11</literal>) which is used by GDK.</simpara>
</listitem>

<listitem><simpara>The Xext library (<literal>-lXext</literal>). This contains code 
for shared memory pixmaps and other X extensions.</simpara>
</listitem>

<listitem><simpara>The math library (<literal>-lm</literal>). This is used by GTK 
for various purposes.</simpara>
</listitem>
</itemizedlist>

</sect1>

<!-- ----------------------------------------------------------------- -->
<sect1 id="sec-TheoryOfSignalsAndCallbacks">
<title>Theory of Signals and Callbacks</title>

<note>
<para>In version 2.0, the signal system has been moved from GTK to GLib, therefore the
functions and types explained in this section have a "g_" prefix rather than a "gtk_" 
prefix. We won't go into details about the extensions which the GLib 2.0 signal system
has relative to the GTK 1.2 signal system.</para>
</note>

<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>

<programlisting role="C">
gulong g_signal_connect( gpointer      *object,
                         const gchar   *name,
                         GCallback     func,
                         gpointer      func_data );
</programlisting>

<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>

<programlisting role="C">
void callback_func( GtkWidget *widget,
                    gpointer   callback_data );
</programlisting>

<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 g_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.</para>

<para>Another call used in the <emphasis>helloworld</emphasis> example, is:</para>

<programlisting role="C">
gulong g_signal_connect_swapped( gpointer     *object,
                                 const gchar  *name,
                                 GCallback    func,
                                 gpointer     *slot_object );
</programlisting>

<para>g_signal_connect_swapped() is the same as g_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>

<programlisting role="C">
void callback_func( GtkObject *object );
</programlisting>

<para>where the object is usually a widget. We usually don't setup callbacks
for g_signal_connect_swapped() 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 g_signal_connect_swapped() for
these, whereas for your functions, you may need to have additional
data supplied to the callbacks.</para>

</sect1>

<!-- ----------------------------------------------------------------- -->
<sect1 id="sec-Events">
<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> scroll_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> visibility_notify_event</simpara>
</listitem>
<listitem><simpara> client_event</simpara>
</listitem>
<listitem><simpara> no_expose_event</simpara>
</listitem>
<listitem><simpara> window_state_event</simpara>
</listitem>
</itemizedlist>

<para>In order to connect a callback function to one of these events you
use the function g_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>

<programlisting role="C">
gint callback_func( GtkWidget *widget,
                    GdkEvent  *event,
                    gpointer   callback_data );
</programlisting>

<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>
member that 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_ENTER
  GDK_DRAG_LEAVE
  GDK_DRAG_MOTION
  GDK_DRAG_STATUS
  GDK_DROP_START
  GDK_DROP_FINISHED
  GDK_CLIENT_EVENT
  GDK_VISIBILITY_NOTIFY
  GDK_NO_EXPOSE
  GDK_SCROLL
  GDK_WINDOW_STATE
  GDK_SETTING
</programlisting>

<para>So, to connect a callback function to one of these events we would use
something like:</para>

<programlisting role="C">
g_signal_connect (G_OBJECT (button), "button_press_event",
                  G_CALLBACK (button_press_callback), NULL);
</programlisting>

<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
button_press_callback() will be called. This function may be declared as:</para>

<programlisting role="C">
static gboolean button_press_callback( GtkWidget      *widget, 
                                       GdkEventButton *event,
                                       gpointer        data );
</programlisting>

<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-AdvancedEventsAndSignals">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="app-GDKEventTypes">GDK Event Types</link>.</para>

<para>The GDK selection and drag-and-drop APIs also emit a number of events which
are reflected in GTK by the signals. See <link 
linkend="sec-SignalsOnSourceWidgets">Signals on the source widget</link> and <link 
linkend="sec-SignalsOnDestWidgets">Signals on the destination widget</link>
for details on the signatures of the callback functions for these signals:</para>

<itemizedlist spacing=Compact>
<listitem><simpara> selection_received</simpara>
</listitem>
<listitem><simpara> selection_get</simpara>
</listitem>
<listitem><simpara> drag_begin_event</simpara>
</listitem>
<listitem><simpara> drag_end_event</simpara>
</listitem>
<listitem><simpara> drag_data_delete</simpara>
</listitem>
<listitem><simpara> drag_motion</simpara>
</listitem>
<listitem><simpara> drag_drop</simpara>
</listitem>
<listitem><simpara> drag_data_get</simpara>
</listitem>
<listitem><simpara> drag_data_received</simpara>
</listitem>
</itemizedlist>

</sect1>

<!-- ----------------------------------------------------------------- -->
<sect1 id="sec-SteppingThroughHelloWorld">
<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">
static 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">
static gboolean 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">
static 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>G_OBJECT</literal> and <literal>G_CALLBACK</literal> are macros 
that perform type casting and checking for us, as well as aid the readability of
the code.</para>

<programlisting role="C">
    g_signal_connect (G_OBJECT (window), "delete_event",
                      G_CALLBACK (delete_event), NULL);
    g_signal_connect (G_OBJECT (window), "destroy",
                      G_CALLBACK (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">
    g_signal_connect (G_OBJECT (button), "clicked",
                      G_CALLBACK (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 g_signal_connect_swapped() 
function here instead of straight g_signal_connect().</para>

<programlisting role="C">
    g_signal_connect_swapped (G_OBJECT (button), "clicked",
                              G_CALLBACK (gtk_widget_destroy),
                              G_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 id="sec-DataTypes">
<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 GLib 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 <filename>glib/glib.h</filename> (which gets included from 
<filename>gtk.h</filename>).</para>

<para>You'll also notice GTK's ability to use GtkWidget when the function
calls for a GtkObject. GTK is an object oriented design, and a widget
is an object.</para>

</sect1>

<!-- ----------------------------------------------------------------- -->
<sect1 id="sec-MoreOnSignalHandlers">
<title>More on Signal Handlers</title>

<para>Lets take another look at the g_signal_connect() declaration.</para>

<programlisting role="C">
gulong g_signal_connect( gpointer object,
                         const gchar *name,
                         GCallback func,
                         gpointer func_data );
</programlisting>

<para>Notice the gulong 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 g_signal_handler_disconnect( gpointer object,
                                  gulong   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
g_signal_handler_block() and g_signal_handler_unblock() family of
functions.</para>

<programlisting role="C">
void g_signal_handler_block( gpointer object,
                             gulong   id );

void g_signal_handlers_block_by_func( gpointer  object,
                                      GCallback func,
                                      gpointer  data );

void g_signal_handler_unblock( gpointer object,
                               gulong   id );

void g_signal_handlers_unblock_by_func( gpointer  object,
                                        GCallback func,
                                        gpointer  data );
</programlisting>

</sect1>

<!-- ----------------------------------------------------------------- -->
<sect1 id="sec-AnUpgradedHelloWorld">
<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>

<para>
<inlinemediaobject>
<imageobject>
<imagedata fileref="images/helloworld2.png" format="png">
</imageobject>
</inlinemediaobject>
</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. */
static void callback( GtkWidget *widget,
                      gpointer   data )
{
    g_print ("Hello again - %s was pressed\n", (gchar *) data);
}

/* another callback */
static gboolean 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. */
    g_signal_connect (G_OBJECT (window), "delete_event",
		      G_CALLBACK (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 */
    g_signal_connect (G_OBJECT (button), "clicked",
		      G_CALLBACK (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. */
    g_signal_connect (G_OBJECT (button), "clicked",
		      G_CALLBACK (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>

</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 id="sec-TheoryOfPackingBoxes">
<title>Theory of Packing Boxes</title>

<para>Most packing is done by creating boxes. 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 id="sec-DetailsOfBoxes">
<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>
<inlinemediaobject>
<imageobject>
<imagedata fileref="images/packbox1.png" format="png">
</imageobject>
</inlinemediaobject>
</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>

<programlisting role="C">
void gtk_box_pack_start( GtkBox    *box,
                         GtkWidget *child,
                         gboolean   expand,
                         gboolean   fill,
                         guint      padding );
</programlisting>

<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>

<programlisting role="C">
GtkWidget *gtk_hbox_new ( gboolean homogeneous,
                          gint     spacing );
</programlisting>

<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>
<inlinemediaobject>
<imageobject>
<imagedata fileref="images/packbox2.png" format="png">
</imageobject>
</inlinemediaobject>
</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 id="sec-PackingDemonstrationProgram">
<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"

static gboolean 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. */
static GtkWidget *make_box( gboolean homogeneous,
                            gint     spacing,
                            gboolean expand,
                            gboolean fill,
                            guint    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. */
	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 */
    g_signal_connect (G_OBJECT (window), "delete_event",
		      G_CALLBACK (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_size_request (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 */
    g_signal_connect_swapped (G_OBJECT (button), "clicked",
			      G_CALLBACK (gtk_main_quit),
			      G_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 
     * exit() is used. */
    
    return 0;
}
<!-- example-end -->
</programlisting>

</sect1>

<!-- ----------------------------------------------------------------- -->
<sect1 id="sec-PackingUsingTables">
<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>

<programlisting role="C">
GtkWidget *gtk_table_new( guint    rows,
                          guint    columns,
                          gboolean homogeneous );
</programlisting>

<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,
                       guint            left_attach,
                       guint            right_attach,
                       guint            top_attach,
                       guint            bottom_attach,
                       GtkAttachOptions xoptions,
                       GtkAttachOptions yoptions,
                       guint            xpadding,
                       guint            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 <emphasis>only</emphasis>,
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>

<variablelist>
<varlistentry>
<term><literal>GTK_FILL</literal></term>
<listitem><para>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.</para>
</listitem>
</varlistentry>

<varlistentry>
<term><literal>GTK_SHRINK</literal></term>
<listitem><para>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.</para>
</listitem>
</varlistentry>

<varlistentry>
<term><literal>GTK_EXPAND</literal></term>
<listitem><para>This will cause the table to expand to use up
any remaining space in the window.</para>
</listitem>
</varlistentry>
</variablelist>

<para>Padding is just like in boxes, creating a clear area around the widget
specified in pixels.</para>

<para>gtk_table_attach() has a <emphasis>lot</emphasis> of options.  
So, there's a shortcut:</para>

<programlisting role="C">
void gtk_table_attach_defaults( GtkTable  *table,
                                GtkWidget *widget,
                                guint      left_attach,
                                guint      right_attach,
                                guint      top_attach,
                                guint      bottom_attach );
</programlisting>

<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>

<programlisting role="C">
void gtk_table_set_row_spacing( GtkTable *table,
                                guint     row,
                                guint     spacing );
</programlisting>

<para>and</para>

<programlisting role="C">
void gtk_table_set_col_spacing ( GtkTable *table,
                                 guint     column,
                                 guint     spacing );
</programlisting>

<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>

<programlisting role="C">
void gtk_table_set_row_spacings( GtkTable *table,
                                 guint    spacing );
</programlisting>

<para>And,</para>

<programlisting role="C">
void gtk_table_set_col_spacings( GtkTable *table,
                                 guint     spacing );
</programlisting>

<para>Note that with these calls, the last row and last column do not get
any spacing.</para>

</sect1>

<!-- ----------------------------------------------------------------- -->
<sect1 id="sec-TablePackingExamples">
<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>
<inlinemediaobject>
<imageobject>
<imagedata fileref="images/table.png" format="png">
</imageobject>
</inlinemediaobject>
</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 */
static void callback( GtkWidget *widget,
                      gpointer   data )
{
    g_print ("Hello again - %s was pressed\n", (char *) data);
}

/* This callback quits the program */
static gboolean 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. */
    g_signal_connect (G_OBJECT (window), "delete_event",
                      G_CALLBACK (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 */
    g_signal_connect (G_OBJECT (button), "clicked",
	              G_CALLBACK (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 */
    g_signal_connect (G_OBJECT (button), "clicked",
                      G_CALLBACK (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 */
    g_signal_connect (G_OBJECT (button), "clicked",
                      G_CALLBACK (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 id="sec-Casting">
<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">
  G_OBJECT (object)
  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 GObject base class. This means you can use a widget
in any place the function asks for an object - simply use the
<literal>G_OBJECT()</literal> macro.</para>

<para>For example:</para>

<programlisting role="C">
g_signal_connect( G_OBJECT (button), "clicked",
                  G_CALLBACK (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 or the GTK API reference manual. 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 id="sec-WidgetHierarchy">
<title>Widget Hierarchy</title>

<para>For your reference, here is the class hierarchy tree used to implement 
widgets. (Deprecated widgets and auxiliary classes have been omitted.)</para>

<programlisting role="C">
GObject
 |  
 GtkObject
  +GtkWidget
  | +GtkMisc
  | | +GtkLabel
  | | | `GtkAccelLabel
  | | +GtkArrow
  | | `GtkImage
  | +GtkContainer
  | | +GtkBin
  | | | +GtkAlignment
  | | | +GtkFrame
  | | | | `GtkAspectFrame
  | | | +GtkButton
  | | | | +GtkToggleButton
  | | | | | `GtkCheckButton
  | | | | |   `GtkRadioButton
  | | | | `GtkOptionMenu
  | | | +GtkItem
  | | | | +GtkMenuItem
  | | | |   +GtkCheckMenuItem
  | | | |   | `GtkRadioMenuItem
  | | | |   +GtkImageMenuItem
  | | | |   +GtkSeparatorMenuItem
  | | | |   `GtkTearoffMenuItem
  | | | +GtkWindow
  | | | | +GtkDialog
  | | | | | +GtkColorSelectionDialog
  | | | | | +GtkFileSelection
  | | | | | +GtkFontSelectionDialog
  | | | | | +GtkInputDialog
  | | | | | `GtkMessageDialog
  | | | | `GtkPlug
  | | | +GtkEventBox
  | | | +GtkHandleBox
  | | | +GtkScrolledWindow
  | | | `GtkViewport
  | | +GtkBox
  | | | +GtkButtonBox
  | | | | +GtkHButtonBox
  | | | | `GtkVButtonBox
  | | | +GtkVBox
  | | | | +GtkColorSelection
  | | | | +GtkFontSelection
  | | | | `GtkGammaCurve
  | | | `GtkHBox
  | | |   +GtkCombo
  | | |   `GtkStatusbar
  | | +GtkFixed
  | | +GtkPaned
  | | | +GtkHPaned
  | | | `GtkVPaned
  | | +GtkLayout
  | | +GtkMenuShell
  | | | +GtkMenuBar
  | | | `GtkMenu
  | | +GtkNotebook
  | | +GtkSocket
  | | +GtkTable
  | | +GtkTextView
  | | +GtkToolbar
  | | `GtkTreeView
  | +GtkCalendar
  | +GtkDrawingArea
  | | `GtkCurve
  | +GtkEditable
  | | +GtkEntry
  | |   `GtkSpinButton
  | +GtkRuler
  | | +GtkHRuler
  | | `GtkVRuler
  | +GtkRange
  | | +GtkScale
  | | | +GtkHScale
  | | | `GtkVScale
  | | `GtkScrollbar
  | |   +GtkHScrollbar
  | |   `GtkVScrollbar
  | +GtkSeparator
  | | +GtkHSeparator
  | | `GtkVSeparator
  | +GtkInvisible
  | +GtkPreview
  | `GtkProgressBar
  +GtkAdjustment
  +GtkCellRenderer
  | +GtkCellRendererPixbuf
  | +GtkCellRendererText
  | +GtkCellRendererToggle
  +GtkItemFactory
  +GtkTooltips
  `GtkTreeViewColumn
</programlisting>

</sect1>

<!-- ----------------------------------------------------------------- -->
<sect1 id="sec-WidgetsWithoutWindows">
<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="sec-EventBox">EventBox</link> widget.</para>

<programlisting role="C">
GtkAlignment
GtkArrow
GtkBin
GtkBox
GtkButton
GtkCheckButton
GtkFixed
GtkImage
GtkLabel
GtkMenuItem
GtkNotebook
GtkPaned
GtkRadioButton
GtkRange
GtkScrolledWindow
GtkSeparator
GtkTable
GtkToolbar
GtkAspectFrame
GtkFrame
GtkVBox
GtkHBox
GtkVSeparator
GtkHSeparator
</programlisting>

<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 <literal>testgtk</literal> program that comes with GTK. It can be found in
<filename>tests/testgtk.c</filename>.</para>

</sect1>
</chapter>

<!-- ***************************************************************** -->
<chapter id="ch-ButtonWidget">
<title>The Button Widget</title>

<!-- ----------------------------------------------------------------- -->
<sect1 id="sec-NormalButtons">
<title>Normal Buttons</title>

<para>We've almost seen all there is to see of the button widget. It's
pretty simple. There is however more than one way to create a button. You can
use the gtk_button_new_with_label() or gtk_button_new_with_mnemonic() to create 
a button with a label, use gtk_button_new_from_stock() to create a button
containing the image and text from a stock item 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
image 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 images 
later in the tutorial.</para>

<para>
<inlinemediaobject>
<imageobject>
<imagedata fileref="images/buttons.png" format="png">
</imageobject>
</inlinemediaobject>
</para>

<programlisting role="C">
<!-- example-start buttons buttons.c -->

#include &lt;stdlib.h&gt;
#include &lt;gtk/gtk.h&gt;

/* Create a new hbox with an image and a label packed into it
 * and return the box. */

static GtkWidget *xpm_label_box( gchar     *xpm_filename,
                                 gchar     *label_text )
{
    GtkWidget *box;
    GtkWidget *label;
    GtkWidget *image;

    /* Create box for image and label */
    box = gtk_hbox_new (FALSE, 0);
    gtk_container_set_border_width (GTK_CONTAINER (box), 2);

    /* Now on to the image stuff */
    image = gtk_image_new_from_file (xpm_filename);

    /* Create a label for the button */
    label = gtk_label_new (label_text);

    /* Pack the image and label into the box */
    gtk_box_pack_start (GTK_BOX (box), image, FALSE, FALSE, 3);
    gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 3);

    gtk_widget_show (image);
    gtk_widget_show (label);

    return box;
}

/* Our usual callback function */
static 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 *box;

    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. */
    g_signal_connect (G_OBJECT (window), "destroy",
	              G_CALLBACK (gtk_main_quit), NULL);

    g_signal_connect (G_OBJECT (window), "delete_event",
	 	      G_CALLBACK (gtk_main_quit), NULL);

    /* Sets the border width of the window. */
    gtk_container_set_border_width (GTK_CONTAINER (window), 10);

    /* Create a new button */
    button = gtk_button_new ();

    /* Connect the "clicked" signal of the button to our callback */
    g_signal_connect (G_OBJECT (button), "clicked",
		      G_CALLBACK (callback), (gpointer) "cool button");

    /* This calls our box creating function */
    box = xpm_label_box ("info.xpm", "cool button");

    /* Pack and show all our widgets */
    gtk_widget_show (box);

    gtk_container_add (GTK_CONTAINER (button), box);

    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 images and labels into
any widget that can be a container.</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 id="sec-ToggleButtons">
<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( const gchar *label );

GtkWidget *gtk_toggle_button_new_with_mnemonic( const 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 last two, a
button with a label widget already packed into it. The _mnemonic() variant
additionally parses the label for '_'-prefixed mnemonic characters.</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 button, 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>

<programlisting role="C">
void toggle_button_callback (GtkWidget *widget, gpointer data)
{
    if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) 
    {
        /* If control reaches here, the toggle button is down */
    
    } else {
    
        /* If control reaches here, the toggle button is up */
    }
}
</programlisting>

<para>To force the state of a toggle button, and its children, the radio and
check buttons, use this function:</para>

<programlisting role="C">
void gtk_toggle_button_set_active( GtkToggleButton *toggle_button,
                                   gboolean        is_active );
</programlisting>

<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" and "toggled"
signals to be emitted from the button.</para>

<programlisting role="C">
gboolean gtk_toggle_button_get_active	(GtkToggleButton *toggle_button);
</programlisting>

<para>This returns the current state of the toggle button as a boolean
TRUE/FALSE value.</para>

</sect1>

<!-- ----------------------------------------------------------------- -->
<sect1 id="sec-CheckButtons">
<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 creation functions are similar to those of the normal button.</para>

<programlisting role="C">
GtkWidget *gtk_check_button_new( void );

GtkWidget *gtk_check_button_new_with_label ( const gchar *label );

GtkWidget *gtk_check_button_new_with_mnemonic ( const gchar *label );
</programlisting>

<para>The gtk_check_button_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 id="sec-RadioButtons">
<title>Radio Buttons</title>

<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>

<programlisting role="C">
GtkWidget *gtk_radio_button_new( GSList *group );

GtkWidget *gtk_radio_button_new_from_widget( GtkRadioButton *group );

GtkWidget *gtk_radio_button_new_with_label( GSList *group,
                                            const gchar  *label );

GtkWidget* gtk_radio_button_new_with_label_from_widget( GtkRadioButton *group,
                                                        const gchar    *label );

GtkWidget *gtk_radio_button_new_with_mnemonic( GSList *group,
                                               const gchar  *label );

GtkWidget *gtk_radio_button_new_with_mnemonic_from_widget( GtkRadioButton *group,
                                                           const gchar  *label );

</programlisting>

<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() or 
gtk_radio_button_new_with_label() should pass NULL as the first argument. 
Then create a group using:</para>

<programlisting role="C">
GSList *gtk_radio_button_get_group( GtkRadioButton *radio_button );
</programlisting>

<para>The important thing to remember is that gtk_radio_button_get_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:</para>

<programlisting role="C">
     button2 = gtk_radio_button_new_with_label(
                 gtk_radio_button_get_group (GTK_RADIO_BUTTON (button1)),
                 "button2");
</programlisting>

<para>
The _from_widget() variants of the creation functions allow you to shorten this
further, by omitting the gtk_radio_button_get_group() call. This form is used 
in the example to create the third button:
</para>

<programlisting role="C">
     button2 = gtk_radio_button_new_with_label_from_widget(
	         GTK_RADIO_BUTTON (button1), 
                 "button2");
</programlisting>

<para>It is also a good idea to explicitly set which button should be the
default depressed button with:</para>

<programlisting role="C">
void gtk_toggle_button_set_active( GtkToggleButton *toggle_button,
                                   gboolean        state );
</programlisting>

<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>

<para>
<inlinemediaobject>
<imageobject>
<imagedata fileref="images/radiobuttons.png" format="png">
</imageobject>
</inlinemediaobject>
</para>

<programlisting role="C">
<!-- example-start radiobuttons radiobuttons.c -->

#include &lt;glib.h&gt;
#include &lt;gtk/gtk.h&gt;

static gboolean 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);
  
    g_signal_connect (G_OBJECT (window), "delete_event",
		      G_CALLBACK (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_get_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_from_widget (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");
    g_signal_connect_swapped (G_OBJECT (button), "clicked",
                              G_CALLBACK (close_application),
                              G_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>

</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="sec-ProgressBars">Progress Bars</link>,
<link linkend="sec-Viewports">Viewports</link>,
<link linkend="sec-ScrolledWindows">Scrolled Windows</link>, and others.</para>

<!-- ----------------------------------------------------------------- -->
<sect1 id="sec-CreatingAnAdjustment">
<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>

<programlisting role="C">
GtkObject *gtk_adjustment_new( gdouble value,
                               gdouble lower,
                               gdouble upper,
                               gdouble step_increment,
                               gdouble page_increment,
                               gdouble page_size );
</programlisting>

<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 id="sec-UsingAdjustments">
<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 viewport widget?  Of course it will! Just like this:</para>

<programlisting role="C">
  /* creates its own adjustments */
  viewport = gtk_viewport_new (NULL, NULL);
  /* uses the newly-created adjustment for the scrollbar as well */
  vscrollbar = gtk_vscrollbar_new (gtk_viewport_get_vadjustment (viewport));
</programlisting>

</sect1>

<!-- ----------------------------------------------------------------- -->
<sect1 id="sec-AdjustmentInternals">
<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>

<programlisting role="C">
struct _GtkAdjustment
{
  GtkObject parent_instance;
  
  gdouble lower;
  gdouble upper;
  gdouble value;
  gdouble step_increment;
  gdouble page_increment;
  gdouble page_size;
};
</programlisting>

<para>If you don't like to poke directly at struct internals like a 
<emphasis>real</emphasis> C programmer, you can use the following accessor to
inspect the <literal>value</literal> of an adjustment:</para>

<programlisting role="C">
gdouble	gtk_adjustment_get_value( GtkAdjustment *adjustment);
</programlisting>

<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>

<programlisting role="C">
void gtk_adjustment_set_value( GtkAdjustment *adjustment,
                               gdouble       value );
</programlisting>

<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>

<programlisting role="C">
  void (* value_changed) (GtkAdjustment *adjustment);
</programlisting>

<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
gtk_adjustment_set_value(). 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>

<programlisting role="C">
void cb_rotate_picture (GtkAdjustment *adj, GtkWidget *picture)
{
  set_picture_rotation (picture, gtk_adjustment_get_value (adj));
...
</programlisting>

<para>and connect it to the scale widget's adjustment like this:</para>

<programlisting role="C">
g_signal_connect (G_OBJECT (adj), "value_changed",
	          G_CALLBACK (cb_rotate_picture), (gpointer) picture);
</programlisting>

<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>

<programlisting role="C">
  void (* changed) (GtkAdjustment *adjustment);
</programlisting>

<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>

<programlisting role="C">
g_signal_emit_by_name (G_OBJECT (adjustment), "changed");
</programlisting>

<para>Now go forth and adjust!</para>

</sect1>
</chapter>

<!-- ***************************************************************** -->
<chapter id="ch-RangeWidgets">
<title>Range Widgets</title>

<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-Adjustments">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 id="sec-ScrollbarWidgets">
<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:</para>

<programlisting role="C">
GtkWidget *gtk_hscrollbar_new( GtkAdjustment *adjustment );

GtkWidget *gtk_vscrollbar_new( GtkAdjustment *adjustment );
</programlisting>

<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 id="sec-ScaleWidgets">
<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 create vertical and 
horizontal scale widgets, respectively:</para>

<programlisting role="C">
GtkWidget *gtk_vscale_new( GtkAdjustment *adjustment );

GtkWidget *gtk_vscale_new_with_range( gdouble min,
                                      gdouble max,
                                      gdouble step );

GtkWidget *gtk_hscale_new( GtkAdjustment *adjustment );

GtkWidget *gtk_hscale_new_with_range( gdouble min,
                                      gdouble max,
                                      gdouble step );
</programlisting>

<para>The <literal>adjustment</literal> argument can either be an adjustment which has
already been created with gtk_adjustment_new(), or NULL, 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. The _new_with_range() variants take care of creating
a suitable adjustment. (If you're <emphasis>already</emphasis> thoroughly
confused, read the section on <link linkend="ch-Adjustments">Adjustments</link> 
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>

<programlisting role="C">
void gtk_scale_set_draw_value( GtkScale *scale,
                               gboolean draw_value );
</programlisting>

<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 Adjustment. You can
change this with:</para>

<programlisting role="C">
void gtk_scale_set_digits( GtkScale *scale,
                            gint     digits );
</programlisting>

<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>

<programlisting role="C">
void gtk_scale_set_value_pos( GtkScale        *scale,
                              GtkPositionType  pos );
</programlisting>

<para>The argument <literal>pos</literal> is of type <literal>GtkPositionType</literal>,
which can take one of the following values:</para>

<programlisting role="C">
  GTK_POS_LEFT
  GTK_POS_RIGHT
  GTK_POS_TOP
  GTK_POS_BOTTOM
</programlisting>

<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, in order to learn more about their functions
and features.</para>

</sect2>
</sect1>

<!-- ----------------------------------------------------------------- -->
<sect1 id="sec-CommonRangeFunctions">
<title>Common Range Functions</title>

<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>

<!-- ----------------------------------------------------------------- -->
<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>

<variablelist>
<varlistentry>
<term><literal>GTK_UPDATE_CONTINUOUS</literal></term>
<listitem><para>This is the default. The
"value_changed" signal is emitted continuously, i.e., whenever the
slider is moved by even the tiniest amount.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>GTK_UPDATE_DISCONTINUOUS</literal></term>
<listitem><para>The "value_changed" signal is
only emitted once the slider has stopped moving and the user has
released the mouse button.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>GTK_UPDATE_DELAYED</literal></term>
<listitem><para>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.</para>
</listitem>
</varlistentry>
</variablelist>

<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>

<programlisting role="C">
void gtk_range_set_update_policy( GtkRange      *range,
	                          GtkUpdateType  policy);
</programlisting>

</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>

<programlisting role="C">
GtkAdjustment* gtk_range_get_adjustment( GtkRange *range );

void gtk_range_set_adjustment( GtkRange      *range,
                               GtkAdjustment *adjustment );
</programlisting>

<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>

<programlisting role="C">
g_signal_emit_by_name (G_OBJECT (adjustment), "changed");
</programlisting>

</sect2>
</sect1>

<!-- ----------------------------------------------------------------- -->
<sect1 id="sec-KeyAndMouseBindings">
<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 button-3 in the trough of a range or any button on 
a scrollbar's arrows will cause its adjustment's value to change by
<literal>step_increment</literal> at a time.</para>

<para>Scrollbars are not focusable, thus have no key bindings. The key bindings
for the other range widgets (which are, of course, only active when the widget 
has focus) are do <emphasis>not</emphasis> differentiate between horizontal and 
vertical range widgets.</para>

<para>All range widgets can be operated with the left, right, 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. This is done with the <literal>Home</literal> 
and <literal>End</literal> keys.</para>

</sect1>

<!-- ----------------------------------------------------------------- -->
<sect1 id="sec-RangeWidgetsExample">
<title>Example</title>

<para>This example is a somewhat modified version of the "range controls"
test from <filename>testgtk.c</filename>. 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>

<para>
<inlinemediaobject>
<imageobject>
<imagedata fileref="images/rangewidgets.png" format="png">
</imageobject>
</inlinemediaobject>
</para>

<programlisting role="C">
<!-- example-start rangewidgets rangewidgets.c -->

#include &lt;gtk/gtk.h&gt;

GtkWidget *hscale, *vscale;

static 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);
}

static 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);
}

static 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);
}

static 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;

    /* This sets the adjustment and makes it emit the "changed" signal to 
       reconfigure all the widgets that are attached to this signal.  */
    gtk_adjustment_set_value (set, CLAMP (set->value,
					  set->lower,
					  (set->upper - set->page_size)));
    g_signal_emit_by_name(G_OBJECT(set), "changed");
}

static 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 */

static GtkWidget *make_menu_item ( gchar     *name,
                                   GCallback  callback,
                                   gpointer   data )
{
    GtkWidget *item;
  
    item = gtk_menu_item_new_with_label (name);
    g_signal_connect (G_OBJECT (item), "activate",
	              callback, (gpointer) data);
    gtk_widget_show (item);

    return item;
}

static 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 */

static 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);
    g_signal_connect (G_OBJECT (window), "destroy",
                      G_CALLBACK (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_size_request (GTK_WIDGET (hscale), 200, -1);
    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);
    g_signal_connect (G_OBJECT (button), "toggled",
                      G_CALLBACK (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",
                           G_CALLBACK (cb_pos_menu_select),
                           GINT_TO_POINTER (GTK_POS_TOP));
    gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
  
    item = make_menu_item ("Bottom", G_CALLBACK (cb_pos_menu_select), 
                           GINT_TO_POINTER (GTK_POS_BOTTOM));
    gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
  
    item = make_menu_item ("Left", G_CALLBACK (cb_pos_menu_select),
                           GINT_TO_POINTER (GTK_POS_LEFT));
    gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
  
    item = make_menu_item ("Right", G_CALLBACK (cb_pos_menu_select),
                           GINT_TO_POINTER (GTK_POS_RIGHT));
    gtk_menu_shell_append (GTK_MENU_SHELL (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",
                           G_CALLBACK (cb_update_menu_select),
                           GINT_TO_POINTER (GTK_UPDATE_CONTINUOUS));
    gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
  
    item = make_menu_item ("Discontinuous",
                           G_CALLBACK (cb_update_menu_select),
                           GINT_TO_POINTER (GTK_UPDATE_DISCONTINUOUS));
    gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
  
    item = make_menu_item ("Delayed",
                           G_CALLBACK (cb_update_menu_select),
                           GINT_TO_POINTER (GTK_UPDATE_DELAYED));
    gtk_menu_shell_append (GTK_MENU_SHELL (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);
    g_signal_connect (G_OBJECT (adj2), "value_changed",
                      G_CALLBACK (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);
    g_signal_connect (G_OBJECT (adj2), "value_changed",
                      G_CALLBACK (cb_page_size), (gpointer) 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");
    g_signal_connect_swapped (G_OBJECT (button), "clicked",
                              G_CALLBACK (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 g_signal_connect()
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 id="sec-Labels">
<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="sec-EventBox">
EventBox</link> widget or a Button widget.</para>

<para>To create a new label, use:</para>

<programlisting role="C">
GtkWidget *gtk_label_new( const char *str );

GtkWidget *gtk_label_new_with_mnemonic( const char *str );
</programlisting>

<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>

<programlisting role="C">
void gtk_label_set_text( GtkLabel   *label,
                         const char *str );
</programlisting>

<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>

<programlisting role="C">
const gchar* gtk_label_get_text( GtkLabel  *label );                    
</programlisting>

<para>Do not free the returned string, as it is used internally by GTK.</para>

<para>The label text can be justified using:</para>

<programlisting role="C">
void gtk_label_set_justify( GtkLabel         *label,
                            GtkJustification  jtype );
</programlisting>

<para>Values for <literal>jtype</literal> are:</para>
<programlisting role="C">
  GTK_JUSTIFY_LEFT
  GTK_JUSTIFY_RIGHT
  GTK_JUSTIFY_CENTER (the default)
  GTK_JUSTIFY_FILL
</programlisting>

<para>The label widget is also capable of line wrapping the text
automatically. This can be activated using:</para>

<programlisting role="C">
void gtk_label_set_line_wrap (GtkLabel *label,
                              gboolean  wrap);
</programlisting>

<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>

<programlisting role="C">
void       gtk_label_set_pattern   (GtkLabel          *label,
                                    const gchar       *pattern);
</programlisting>

<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 <literal>"__     __"</literal> would underline the
first two characters and eight and ninth characters.</para>

<note><para>If you simply want to have an underlined accelerator ("mnemonic") 
in your label, you should use gtk_label_new_with_mnemonic() or 
gtk_label_set_text_with_mnemonic(), not gtk_label_set_pattern().</para>
</note>

<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="sec-Frames">Frame</link> 
widget is explained later on.</para>

<para>In GTK+ 2.0, label texts can contain markup for font and other text attribute 
changes, and labels may be selectable (for copy-and-paste). These advanced features
won't be explained here.</para>

<para>
<inlinemediaobject>
<imageobject>
<imagedata fileref="images/label.png" format="png">
</imageobject>
</inlinemediaobject>
</para>

<programlisting role="C">
<!-- example-start label label.c -->

#include &lt;gtk/gtk.h&gt;

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);
  g_signal_connect (G_OBJECT (window), "destroy",
		    G_CALLBACK (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