YAPOTT - Yet Another Post Of The Tutorial






Hmm.. is everyone getting tired of these filling your mailbox yet ?
Someone want to donate some space on a web server somewhere for it ?
Preferably somewhere where I can upload it myself without having to mail
it to someone for them to do it...

Anyway, I thought I'd let ya'll see it.  Check out the new section on
GTK's rc files :)

Ian


-------------------------------------------------------------


<!doctype linuxdoc system>
<article>
<title>GTK Tutorial
<author>Ian Main, <tt><htmlurl url="mailto:slow@intergate.bc.ca"
			      name="slow@intergate.bc.ca"></tt>
<date>August 2, 1997


<sect>Introduction
<p>
GTK (GIMP Toolkit) was originally developed as a toolkit for the GIMP
(General Image Manipulation Program).  GTK is built on top of GDK (GIMP
Drawing Kit)  which is basically wrapper around the Xlib functions.  It's
called the GIMP toolkit because it was original written for developing
the GIMP, but has now been used in several free software projects.  The
authors are
<itemize>
<item> Peter Mattis   <tt><htmlurl url="mailto:petm@xcf.berkeley.edu"
			   name="petm@xcf.berkeley.edu"></tt>
<item> Spencer Kimball <tt><htmlurl url="mailto:spencer@xcf.berkeley.edu"
			   name="spencer@xcf.berkeley.edu"></tt>
<item> Josh MacDonald <tt><htmlurl url="mailto:jmacd@xcf.berkeley.edu"
			   name="jmacd@xcf.berkeley.edu"></tt>
</itemize>

<p>
GTK is essentially an object oriented API.  Although written completely in
C, it is implemented using the idea of classes, and callback functions
(pointers to functions).
<p>
There is also a third component called glib which contains a few
replacements for printf, malloc etc.  These are used to increase gtk's
portability, as some of the functions implemented here are not available or
nonstandard on other Unicies such as g_strerror().   Some also contain 
enhancements to the libc versions such as
g_malloc will test for errors for you.
<p>
This tutorial is an attempt to document as much as possible of gtk, t is by 
no means complete.  This
tutorial assumes a good understanding of C, and how to create C programs.
It would be a great benifit 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 troubles with.
Note that there is also a C++ API for gtk (gtk--) in the works, so if you
prefer to use C++, you should look into this instead.
<p>
I would very much like to hear any problems you have learning gtk from this
document, and would appreciate input as to how it may be improved.

<sect>Getting Started
<p>
The first thing to do of course, is download the gtk source and install
it.  You can either get the distro with GIMP, or d/l it from Peter
Mattis's home dir ftp.xcf.berkely.edu/pub/pmattis.  Hopefully there will be
a gtk distribution page up shortly.
<p>
We'll start with the simplest GTK program possible.  This program will
create a 200x200 pixel window and has no way of exiting except to be
killed using the shell.

<tscreen><verb>
#include <gtk/gtk.h>

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;
}
</verb></tscreen>

All programs will of course include the gtk/gtk.h which declares the
variables, functions, structures etc. that will be used in your gtk application.
<p>
The next line

<tscreen><verb>
gtk_init (&amp;argc, &amp;argv);
</verb></tscreen>

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 colormap 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
arguements passed to your application on the command line, looking for one
of the following:
<itemize>
<item> <tt/--display/
<item> <tt/--debug-level/
<item> <tt/--no-xshm/
<item> <tt/--sync/
<item> <tt/--show-events/
<item> <tt/--no-show-events/
</itemize>
It removes these from the arguement list, leaving anything it does
not recognize for your application to parse or ignore.	This creates a set
of standard arguments excepted by all gtk applications.
<p>
The next two lines of code create and display a window.

<tscreen><verb>
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  gtk_widget_show (window);
</verb></tscreen>

The GTK_WINDOW_TOPLEVEL 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.
<p>
The gtk_widget_show() function, lets gtk know that we are done setting the
attributes of this widget, and it can display it.
<p>
The last line enters the GTK main processing loop.

<tscreen><verb>
gtk_main ();
</verb></tscreen>

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 keypresses) to occur.
In our simple example however, events are ignored.


<sect1>Hello World in GTK
<p>
OK, now for a program with a widget (a button).  It's the classic hello
world ala gtk.	This would make a good base for a new gtk application.

<tscreen><verb>

#include <gtk/gtk.h>

/* this is a callback function. the data arguments are ignored in this example..
 * More on callbacks below. */
void hello (GtkWidget *widget, gpointer *data)
{
    g_print ("Hello World\n");
}

/* another callback */
void destroy (GtkWidget *widget, gpointer *data)
{
    gtk_main_quit ();
}

int main (int argc, char *argv[])
{
    /* GtkWidget is the storage type for widgets */
    GtkWidget *window;
    GtkWidget *button;
    
    /* this is called in all gtk applications.  Arguements 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 "destroy" signal (this can be given
    * by the application, or the window manager, the function destroy
    * will be called as defined above.  The data passed to the callback
    * function is NULL as it is ignored anyway. */
    gtk_signal_connect (GTK_OBJECT (window), "destroy",
			GTK_SIGNAL_FUNC (destroy), NULL);
    
    /* sets the border width of the window. */
    gtk_container_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 it's arguement.  The hello() function is
     * defined above. */
    gtk_signal_connect (GTK_OBJECT (button), "clicked",
			GTK_SIGNAL_FUNC (hello), NULL);
    
    /* This will cause the window to be destroyed by calling
     * gtk_widget_destroy(window) when "clicked.  Again, the destroy
     * signal could come from here, or the window manager. */
    gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
			       GTK_SIGNAL_FUNC (gtk_widget_destroy),
			       GTK_OBJECT (window));
    
    /* this packs the button into the window (a gtk container). */
    gtk_container_add (GTK_CONTAINER (window), button);
    
    /* the final step is to display this newly created widget... */
    gtk_widget_show (button);
    
    /* and the window */
    gtk_widget_show (window);
    
    /* all gtk applications must have a gtk_main().	Control ends here
     * and waits for an event to occur (like a key press or mouse event). */
    gtk_main ();
    
    return 0;
}
</verb></tscreen>


To compile use:

<tscreen><verb>
gcc -Wall -g -lgtk -lgdk -lglib -lX11 -lXext -lm hello_world.c -o hello_world
</verb></tscreen>

