StdGUI: Standard GUI Framework for C


Contents

Overview

Writing GUI programs in C is just too hard: you need to write lots of code just to get minimal functionality, application logic is often entangled with GUI code and the GUI code is not portable between major platforms (X Windows code is completely different from MS Windows code which is completely different from Mac OS X code). It would be nice if we could write GUI programs in C with the same ease and portability that we have for command line tools.

The standard GUI framework, StdGUI, is an attempt to build a library that makes writing GUI programs in C as easy and portable as writing command line programs in C. Currently (autumn of 2005) the library only works on X Windows, but this is simply an accident of birth: I had to select something as the platform for the first implementation and X Windows was it. The StdGUI API was designed, largely, before the target platform was selected, so it should be equally applicable (or equally inapplicable, I suppose) to other platforms as it is to X Windows.

Mostly by accident, the structure of the StdGUI API is very similar to that of GTK+ or some other X Windows GUI toolkits (and, it turns out, much to my chagrin, to the MS Windows Win32 API as well). Every application starts by calling start_gui() which sets up the GUI system and does any host-specific stuff that needs doing. Once the GUI system is initialized, the application may create windows and GUI widgets (buttons, checkboxes, text fields, scrolling lists, etc.) in order to implement a user interface. Windows, widgets and the application context itself have string properties that control their appearance and behavior. Some properties refer to callback functions, named in the application context when the start_gui() function is called or by calling the define_callback() function, that allow client program code to be called in response to system events. Once you have a window or widget you can draw into the window's or widget's graphic using drawing functions that operate on colors, fonts, geometric shapes, images and pictures (recorded sequences of drawing operations).

Example Code

While it usually takes several pages of code to write a simple GUI program in C using existing vendor APIs (such as Xlib), a simple GUI program can be written using StdGUI in about two dozen lines of code. While that is significantly longer than the traditional Hello World program in C, it is much shorter that a similar program using Xlib (or other GUI APIs).

Here, for example, is the standard Hello World program from The C Programming Language by Kernighan and Ritchie:

#include <stdio.h>

int main()
{
	printf("Hello World\n");
	return 0;
}

The output, of course, looks like this:

Hello World

Here, with comments removed for brevity, is the Hello World program from the GTK+ tutorial:

#include <gtk/gtk.h>

static void hello(GtkWidget *widget, gpointer data)
{
	g_print("Hello World\n");
}

static gboolean delete_event(GtkWidget *widget, GdkEvent *event,
	gpointer data)
{
	g_print("delete event occurred\n");

	return TRUE; /* return FALSE, instead, to destroy the main window */
}

static void destroy(GtkWidget *widget, gpointer data )
{
	gtk_main_quit();
}

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

	gtk_init(&argc, &argv);

	window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

	g_signal_connect(G_OBJECT(window), "delete_event",
		G_CALLBACK(delete_event), NULL);
	g_signal_connect(G_OBJECT(window), "destroy",
		G_CALLBACK(destroy), NULL);
	gtk_container_set_border_width(GTK_CONTAINER(window), 10);

	button = gtk_button_new_with_label("Hello World");
	g_signal_connect(G_OBJECT(button), "clicked",
		G_CALLBACK(hello), NULL);
	g_signal_connect_swapped(G_OBJECT(button), "clicked",
		G_CALLBACK(gtk_widget_destroy), G_OBJECT(window));
	gtk_container_add(GTK_CONTAINER(window), button);

	gtk_widget_show(button);
	gtk_widget_show(window);

	gtk_main();

	return 0;
}

The output for the GTK+ program looks like this:

And, for comparison, here is the example Hello World program for StdGUI:

#include <stdgui.h>

CALLBACK(draw_hello, evt, param)
{
	int ascent, descent;
	FONT fnt;

	fnt = get_appfont();
	get_font_info(fnt, &ascent, &descent, NULL);
	plot_str(evt->graphic, 5, 5+ascent+descent, "Hello World", fnt);
	
	return 0;
}

int main(int args, char *arg[])
{
	int rv;

	start_gui("Hello", args, arg, 0,
		DEF_CB, "draw_hello", draw_hello, DONE);

	create_window("Hello", 0, 0, 200, 100, 0,
		SET_PROP, "ON_REDRAW", 1, "draw_hello", DONE);

	run_event_loop(&rv);

	return rv;
}

And here is the output from the Standard GUI program:

From this limited example, it certainly appears that the StdGUI program is shorter and simpler than the GTK+ version. For real programs, of course, most of the size advantage will disappear, since most of the code will be concerned with the program's actual functionality, not with user interface interaction, but the advantage of clarity will, hopefully, remain. In any case, the ease of writing small programs should prove an advantage for new or casual users of StdGUI.

