Contents Previous Next

4 Overview of the Motif Toolkit


This chapter helps the reader understand the components of a real Motif application. It discusses how to handle the geometry management of primitive widgets within a manager widget, when to put components into the main window, when to use dialog boxes and menus, and how to relate to the window manager. After reading this chapter, the programmer should have a solid overview of Motif application programming, and she should be able to read the remaining chapters in any order.

In Chapter 2, The Motif Programming Model, we talked about the basic structure of an Xt-based program. We described how to initialize the toolkit, create and configure widgets, link them to the application, and turn control over to Xt's main loop. In this chapter, we discuss the widgets in the Motif toolkit and how you can put them together to create an effective user interface for an application.

If you already have a basic understanding of the Motif widgets, you can jump ahead to any of the later chapters in the book that focus on individual widget classes. This chapter provides some insight into the design of the widgets and a general overview of the Motif style and methodology, which you may find useful when developing your own applications.

This chapter also describes all of the new features in Release 1.2 of Motif. If you are familiar with Motif 1.1 but need to get up to speed with Motif 1.2, you should read Section #smotif12. In this section, we summarize the new features and tell you where to find more information about them. We also describe all the changes made to the example programs in this book to make them up-to-date with Motif 1.2. While Motif 1.2 is backwards-compatible with Motif 1.1, there are a number of functions and resources in Motif 1.2 that replace obsolete functions and resources in Motif 1.1.

4.1 The Motif Style

You don't build a house just by nailing together a bunch of boards; you have to design it from the ground up before you really get started. Even with a prefabricated house, where many of the components have already been built, you need a master plan for putting the pieces together. Similarly, when you are designing a graphical user interface for an application, you have to think about the tasks your application is going to perform. You must envision the interface and then learn to use your tools effectively in order to create what you've envisioned.

The Motif toolkit provides basic components that you can assemble into a graphical user interface. However, without design schematics, the process of assembling the user-interface elements may become ad hoc or inconsistent. Here is where the Motif Style Guide comes in. It presents a set of guidelines for how widgets should be assembled and grouped, as well as how they should function and interact with the user.

All Motif programmers should be intimately familiar with the Style Guide. While we make recommendations for Motif style from time to time, this book is not a replacement for the Style Guide. There are many aspects of Motif style that are not covered in detail here, as they involve the content of an application rather than just the mechanics. On the other hand, the Motif Style Guide is not an instructional manual for the Motif toolkit. In fact, many of the objects described in the Style Guide are not even widgets, but higher-level, more complex objects that are composed of many widgets.

For example, the Style Guide describes an object called a MenuBar, which spans the top of the main window of an application. The MenuBar contains menu titles that, when clicked on, display PulldownMenus. The Motif toolkit does not implement MenuBars or PulldownMenus as distinct widget classes, nor does the Style Guide make any recommendations about how menu objects should be implemented. What the Style Guide does talk about (albeit somewhat loosely) is the actions that can be taken by an item on a menu: it can invoke an application function, pop up a dialog box containing yet more options and commands, or display a cascading menu (also known as a pullright menu).

The Style Guide also makes recommendations about the menus that an application should provide. For example, most applications should have a File menu that provides items such as an Exit button to exit the application and a Save button to save file. It also specifies details of presentation, such as that you should provide an ellipsis (...) as part of the label for a menu item that requires the user to provide more information before action is taken.

How the Motif toolkit goes about supporting, and in some cases enforcing, the guidelines of the Motif Style Guide brings up some interesting points, particularly in relation to some of the underlying principles of the X Toolkit Intrinsics. In Xt, a widget is envisioned as a self-contained object that is designed to serve a specific, clearly-defined function. Many of the Motif widgets, such as Labels, PushButtons, ScrollBars, and other common interface objects, are implemented as separate widgets.

In other cases, however, Motif steps outside of the Xt model by creating compound objects out of several widgets and then expecting you to treat them as if they were a single object. For example, Motif provides the ScrolledText and ScrolledList objects, which combine a Text or List widget with a ScrolledWindow widget, which in turn automatically manages horizontal and vertical ScrollBars.

In another case, the Motif toolkit provides a complex, general-purpose widget that can be configured to appear in several guises. There is no MenuBar widget class and no PulldownMenu widget class. Instead, the RowColumn widget, which also serves as a general-purpose manager widget, has resources that allow it to be configured as either a MenuBar or a PulldownMenu pane. Those familiar with Xt may find this widget design to be a breach of Xt's design goals, though.

In order to allow the programmer to think of ScrolledText objects, MenuBars, and PulldownMenus as distinct objects, the Motif toolkit provides convenience creation functions. These routines make it appear as though you are creating discrete objects when, in fact, you are not. For example, XmCreateMenuBar() and XmCreateSimplePulldownMenu() automatically create and configure a RowColumn widget as a MenuBar and a PulldownMenu, respectively. There are also convenience routines for creating various types of predefined dialog boxes, which are actually composed of widgets from four or five separate widget classes.

Convenience routines emphasize the functional side of user-interface objects while hiding their implementation. However, since Motif is a truly object-oriented system, it behooves you to understand what you're really dealing with. For example, if you want to use resource classes to configure all MenuBars to be one color and all PulldownMenus another, you cannot do so because they are not actually distinct widget classes. The class name for both objects is XmRowColumn.

In the remainder of this chapter, we look at Motif user-interface objects from the perspective of both the functional object illusion and the actual widget implementation. In the body of the book, we use the Motif convenience routines for creating most compound objects, but stick to the underlying Xt routines for creating simple widgets or gadgets. With the compound objects, we show you how to pierce the veil of Motif's convenience functions and work directly with the underlying widgets when necessary. the figure shows the entire class hierarchy of the Motif widget set.

figs.eps/V6a.03.01.eps.png
The class hierarchy of the Motif widget set


We begin by taking a closer look at the Motif user-interface components with which the user typically interacts. Then we examine how the manager widget classes are used to arrange the more visible application controls. And finally, we explore the use of all of these objects to create functional windows and dialogs that make up a real application.

4.2 Application Controls

In many ways, application controls are the heart of a graphical user interface. Rather than controlling an application by typing commands, the user is presented with choices using graphical elements. The user no longer needs to remember the syntax of commands, since her choices are presented to her as she goes along. As we've discussed, some of Motif's application controls (such as menus) are compound objects assembled by convenience routines. Others are simple, single-purpose widgets that you can create directly.

The widgets in this latter group are collectively referred to as primitive widgets -- not because they are simple, but because they are designed to work alone. The contrast is not between primitive and sophisticated widgets, but between primitive and manager widgets. Some of the primitive Motif widget classes have corresponding gadget classes. The following sections describe the different types of primitive application controls available in the Motif toolkit.

The compound objects in the Motif toolkit are composed of primitive widgets and gadgets. Because an understanding of these objects relies on an understanding of the primitive widgets, as well as the Motif manager and shell widgets, we are going to postpone discussing compound objects until later in the chapter.

4.2.1 The Primitive Widget Class

The Primitive widget class is a superclass for all of the Motif primitive widgets. This widget class is a metaclass; it serves only to define certain common behavior used by all its sub­classes, so one never instantiates a widget directly from the Primitive class. This statement is somewhat like saying that hammer is a class of object, but that you never really have a ­generic hammer. You can only have a specific type of hammer, like a claw hammer, a ball peen hammer, or a sledge hammer. A claw hammer has the prongs in the back behind the hammer-head that allow you to pull nails out of a wall; a ball peen hammer has a round corner where the claw would be otherwise be; a sledge hammer is the large, heavyweight hammer used to drive thick nails through concrete or to destroy things.

Just as all hammers have particular characteristics that qualify them as hammers, the Primitive widget class provides its subclasses with common resources such as window border ­attributes, highlighting, and help with keyboard traversal (so the user can avoid the mouse and navigate through the controls in a window using the keyboard). The actual widget classes that you use are subclassed from the Primitive class, as shown in the figure.

figs.eps/V6a.03.02.eps.png
The Primitive widget class hierarchy

The Primitive class itself inherits even more basic widget behavior from the Xt-defined Core widget class, which establishes the basic nature of "widgetness." The Core class provides widgets with the capability to have windows and background colors, as well as translations, actions, and so on. You could actually use a simple Core widget as an instance and define your own translations and action routines, although this technique is not used frequently. Complete details are provided in Volume Four, X Toolkit Intrinsics Programming Manual. The Label widget provides a visual label either as text or as an image in the form of a Pixmap. The text of a Label is an XmString, or compound string, not a character string (char*). A compound string can be oriented from left-to-right or right-to-left and it can also contain multiple lines and multiple fonts. Chapter 19, Compound Strings, discusses functions that manipulate compound strings, as well as functions that convert between character strings and compound strings.

The Label widget does not provide any callback routines, since it does not have any specified behavior. Using Xt, you could install event translations and action routines to make a Label respond to user input, but the Label widget is not intended to be used this way. It is only meant to be used to display labels or other visual aids. In Motif 1.2, instances of Label and all of its subclasses are automatically registered as drag sources for drag and drop operations by the toolkit.

Label widgets are described in detail in Chapter 11, Labels and Buttons. the figure displays a single Label widget with multiple lines and multiple fonts.

figs.eps/V6a.03.03.eps.png
A Label with multiple lines and fonts

The PushButton widget supports the same visual display capabilities as a Label, since it is subclassed from Label. In addition, the PushButton provides resources for the programmer to install callback routines that are called when the user arms, activates, or disarms the button. The PushButton also displays a shadow border that changes in appearance to indicate when the pointer is in the widget and when it has been activated.

When a PushButton is not selected, it appears to project out towards the user. When the pointer moves into the button, its border is highlighted. When the user actually selects the button by pressing the first mouse button on it, the button appears to be pushed in and is said to be armed. The user activates a PushButton by releasing the mouse button while the button is armed. PushButton widgets are also covered in detail in Chapter 11, Labels and Buttons . the figure shows some examples of PushButtons.