The libraries above must all be in your default search paths, if not, add
-L&lt;library directory&gt; and gcc will look in these directories for
the needed
libraries.  For instance, on my Debian Linux box, I have to add
<tt>-L/usr/X11R6/lib</> for it to find the X11 libraries.
<p>
You may also have to play with the order of the above libraries.  This works
fine for me as is.  If anyone has problems, please let me know.
<p>
The libraries we are linking in are:
<itemize>
<item>The glib library (-lglib), containing misclaneous functions, none of
which are used in this particular example.  See the section on glib for details.
<item>The gdk library (-lgdk), the Xlib wrapper.
<item>The gtk library (-lgtk), the widget library, based on top of gdk.
<item>The xlib library (-lXlib) which is used by gdk.
<item>The Xext library (-lXext).  This contains code for shared memory
pixmaps and other X extentions.
<item>The math library (-lm).  This is used by gtk for various purposes.
</itemize>

<sect1>Theory of Signals and Callbacks
<p>
Before we look in detail at hello world, we'll discuss events 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.
<p>
This control is done using the idea of "signals".  When an event occurs, such as
the press of a mouse button, the
approprate signal will be "emitted" by the widget.  This is how GTK does
most of its useful work.  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:

<tscreen><verb>
gint gtk_signal_connect (GtkObject *object,
                         gchar *name,
			 GtkSignalFunc func,
			 gpointer func_data);
</verb></tscreen>
<p>
Where the first arguement is the widget which will be emitting the signal.  The
second, the name of the signal you wish to catch.  The third, the function
you wish to be called when it is caught, and the fourth, the data you wish
to have passed to this function.
<p>
The function specified in the third arguement is called a "callback
function", and should be of the form:

<tscreen><verb>
void callback_func(GtkWidget *widget, gpointer *callback_data);
</verb></tscreen>
<p>
Where the first arguement will be the widget that emitted the signal, and
the second, a pointer to the data given as the last arguement to the
gtk_signal_connect() function as shown above.
<p>
Another call used in the hello world example, is:

<tscreen><verb>
gint gtk_signal_connect_object (GtkObject *object,
                                gchar  *name,
				GtkSignalFunc func,
				GtkObject *slot_object);
</verb></tscreen>
<p>
gtk_signal_connect_object() is the same as gtk_signal_connect() except that
the callback function only uses one arguement, a
pointer to a gtk 
object.  So when using this function to connect signals, the callback should be of
the form:

<tscreen><verb>
void callback_func (GtkObject *object);
</verb></tscreen>
<p>
Where the object is usually a widget.  We usually don't setup callbacks for
gtk_signal_connect_object however.  They are usually used 
to call a gtk function that accepts a single widget or object as an
arguement, as is the case in our hello world example.

<sect1>Back to Hello World
<p>
Now that we know the theory behind this, lets clarify by walking through 
the example hello world program.
<p>
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 
arguement to tell us which button was pressed.

<tscreen><verb>
void hello (GtkWidget *widget, gpointer *data)
{
    g_print ("Hello World\n");
}
</verb></tscreen>
<p>
Here is another callback function which just quits by calling
gtk_main_quit().  Not really much to say about this, it is pretty self
explanatory.
<tscreen><verb>
void destroy (GtkWidget *widget, gpointer *data)
{
    gtk_main_quit ();
}
</verb></tscreen>
<p>
I assume you know about the main() function... yes, as with other
applications, all gtk applications will also have one of these.
<tscreen><verb>
int main (int argc, char *argv[])
{
</verb></tscreen>
<p>
This next part, declares a pointer to a structure of type GtkWidget.  These
are used below to create a window and a button.
<tscreen><verb>
    GtkWidget *window;
    GtkWidget *button;
</verb></tscreen>
<p>
Here is our gtk_init again.  As before, this initializes the toolkit, and
parses the arguements found on the command line.  Any arguement 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 arguements.
<tscreen><verb>
    gtk_init (&amp;argc, &amp;argv);
</verb></tscreen>
<p>
Create a new window.  This is fairly straight forward.  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 below where we call
gtk_widget_show(window) near the end of our program.
<tscreen><verb>
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
</verb></tscreen>
<p>
Here is an example of connecting a signal handler to an object, in this case, the
window.  Here, the "destroy" signal is caught.  This is emitted when we use
the window manager to kill the window, or when we send the
gtk_widget_destroy() call passing in the window widget as the object to
destroy.  By setting this up, we handle both cases with a single call.
Here, it just calls the destroy() function defined above with a NULL
arguement, which quits gtk for us.  This will allow us to use the window
manager to quit the program.
<p>
The GTK_OBJECT and GTK_SIGNAL_FUNC are macros that perform type casting for
us, as well as aid the readability of the code.
<tscreen><verb>
    gtk_signal_connect (GTK_OBJECT (window), "destroy",
			GTK_SIGNAL_FUNC (destroy), NULL);
</verb></tscreen>
<p>
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 _____.
<p>
And again, GTK_CONTAINER is a macro to perform typecasting.
<tscreen><verb>
    gtk_container_border_width (GTK_CONTAINER (window), 10);
</verb></tscreen>
<p>
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.
<tscreen><verb>
    button = gtk_button_new_with_label ("Hello World");
</verb></tscreen>
<p>
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.
<tscreen><verb>
    gtk_signal_connect (GTK_OBJECT (button), "clicked",
			GTK_SIGNAL_FUNC (hello), NULL);
</verb></tscreen>
<p>
We are also going to use this button to exit our program.  This will
illistrate 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 function 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 arguement, we use the gtk_signal_connect_object()
function here instead of straight gtk_signal_connect().

<tscreen><verb>
    gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
			       GTK_SIGNAL_FUNC (gtk_widget_destroy),
			       GTK_OBJECT (window));
</verb></tscreen>
<p>
This is a packing call, which will be explained in depth later on.  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.
<tscreen><verb>
    gtk_container_add (GTK_CONTAINER (window), button);
</verb></tscreen>
<p>
Now that we have everything setup 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 simple example, you'd never notice.
<tscreen><verb>
    gtk_widget_show (button);

    gtk_widget_show (window);
</verb></tscreen>
<p>
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.
<tscreen><verb>
    gtk_main ();
</verb></tscreen>
And the final return.  Control returns here after gtk_quit() is called.
<tscreen><verb>
    return 0;
</verb></tscreen>
<p>
So, to recap on events, 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
arguement, and then the next handler for this signal is called.  This calls
the gtk_widget_destroy() function, passing it the window widget as it's
arguement, 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.
<p>
Another course of events, is to use the window manager to kill the window.
This will also cause the window to emit the "destroy" signal, and again the
destroy() callback is called whcih exits gtk.
<p>
Note that these signals are not the same as the Unix system
signals, and are not implemented using them, although the terminalogy is
almost identical.


<sect>More on GTK 
<p>
<sect1>Data Types
<p>
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.  This is done
to get around that nasty dependancy on the size of simple data types when doing calculations.
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 straight forward and intuitive.  They are all defined in
glib/glib.h (which gets included from gtk.h).
<p>
You'll also notice the ability to use GtkWidget when the function calls for a GtkObject.  
GTK is an object oriented design, and a widget is an object.

