dcsimg

Gettin’ GUI with GTK+

If you're interested in writing portable GUI-based applications for Linux, the "GIMP Toolkit," or GTK+, can provide you with a strong foundation to build on.

GTK opener

If you’re interested in writing portable GUI-based applications for Linux, the “GIMP Toolkit,” or GTK+, can provide you with a strong foundation to build on. Unlike the administrative and low-level world of the Linux kernel and its related daemons, applications are user-level tools that, in today’s modern GUI-centric world, are event-driven and graphically-based. Perhaps you’ve considered moving to Linux — or have already done so –and want to know if you can easily produce easy-to-use applications. Or maybe you want to know how hard it will be to port your existing GUI (Graphical User Interface) programs from another platform to Linux. While no one can answer those questions absolutely, this article aims to show you how GTK+ might fill your needs.

What is GTK+?

GTK+ is an acronym for “GIMP Toolkit.” It was originally designed as a library of user interface components (otherwise known as an API — Application Programming Interface) for use specifically in creating the GIMP’s user interface. For those who don’t know, the GIMP is a Unix and Linux-based alternative to Adobe’s Photoshop and is one of the centerpieces of the Linux desktop world. GTK+’s design is portable and extensible; not long after its introduction, it became a major influence on the look and feel of the Linux desktop. In fact, GTK+ provides the underlying libraries upon which the GNOME desktop environment is built.








GTK+/Figure1
Figure One: GTK, GDK, and GLib in the X protocol stack.

While GTK (without the “+” suffix) is the API most developers work with on a regular basis, GTK+ (with the “+” suffix) is actually a collection of related APIs: GLib, GDK, and GTK. GLib is a set of useful functions for handling issues like hash tables, memory management, and string management in a manner that eliminates platform-specific function calls. For example, using secure string formatting (to prevent buffer overflows) normally requires different function calls depending on which operating system you are using. By using a single GLib call for the same feature, developers can leave platform specifics to the GLib maintainers.

GDK is the platform-specific library that handles low-level window features. This means it is GDK that directly interfaces with the X Window System, Windows95, or BeOS. While it is possible to make calls directly to GDK functions from your application, you normally don’t want to do that, since doing so could potentially tie your application too closely to a given platform. GDK is dependent on GLib; GTK is dependent on both GDK and GLib. You can use GLib without having to create a graphical interface, but you can’t create a windowing interface with GTK without having GLib available.

GDK has to be ported to each platform that a GTK+ application is to run on, but GTK+ application programmers don’t really care about that. As long as you use the GTK (and possibly GLib) API, you will improve portability at the user interface level — most certainly to Unix platforms and probably to Microsoft, BeOS, and other platforms. Doing this does not necessarily guarantee portability, since you may still have other non-GUI, OS-specific function calls in your application, but using GTK+ and friends will take care of user interface porting issues.

Another thing to note about the GTK+ libraries is that while they are the building blocks of many GUI-based applications, they are also the building blocks of desktop environments (like GNOME) and some window managers. A desktop environment is a set of tools and programs that handle what users think of as “desktop functionality.” This includes everything from allowing drag-and-drop between multiple applications to managing your sessions between uses to allowing applications to embed data from other applications. A window manager is often confused with a desktop environment, but it’s actually just a special purpose application that handles the positioning of windows and a few other items.

GNOME and KDE are the best-known desktop environments for Linux, and each can have one of many different window managers running under them. GTK+ based applications work with both the window manager and desktop environment. The only other piece of the puzzle is the X server, which to end-users is nothing more than the driver for your video card. GTK+ libraries are not directly used by the X server.

Now that we’ve covered all this background, let’s start our exploration of programming with GTK+ by looking at some of the basic features and functionality it provides, beginning with language bindings and widgets.

Language Bindings








GTK+/Figure2
Figure Two: The relationship between GTK+ applications, window managers, and a desktop environment.

