Chapter 2. Introduction to the X Toolkit and Motif

This chapter provides a conceptual introduction to the X Toolkit (including the Motif widget set), followed by a practical tutorial that starts with the most fundamental toolkit program, a “hello world” type application consisting of only a single widget. This application is successively refined until the major elements of any X Toolkit program have been introduced.

It is difficult to build applications that have a graphical user interface using a low-level programming library such as Xlib. To simplify development, each of the user-interface elements of a graphical application--scrollbars, command buttons, dialog boxes, popup or pulldown menus (everything but the main application window)--should ideally be available ready-made, so the programmer need only integrate them with the application code.

The purpose of the X Toolkit is to provide such a simplified approach to graphical user-interface programming. However, in keeping with the X philosophy of “mechanism, not policy,” the designers of the X Toolkit didn't develop a fixed set of components with a predefined look and feel. Instead, they created a general mechanism for producing reusable user-interface components so that these components can be built either by the application programmer himself, or by lower-level “object programmers” and then collected in libraries for use by the application. Motif is such a library of ready-to-use user-interface elements.

The heart of the Toolkit is a C library called Xt, also known as the X Toolkit Intrinsics. Xt provides routines for creating and using user-interface components called widgets. A typical application uses Xt along with a library of pre-built widgets (a widget set) such as Motif. This widget set includes menus, dialog boxes, scrollbars, command buttons, and so forth, which all work together to provide a consistent “look and feel” for an application.

Programming with Widgets

The simplest way to understand the role of widgets in an application is to look at a hypothetical application, as shown in Figure 2-1.

Figure 2-1. A widget-based application (simulated)

If you are at all familiar with graphical applications, you will recognize many of the widgets called out in the figure as standard user-interface elements:

  • Push buttons, which initiate an action when clicked on with the mouse. (Pushbuttons are sometimes called command buttons in other widget sets, but in Motif a Command widget is used for typing in commands.)

  • A scrollbar, which allows the user to scroll data visible in a display window. (The position of a “thumb” within the scrollbar indicates the position of the visible data within a larger data buffer, and lets the user change the current position in the buffer by dragging the thumb with the mouse. Widget sets have various names for the scrollbar thumb.)

  • A data entry area, in which the user can type information requested by the application.

Other widgets in the application may not be as obvious:

  • Composite widgets, which are used to contain other widgets. In all widget sets, special classes of widgets manage the position (and possibly the size) of the child widgets they contain.

    Composite widgets are an important part of any widget set, since they insulate the application programmer from having to place each widget individually, or from having to reposition or resize various widgets when the application is resized by the user. Composite widgets automatically adjust the layout of their children when child widgets are added or removed.

  • Shell widgets. In any X Toolkit application, a special widget called a Shell widget is created by the call to initialize the Toolkit. This widget is used as the parent of all other application widgets (with the exception of popups, which receive their own transient Shell widget as a parent), and includes special functionality that allows it to interact with the window manager. The Shell widget is invisible, since it is overlaid by the main widget of the application (typically a composite widget), which is exactly the same size.[7]

  • A special-purpose application window. Most applications have at least one window that has unusual characteristics not supported by an existing widget. For example, in our hypothetical application, the main application window is used to graph the performance of a stock portfolio.

    There are several ways to implement such windows. Which to use depends on the complexity of what you plan to draw, the types of input you want it to accept, and whether you know how to write a widget. You can add graphics to a DrawingArea widget. You can add functionality to an existing widget (usually called a Primitive widget) by adding actions as described in "Chapter 4, An Example Application," or you can write your own widget, as described in "Chapter 6, Inside a Widget." As you will see, no matter how you write application code to operate the special-purpose window, making a widget that does the same thing is mostly a matter of rearranging the code and changing variable names. Placing code into a widget gives you easier access to the configurability features of Xt, and neatly packages up the code to operate the special window.

  • A popup dialog box. A popup is a widget that appears temporarily on the screen, until the user provides a certain kind of input. Popups are usually invisible when the application starts up. Using Xt, applications create popups very much like permanent widgets. The only difference is that a special kind of Shell widget called a popup shell needs to be created as the parent of the widget to be popped up. Many types of menus and dialog boxes (also referred to as “notices”) are intended to be used as popups.

There is one other element in the figure that is not strictly part of the application, and is not provided by the widget set. This is the titlebar, which is added to the application by the window manager. Typically, the titlebar displays the window or application name, and also provides control areas for moving, resizing and iconifying the application.

While the titlebar isn't a widget, it is a window. The window manager adds the titlebar by “reparenting” the application. That is, it inserts another window between the application's toplevel window and the root window. The visible portion of this window is the titlebar.

The titlebar in the figure has been added by the twm window manager, which is standard in X11 R5 from MIT. Clicking on the small X logo in the left corner of the titlebar iconifies the application; dragging the pointer in the nested box symbol in the right corner resizes the window. The window can be moved by holding down the pointer anywhere else in the titlebar and dragging the window to a new location.

About Widget Sets

Shell widgets, and a few other base widget classes (Core, Composite, and Constraint) that are used to build more complex widgets, are defined by Xt. The special-purpose application window is written by the application programmer. All of the other widgets shown in Figure 2-1 come from a widget set--a library of pre-built user-interface components. Specifically, they are from the Athena widget set, developed at MIT.

The Athena widget set is distributed free along with the MIT X Window System distribution, and as a result, is the basis for many of the demonstration applications shipped by MIT and a great deal of public-domain X software. However, the Athena widget set was not intended to be complete--it was built mainly for testing and demonstrating the Intrinsics. Furthermore, the Athena widgets do not have a particularly attractive appearance nor user-interface conventions. For these reasons, we suggest that serious application development efforts should begin with a commercial widget set.[8]

Two commercial widget sets that are easily available and quite complete are OSF's Motif and AT&T's OPEN LOOK widgets. Both Motif and OPEN LOOK contain menus, scrollbars, command buttons, dialog boxes, and a wide variety of composite widgets. Both have an attractive appearance and consistent, well defined user-interface conventions. Each comes with a style guide that contains suggestions for designing applications to blend in well with other applications using that widget set.

In order to highlight some of the added value provided by a commercial widget set such as Motif, Figure 2-2 shows the same hypothetical application constructed with Motif widgets, and with a titlebar provided by the mwm window manager.

Figure 2-2. A Motif widget-based application (simulated)

As you can see, Motif has a distinctive appearance, using shadowed outlines to simulate a 3-D appearance (buttons appear to be pushed in when you click on them, and so forth). What is more important, Motif has conventions about the use of its widgets that lead to a consistent look among all applications using Motif. The OSF/Motif Style Guide contains recommendations for application design and layout, and whenever possible, these recommendations are actually embodied in the design of the widget set. For example, the Motif MainWindow widget provides a menubar at the top of the application, which can contain titles for standard “pulldown” menus for file manipulation and on-line help, as well as for various application functions.

Motif also provides many more widgets than Athena, making it easy to create control areas such as radio boxes (groups of buttons, of which only one can be chosen at a time) or check boxes (groups of buttons that may be set independently of each other, say for making application configuration choices.) There are also convenience functions for creating many common combinations of widgets.

The mwm window manager provides similar functions to twm, but also always provides support for a help feature (invoked by clicking on the box in the upper right corner of the titlebar).

The Motif widgets also support some advanced features for internationalization such as language-independent “compound strings,” keyboard traversal (moving around widgets with keyboard keys rather than a mouse--this is very helpful for the design of data-entry applications) and mnemonic key equivalents for invoking menu commands.

This book provides examples that use the Motif 1.2 widget set. However, the techniques described in this book for using, modifying, and creating widgets are defined by Xt, and therefore are the same regardless of which widget set you use. You can use the same techniques to create applications using AT&T's OPEN LOOK widget set, or using the Athena widgets.

Note, however, that Motif provides many Xt-level functions (such as support for keyboard traversal and compound strings) that go beyond those provided by Xt. These features, are not portable to other widget sets. If you plan to write an application that will be portable between widget sets, you may wish to stay away from these Motif-specific features.

An important reminder here is that this is a book on the Xt Intrinsics, not primarily on Motif. Motif-specific features are introduced, but not described in minute detail. Moreover, Motif-specific features are carefully distinguished from the basic Xt features, to make it is easier to know what features are portable between widget sets. (Motif-specific features are described primarily in "Chapter 5, More About Motif.") Volume Six, provides a more complete description of how to use each Motif widget, how to properly design an application according to the Motif style guide, and how to use the Motif-specific features and functions.

Widget Classes and Instances

A widget set defines classes of widgets. DrawingArea is a class of widget, as are ArrowButton, PushButton, ScrollBar, and the various widgets shown in our hypothetical application.[9] Each time you create a widget, you create an instance of one of these predefined classes. For example, you might create several PushButton widgets, each with a unique name, containing a unique text label, and each invoking different application code when it is clicked on. All these widgets would be of class PushButton, but they usually have different string names such as “quit”, “run”, and “stop”. They would have similar characteristics, but they would not necessarily look or act exactly the same since each could have been configured differently.

A widget class has certain fixed features which are common to all instances of that class, and certain characteristics which can be changed from one instance to the next.

How you view a class depends on whether you are using existing widget classes or are also writing new ones. Eventually you will thoroughly understand both these views of a class, since you will be competent in both using and writing widgets. For the first four chapters of this book, we will concentrate on the widget user's point of view. Both views are introduced here because we don't want to mislead you by telling you only the widget user's view, half the story of what a class is.