<sect1>More on Signal Handlers
<p>
Lets take another look at the gtk_signal_connect decleration.

<tscreen><verb>
gint gtk_signal_connect (GtkObject *object, gchar *name,
			 GtkSignalFunc func, gpointer func_data);
</verb></tscreen>

Notice the gint return value ?  This is a tag that identifies your callback
function.  As said 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.  
This tag allows you to remove this callback from the list by using:
<tscreen><verb>
void gtk_signal_disconnect (GtkObject *object,
                            gint id);
</verb></tscreen>
So, by passing in the widget you wish to remove the handler from, and the
tag or id returned by one of the signal_connect functions, you can
disconnect a signal handler.

You may also use:

<tscreen><verb>
gtk_signal_disconnect_by_data (GtkObject *object,
                               gpointer data);
</verb></tscreen>
<p>
Which I have never used and I don't really know for sure how it works :)
<p>
Another function to remove all the signal handers from an object is:
<tscreen><verb>
gtk_signal_handlers_destroy (GtkObject *object);
</verb></tscreen>
<p>
This call is fairly self explanitory.  It simply removes all the current
signal handlers from the object passed in as the first arguement.


<sect1>An Upgraded Hello World
<p>
Let's take a look at a slightly improved hello world with better examples
of callbacks.  This will also introduce us to our next topic, packing
widgets.

<tscreen><verb>
#include <gtk/gtk.h>

/* Our new improved callback.  The data passed to this function is printed
 * to stdout. */
void callback (GtkWidget *widget, gpointer *data)
{
    g_print ("Hello again - %s was pressed\n", (char *) data);
}

/* another callback */
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;
    GtkWidget *box1;

    /* this is called in all gtk applications.	Arguements 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, this just sets the title of our
     * new window to "Hello Buttons!" */
    gtk_window_set_title (GTK_WINDOW (window), "Hello Buttons!");

    /* It's a good idea to do this for all windows. */
    gtk_signal_connect (GTK_OBJECT (window), "destroy",
			GTK_SIGNAL_FUNC (destroy), NULL);


    /* sets the border width of the window. */
    gtk_container_border_width (GTK_CONTAINER (window), 10);

    /* we create a box to pack widgets into.  this is described in detail
     * in the "packing" section below.  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 it's arguement */
    gtk_signal_connect (GTK_OBJECT (button), "clicked",
			GTK_SIGNAL_FUNC (callback), (gpointer) "button 1");

    /* instead of gtk_container_add, we pack this button into the invisible
     * box, which has been packed into the window. */
    gtk_box_pack_start(GTK_BOX(box1), button, TRUE, TRUE, 0);

    /* always remember this step, this tells gtk that our preparation for
     * this button is complete, and it can be displayed now. */
    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 arguement,
     * passing a pointer to "button 2" instead. */
    gtk_signal_connect (GTK_OBJECT (button), "clicked",
			GTK_SIGNAL_FUNC (callback), (gpointer) "button 2");

    gtk_box_pack_start(GTK_BOX(box1), button, TRUE, TRUE, 0);

    /* we show the widgets in the reverse order we created them,
     * someone want to explain to me why ?? :) or is it even
     * necessary ? */
    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;
}
</verb></tscreen>
<p>
Compile this program using the same linking arguements 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.  Try playing with resizing the window.
<p>
Just as a side note, there is another useful define for gtk_window_new() -
GTK_WINDOW_DIALOG.  This interacts with the window manager a little
differently and should be used for transient windows.

<sect>Packing Widgets
<p>
When creating an application, you'll want to put more than one button
inside a window.  Our first hello world 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.
<p>
Most packing is done by creating boxes as in the example above.  These are
invisible widget containers that we can pack our widgets into and 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.
<p>
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 allow 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.	And in
fact, many widgets are actually containers themselves including the
button, but we usually only use a label inside a button.
<p>
By using these calls, gtk knows where you want to place your widgets so it
can do automatic resizing and other nifty things.  there's 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.
<p>
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 you can get.

<tscreen><verb>    <!-- Don't know the tag for images, but there is one -->
&lt;p align=center> &lt;img src="packbox1.gif" width=528 height=235> &lt;/p>
</verb></tscreen>

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).
<p>
This is the declaration of the gtk_box_pack_start function.

<tscreen><verb>
void gtk_box_pack_start (GtkBox    *box,
			 GtkWidget *child,
			 gint	    expand,
			 gint	    fill,
			 gint	    padding);
</verb></tscreen>

The first arguement is the box you are packing the object into, the second
is this object.  The objects will all be buttons for now, so we'll be
packing buttons into boxes.
<p>
The expand argument to gtk_box_pack_start() or 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 alloted 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
justifying of your widgets.  Otherwise, they will all expand to fit in the
box, and the same effect could be achieved by using only one of
gtk_box_pack_start or pack_end functions.
<p>
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.
<p>
[does the above sound right to you ?]
<p>
When creating a new box, the function looks like this:

<tscreen><verb>
GtkWidget * gtk_hbox_new (gint homogeneous,
			  gint spacing);
</verb></tscreen>

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 expand
argument to the gtk_box_pack routines is always turned on.
<p>
What's the difference between spacing (set when the box is created) and
adding (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:

<tscreen><verb>    <!-- Don't know the tag for images, but there is one -->
&lt;p align=center> &lt;img src="packbox2.gif" width=509 height=213> &lt;/p>
</verb></tscreen>

<p>
Someone write about table widgets! :)

<sect>Widget Overview
<p>
<p>
The general steps to creating a widget in gtk are:
<enum>
<item> gtk_*_new - one of various functions to create a new widget.  These
are all detailed in this section.

<item> Connect all signals we wish to use to the appropriate handlers.

<item> Set the attributes of the widget.

<item> Pack the widget into a container using the appropriate call such as 
gtk_container_add() or gtk_box_pack_start().

<item> gtk_widget_show()
</enum>
<p>
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.

We'll further our exploration of gtk by examining each widget in turn,
creating a few simple functions to display them.  Another good source is
the testgtk.c program that comes with gtk.  It can be found in
gtk/testgtk.c.
<p>
For your reference, here is the class hierarchy tree used to implement widgets.