Language bindings provide programmers with a way to use a single library or API from multiple programming languages. GTK, Glib, and GDK are all written using the C language and by default all provide a C binding. But GTK+ goes far beyond this with language bindings for C++ and many scripting languages, including Perl and Python. This means that a Perl script, for example, can provide a graphical interface that has the same look and feel as more sophisticated C-based applications. The result is a more unified appearance to the desktop, and that ultimately is what makes end-users happy.

Widgets

If you are unfamiliar with creating graphical applications, you should first know that the buttons, sliders, text fields, and other features (both visible and hidden) found in GUI programs are known as “widgets.” A button widget, for example, is a programming object that includes data and, in many cases, code for handling that data. The reason you need to associate code with data in these widgets is so that proper layout and signal handling (also known as “events” — the terms are used fairly interchangeably in GTK+ parlance) are provided. Layout issues relate to where visible features are displayed in relation to one another — a text label inside a button, for example.

Signal handling is of prime importance to widgets. GUI applications are event-driven, meaning that they usually just sit idle until the user (or some external influence) requests that they to do something. Those requests are known as “events” and can take many forms, from mouse button presses and mouse movements to keystrokes to interrupts from networking code.

Types of Widgets








GTK+/Calander
Figure Four: The calendar widget gives you complete access to any day of just about any year.

Widgets come in many forms, not all of which are visible to the end-user. However, they can be generalized so that they fit into one of several categories. These include layout, event handlers, single use, and combination widgets. The simplest widgets are single-use widgets. These include buttons, scroll bars, labels, and menus. Combination widgets are widgets that provide a set of single- use widgets in a convenient packaged form. The “file selection” and “calendar” widgets are examples of these. Layout widgets are invisible widgets, which allow single-use and combination widgets to be put in meaningful places in relation to one another. The most popular layout widget is probably the “table widget,” which allows you to place other widgets in a grid, specifying the way the empty space between cells in the table is displayed.

Some widgets provide features that are not visible to users. Often these widgets are designed to provide extra features that other widgets do not have. For example, label widgets provide the ability to display simple text labels. However, label widgets don’t normally respond to events. In order to have a label respond to a mouse click, you have to place the label widget inside an event widget. An event widget is an invisible widget that adds signal handling to other widgets. There are other examples of this sort of behavior, but we won’t be getting that complex with our examples. We’ve classified these widgets as event handlers. Signals are the events that cause the code associated with a given widget to be run. Event handlers are the core of complex programs but are not needed in the most simplistic applications, so we’ll only touch on their use.

Note: Hardcore GTK+ programmers will argue with the classifications used here, but the point is to be introductory, not exact. The amount of detail that we could get into here is overwhelming; we’re out to motivate developers, not scare them away.

Say Hello

Enough of the introduction — let’s do some work! We’ll start with the basic “Hello, World!” program to show the core parts of any GTK+ application. First, take a look at the code for this program, as shown in Listing One.




Listing One: A Simple “Hello, World!” Program


  #include <gtk/gtk.h>

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

/* GTK initialization – required of every GTK program */
gtk_init(&argc, &argv);

/* This establishes the top-level window, the parent of all other windows */
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

/* Create a label */
label = gtk_label_new(“Hello, World!”);

/* Place it inside the parent (top level) window */
gtk_container_add (GTK_CONTAINER (window), label);

/* And display all the windows */
gtk_widget_show(label);
gtk_widget_show(window);

/* This is a main loop that all simple GTK applications go into. */
gtk_main();

return(0);
)








GTK+/Hello World
Figure Three: The tiny window created from the “Hello, World!” program.

There are few parts to this simple program. The first is the call to gtk_init() that handles the initialization of default colors and fonts. It will also parse a few command-line parameters such as -display and -sync, but you seldom need to use these. Note that GTK does not provide a mechanism for parsing command-line options like Motif does; you need to use the getopt() and getopt_long() functions to be able to parse the command line manually. Both functions are standard on Linux systems, but getopt_long() may not be available on other Unix (or non-Unix) platforms. In that case, you may need to grab the GNU source for getopt_long() and add it to your program or write your own command-line parsing function.