For a user of existing widget classes (a widget set), a widget class is a black box that has certain fixed features and certain configurable features, both of which are documented on the widget class's reference page. You need not know anything about how a class is implemented in Xt. You know that when you create an instance of that widget class, the instance will have the documented fixed features and that you can set the configurable features. A user of existing widget classes is most interested in the configurable features, since setting these is a big part of programming an Xt application. Each configurable feature is called a resource. Resources are more fully introduced in the next section.

If you are writing a widget class, or if you have written one and see things from that perspective, a class seems slightly different. To you, a widget class is a set of files in which the widget class is implemented. The widget class is no longer a black box--it is an open box. Knowing what widget class code looks like, you know that its fixed features and its configurable features are implemented in distinct sections of the code. You know that each resource is actually represented by a field in a structure. You know that each class has a structure (the class structure) that contains all the fixed features (both code and data) of that class. Even though you don't necessarily have access to the source code for a widget class, your definition of a class is based on how that class is implemented.

Figure 2-3 illustrates these two ways of viewing what a class is.

Figure 2-3. Two ways to think about a class

These two views of a class take on special relevance when looking at a characteristic of the Toolkit called class inheritance. Widget features and characteristics can be inherited from other, more basic classes of widgets. To a widget user, class inheritance is important only because it means that the resources (configurable features) of a widget class are defined not only by the class itself but also by the classes from which the class inherits features, called its superclasses. When you look up a widget class's features on its reference page, either all its superclass's resources will be described, or you will have to look up its superclass and look on that page also, and continue up the class inheritance hierarchy to the most basic widget, in order to get a complete list of its capabilities. This sounds difficult, but in reality you get to know the features of the most basic classes by heart, and the classes are not deeply nested.

From the widget writer's point of view, inheritance means that a new class of widget needs to define only its own unique features, and need not re-implement features common to all widgets, or already implemented by an existing superclass. All classes exist in a single-inheritance hierarchy that defines which other classes each class inherits features. (Note that the class hierarchy is completely different from the parent-child relationship of widget instances you create in an application. The class hierarchy of a particular widget set is fixed by the creators of the widget set, while the instance hierarchy is different in every application, and is determined solely by the writer of the application. The instance hierarchy specifies which widgets contain which other widgets on the screen.)

Figure 2-4 shows the class inheritance hierarchy for the Motif widget set. Classes defined by Xt (which are the same for all widget sets) are shaded gray.[10] This section describes the Xt classes, as well as the most basic Motif classes, in order to clarify the concept of classing as implemented in the Toolkit. A description and illustration of each of the Motif widgets is given later in the book.

Figure 2-4. Class hierarchy of the Motif widget set

The Core widget class, defined by the Intrinsics, is the root of the hierarchy, from which all other classes descend. The Core class defines characteristics common to all widgets, such as size and position.

The Motif Primitive widget class inherits basic widget features from Core and adds a few minor features of its own (for example, control of Motif style 3-D shadows) that are common to many Motif widgets. The Label widget in turn adds the ability to display a string or a pixmap, and adds mechanisms for changing the font and placement of the string. PushButton then inherits features from Label (including those already inherited from Core and Primitive) and adds more features, such as the ability to accept user input and highlight the button. PushButton is known as a subclass of Label, and Label is the superclass of PushButton. In general, lower classes in the hierarchy have more features.

The Composite class adds geometry-management capabilities to the basic characteristics defined by Core. Constraint is a further refinement of Composite that allows the application or the user to supply instructions on how the size and position of each child should be managed. All Motif geometry-managing widgets are subclasses of Manager, which is itself a subclass of Constraint. Manager is Motif's equivalent of Primitive for geometry-managing widgets--it adds features such as 3-D shadows so that they are available in virtually all Motif widgets.

Shell is a special class of Composite widget designed for interaction with the window manager.

New widgets can be subclassed by the widget programmer directly from Core, Composite, or Constraint, or can be subclassed from an existing widget in any widget set that has some of the desired behavior. For example, it is easy to imagine creating a subclass of Primitive in order to develop a custom graphics window.

As long as appropriate widget classes are available, the application programmer needs to know little or nothing about widget internals. In fact, even if widget internals are known, it is unwise to depend on them. Widgets should be treated as black boxes with documented inputs and outputs. If only these documented interfaces are used, the widget internals can be modified without affecting the application, and the application can be modified without affecting the widget.

Widget Configurability with Resources

To serve their purpose as reusable user-interface components, widgets must be highly configurable. For example, an application programmer must be able to define not only a separate label for each PushButton widget, but also the application function that is invoked when the button is clicked. The programmer will also want to let the user define additional attributes such as font and color.

To support this degree of configurability, widget classes can declare variables as named resources of the widget. The application can pass the value of widget resources as arguments to the call to create a widget instance, or can set them after creation using the Intrinsics call XtSetValues(). Even before that, though, as an application starts up, a part of Xlib called the resource manager reads configuration settings placed in a series of ASCII files by the user and/or the application developer, and Xt automatically uses this information to configure the widgets in the application. The collection of resource name/value pairs contained in the various resource files and set directly by the application is collectively referred to as the resource database.

Figure 2-5 shows several Label widgets configured with different resource settings, to show you how radically the appearance of even such a simple widget can be altered. Note that a widget's input characteristics can also be configured (although the Label class has no input characteristics to configure).

Figure 2-5. Several Athena Label widgets configured using resources

The resource manager provides a flexible mechanism for generalizing the behavior of widgets. The application developer can “hardcode” the value of those resources that must not be changed because they could cripple the application (as when changing the label of the Quit widget to Save), and can establish reasonable defaults for other resources, so that the user can configure all nonessential aspects of an application's look and feel.

Note that the term “resource” is used somewhat ambiguously in X. First, in the original documentation for Xlib and the X Protocol, various data structures that are maintained by the server and identified to clients only by an integer ID are referred to as resources. These data structures include windows, colormaps, fonts, and so forth. In this series, these are normally called server resources where there is possible confusion.

Second, the term is commonly used to refer both to a widget variable publicly declared as a widget resource, and to the name/value pairs in the resource database. In this book, we will use the term resource to refer to the actual variable and its current value in a widget instance, and the term resource setting to refer to a name/value pair in the database. The two are closely related, but may not be identical. For example, separate settings for the same resource may be requested in an app-defaults file and in an individual's user-preference file.[11] Furthermore, the value of a resource may be set on the fly by a call to XtSetValues(), but this value is never saved in the resource database. (This value can be retrieved from within a widget or application by a call to XtGetValues().)

Widget Independence