<tscreen><verb>
    GtkObject
    +-- GtkData
    |	\-- GtkAdjustment
    |
    \-- GtkWidget
	+-- GtkContainer
	|   +-- GtkBin
	|   |	+-- GtkAlignment
	|   |	+-- GtkFrame
	|   |	|   *-- GtkAspectFrame
	|   |	|
	|   |	+-- GtkItem
	|   |	|   +-- GtkListItem
	|   |	|   +-- GtkMenuItem
	|   |	|   |	+-- GtkCheckMenuItem
	|   |	|   |	    *-- GtkRadioMenuItem
	|   |	|   |
	|   |	|   *-- GtkTreeItem
	|   |	|
	|   |	+-- GtkViewport
	|   |	\-- GtkWindow
	|   |	    +-- GtkDialog
	|   |	    \-- GtkFileSelection
	|   |
	|   +-- GtkBox
	|   |	+-- GtkHBox
	|   |	\-- GtkVBox
	|   |	    +-- GtkColorSelection
	|   |	    \-- GtkCurve
	|   |
	|   +-- GtkButton
	|   |	+-- GtkOptionMenu
	|   |	\-- GtkToggleButton
	|   |	    \-- GtkCheckButton
	|   |		\-- GtkRadioButton
	|   |
	|   +-- GtkList
	|   +-- GtkMenuShell
	|   |	+-- GtkMenu
	|   |	\-- GtkMenuBar
	|   |
	|   +-- GtkNotebook
	|   +-- GtkScrolledWindow
	|   +-- GtkTable
	|   \-- GtkTree
	|
	+-- GtkDrawingArea
	+-- GtkEntry
	+-- GtkMisc
	|   +-- GtkArrow
	|   +-- GtkImage
	|   +-- GtkLabel
	|   \-- GtkPixmap
	|
	+-- GtkPreview
	+-- GtkProgressBar
	+-- GtkRange
	|   +-- GtkScale
	|   |	+-- GtkHScale
	|   |	\-- GtkVScale
	|   |
	|   \-- GtkScrollbar
	|	+-- GtkHScrollbar
	|	\-- GtkVScrollbar
	|
	+-- GtkRuler
	|   +-- GtkHRuler
	|   \-- GtkVRuler
	|
	\-- GtkSeparator
	    +-- GtkHSeparator
	    \-- GtkVSeparator

</verb></tscreen>

<sect1>The Button Widget
<p>
We've almost seen all there is to see of the button widget.  It's pretty
simple.  There is however two ways to create a button.	You can use the
gtk_button_new_with_label() to create a button with a label, or use
gtk_button_new() to create a blank button.  It's then up to you to pack a
label or pixmap into this new button.  To do this, create a new box, and
then pack your objects into this box using the usual gtk_box_pack_start,
and then use gtk_container_add to pack the box into the button.
<p>
Here's an example of using gtk_button_new to create a button with a
picture and a label in it.  I've broken the code to create a box up from
the rest so you can use it in your programs.


<tscreen><verb>
#include <gtk/gtk.h>


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

GtkWidget *xpm_label_box (GtkWidget *parent, gchar *xpm_filename, gchar *label_text)
{
    GtkWidget *box1;
    GtkWidget *label;
    GtkWidget *pixmapwid;
    GdkPixmap *pixmap;
    GdkBitmap *mask;
    GtkStyle *style;

    /* create box for xpm and label */
    box1 = gtk_hbox_new (FALSE, 0);
    gtk_container_border_width (GTK_CONTAINER (box1), 2);

    /* get style of button.. I assume it's to get the background color.
     * if someone knows the real reason, please enlighten me. */
    style = gtk_widget_get_style(parent);

    /* now on to the xpm stuff.. load xpm */
    pixmap = gdk_pixmap_create_from_xpm (parent->window, &amp;mask,
					 &amp;style->bg[GTK_STATE_NORMAL],
					 xpm_filename);
    pixmapwid = gtk_pixmap_new (pixmap, mask);

    /* create label for button */
    label = gtk_label_new (label_text);

    /* pack the pixmap and label into the box */
    gtk_box_pack_start (GTK_BOX (box1),
			pixmapwid, FALSE, FALSE, 3);

    gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 3);

    gtk_widget_show(pixmapwid);
    gtk_widget_show(label);

    return (box1);
}

/* our usual callback function */
void callback (GtkWidget *widget, gpointer *data)
{
    g_print ("Hello again - %s was pressed\n", (char *) data);
}


int main (int argc, char *argv[])
{
    /* GtkWidget is the storage type for widgets */
    GtkWidget *window;
    GtkWidget *button;
    GtkWidget *box1;

    gtk_init (&amp;argc, &amp;argv);

    /* create a new window */
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);

    gtk_window_set_title (GTK_WINDOW (window), "Pixmap'd Buttons!");

    /* It's a good idea to do this for all windows. */
    gtk_signal_connect (GTK_OBJECT (window), "destroy",
			GTK_SIGNAL_FUNC (gtk_exit), NULL);


    /* sets the border width of the window. */
    gtk_container_border_width (GTK_CONTAINER (window), 10);

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

    /* You should be getting used to seeing most of these functions by now */
    gtk_signal_connect (GTK_OBJECT (button), "clicked",
			GTK_SIGNAL_FUNC (callback), (gpointer) "cool button");

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

    /* pack and show all our widgets */
    gtk_widget_show(box1);

    gtk_container_add (GTK_CONTAINER (button), box1);

    gtk_widget_show(button);

    gtk_container_add (GTK_CONTAINER (window), button);

    gtk_widget_show (window);

    /* rest in gtk_main and wait for the fun to begin! */
    gtk_main ();

    return 0;
}
</verb></tscreen>

The xpm_label_box function could be used to pack xpm's and labels into any
widget that can be a container.

<sect1> Toggle Buttons
<p>
Toggle buttons are very similar to normal buttons, 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. 

Toggle buttons are the basis for check buttons and radio buttons, as such,
many of the calls used for toggle buttons are inhereted by radio and check
buttons.  I will point these out when we come to them.

Creating a new toggle button:

<tscreen><verb>
GtkWidget* gtk_toggle_button_new (void);

GtkWidget* gtk_toggle_button_new_with_label (gchar *label);
</verb></tscreen>
<p>
As you can imagine, these work identically to the normal button widget
calls.  The first creates a blank toggle button, and the second, one with a
label widget already packed into it.
<p>
To retreive the state of the toggle widget, including radio and check
buttons, we use a macro as shown in our example below.  This tests the state
of the toggle in a callback.  The signal of interest emitted to us by toggle
buttons (the toggle button, check button, and radio button widgets), is the
"toggled" signal.  To check the state of these buttons, use a callback to
catch this signal that looks something like this:

<tscreen><verb>
void toggle_button_callback (GtkWidget *widget, gpointer   data)
{
    if (GTK_TOGGLE_BUTTON (widget)->active) 
    {
        /* If control reaches here, the toggle button is depressed. */
    }
}
</verb></tscreen>

The above is in need of testing.. It's just a guess..

<tscreen><verb>
guint gtk_toggle_button_get_type (void);
</verb></tscreen>
<p>
No idea... they all have this, but I dunno what it is :)

<tscreen><verb>
void gtk_toggle_button_set_mode (GtkToggleButton *toggle_button,
                                 gint draw_indicator);