figs.eps/V6a.03.04.eps.png
PushButton widgets

The DrawnButton widget is similar to a PushButton in its functionality and its three-dimensional appearance. However, the DrawnButton is used when an application wants to draw the text or image directly into the widget's window, rather than have the widget handle the drawing. If the image is dynamic and changes frequently during the course of an application, you may want to handle the drawing yourself. The DrawnButton provides additional callback resources that are called when the button is resized or exposed and additional ways to draw an outlined border. The DrawnButton widget is discussed in Chapter 11, Labels and Buttons. the figure shows some DrawnButtons.

figs.eps/V6a.03.05.eps.png
DrawnButtons widgets

The ToggleButton widget displays text or graphics like a Label widget, but it has an additional indicator graphic (a square or diamond shape) to the left of the label. The indicator shows the state of the ToggleButton: on or off. When the ToggleButton is on, the indicator is colored and appears to be pushed in. When the button is off, the indicator appears to project outward. The ToggleButton provides a additional resource for specifying a callback routine that is called when the user changes the state of the ToggleButton.

One common use of ToggleButtons is to set the application state. In this case, the callback routines typically set simple Boolean variables internal to the application. ToggleButtons can also be arranged in two different kinds of groups. In one configuration, known as a RadioBox, only one button in the group of buttons can be chosen at a time. The other configuration, a CheckBox, allows the user to select any number of buttons. When ToggleButtons are grouped as a RadioBox, the indicators are diamond-shaped; otherwise, they are square-shaped. ToggleButton widgets are described in detail in Chapter 11. the figure shows the two different ways that ToggleButtons can be grouped.

figs.eps/V6a.03.06.eps.png
ToggleButtons in a CheckBox and a RadioBox

The CascadeButton widget is a special kind of button that is used to pop up menus. A CascadeButton can only be used as a child of a RowColumn widget, such as: in a MenuBar as the title of a PulldownMenu, in a PulldownMenu pane as an item that has a cascading menu associated with it, or as the button in an OptionMenu. The menu that is posted by a CascadeButton is not a part of the widget itself; the menu is associated with the button through a resource. A CascadeButton merely provides the label and other visual aids that support the appearance that a menu can pop up from the object. Even though the CascadeButton widget class is subclassed from Label and could inherit all of its functionality, Motif imposes restrictions on the labels that a CascadeButton can display. CascadeButton labels cannot contain multiple lines or multiple fonts. Because CascadeButtons are typically used in menus, they do not display border shadows like other buttons. They do have similar highlighting behavior when selected, however. CascadeButton widgets are explained in both Chapter 4, The Main Window, and Chapter 15, Menus. Despite the similarity in its name, the ArrowButton widget is not subclassed from Label like the other button widgets. Like the remaining widgets described in this section, it is subclassed directly from the Primitive widget class. The ArrowButton widget contains an image of an arrow pointing in one of four directions: up, down, left, or right. When the user selects this widget, the ArrowButton provides visual feedback giving the illusion that the button is pressed in and invokes a callback routine that an application can use to perform application-specific positioning.

In most respects, an ArrowButton can be considered identical to a PushButton, as it is easy enough to provide an arrow pixmap for a PushButton. Since directional arrows are a common user-interface element, the ArrowButton is provided as a separate widget class for ­simplicity. ArrowButton widgets are covered in detail in Chapter 11, Labels and Buttons. the figure shows the four variations of the ArrowButton widget.

figs.eps/V6a.03.07.eps.png
ArrowButton widgets

The List widget provides a mechanism for the programmer to make a list of text items available to the user for selection. The user selects items from a List using the mouse or the keyboard. The List widget allows you to specify whether the user can select a single item or multiple items. While List is a Primitive widget, it is typically created as part of a ScrolledList compound object using a Motif convenience function. The advantage of the ScrolledList object is that it provides a ScrollBar when the List grows bigger than the size of its visible area. In Motif 1.2, instances of the List widget are automatically registered as drag sources for drag and drop operations by the toolkit. We explore the List widget in detail in Chapter 12, The List Widget. the figure shows a List widget in context with other interface ­elements.

figs.eps/V6a.03.08.eps.png
A List widget in an application

The ScrollBar widget is one of the more intuitive user-interface elements in the Motif toolkit. ScrollBars are almost always used as children of a ScrolledWindow widget. When the contents of a window are larger than the viewing area, a ScrollBar allows the user to scroll the window to view the entire contents.

ScrollBars can be oriented vertically or horizontally. The ScrollBar also provides a number of callback resources that allow you to control its operation. ScrollBar widgets are discussed in Chapter 9, ScrolledWindows and ScrollBars. the figure shows both vertical and horizontal ScrollBars.

figs.eps/V6a.03.09.eps.png
Horizontal and vertical ScrollBar widgets in a ScrolledWindow

The Separator widget is used as a visual aid to separate adjacent items in a display. A Separator appears as a line between the objects it is separating; it can be oriented vertically or horizontally. Separators can be used in menus to separate menu items, in dialog boxes to ­separate discrete areas of control, and at various points in an interface for purely aesthetic ­reasons. The Text widget is a complete text editor contained in a widget. The Text widget provides resources to configure the editing style of the widget, as well as callback resources that allow text verification. The widget can be configured as a multiline text entry area or as a single-line data entry field. The TextField widget class is available as a somewhat lighter-weight text entry area. The TextField widget is limited to a single-line, but in all other respects there is little difference between the two classes. In Motif 1.2, instances of the Text and TextField widgets are automatically registered as drag sources and drop sites for drag and drop operations by the toolkit.

The Text and TextField widgets can be used in many different ways to support the text entry requirements of an application. The two widgets are described in detail in Chapter 14, Text Widgets. the figure shows an application that uses various forms of the Text widget.

figs.eps/V6a.03.10.eps.png
Text and TextField widgets


4.2.2 Gadgets

Another set of application controls is provided in the form of gadgets. There are gadgets that are equivalent to many of the primitive widgets: LabelGadgets, SeparatorGadgets, PushButtonGadgets, CascadeButtonGadgets, ToggleButtonGadgets, and ArrowButtonGadgets. The appearance and behavior of the gadgets is mostly identical to that of the corresponding widgets. A further understanding of how gadgets work depends on an understanding of the manager widgets that support them, so we are going to return to this topic later in the chapter.

figs.eps/V6a.03.11.eps.png
The Gadget class hierarchy


The Gadget class is a superclass for all of the Motif gadgets. Like Primitive, this class is a metaclass that is never instantiated. However, gadgets are not widgets. The Gadget class is subclassed from the RectObj class, not from the Core widget class. the figure shows the class hierarchy for gadgets.

4.3 Application Layout

While the controls are the most obvious part of a graphical user interface, these elements alone do not make an effective interface. A random arrangement of buttons or a collection of nested menus can make an application as obscure and as difficult to use as one with a command-line interface. The arrangement of the controls in an application makes all the difference.

To help you lay out your application, Motif provides you with a set of manager widgets. You can think of manager widgets as boxes in which you can put things. These boxes, however, can grow or shrink as necessary to provide the best fit possible for the items that they contain. You can place boxes inside of other boxes, whether or not they contain other items. By using different size boxes, you can organize things in many different ways.

Manager widgets are so named because they manage the size and position of other widgets. The relationship between a manager widget and the widgets that it manages is commonly referred to as the parent-child model. The manager acts as the parent, and the other widgets are its children.

Unlike primitive widgets, such as PushButtons, ScrollBars, and Labels, whose usefulness depends on their visual appearance and interaction with the user, manager widgets provide no visual feedback and have few callback routines that react to user input. Manager widgets have two basic purposes: they manage the sizes and positions of their children, and they provide support for gadgets. Like other widgets, manager widgets have windows, they can receive events, and they can be manipulated directly with Motif and Xt functions. You can draw directly into the window of a manager widget, look for events in the widget, and specify resources for it.

There are many manager widget classes, each of which is tuned for a particular kind of widget layout. A manager widget can manage other manager widgets, as well as primitive widgets like Labels and PushButtons. In fact, the layout of an application is typically a kind of tree structure. As discussed in Chapter 2, The Motif Programming Model, the top of the tree is always a shell widget like that returned by XtVaAppInitialize(). Shell widgets are composite widgets that can only have a single managed child. This child is usually a ­general-purpose manager widget. This manager contains other managers and the primitive widgets that compose the user interface for a window in an application.

the figure shows the all of the different manager and primitive widgets that make up the displayed dialog box. The parent-child relationships between the widgets in this dialog box are illustrated in the tree structure shown in the figure. Although the dialog box is composed of many different components, it appears to the user as a single, conceptually focused user-interface object.

figs.eps/V6a.03.12.eps.png
The layout of a dialog box

figs.eps/V6a.03.13.eps.png
The widget hierarchy of a dialog box


4.3.1 The Manager Widget Class


As with the Primitive widget class and the Gadget class, the Manager widget class is a superclass for all of the Motif manager widgets. The Manager class is another metaclass. You never create an instance of a Manager widget; you create an instance of one of its subclasses. The actual widget classes that you use are shown in the figure.

Manager is subclassed from the Xt Constraint class, which in turn is subclassed from the Xt Composite class. The Composite widget class defines the basic characteristics of widgets that are able to manage the size and position of other widgets. Xt uses the general term ­composite widget for any widget with this capability. The Constraint class adds the capability to provide additional resources for the widgets that are being managed. These resources constrain the position of the widgets. They can be thought of as hints about how the widgets should be laid out.

figs.eps/V6a.03.14.eps.png
The Manager widget class hierarchy

