More tutorial




Sorry for another long post, but I figured I'd put up what I've done for
now before I head to bed.  I fixed some stupid things here too and changed
around some.. ignore the last one.

(For anyone interested, I've started a #gtk irc channel on
irc.linpeople.org)

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.  The authors are

Peter Mattis    (petm@xcf.berkeley.edu)
Spencer Kimball (spencer@xcf.berkeley.edu)
Josh MacDonald  (jmacd@xcf.berkeley.edu)

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 and changed.  It is by no means complete.  This tutorial 
assumes a good understanding of C, and how to create C programs.
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.


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 we will 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 or window manager.

#include <gtk/gtk.h>

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

  gtk_init (&argc, &argv);

  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  gtk_widget_show (window);

  gtk_main ();

  return 0;
}

All programs will of course include the gtk/gtk.h which declares the
variables and functions used in your gtk application.

The next line

gtk_init (&argc, &argv);

calls the function gtk_init(gint *argc, gchar ***argv) and is always called 
in any gtk application.  
This will setup a few things for us such as the default visual and colormap.
This 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:

--display
--debug-level
--no-xshm 
--sync
--show-events
--no-show-events

It then removes these from the
arguement list, and leaves anything it does not recognize for your
application to parse or ignore. This creates a set of standard arguments
excepted by all gtk applications.

The next two lines of code create and display a window.

  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  gtk_widget_show (window);

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.

The last line enters the GTK main processing loop.

  gtk_main ();

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.
In our simple example however, no events will be registered. 


HELLO WORLD IN GTK

OK, now for a program with a widget (a button).  It's the classic hello world
ala gtk.  This is taken from the hello world that Raph wrote with comments added.  
This will make a good base for a gtk application.

     #include <gtk/gtk.h>

     /* this is a callback function. the data arg is ignored..
      * More on callbacks below. */
     void hello (gpointer *data)
     {
        g_print ("Hello World\n");
     }
     
     /* another callback */
     void destroy (void)
     {
       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 (&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 toolkit, 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.

(You may also add timeout functions and file descriptor checks (like select()) to
gtk_main().  More on this later.)

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.

MORE WIDGETS

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


(more to come later..)





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