</verb></tscreen>
<p>
No idea.

<tscreen><verb>
void gtk_toggle_button_set_state (GtkToggleButton *toggle_button,
                                  gint state);
</verb></tscreen>
<p>
The above call can be used to set the state of the toggle button, and it's
children the radio and check buttons.  Passing
in your created button as the first arguement, and a TRUE or FALSE
for the second state arguement to specify whether it should be up (released) or
down (depressed).  Default is up, or FALSE.

<tscreen><verb>
void       gtk_toggle_button_toggled        (GtkToggleButton *toggle_button);
</verb></tscreen>
<p>
Hmm.. judging from the gtk code, it toggles the button, and emits the
"toggled" signal..

<sect1> Check Buttons
<p>
Check buttons inherent 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 seen for
toggling options on and off in applications.

The two creation functions are the same as for the normal button.

<tscreen><verb>
GtkWidget* gtk_check_button_new (void);

GtkWidget* gtk_check_button_new_with_label (gchar *label);
</verb></tscreen>

The new_with_label function creates a check button with a label beside it.

Checking the state of the check button is identical to that of the toggle
button.

<sect1> Radio Buttons
<p>
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.

Creating a new radio button is done with one of these calls:

<tscreen><verb>
GtkWidget* gtk_radio_button_new (GSList *group);

GtkWidget* gtk_radio_button_new_with_label (GSList *group,
                                            gchar *label);
</verb></tscreen>
<p>
You'll notice the extra arguement to these calls.  They require a group to
perform they're duty properly.  The first call should pass NULL as the first
arguement.  You then create a group using:

<tscreen><verb>
GSList* gtk_radio_button_group (GtkRadioButton *radio_button);
</verb></tscreen>

<p>
You then pass this group as the first arguement to each subsequent call to
gtk_radio_button_new or new_with_label.  It is also a good idea to
explicitly set which button should be the default depressed button with:

<tscreen><verb>
void gtk_toggle_button_set_state (GtkToggleButton *toggle_button,
                                  gint state);
</verb></tscreen>
<p>
This is described in the section on toggle buttons, and works in exactly the
same way.
<p>
[Insert an example here of how to use these guys cause I think it could do a
lot of good at this point.]

<sect1>The Tooltips Widget
<p>
These are the little text strings that pop up when you leave your pointer
over a button or other widget for a few seconds.  They are easy to use, so I
will just explain them without giving an example.  If you want to see some
code, take a look at the testgtk.c program distributed with gtk.
<p>
The first call you will use to create a new tooltip.  You only need to do
this once in a given function.	The GtkTooltip this function returns can be
used to create multiple tooltips.

<tscreen><verb>
GtkTooltips *gtk_tooltips_new (void);
</verb></tscreen>

Once you have created a new tooltip, and the widget you wish to use it on,
simply use this call to set it.

<tscreen><verb>
void gtk_tooltips_set_tips   (GtkTooltips *tooltips,
			      GtkWidget   *widget,
			      gchar	  *tips_text);
</verb></tscreen>

The first arguement is the tooltip you've already created, followed by the
widget you wish to have this tooltip pop up for, and the text you wish it to
say.
<p>
Here's a short example:

<tscreen><verb>
GtkTooltips *tooltips;
GtkWidget *button;
...
tooltips = gtk_tooltips_new ();
button = gtk_button_new_with_label ("button 1");
...
gtk_tooltips_set_tips (tooltips, button, "This is button 1");
</verb></tscreen>


There are other calls used with tooltips.  I will just list them with a
brief description of what they do.

<tscreen><verb>
void gtk_tooltips_destroy    (GtkTooltips *tooltips);
</verb></tscreen>

Destroy the created tooltips.

<tscreen><verb>
void gtk_tooltips_enable     (GtkTooltips *tooltips);
</verb></tscreen>

Enable a disabled set of tooltips.

<tscreen><verb>
void gtk_tooltips_disable    (GtkTooltips *tooltips);
</verb></tscreen>

Disable an enabled set of tooltips.

<tscreen><verb>
void gtk_tooltips_set_delay  (GtkTooltips *tooltips,
			      gint	   delay);
			      void	  gtk_tooltips_set_tips
			      (GtkTooltips *tooltips,
			      GtkWidget   *widget,
			      gchar	  *tips_text);
</verb></tscreen>

Sets how many milliseconds you have to hold you pointer over the widget before the
tooltip will pop up.  The default is 1000 milliseconds or 1 second.

<tscreen><verb>
void gtk_tooltips_set_colors (GtkTooltips *tooltips,
			      GdkColor	  *background,
			      GdkColor	  *foreground);
</verb></tscreen>

Set the foreground and background color of the tooltips.  Again, I have no
idea how to specify the colors.
<p>
And that's all the functions associated with tooltips.  More than you'll
ever want to know :)



<sect1> Scrolled Windows
<p>
Please write about me :)

<sect1> Text Entries
<p>
Please write about me :)

<sect1> Lists
<p>
Please write about me :)

<sect1> Color Selections
<p>
Please write about me :)

<sect1> File Selections
<p>
Please write about me :)

<sect1> Dialogs
<p>
Please write about me :)

<sect1> Range Controls
<p>
Please write about me :)

<sect1> Rulers
<p>
Please write about me :)

<sect1> Text Boxes
<p>
Please write about me :)

<sect1> Notebooks
<p>
Please write about me :)

<sect1> Progress Bars
<p>
Please write about me :)

<sect1> Color Previews
<p>
Please write about me :)

<sect1> Grey Previews
<p>
Please write about me :)

<sect1> Curves
<p>
Please write about me :)

<sect1> Pixmaps
<p>
Please write about me :)


<sect1>Menu Widgets
<p>
There are two ways to create menus, there's the easy way, and there's the
hard way.  Both have their uses, but you can usually use the menu_factory
(the easy way).  The "hard" way is to create all the menus using the calls
directly.  The easy way is to use the gtk_menu_factory calls.  This is
much simpler, but I've had problems because of the '/' that is used to
seperated menus.  Other than this, there is no real reason to use the
manual method (is this true ??)
<p>
In the true tradition of teaching, we'll show you the hard
way first. <tt>:)</>
<p>
Let's look at the functions that are used to create menus.
This first function is used to create a new menu.

<tscreen><verb>
GtkWidget *gtk_menu_bar_new()
</verb></tscreen>

This rather self explanatory function creates a new menu bar.  You use
gtk_container_add to pack this into a window, or the box_pack functions to
pack it into a box - the same as buttons.

<tscreen><verb>
GtkWidget *gtk_menu_new();
</verb></tscreen>

This function returns a pointer to a new menu, it is never actually shown
(with gtk_widget_show), it just holds the menu items.  Hopefully this will
become more clear when you look at the example below.
<p>
The next two calls are used to create menu items that are packed into
the menu.