Discussion

The simplicity of StdGUI programs comes from three sources:

  1. The StdGUI API is more abstract than most APIs on which it is implemented. The client program specifies only the coarsest behaviors: all standard behaviors are implemented in the run_event_loop() function. This also aids portability by separating the client code form all sorts of API specific features and behaviors.
  2. Many behaviors have usefull default definitions, so no client code is needed to implement them. An example of this is the default close window behavior: if no ON_CLOSE property is set for a window, the default behavior closes the window and ends the event loop if no more windows exist.
  3. Many StdGUI functions take multiple parameters, allowing a single function call to take the place of many calls in other APIs. An example of this sort of function is the create_window() function, which may take multiple property definitions (terminated with a NULL value).
At least two of these features of StdGUI conspire to make the StdGUI Hello World program simpler than the GTK+ version: The standard behaviors eliminate the need for two callbacks that are required in the GTK+ program (delete_event() and destroy() functions) and the multiple parameters in the create_window() function take the place of the calls to g_signal_connect(). (Obviously, the lack of a button widget in the StdGUI Hello World program further tilts the playing field against GTK+)

The Standard GUI framework also tries to head off simple mistakes and misuse: two examples of these safeguards (the only examples, at the moment) are the automatic registration of an exit function that cleans up the GUI system and a guard variable that prevents the touch_rect() function from causing a new redraw event while handling a current redraw event. Since some people may take issue with a policy that coddles the clumsy or incompetent programmer, the framework will generate an error message in the log whenever it saves someone ass.

There is a fundamental difference, I think, between the design approach I am taking with StdGUI and that taken by other GUI frameworks or APIs: I want simple programs (like the example hello world program above) to be simple and complex programs to be possible without increasing the complexity of the complex programs beyond their inherent complexity. That is a pretty fine line to walk, and most GUI systems don't do a very good job of it on one side or the other (possibly both). In fact, most GUI systems that I've seen seem to err on the side of making simple programs more complex. That increased complexity seems to remain constant, regardless of the complexity of the target application, which means that you don't feel the increased complexity as much with real applications than you do with toy examples.

I think a balance can be struck where simple programs can be fairly easy to write while still allowing the complex applications to be written without too much added overhead. We'll see how I do at proving this assertion.

Download

The StdGUI library is in an early alpha stage of development, but is already usable for simple projects. There is still lots of stuff left to do: none of the default widgets have been written, menus and automatic layout haven't even had skeletons written, and there is no documentation. However, if you would like to fool around with StdGUI, you can download a current copy of the codebase here.

One more word of warning: Since StdGUI is still in alpha you should expect the API to change, sometimes drastically. For this reason I suggest you not use StdGUI, at this time, for production work. Please feel free to play around with it, but don't expect it to be a stable platform (at least, not for another few months).

The current (alpha) version of StdGUI builds on Linux or Darwin under X-Windows. Though I haven't tried it, I am certain that the make file would require specific modification in order to work on other unix-like systems. I've got some stuff in the make file for Cygwin support, but it isn't working just yet: If anyone knows what I'm doing wrong (look at the libstdgui.so target under the CYGWIN_* case. I know that I ought to be using GNU libtool, but I'd prefer to understand the dirty details), I'd be happy to be enlightened.

Documentation

The only real documentation for StdGUI, at the moment (aside from the source code itself), are a series of manpages that describe the framework functions in each major module:

At some point I intend to write an actual tutorial on how to write programs using the StdGUI framework, but that will wait for the framework API to settle down a bit.

Future Plans

I have a fairly detailed plan for what to do with StdGUI in the future. Some of the major enhancements include:

I figure that's enough work to keep me busy for at least a few years, so, for the moment, that's where the list ends.

Postscript

I'm not trying to pick on GTK+ here, it just makes a convenient example: the other possible examples (X Windows Xlib, Microsoft Windows Win32, or Apple Carbon) would be much too verbose to fit on this tiny webpage.

I actually rather like GTK+, it looks very similar to what I would have done (and am doing). In fact, GTK+ is very close to what I am looking for, I just think it is a little more cumbersome and obscure than it needs to be. I'm not really trying to supplant GTK+, Qt/KDE or any other user interface system, I just want an easier way to write simple applications in C (rather than C++, C# or Objective C), and GTK+ doesn't quite scratch my personal itch, so please don't send me irate emails because I have impugned the honor of you're favorite API.


Home