Each widget operates, to a large degree, independently of the application. Xt dispatches events to a widget, which performs the appropriate actions according to the design of its class, without application help. For example, widgets redraw themselves automatically when they become exposed after being covered by another window.[12] Widgets also handle the consequences when the values of their resources are changed. An instance of Label, for example, does not depend on the application that created it to determine its size. By default, Label will choose a size large enough to accommodate the current string in the current font. If the application changes the text or font in the Label widget with a call to XtSetValues(), the Label widget itself will attempt to keep its own window large enough to accommodate the current string. (Of course, if necessary, the application can also explicitly choose the Label widget's size.) When the application tells a Label widget what font to display its string in, the widget knows how to load a new font, recalculate its own size, and redraw its string--the application doesn't have to micro-manage any of this. The application simply sets the font resource of the widget, and the widget does the rest.

Figure 2-6 and Figure 2-7 illustrate how a widget operates independently of the application and how XtSetValues() lets the application set how a widget operates itself.

Figure 2-6. Widgets operate independently of the application


Figure 2-7. XtSetValues lets the application set how a widget will operate itself


Widget-Application Interaction

In the other direction, widgets are designed to let the user control the application. Therefore, widgets have the ability to invoke certain sections of application code--sections of the application's own choosing. Again, widgets will operate fine without invoking any application code, but if they don't invoke any, they won't do anything for the user.

One way that the application arranges for widgets to invoke application code is by registering application functions with Xt. Once the application is running, Xt will call these functions in response to some occurrence in the widget. For example, a PushButton widget usually invokes an application function when the user clicks on the widget. (Thus, the widget labeled “Quit” might invoke the code that checks whether data has been saved, and if so, exits the application.) Or the ScrollBar widget notifies the application when the user has moved the thumb, by calling a function that the application has registered with the widget for that purpose. Figure 2-8 and Figure 2-9 illustrate how an application registers a function during the startup phase, and how Xt then calls the function during the event-loop phase in response to a particular occurrence in the widget.

Figure 2-8. Application registers a function with Xt during startup phase

There are three separate mechanisms that can be used to link widgets and application functions: callbacks, actions, and event handlers.

Generally speaking, a widget expecting to interact with an application will declare one or more callback lists as resources; the application adds functions to these callback lists, which will be invoked whenever the predefined callback conditions are met. Callback lists are resources, so that the application can set or change the function that will be invoked.

Callbacks are not necessarily invoked in response to any event; a widget can call the specified routines at any arbitrary point in its code, whenever it wants to provide a “hook” for application interaction. For example, all widgets provide a destroyCallback resource to allow applications to provide a routine to be executed when the widget is destroyed. All callbacks have what Motif calls a reason--a well-defined occurrence of some kind that causes the callback to be triggered.

Figure 2-9. Xt calls the function during the event-loop phase in response to an occurrence

Although a callback reason need not be an event, callbacks are often invoked by widgets from within actions, which are event-driven. Action routines are called directly by Xt in response to events specified in a translation table. Xt supports a high-level event-specification syntax, which allows easy specification of complicated event sequences (such as double- or triple-clicks, or key- and button-press combinations) as the trigger for actions. Furthermore, the translation table is a resource, allowing the application developer or the user to configure the events that will invoke a given widget action.

Actions are usually internal to the widget and require no interaction with the application. (For example, in the Text widget, all editing operations are carried out entirely by the widget, using functions defined as actions. The only role required of the application is to read and write files.) However, an application can also add actions to a widget, which can function in much the same way as callbacks, but without the widget class having made provision for them.

The purpose of a well-designed widget set is to implement a particular user interface, which provides conventions designed to make all applications operate in the same way. A widget's callbacks are often designed to support the intended use of the widget, while adding actions to a widget can make it behave in ways the designer did not foresee and that the user might not expect. Nonetheless, there are cases in which the best way to implement the desired behavior is to add actions to an existing widget.

In addition to callbacks and actions, it is also possible for an application (or a widget) to implement event handlers, which use an event-selection mechanism similar to that used in Xlib. Event handlers are rarely used by application programmers, since actions are simpler and configurable without recompiling.

Some widgets also declare public routines, which can be used by an application to control aspects of the widget's behavior or to get widget data. Usually, the purpose of public routines is to provide a more convenient means for setting or getting widget data that would otherwise have to be accessed through resources.

Xt and Object-oriented Programming (OOP)

Xt provides an object-oriented programming (OOP) style, where the objects are widgets. However, since Xt is written in C, a language that provides no special support for OOP, Xt depends on programming conventions and programmer discipline to maintain the semblance of objects. It is very important that the programmer understand the goals and rules of OOP, because the language and the system won't enforce these rules, and if you don't follow them, you won't get the benefits. If you are familiar with another object-oriented system, you will need to understand Xt's particular implementation of OOP. On the other hand, if Xt is your first exposure to OOP, an explanation of its goals and concepts should make the whole system make a lot more sense.

Traditionally, object-oriented programming is defined in terms of the five words object, method, message, class, and instance, and the concept of encapsulation. We've already talked about classes and instances. This section describes the remainder of these terms.

The Object

In OOP, an object contains two elements: the data that represents a state, and code that reads or writes that data (called methods) and performs some action based on it. For example, the string displayed by a Label widget is part of its state data, and the code that actually draws the string on the window is a method that reads the state data and draws based on it. Inside widget code, the state data is represented as structure members, and the methods are represented as pointers to functions. Some state data members are public; they are resources that can be set or retrieved from outside the object. Other state data members are private; they cannot be read or written from outside, but they help the widget keep its own house in order.

Methods

What is called a method in traditional OOP is either a method or an action in Xt. In Xt, methods are a set of functions that are fixed for a particular class, triggered in fixed ways usually in response to Xt function calls made by the application (with one special case, the expose method, triggered directly by the Expose event). A widget's methods supply its most basic functions, such as the code needed to create a window, or to redraw itself. Actions, on the other hand, are called in response to the events specified in a translation table, and thus the events that trigger actions are user configurable. Actions supply most of the features of widgets, and these features can be added to or replaced by the application, as demonstrated in Section 4.2, "xbitmap2: Adding Graphics to Display the Bitmap" and Section 4.4, "xbitmap4: A Bitmap Editor Without a BitmapEdit Widget."

From the widget writer's point of view, each method is just a function whose pointer has a place in the class structure. Each method has particular responsibilities in managing the basic functions necessary for a widget to be a widget. For example, every widget class must have a method that responds to calls to XtSetValues(). What each of the vital methods must do is described in "Chapter 7, Basic Widget Methods." Each method has different arguments and returned values.

Every action, on the other hand, has the same set of arguments. Actions generally perform the features of the widget that are triggered by events. You could say that actions are the widget's occupation: it needs them to do anything useful but not to exist.

Messages

In pure OOP, input to objects and communication between them are called messages. In Xt, however, the forms of communication are function calls, events, actions, and callbacks. As you have seen, applications can communicate with widgets using function calls, such as to set or get widget resources using XtSetValues() and XtGetValues(). Widgets also respond directly to events from the user. Widgets contact the application when certain things occur using callbacks or actions. Widgets pass data back and forth using special kinds of events. All these types of communication can be thought of as forms of messages.

Encapsulation

Objects are intended to be black boxes with documented inputs and outputs. In other words, a program that uses an object must not depend on the internal implementation of the object, but instead only on the known inputs and outputs. This is called code encapsulation. The advantages of code encapsulation are that programmers can use the object without needing to understand its internal implementation (hiding details), and that the internal implementation of the object can be changed at any time because no other code depends on it. This can be stated in another way: it minimizes interdependencies. In large software projects, this one feature makes OOP worthwhile.

This encapsulation is very effective in Xt. You should be able to get a long way toward completing an application without even needing to know what the code inside a widget looks like, let alone the details that implement a particular widget. For that reason, in this book we don't show you what is inside a widget until "Chapter 6, Inside a Widget." Even when you do know how widgets are implemented, it is a good idea to “forget” while writing application code, so that you are not tempted to depend on implementation details.

Each widget class has a public include file and a private include file. The application includes just the public include file, while the actual widget code includes the private (which happens also to include the public). The names of both include files are based on the class name of the widget, but the private include file adds the letter P to the end. For example, the Label widget's public include file is Label.h, while its private include file is LabelP.h. Application code should include only the public include file, to maintain the desired encapsulation. It is tempting for beginning Xt programmers to include the private include file, because it allows you to take shortcuts, but you should resist the temptation.[13]

Structure of Motif Applications

All Motif applications have the same basic structure, as follows:

  1. Include <Xm/Xm.h>, the standard header file for Motif. (Note that <X11/Intrinsic.h> and <X11/StringDefs.h> replace <Xm/Xm.h> when using other widget sets.)

  2. Include the public header file for each widget class used in the application. (Each widget class also has a private header file, which is used in the widget code. Do not include this file.)

  3. Register the locale callback function with XtSetLanguageProc(). This function sets up internationalization support. This call is virtually always made with three NULL arguments. Always include it as boilerplate; exactly what it does is described in Chapter 14.

  4. Initialize the Toolkit with XtAppInitialize() or XtVaAppInitialize(). (These two functions do exactly the same thing but have slightly different argument styles. The difference is described in Section 2.5.1, "Setting and Getting Resources from the Application." Many other Xt functions also have two versions with and without “Va” in their names. In the future, unless specifically stated otherwise, you can assume that when a sentence mentions one version it also applies to the other.)

  5. Create widgets and tell their composite parent widget about them. This requires one call to XtVaCreateManagedWidget() for each widget. (Separate XtVaCreateWidget() and XtManageChildren() calls can also be used to speed startup of applications with many widgets.) In Motif, there are also individual functions for creating many individual widgets and combinations of widgets. We use these “convenience functions” only for combinations of widgets, since XtVaCreateManagedWidget() is more general, more concise, and no more difficult to use.

  6. Register callbacks, actions, and event handlers, if any, with Xt.

  7. Realize the widgets by calling XtRealizeWidget(). This function has to be called only once in the entire application, passing it the shell widget returned by XtVaAppInitialize(). This step actually creates the windows for widgets and maps them on the screen. This step is separate from creating the widgets themselves, because it allows all interdependent widgets to work out their relative size and position before any windows are created. (For more on geometry management, see "Chapter 12, Geometry Management.")

  8. Begin the loop processing events by calling XtAppMainLoop(). At this point, Xt takes control of your application and operates the widgets. If any widgets are to call functions in your application, you must have registered these functions with Xt before calling XtAppMainLoop.

The four steps (3 through 6 above) of initializing the Toolkit, creating widgets, registering application functions with Xt, and realizing widgets, comprise the setup phase of the application. Your application should do as much of its work as possible in this phase, before calling XtAppMainLoop(), in order to speed up the second phase of the application (which is the event loop). This policy improves the response time to user events.[14] As we will see in "Chapter 6, Inside a Widget," this policy also applies to the code inside a widget. It is basic to X, and indeed to any event-driven system.

A Simple X Toolkit Application

Some application code that uses the X Toolkit will go a long way to illustrate the basic concepts introduced above.

Figure 2-10 shows the actual window created by a minimal “hello, world” Toolkit application xhello, and Example 2-1 shows the code for it. xhello simply displays the string “hello” in a window.

Figure 2-10. xhello: appearance on screen


Most window managers add a decorated border above or surrounding the window; this is not part of the application. Likewise, the placement of the widget on the screen depends on the window manager. Since no coordinates are specified as resources for the widget, most window managers will require the user to place it interactively. Some window managers can be configured to place new windows at an arbitrary default location.

The Code

Example 2-1 shows the code for xhello.c.

Example 2-1. xhello.c: a minimal "hello, world" application

/*
 * xhello.c - simple program to put up a banner on the display
 */

/*
 * Header file required for all Motif programs is <Xm/Xm.h>.
 * In other Xt-based widget sets:
 * #include <X11/Intrinsic.h>

 * #include <X11/StringDefs.h>
 */
#include <Xm/Xm.h>    /* Standard Motif definitions */

/*
 * Public header file for widgets actually used in this file.
 */
#include <Xm/Label.h>     /* Motif Label Widget */

main(argc, argv)
int argc;
char **argv;
{
    XtAppContext app_context;
    Widget topLevel, hello;

    /* Register the default language procedure */
        XtSetLanguageProc(NULL, (XtLanguageProc)NULL, NULL);

    /* Initialize the Xt Intrinsics */
    topLevel = XtVaAppInitialize(
            &app_context,       /* Application context */
            "XHello",               /* Application class */
            NULL, 0,                /* command line option list */
            &argc, argv,        /* command line args */
            NULL,                   /* for missing app-defaults file */
            NULL);                  /* terminate varargs list */

        /* Create a widget */
    hello = XtVaCreateManagedWidget(
            "hello",                /* arbitrary widget name */
            xmLabelWidgetClass,     /* widget class from Label.h */
            topLevel,               /* parent widget */
            NULL);                  /* terminate varargs list */

    /*
     *  Create windows for widgets and map them.
     */
    XtRealizeWidget(topLevel);

    /*
     *  Loop for events.
     */
    XtAppMainLoop(app_context);
}


Each of the Xt Intrinsics calls in xhello do more than meets the eye:

  • XtVaAppInitialize() performs several important tasks. It reads the resource databases and merges in any command-line arguments so that Xt can use this information to configure widgets as they are created. It also opens a connection to the server, and creates a Shell widget that is designed to interact with the window manager and to be the parent for other widgets created in the application.

    The first argument to XtVaAppInitialize() passes the address of an XtAppContext. An XtAppContext is an opaque pointer to a large structure in which Xt will manage all the data associated with the application. The only use of the XtAppContext returned from XtVaAppInitialize() in a typical application is to pass it to XtAppMainLoop() and possibly a few other functions. The true purpose for the XtAppContext being a public variable is complicated and is discussed later.

    The second argument (a string) is the class name of the application. It is the string that can be used in resource files to set resources for this application, and it is also the name of the app-defaults file, in which the application writer establishes default resource settings for the application. By convention, the class name is the same name as the application name (the string typed to invoke the application), except with the first letter capitalized, or if the application name begins with X, the first two letters capitalized. For the current application, the class name is XHello since the application name is xhello.

    The remaining arguments have special purposes that are not used in this application. We will introduce them briefly here but reserve complete treatment of them for "Chapter 3, More Techniques for Using Widgets." The third and fourth arguments are a pointer to and length of an array of application-specific command-line arguments that you can define. The fifth and sixth arguments are the common argc and argv--which XtVaAppInitialize() parses for a variety of standard X Toolkit options and the ones you defined in the previous arguments. The seventh argument is where you specify fallback resource settings in case the app-defaults file is not installed properly. The final argument terminates a variable-length argument list which can be used to customize the Shell widget with resources: this application uses the default Shell widget and therefore provides no resource settings in the list.

    The Shell widget returned by the call to XtVaAppInitialize() is used as the parent of the first widget created in the application.

  • The XtVaCreateManagedWidget() call both creates the Label widget and tells the parent (the Shell widget) that the Label widget's geometry is to be managed. It is also possible to call XtVaCreateWidget() and either XtManageChild() or XtManageChildren() separately, but this is usually done only if you want to create many children of a single widget, then put them all under parental management at once.

    XtVaCreateManagedWidget() is used for creating any class of widget. The first argument is the instance name, a string which Xt uses to look up settings in the resource database.[15] The second argument specifies the class of widget to create--this variable comes from the header file for that widget, and should always be found on the reference page for a widget. The third argument is the parent, which in this case is the Shell widget returned by XtVaAppInitialize(), but in a more complex example could be a composite widget deeper in a hierarchy of nested widgets. The fourth argument terminates a varargs list, unused in this example, that is for hardcoding widget resources. (More on varargs lists later.)

    Notice that XtVaCreateManagedWidget() and XtVaAppInitialize() each return a value of type Widget. This type is an opaque pointer that is used to refer to a widget instance. It is used anywhere in the application that you need to refer to a particular widget. We sometimes refer to this as a widget ID, since even though it is a pointer to a structure, the individual fields in that structure should never be accessed from the application, so it can be treated just as a unique number.

  • The steps of initializing the Toolkit and creating widgets seem logical. However, what does it mean to realize a widget? XtRealizeWidget() actually makes windows for the widgets, whereas creating the widgets simply creates and initializes various internal widget data structures.[16] Creation and realization of widgets are separate because some window geometries cannot be known until all the widgets are created and the composite widgets have determined their geometries. The realization step says “OK, all the widgets are created now; calculate their sizes and positions and make windows for them.” However, note that it is acceptable to create additional widgets after calling XtRealizeWidget() as long as there is a good reason to do so (for example, when it cannot be known whether the widget would be needed until a certain user event arrives).

    The realization step also maps all the widget windows. Mapping is an X concept, not something added by Xt. Mapping a window makes it eligible for display. For a window to actually become visible, all its ancestors must be mapped. Since XtRealizeWidget() is called for the widget created by XtVaAppInitialize(), which is the ancestor of all widgets in the application, the end result is that the entire application is displayed.[17]

  • XtAppMainLoop() transfers control of the application to Xt. From this point on, Xt drives all the widgets in response to events, and it interacts with the application only at times the application has arranged ahead of time. xhello did not arrange any interaction with the widget, so Xt operates the Label widget without returning to xhello's code. Example 2-3 demonstrates how to make such arrangements.

    Xt programming is event-driven. XtAppMainLoop() dispatches events to widgets and functions in the order in which they occur. These events can be caused by user actions such as pressing a key or by window system actions such as displaying a new window. This is fundamentally different from procedural programming, where the application is in charge and polls for user input at certain points.

Compiling the Application

You can get the code for xhello.c and all the rest of the examples in this book via uucp or anonymous ftp, as described in the Preface. It is a good idea to compile and run each example as it is presented.

The example programs come with Imakefiles that should make building them easy if you have the imake program (which should already be in /usr/bin/X11 on UNIX-based systems that have X11 Release 4 installed), and you need the configuration files, in /usr/lib/X11/config on most UNIX-based systems. The source for imake and the configuration files are also in the X11R4 distribution from MIT (see "Appendix F, Sources of Additional Information" for how to get this distribution).

An Imakefile is a system-independent makefile that is used by imake to generate a Makefile. This is necessary because it is impossible to write a Makefile that will work on all systems. You invoke imake using the xmkmf program (also in /usr/bin/X11 and on the R4 distribution). Complete instructions for compiling the examples using imake are provided in a README file in the example source. Note that the examples are designed to work with Motif 1.1, and probably will not work with Motif 1.0.

To compile any of the examples on a UNIX system without using imake, use the following command line:

cc -O -o filename filename.c -lXm -lXt -lX11

If you want to do debugging, replace -O with -g in this command line. The order of the libraries is important. Xm relies on Xt, and both Xm and Xt rely on Xlib (the -lX11 link flag specifies Xlib).

Note that unlike the Athena widget set, Motif does not use the Xmu miscellaneous utilities library, or the Xext extension library, both provided by MIT.

The App-defaults File

As mentioned above, the resource mechanism allows widgets to be customized. Widget resources can be set from any one of several sources, including a user's resource file, the command line, or an application-specific defaults file.

Each resource of a widget has a default value determined by the widget class that declared the resource. However, in many cases, the application wants a different default value, but still wants the user to be able to change the value of that resource.

The Label widget is a case in point. Example 2-1 (xhello) sets the default string displayed in the Label widget, “hello,” by naming the widget hello in the call to XtVaCreateManagedWidget(). It just so happens that the Label widget uses its widget name as the string to be displayed if no other string has been specified in the resource database. However, this trick doesn't exist for the other resources of Label or of other widgets.

The application can provide a default value for resources by hardcoding them in the application source file using the fallback resources argument of XtAppInitialize(). However, changing these settings would require recompiling the source. Xt provides a better way.

To provide defaults, applications should always create an “app-defaults” resource file, which on UNIX systems is usually stored in the directory /usr/lib/X11/app-defaults.[18] For any application, the name of this file should be the same as the classname argument to XtVaAppInitialize(). By convention, this string is the same as the name of the application, with the first letter capitalized. If the application name begins with X, the first two letters should be capitalized. For xhello this is XHello.[19]

Example 2-2 shows the contents of the app-defaults file necessary to make xhello display the string “Hello, World!” instead of the default “hello.”

Example 2-2. XHello: the app-defaults file

*hello.labelString:       Hello, World!

The name of the widget instance whose string we are setting is hello, and the Label widget's resource that sets the string is labelString. After the colon is the string we want the widget to display. The string should not be quoted. White space after the colon is ignored.

All resource settings in app-defaults files should start with an asterisk, instead of specifying the application name or class (xhello or XHello). This is important as it allows the user to easily override this setting, for reasons described in Chapter 10 in the discussion of the ? wildcard.

The app-defaults file has the same format as all other resource database files. In brief, there are two types of resources: application resources and widget resources. (You already know about widget resources. Application resources are the same except that they apply to the application code instead of to individual widgets. Application resources are defined by the application writer--how to do this is described in "Chapter 3, More Techniques for Using Widgets.")

The syntax for specifying application resources in a resource file is simple:

application_name.resource_name: value

Widget resources are more complicated since there may be multiple instances of the same widget class in an application. As a result, you must specify the name not only of the widget, but a pathname starting with the application name and containing the name of each widget in the widget hierarchy leading to the desired widget. For example, in the application xhello, the complete resource specification for the resource called label for the Label widget called hello would be:

xhello.hello.labelString:  Hello, World!

The xhello refers to the widget created by XtVaAppInitialize(), and hello is its child created by XtVaCreateManagedWidget(). One possible source of confusion is that the shell widget instance returned by XtVaAppInitialize() is not named xhello by the arguments of that call (no instance name string is specified there at all--only its class name string XHello). Its instance name is the same as the name of the application (specified on the command line): xhello.

To simplify resource specifications, a wildcard syntax may be used, specifying an asterisk instead of a dot, and omitting one or more terms of the fully qualified name. For example, as we've shown above:

*hello.labelString:  Hello, World!

or since there is no other Label widget in the application, even:

*labelString:  Hello, World!

If you specify a widget correctly and the resource name correctly, but provide an illegal value, the widget should display an error message: the Motif widget set is fairly thorough about this. But the resource manager (the part of Xlib that processes resource specifications) silently ignores resource specification errors of any kind, so they can be difficult to track down. The kinds of errors that are not reported include:

  • Misspelling any widget name or resource name.

  • Leaving out a level in the hierarchy when using the . (period) binding.

  • Setting a resource on a widget that doesn't exist.

  • Setting a resource that doesn't exist for the widget.

You should also be aware that widget classes can be used in resource specifications. For example, instead of setting the foreground resource of each PushButton widget one at a time using their widget instance names, they can all be set with one line using the widget class name in place of the instance name:

*XmPushButton.foreground:  blue

Because widget instance names take precedence over class names, however, one can override a class setting with a specific resource setting, by using a name for an individual widget instance. Therefore, you can set the foreground of all PushButtons to blue with one line, but then override that for one widget with one other line by setting the foreground using the widget's instance name.

Note that all resource specifications in files are given as strings, even though the data required for the resource may be of a different type. Xt automatically converts the string found in the resource database files into the appropriate destination type. For example, colors are specified as color names, which are automatically converted to the pixel values that are required for drawing. These converters are normally defined by Xt or the widget class.

Note also that in resource files, you and users specify the resource name as shown above. But in any Xt calls from source code, you always use symbolic constants of the form XmNresourceName (e.g., XmNforeground). (Standard Xt, as used for example with the Athena widget set, uses symbolic constants that begin with XtN instead.) Resource names are actually strings, and it improves compile-time checking to use symbolic constants instead of typing the string in directly.

The complete list of sources for resource database settings, the precedence rules used for establishing the actual resource value when there are conflicting settings in different database sources, and the mechanics of type conversion, are all described in detail in "Chapter 10, Resource Management and Type Conversion." (See also Chapter 10, Setting Resources, in Volume Three.) We'll also be returning to the topic of resources with each new example.

To Hardcode or Not to Hardcode

The resource settings you place in the app-defaults file for your application are, as the name suggests, only defaults. The user can place similar settings in a separate resource file, and these user settings override your app-defaults settings. This allows the user to customize the application.

There are pros and cons to applications that can be radically customized by the user through resources. The pros are quite clear:

  • A flexible application will meet the needs of a wider audience.

  • Users will have a wide variety of systems on which different colors and fonts will look best.

  • Users may have a special job in mind for which the application can be customized.

Some of the cons are that:

  • A user may make a mistake in the configuration that makes the application inoperable in some way.

  • Documentation and technical support become more difficult.

A partial solution is to document the default resource specifications and require that users reinstall those default specifications before a technical support person tries to solve their problems. In some cases, dialog boxes can be added that require the user to confirm any irreversible actions.

In any case, you may eventually want to hardcode certain resources in the application so that they are not user-configurable. This would be done for resources that, if set incorrectly, would make your application operate in an unsafe fashion. Hardcoding a widget resource is done by placing the resource name and the desired value in the final arguments to XtVaCreateManagedWidget() or XtCreateManagedWidget().

This technique is demonstrated later, because you won't need it until the later stages of developing your application. While an application is under development, it is better to leave as many resources as possible configurable from resource files, because this allows you to change them in the app-defaults file without recompiling the source.[20] When the code is stable and almost ready for release, then it's time to determine which resources need to be hardcoded, and then to hardcode them.

Connecting Widgets to Application Code

The Toolkit is designed so that the code that implements the user interface and the code that implements application features can be kept separate. This is an advantage, because it allows either part to be modified without affecting the other. However, these two pieces of code need to be intimately connected, because the user interface must drive the application code.

This section describes how to make this connection using callbacks. As mentioned earlier, the general idea is that the application registers functions to be called later by Xt in response to occurrences within certain widgets.

Callbacks are the method used when taking advantage of features of existing widgets. There are other methods, using actions in combination with translations or event handlers, but they are used primarily when adding functionality to widgets. The main purpose of actions is to modularize the code within a widget that responds to events. The use of actions in the application will be demonstrated in Chapter 4, "An Example Application" and in widget code in Chapter 6, "Inside a Widget."

A callback list is a widget resource. The application can add a callback routine to a widget using XtAddCallback() or XtAddCallbacks() only if the widget has declared a callback list as a resource. When a widget has a callback resource, it means that the widget writer foresaw that users of the widget would want to have application code called in response to a particular user behavior in that widget.

A widget class may have more than one callback resource. The Motif ScrollBar widget, for example, has eight, in addition to those defined by its superclasses Primitive and Core! Each callback resource represents a very specific occurrence in the widget. This allows you to specify a different function to handle each of these different occurrences. One of these resources, XmNpageIncrementCallback, is called when the user indicates that the information displayed should be paged down. XmNincrementCallback is similar but it indicates that the data should be moved a smaller amount. The purpose of the XmNpageDecrementCallback, XmNtoTopCallback, and XmNtoBottomCallback should now be obvious. Each of these callbacks indicates a different kind of user behavior, and requires a different kind of movement of the data in the associated window. The callback function registered with each of these callback resources would actually move the data in the various ways. All widgets also have the callback XmNdestroyCallback, which is called when the widget is destroyed.

Note that a callback function is registered for a specific callback resource and on a specific widget instance. Therefore, two widgets can have different functions registered for the same callback resource.

The next section describes how to use callbacks, since they are by far the more often used of the two techniques to link the user interface with application code. The use of actions is demonstrated in "Chapter 4, An Example Application."

Callbacks

To illustrate the use of callbacks from the application, we will write an application that uses the PushButton widget. Some analogue of this widget is present in every widget set. It contains a string or picture, and executes a command when a pointer button is clicked on it.

A PushButton widget calls an application function when you press and release the first pointer button (by default) in its window. When you press and hold the pointer button in the PushButton widget's window, the PushButton widget redraws the window in a slightly darker color, and swaps the colors of the two portions of the 3-D shadow surrounding the window. This gives the illusion that the button is actually being pressed into the screen. Moving the held button out of the window resets the widget without executing the command.

The xgoodbye program creates a single PushButton widget. It is very similar to xhello, but takes advantage of the callback provided by the PushButton widget. Clicking on the “Goodbye, Cruel World” button exits the program.

Figure 2-11 shows the window that xgoodbye creates if you have installed the suggested app-defaults file (otherwise, it will display “goodbye”). It is suggested that you compile and run xgoodbye.c, testing its response to moving the pointer in and out of its window, and clicking the various pointer buttons on its window.

Figure 2-11. The appearance of xgoodbye when the pointer is in the window

This example is not as frivolous as it seems. Many applications use code identical to this to implement their “Quit” button.

The code for xgoodbye.c is shown in Example 2-3.

Example 2-3. xgoodbye.c: complete code

/*
 * xgoodbye.c - simple program to put up a banner on the display
 *      and callback an application function.
 */

#include <stdio.h>
/*
 * Include file required for all Motif programs
 */
#include <Xm/Xm.h>  /* Standard Motif definitions */

/*
 * Public include file for widgets we actually use in this file.
 */
#include <Xm/PushB.h>    /* Motif PushButton Widget */

/*
 * Quit button callback function
 */
/* ARGSUSED */
void Quit(w, client_data, call_data)
Widget w;
XtPointer client_data, call_data;
{
    fprintf(stderr, "It was nice knowing you.\n");
    exit(0);
}

main(argc, argv)
int argc;
char **argv;
{
    XtAppContext app_context;
    Widget topLevel, goodbye;

        XtSetLanguageProc(NULL, (XtLanguageProc)NULL, NULL);

    topLevel = XtVaAppInitialize(
            &app_context,       /* Application context */
            "XGoodbye",         /* Application class */
            NULL, 0,            /* command line option list */
            &argc, argv,        /* command line args */
            NULL,               /* for missing app-defaults file */
            NULL);              /* terminate varargs list */

    goodbye = XtVaCreateManagedWidget(
            "goodbye",          /* arbitrary widget name */
            xmPushButtonWidgetClass, /* widget class from PushB.h */
            topLevel,           /* parent widget */
            NULL);              /* terminate varargs list */

    XtAddCallback(goodbye, XmNactivateCallback, Quit,
            0 /* client_data */);

    /*
     *  Create windows for widgets and map them.
     */
    XtRealizeWidget(topLevel);

    /*
     *  Loop for events.
     */
    XtAppMainLoop(app_context);
}

And here is xgoodbye's app-defaults file:

Example 2-4. XGoodbye: the app-defaults file

!
! Core resources
!
*goodbye.width: 200
*goodbye.height: 100
*goodbye.alignment: XmALIGNMENT_END
!
! Label resources
!
*goodbye.foreground: mediumblue
*goodbye.fontList: *courier-bold*180*iso8859-1
*goodbye.labelString:  Goodbye, Cruel World!

The differences between xgoodbye and xhello all apply to adding a callback function. In this example we have some application code (the Quit function) that we register with Xt as a callback function for the widget called goodbye using the XtAddCallback() call.

The Quit function is defined before main, so that we can use the function pointer Quit in the XtAddCallback() call. It is also legal in C to declare Quit as a function pointer early in the application, but actually to define it further down in the source code.

The XtAddCallback() call used to register Quit as the PushButton widget's callback is as follows:

XtAddCallback(goodbye, XmNactivateCallback, Quit, 0);

The first argument, goodbye, is the widget that is to trigger the callback. The second argument, XmNactivateCallback, is a symbolic constant that identifies which of the widget's callback resources is being set. (This constant, like almost all resource names in Motif, is defined in the file <Xm/Xm.h>. Other widget sets define resource name constants in the public header files of individual widgets.)

The third argument of XtAddCallback() is the function the widget is to call, and the last argument is any data to be passed to the callback function. No data is to be passed to Quit. Later on we'll show many examples where this argument is used to pass data.

The Quit function itself, like all callback functions, takes three arguments:

void Quit(w, client_data, call_data)
  • The first argument is the widget that triggered the callback, as specified as the first argument in XtAddCallback(). You would use the value of this argument in your callback function if you registered the same function as a callback for two different widgets, and if you wanted to distinguish in the callback which widget the user clicked on.

  • The second argument, client_data, is the value passed as the last argument of XtAddCallback(). This can be any data that you need in the callback function.

  • The third argument, call_data, is a piece of data passed from the widget. Some classes of widget set this argument, but others do not. The documentation for the widget will specify the contents of this data if it is used. The PushButton widget doesn't provide any call_data, but the ScrollBar widget, for example, passes back the current position of the thumb.

If you are intentionally not going to use one or more of these arguments, you should place the comment /* ARGSUSED */ on the line before the function. This prevents the C program checker lint from complaining about the unused arguments. The lint program can help you catch problems in your code that the C compiler can't detect. See the Nutshell Handbook Checking C Programs with lint for more details.

By convention, callback function names (and as you will see, action function names as well) are capitalized. This lessens the chance of collision with other variables names because callback functions are global in the source file. If this convention is not used, the most common collision is between callback functions and widget IDs of type Widget. It is tempting to call the quit callback function quit, and also to call the quit widget quit, but this will result in mysterious errors or a core dump. If you follow the convention that callback functions are given a capitalized name such as Quit, you avoid this potential problem.

More About Resources

You now have read about enough techniques to construct an application that uses widgets for its user interface and connects the widgets to application code. However, in order to really take advantage of any widget class, you have to learn about its resources, so that you can set the desired resources in the app-defaults file.

A class defines its own resources and also inherits the resources of all its superclasses. For example, PushButton supports not only its own resources but also the resources of its superclasses, Label, Primitive, and Core. The documentation for a widget class may describe only the resources for that class and list the name of the immediate superclass (which you can then look up), or it may list all the resources of that class and all superclasses.

Setting and Getting Resources from the Application

Resources are not just for customization of widgets at application startup. The application can change resources of widgets that have already been created, before or while the application is displayed. The application can also query the value of most resources. This section describes first how to set resources and then how to get them.

Setting resources is perhaps most often used for resetting strings in Label widgets. This can be very useful, but you should be aware that setting a resource from the application wipes out the app-defaults or user-specified value for that same resource (if any), unless you first query the resource, and then set it based on its earlier value. It is especially important not to hardcode strings if you want to be able to change the language used by the application simply by changing app-default files.

There are two parallel sets of functions that set or get resources. The two versions of each function have the same name except that one begins with XtVa and the other with Xt only. The arguments of both functions pass in or pass out resource name/value pairs, but they do it using a slightly different format of arguments. The XtVa style uses an ANSI C varargs list, which is a NULL-terminated list of resource name/value pairs. The Xt version takes an array of Arg structures (called an ArgList) and an array length. Each Arg structure contains a resource name/value pair. We will call these two styles the varargs style and the ArgList style.

The ArgList routines were the only interface until R4, and they can still be used. Using the ArgList form of call is slightly more efficient than the varargs form, since internally the varargs routines simply massage their arguments into the ArgList forms. However, the ArgList form is more verbose, hard to read, and error-prone, and lacks some of the features supported by the varargs form. The loss of efficiency of the varargs form is probably insignificant unless you depend on maximum speed in setting or getting resources many times in a loop. We use the varargs interface in most of this book, but will also show you how to use the ArgList form in the following sections so that you can understand existing applications written using them. Also, Motif provides only ArgList forms for some of its functions.

The following sections demonstrate how to set and get resources of an existing widget using the ArgList and varargs interfaces. The same form of arguments are used in many other functions that set resources, often while creating various types of widgets. Table 2-1 presents the parallel lists of Xt functions. The final arguments of all of these (many of which have not yet been described) are used in exactly the same manner as in the examples shown in Section 2.5.1.1, "Setting Resources with the Varargs Interfaces" and Section 2.5.1.2, "Setting Resources with the ArgList Interfaces."

Table 2-1. Functions that Set Resources: ArgList and varargs Counterparts

ArgList

Varargs

XtSetValues()

XtVaSetValues()

XtGetValues()

XtVaGetValues()

XtCreateWidget()

XtVaCreateWidget()

XtCreateManagedWidget()

XtVaCreateManagedWidget()

XtAppCreateShell()

XtVaAppCreateShell()

XtGetSubresources()

XtVaGetSubresources()

XtGetApplicationResources()

XtVaGetApplicationResources()

XtCreatePopupShell()

XtVaCreatePopupShell()

XtSetSubvalues()

XtVaSetSubvalues()

XtGetSubvalues()

XtVaGetSubvalues()

XtAppInitialize()

XtVaAppInitialize()


Setting Resources with the Varargs Interfaces

The easiest way to set and get resources is to use the Xt functions XtVaSetValues() and XtVaGetValues(). Each of these functions takes a widget argument and a variable length list of resource name/value pairs, terminated by NULL. These interfaces are new to R4.

Note that the resource to set is called XmNlabelString, and its value must be a special type called a compound string, represented by a structure of type XmString. A single compound string can be multi-lingual, multiline, and multifont. A compound string contains a string, a character set, and a draw direction (left to right or right to left). The strings we specified in the app-defaults files for xhello and xgoodbye were automatically converted into compound strings by Xt. However, to set a string in the application code, we must do this conversion ourselves. This is done easily with the Motif function XmStringCreateLocalized(). (Motif also provides numerous other functions for manipulating compound strings.) XmStringCreateLocalized() replaces XmStringCreateSimple() which was used in Motif 1.1. XmStringCreateLocalized() interprets its string argument in the user's locale (the user's language and culture, usually based on data from files defined by ANSI-C). Therefore, all strings should be read from the resource database or from files, not defined in the code. For simplicity, however, we have shown the strings defined in the code.