After initialization, the program creates its top-level window. This window is required; it is the parent inside which all other widgets will be placed. Creating the top-level window is done with the function gtk_window_new(). There are multiple types of windows that this function can create, but in this case we simply use the GTK_WINDOW_ TOPLEVEL value to specify a top-level window.

Next, we want to create a simple label. This is a widget that does nothing but display a text string. While some support for different national languages are built into the current GTK+ 1.2, the upcoming GTK+ 2.0 (due out sometime this year) will have much greater support for languages that have special characters and/or read right to left.

In this simple example, we created a label using ordinary text (well, ordinary for US English-speaking programmers at least) and the gtk_ label_new() function. Note that both the top-level window and the label are saved in variables that are pointers to GtkWidget structures. There are a few other types of GTK structures, such as GtkStyle and GdkBitmap, but this example is too simplistic for those just now.

After we’ve created the label, we need to place it inside the top-level widget using the gtk_container_add() function. The top-level window acts as a container in which we can place other widgets. Again, this is the most simplistic case, so special layout considerations inside the top-level widget are not really necessary. In another example in this article, we’ll look a bit more closely at handling layout issues.

The only things left to do in this example are to display the windows we’ve created using gtk_widget_show() and then enter the main loop for GTK. The main loop is a very fast loop that checks for new signals. Signals can come from many places and can be associated with different windows. In this example, the label and top-level widget have not specified what to do if a signal is encountered for them, so all signals are simply ignored.

To compile this program, we use the command line:


gcc ‘gtk-config –cflags’ ‘gtk-config –libs’ hello.c -o hello

This requires that the gtk-config script be in your path. This script knows how to figure out where the relevant include files and libraries are to build GTK+ applications.

When you run the program a single window is displayed with the words “Hello, World!”, as shown in Figure Three. To exit the program you have to kill the program manually, normally using the Ctrl-C key sequence from the terminal window from which you started the application. It doesn’t take much more to add the ability to exit the program using a menu or button. However, GTK+ programs are so simple to work on, we’re going to jump right ahead to a useful little program — a calendar tool with a “To Do” list.

The Calendar Tool Example

In our next example, we want to build a small program to show a calendar from which we can select different days. When a day is selected, the complete date is placed in a label above the calendar. Below the calendar we need a quit button to give us a means of exiting the program gracefully.

With other widgets sets (such as Motif), building a calendar can be very complex; you need to write code for handling changing from day to day or month to month, as well as building a layout mechanism for each calendar day of each month or year. With GTK+ this process is simplified; a complete calendar widget already exists. You simply add it to your window and use it’s built-in API for handling signals. Watch and see how simple it really is.

Let’s start with a single window and the calendar widget. We’ll add the label and button later. The code for our simple calendar program looks just like our first example, except we use the calendar widget where we used the label widget previously, as illustrated in Listing Two .




Listing Two: Replace the Original Label Widget With the Calendar Widget


  #include <gtk/gtk.h>

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

/* GTK initialization – required of every GTK program */
gtk_init(&argc, &argv);

/* This establishes the top-level window, the parent of all other windows */
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

/* The Calendar widget does most of the hard work for us */
cal = gtk_calendar_new();

/* Place it inside the parent (top level) window */
gtk_container_add (GTK_CONTAINER (window), cal);

/* And display all the windows */
gtk_widget_show(cal);
gtk_widget_show(window);

/* This is a main loop that all simple GTK applications go into. */
gtk_main();

return(0);

}

The result of changing that one line (and renaming the variable associated with it) is dramatic. The calendar widget is a much more sophisticated widget than a simple label widget. By providing the navigation bar atop the month display, it shows what a combination widget would look like. Clicking on different days selects that day. You can even bounce from month to month and year to year!

