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 2.1 of Motif. If you are familiar with Motif 1.2 but need to get up to speed with Motif 2.1, you should read Changes in Motif 2.1. 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 2.1. While Motif 2.1 is backwards-compatible with Motif 1.2, there are a number of functions and resources in Motif 2.1 that replace obsolete functions and resources in Motif 1.2.
The Motif StyleYou 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) are 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, the toolkit functions 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 behoves 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 both compound objects, and 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.Figure 3-1 shows the entire 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.
Figure 3-1 Class Hierarchy of the Motif widget set
Application ControlsIn 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.
The Primitive Widget ClassThe 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 subclasses, 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.1
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 Figure 3-2.
Figure 3-2 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 4.
The Label ClassThe 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 25, 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, instances of Label and all of its subclasses are automatically registered as drag sources for drag and drop operations by the toolkit2.
Label widgets are described in detail in Chapter 12, Labels and Buttons. Figure 3-3 displays a single Label widget with multiple lines and multiple fonts.
Figure 3-3 A Label with multiple lines and fonts
The PushButton ClassThe 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 12, Labels and Buttons. Figure 3-4 shows some examples of PushButtons.
Figure 3-4 PushButton widgets
The DrawnButton ClassThe 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 12, Labels and Buttons. Figure 3-5 shows some DrawnButtons.
Figure 3-5 DrawnButton widgets
The ToggleButton ClassThe ToggleButton widget displays text or graphics like a Label widget, but it has an additional indicator graphic (a square, diamond, and additionally in Motif 2.1, a circle or check mark shape) to the side of the label. The indicator shows the state of the ToggleButton: in Motif 1.2 this could be simply on or off; in Motif 2.1 a toggle can exist in a third indeterminate state. 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. In the indeterminate state, the toggle is half colored, half uncolored. The ToggleButton provides an 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 by default diamond-shaped; otherwise, they default to a square-shaped appearance. ToggleButton widgets are described in detail in Chapter 12, Labels and Buttons. Figure 3-6 shows the two different ways that ToggleButtons can be grouped.
Figure 3-6 ToggleButton widgets
The CascadeButton ClassThe CascadeButton widget is a special kind of button that is used to popup 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 20, Interacting With the Window Manager.
The ArrowButton ClassDespite 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 12, Labels and Buttons. Figure 3-7 shows the four variations of the ArrowButton widget.
Figure 3-7 ArrowButton widgets
The List ClassThe 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. 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 13.
Figure 3-8 shows a List widget in context with other interface elements.
Figure 3-8 A List widget in an application dialog
The ScrollBar ClassThe 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 10, ScrolledWindows and ScrollBars. Figure 3-9 shows both vertical and horizontal ScrollBars.
Figure 3-9 ScrollBars
The Separator ClassThe 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 and TextField ClassesThe 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. 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 18, Text Widgets.Figure 3-10 shows an application that uses various forms of the Text widget.
Figure 3-10 Text Widgets
GadgetsAnother set of application controls is provided in the form of gadgets. There are gadgets that are equivalent to many of the primitive widgets: ArrowButtonGadgets, SeparatorGadgets, PushButtonGadgets, CascadeButtonGadgets, ToggleButtonGadgets, LabelGadgets, and in Motif 2.1, IconGadgets. The IconGadget is similar to a LabelGadget, except that it can display a label and an image simultaneously. The appearance and behavior of the gadgets are mostly identical to that of the corresponding widgets3. 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.
Figure 3-11 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. Figure 3-11 shows the class hierarchy for gadgets.
Application LayoutWhile 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 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.
Figure 3-12 shows all of the different manager and primitive widgets that make up the displayed dialog box.
Figure 3-12 The layout of a dialog box
The parent-child relationships between the widgets in this dialog box are illustrated in the tree structure shown in Figure 3-13.
Although the dialog box is composed of many different components, it appears to the user as a single, conceptually focused user-interface object.
Figure 3-13 Parent-child relationships between widgets
The Manager Widget ClassAs 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 Figure 3-14.
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.
Figure 3-14 Class hierarchy of the Manager widget classes
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 ClassThe 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 DrawingArea is discussed in detail in Chapter 11, The DrawingArea Widget.
The ScrolledWindow ClassThe 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 ScrolledWindow is discussed in Chapter 10, ScrolledWindows and ScrollBars.
The MainWindow ClassThe 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 MainWindow is discussed in Chapter 4, The Main Window.
The RowColumn ClassThe 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 general purpose RowColumn is discussed in Chapter 8, Manager Widgets.
The Frame ClassThe 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, a Frame widget can have two children: a work area and a title. The work area child can be a manager widget that contains many other children. The Frame is discussed in Chapter 8, Manager Widgets.
The PanedWindow ClassThe PanedWindow widget manages its children in a vertically (and, in Motif 2.1, a horizontally) 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 PanedWindow is discussed in Chapter 8, Manager Widgets.
The BulletinBoard ClassThe 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 BulletinBoard is discussed in Chapter 8, Manager Widgets.
The Form ClassThe 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 Form is discussed in Chapter 8, Manager Widgets.
The Scale ClassThe 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, although in Motif 2.1 there are convenience routines to automatically place tick marks along the Scale. The Scale is discussed in Chapter 16, The Scale Widget.The following Manager widget classes are additionally available in Motif 2.1:4
The Container ClassThe Container class is a complex constraint widget which can lay out IconGadget children in three styles: in a tree arrangement, with a tabular data style, and in a free floating format based upon the x, y specifications for each child. The Container class allows for a more object-oriented approach to the front end of an application than the older MainWindow, in that the IconGadget children can pictorially represent application objects of some kind with the Container providing the layout and selection mechanisms. The Container is discussed in Chapter 9, Containers and IconGadgets. Figure 3-15 shows the Container configured to display in a tree arrangement with additional tabular data.
Figure 3-15 A Container widget with IconGadget children
The SpinBox ClassThe SpinBox class allows the user to input data by selecting from, and rotating through, a set of values. Text widget children are added to the SpinBox, whereupon the range or set of values associated with each text is specified through constraint resources. The SpinBox automatically adds extra ArrowButtons which are used for rotating through the values of the text widget child which currently has the input focus. The programmer however has to supply the Text widgets underneath the SpinBox. For convenience, the SimpleSpinBox subclass is provided which encapsulates the most frequent use of this type of arrangement: it comes with a single built-in Text child. The SpinBox is discussed in Chapter 15, The SpinBox and SimpleSpinBox Widgets. Figure 3-16 shows a SpinBox containing three Label and Text children, and a SimpleSpinBox. The SimpleSpinBox is not meant to be used as a general purpose manager.
Figure 3-16 SpinBox and SimpleSpinBox widgets
The ComboBox ClassThe ComboBox class combines textual input with list selection. The widget presents itself to the user as a Text widget with an ArrowButton to the side. The user can either type directly into the Text widget, or press the ArrowButton, when a list of items from which to choose is popped up immediately under the Text. Whether in fact the Text widget is directly editable, and whether the list of available options is permanently visible (as opposed to being displayed on user request by pressing the ArrowButtons) is controllable through resources when the ComboBox is created. This widget class is not intended to be used as a general manager. The ComboBox is discussed in Chapter 14, The ComboBox Widget. Sample ComboBoxes are shown in Figure 3-17.
Figure 3-17 ComboBoxes with other widgets
The Notebook ClassThe Notebook class lays out its children as though they are pages in a book. That is, only one child is currently visible at any given time, and they all occupy a single area on the screen; the user can chose from the available pages either by selecting from Tabs which can be associated with a child, or by activating the Page Scroller, which is typically a SpinBox. To complete the analogy, resources are provided to control the general book-like characteristics of the Notebook in terms of its binding and overlapping page appearance. The Notebook is a constraint widget: you add children, and then specify the role which each child is to perform. Typically, a Form or other manager is added to represent some page, and optionally PushButtons can be added and associated with a page in order to represent Tab inserts along the edges of the Notebook pages. The Notebook is discussed in Chapter 17, The Notebook Widget. Figure 3-18 shows a Notebook with Tabs inserted on the edge.
Figure 3-18 The Notebook widget
Geometry ManagementThe 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 accommodate 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 1, 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 4, 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.
Gadget ManagementIn 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 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.
In Motif 1.2, the 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 1.2 Manager and Gadget classes. It is possible to 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. Indeed, gadgets in Motif 2.1 have been redesigned with precisely this extra functionality.
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.
Keyboard TraversalKeyboard 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.
Putting Together a Complete ApplicationManagers 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.
The Main WindowEvery 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 Figure 3-19.
Figure 3-19 Recommended layout for MainWindow widget
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.
MenusMotif 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. Figure 3-20 shows a typical MenuBar and PulldownMenu.
Figure 3-20 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 Figure 3-21, so these menus are sometimes referred to as pullright menus.
Figure 3-21 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. Figure 3-22 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.
Figure 3-22 An OptionMenu
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 19, Menus.
The Window ManagerTo 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. Figure 3-23 shows the standard Motif window manager (mwm) decorations. For information on how to use mwm, see Motif Volume 3.
Figure 3-23 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 20, 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. Figure 3-24 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.
Figure 3-24 The Shell widget class hierarchy
Shells for MenusIn 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 widgetclass, 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 19, Menus.
Shells for Window Manager CommunicationShell 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 20, Interacting With the Window Manager, discusses window manager interactions in more detail.
Shells for DialogsYou 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.
Shells for Application WindowsWhen you initialize the X Toolkit with a call such as XtOpenApplication(), you are automatically returned a SessionShell widget to use as the top-level widget in your application5. 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.
DialogsSome 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 DialogsMessage 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 labelled 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.
ErrorDialogThe 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.
InformationDialogThe InformationDialog displays an "i" along with an informational message. These dialogs are usually displayed in response to a request for help.
MessageDialogThe 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.
QuestionDialogThe 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.
TemplateDialogMotif 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.
WarningDialogThe 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.
WorkingDialogThe 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.Figure 3-25 shows a typical QuestionDialog in an application. For more information on message dialogs, see Chapter 5, Introduction to Dialogs.
Figure 3-25 A QuestionDialog
Selection DialogsSelection 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 TextField widget that can be used to type in a choice which may or may not also be on the list. Figure 3-26 shows a SelectionDialog.
Figure 3-26 A SelectionDialog
The PromptDialog, as shown in Figure 3-27 is useful for prompting the user to enter some information.
Figure 3-27 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 Figure 3-28.
Figure 3-28 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. Figure 3-29 shows an example of a CommandDialog.
Figure 3-29 A CommandDialog
For detailed information about all of the different Motif selection dialogs, see Chapter 6, Selection Dialogs.
Custom DialogsThere 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.
Figure 3-30 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.
Figure 3-30 A custom dialog
Dialog ModalityOne 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 acquire input 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.
PixmapsIn 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() 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 requester 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:
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.Pixmap XmGetPixmapByDepth( Screen *screen char *image_name, Pixel foreground, Pixel background, int depth)
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.6 In Motif, you can use XmGetPixmapByDepth() to create a bitmap; you can also 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. Table 3-1 lists the image names predefined by the toolkit.
- Look in the pixmap cache for an image that has the same screen, image_name, foreground, background, and depth as the specified image. If there is a match, return the pixmap.
- If there is no match in the pixmap cache, look in the image cache for an image that matches the specified image_name. If there is a match, use the image to create the pixmap that is returned.
- Otherwise, interpret the image_name as a filename, read the pixmap data directly out of that file, and create the pixmap.
Table 3-1 Predefined Image Names in the Motif Toolkit Image Name
Solid background tile
A 25% foreground, 75% background tile
A 50% foreground, 50% background tile
A 75% foreground, 25% background tile
Vertical lines tile (Motif 1.2.3 onwards)
Horizontal lines tile (Motif 1.2.3 onwards)
As horizontal_tile (Motif 1.2.2 backwards compatibility)
As horizontal_tile (Motif 1.2.2 backwards compatibility)
Left slanting lines tile
Right slanting lines tile
A rightwards pointing arrow (Motif 2.1)
A leftwards pointing arrow (Motif 2.1)
A tick mark (Motif 2.1)
A horizontal line (Motif 2.1)
A rightwards pointing filled arrow (Motif 2.1)
A leftwards pointing filled arrow (Motif 2.1)
A filled arrow pointing downwards (Motif 2.1)
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:
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.Boolean XmInstallImage (XImage image, char *image_name)
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 any more 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 6B, 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/X11R6/include/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.
ColorColor 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. In any case, you should be wary when providing information or state purely through the use of color: a color-blind user may not notice the differences; color-blindness is not a trivial or rare issue.
The Motif widget set provides a number of widget resources that specify colors. All of the Motif widgets use the XmNforeground and XmNbackground resources. Although every widget class makes different use of the XmNbackground and XmNforeground 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. In Motif 2.1, gadgets can also be colored in much the same way that their widget equivalents can; in Motif 1.2, however, their colors are inherited from their Manager parent.
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 an 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. In Motif 1.2, 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. You can use the XmChangeColor() routine, which takes the following form:
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).void XmChangeColor (Widget widget, Pixel background)
The routine XmGetColors() can be used to query the colors which Motif calculates. XmGetColors() takes the following form:
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 could specify the appropriate resources for the widget.void XmGetColors( Screen *screen, Colormap colormap, Pixel bg, Pixel *fg, Pixel *top_shadow, Pixel *bottom_shadow, Pixel *select)
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 XmNforeground color. You cannot change the color of individual items in a List widget. The XmNbackground 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 XmNforeground 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.
Changes in Motif 2.1Release 2.1 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 2.1 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 2.1.
General Toolkit Changes
Gadget ResourcesGadgets can now be painted independently, and no longer directly inherit their color appearance from the Manager parent. Foreground, background, top and bottom shadow, and highlight colors are now included in the gadget cache. Similarly cached are the top and bottom shadow pixmaps, and the highlight pixmap.
TraitsA Trait is an encapsulation of a piece of logical widget behavior. It defines a set of methods for querying and setting this behavior, whatever it may be. Different widget classes may share in common the behavior, even though their class inheritance graphs are only vaguely related. To be more concrete, if we consider a ComboBox and a Text widget, the class hierarchy for the ComboBox does not derive through a Text class directly, and yet considered logically, because the ComboBox and the Text widget both have a value which is a string, there is sufficient in common such that we could define methods to read or write the value irrespective of which widget instance we are actually dealing with. Such methods already exist in Motif 2.0, and are known as a Trait.
Traits are named, and there is a standard routine for querying a widget to determine whether it supports a given trait. And thus there are two ways of setting the value of a text widget: we can use the older XmTextSetString() functional interface, or we can fetch the XmQTaccessTextual trait from the widget concerned, then use the setValue() routine of the trait. The beauty of the second method is that it will also work for other widgets in the Motif set which are logically also Text-like in some of their behavior.
However, Traits are really the domain of the widget author, to provide consistency in behavior between logically related widget classes. Mention of particular Traits will be made if and when necessary, otherwise you are referred to the Widget Writer's Guide in the official documentation.
Renditions and RenderTablesThe XmFontList data type and associated functions are now considered deprecated. In Motif 1.2, the appearance of compound strings depended upon a small number of widget attributes, of which the XmNfontList resource is the most important. The mechanisms for inheriting compound string appearance characteristics relied solely upon default XmFontList values derived usually from the containing VendorShell or BulletinBoard. In Motif 2.0, there is the new entity called the XmRendition, which is a named (tagged) object that consists of a complete set of appearance resources, including coloration, font, underline and strike-through settings. An XmRendition is a shareable object which is independently reference counted. An XmRenderTable is simply a set of XmRendition objects; compound strings are rendered by comparing tags associated with components in the string against tagged XmRendition objects in the XmRenderTable. The means whereby a widget inherits compound string rendering information is now rationalized through the Trait mechanisms: a parent widget may choose to implement a Trait which provides default render table data to its descendants. The BulletinBoard, VendorShell, and MenuShell classes implement such a Trait.
The appearance of a compound string can now be specified through a whole group of attributes that can be manipulated as a single set. Compound strings may now be multi-colored as a result.
An XmRendition object is a pseudo-widget: although not true widget classes, Renditions and RenderTables may be specified in resource files, as well as in code. Widget classes which used to support the XmNfontList now also support an XmNrenderTable resource. For backwards compatibility, the XmNfontList resource continues to persist, although it is internally implemented through the new XmRenderTable type.
It is not necessary to precisely specify all attributes for each and every Rendition within a RenderTable: attributes may be given the value XmAS_IS, which simply means that the value of the attribute is inherited from Renditions which are placed earlier in the RenderTable.
Renditions and RenderTables are discussed at length in Chapter 24.
TabListsIn Motif 1.2, creating tabular or multi-columnar data within a widget could usually only be performed through some code by the programmer which required careful calculations based upon the size of the current font. Motif 2.0 introduces the notion of an XmTabList, which is a set of XmTab objects. An XmTab describes a logical offset across a widget: it consists of a floating point quantity, a unit in which the quantity is expressed (inches, font units, millimetres, and so forth), and an offset model, which specifies whether the Tab value is counted in terms of absolute distance across the widget, or relative to a previous XmTab object in the XmTabList.
The new XmRendition object contains an XmTabList attribute. The creation of a multi-column list can now be achieved by embedding tab component separators within the compound strings of the list: each tab separator marks the beginning of a new column entry, where that column appears on the screen depends on the XmNtabList attribute of the Rendition used to render that portion of the compound string. Tabs and TabLists are covered as part of the discussion in Chapter 25, Compound Strings.
Compound StringsCompound strings have been re-modelled to use the new XmRendition object. In order to do this, new XmString component types have been defined.
The compound string segments XmSTRING_COMPONENT_RENDITION_BEGIN and XmSTRING_COMPONENT_RENDITION_END can be embedded into a compound string in order to associate portions of the string with particular Rendition specifications.
To enable tabular layout of compound strings, the new XmSTRING_COMPONENT_TAB segment is defined, and this marks a column boundary within the string. How this is rendered will depend upon the value of the XmTabList attribute associated with the current Rendition in force.
Additionally, the compound string segments XmSTRING_COMPONENT_LAYOUT_PUSH and XmSTRING_COMPONENT_LAYOUT_POP can be used to embed layout direction specifications into the string.
XmStringComponentCreate() has been augmented to create the new component types.
Compound Strings are discussed in Chapter 25.
Parse Mappings and Parse TablesStrings and compound strings can be dynamically manipulated by new table-driven parsing routines. An XmParseMapping represents an entry in the table, an XmParseTable is the table itself. Each entry in the table specifies a transformation: what to compare against in the original input string, what to replace any matching occurrence with, and so forth. The XmParseMapping object can either perform simple substitutions by supplying fixed substitution patterns, or it can specify further substitution routines which dynamically modify the input depending on circumstances.
Typically, parse tables and their constituent parse mapping objects are used by passing them as parameters to the XmStringParseText(), XmStringUnparse(), and XmStringGenerate() functions.
Essentially, parse tables are simply filters which provide programmatic control over the way in which strings are converted into compound strings, or vice versa.
Parse Mappings are discussed in Chapter 25, Compound Strings.
Layout DirectionIn Motif 1.2, although compound strings could be reversed by suitable setting of the XmNstringDirection resource, the layout of components in which they were rendered could not. The new Motif 2.0 XmNlayoutDirection resource rectifies the issue: it is possible to reverse the layout of a ComboBox, for example, so that the constituent arrow button is drawn to the left of the text. This could be performed at user request either for reasons of Internationalization or handedness. Layout direction resources are added to both the Manager and Primitive base classes: all Motif widgets therefore inherit the control.
Uniform Transfer ModelIn Motif 1.2, different styles of communication between widgets required separate code to implement. Thus the codes to implement data transfer through the ClipBoard, to the primary or secondary selection, and through Drag and Drop would not necessarily share much in common in terms of the functions required to achieve the desired effect. In Motif 2.0, the disparate communication interfaces have been subsumed into a common Uniform Transfer Model.
Under the Model, two new callbacks are added to the system: an XmNconvertCallback, and an XmNdestinationCallback. The convert callback is associated with the source of the data, and is both responsible for exporting the data in the format required by the destination, and in furnishing a list of formats in which the source is prepared to export that data. The destination callback communicates with the source in order to determine the best format in which to receive the data, and it arranges for the data to be handled appropriately when it arrives by setting up a transfer procedure to perform the task. The simplest destination callback could in fact request data in a fixed format from the source without bothering to request the list of supported forms.
The programmer is not required to implement convert and destination callbacks for all the various types of data transfer which Motif supports. Widgets have mechanisms which utilize the Trait system in order to effect default data transference. A programmer only needs to write convert or destination callbacks where the data is to be transferred in a manner which differs from the built-in target formats.
The Uniform Transfer Model is discussed in Chapter 23, The Uniform Transfer Model.
Automatic Popup SupportIn the past, in order to popup a context sensitive menu, it was necessary to write event handler code to intercept ButtonPress events, followed by the appropriate code to pick and display the relevant menu. In Motif 2.0, the RowColumn widget has been enhanced to provide auto-popup behavior, and the decision making process of selecting the relevant menu to display has been encapsulated in a new callback, the XmNpopupHandlerCallback, built into the Manager and Primitive classes. Now it is only necessary to provide the callback, filling in an appropriate field of the callback data, in order to specify the required menu: the housekeeping tasks of event interception and menu display are built-in.
Specific Widget ChangesMotif 2.1 introduces a number of new widget classes, as well as including new resources for classes previously defined.
VendorShellThe VendorShell has the new resources XmNbuttonRenderTable, XmNlabelRenderTable, and XmNtextRenderTable. These supersede the deprecated XmNbuttonFontList, XmNlabelFontList, XmNtextFontList resources respectively.
For finer control over the X input contexts which are created in Internationalized applications, the resource XmNinputMethod is provided: the value XmPER_SHELL creates one input context per shell hierarchy, the value XmPER_WIDGET creates one for each widget which requests one.
VendorShell also supports the XmNlayoutDirection resource. The widget does not use this resource itself, but maintains and supplies the resource as a default for whichever descendant in the widget hierarchy lacks an explicit value.
In Motif 2.0, XmNshellUnitType is considered deprecated: it is replaced by the XmNunitType resource. This also acts as a default value for widget descendants requiring resolution information.
ArrowButtonThe XmNdetailShadowThickness resource allows the programmer to specify the shadow thickness inside the triangle of the ArrowButton. The ArrowButtonGadget also supports the resource.
BulletinBoardThe BulletinBoard has the new resources XmNbuttonRenderTable, XmNlabelRenderTable, and XmNtextRenderTable which superseded the deprecated XmNbuttonFontList, XmNlabelFontList, XmNtextFontList resources respectively.
ComboBoxComboBox is a new widget as of Motif 2.0, combining direct textual input with the convenience of list selection.
ContainerContainer is a new widget in Motif 2.0. It organises IconGadget children in a variety of layout styles, including a Tree format.
DisplayThe XmDisplay object has suffered a number of changes in order to interface Motif with a CDE desktop. Most of the resources alter the appearance of Toggles, and the shadowing on Buttons, and are described fully in Volume 6B.
The most important of the new resources are the XmNnoFontCallback and XmNnoRenditionCallback lists. Whenever an attempt is made to render a compound string, if font or rendition information is found to be absent, a callback can be supplied by the programmer which can attempt to find an alternative. This is a significant improvement over Motif 1.2, where the system itself would decide on an appropriate default font without recourse to any intelligent intervention.
DrawingAreaDrawingArea now supports the new XmNconvertCallback and XmNdestinationCallback resources associated with the Uniform Transfer Model. The DrawingArea itself does not define any export target formats.
FileSelectionBoxIn Motif 2.0 and later, the search pattern and base directory path can be displayed in separate text fields, as opposed to being concatenated together and displayed in a single field. The resource XmNpathMode controls whether this new feature is enabled.
GadgetThe appearance resources XmNbackground, XmNbackgroundPixmap, XmNbottomShadowColor, XmNbottomShadowPixmap, XmNhighlightPixmap, XmNtopShadowPixmap are added so that Gadgets no longer strictly inherit their colors from the Manager parent.
As for the Manager and Primitive base classes, Gadget also supports XmNlayoutDirection to control the order in which components of the object are laid out.
GrabShellA new widget in Motif 2.0. GrabShell is a shell widget which grabs the pointer and keyboard when it is mapped. It therefore directs focus to its child, and is used by the ComboBox to implement its popup list.
IconGadgetNew in Motif 2.0, the IconGadget can display both textual and pixmap information simultaneously. The gadget is closely associated with the Container. Each IconGadget supposedly represents pictorially some application object of some kind, and the Container organises the layout and selection of the given objects. Extra "detail" data can be associated with an IconGadget, and the Container can display this extra information in a tabular format.
LabelThe XmNfontList resource is deprecated, and is superseded by the XmNrenderTable resource. Similarly for LabelGadget.
ListThe List supports keyboard matching of items in Motif 2.0 and later. If the resource XmNmatchBehavior is enabled, characters typed are compared with the first character of each item, and the new currently selected item is reset accordingly. The color of the selected item itself can now be specified through the XmNselectColor resource.
The set of selected positions can be manipulated through the new XmNselectedPositions, XmNselectedPositionCount resources.
The way in which the user selects items in the list is controllable through the XmNselectionMode resource. In XmNORMAL_MODE, navigating the list using the keyboard can select the item under the location cursor. In XmADD_MODE, navigating through the list has no side effects with respect to the selected item set.
The List supports the XmNdestinationCallback in order to make the widget partake in the Uniform Transfer Model.
MainWindowFrom Motif 2.0, the routine XmMainWindowSetAreas() is marked as deprecated. The programmer should set the XmNcommandWindow, XmNmenuBar, XmNmessageWindow, XmNworkWindow, XmNhorizontalScrollBar, XmNverticalScrollBar resources directly using the standard Xt mechanisms.
ManagerNew support for automatic popup menu control is provided through the Motif 2.0 XmNpopupMenuHandlerCallback.
The Motif 2.0 XmNlayoutDirection resource facilitates automatic layout control.
MenuShellThe XmNbuttonFontList and XmNlabelFontList resources are deprecated, and are superseded by the XmNbuttonRenderTable and XmNlabelRenderTable resources. Similarly deprecated is the XmNdefaultFontList resource, although there is no replacement XmNdefaultRenderTable resource.
NotebookNotebook is a new widget in Motif 2.0. It simply lays out its children as though they are pages in a book.
PanedWindowAs of Motif 2.0, the PanedWindow now officially supports a horizontal configuration: set the XmNorientation resource to XmHORIZONTAL or XmVERTICAL to taste.
PrimitiveThe XmNlayoutDirection, XmNconvertCallback resources are added to this base class.
To support automatic context-sensitive menus, the XmNpopupHandlerCallback has been added to the system.
PrintShellThe PrintShell interfaces with the X11R6 X Print (Xp) extensions. A widget hierarchy can be printed by creating that hierarchy underneath a PrintShell, followed by appropriate code to invoke the printing. Printing can be either synchronous, or asynchronous, and the programmer can decide, by setting appropriate widget resources, whether the output is to consist of the contents of the widgets concerned, or whether it is more of a screen snapshot of the widgets themselves.
RowColumnA new resource, XmNtearOffTitle, allows the programmer to specify a title for a tear-off menu.
ScaleAs of Motif 2.0, the Scale widget supports automatic tick marks. The function XmScaleSetTicks() evenly spaces marks of various sizes along the edge.
The Scale can be configured as to whether it responds to user input through the new XmNeditable resource: for a read-only scale, set the resource to false.
Arrows can be placed at either or both ends of the Scale through the XmNshowArrows resource, and the general appearance of the slider is configurable through XmNsliderMark: this can be configured to appear in various etched rectangle arrangements, as a circle, or as a thumb mark.
The size of the slider is configurable through the XmNsliderSize resource. This resource is undocumented by the official channels, and thus there is no official guidance to its usage.
The color of the slider is also tunable: it can either be based upon the foreground or background of the Scale, or upon the existing trough color. The XmNsliderVisual resource controls this aspect of behavior.
The Scale can behave as a thermometer, with the slider anchored at one end rather than floating in the middle. XmNslidingMode is the resource required to configure this setting.
Lastly, as of Motif 2.0, the XmNfontList resource is deprecated, and replaced with the newer XmNrenderTable resource. The Scale also supports the XmNconvertCallback list in order to participate in the Uniform Transfer Model.
ScreenThe XmScreen object has been enhanced to provide a greater control over the way in which Motif allocates colors. The XmNcolorAllocationProc resource allows the programmer to specify a procedure to perform the allocation. The default is the standard XAllocColor() routine.
Similarly, the algorithm by which Motif calculates default foreground, background, and shadow colors is also now tunable through the XmNcolorCalculationProc resource.
The allocation of pixmaps can be controlled through the XmNbitmapConversionModel resource: by default (XmMATCH_DEPTH) pixmaps are created such that the depth matches the widget for which they are allocated. Setting the value to XmMATCH_DYNAMIC converts loaded bitmap files to a pixmap depth of 1.
Also on the subject of pixmaps, the XmNinsensitiveStipplePixmap resource provides a stipple to use when making widgets appear insensitive. This is mostly used internally by the Gadget utilities.
Motif as of version 2.0 supports the notion of color objects: the XmNuseColorObject resource enables the feature, such that if a color is dynamically altered, all widgets which reference the color are changed as a side effect. Clearly, this resource is part of the CDE enhancements to Motif: it allows the desktop to change the whole style of color of an application without having to modify the entire widget hierarchy.
ScrollBarMuch of the enhancements associated with the Scale are in fact related to the ScrollBar: XmNeditable, XmNshowArrows, XmNsliderMark, XmNsliderVisual, XmNslidingMode are all newly supported as of Motif 2.0.
The resource XmNsnapBackMultiple controls the behavior of the ScrollBar if the user drags the mouse outside the bounds of the widget. It specifies a distance, which if exceeded, causes the ScrollBar to snap back to its pre-drag settings.
As of Motif 2.0, the ScrolledWIndow (and derived classes) supports automatic drag through the resource XmNautoDragModel.
SpinBox and SimpleSpinBoxTwo new widget classes, the first available as of Motif 2.0, the second from Motif 2.1, which allows the user to rotate through a range of values. SpinBox is the general purpose manager, into which any number of Text components are added. It rotates the values associated with the Text component which currently has the focus. SimpleSpinBox is a pre-packaged unit that contains a single built-in Text component. The range of values associated with any Text is specified through constraint resources. Rotation of the values is achieved by pressing on an ArrowButton which the SpinBox components automatically add for the purpose.
Text and TextFieldThe number of lines within the Text is now available through the XmNtotalLines resource, added as of Motif 2.1.
In both widget classes, the XmNfontList resource is obsolete, replaced with the XmNrenderTable resource, and the XmNdestinationCallback is added in order to interface with the Uniform Transfer Model.
ToggleButton and ToggleButtonGadgetThe Toggle widgets have been reworked in order to provide consistency of appearance under the CDE environment.
The resource XmNdetailShadowThickness controls the thickness of the shadow on the Toggle indicator.
In Motif 2.0 and later, a Toggle may be in one of three states: set, unset, and indeterminate. By default, the Toggle holds two states, unless the resource XmNtoggleMode is set to XmTOGGLE_INDETERMINATE, which enables the third state. The resource XmNindeterminateInsensitivePixmap and XmNindeterminatePixmap are pixmaps displayed when the toggle is in the third indeterminate state.
In Motif 1.2, the resource XmNindicatorOn is a Boolean value; in Motif 2.0 and later, this becomes an enumerated type, and specifies not just whether the indicator is visible, but also its appearance: a check box, shadowed box, check (tick) mark, cross, and so on become available. This blurs the distinction with the resource XmNindicatorType, which is extended to include XmONE_OF_MANY_ROUND, XmONE_OF_MANY_DIAMOND, indicating a round or diamond shaped indicator.
The resource XmNset also changes type from Boolean to an enumeration. The valid range is now XmUNSET, XmSET, and XmINDETERMINATE.
Lastly, an XmNunselectColor is added from Motif 2.0 onwards to complement the XmNselectColor resource.
Changes to the Example ProgramsAll of the example programs in this book have been updated to Motif 2.1 and X11R6. For example, calls to manipulate compound strings and font lists have been replaced with calls to handle the new render table type.
Changes involving new Motif 2.1 functions and resources are described in detail when each example is presented.
SummaryThe 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.
1 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.
2 In fact, in Motif 2.1, drag and drop for a Label, LabelGadget, or Scale may be disabled by default if the resource XmNenableUnselectableDrag is False. See the section on XmDisplay in Volume 6B for more details.
3 The IconGadget is exceptional: there is no widget equivalent to this gadget class.
4 Available from Motif 2.0 onwards.
5 The ApplicationShell, XtAppInitialize() and XtVaAppInitialize() are considered deprecated in X11R6.
6 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.