Motif provides a number of general-purpose manager widgets that allow the programmer to manage the size and arrangement of an arbitrary number of children. In some ways, the art of Motif programming is the design of effective widget layouts, using these particular manager widgets. Motif also provides some narrowly-focused manager widgets, such as certain dialog classes, that can almost be treated as if they were single user-interface components. These widgets create and manage their children with minimal help from an application. We sometimes refer to these widgets as compound objects, since they include both a manager widget and one or more children. This section describes the different manager widgets briefly; a more detailed description of the widgets is given in Chapter 8, Manager Widgets .

The DrawingArea Class

The DrawingArea widget provides an area in which an application can display graphics. Callback routines can be used to notify the application when expose and resize events take place and when there is input from the keyboard or mouse. The DrawingArea can also be used to manage the geometry layout for child widgets, but its functionality in this area is quite limited.
The ScrolledWindow Class

The ScrolledWindow widget provides a viewport for data such as text or graphics. If the data that is being viewed is larger than the ScrolledWindow, ScrollBars allow the user to view the entire contents of the window interactively.
The MainWindow Class

The MainWindow widget acts as the standard layout manager for the main window of an application. It is specifically tuned to pay attention to the existence of a MenuBar, a command area, a message area, a work region, and ScrollBars, although all of these areas are optional.
The RowColumn Class

The RowColumn widget is perhaps the most widely used and robust of all of the manager widgets. As its name suggests, the widget lays out its children in rows and columns. The RowColumn widget is used by many different parts of the toolkit to implement compound objects like MenuBars, PulldownMenus, CheckBoxes, and RadioBoxes.
The Frame Class

The Frame widget provides a three-dimensional border for a widget that does not normally have a border. It can also be used to enhance the style of the border for a widget that already has a border. In Motif 1.2, a Frame widget can have two children: a work area and a title. In Motif 1.1, Frame can only have a work area child. In either case, the work area child can be a manager widget that contains many other children.
The PanedWindow Class

The PanedWindow widget manages its children in a vertically tiled format. Its width always matches the widest widget in its list of managed children; the widget forces all of its children to stretch to the same width as that widget. Each pane in a PanedWindow contains a child widget; every pane has an associated sash (or grip) that allows the user to change the height of the pane interactively. Resizing a pane with the grip can cause the widgets in other panes to change size.
The BulletinBoard Class

The BulletinBoard widget does not impose much of a layout policy for the widgets that it manages. The widget acts like a real bulletin board, in that an application pins a widget on the bulletin board, and it sticks where it is placed. The BulletinBoard does impose margins and has a resource that controls whether or not its children can overlap. However, when a BulletinBoard is resized, it does not move or resize its children based on its new size. The BulletinBoard is useful mostly for the layout of dialog boxes and other windows that are rarely resized. The predefined Motif dialog widget classes use BulletinBoard widgets for this reason.
The Form Class

The Form widget provides a great deal of control over the placement and sizing of the widgets it manages. A Form can lay out its children in a grid-like manner or it can allow its children to link themselves to one another in a chain-like fashion. Form uses constraint resources to specify how children are resized and positioned relative to each other and the Form as a whole.
The Scale Class

The Scale widget is a slider object that is somewhat similar in appearance and functionality to a ScrollBar. A Scale is typically used to provide feedback to the user about the value of a state variable in an application. This widget class is not intended to be used as a general manager. The Scale creates and manages its own widgets, which are needed to construct the Scale object. The only children that you can add to a Scale widget are Label widgets that represent tick marks.

4.3.2 Geometry Management

The process by which a manager widget controls the layout of its children is known as geometry management. A child widget is always placed within the boundaries of its parent. A child cannot move or resize itself without requesting permission from its parent, which can deny the request. The manager, acting as the parent, can even force the child into an arbitrary size or position. However, like any good parent, a manager widget should be fair at all times and not deny reasonable requests made by its children. As you might expect, geometry management can be quite complex in an application with several levels of managers.

As an example, consider adding a new item to a List widget. In order to display the new item, the List widget must grow vertically, so it requests a new size from its manager parent. If that parent can accomodate the larger size, or it has another mechanism for satisfying the request, such as ScrollBars, it can approve the request. However, if the manager itself must grow to honor the List widget's request, it has to negotiate with its own parent. This chain reaction may go all the way up to the shell widget, in which case the shell must communicate with the window manager about the new size. If the window manager and the shell agree to the new size, the acknowledgement filters back down through the widget tree to the List widget, which can now grow to its requested size. If any of the composite widgets in the hierarchy refuse to resize, the List widget's request is either denied or only partially fulfilled.

Most of the time, this type of interaction completes successfully, as there are rarely disputes among children about resizing negotiations or positional boundaries. Children usually go where their managers put them and make very few requests of their own. One exception is a RowColumn widget that is acting as a MenuBar, since it must be situated at the top of the window, and it must span the window horizontally. ScrollBars are another possible exception, since they are typically positioned at the edges of ScrolledWindow widgets.

So, how do children request geometry changes from their parents? The answer to this question is rather complicated, since the X Toolkit Intrinsics supports a large selection of functions that enable two-way communication about geometry management. For example, a child can use XtMakeGeometryRequest() to request permission to be made a specific size or to be placed in a particular location. A parent can use a function like XtQueryGeometry() to give a child the opportunity to announce its preferred geometry.

Some of these functions and methods are described in Chapter 8, Manager Widgets, but a detailed treatment of custom geometry management techniques is beyond the scope of this book. These functions are mostly used by the internals of composite and constraint widgets. See Volume Four, X Toolkit Intrinsics Programming Manual , for a more detailed discussion of geometry management techniques.

In the Motif toolkit, geometry management cannot work without cooperation. The easiest way for a child to cooperate with its parents and siblings is simply to comply with whatever layout policy is supported by its manager widget parent. A child should not try to force itself into a size or a position that is not supported by its parent. Each of the manager widget classes described above is designed to support a specific layout style. For example, the RowColumn widget lays out its children in rows and columns, the Form widget allows its children to specify positions relative to other widgets within the Form, and the PanedWindow widget lets its children specify their desired maximum and minimum heights.

Manager widgets use constraint resources to support their layout policies. Constraint resources are defined by Xt's Constraint widget class, which is a superclass for the Manager widget class and thus all of the Motif manager widgets. Unlike other resources, constraint resources apply to the children of a manager widget, not to the manager itself. Examples of constraint resources include maximum and minimum heights, relative sizes and positions, specific positional constraints, and even absolute x,y coordinates. While these examples deal exclusively with size and position, constraint resources can be used for any arbitrary information that needs to be kept on a per-child basis.

Here's how constraint resources work. When a manager needs to size or position its children, it deals only with the children that are managed; unmanaged children are ignored in geometry management negotiations. For each managed child, the manager examines the child's constraint resources. Depending on the constraints that are specified, the manager either enforces the geometry changes or negotiates with its own parent to see if it can comply with the changes. This process uses an extra internal data structure for each child. The data structure stores the constraints that are used by the widget's parent to aid it in geometry management.

4.3.3 Gadget Management

In addition to handling geometry management, manager widgets are responsible for their gadget children. In order to understand how managers support gadgets, we need to define more clearly what a gadget is. Every widget has its own X window, which simplifies many aspects of programming, since each widget can take responsibility for repainting itself, selecting its own events, and in general being as self-sufficient as possible. Historically, however, windows have been perceived as heavyweight objects. The concern is that system performance will be degraded if an application uses too many windows. Since an application with a graphical user interface frequently uses hundreds of widgets, or perhaps even thousands for a very large program, the performance issue is an important one.

Gadgets, or windowless widgets, were originally developed as a part of Motif. They were added to Xt as of X11 Release 4. Motif provides gadget versions of many common primitive widgets, such as PushButtons and Labels. Like widgets, gadgets can be created using either Motif convenience functions or XtCreateManagedWidget() . While the widget and gadget versions of an object are functionally very similar, there are some small but important differences.

Because a gadget does not have its own window, it is entirely dependent on its parent, a manager widget, for its basic functionality. For example, the manager must handle redrawing the gadget on exposure, highlighting it as a result of keyboard traversal, and notifying it of event activity. Without a window, a gadget has no control over the colors that it uses or any other window-based attributes normally associated with a widget. For this reason, gadgets can only be used in managers that support them. How closely a gadget emulates its widget counterpart is largely dependent on the capabilities of the manager widget parent.

The Motif Manager class limits the colors that can be used by gadgets. A gadget uses the same background, foreground, and shadow colors as its manager widget parent. These restrictions are not inherent in the Xt Composite widget class or in Xt-based gadgets; they are specific to the Motif Manager and Gadget classes. Hypothetically, you could write a Composite widget that allows its gadget children to specify their own background colors. Such a widget would have to paint the area of its window occupied by the gadget with the specified color to give the user the impression that the gadget is indeed a separately-colored widget.

You can use the color restrictions of the Motif managers and gadgets to provide a consistent interface for your application. For example, by using PushButton gadgets instead of PushButton widgets, you can ensure that all of the buttons in particular window are the same color. In this situation, the user can specify color resources for the manager widget, but not the PushButtons themselves.

Although gadgets were originally developed to improve performance, it is no longer necessary to automatically use them if you are looking for performance improvements in an ­application with many widgets. In both X11 Release 4 and Release 5, windows have become substantially lighter-weight objects than they were when gadgets were first developed. If anything, gadgets are worse than widgets at this point from a performance perspective because the Motif managers take a very simplistic approach to the way they handle events for gadgets. A manager tracks all events, even MotionNotify, whether or not its gadgets have expressed interest in the events. As a result, gadgets typically generate a great deal of network traffic. X terminal users are especially likely to notice a network performance drop. There are some other complications that surround the use of gadgets, which we discuss when they come up in the course of this book.

4.3.4 Keyboard Traversal

Keyboard traversal is a mechanism that allows a user to navigate through the components in a user interface using only the keyboard. The Motif Style Guide specifies that all applications must support keyboard traversal for all application functionality. Support of keyboard traversal is important because not every display provides a mouse or other pointing device. For some applications, such as data entry, using keyboard traversal is more convenient than using a pointing device. All of the Motif widgets support keyboard-based navigation.

