Home About Meetings Directions Mailing Lists Jobs

Chris Lansdown gtk talk 13 June 2000

From LILUG

The original document presented at LILUG and stored on the original LILUG website was written by Christopher Lansdown and is in the public domain.

Contents

Introduction

Gtk is what is commonly known as a widget toolkit. A widget toolkit is a library which sits on top of a windowing system (such as the X window system) and provides high-level functionality. For example, on the X window system there are relatively few things that a client application can request from the X server -- a window, some text, lines, rectangles, and pixels (more or less). Gtk provides a simple way for a program to create useful things like buttons, menus, and font dialogs. (Lest it be thought a mark against X, the X window system was designed to be used nearly everywhere in an interoperable manner. X was not in a position to change rapidly and thus including things like buttons and such in X would have virtually guaranteed that they would stagnate. Just looking at the Athena Widget Set is proof enough of this. Whether this was on the minds of the designers of X I do not know, but serendipity is never to be help against someone.)

User Stuff

Using Themes

Gtk, as of version 1.2.0, has the ability to customize how its widgets appear and a user-by-user basis. This is done through the use of themes. Themes can be as simple as changing the default colors to engines which completely alter how widgets are drawn.

While there are tools for choosing what theme you want to use, describing the action of clicking on a theme name in a list and then clicking OK in the gnome control panel in the theme selector section is not very exciting. Unfortunately, the manual method is not much more exciting. When every Gtk program starts, it looks for a file called ".gtkrc" in the home directory of the user it is running as. If it finds this file, it parses it as an RC file. What this means is described below.

Using RC files

Gtk is designed to be very configurable. To this end, it supports RC files, or resource files. These files specify the fonts and colors that Gtk should use to draw its widgets. RC files can also specify an engine. An engine is a dynamically loadable module which will provide the drawing functionality for widgets instead of using the default Gtk drawing routines. More than one RC file can be parsed, each new RC files will simply overwrite the values that it specifies and leave the rest. This can be used to set a particular theme engine for all Gtk applications and then override it for a specific application which looks better with a different theme engine.

Programmer Stuff

Anatomy of a Gtk Program

A Gtk program has a few important parts to it. The first is the setup of Gtk, which is accomplished by calling the function gtk_init(&argc, &argv); This function takes care of parsing environment variables and arguments to determine the appropriate display, parses the .gtkrc theme file, and creates the X connection.