Example 2-5 shows the code needed to change the string of a Label widget--this will work any time after the widget has been created, either before or after the widget is realized.

Example 2-5. Using XtVaSetValues to set a widget resource

static String new_label = "Hi there."
XmString text;
    .
    .
    .
text = XmStringCreateLocalized(new_label);
XtVaSetValues(w,                       /* widget being modified */
        XmNlabelString, text,          /* resource setting */
        XmNalignment, XmALIGNMENT_END, /* resource setting */
        NULL);                         /* terminate varargs list */
XmStringFree(text);

Note that a single XtVaSetValues() call can set any number of resources of a single widget instance. This example also changes the justification of the string (which by default is centered). (In order for justification to appear, the widget must be wider than the string being displayed. This can be arranged with the resource setting *hello.width: 400.)

The resource names used in the above example are XmNalignment and XmNlabelString. The include file <Xm/Xm.h> contains these resource name symbolic constants. Resource names are actually strings. These strings are stored in symbolic constants to improve compile-time checking. If you misspell a symbolic constant, the compiler will note the error. If you misspell a string, on the other hand, the error will go unnoticed by the compiler and go unnoticed at run time as well, but the resource setting will do nothing. Therefore, all resource names are specified using constants of the form XmNname, where name is the resource name.

When you use a widget set other than Motif, you include <X11/StringDefs.h> instead of <Xm/Xm.h>. In StringDefs.h the same set of strings are given symbolic constants that begin with XtN. Motif has redefined these symbols just so that all its symbols and functions begin with Xm.

