GTK tutorial (a start)




I've started a simple gtk tutorial which I've included below.  It's kinda
messy and may be inaccurate in some places.  Please feel free to add,
comment or help in any way you see fit.  It's only plain text for now, I
will move it to other formats when it get's better. 

If no one objects, I will post updates to the list once in a while when
significant changes are made in the hopes that mistakes can be corrected,
and you can add to the document :)  Even the smallest changes are welcome. 

Thanks,

Ian



INTRODUCTION:

GTK (General Toolkit) was originally developed as a toolkit for the GIMP
(General Image Manipulation Program).  GTK is built on top of GDK (General
Drawing Kit)  which is basically wrapper around the Xlib functions.  This
was all written by S & Peter Mattis.  GTK is built on top of GDK and you
will often see the GDK calls in GTK programs. 

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

This tutorial is a compilation of other documentation found on gtk, as well
as some I've added.  It is by no means complete.  This tutorial also assumes
a good understanding of C, and how to create C programs.


GETTING STARTED

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 (Hope this is ok :) ..
may change ?). 

OK, now that you have it installed, we will start with a simple hello world
program that Raph wrote with comments added:

     /* all programs will of course include the gtk/gtk.h which declares the
      * variables and functions used in your gtk application. */
     #include <gtk/gtk.h>

     /* this is a callback function.. more on this down below. */
     void hello (void)
     {
        g_print ("Hello World\n");
     }
     
     
     void destroy (void)
     {
       gtk_main_quit ();
     }

     int main (int argc, char *argv[])
     {
       /* GtkWidget is the storage type for all types of 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 (&argc, &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 NULL passed to this function
        * is used to pass optional data into this "callback" function. */
       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 recieves 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 keypress or mouse event). */
       gtk_main ();

       return 0;
     }


To compile use:

gcc -Wall -g -lgtk -lgdk -lglib -lX11 -lXext -lm hello_world.c -o hello_world

The libraries above must all be in your default search paths, if not, add
-L<library directory> and gcc will look in these directories for the needed
libraries.  For instance, on my Debian Linux box, I have to add
-L/usr/X11R6/lib for it to find the X11 libraries.

Now the explanation:

As you can see from this example, it is quite easy to build a simple gtk
application.  GTK is an event driven API which means it will sleep in
gtk_main until an event occurs and control is passed to the appropriate
function.  By passing in a pointer to the function to be called when the
appropriate event occurs (by connecting a "signal") we tell the
application what we want to have done with when a given event occurs.

The general steps to creating a widget in gtk are:

1) gtk_*_new - one of various functions to create a new widget.

2) connect all signals we wish to use to the appropriate handlers.

3) set the attributes of the widget.

4) pack the widget into a container using gtk_container_add() or
gtk_box_pack_start() (are there others ?).

5) gtk_widget_show()



When setting up a signal handler (better term ?) we use a call to
gtk_signal_connect().  The decleration of this function is:

gint gtk_signal_connect (GtkObject *object, gchar *name,
                         GtkSignalFunc func, gpointer func_data);

There are a few things you'll notice right away from this example.  The
gint, gchar etc. are typedefs to int and char respectively.  This is done
for portabilities sake.  A good example is "gint32" which will be
typedef'd to a 32 bit integer for any platform, whether it be the 64 bit
alpha (int (or short int?)), or the 32 bit intel (long int or int).  The
typedefs are very straight forward and intuitive.  They are all defined in
glib/glib.h (which gets included from gtk.h). 

The fist arguement to gtk_signal_connect is the object which will generate
the signal, usually a widget (always?).  The second of course is the
signal name, followed by the function you wish to be called, and then a
pointer to the data you wish to pass to this called function. 

The callback function you specify should be of the form:

void callback_func(gpointer *callback_data);

So, if we wanted to pass the above function some data when a button is
pressed, we use:

gtk_signal_connect (GTK_OBJECT (button), "clicked",
                    GTK_SIGNAL_FUNC (callback_func), (gpointer) callback_data);

This assumes of course that you have already created a button.


gtk_init(gint *argc, gchar ***argv) is always called in any gtk
application.  This in turn will setup a few things such as the default
visual and colormap and 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 things like --display, --debug-level,
--no-xshm etc.  It then removes these from the arguement list, and leaves
anything it does not recognize for your application to parse. This creates
a set of standard arguments excepted by all gtk applications. 

gtk_main() is another call you will see in every gtk application.  When
control reaches this point, gtk will sleep waiting for X events to occur
(you may also add timeouts and file descriptor checks).  When an event
occurs, it dispatches the appropriate signal, which in turn calls the
function you've setup to handle this signal with the arguement you've
specified. 

MORE WIDGETS

The testgtk.c program distributed with gtk is an excellent place to see
and learn about all the widgets gtk supports.


(more to come later..)





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