Somewhere around this (before or after doesn't really matter, though it should be done before the program does its own argument parsing) the program takes care of its own initialization, including the creating of its interface.

Finally, it calls gtk_main(); which goes into a loop select()ing on the socket to the X server and any other file descriptors that the program asks gtk to look after. When events occur on any of these file descriptors for which callbacks into the program have been defined, Gtk calls them.

This loop continues until gtk_main_quit() is called. The gtk_main() which was called originally will then return and execution will continue after that function. At this point a typical program will simply return 0 for success and terminate.

As a bit of background information, Gtk is built on top of two libraries: gdk and glib. These two libraries handle most of the operating-system dependencies so that gtk will run unmodified on any platform which has a port of gdk and glib.

Writing a Tiny Program

We will start out with the classic "Hello World!" program that all C programmers have done at one point or other:

example1.c

This illustrates most of what we talked about above. Gtk_init() is first called to set everything up. Widgets such as windows and labels are created very easily, and then control is passed to gtk_main(). We also see a rudimentary use of signals, though rather than attaching the delete_event to our own code, we simply have gtk call the gtk_main_quit() function when that signal is received (the delete_event signal is what the program gets when a user clicks on the kill application button that their window manager provides).

Another feature of Gtk is hinted at hear. A widget will not be seen by the user (or even have most resources allocated to it) until it is "shown". Show()ing a widget causes it to be first realized (if it has not already been so, realizing is the process of allocating the resources for it) and then displayed. Gtk_widget_show() is the normal function, but for convenience gtk_widget_show_all() will show the specified widget and all of its children widgets (in this case just the label).

Compiling It

Compiling this program is relatively simple. Let us suppose that the source file was called hello_world.c. We would compile it with the simple line: gcc -o hello_world hello_world.c `gtk-config --cflags` `gtk-config --libs` (Please note that those are back ticks around the gtk-config sections. Back ticks are normally located on the same key as the tilde (below the escape key) and indicate that the shell should execute the command inside of them and replace the back tick section with its output on the command line.)

In order to accommodate a variety of systems, the shell program gtk-config was created so that programmers would not have to try to figure out what libraries gtk depends on. Instead, this information is calculated when the gtk libraries are compiled and gtk-config is used to access this information. (Instructions for how to do this by autoconf are in appendix A.)

Writing a Slightly Bigger Program

We will now write a slightly bigger program which demonstrates a little more of how a Gtk program works:

example2.c

While this program does not do anything useful, it does contain many important elements of Gtk that a real program would use. Aside from those mentioned previously, we see the real use of callbacks as well as the packing of widgets.

In order to create layouts more complicated than enclosing a single widget in another, gtk provides packing widgets. It has three: a horizontal box, a vertical box, and a table. In this example we only used the horizontal box. A vertical box operates the same way except that it packs widgets from top to bottom rather than from left to right. A table does what you might expect, it contains columns and rows and allows you to attach a widget to one more more contiguous cells. Gtk uses the packing method of layout rather than fixed positions to allow for easy resizing of applications. Virtually all of the work of writing a resizeable program is handled by Gtk. For those rare instances where a program should not be able to resize, gtk allows this too.

The steps for packing widgets are fairly simple. This talk will cover only boxes for lack of time and space to do otherwise. The first step is to create the box. Next the box must be placed inside a container or packed into a packing widget. Finally widgets are packed into the box using gtk_box_pack_start() (left to right/top to bottom) or gtk_box_pack_end() (right to left/bottom to top).

The real use of callbacks has also been demonstrated in this example. We defined a callback say_hello_cb() and attached this to the "clicked" signal of each of the buttons. Of course we need not have used the same callback each time, but it was most convenient in this case. Each signal defines the type of callback that it takes, but there are some constants. The first argument is always the widget which generated the signal and the last argument is always a pointer that the user defines. This is generally used to allow a callback to be attached to more than one button and to behave differently. It is also useful to avoid the overuse of global variables. In this case we used it for the former purpose, printing out different messages depending on the button which was clicked.

Writing a Slightly Useful Program

We will now write a program that someone could conceivably want:

example3.perl

The astute reader will notice that this program was not written in C but rather in perl. This brings up the topic of bindings for languages other than C: Gtk has plenty of them. Fans of object orientation will notice that the Gtk Perl bindings are object oriented. The C++ bindings of Gtk are also object oriented, for those who prefer that sort of thing.

A Brief Explanation of Gnome

Gnome, or the Gnu Network Object Model Environment is a project that mostly deals with a different problem-space than Gtk does. Gnome has the lofty goal of creating an entire environment, more or less. This consists of applications, standards, libraries, corba services, and many other things. However, there is a gnome user interface library which adds some widgets to the standard gtk widgets. Gnome UI widgets are mostly convenience widgets, such as an about dialog box, a yes/no dialog box, and error dialog box, and so forth. Gnome also provides some replacement widgets such as menus and toolbars which allow a user to configure behavior across all gnome applications. Gnome also provides default icons for a range of normal menu items and toolbar buttons which are quite attractive. To the extent that the dependence on the myriad gnome libraries is viable, using gnome will probably make your life easier, though it would be best to start off with some small gtk-only work first to get used to it.

Glade

Many people have heard of glade, the Gtk interface builder. While it is as yet unfinished, it is still a useful program. It is out of the scope of this talk to describe glade much, but because graphical programming is inherently complex, glade will only make writing Gtk applications easier when you can do it without glade, for the most part.

Conclusion

Gtk is a powerful and useful widget toolkit with bindings for many languages. It has been the aim of this talk to encourage people who want to write graphical user interfaces to look into Gtk for doing so. Straight gtk, without the use of any direct X calls is also portable as there is a windows port of Gtk. For more information please go to the main Gtk site, www.gtk.org. It has a very useful tutorial which has taught many people how to use Gtk in useful and powerful ways.

Appendix A

Makefile.am:

 bin_PROGRAMS = hello_world
 hello_world_SOURCES = hello_world.c

configure.in:

 AC_INIT(hello_world.c)
 AM_INIT_AUTOMAKE(hello_world,1.0.0)
 AM_PATH_GTK(1.2.0)
 FLAGS="$CFLAGS $GTK_CFLAGS"
 CPPFLAGS="$CPPFLAGS $GTK_CFLAGS"
 LDFLAGS="$LDFLAGS $GTK_LIBS"
 AC_PROG_CC
 AC_PROG_INSTALL
 AC_OUTPUT(Makefile)

This would be turned into a program by the sequence: automake && aclocal &&autoconf && ./configure && make