Also note that the value specified for each resource setting must be the type expected by the widget for that resource, or an error will occur. In this case, the type is XmString. If you were to attempt to pass a normal char * as the value, the widget would report the error at run time. In XtVaSetValues() calls (and XtSetValues() calls described in the next section), conversion from strings to the appropriate type does not happen automatically as it does for settings in resource files. However, you can arrange for it to happen by placing special arguments in the XtVaSetValues() call, as described in Section 3.8.2, "Using the Argument List Interfaces." (Note that this is a feature of the varargs interfaces that is not supported by the ArgList interfaces.)


Note: Don't set resources of type float using the XtVaSetValues() interface. On some systems float is widened to double (as specified in the Kernighan & Ritchie C manual). When this widening occurs, half the bytes are read by the Intrinsics as a float, and the next 4 as the string name of another resource. This can point into invalid memory, and cause a segmentation fault. Use XtSetArg() and XtSetValues() to avoid the problem. However, since the value field of the Arg is a long which may not be the same size as a float, use the following approach:
    Arg arg;
    union {
        int    int_value;
        float    float_value;
    } value;
    value.float_value = 3.2;
    XtSetArg (arg, "name", value.int_value);


Setting Resources with the ArgList Interfaces

As mentioned above, the use of the ArgList interfaces is less elegant than the varargs interfaces just described, and ArgList interfaces lack the ability to use Xt's value conversion mechanism. However, the ArgList interfaces were the only interfaces until R4, and therefore are used in most existing applications. Example 2-6 shows how to set resources using XtSetValues().

