/* trivial.uil −− Illustrate a minimal widget declaration. */
module trivial
object root : XmPushButton { };
end module;
The widget definition in the source code consists of three parts, not including the object keyword. The definition
begins with the widget name, which is a programmer−defined identifier. The name of the widget in this example is
root. The type of widget follows the name; a colon separates the name and the type. Legal widget types include all
of the standard Motif widgets as well as the names of specific instances of Motif widgets, such as XmMenuBar (a
RowColumn) or XmQuestionDialog (a MessageBox). You can find a complete list of widget type names in
Appendix D, Table of UIL Objects, of Volume Six B, Motif Reference Manual. UIL also supports non−Motif
widgets with the user_defined type, which we explain later in Chapter 26, Advanced UIL Programming. The
last, and usually largest, part of a widget definition is made up of the widget attributes. In our simple definition, we do
not specify any attributes, but even so, we must include the curly braces that would surround them. Widget definitions
always end with a semicolon.
After compiling the module, we can display its output with the showuid program. The following two commands
accomplish these steps:
uil −o trivial.uid trivial.uil
showuid trivial
You don't need to use the −root option because the PushButton uses the default widget name root. The output of
the program appears in the figure.
User interface of trivial.uil
25.2.1 Specifying Widget Attributes
A bare−bones widget definition like the one in the previous example is rare in even the simplest Motif applications.
To create a useful interface, you need a hierarchy of customized widgets, which is where widget attributes enter the
picture. When you define a widget in UIL, you can specify children and resources in subsections of its attribute
section. The controls subsection contains a list of a manager widget's children, and the arguments and
callbacks subsections contain lists of the widget's resource and callback settings. Each subsection begins with the
subsection name followed by a list of children, resources, or callback settings. Each subsection can occur only once in
a single widget definition, but they can occur in any order. The controls subsection of a widget definition is where
you specify the children of the widget. The name of this subsection was chosen because the parent widget manages, or
controls, the child widgets. The module in the source code shows a typical usage of the controls subsection.
25 Creating a User Interface With UIL25.2.1 Specifying Widget Attributes
659
/* kids.uil −− Simple demonstration of the controls subsection. */
module kids
object top : XmTextField { };
object bottom : XmPushButton { };
object root : XmPanedWindow {
controls {
XmTextField top;
XmPushButton bottom;
};
};
end module;
In this example, we define three widgets: a TextField, a PushButton, and a PanedWindow. The controls subsection
of the PanedWindow specifies that the TextField and the PushButton are its children. The example illustrates the form
of an entry in a controls subsection, where the widget type is followed by the name of a widget and a semicolon.
Even though the type of the widget has already been specified in a separate widget definition, you must specify it
again here. In this example, we define the children before their parent, but widgets referenced in a controls
subsection can be defined anywhere in the UIL module because UIL allows forward references. The output of the
module is shown in the figure, where we typed some text in the TextField.
User interface of kids.uil
Each of the three widget definitions begins with object, which means that each of them is in a separate object
section. Technically, you only need the object keyword before the first widget in consecutive definitions. Although
the convention of placing an object keyword before each definition requires a bit more typing, it makes definitions
easier to recognize and move around in a module.
One advantage of defining your interface with UIL is that the compiler always makes sure that the children listed in a
controls subsection are allowed for that parent. If you try to use an unsupported widget, the UIL compiler issues
an error message, and the compilation fails. Appendix D, Table of UIL Objects, in Volume Six B, Motif Reference
Manual, contains a complete listing of the Motif widgets and the children that they support. In contrast, when you
create widgets directly with Xt, there is no compile−time checking that makes sure the widget hierarchy is valid.
Many of the Motif manager widgets provide some form of run−time checking, but we don't recommend relying on
this behavior.
The presence of a widget definition in a UIL module does not necessarily mean that the widget is created at run−time.
A widget is not created until you fetch it directly with MrmFetchWidget() or MrmFetchWidgetOverride(),
or it appears in a widget hierarchy fetched with one of these routines. By referencing a widget in a controls
subsection, you make it part of a widget hierarchy. When the hierarchy is fetched, all of the widgets in the hierarchy
25 Creating a User Interface With UIL25.2.1 Specifying Widget Attributes
660
are created. (The widget creation process is described in Section #suilcreate.) If a widget is defined, but never
referenced or fetched from an application, it is never created.
When a widget is created based on a UIL definition, you are not limited to creating a single instance of it. Every call
to MrmFetchWidget() or MrmFetchWidgetOverride() results in the creation of a new widget, assuming a
definition is found. In addition, each widget reference in a controls subsection results in the creation of an instance
of that widget when the enclosing hierarchy is fetched. This behavior lets you reuse a widget as often as necessary.
You can reuse widgets at any level, from a single widget to an entire hierarchy. You can place a complete widget
definition inside a controls subsection, instead of referencing a widget defined elsewhere. For example, we can
move the child widget definitions from the source code into the body of the PanedWindow definition, as shown in the
following fragment:
object root : XmPanedWindow {
controls {
top : XmText { };
bottom : XmPushButton { };
};
};
The form of an in−line widget definition is the same as a widget definition in an object section. In−line definitions
are most useful for specifying widget children that have few or no attributes. While larger definitions are allowed,
they tend to clutter up the parent definition, which makes both reading and editing the module more difficult.
Unlike widgets defined in an object section, the name of an in−line widget is optional. This feature is most frequently
used in menu definitions, as the following fragment illustrates:
object file_menu : XmPulldownMenu {
controls {
XmPushButton open;
XmPushButton print;
XmSeparator { };
XmPushButton quit;
};
};
This definition contains an unnamed Separator, along with references to three PushButtons that are defined elsewhere.
In this situation, it is worthwhile to create a stand−alone definition for the Separator because it doesn't have any
attributes. The UIL compiler automatically generates a name when you don't provide one. The format of these names
is not documented and can vary from one compilation to the next. If a widget does not have a well−defined name,
neither you nor the users of your application can customize it using X resource files. If you want to allow such
customizations, you must explicitly name the widget. When you define an object of a class that has both a widget and
a gadget variant, you can specify in the definition which type is created. Motif supports widget and gadget variants of
the Label, PushButton, ToggleButton, ArrowButton, CascadeButton, and Separator objects. As we explained in
Section #suiloptions, you can specify the default type for each class in the objects option setting at the top of a
module. If you do not set this option, widgets are used by default. The following code fragment demonstrates how to
define a PushButtonGadget, regardless of the default PushButton type setting:
object push_me : XmPushButton gadget { };
UIL also supports the type names with Gadget appended, so the following definition is also legal:
object toggle_me : XmToggleButtonGadget { };
25 Creating a User Interface With UIL25.2.1 Specifying Widget Attributes
661
You can use the widget keyword to ensure that the widget version of an object is created, as shown in the following
fragment:
object this_way : XmArrowButton widget { };
This syntax is the only way to specify a widget variant; the UIL compiler does not recognize type names such as
XmArrowButtonWidget. Several Motif widgets are compound objects, which means that they are composed of
one or more simpler widgets. For example, the FileSelectionBox is a complete dialog box packaged as a widget; it
contains Lists, TextFields, Labels and PushButtons. As of Motif 1.2, UIL lets you access and customize the
automatically−created children of a compound object. Like other child widgets, you reference automatically−created
children in the controls subsection of their parent, although the syntax is slightly different. The following code
fragment illustrates this syntax:
object yes_or_no : XmQuestionDialog {
controls {
Xm_OK {
arguments {
XmNlabelType = XmPIXMAP;
XmNlabelPixmap = xbitmapfile ('thumb_up.xbm');
};
};
};
};
This fragment shows how to make the OK PushButtons in a QuestionDialog display an icon instead of the usual text
string. The name of this button is Xm_OK. The name is followed by attribute settings, just like any other widget
definition. lists the names of all the automatically−created children of each of the Motif composite widgets. tab(@),
linesize(2); lp9 | lp9 lp9 | lp9.
Widget@Child Names
_
XmScale@Xm_Title XmScrolledWindow@Xm_VertScrollBar, Xm_HorScrollBar
XmOptionMenu@Xm_OptionLabel, Xm_OptionButton XmPopupMenu@Xm_TearOffControl
XmPulldownMenu@Xm_TearOffControl XmMainWindow@Xm_Separator1, Xm_Separator2, Xm_Separator3
XmMessageBox@T{ Xm_Symbol, Xm_Separator, Xm_Message, Xm_OK, Xm_Cancel, Xm_Help T}
XmSelectionBox@T{ Xm_Items, Xm_ItemsList, Xm_Selection, Xm_Text, Xm_Separator, Xm_OK, Xm_Apply,
Xm_Cancel, Xm_Help T} XmFileSelectionBox@T{ Xm_Items, Xm_ItemsList, Xm_Separator, Xm_OK,
Xm_Cancel, Xm_Help, -Xm_FilterLabel, Xm_Filter, Xm_FilterText, Xm_DirList, Xm_Dir T}
_ Remember that the Motif compound objects provide resources that allow you to set the commonly−used resources
of their children. For example, the XmNmessageString resource of the QuestionDialog is the same as the
XmNlabelString resource of its Xm_Message child. It is better to set the resource on the compound object rather
than on the child, so we suggest that before you set a resource on an automatically−created child, you make sure that
the resource cannnot be set in the arguments subsection of the parent. Mrm automatically manages all of the
widgets that you fetch with the exception of dialogs, menus, and the widget at the top of the fetched hierarchy. You
can prevent Mrm from managing individual widgets by preceding their controls subsection entry with the
unmanaged keyword, as shown in the following fragments:
object panel : XmRowColumn {
controls {
XmPushButton visible;
unmanaged XmPushButton invisible;
};
};
object error : XmErrorDialog {
25 Creating a User Interface With UIL25.2.1 Specifying Widget Attributes
662
controls {
Xm_Help unmanaged { };
};
};
When the panel RowColumn widget is created, both PushButtons are created, but only the first one is managed.
When you want to manage the other button, your application code must handle it, just like it must manage dialogs and
popup menus. You can also unmanage automatically−created children as shown in the second object definition above.
In this case, the unmanaged keyword follows the name of the automatically−created widget instead of preceding it.
In UIL, you specify resources (with the exception of callbacks) in the arguments subsection of a widget definition.
The UIL module in the source code shows several examples of resource settings.
/* resource.uil − Basic example of setting widget resources. */
module resource
object root : XmPushButton {
arguments {
XmNlabelString = "Candy−Gram!";
XmNmarginWidth = 350;
XmNmarginHeight = 350;
XmNunitType = Xm100TH_MILLIMETERS;
XmNforeground = color ('SlateGrey');
XmNbackground = color ('LemonChiffon');
XmNfontList = font ('*times−bold−r−normal*180−100−100*');
};
};
end module;
In this example, we set several PushButton resources. These settings demonstrate the use of a number of UIL data
types. However, we're not going to discuss the data types right now, as they are covered later in Section #suiltypes.
The basic format of each setting is the same. Each consists of a resource name, an equal sign (=), a value, and a
semicolon. the figure shows the output of this example, which is quite different from the simple PushButtons in our
earlier examples.
User interface of resource.uil
Creating a PushButton with the same resource settings in application code requires a lot more work. You need to
declare variables for the XmString, Color, and XmFontList values and then you must create or allocate each of
these values by calling various Xm, Xt, and X routines. After the values are created, you can create the widget. Any
values copied by the widget should be freed. When you use UIL and Mrm, all of this work boils down to the much
simpler widget definition shown above and a single call to MrmFetchWidget().
25 Creating a User Interface With UIL25.2.1 Specifying Widget Attributes
663

Get Volume 6A: Motif Programming Manual now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.