But the calendar program as it stands now is not very useful. You can view a calendar but you can’t really do anything with it yet. The first thing we need to do is provide some feedback when a new day is selected. The way to do this is by writing signal handlers, which in GUI program parlance are known as callbacks.

Adding Callbacks

To add a callback to a program, you need to do two things. The first is to write a small subroutine that does the work you need done when a particular signal (remember that the two terms are synonymous) is encountered. For example, when a new day is selected, we could have some text written to the console stating what day was chosen. See the example in Listing Three. The other thing you need to do is attach the callback routine to the event of interest in relation to a specific widget.




Listing Three: The Callback Routine to Print the Date Selected


  void
print_date(
GtkWidget *src,
gpointer user_data
)
{
int month, day, year;

gtk_calendar_get_date(GTK_CALENDAR(src), &year, &month, &day);
printf(“Date chosen: %02d/%02d/%d\n”, month+1, day, year);

}

As complex as that sounds, it only requires a single line of code to get it done, as illustrated in Listing Four.




Listing Four: A Single Call to gtk_signal Connect
Is Added After Creating the Calendar Widget


  /* The Calendar widget does most of the hard work for us */ cal = gtk_calendar_new();

/* Add the callback when a new date is chose */
gtk_signal_connect (GTK_OBJECT (cal), “day_selected”,
GTK_SIGNAL_FUNC (print_date), (gpointer)0);

/* Place it inside the parent (top level) window */
gtk_container_add (GTK_CONTAINER (window), cal);

In Listing Four you can see that the function gtk_signal_ connect() is called in order to associate the new callback routine, print_date(), with the calendar widget. The arguments to gtk_signal_connect() are:


  1. The calendar widget, cast to a type of GTK_OBJECT
  2. The event of interest, which in this case is called the day_selected event
  3. The callback function that we’ve called print_date()
  4. A bit of event specific data, which in this case we’ve set to 0 (or NULL) because we won’t be using it in any of our examples

Note that the calendar widget, cal, is being cast to a different variable type, GtkObject. However, in GTK+ such casting is done using macros instead of a type definition. In order to cast a variable of type GtkWidget to a type of GtkObject, we’ve used the GTK_OBJECT macro. This use of macros for casting types is an easy place to get confused when you first learn about GTK, but once you’ve done it for a short time, it will become second nature.

