|
|
COMP 320 Tutorial - X-Windows GUI |
|
| Home | Administration | Assignments | Syllabus & Notes | Related Web Links |
|---|
Tutorial goals:
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.
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.
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.
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.
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
|
#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
|
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.
XtVaCreateManagedWidget creates widgets with a given set
of properties. The most important arguments are the widget name,
widget type and the parent widget, in that order. Then you specify
the resource properties. In this example we are setting the
"label" resource denoted by XtNlabel to be the string "Quit".
XtRealizeWidget builds all the data structures necessary
to show the widgets and to handle events.
XtAppMainLoop makes the application enter an infinite
loop that waits for user events to happen.
XtAddCallback registers the "event listener" for the widget.
The callback function, quit_proc, simply terminates the
program by finishing the infinite loop of the application context and
then exiting the application.
For details on these X functions, see their online manual pages.
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.
|
|
Here's a sample solution. |
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.