Example 2-6. Using XtSetValues to set a widget resource

Arg arg;
static String new_label = "Hi there."
XmString compound;
    .
    .
    .
compound = XmStringCreateLocalized(new_label);
XtSetArg(arg, XmNlabelString, compound);
XtSetValues(w, &arg, 1);
XmStringFree(compound);

The Arg type is defined as a structure containing the name and value pair that defines a resource:

typedef struct {
    String      name;
    XtArgVal    value;
} Arg, *ArgList;

The definition of XtArgVal differs depending on architecture--its purpose is precisely to make code portable between architectures with different byte sizes. Its use in application code is demonstrated in Section 3.8.2, "Using the Argument List Interfaces." All resource values (in all varargs and ArgList calls) are limited to the size of XtArgVal, which is the largest of char *, caddr_t, long, int *, and proc *. This means that for larger pieces of data, a pointer must be used. For example, data of type float or double must be passed as pointers. The documentation for a widget class that declares a resource with a large value should document the fact that a pointer must be passed rather than the value itself.

XtSetArg() is a macro that makes it more convenient to set the two members of the Arg structure. If desired, you can also set the Arg structure members like any other C structure by using the . or -> syntax.

Note that the first member of Arg is of type String, but should be set to one of the XmN resource name constants.

XtSetValues() is the call that actually changes the widget resource. You pass it the widget to be reconfigured, a list of Arg structures, and the length of the list. Example 2-6