<tscreen><verb>
GtkWidget *gtk_menu_item_new()
</verb></tscreen>

and

<tscreen><verb>
GtkWidget *gtk_menu_item_new_with_label(const char *label)
</verb></tscreen>

These calls are used to create the menus that are to be displayed.
Remember to differentiate between a "menu" as created with gtk_menu_new
and a "menu item" as created by the gtk_menu_item_new functions.  The
menu item will be an actual button with an associated action,
whereas a menu will be a container holding these

<tscreen><verb>
gtk_menu_item_append()

gtk_menu_item_set_submenu()
</verb></tscreen>

The gtk_menu_new_with_label and plain gtk_menu_new functions are just as you'd expect after
reading about the buttons.  One creates a new menu item with a label
already packed into it, and the other just creates a blank menu item.
<p>
The steps to create a menu are outlined below:
<itemize>
<item>	Create a new menu using gtk_menu_new()
<item>	Create a menu item using gtk_menu_item_new().  This will be the root of
  the menu, the text appearing here will be on the menu bar itself.
<item>	Use multiple calls to gtk_menu_item_new for each item you wish to have on
  your menu.  And use gtk_menu_item_append() to put each of these new items on
  together.  This creates a list of menu items.
<item>	Use gtk_menu_item_set_submenu() to attach the newly created menu_items to
  the root menu item (The one created in the second step).
<item>	Create a new menu bar using gtk_menu_bar_new.  This step only needs
  to be done once when creating a series of menus on one menu bar.
<item> Use gtk_menu_bar_append to put the root menu onto the menubar.
</itemize>
And that should about do it.  Let's take a look at an example to help clarify.


<tscreen><verb>
#include <gtk/gtk.h>

int main (int argc, char *argv[])
{

    GtkWidget *window;
    GtkWidget *menu;
    GtkWidget *menu_bar;
    GtkWidget *root_menu;
    GtkWidget *menu_items;
    char buf[128];
    int i;

    gtk_init (&amp;argc, &amp;argv);

    /* create a new window */
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW (window), "GTK Menu Test");
    gtk_signal_connect(GTK_OBJECT (window), "destroy",
		       (GtkSignalFunc) gtk_exit, NULL);

    /* Init the menu-widget, and remember -- never
     * gtk_show_widget() the menu widget!! */
    menu = gtk_menu_new();

    /* This is the root menu, and will be the label will be the menu name displayed on
     * the menu bar.  There won't be
     * a signal handler attached, as it only pops up the rest of the menu when pressed. */
    root_menu = gtk_menu_item_new_with_label("Root Menu");

    gtk_widget_show(root_menu);

    /* Next we make a little loop that makes three menu-entries for "test-menu".
     * Notice the call to gtk_menu_append.  Here we are adding a list of menu items
     * to our menu.  Normally, we'd also catch the "clicked" signal on each of the
     * menu items and setup a callback for it, but it's omitted here to save space. */

    for(i = 0; i < 3; i++)
	{
	    /* Copy the names to the buf. */
	    sprintf(buf, "Test-undermenu - %d", i);

	    /* Create a new menu-item with a name... */
	    menu_items = gtk_menu_item_new_with_label(buf);

	    /* ...and add it to the menu. */
	    gtk_menu_append(GTK_MENU (menu), menu_items);

	    /* Show the widget */
	    gtk_widget_show(menu_items);
	}

    /* Now we specify that we want our newly created "menu" to be the menu for the "root menu" */
    gtk_menu_item_set_submenu(GTK_MENU_ITEM (root_menu), menu);

    /* Create a menu-bar to hold the menus and add it to our main window*/
    menu_bar = gtk_menu_bar_new();
    gtk_container_add(GTK_CONTAINER(window), menu_bar);
    gtk_widget_show(menu_bar);

    /* And finally we append the menu-item to the menu-bar -- this is the "root"
     * menu-item I have been raving about =) */
    gtk_menu_bar_append(GTK_MENU_BAR (menu_bar), root_menu);

    /* always display the window as the last step so it all splashes on the screen at once. */
    gtk_widget_show(window);

    gtk_main ();

    return 0;
}
</verb></tscreen>

You may also set a menu item to be insensitive or, using an accelerator
table, bind keys to menu functions.
<p>
[ maybe insert a few calls or something ]
<p>
Now that we've shown you the hard way, here's how you do it using the
gtk_menu_factory calls.
<p>
[ gtk_menu_factory example and explanation ]

<sect>Timeouts, IO and Idle Functions
<p>
<sect1>Timeouts
<p>
You may be wondering how you make gtk do useful work when in gtk_main.
Well, you have several options.  Using the following functions you can
create a timeout function.

<tscreen><verb>
gint gtk_timeout_add (guint32 interval,
		      GtkFunction function,
		      gpointer data);
</verb></tscreen>

The first arguement is the number of milliseconds
between calls to your function.  The second arguement is the function
you wish to have called, and
the third, the data passed to this callback function.  The return value is
an integer "tag" which may be used to stop the timeout by calling:

<tscreen><verb>
void gtk_timeout_remove (gint tag);
</verb></tscreen>

You may also stop the timeout function by returning zero or FALSE from
your callback function.  Obviously this means if you want your function to
continue to be called, it should return a non-negative value, ie TRUE.

The declaration of you callback should look something like this:

<tscreen><verb>
gint timeout_callback (gpointer data);
</verb></tscreen>

<sect1>Monitoring IO
<p>
Another nifty feature of gtk, is the ability to have it check for data on a
file descriptor for you (as returned by open(2) or socket(2)).	This is
especially useful for networking applications.	The function:

<tscreen><verb>
gint gdk_input_add (gint source,
		    GdkInputCondition condition,
		    GdkInputFunction  function,
		    gpointer data);
</verb></tscreen>

Where the first arguement is the file descriptor you wish to have watched,
and the second specifies what you want gdk to look for.  This may be one of:
<p>
GDK_INPUT_READ - Call your function when there is data ready for reading on
your file descriptor.
<p>
GDK_INPUT_WRITE - Call your function when the file descriptor is ready for
writing.
<p>
As I'm sure you've figured out already, the third arguement is the function
you wish to have called when the above conditions are satisfied, and the
fourth is the data to pass to this function.
<p>
The return value is a tag that may be used to stop gdk from monitoring this
file descriptor using the following function.

<tscreen><verb>
void gdk_input_remove (gint tag);
</verb></tscreen>
<p>
As with the gtk_timeout_add function above, a FALSE return from your
callback function will also cause gtk to stop monitoring the file
descriptor. (will have to verify this.)


<sect1>Idle Functions
<p>
What about if you have a function you want called when nothing else is
happening ?