Keyboard traversal is based on the concept of a tab group. A tab group is a group of widgets that are related for the purpose of keyboard traversal. For example, all the items in a menu are considered a tab group, since they are grouped together and perform related functions.

At any given time, only one component on a display can be "listening" to the keyboard for keyboard events. The widget that is listening to the keyboard is said to have the keyboard focus, or input focus. The widget that has the input focus identifies itself by displaying a location cursor. The location cursor is often a highlighted border that surrounds the widget. A user can move the input focus to another widget using the mouse or the keyboard.

The user can move the keyboard focus between items in the same tab group using the arrow keys. When the user finds the item that she wants, she can activate it with the RETURN key or the SPACEBAR. If the user wants to move from one tab group to another, she uses the TAB key. (In a multiline Text widget, CTRL-TAB is used because otherwise there would be no way to insert a tab character.) To traverse the tab groups in reverse, the SHIFT key is used with the TAB key. Keyboard traversal wraps from the last item to the first item, both within a tab group and between tab groups.

Although keyboard traversal is not completely controlled by manager widgets, they do play a pivotal role in implementing it. A manager widget is typically initialized as a tab group; its primitive widget children are members of the tab group. The Text and List widgets are exceptions to this rule. These widgets are set up as their own tab groups, so that keyboard traversal can be used to move among the text in a Text widget or the items in a List widget. Within a tab group, there is no sense of a manager-within-manager structure. The widget hierarchy is flattened out so that it appears to the user that all of the controls in a window are at the same level.

Keyboard traversal only works if each widget in an interface cooperates. If a PushButton has the keyboard focus and the user presses the TAB key, the internals of the PushButton widget are responsible for directing the focus to the next tab group. Manager widgets play a key role in keyboard traversal because they are responsible for the keyboard events that take place within gadgets. If an event occurs within a PushButton gadget, its manager parent is responsible for directing the input focus to the next tab group.

Although the whole process of keyboard traversal may seem complex and difficult, it is automated by the Motif toolkit and does not require application intervention. However, the toolkit does provide mechanisms that allow you to control keyboard navigation. There are resources that allow you to specify widgets that are tab groups, widgets that are in tab groups, and widgets that do not participate in keyboard navigation. There are also functions that allow you to specify explicitly the direction of keyboard traversal. Fortunately, such fine-tuning is rarely necessary.

4.4 Putting Together a Complete Application

Managers and primitive widgets provide the basic tools with which you can build a graphical user interface from the ground up. Motif also provides several components that address the large-scale organization of an application. The specialized MainWindow manager widget is intended to be used as the organizing frame for an application. Motif also provides different types of menus and dialog boxes that can be used to organize application functionality.

Since an application is always used in conjuction with a window manager, we need to discuss the role played by the window manager. In the course of this discussion, we also need to take a closer look at shell widgets, since they provide the communication link between an application and the window manager.

Both pixmaps and colors play an important role in a graphical user interface. Motif provides routines that cache pixmaps so that they can be reused throughout an application. The three-dimensional appearance of Motif components is implemented using a variety of color resources. It is important to understand these resources so that the 3D shadows are an effective part of the user interface.

4.4.1 The Main Window

Every application is different. A word processor, paint program, or spreadsheet typically has a single main work area, with controls taking on a peripheral role, perhaps in PulldownMenus. More sophisticated programs, on the other hand, may have several main work areas. For example, an electronic mail program may have a work area in which the user reviews and selects from a list of incoming messages, another where she reads and responds to messages, and yet another where she issues commands to organize, delete, or otherwise affect groups of messages. Still other applications, such as data-entry programs, don't really have a separate work area. The work area is really just a collection of controls, such as CheckBoxes and text entry areas, that are filled in by the user.

It is quite conceivable that an application could provide multiple windows for performing different tasks. For example, an order entry program might use one window for looking up a customer record, another for checking stock on hand, and yet another for entering the current order. Motif allows for the creation of multiple top-level application windows, as well as transient dialog boxes that ask for additional information or confirmation before carrying out a command.

Nonetheless, every application has at least one main window. The main window is the most visible window in an application. It is the first window the user sees and also the place where the user interacts with most application functionality. No matter how small or large an application may be, there needs to be a focal point that ties it all together. As a program grows more complex, the main window may grow more abstract and perform fewer functions, but it always exists. In a sophisticated application, the main window is transformed into a hub where the user starts, finishes, and returns again and again as she goes from one function to the next.

The Motif Style Guide suggests a particular layout for the main window. Applications should use this layout unless they have a compelling reason not to. The recommended layout is shown in the figure.

figs.eps/V6a.03.15.eps.png
Recommended layout for a main window


A main window should have a menu bar across the top, with the work area immediately below it. The work area usually contains the main interface object of the application. For example, a paint or draw application might provide a DrawingArea widget as a canvas, an electronic mail application might provide a ScrolledList of message summaries from which the user can make selections, and a Text editor might place a Text widget in the work area. An application work area might require a custom widget or a non-widget-based X window instead.

The work area can have both horizontal and vertical scrollbars allowing the user to view its entire contents if they are too large to be displayed all at once. The main window can also contain an optional command area below the work area, where the user can enter typed commands. This area is most helpful for porting character-based applications to a Motif GUI, but it can be useful for other applications as well. At the bottom of the main window is an optional message area. This area should be used for status and informational messages only, not for error messages or any other type of message that requires a response from the user.

While it is possible to construct your own main window, the Motif toolkit provides the ­special-purpose MainWindow widget, which supports the recommended style. All of the elements in the MainWindow are optional, so an application can use it to display just the areas that it requires. The MainWindow widget is described in detail in Chapter 4, The Main Window.

4.4.2 Menus

Motif supports three different styles of menus. PulldownMenus that are displayed from the MenuBar in a MainWindow are the most common type of menu. A PulldownMenu is displayed when the user selects a CascadeButton in the MenuBar. The menu pane is displayed below the CascadeButton. the figure shows a typical MenuBar and PulldownMenu.

figs.eps/V6a.03.16.eps.png
A MenuBar and an associated PulldownMenu


An item in a PulldownMenu can have a cascading menu associated with it. The cascading menu is displayed to the right of the menu item as shown in the figure, so these menus are sometimes referred to as pullright menus.

figs.eps/V6a.03.17.eps.png
A cascading menu

MenuBars, PulldownMenus, and cascading menus are all created in a similar way. Motif provides convenience functions that create specially configured RowColumn widgets for these menu objects. The RowColumn widget is then populated with PushButtons, CascadeButtons, ToggleButtons, and Separators, or their gadget equivalents. In the case of a MenuBar, all of the children must be CascadeButtons, since each button brings up a separate menu. In a PulldownMenu pane, most of the items are PushButtons or ToggleButtons, although ­Separators can be used for clarity. If an item posts a cascading menu, it must be a CascadeButton. The additional menu is created separately, populated with its own buttons, and ­attached to the CascadeButton.

Motif also supports a construct called an OptionMenu. An OptionMenu is another specially-configured RowColumn widget, but in this case the behavior is quite different. An OptionMenu is typically used to prompt the user to choose a value. The RowColumn widget displays a Label and a CascadeButton that shows the current value. When the user clicks on the button, a menu that contains the rest of the choices is popped up directly on top of the CascadeButton. Choosing an item from the menu modifies the label of the CascadeButton so that it shows the currently-selected item. the figure shows an OptionMenu, both before and after it is popped up.

Additionally, Motif provides PopupMenus. Unlike the other types of menus, a PopupMenu is not attached to a visible interface element. A PopupMenu can be popped up at any arbitrary location in an application, usually as a result of the user pressing the third mouse button. PopupMenus are meant to provide shortcuts to application functionality, so an application can use different PopupMenus in different contexts and for different components in an interface.

figs.eps/V6a.03.18.eps.png
An OptionMenu

In Motif 1.2, a menu can be torn off from the component that posted it. A menu is normally only displayed for as long as it takes the user to make a selection. Once the selection is made, the menu is closed. When a menu is torn off, it remains posted in its own window. Now the user can make as many selections from the menu as she would like without having to repost the menu each time. For more information on tear-off menu functionality, as well as the different types of Motif menus, see Chapter 15, Menus.

4.4.3 The Window Manager

To the user, the MainWindow looks like the top-level window of an application. In window-system talk, a top-level window resides at the top of the window hierarchy for an application. Its parent is the root window, which is what the user perceives as the background behind all the windows on the desktop. In the Xt-world, however, things are a little different. Behind every visible top-level application window is a special kind of widget known as a shell widget.

Every window that can be placed independently on the screen, including top-level windows and dialog boxes, has a shell widget as its parent. The user does not see the shell because it is obscured by all of the other widgets in the window. A shell widget can only contain one managed child widget; the shell does not perform any geometry management except to shrink-wrap itself around this child. The child is typically a manager widget, such as a MainWindow, that is responsible for managing the layout of the primitive components, such as Labels, Text widgets, ScrollBars, and PushButtons. The items that the user actually sees and interacts with are descendants of the shell widget because they are contained within its boundaries.

Aside from managing its single child, the main job of the shell is to communicate with the window manager on behalf of the application. Without the shell, the application has no idea what else is happening on the desktop. It is very important for you to understand that the window manager is a separate application from your own. The visual and physical interaction between an application and the window manager is usually so close that most users cannot tell the difference between the two, but the distinction is important from a programming perspective.

To get an idea of the relationship between the window manager and an application, let's compare it with the way a bed is built and how it fits into a room. A bed is made up of a frame, a mattress, and as many accessories as you want to pile on top of it. The main window is the mattress; the sheets, pillows, blankets, and stuffed animals you throw on it represent the user-interface controls inside the main window. The whole lot sits on top of the bed frame, which is the shell widget. When you push a bed around the room, you're really pushing the bed's frame. The rest just happens to go along with it. The same is true for windows on the screen. The user never moves an application window, she moves the shell widget using the window manager frame. The application just happens to move with it.

