[RiceCS]

COMP 320 Tutorial - X-Windows GUI

[Rice]

Tutorial goals:


Introduction

The purpose of this tutorial is to enable anyone with knowledge of C but without knowledge of the internals of X-Windows to write X-Windows applications.

The tutorial uses the Athena "widget set". This is because of several reasons: the Athena widget set, unlike the Motif set, is free. Moreover, it is included with each and every X distribution we know. Still, a lot of the basics in the tutorial are equally valid for Athena and Motif users. Therefore, even if you would rather use Motif instead of Athena, this tutorial may still have its use to you.


Basics of X applications

An X application is basically a collection of widgets that are linked together in various ways. A widget is a more-or-less self-supporting object within this application; a button, a check box, or a composite widget like a viewport with scrollbars.

Widgets depend on each other. Suppose, for example, that we have an application which at some point displays a window with a number of check boxes in a panel and a few command buttons. In this example, the panel and the command buttons would depend on the window, and the check boxes would in turn depend on the panel.

The correct X terminology for this relation uses parents and children; in the aforementioned example, the window would be the parent to the command buttons, while the check boxes would be children of the panel.

If you are familiar with Java GUIs, you notice that X GUI mechanism is very similar to Java. This is because the Java GUI architecture was modelled after X.

Making it work: Events and Callbacks

It is, of course, necessary for widgets to be able to communicate with the application and vice versa. There are two mechanisms in X for this, events and callbacks.

An event is something that occurs as a result of a user's action, for example moving the mouse or pressing a key. It is possible to register an event handler with a widget, thus instructing the program to call a specific procedure (callback function) when a certain event occurs. This is similar to the event/eventlistener model in Java.

Every widget has at least one callback list, the destroy_callbacks list. This is a list of procedures; every member of this list is called when the widget is destroyed.

Customizing widgets: Resources

Resources can be seen as parameters to a widget. Examples of resources for a widget are its height, width, and (for a command button) the font of the text on the button. Resources can be set by the programmer at coding time or by the users at runtime.


Our First Program

This will be a very simple program: it will have one button, which will end the program when clicked.

Required header files: When making an X program, we always need two header files, X11/Intrinsic.h and X11/StringDefs.h. You must also include the header files for any widgets used in the program.

Required compiling options: When compiling, you must add the directory /usr/X11/include to the search path for header files. One way to do this is to invoke gcc with the

     -I /usr/X11/include
option. You must also add
     -L /usr/X11/lib -L /usr/openwin/lib
for linking. Additionally, when using Solaris, there are Solaris-specific libraries needed, which are included with the options
     -lsocket -lxnet -lnsl
So, the final command might be
     gcc -I /usr/X11/include -L /usr/X11/lib -L /usr/openwin/lib sample.c -lsocket -lxnet -lnsl -lXaw -lXext -lXmu -lXt -lX11 -o sample

Sample Program

#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/Command.h>

XtAppContext app_context;
Widget       toplevel;     /* The overall window.       */
Widget       form;         /* The layout of the window. */
Widget       quit_button;  /* The button in the window. */

/* The callback function for the quit button. */
void quit_proc (Widget w, XtPointer client_data, XtPointer call_data)
{
    XtDestroyApplicationContext (app_context);
    exit (0);
}

int main (int argc, char ** argv)
{
    /* Create the window and its contents' appearance. */
    toplevel = XtOpenApplication (&app_context, "XFirst", NULL, 0, &argc,
				  argv, NULL,
				  applicationShellWidgetClass,
				  NULL,
				  0);
    form = XtVaCreateManagedWidget ("form", formWidgetClass, toplevel, NULL);
    quit_button = XtVaCreateManagedWidget ("quit_button", commandWidgetClass,
					   form, XtNlabel, "Quit", NULL);

    /* Create window's behavior. */
    XtAddCallback (quit_button, XtNcallback, quit_proc, NULL);

    /* Display the window. */
    XtRealizeWidget (toplevel);

    /* Infinite loop, waiting for events to happen. */
    XtAppMainLoop (app_context);

    return 0;
}

That code is also available in sample1.c.

In the main function, we create the top level widget (the top of the widget tree; all widgets are children of this widget) as well as the form widget. A form widget takes care of layout (like Java's LayoutManagers), which is not quite necessary in this program, since there is only one widget. We also create the button widget and assign it its callback function.

For details on these X functions, see their online manual pages.

Resources

Some people call them properties, but in X terminology, they're resources. A widget is defined by its resources; they determine its width, height, color, font and many other things.

We have already seen that we can set resources using the XtVaCreateManagedWidget function. This, however, does not provide for much flexibility; suppose that we would like the "Quit" button from the example in the previous section to say "Exit" instead. We would then have to change the source code and consequently recompile the program to get this effect; this is not a problem for a very small program, but it would be rather annoying for a Netscape-sized application.

A way to solve this problem is using the resource file. This is a file in human-readable format, in which you can specify values for the various resources that belong to the application. Resource files can be put in two locations. There is a directory for system-wide resource files, usually in your local X11 directory, under lib/X11/app-defaults. The other location is your own resource file directory. You can specify its location in the environment variable XAPPLRESDIR. Usually, it resides under your home directory as .app-defaults or something like that. See man X for more details.

It is also possible to change resources at runtime. To do this, Athena provides the XtVaSetValues and XtVaGetValues functions. The prototype for XtVaSetValues is

     XtVaSetValues (Widget w, ...)
where ... is a NULL terminated list of resource names and values. XtVaGetValues is similar, though its parameter list is not of resource names and values, but of resource names and pointers to variables where the resource values can be stored.

Two useful resources for providing layouts in forms are XtNfromHoriz and XtNfromVert, as they can be used to provide layout for an application by defining relative placement of widgets. With them, you can tell a widget to place itself beneath or to the right of another widget. If XtNfromHoriz or fromVert is not used, the widget will place itself at the left or top edge, respectively, of the form. For example, if you would like to place a "north" button to the right of a "northwest" button, you would do this by setting the horizontal value of the "north" button to be equal to the name of the "northwest" one.

To find out what resources are available, use the UNIX program listres. With no arguments, it lists the available widget classes. With a widget class as an argument, it lists its available resources.

X Exercise
  1. Take the sample program above and extend it to have a new button located to the right of the old quit button and that changes its display label each time the user clicks it.

    Follow the above guide for the big picture. Read the associated manual pages for the details.

  2. If you have time, add more stuff to your window. Have fun.

Here's a sample solution.

For more information

This Motif page has a complete tutorial on X Windows programming. Although it is not Athena, it is similar enough that it can be useful for learning X GUI. And here's another good X tutorial.