<tscreen><verb>
gint gtk_idle_add (GtkFunction function,
		   gpointer data);

void gtk_idle_remove (gint tag);
</verb></tscreen>
<p>
I won't explain the meaning of the arguements as they follow very much like
the ones above.  The function pointed to by the first arguement to
gtk_idle_add will be called whenever the opportunity arises.  As with the
others, returning FALSE will stop the idle function from being called.


<sect>glib Functions
<p>
There are several useful function that we recomend you use when creating gdk
and gtk applications.  I will list them all here with a brief explanation.
They are all duplicates of standard libc functions so I won't go into
detail.  This is mostly to be used as a reference, so you know what is
available for use.


<tscreen><verb>
gpointer g_malloc      (gulong    size);
</verb></tscreen>

This is a replacement for malloc().  You do not need to check the return
vaule as it is done for you in this function.

<tscreen><verb>
gpointer g_malloc0     (gulong    size);
</verb></tscreen>

Same as above, but zero's the memory before returning a pointer to it.

<tscreen><verb>
gpointer g_realloc     (gpointer  mem,
                        gulong    size);
</verb></tscreen>

Relocates "size" bytes of memory starting at "mem".  Obviously, the memory should have been
previously allocated.

<tscreen><verb>
void     g_free        (gpointer  mem);
</verb></tscreen>

Free's memory.  Easy one.

<tscreen><verb>
gchar* g_strdup    (const gchar *str);
</verb></tscreen>

Replacement strdup function.  Allocates memory for a new string and returns
a pointer to it.

<tscreen><verb>
gchar* g_strerror  (gint errnum);
</verb></tscreen>

I recomend using this for all error messages.  It's much nicer, and more
portable than perror() or others.  The output is usually of the form:

<tscreen><verb>
program name:function that failed:file or further description:strerror
</verb></tscreen>

Here's an example of one such call used in our hello_world program:

<tscreen><verb>
g_print("hello_world:open:%s:%s\n", filename, g_strerror(errno));
</verb></tscreen>

And our last function:

<tscreen><verb>
gchar* g_strsignal (gint signum);
</verb></tscreen>

Prints out the name of the signal given the signal number.

There are many more such functions in glib/glib.h, but I will not go into
depth on them.  If anyone wants to add some short descriptions of other
functions in here, like for the linked list stuff, please do.

<sect>Setting Widget Attributes
<p>
This section will describe calls used to set attributes such as padding and
style.  Also stuff on umm.. stuff.. (brain went blank :)


<sect>GTK's rc Files
<p>
GTK has it's own way of dealing with application defaults, by using rc
files.  These can be used to set the colors of just about any widget, and
can also be used to tile pixmaps onto the background of some widgets.  

<sect1>Functions For rc Files 
<p>
When your application starts, you should include a call to:
<tscreen><verb>
void gtk_rc_parse (char *filename);
</verb></tscreen>
<p>
Passing in the filename of your rc file.  This will cause gtk to parse this
file, and use the style settings for the widget types defined there.
<p>
If you wish to have a special set of widgets that can take on a different
style from others, or any other logical division of widgets, use a call to:
<tscreen><verb>
void gtk_widget_set_name (GtkWidget *widget,
                          gchar *name);
</verb></tscreen>
<p>
Passing your newly created widget in as the first arguement, and the name
you wish to give it as the second.  This will allow you to change the
attributes of this widget by name through the rc file.
<p>
If we use a call something like this:

<tscreen><verb>
button = gtk_button_new_with_label ("Special Button");
gtk_widget_set_name (button, "special button");
</verb></tscreen>
<p>
Then this button is given the name "special button" and may be addressed by
name in the rc file as "special button.GtkButton".  [<--- Verify ME!]
<p>
The example rc file below, sets the properties of the main window, and lets
all children of that main window inheret the style described by the "main
button" style.  The code used in the application is:

<tscreen><verb>
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_widget_set_name (window, "main window");
</verb></tscreen>
<p>
And then the style is defined in the rc file using:

<tscreen><verb>
widget "main window.*GtkButton*" style "main_button"
</verb></tscreen>
<p>
Which sets all the GtkButton widgets in the "main window" to the
"main_buttons" style as defined in the rc file.
<p>
As you can see, this is a fairly powerful and flexible system.  Use your
imagination as to how best to take advantage of this.

<sect1>GTK's rc File Format
<p>
The format of the gtk file is illustrated in the example below.  This is
the testgtkrc file from the gtk distribution, but I've added a
few comments and things.  You may wish to include this explanation
your application to allow the user to fine tune his application.
<p>
There are several directives to change the attributes of a widget.
<itemize>
<item>fg - Sets the foreground color of a widget.
<item>bg - Sets the background color of a widget.
<item>bg_pixmap - Sets the background of a widget to a tiled pixmap.
<item>font - Sets the font to be used with the given widget.
</itemize>
<p>
In addition to this, there are several states a widget can be in, and you
can set different colors, pixmaps and fonts for each state.  These states are:
<itemize>
<item>NORMAL - The normal state of a widget, without the mouse over top of
it, and not being pressed etc.
<item>PRELIGHT - When the mouse is over top of the widget, colors defined
using this state will be in effect.
<item>ACTIVE - When the widget is pressed or clicked it will be active, and
the attributes assigned by this tag will be in effect.
<item>INSENSITIVE - When a widget is set insensitive, and cannot be
activated, it will take these attributes.
<item>SELECTED - When an object is selected, it takes these attributes.
</itemize>
<p>
When using the "fg" and "bg" keywords to set the colors of widgets, the
format is:
<tscreen><verb>
  fg[<STATE>] = { Red, Green, Blue }
</verb></tscreen>
<p>
Where STATE is one of the above states (PRELIGHT, ACTIVE etc), and the Red,
Green and Blue are values in the range of 0 - 1.0,  { 1.0, 1.0, 1.0 } being
white.
They must be in float form, or they will register as 0, so a straight 
"1" will not work, it must
be "1.0".  A straight "0" is fine because it doesn't matter if it's not
recognized.  Unrecognized values are set to 0.
<p>
bg_pixmap is very similar to the above, except the colors are replaced by a
filename.  Note the broken pixmap_path requires us to give the full path to
our pixmaps, or have them in the current directory.  Someone should really fix this.
<p>
The font directive is simply:
<tscreen><verb>
font = "<font name>"
</verb></tscreen>
<p>
Where the only hard part is figuring out the font string.  Using xfontsel or
similar utility should do it.
<p>
The "widget_class" sets the style of a class of widgets.  These classes are
listed in the widget overview on the class hierarchy.
<p>
The "widget" directive implicitly sets a specific named set of widget to a
given style, overriding any style set for the given widget class.
These widgets are registered inside the application using the
gtk_widget_set_name() call.  This allows you to specify the attributes of a
widget on a per widget basis, rather than setting the attributes of an
entire widget class.  I urge you to document any of these special widgets so
users may customize them.
<p>
When the keyword "<tt>parent</>" is used as an attribute, the widget will take on
the attributes of it's parent in the application.
<p>
When defining a style, you may assign the attributes of a previously defined
style to this new one.
<tscreen><verb>
style "main_button" = "button"
{
  font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
  bg[PRELIGHT] = { 0.75, 0, 0 }
}
</verb></tscreen>
<p>
This example takes the "button" style, and creates a new "main_button" style
simply by changing the font and prelight background color of the "button"
style.
<p>
Of course, many of these attributes don't apply to all widgets.  It's a
simple matter of common sense really.  Anything that could apply, should.