You may have to stretch your imagination a little to visualize a bed resizing itself with its frame, but this is precisely what happens when the user resizes an application. It is the window manager that the user interacts with during a resizing operation. The window manager only informs the application about the new size when the user is done resizing. The window manager tells the shell, the shell communicates the new size to its child, and the change ­filters down to the rest of the widgets in the application.

The window manager frame is composed of window decorations that the window manager places on all top-level windows. These controls allow the user to interactively move a window, resize it, cause it to redraw itself, or even to close it. the figure shows the standard Motif window manager (mwm) decorations. For information on how to use mwm, see Volume Three, X Window System User's Guide, Motif Edition.

figs.eps/V6a.03.19.eps.png
Motif window manager decorations

The window menu displays a list of window manager functions that allow the user to move, resize, and exit the application. An application does not have access to the menu itself or the items within it; similarly, it cannot get handles to the minimize and maximize buttons. These objects belong to the window manager and act independently from an application.

Motif provides window manager protocols that allow menu items like these to affect an application. An application can also interact with the window manager using many of the same types of protocols. You can specify which of the items in the window menu you want to appear, whether or not there are resize handles on the window frame, and whether or not you want to allow the user to iconify the window. However, the user is expecting all of the applications on her desktop to interact consistently with the window manager. This expectation is magnified by the fact that the user has probably set quite a few resources for the window manager. Since unexpected interference from an application rarely makes users happy, you should leave the window manager alone. A technical discussion of the window manager can be found in Chapter 16, Interacting With the Window Manager.

As we pointed out earlier, it is possible for an application to have more than one independent window. In addition to the main window, there may be one or more dialog boxes, as well as popup windows, and even independent application windows that co-exist with the main window. Each of these cases requires different handling by the window manager, and as a result, there are several different classes of shell widgets. the figure shows the class hierarchy of the different types of shell widgets available in the Motif toolkit. The Shell widget class is another metaclass that specifies resources and behaviors inherited by all of its subclasses.

figs.eps/V6a.03.20.eps.png
The Shell widget class hierarchy

In some cases, an application needs to put up a temporary window that is completely free of window manager interaction. Menus are one such a case. When a user pops up a menu, she typically wants to make a choice immediately, and she wants that choice to take precedence over any other window system activity. The window manager does not need to be involved either to decorate or to position the menu, as it is entirely up to the application.

As its name suggests, the OverrideShell widget class is provided for windows that bypass the window manager. OverrideShells are like futons; you can place them on the floor without using a bed-frame (and without being tasteless). It doesn't make much sense to use an OverrideShell as the main window for an application, except possibly for a screen-locking application. The purpose of this type of application is to prevent other applications from appearing on the screen while the computer is left unattended. Because the window manager is unaware of the OverrideShell, it does not provide window manager controls, and it does not interpret window manager accelerators and other methods for bypassing the lock.

The OverrideShell is a generic Xt-based widget class, so the Motif toolkit provides the MenuShell to service the special interface needs required by the Motif Style Guide. The MenuShell's translation table is set to support keyboard traversal, its XmNfocusPolicy is set to XmPOINTER, and its XmNallowShellResize resource is set to True. The MenuShell also makes sure that its child is a RowColumn widget. There is little more to be said about MenuShells, but for an in-depth discussion on the various types of menus you can use in Motif, see Chapter 15, Menus . Shell widgets must communicate with the window manager to negotiate screen real estate and a wide variety of other properties. The information that is exchanged is defined by the X Consortium's Inter-Client Communications Conventions Manual (ICCCM). The WMShell widget class implements ICCCM-compliant behavior as a standard part of the X Toolkit Intrinsics, so that it is available to all vendors providing Xt-based widget sets and window managers. This shell widget is what allows Motif applications to work correctly with virtually any ICCCM-compliant window manager. In our analogy, a WMShell is a simple, wire bed-frame that doesn't have any special attributes, like wheels or rollers.

The VendorShell widget class is subclassed from the WMShell class; it allows vendors, such as OSF, to define attributes that are specific to their own window managers. In our analogy, this widget class is like having a bed frame that has attached cabinets, shelves above the headboard, or nice wheels that glide on the carpet. The Motif VendorShell is aware of special features of mwm. The widget does not actually add any functionality to the window manager, but it is designed for applications that wish to interact with it. For example, all the attributes of window manager decorations can be modified or controlled through resources specific to the VendorShell.

WMShells and VendorShells are never instantiated directly by an application, but the features they provide are available to an application. For example, the Motif VendorShell allows an application to specify the items in the window menu and to control what happens when the user closes the window from the window menu. Chapter 16, Interacting With the Window Manager, discusses window manager interactions in more detail. You can think of dialog boxes as an application's secondary windows. Since dialogs are not meant to remain on the screen for very long, they do not need all of the decorations that are typically provided by the window manager. However, dialogs are not completely independent like menus, so they do need to be controlled by the window manager. For example, if an application is iconified, its dialog boxes are typically iconified as well. Dialog boxes are usually implemented in Xt using TransientShells.

The DialogShell is a Motif-defined widget class subclassed from the TransientShell and VendorShell classes. Motif functions for creating dialog boxes tend to hide the shell widget side of the dialog. When you make a call like XmCreateMessageDialog() , you are actually creating a MessageBox widget as a child of a DialogShell widget. See Chapter 5, Introduction to Dialogs, for details on Motif dialogs. When you initialize the X Toolkit with a call such as XtAppInitialize(), you are automatically returned an ApplicationShell widget to use as the top-level widget in your application. If an application uses additional top-level windows, they are typically TopLevelShells. The differences between these two classes are subtle and deal mostly with how resources are specified in a resource file. In Chapter 7, Custom Dialogs, we explore some ways in which TopLevelShells can be used as primary windows apart from the main window.

4.4.4 Dialogs

Some applications can get all their work done in one main window. Others may require multiple windows, so Motif allows an application to have multiple top-level windows. However, even applications without this level of complexity need to display transient windows called dialog boxes. Motif provides two main types of dialog boxes: message dialogs and selection dialogs. Message dialogs are designed to allow an application to communicate with the user, while selection dialogs prompt the user to enter different types of information. It is also possible to create custom dialogs for specialized application functionality. Message dialogs simply communicate some kind of message to the user and include buttons that allow the user to respond to the message. For example, a menu item to delete a file might issue a dialog with the message, "Are you sure?" with PushButtons labeled Yes, No, and Cancel.

The Motif MessageBox widget that is used to create message dialogs actually comes in seven different guises. The different styles are meant to be used for different types of messages; some of the styles also display a symbol defined by the Motif Style Guide . Motif provides convenience routines for creating all of the different styles, so they are often referred to as if they are distinct widget classes.

ErrorDialog

The ErrorDialog shows a "do not enter" symbol along with a message that the user has made an error. For example, she may have pressed a PushButton at the wrong time, made an invalid selection in a List widget, or entered an unknown filename for a Text widget.
InformationDialog

The InformationDialog displays an "i" along with an informational message. These dialogs are usually displayed in response to a request for help.
MessageDialog

The MessageDialog does not display a symbol by default, although a symbol can be specified using the XmNsymbolPixmap resource. These dialogs can be used to display any kind of message.
QuestionDialog

The QuestionDialog shows a question mark symbol with a question that the user needs to answer. Questions are typically of the yes/no form, so the possible answers typically include Yes and No . A QuestionDialog should not be used for a question that requires an answer in the form of text or a selection from a list of some kind.
TemplateDialog

Motif 1.2 provides a TemplateDialog to allow an application to create a custom dialog. By default, the TemplateDialog does not display a symbol or a message, but these items can be added to the dialog.
WarningDialog

The WarningDialog displays an exclamation mark along with a message that warns the user about a particular situation. These dialogs are commonly used to make sure that the user wants to do something destructive, like delete a file or exit an application without saving data.
WorkingDialog

The WorkingDialog displays an hourglass with a message indicating that the application is busy processing a lengthy computation or anything else that requires the user to wait.

the figure shows a typical QuestionDialog in an application. For more information on message dialogs, see Chapter 5, Introduction to Dialogs.

figs.eps/V6a.03.21.eps.png
A QuestionDialog

Selection dialogs are meant to provide the user with a list of choices of some sort. Motif ­provides different styles of selection dialogs for different purposes. For example, a SelectionDialog presents a ScrolledList containing an arbitrary list of choices that can be selected with the mouse. The dialog also contains a TextField widget that can be used to type in a choice which may or may not also be on the list. the figure shows a SelectionDialog.

The PromptDialog, as shown in the figure, is useful for prompting the user to enter some information.

figs.eps/V6a.03.22.eps.png
A SelectionDialog

figs.eps/V6a.03.23.eps.png
A PromptDialog

The FileSelectionDialog is a more complex cousin to the SelectionDialog. It is used to select a file in the directory structure. A FileSelectionDialog is shown in the figure.

figs.eps/V6a.03.24.eps.png
A FileSelectionDialog

The CommandDialog is an extension of the PromptDialog in that items input to the text entry field are stored in a ScrolledList. The intent is for the user to provide the application with commands; the list region contains a history of the commands that have already been typed. The user can select an item in the history list to reissue a previous command. the figure shows an example of a CommandDialog.

figs.eps/V6a.03.25.eps.png
A CommandDialog


For detailed information about all of the different Motif selection dialogs, see Chapter 6, Selection Dialogs. There are many types of functionality that are not covered by the standard Motif dialog types. Fortunately, it is fairly easy to create your own dialogs. If you need to create a custom dialog, there are some guidelines in the Motif Style Guide that you should follow. At the highest level, all dialogs are broken down into two major components: the control area (or work area) and the action area. These areas are conceptual regions that may be represented by multiple widgets.