Event types are one of the hardest items in GTK to get a grasp of; there are few simple references for these. Because event types vary from widget to widget — the calendar widget’s day_selected event, for example, has no meaning to an ordinary button widget — you need to know the types of events relevant to the widget you’re working on. Some event types span nearly all widgets: key_press for when a keyboard key is pressed, enter_notify for when the mouse has entered the region of the display where the widget lives, and expose_event for when a widget becomes visible (no longer obscured on the display by another window). While many of the events available to widgets are listed in the useful online documentation (see http://www.gtk.org for more details), there may still be times when you need to dig into a widget’s class_init() routine to find all its relevant events. And if you find that a widget doesn’t accept a particular event, you can often place it inside the special “eventbox” widget, which will allow you to check for events on the original widget even though it normally doesn’t support handling those events. The most common use of the eventbox widget is to add event handling to the otherwise eventless label widget.

After you recompile the program and run it again, each time you select a new day (or month or year), the new date will get printed. This happens because the callback routine, print_ date(), uses one of the calendar widget’s API routines, gtk_ calendar_get_date(), to retrieve the currently selected date from the widget. The first argument to this function is a GtkWidget cast to a type of GtkCalendar (again, using a macro, GTK_ CALENDAR). The callback routine’s parameters include the calendar widget for which we set up the callback (using the gtk_signal_connect() function) and the user data (which we’re ignoring in our examples).




What’s Included With GTK+ 2.0

GLibThe portability library for common programming issues
GObjectA portable, low-level object-oriented facility for GTK
PangoThe international language support library
GdkPixbufAn image-handling library designed to replace Imlib that is used by many GTK programs even though it’s not actually part of GTK 1.2 itself
GDKPlatform-specific window interface
GTKPlatform-independent windowing API
The libraries are listed here in ascending dependency as well. That is, GLib is not dependent on anything, but Pango is dependent on both GObject and GLib. It is possible to write programs that make use of Pango but are not GTK+ based applications, which extends the GTK library set to more than just the graphical interface.

Layout Issues: Adding the Date Label and Quit Button

While the program as it stands now is functional, we really need to add a few more pieces to the puzzle. First, we want to add a “Quit” button to allow us to exit gracefully (killing the program with Ctrl-C works, but could cause problems for more complex programs). Next, we want a label across the top of the calendar that shows the currently selected date.

We’ve made a number of changes to our existing code to get these features added. Again, we’ll look at the code first (see Listing Five).




Listing Five: The Label and Quit Buttons Are Added Above and Below the Calendar, Respectively


  #include <gtk/gtk.h>

GtkWidget *label;

void
quit_function(
)
{
exit();
}

void
print_date(
GtkWidget *src,
gpointer user_data
)
{
char buf[256];
int month, day, year;

gtk_calendar_get_date(GTK_CALENDAR(src), &year, &month, &day);
sprintf(buf, “Date chosen: %02d/%02d/%d”, month+1, day, year);
gtk_label_set_text(GTK_LABEL(label), buf);
}

int
main(
int argc,
char **argv
)
{
GtkWidget *window;
GtkWidget *vbox;
GtkWidget *cal;
GtkWidget *quit;

/* GTK initialization – required of every GTK program */
gtk_init(&argc, &argv);

/* This establishes the top-level window, the parent of all other windows */
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

/* Add a VBox, to handle vertical layout, inside the top-level window. */
vbox = gtk_vbox_new(FALSE,0);
gtk_container_add (GTK_CONTAINER (window), vbox);

/* A label gets added to the Vbox first. */
label = gtk_label_new(“Date Chosen: None.”);
gtk_container_add (GTK_CONTAINER (vbox), label);

/* The Calendar widget does most of the hard work for us */
cal = gtk_calendar_new();

/* Add the callback when a new date is chosen */
gtk_signal_connect (GTK_OBJECT (cal), “day_selected”,
GTK_SIGNAL_FUNC (print_date), (gpointer)0);

/* Place it after the label and inside our vertical layout box */
gtk_container_add (GTK_CONTAINER (vbox), cal);

/* A Quit button, to exit gracefully */
quit = gtk_button_new_with_label(“Quit”);
gtk_container_add (GTK_CONTAINER (vbox), quit);

/* Add the callback for the Quit button */
gtk_signal_connect (GTK_OBJECT (quit), “clicked”,
GTK_SIGNAL_FUNC (quit_function), (gpointer)0);

/* And display all the windows */
gtk_widget_show(quit);
gtk_widget_show(cal);
gtk_widget_show(label);
gtk_widget_show(vbox);
gtk_widget_show(window);

/* This is a main loop that all simple GTK applications go into. */
gtk_main();

return(0);

}

Looking first in the main() routine, we find a new layout widget being used — the GtkVBox. This widget provides simple vertical alignment for all the widgets placed inside of it. It has a counterpart called the GtkHBox, which handles aligning widgets side by side horizontally. We placed a label, the calendar widget, and a button inside the GtkVBox, in that order, using the gtk_container_add() function. This function will simply append widgets in order, which is what we want in this case. There are also functions for pre-pending widgets to the existing order inside both GtkVBox and GtkHBox widgets, as well as more complex layout features using the GtkTable widget.

We changed the callback for the print_date() function so that the new label gets updated with the selected date instead of printing it out to the console. To do this we had to make the label widget’s variable global in scope. There are other ways to make the label widget’s variable available to the callback routine, but this is the simplest method. You’ll find GUI programmers who will argue over the validity of using global variables in their programs, but for our purposes, they work just fine.








GTK+/Maroon Calander
Figure Five: The updated display, with label and quit button.

Another thing we changed in the print_ date() routine — we removed the trailing newline for the text we print in the label. When we created the label, we added some default text without the newline. That’s what you see in Figure Five .

The new Quit button has a couple of interesting characteristics. The first is that we added a label to the button automatically using gtk_button_new_with_label(). If you need to create a button without a label, you can use the more generic gtk_button_new() function instead (are you beginning to notice a consistent naming scheme for the functions that create widgets?).

The other item to note is the event type — the “clicked” type for setting up the callback for the button. (This event type is commonly used with buttons.) Of course, there is a new callback for this button too — one that simply exits the program.

To Do Entries Using Text Entry and a CList Widget

Now we’re ready to add a simple To Do list to our calendar. To add this feature, we need to include a place to enter the To Do text and a place to display the list of To Do items. The first of these requires a GtkEntry widget — a simple text entry field where we can type pretty much whatever we want. The other item is more complex and requires the GtkCList widget, a combination widget that provides multiple columns and rows for display.

The first thing we need to do is change the way the current program handles its layout. The existing program has all the widgets lined up vertically. This layout simply won’t do if we add a long list of To Do entries, so we’ll want that list to the right of the existing widgets. This is easily accomplished by adding a GtkHBox for horizontal alignment as the first child window to the top-level window. We’ll then stuff the existing GtkVBox (which currently holds everything else) inside the GtkHBox and add a GtkCList after the GtkVBox. This effectively places the GtkCList (which is often referred to as a CList widget) side by side with all the other widgets.

The GtkCList is a special widget for handling multi-column, multi-row data. In our example we want to display a date followed by the text explaining what the To Do item is. Setting up the CList requires three lines of code (as seen in Listing Six) for this example. The first line, the call to gtk_clist_new_with_ titles(), creates the CList and adds two titles, one for each column. The titles are taken from a static array of text strings to make life easier.




Listing Six: A New GtkHBox Goes Ahead of the Old GtkVBox,
the GtkCList Goes in After the GtkVBox


  static char *titles[] = {
“Date”,
“To Do item for that day.”
};

GtkWidget *hbox;
GtkWidget *list;

/* GTK initialization – required of every GTK program */
gtk_init(&argc, &argv);

/* This establishes the top-level window, the parent of all other windows */
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

/* Add a HBox, to handle horizontal layout, inside the top-level window. */
hbox = gtk_hbox_new(FALSE,0);
gtk_container_add (GTK_CONTAINER (window), hbox);

/* Add a VBox, to handle vertical layout, inside the hbox. */
vbox = gtk_vbox_new(FALSE,0);
gtk_container_add (GTK_CONTAINER (hbox), vbox);

/* A List for each days To Do */
list = gtk_clist_new_with_titles(2, titles);
gtk_container_add (GTK_CONTAINER (hbox), list);
gtk_clist_set_column_width(GTK_CLIST(list), 0, 140);
gtk_clist_set_column_width(GTK_CLIST(list), 1, 240);

After creating the list, the widget is added to the GtkHBox. The next two calls to gtk_clist_ set_column_width() set the initial width of the two columns in the widget. The size specified is in pixels. Note once again the casting of the CList widget to a GtkCList using the GTK_CLIST macro. Listing Seven illustrates the addition of GtkEntry widget. The biggest change we will have with this version of our code shows up in the print_date() callback routine, which is shown in Listing Eight.




Listing Seven: The GtkEntry Widget Is About As Simple As They Come


     /* The Calendar widget does most of the hard work for us */
cal = gtk_calendar_new();

/* Add the callback when a new date is chose */
gtk_signal_connect (GTK_OBJECT (cal), “day_selected”,
GTK_SIGNAL_FUNC (print_date), (gpointer)0);

/* Place it after the label and inside our vertical layout box */
gtk_container_add (GTK_CONTAINER (vbox), cal);

/* A text entry field for adding a note to each date */
entry = gtk_entry_new();
gtk_container_add (GTK_CONTAINER (vbox), entry);

/* A Quit button, to exit gracefully */
quit = gtk_button_new_with_label(“Quit”);
gtk_container_add (GTK_CONTAINER (vbox), quit);




Listing Eight: The print_date() Callback Changes Significantly to Handle Our New cList Widget


  void
print_date(
GtkWidget *src,
gpointer user_data
)
{
char buf[256];
int month, day, year;
char row_data[2][512];
char *rows[2];
char *todo_text;
int row;

/* Get the date from the calendar */
gtk_calendar_get_date(GTK_CALENDAR(src), &year, &month, &day);
sprintf(buf, “%02d/%02d/%d”, month+1, day, year);

/* Get the todo entry */
todo_text = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, -1);

/* Place the date into the Todo date along with the Todo entry */
sprintf((char *)row_data[0], buf);
sprintf((char *)row_data[1], todo_text);
rows[0] = row_data[0];
rows[1] = row_data[1];
row = gtk_clist_prepend(GTK_CLIST(list), rows);

/* Update the date label above the calendar */
gtk_label_set_text(GTK_LABEL(label), buf);

/* Cleanup */
g_free(todo_text);
}