XtSetValues() can set any number of resources of a single widget instance. Example 2-7 shows the code necessary to set two resources. Compare this to Example 2-5 to see how much clearer the varargs interfaces are.

Example 2-7. Code fragment to set multiple resources of a widget

static String new_label = "Hi there."
XmString compound;
Arg args[3];
int i;
    .
    .
    .
compound = XmStringCreateLocalized(new_label);
i = 0;
XtSetArg(args[i], XmNalignment, XmALIGNMENT_END);  i++;
XtSetArg(args[i], XmNlabelString, compound);  i++;
XtSetValues(w, args, i);
XmStringFree(compound);


Note that the counter i cannot be incremented inside the XtSetArg() macro, because that macro references its first argument twice. Therefore, the counter is customarily incremented on the end of the same line, so that additional resource settings can easily be added.

Getting a Resource Value

It is also useful to be able to get the current value of a widget resource. One use of this is in finding out what value the user has specified for a particular resource, so that it can be modified with application data. Because C-Language arguments are passed by value, and some resource values are not actual values but pointers to them, it is important to thoroughly understand pointers while getting widget values. Example 2-8 shows how to get a pointer to the current string in a Label widget, using the varargs interface. This has to be done in two steps: first query the XmNlabelString resource to get the compound string, and then extract the character array from the compound string. Querying other resources is easier.

Example 2-8. Code fragment to get a widget resource using XtVaGetValues

#define MAXLEN 256
        .
        .
        .
    Widget hello;
    String p;         /* NOTE - memory for array not allocated */
    XmString      compound;
        .
        .
        .
    /* XmLabel widget named hello created here. */
    XtVaGetValues(hello,
            XmNlabelString, &compound,
            NULL);
    (void) XmStringGetLtoR(compound, XmFONTLIST_DEFAULT_TAG, &p);
    XmStringFree(compound);
    /* use string p */
    XtFree(p);


The type String is defined by Xt to be char *. In the Athena widgets, a string queried from a resource must not be modified or freed by the application, since it points directly to private widget data. In Motif, the compound string returned from XtVaGetValues() (or XtGetValues(), of course) should be freed after use with XmStringFree() or XtFree() (they are equivalent), since Motif widgets pass a pointer to a copy of the resource value stored in the widget, not to a pointer to the widget's internal data.

Example 2-9 shows how to query a widget resource using the ArgList interface, XtGetValues().

Example 2-9. Code fragment to get a widget resource using XtGetValues

#define MAXLEN 256
        .
        .
        .
    Widget hello;
    Arg arg;
    String p;    /* NOTE - memory for array not allocated */
    XmString compound;
            NULL);
        .
        .
        .
    /* Label widget named hello created here. */
    XtSetArg(arg, XmNlabelString, &compound);
    XtGetValues(hello, &arg, 1);
    (void) XmStringGetLtoR(compound, XmFONTLIST_DEFAULT_TAG, &p);
    XmStringFree(compound);
    /* use string p */
    XtFree(p);


Note, however, that some resources are not designed to be queried. For example, translation tables and callbacks are compiled into an internal representation, so it is pointless to try to read them.

Core Resources

The most basic widget class defined by Xt is Core. All widgets are subclasses of Core. Therefore, the resources of the Core class are available for all widgets. Table 2-2 shows the Core resources. Note that the resource name constants all begin with Xm. These constants are defined in the file <Xm/Xm.h>. In standard Xt, the resource name constants begin with Xt, and are defined in <Xt/StringDefs.h>.

Table 2-2. Core Resources

Name

Type

Default

XmNx

Position

0

XmNy

Position

0

XmNwidth

Dimension

0

XmNheight

Dimension

0

XmNscreen

Pointer

from Display

XmNcolormap

Pointer

from parent

XmNdepth

int

from parent

XmNbackground

Pixel

White

XmNbackgroundPixmap

Pixmap

NULL

XmNborderWidth

Dimension

1

XmNborderColor

Pixel

Black

XmNborderPixmap

Pixmap

NULL

XmNtranslations

XtTranslations

NULL

XmNaccelerators

XtTranslations

NULL

XmNmappedWhenManaged

Boolean

True

XmNdestroyCallback

Pointer

NULL

XmNsensitive

Boolean

True

XmNancestorSensitive

Boolean

True


The fact that size and position are resources of all widgets means that your app-defaults file can control the layout of the application. You should always resize widgets by setting these resources--never resize or move a widget's window using Xlib calls since this would make Xt's knowledge of window geometries inaccurate. Nor should you use the Xt functions XtConfigureWidget(), XtMoveWidget(), or XtResizeWidget() from the application. These routines are intended to be used only by geometry-managing composite widgets.

The XmNscreen, XmNcolormap, and XmNdepth resources hold the default screen, colormap, and depth (the number of bits per pixel used for indexing colors in the colormap). The top-level shell widget gets the screen from the DISPLAY environment variable or -display command-line option; other widgets inherit that value and cannot change it. The top-level shell widget gets the root window's depth, visual, and default colormap; other widgets inherit these attributes from their parent, so unless an intervening widget has set these attributes differently, a widget will inherit the root window's attributes by default. Normally you will set the depth, visual, and colormap resources only on Shell widgets and only when your application has special color requirements.

The XmNbackground, XmNbackgroundPixmap, XmNborderWidth, XmNborderColor, and XmNborderPixmap widget resources control the background and border of the window created by a widget. The background and border of a window are maintained by the X server, and setting these resources causes an immediate change in the window on the screen. You can set either a background color or a background pixmap, but not both. Whichever is set later takes priority. The same applies to the border. Details on the possible values to which these may be set are in Chapter 4, "Window Attributes" of Volume One.

A pixmap is similar to a window but is off-screen. It is an array of pixels. When used as a background or border, a pixmap is tiled by laying out multiple copies of it side by side, for the purpose of patterning. Pixmaps are also used for icon patterns, in drawing, and as a temporary drawing surface later copied to a window.

The XmNbackground and XmNborderColor resources can be set using either a color name string or a hexadecimal color specification. (See "Appendix B," for more information on acceptable forms of color specification.)

The value of the XmNbackgroundPixmap and XmNborderPixmap resources should be a pathname to a file containing the bitmap, or to a bitmap created in your program. On UNIX systems, standard X bitmaps are stored in the directory /usr/include/X11/bitmaps. See Appendix C in Volume Three, for information on these standard bitmaps.

XmNtranslations is the resource that contains the translation table that maps events into actions. As is described exhaustively in "Chapter 8, Events, Translations, and Accelerators," by setting this resource you can change the events that trigger a widget's actions or the actions your application has registered. XmNaccelerators contains an accelerator table. (Accelerators are an extended form of translations that allow events in one widget to be bound to actions in another.)

XmNmappedWhenManaged is a resource used by geometry-managing widgets to specify whether a widget should be eligible for display (i.e., mapped to the screen) as soon as it is placed under parental geometry management, or whether this should not happen until some later time. We'll talk more about this concept in "Chapter 12, Geometry Management."

The XmNdestroyCallback resource, as mentioned in Section 2.4.1, "Callbacks" above, lets you provide an application function to be called when a widget is destroyed. This is infrequently used, since the Toolkit normally handles the job of freeing widget data structures and any server resources.

The XmNsensitive resource controls whether a widget responds to user input. This allows you to turn on or off user input in a certain widget at will. For example, if you have a PushButton widget whose command is not allowed at certain times, you would set XmNsensitive to False during the period the command is not allowed. The PushButton widget changes its own look to indicate that it is invalid.

The XmNancestorSensitive resource specifies whether the widget's parent (or earlier ancestor) is sensitive. Sensitivity is automatically propagated downward, such that if any ancestor is insensitive, a widget is insensitive. This resource rarely needs to be set, but is sometimes useful to query.

Other Inherited Resources

Besides the resources inherited from Core, a widget inherits resources from each of its superclasses. For example, the PushButton widget used in xgoodbye inherits resources from its superclass, the Label widget class, and from Label's superclass, Primitive. As shown in Table 2-3, these include, in addition to the label itself, a font list, a foreground color, spacing above and below the string, and a value specifying how the string should be placed in the widget. (Note that there are many other resources not listed.)

Table 2-3. Label Resources

Name

Type

Default

XmNfontList

XmFontList*

the default font

XmNforeground

Pixel

XmForegroundColorDefault

XmNhighlightOnEnte r

Boolean

False

XmNmarginHeight

Dimension

2 (pixels)

XmNmarginWidth

Dimension

2 (pixels)

XmNalignment

unsigned char

XmALIGNMENT_CENTER

XmNlabelString

XmString (compound)

NULL


It is a worthwhile exercise to experiment with the resources available to an application through its widgets, even with such a simple example as xgoodbye. For example, consider the resource settings for goodbye shown in Example 2-10.[21]

Example 2-10. Alternate resource settings for xgoodbye

! Core resources
!
! The following two lines don't work, but demonstrate a point
*goodbye.x: 100
*goodbye.y: 100
!
! Even though the following specification syntactically applies to
! all widgets in the application, and all windows have borders, the
! borderWidth resource value is only used by certain widgets.
! PushButton is not one of them, so this instruction is ignored.
!
*borderWidth: 10
!
*goodbye.width: 250
*goodbye.height: 100
*goodbye.alignment: XmALIGNMENT_END
!
! Label resources
!
*goodbye.foreground: red
*goodbye.fontList: *courier-bold*180*iso8859-1
*goodbye.labelString:  Click on me.