In a message dialog, the control area is used only to display messages, but as you can see from the selection dialogs, this area can be used to provide a variety of control elements. For example, the SelectionDialog uses a List widget and a TextField widget. It is also common for a custom dialog to display an array of PushButtons or ToggleButtons. A communications program might have a setup dialog that allows the user to set parameters such as baud rate, parity, start and stop bits, and so on, using an array of ToggleButtons. The controls in the control area provide information that is used by the application once an action area button is pressed.

the figure shows a custom dialog with a control area that contains many items. Chapter 7, Custom Dialogs, discusses how to build customized dialogs, which may require the direct creation of widgets in the control area. Motif dialogs, on the other hand, do not require you to create any of the objects in the control area. The widgets displayed in that part of the dialog are always predefined and automatically created. One important concept to be aware of when it comes to dialogs is modality. In general, GUI-based programs are expected to be modeless. What this ultimately means is that the user, not the application, should be in control. The user should be able to choose from an array of application functions at any time, rather than stepping through them in a prearranged sequence, under the application's control.

Of course, there are limits to modelessness. Sometimes one thing has to happen before another. Often, sequencing can be taken care of simply by nesting graphical user interface elements. For example, faced with the main window, the user may have only a choice of menu titles; once she pulls down the file menu, she may have a choice of opening, closing, saving, renaming, or printing the contents of a file. At some point, though, she goes far enough down a particular path that her choices need to be constrained.

With respect to dialogs, modality allows a dialog box to require and before the user can go back to working with the application. For example, if the user asks to load a file, she may need to specify a filename in a dialog before she can edit the file. A modal dialog requires an answer immediately, by disallowing input to any other part of the application until it is either satisfied or cancelled. There may be other cases, though, where dialogs are modeless. They can be left up on the screen without an immediate response, while the user interacts with the main application window or another dialog.

figs.eps/V6a.03.26.eps.png
A custom dialog


4.4.5 Pixmaps

In this section, we are going to take a closer look at how Motif supports graphic images. The Motif Label widget and all of its subclasses can display pixmaps as their labels. The MessageBox provides the XmNsymbolPixmap resource for specifying the image that is displayed in a dialog.

The Motif toolkit provides a number of routines for manipulating pixmaps. XmGetPixmapByDepth() and XmGetPixmap() both create a pixmap and cache it, so that it can be reused by an application. XmGetPixmapByDepth() is new in Motif 1.2; it provides a way to specify the depth of the pixmap that is created. XmGetPixmap() always creates a pixmap that has the same depth as the screen on which image is created. The caching mechanism provided by these routines is on a per-client basis; different processes cannot share pixmaps.

Whenever a new pixmap is created using one of these functions, the toolkit retains a handle to the pixmap in case another call is made requesting the same image. If this occurs, the function returns the exact same pixmap that was returned to the original requestor and increments an internal reference counter. In order to keep a clean house, whenever you retrieve a pixmap using either XmGetPixmap() or XmGetPixmapByDepth(), you should call XmDestroyPixmap() when you no longer need the image. This function decrements the reference count for the pixmap. If the reference count reaches zero, XmDestroyPixmap() actually calls XDestroyPixmap() to discard the pixmap.

XmGetPixmapByDepth() takes the following form:

   Pixmap
   XmGetPixmapByDepth(screen, image_name, foreground,
           background, depth)
       Screen *screen;
       char   *image_name;
       Pixel   foreground;
       Pixel   background;
       int     depth;
The image_name can either be a filename or the name of an image registered using XmInstallImage(), which we are going to describe shortly. The background and foreground colors and the depth of the pixmap are specified by the corresponding parameters.

XmGetPixmap() takes the same form as XmGetPixmapByDepth(), minus the depth parameter. XmGetPixmap() creates a pixmap that has the same depth as the given screen, so you cannot rely on XmGetPixmap() to create a single-plane pixmap. The terms single-bit and single-plane are interchangeable; they imply a pixmap with only two colors: 0 and 1. While the term bitmap usually refers to a single-plane pixmap, this is not necessarily true outside of the X social culture. In Motif 1.2, you can use XmGetPixmapByDepth() to create a bitmap; with Motif 1.1 you have to use an Xlib routine, XCreateBitmapFromData().

Whenever XmGetPixmapByDepth() or XmGetPixmap() is called, it looks in the cache for a previously-created pixmap that matches the given name, colors, and depth. If the routine finds a match, it returns the cached pixmap and increments the reference count for the image. Since the pixmaps are cached, two separate parts of an application could have a handle to the same pixmap.

The image_name parameter is the key to where the routines get the data for the pixmap. As we just mentioned, this parameter can either be a filename or a symbolic name previously registered using XmInstallImage(). Both XmGetPixmap() and XmGetPixmapByDepth() use the following algorithm to determine what pixmap to return or create:

The first step is fairly straightforward. The second step checks the image cache that is used internally by the Motif toolkit. Motif defines a number of images that you can use in an application. lists the image names predefined by the toolkit. tab(@), linesize(2); l | l lfCWp9 | l.
Image Name@Description _
background@Solid background tile 25_foreground@A 25% foreground, 75% background tile 50_foreground@A 50% foreground, 50% background tile 75_foreground@A 75% foreground, 25% background tile horizontal@Horizontal lines tile vertical@Vertical lines tile slant_left@Left slanting lines tile slant_right@Right slanting lines tile
_ Motif also installs a number of images at run-time to support dialog images and other random pixmaps. None of these image names are publicly available. You can install your own images by predefining them and loading them into the image cache using XmInstallImage(), which takes the following form:
   Boolean
   XmInstallImage(image, image_name)
       XImage   *image;
       char     *image_name;
The image parameter is a pointer to an XImage data structure that has been previously created or, more commonly, statically initialized by the application. It is possible to create an image dynamically from an existing window or pixmap using XGetImage(), but this is not the way the function is typically used.

If you attempt to install an image using an image_name that matches one already in the cache, the function returns False and the image is not installed. Otherwise, the function returns True. You can uninstall an image by calling XmUninstallImage(). Once the image is uninstalled, it cannot be referenced by name anymore and a new image may be installed with the same name. The XImage structure is not copied by XmInstallImage(), so if the image pointer you pass has been allocated using XCreateImage() or XGetImage(), you must not free the data until after you call XmUninstallImage() .

If XmGetPixmap() or XmGetPixmapByDepth() finds a match in the image cache, it creates the pixmap based on the image data, not on the image itself. As a result, the pixmap that is created is not affected by the image being uninstalled by XmUninstallImage().

If the pixmap retrieval routines do not find a match in the image cache, the pixmap is loaded from a file. If image_name starts with a slash character (/), it is taken as a full pathname. Otherwise, the routines look for the file using a search path. On POSIX systems, the environment variable XBMLANGPATH can be set to specify a desired directory in which to search for bitmap files. If this variable is not set, the pathname used is based on the values of the XAPPLRESDIR, HOME, and LANG environment variables. See the reference page in Volume Six B, Motif Reference Manual, for complete details on the search path that is used.

When XmGetPixmap() or XmGetPixmapByDepth() looks in the pixmap cache for a image name, the pathname must match completely for the routine to return a cached image. The file xlogo64 will not match a previously-loaded pixmap that has the name /usr/include/X11/bitmaps/xlogo64. If you do not need to worry about using different pixmaps for different environments, we recommended that you always specify a full pathname to these routines to be assured that you get the desired file.

4.4.6 Color

Color plays an important role in a graphical user interface. It appeals to the senses, so it can provide an aesthetic quality, while at the same time it can be used to convey information to the user. However, for all the power of color, it is frequently abused by applications. A color combination that appeals to some people may offend others. The safest bet with color is to avoid hard-coding any use of color in your application and provide enough flexibility so that the user can configure colors in a resource file or interactively using the application. Of course, many applications are based on the use of color, so this sweeping generalization only applies to those parts of an application that are not dependent on color.

The Motif widget set provides a number of widget resources that specify colors. All of the Motif widgets use the XmNforeground and XmNbackground resources. However, Motif gadgets do not use these resources because they are rendered using the foreground and background colors of their parent. Although every widget class makes different use of the XmN­background and foreground resources, text is typically rendered in the foreground color and everything else is shown using the background color. Some widgets provide additional color resources for particular aspects of their appearance. For example, ToggleButtons use the XmNselectColor resource for the square/diamond selection indicator, PushButtons use XmNarmColor as their background when they are armed, and ScrollBars use XmNtroughColor to set the color of the area behind the slider and directional arrows.

The XmNborderColor resource is another resource that can be specified for any widget, as it is defined by the Core widget class. Since Motif widgets typically have a border width of 0, this resource is rarely used. The XmNhighlightColor resource specifies the color of the highlighting rectangle that is displayed around the interface component that has the keyboard focus. This resource is defined by the Gadget, Manager, and Primitive metaclasses, so it can be specified for any Motif component.

Perhaps the most troublesome of all the color resources are XmNtopShadowColor and XmNbottomShadowColor . These are the colors that give Motif widgets their 3D appearance on a color display. If set inappropriately, these colors can ruin the aesthetics of a interface. These resources are set automatically by the toolkit based on the background color of the object, so the colors are not normally a problem. If the background color of a PushButton is blue when it is created, the toolkit automatically calculates the XmNtopShadowColor to be a slightly lighter shade of blue and the XmNbottomShadowColor to be a slightly darker shade.

The problems arise if you want to change the background color of a widget dynamically because the toolkit does not automatically change the shadow colors for you. So if you change the XmNbackground of the PushButton to red, the top and bottom shadow colors remain the different shades of blue. It is important to note that the shadow resources are only used by widgets, not gadgets. If you dynamically change the background color of a manager widget, it automatically recalculates the top and bottom shadow colors and redisplays its gadgets correctly. Many consider the fact that this process is not automated for widgets to be a design flaw in the Motif toolkit.