As before, we start this routine by retrieving the currently selected date and saving a formatted version of it. Next we retrieve, using the gtk_editable_get_chars() function, the text in the GtkEntry field we added between the calendar and Quit button. The text is returned into a newly allocated block of storage, so we have to be sure to free it up later using the GLib function g_free().

After that, things get a little more involved. We need to fill an array of character buffers with the data for each column of each row. There are multiple ways of doing this, but we’re using code based on examples from other GTK+ programs. We stuff the data into the first element of the row_ data[] array and the To Do text into the second element. We then push those entries into another array to make them easier to pass to the gtk_clist_ prepend() function. This function will insert the new row into the CList at the top of the list. The function returns the number of the row added, but we don’t really need that in this example. We finish by updating the label widget once again.

Notice that we also removed some text from the date string. Since the CList uses column headings, that old text (Date Chosen:) is no longer needed. For a complete listing of all the code for our project, see http://www.linux-mag.com/downloads/gtkcode.txt.

Issues and Features








GTK+/Scheduler
Figure Six: The final version of the Calendar/To Do program.

There are some problems with this program as it stands. First of all, if you enter too many To Dos, the GtkCList grows automatically, but the Quit button grows unexpectedly. You can fix this problem by using a GtkTable instead of a GtkVBox for the right side of the window where the button, entry, calendar, and label are all displayed. Alternatively, you can place the GtkCList inside a GtkScrolledWindow, which will allow the windows to maintain their initial size while provide a scrolled list of To Do entries.

Another limitation is that the GtkEntry field is not cleared after each new date is selected. You can handle this with the gtk_entry_set_ text() function and set the text to an empty string (not a NULL string, but a string with no characters in it).

The Future of GTK+

As with most software, GTK+ is evolving. The next release is expected to be GTK+ 2.0 and is due out later this year, though no date has yet been mentioned. GTK+ 2.0 will be a major enhancement to the current release. Instead of just GTK, GDK, and GLib, the new version of GTK+ will have six libraries (see What’s Included With GTK+2.0, pg. 62).

While GTK+ is the basis for all GNOME applications and works well on many platforms, it is not the only solution; Qt, Motif, Tk, and a host of other windowing interfaces exist for Linux. Since GTK+ is the basis for GNOME, building a coherent desktop suite with it is easier to accomplish.



Michael J. Hammel is the author of Artists’ Guide to the GIMP. He can be reached at mjhammel@graphics-muse.org.

Fatal error: Call to undefined function aa_author_bios() in /opt/apache/dms/b2b/linux-mag.com/site/www/htdocs/wp-content/themes/linuxmag/single.php on line 62