<tscreen><verb>
# pixmap_path "<dir 1>:<dir 2>:<dir 3>:..." (doesn't work yet)
#
# When is someone gonna fix this ??
#
# style <name> [= <name>]
# {
#   <option>
# }
#
# widget <widget_set> style <style_name>
# widget_class <widget_class_set> style <style_name>


# Here is a list of all the possible states.  Note that some do not apply to
# certain widgets.
#
# NORMAL - The normal state of a widget, without the mouse over top of
# it, and not being pressed etc.
#
# PRELIGHT - When the mouse is over top of the widget, colors defined
# using this state will be in effect.
#
# ACTIVE - When the widget is pressed or clicked it will be active, and
# the attributes assigned by this tag will be in effect.
#
# INSENSITIVE - When a widget is set insensitive, and cannot be
# activated, it will take these attributes.
#
# SELECTED - When an object is selected, it takes these attributes.
#
# Given these states, we can set the attributes of the widgets in each of
# these states using the following directives.
#
# fg - Sets the foreground color of a widget.
# fg - Sets the background color of a widget.
# bg_pixmap - Sets the background of a widget to a tiled pixmap.
# font - Sets the font to be used with the given widget.
#


# This sets a style called "button".  The name is not really important, as
# it is assigned to the actual widgets at the bottom of the file.

style "window"
{
  #This sets the padding around the window to the pixmap specified.
  #bg_pixmap[<STATE>] = "<pixmap filename>"
  bg_pixmap[NORMAL] = "warning.xpm"
}

style "scale"
{
  #Sets the foreground color (font color) to red when in the "NORMAL"
  #state.
  
  fg[NORMAL] = { 1.0, 0, 0 }
  
  #Sets the background pixmap of this widget to that of it's parent.
  bg_pixmap[NORMAL] = "<parent>"
}

style "button"
{
  #This shows all the possible states for a button.  The only one that
  #doesn't apply is the SELECTED state.
  
  fg[PRELIGHT] = { 0, 1.0, 1.0 }
  bg[PRELIGHT] = { 0, 0, 1.0 }
  bg[ACTIVE] = { 1.0, 0, 0 }
  fg[ACTIVE] = { 0, 1.0, 0 }
  bg[NORMAL] = { 1.0, 1.0, 0 }
  fg[NORMAL] = { .99, 0, .99 }
  bg[INSENSITIVE] = { 1.0, 1.0, 1.0 }
  fg[INSENSITIVE] = { 1.0, 0, 1.0 }
}

# In this example, we inheret the attributes of the "button" style and then
# override the font and background color when prelit to create a new
# "main_button" style.

style "main_button" = "button"
{
  font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
  bg[PRELIGHT] = { 0.75, 0, 0 }
}

style "toggle_button" = "button"
{
  fg[NORMAL] = { 1.0, 0, 0 }
  fg[ACTIVE] = { 1.0, 0, 0 }
  # This sets the background pixmap of the toggle_button to that of it's
  # parent widget (as defined in the application).
  bg_pixmap[NORMAL] = "<parent>"
}

style "text"
{
  bg_pixmap[NORMAL] = "marble.xpm"
  fg[NORMAL] = { 1.0, 1.0, 1.0 }
}

style "ruler"
{
  font = "-adobe-helvetica-medium-r-normal--*-80-*-*-*-*-*-*"
}

# pixmap_path "~/.pixmaps"

# These set the widget types to use the styles defined above.
# The widget types are listed in the class hierarchy, but could probably be
# just listed in this document for the users reference.

widget_class "GtkWindow" style "window"
widget_class "GtkDialog" style "window"
widget_class "GtkFileSelection" style "window"
widget_class "*Gtk*Scale" style "scale"
widget_class "*GtkCheckButton*" style "toggle_button"
widget_class "*GtkRadioButton*" style "toggle_button"
widget_class "*GtkButton*" style "button"
widget_class "*Ruler" style "ruler"
widget_class "*GtkText" style "text"

# This is a specific set of buttons defined in the application.  These must
# be documented to be taken advantage of.
widget "main window.*GtkButton*" style "main_button"
</verb></tscreen>

If someone could expand further on this... I'd like to see examples of gtkrc
files too.  This is something that still mystifies me.

<sect>Writing Your Own Widgets
<p>
It's in the works.
<sect>Creating GTK Applications
<p>
This section is simply a gathering of general style guidelines and hints to
creating good gtk applications. It is totaly useless right now cause it's
only a topic sentance :)

<sect>Contributing

<p>
This document, like so much other great software out there, was created for
free by volenteers.  If you are at all knowledgable about any aspect of gtk
that does not already have documentation, please consider contributing to
this document.
<p>
If you do decide to contribute, please mail your text to me, Ian Main, 
<tt><htmlurl url="mailto:slow@intergate.bc.ca"
name="slow@intergate.bc.ca"></tt>. Also, be aware that the entirity of this 
document is free, and any addition by yourself must also be free.  That is, 
people may use any portion of your examples in their programs, and copies 
of this document may be distributed at will etc.
<p>
Thank you.


<sect>Credits
<p>
I would like to thank the following for their contributions to this text.

<itemize>
<item>Bawer Dagdeviren, <tt><htmlurl url="mailto:chamele0n@geocities.com"
			      name="chamele0n@geocities.com"></tt>
for the menus tutorial.			      

<item>Raph Levien, <tt><htmlurl url="mailto:raph@acm.org"
			 name="raph@acm.org"></tt>
for hello world ala gtk, and the widget packing.

<item>Peter Mattis, <tt><htmlurl url="mailto:petm@xcf.berkeley.edu"
                          name="petm@xcf.berkeley.edu"></tt>
for the simplest gtk program.

<item>Werner Koch <tt><htmlurl url="mailto:werner.koch@guug.de"
name="werner.koch@guug.de"></tt> for converting the original plain text to
SGML, and the widget class hierarchy.

</itemize>
<p>
And to all of you who commented and helped refine this document.
<p>
Thanks.

</article>




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]