If you need to change the background color of a widget dynamically, you can recalculate the shadow colors and set the resources yourself. If you are using Motif 1.2, you can use the new XmChangeColor() routine, which takes the following form:

   void
   XmChangeColor(widget, background)
       Widget  widget;
       Pixel   background;
This routine changes all the foreground color, shadow colors, and select color for the specified widget based on the background color. The select color only applies to ToggleButtons (XmNselectColor) and PushButtons ( XmNarmColor).

If you are using Motif 1.1, you have to do a bit more work to change the colors for a widget. In this case, you need to use XmGetColors(), which takes the following form:

   void
   XmGetColors(screen, colormap, bg, fg, top_shadow,
           bottom_shadow, select)
       Screen  *screen;
       Colormap colormap;
       Pixel    bg;
       Pixel   *fg;
       Pixel   *top_shadow;
       Pixel   *bottom_shadow;
       Pixel   *select;
This routine takes a colormap and a background color and calculates and returns an appropriate foreground color, top and bottom shadow colors, and select color. Once you have the colors, you need to specify the appropriate resources for the widget. The following code fragment demonstrates how to set the background of a PushButton to red:
   Pixel bg, top_shadow, bottom_shadow, fg, select_color;
   Colormap cmap;
   Widget pb;

   /* First, set the background color to red... */
   XtVaSetValues (pb,
       XtVaTypedArg, XmNbackground, XmRString, "red", 4,/* strlen("red")+1 */
       NULL);

   /* Once set, get it again, so we know what pixel value it got.
    * Also get the widget's colormap, since we'll be setting its new
    * colors based on the same colormap.
    */
   XtVaGetValues (pb,
       XmNbackground, &bg,
       XmNcolormap,   &cmap,
       NULL);

   /* Let Motif calculate the new colors based on that one color */
   XmGetColors (XtScreen (pb), cmap, bg, &fg,
       &top_shadow, &bottom_shadow, &select_color);

   /* Set the colors accordingly. */
   XtVaSetValues (pb,
       XmNtopShadowColor,    top_shadow,
       XmNbottomShadowColor, bottom_shadow,
       XmNarmColor,          select_color,
       XmNborderColor,       fg,
       NULL);
A basic problem behind setting and getting colors for widgets is that what you get for a given pixel value depends on the colormap. A pixel is simply an index value into an array of color definitions (a colormap). The problem with colormaps is that you never know what colormap is associated with any particular widget.

By calling XtVaSetValues() using the type-converting resource, XtVaTypedArg, we defer the problem to the toolkit and its string-to-color type converter. The toolkit allocates the color out of the colormap already owned by the toolkit and sets the background color accordingly. Then we can get the actual pixel value and the colormap using XtVaGetValues(). We pass the colormap and the background pixel value to XmGetColors() to calculate the rest of the colors. Once we have obtained all of the colors, we can set them using XtVaSetValues().

The Label widget and its subclasses cannot display text using more than one color. However, you can create a multi-plane pixmap and render various strings directly into it using XDrawString(). You can use multiple colors by changing the foreground color in the GC using XSetForeground() or XChangeGC(). Once you have the pixmap, you can use it to set the XmNlabelPixmap resource for the widget.

The text of the entries in a List widget is rendered using the widget's XmN­foreground color. You cannot change the color of individual items in a List widget. The XmN­background of the List affects all areas of the widget not associated with the entries themselves. The text in a Text widget or a TextField widget is also displayed using the XmN­foreground color; there is no way to display text using different colors in these widgets. When a List widget or Text widget is the direct child of a ScrolledWindow, the ScrollBars automatically match the background color of the List or Text widget.

4.5 Changes in Motif 1.2

Release 1.2 of the Motif toolkit introduces a number of new features, as well as many enhancements to existing functionality. This section summarizes all of the changes in Motif 1.2 and refers you to other sections in the book for more detailed information on specific changes. We also describe the changes that we made to the example programs in the book to make them accurate with respect to Motif 1.2.

4.5.1 General Toolkit Changes

Many of the changes in Motif 1.2 affect the functionality of the toolkit as whole, rather than individual widget classes. This release demonstrates performance improvements, as the code has been reorganized to improve locality and dynamic memory usage has been reduced. The toolkit also benefits from the improved performance of the X11R5 translation manager. Motif 1.2 provides a new header file, <Xm/XmAll.h>, that includes all of the public header files for the toolkit. The <Xm/ExtObject.h>, < Xm/Traversal.h>, <Xm/VaSimple.h>, and <Xm/VendorE.h> header files that are present in Motif 1.1 are obsolete in Motif 1.2. The addition of internationalization capabilities is one of the major enhancements provided by Motif 1.2. An internationalized application can run in different language environments without any modification. Most of the support for developing internationalized applications in Motif is based on features provided by X11R5. Xlib provides support for internationalized text output, interclient communication, and localization of the resource database, while Xt handles establishing the locale. See Section #slangproc in Chapter 2, The Motif Programming Model, for more information on establishing the language environment in an Xt-based application; refer to Volume One, Xlib Programming Manual, for a description of the internationalization features in X11R5.

The Text and TextField widgets have been modified to support internationalized text input and output; see Section #stexti18n in Chapter 14, Text Widgets, for more information. The Motif routines that manipulate compound strings and font lists have also been updated for Motif 1.2. See Chapter 19, Compound Strings, for details on the new API for XmString and XmFontList values. The ability to transfer data using the drag and drop metaphor is another major new feature in Motif 1.2. Drag and drop allows the user to select a data source, drag the data around on the display, and drop the data on a new location. The drag and drop mechanism handles data transfer both within and between applications. The Label widget and its subclasses, the List widget, and the Text and TextField widgets all provide built-in drag and drop capabilities. The toolkit also provides some new objects and routines that can be used to implement custom drag and drop functionality. In Chapter 18, Drag and Drop , we describe the Motif drag and drop model and the objects that implement it, and we present some examples of providing custom drag and drop functionality in an application. Motif provides a new feature in menus that allows them to be torn off and displayed in separate windows. Tear-off menus make it easy for the user to make repeated selections from a menu. Normally, when a menu is posted, it is only displayed until a selection is made, and then it is removed. If the menu has been torn off, it is placed in its own window and remains available for the user to make multiple selections. The tear-off functionality is activated by a special tear-off button in the menu. The button displays a dashed line to indicate that the menu can be torn off, much as a coupon is torn out of a newspaper. Tear-off functionality is provided for all of the Motif menu types; it is controlled by the XmNtearOffModel resource of the RowColumn widget. See Section #stearoff in Chapter 15, Menus, for a more complete description of tear-off menus. The new Display and Screen objects store per-display and per-screen resources and data. These objects essentially provide a way for the toolkit to keep track of information about the display and the screen that it needs to access frequently. When Motif creates the first shell on a particular display or screen, it creates a Display or Screen object automatically. An application can retrieve the Display and Screen objects using XmGetXmDisplay() and XmGetXmScreen(), respectively. Values for the resources defined by the Display and Screen objects can be set in a resource file or in a program using XtVaSetValues(), and they can be retrieved using XtVaGetValues().

The Display object defines resources that an application can set to control the behavior of the application on the display. The XmNdragInitiatorProtocolStyle and XmNdragReceiverProtocolStyle resources specify the protocol used during a drag and drop transfer, as described in Section #sdragprot, while XmNdefaultVirtualBindings sets the default virtual bindings for the display. For a complete description of the Display object, see the reference page in Volume Six B, Motif Reference Manual.

The Screen object defines a number of resources that control the default drag icons used during drag and drop; see Section #smodicon for a discussion of these resources. The XmN­darkThreshold, XmNforegroundThreshold, and XmNlightThreshold resources specify values that affect the default color calculation algorithm, as we describe shortly.

The XmNfont, XmNhorizontalFontUnit , and XmNverticalFontUnit resources specify the font units that are used to convert geometry values when the Xm100TH_FONT_UNITS value is being used for units. These resources make the XmSetFontUnit() and XmSetFontUnits() routines in Motif 1.1 obsolete.

The XmNmenuCursor resource controls the pointer shape that is used when a menu is posted; the resource supercedes the XmGetMenuCursor() and XmSetMenuCursor() functions in Motif 1.1. The XmNunpostBehavior resource indicates the behavior of a menu when the mouse button is pressed outside of the menu. The value XmUNPOST_AND_REPLAY unposts the menu hierarchy and replays the event, while XmUNPOST just unposts the menu. For more information on the various Screen resources, see the reference page in Volume Six B, Motif Reference Manual. Motif provides a number of new functions that support better control of keyboard traversal. The XmGetFocusWidget() routine returns the widget that has the input focus, while XmGetTabGroup() returns the widget that is the tab group for the specified widget. An application can also call XmIsTraversable() to determine whether or not a particular widget is eligible to receive the input focus. See Section #skeybtrav in Chapter 8, Manager Widgets, for more information about keyboard traversal.

The Manager widget class defines the XmNinitialFocus resource to allow an application to specify the widget that has the initial keyboard focus in a dialog. This resource can be used for both MessageDialogs and SelectionDialogs, although it is normally only used for SelectionDialogs. The resource specifies the widget that has the keyboard focus the first time that the dialog is popped up, as described in Section #sinitfocus in Chapter 5, Introduction to Dialogs.

The XmTrackingEvent() routine in Motif 1.2 replaces the existing XmTrackingLocate() routine for implementing context-sensitive help. XmTrackingEvent() works for both keyboard and mouse events, and it returns the widget selected by the user, regardless of whether or not the widget is sensitive to input. The routine also returns the actual event performed by the user, as explained in Section #sconthelp in Chapter 21, Advanced Dialog Programming. Motif 1.2 provides a representation type manager to handle many of the tasks related to enumerated values, such as installing resource converters that convert string values to their numerical representations. The toolkit provides following functions for managing representation types:

   XmRepTypeAddReverse()
   XmRepTypeGetId()
   XmRepTypeGetNameList()
   XmRepTypeGetRecord()
   XmRepTypeGetRegistered()
   XmRepTypeRegister()
   XmRepTypeValidValue()