Note that an exclamation point (!) in column zero begins a comment line in a resource file. The number sign (#), the standard UNIX comment symbol, should not be used.

These settings can either be placed in an .Xdefaults file in your home directory, or you can save them in any file you like and load them into the server using the xrdb client, as follows:

xrdb -merge resource_file

(If you want to repeat the experiment with different values, you should be aware that once resources are set with xrdb, they remain in effect. Subsequent invocations of xrdb -merge will replace settings for the same resources, but won't remove any others that were set before. To start with a clean slate, use xrdb -load instead. Note, however, that this will replace all of your resource settings, including those for other applications. See Chapter 10, Setting Resources, of Volume Three, for more information on using xrdb. See Chapter 10 of this book for more information on other possible sources of resource settings.)

The window that results when you run xgoodbye with these resource settings is shown in Figure 2-12.

Figure 2-12. xgoodbye run with new resource settings

If you spend some time playing with different resource settings, you will find some unexpected behavior. For instance, setting the value of the x and y resources has no effect. Regardless of their value, the xgoodbye application is simply placed at the current pointer position.

The reason for this is that these resources set the widget position relative to its parent, and since the goodbye widget is a child of an identically sized Shell widget, they are meaningless. In its geometry-management policy, the shell widget ignores the value of these resources.

If instead you use the x and y resources to try to set the position of the application:

xgoodbye.x:  100
xgoodbye.y:  100

they are ignored also, for a similar reason. It is customary for the window manager to assert control over the position of the main application window (in this case the Shell widget goodbye), and take the value of these resources, whether set by the application or by the user, simply as “hints” to the desired behavior. There is no guarantee that the window manager will honor these hints. The application is generally free to move widgets within its own window, but not to move itself. The basic X philosophy is that the user (through the window manager), not the application, should be in control. (Kill the window manager, or run a window manager that honors application position hints, and the resource specifications shown just above will work.)

Likewise, you will find that specifying:

*goodbye.borderWidth:  10

has no effect, while:

*borderWidth: 10

works. The reason for this behavior is that while the PushButton widget inherits the borderWidth resource from Core, it does nothing with its value. Only certain widget classes (Shells) use the borderWidth resource to set the border width of their window. Just because a resource is inherited by a widget does not mean that the widget's methods do anything to use its value.

Another surprising fact appears if you set the foreground resource to the same color as the background. No text appears in the window, and it does not highlight itself when you move the mouse inside. However, if you click a button, you will find that the widget is still working. What is happening is that the background and foreground colors are now both white, and therefore there is no contrast with which to see the widget's drawing. The widget is not sophisticated enough to check that its two colors are not the same. (Adding this simple check would be easy, but it is much more difficult to tell whether two colors that are not the same contrast enough.)

The cautionary point is that there may be unexpected interactions between resources in widget code. Like programs in general, widgets tend to do what you say, not what you mean. A well-designed widget will minimize ill effects, but given the amount of customization that is possible, it may take some time to uncover all the possible pitfalls. Unfortunately, the documentation for most existing widgets doesn't always do a good job of explaining how resources are used inside the widget.

Advice on X Programming

The X Window System is a very complex collection of software, not to try your patience, but to do things that no programming tools have done before. Not only does X provide tools to build a nice user interface, but it does so with network transparency, so that programs can run on any hardware and operating system and display on any other.

Probably the best feature of all from the application developer's point of view is the portability of the source between hardware and operating systems. It is worth a lot of aggravation to be able to write just one version of a piece of software, and have it able to compile and run on anything from a PC-compatible to a Cray.

The price you pay for these features is additional complexity. The key to programming X successfully is to keep things as simple as possible by keeping this complexity hidden.

By choosing to use Xt and Motif, you have taken a first step to isolate your application from the details of the lower levels of X software. In general, use the highest-level tools available. Use Motif functions instead of Xt functions when equivalents are available, and Xt functions instead of Xlib functions.

Also beware of configuring widgets too extensively. Every widget has many resources, and the number of possible permutations in even one widget makes it impossible for OSF to test them exhaustively. At the same time, programmers tend to abuse this flexibility by overly configuring widgets. Often developers try to make Motif applications work in a particular way that Motif's developers didn't intend or foresee. One way to avoid this problem is to make sure your intended interface conforms to the conventions specified in the OSF/Motif Style Guide.

Although Motif will undoubtedly be improved to support even more varied interfaces, this will take time, and there will always be features that Motif will not support without contortions. If you can compromise a little on the details of how your interface should work, you will be better off. With Motif, you can get 90 percent of what you want in a very short time. Think twice before spending lots of time trying to get the last 10 percent. First think if there is some other user interface design that can fulfill your needs while being more consistent with Motif style. If you still insist on having that functionality, think carefully about the best way to implement it (and consult with someone who knows X intimately, because such a decision may require an understanding of Motif, Xt, and the lower levels of X).

To be advised to compromise in this fashion may rub some programmers the wrong way. Most programmers program systems where they have total control over their environment. Many have the whole screen to play with, and worry about only one target system. In these environments, it is more practical to learn everything there is to know about the system, so that you can implement exactly what you want. Since X is a much larger piece of software than the operating system or toolbox of any one computer, it is less practical to obtain a complete understanding of every level of it. That's why it is better to use your creativity to design a good interface that can be implemented easily, using existing components in the ways they were designed to be used.

Debugging Xt Applications

Debugging Xt applications can be difficult because errors caused by your code can end up causing the program to abort somewhere deep in the Xt Intrinsics. There are, however, several techniques that can help.

One problem is that the standard error handlers exit so that you won't get a stack trace to tell you where the problem occurred. The workaround is to register your own Xlib and Xt error handlers that divide by zero after reporting the error (instead of exiting). See Chapter 14, "Miscellaneous Toolkit Programming Techniques" for information on registering Xt error handlers, and Volume One, Xlib Programming Manual for Xlib error handlers.

If your application generates X protocol errors, then the problem is probably Xlib calls with improper arguments. Because of the asynchronous X protocol, the program will not exit at the error in the code. By running the application with the -sync command-line option, Xlib operates in synchronous mode and Xlib errors are reported immediately.

The editres application is useful for debugging widgets, testing resource settings, and for viewing the widget hierarchy of complex applications. The uses of the editres application are described in Chapter 14.

You are not normally allowed to see the data stored inside widget data structures. But you can view the data from a debugger if you specify the private header file for the widget in your source file. For example, instead of including <Xm/Xm.h> and <Xm/XmPushB.h> in xhello.c, we would include <Xm/XmP.h> and <Xm/XmPushBP.h>.

Finally, an integrated code development and debugging environment such as CodeCenter is invaluable in writing toolkit application and finding bugs in them.



[7] The Shell widget is actually a type of composite widget, which is designed to have only one managed child widget. Its layout policy is extremely simple. It just makes its child widget exactly the same size as itself.

[8] The Athena widgets are described on reference pages in Volume Five.

[9] The names of all Motif widget classes actually begin with Xm. However, to make the text more readable, we have omitted the Xm prefix when referring to these widgets, except in examples and discussions of code where the prefix must actually be used.

[10] Note that the X Toolkit supports only single inheritance. That is, characteristics can be inherited directly from only one superclass (though that superclass may itself have inherited characteristics from prior superclasses). A widget class can inherit only from the classes on a direct path upward from the class to Core.

[11] There are several possible sources of resource settings. If two or more contain resource settings for the same resource of the same widget, which will actually take effect is determined by rules of precedence that are described (along with the various sources of resource settings) in "Chapter 10, Resource Management and Type Conversion."

[12] Redrawing is necessary because the contents of X windows are maintained by the X server only while they are visible. When one window is obscured by another, the contents of the obscured area of one of the windows is lost and must be redrawn when it later becomes exposed. X clients are responsible for redrawing the contents of their windows when this happens. Fortunately, Xt automatically redraws correctly written widgets at the appropriate times so that your application doesn't have to worry about this.

[13] In a language designed for OOP, such as C++, these shortcuts are generally prevented by the compiler or by the language itself.

[14] In X Protocol terms, the setup phase consists of requests to the server that are generally long, and often require immediate replies, which tends to slow performance. The event loop phase, on the other hand, generally consists of short requests and very few “round-trip” requests. For a full description of this concept, see the introductory chapter to Volume Zero.

[15] The instance names for widgets need not be unique. However, if they are not unique then resources can only be set on all widgets with the same name at once. Instance names can also be “”, but then resources cannot be set at all. Instance names that include a period cannot be set from resource files.

[16] A widget is a client-side object. It has no presence on the server other than as a normal X window. The Xt and widget set libraries running on the client side maintain the data that allow programs to work with the abstraction perceived as a widget.

[17] There are several other conditions that can prevent or delay a window from becoming visible, described in Section 2.2.4, "Mapping and Visibility" of Volume One. These will not affect your Toolkit application as long as you draw into windows at the right times, using one of the techniques described in Section 4.2, "xbitmap2: Adding Graphics to Display the Bitmap" and Section 7.3, "The expose Method."

[18] On Sun systems under OpenWindows the default location for the app-defaults files is the /usr/openwin/lib/app-defaults directory. On all systems Xt provides a mechanism that allows you to provide a different app-defaults file for each language. This will be described in "Chapter 10, Resource Management and Type Conversion."

[19] Note that existing applications do not always follow this latter convention. For example, the app-defaults file for xmh is called Xmh, not XMh.

[20] There are a few resources in Motif that currently cannot be set from resource files. OSF may correct this in later releases.

[21] See Appendix B, Specifying Fonts and Colors, for more information on the font resource specification shown in the example.