For more information about these routines, see the appropriate reference pages in Volume Six B, Motif Reference Manual.

Motif also provides a name-to-widget converter in this release so that widgets can be specified in resource files. This converter is most useful for specifying Form attachments in a resource file. The converter uses XtNameToWidget() from the parent of the widget specified on the left-hand side of the resource specification. Motif includes the new xmbind client that configures the virtual key bindings for Motif applications. This action is performed at startup by the Motif Window Manager (mwm) or any application that uses the Motif toolkit, so an application only needs to use xmbind if it wants to reconfigure the bindings without restarting mwm or a Motif application. The toolkit also provides a new function, XmTranslateKey(), to translate a keycode into a virtual keysym. This function allows an application that overrides the default XtKeyProc to handle Motif's virtual key bindings. See Section #seventspec in Chapter 2, The Motif Programming Model , for more information on virtual bindings. The new XmChangeColor() routine changes the foreground color, shadow colors, and select color for a widget based on a background color. The XmNdarkThreshold , XmN­foregroundThreshold, and XmNlightThreshold resources of the Screen object allow the application or the user to set values that affect the default color calculation algorithm. The values for these resources indicate the levels of perceived brightness (between 0 and 100) that distinguish between a light color and a dark color. The XmNforegroundThreshold value is used in calculating the default foreground and highlight colors, while the other two resources are used in calculating the default shadow and select colors. See Section #scolor for a discussion of color resources in Motif. An application can use the new XmWidgetGetBaselines() routine to get the position of the text baseline in a widget, while XmWidgetGetDisplayRect() can be used to get the size and position of the bounding box for the widget. These routines provide information that is useful in laying out and aligning components in an interface.

4.5.2 Specific Widget Changes

Motif 1.2 also introduces a number of new features, including resources and callback routines, for individual widget classes. In Motif 1.2, the Frame widget can have two children: a work area and a title. The Frame draws a border around its work area child and adds space for a title if one is specified. The XmNchildType constraint resource specifies whether a child is the work area or the title. This resource can have either the value XmFRAME_WORKAREA_CHILD or XmFRAME_TITLE_CHILD. The XmNchildHorizontalAlignment, XmNchildHorizontalSpacing, and XmNchildVerticalAlignment constraint resources control the positioning of the title child. For more information on these resources, see Section #sframe in Chapter 8, Manager Widgets. The Label widget functions as a drag source for drag and drop, as described in Chapter 18, Drag and Drop. The ProcessDrag() action routine, which is bound to the second mouse button, handles this functionality. The List widget provides the following new functions for managing list items:

   XmListAddItemUnselected()
   XmListDeletePositions()
   XmListGetKbdItemPos()
   XmListPosSelected()
   XmListPosToBounds()
   XmListReplaceItemsPosUnselected()
   XmListReplaceItemsUnselected()
   XmListReplacePositions()
   XmListSetKbdItemPos()
   XmListUpdateSelectedList()
   XmListYToPos()
For more information on these routines, see Chapter 12, The List Widget, and the appropriate reference pages in Volume Six B, Motif Reference Manual.

When a List widget is set insensitive, it provides visual indication by greying out all of its items. The default value of the XmNvisibleItemCount resource is now set dynamically, based on the item count and the height of the List.

The List widget functions as a drag source for drag and drop, as described in Chapter 18, Drag and Drop. The ListProcessDrag() action routine, which is bound to the second mouse button, handles this functionality. The List also has a ListCopyToClipboard() action routine for copying the selected items to the clipboard, as well as a ListScrollCursorVertically() routine for scrolling the cursor vertically based on a y-position. The MessageBox widget supports the addition of a MenuBar child, a work area child, and multiple PushButton children. The XmNdialogType resource can also be set to the value XmDIALOG_TEMPLATE to create a MessageBox that can be used as a template for creating a custom dialog. Section #smoddialog in Chapter 7, Custom Dialogs, describes the template dialog in more detail. The PanedWindow defines a new constraint resource, XmNpositionIndex, for specifying the position of a child widget in the PanedWindow's list of children. The children are positioned vertically in the PanedWindow according to this list. The list of children does not include the Sashes. A value of 0 indicates the beginning of the list, while XmLAST_POSITION places the child at the end of the list. The RowColumn widget provides a new resource for controlling the alignment of its children. The XmNentryVerticalAlignment resource controls the vertical positioning of children that are subclasses of Label, LabelGadget, and Text, as described in Section #srowcolumn in Chapter 8, Manager Widgets.

The RowColumn widget also defines the XmNpositionIndex constraint resource for specifying the position of a child widget in the RowColumn's list of children. The children are positioned in the RowColumn according to this list. A value of 0 indicates the beginning of the list, while XmLAST_POSITION places the child at the end of the list.

The XmNtearOffModel resource of the RowColumn widget controls tear-off functionality in Motif menus. The widget also defines the XmNtearOffMenuActivateCallback and XmNtearOffMenuDeactivateCallback callback routines for performing any special processing that is necessary for handling tear-off menus. Tear-off functionality is described in detail in Section #stearoff in Chapter 15, Menus. When a ScrollBar is set insensitive, it provides a visual indication of this state by dimming itself. The ScrollBar also has new action routine, CancelDrag(), that cancels the current slider drag. When the user presses the ESCAPE key while the slider is being dragged, the action is invoked. In Motif 1.2, the ScrolledWindow has a new callback that supports keyboard traversal. The XmNtraverseObscuredCallback is invoked when the user attempts to traverse to a widget that is not visible in a ScrolledWindow. An application can use this callback to make a widget visible in a ScrolledWindow so that the widget can receive the input focus. The XmScrollVisible() routine makes an obscured child of a ScrolledWindow visible, while XmGetVisibility() determines whether or not a widget is visible. See Section #sswtrav in Chapter 9, ScrolledWindows and ScrollBars, for more information on keyboard traversal in ScrolledWindows.
The SelectionBox and FileSelectionBox widgets now support the addition of a MenuBar child and multiple PushButton children in addition to the work area child that was supported in Motif 1.1. The new XmNchildPlacement resource controls the location of the work area child, as described in Section #smodseldlg in Chapter 7, Custom Dialogs.
The Text and TextField widgets have a number of new resources and callback routines that support wide-character strings. These changes have been made for internationalization purposes and are described in Section #stexti18n in Chapter 14, Text Widgets. The widgets function as drag sources and drop sites for drag and drop, as described in Chapter 18, Drag and Drop.

The insertion position in the Text and TextField widgets is marked by an I-beam cursor. The destination cursor now follows the insertion cursor, so it is no longer drawn independently as a caret (^). When a Text or TextField widget is set insensitive, it provides a visual indication of this state by greying out its text and its insertion cursor. Both the Text and TextField widgets provide the toggle-overstrike() action routine for switching between insert and overstrike modes. The Text widget also provides the scroll-cursor-vertically() action to scroll the cursor based on a y position. When the user moves the pointer outside of a Text widget while selecting text, the widget continues selecting text by scrolling automatically after a time delay.

The new XmTextDisableRedisplay() and XmTextEnableRedisplay() routines provide a way to control visual updating in a Text widget. The XmTextFindString(), XmTextGetSubstring(), and XmTextFieldGetSubstring() functions make string manipulation easier. For more information on these routines, see the appropriate reference pages in Volume Six B, Motif Reference Manual. The TextField widget also has an XmNfocusCallback in Motif 1.2. The performance of scrolling in the ScrolledText object has been improved in Motif 1.2. One unfortunate side-effect of this improvement is that it introduces a new data structure, which means that subclasses of the Motif 1.1 Text widget may break under Motif 1.2.
If XmNfillOnSelect is explicitly set to True when XmNindicatorOn is False, the background of the ToggleButton is set to the XmNselectColor when the button is on.
The VendorShell provides the XmNaudibleWarning resource to specify whether or not an audible cue accompanies a warning message. The default value is XmBELL, but the resource can also be set to XmNONE. The value of the XmNverifyBell resource of the Text and TextField widgets is based on the new VendorShell resource.

The VendorShell defines the XmNbuttonFontList , XmNlabelFontList, and XmN­textFontList resources to replace the existing XmNdefaultFontList resource. The new resources specify the font lists for the specific types of children of the VendorShell.

The VendorShell also defines the XmNinputMethod and XmNpreeditType resources for controlling internationalized text input. XmNinputMethod specifies the input method for the application, while XmNpreeditType indicates the input method styles that are available. The syntax and possible values of both of these resources are vendor-specific, as discussed in Section #stexti18n in Chapter 14, Text Widgets.

4.5.3 Changes to the Example Programs

All of the example programs in this book have been updated to Motif 1.2 and X11R5. Some of the changes are quite repetitive and are described in the following list:

The rest of the changes involve using new Motif 1.2 functions and resources. These changes are described in detail when each example is presented.

4.6 Summary

The Motif widget set gives you a great deal of flexibility in designing an application. But with this flexibility can come indecision, or even confusion, about the most effective way to use these objects. If you want to give a user a set of exclusive choices, should you use a PulldownMenu, a dialog box that contains ToggleButtons arranged in a CheckBox, or a List widget? There is no right answer--or perhaps it is better to say that the right answer depends on the nature of the choices and the flow of control in your application.

Designing an effective user-interface is an art. Only experience and experimentation can teach you the most effective way to organize an application. What we can do in this book is teach you how to use each widget class and give you a sense of the tradeoffs involved in using different widgets. In this chapter, we've given you a broad overview of the Motif toolkit. Subsequent chapters delve into each widget class in detail. You should be able to read the chapters in any order, as the needs of your application dictate.


Contents Previous Next