User interface of quitbox.uil
The Quit PushButton manages the dialog, which causes it to be displayed. Pressing the OK PushButton exits the
application. There is no need to use the unmanage() callback in this example, as the Cancel PushButton unmanages
the dialog by default. You can easily apply the manage() and unmanage() callbacks to other dialogs in an
interface.
27.5.2 Creating Widgets
In the source code the entire user interface is defined in a single widget hierarchy. This technique is fine for a small
application, but for performance reasons it is not practical in a larger application. Creating a separate hierarchy for
each window allows you to divide an interface into separate modules, as discussed earlier in this chapter. The only
drawback to distributing dialog creation is that it takes longer for a dialog to appear the first time it is displayed. Since
this delay is typically not noticeable, we still recommend this approach.
You can support the as−needed dialog creation policy in UIL by adding another callback that creates a widget
hierarchy. A new widget hierarchy is created by calling MrmFetchWidget(). As a reminder, this function takes the
following form:
Cardinal
MrmFetchWidget(hierarchy, widget_name, parent, widget_return,
class_return)
MrmHierarchy hierarchy;
String widget_name;
Widget parent;
Widget *widget_return;
MrmType *class_return;
A creation callback needs three values to be able to create a new widget hierarchy. These values are the first three
arguments to MrmFetchWidget(). The MrmHierarchy is already available in the application program, so we
only need to make it a global variable instead of a local variable in main(). Since the callback accesses the hierarchy
repeatedly, we also need to remove the call to MrmCloseHierarchy(). In order to get the other two arguments,
we use an asciz_table that contains the names of the parent widget and the widget to create. We can convert the
name of the parent to a widget ID using XtNameToWidget(). This technique only works if we specify a unique
name for each widget. Since we need the top−level widget as an argument to this routine, it becomes a global variable
as well. The complete callback appears in the source code
void
27 Advanced UIL Programming 27.5.2 Creating Widgets
738
create (w, client_data, call_data)
Widget w;
XtPointer client_data;
XtPointer call_data;
{
String *args = (String *) client_data;
String parent_name = args[0];
Widget parent;
/* Get a widget id for the parent widget. */
if (strcmp (parent_name, "toplevel") != 0)
parent = XtNameToWidget (toplevel, parent_name);
else
parent = toplevel;
/* If the parent was found try to create the hierarchy. */
if (parent == NULL)
fprintf (stderr, "Create: No such widget '%s'0, args[0]);
else {
String child_name = args[1];
Widget new_w;
Cardinal status;
MrmType class;
status = MrmFetchWidget (hierarchy, child_name, parent,
&new_w, &class);
if (status != MrmSUCCESS)
fprintf (stderr, "Failed to create hierarchy '%s'0, child_name);
}
/* After the widget is created, this callback can be removed. */
XtRemoveCallback (w, XmNactivateCallback, create, client_data);
}
The callback assigns the client_data argument to a String array, since that is appropriate for the UIL
asciz_table type. The routine also converts the name of the parent widget to a widget ID using
XtNameToWidget(). Since that routine does not consider the top−level widget in its search, the callback performs
a special test for that widget. If the routine finds the ID for the parent widget, it attempts to create the new widget
hierarchy. Once the hierarchy is created, the callback is removed so that the widget hierarchy is not created more than
once. We make the assumption that if the creation fails once, subsequent attempts will also fail.
With the addition of the create() callback, we can split the source code into two modules. Unfortunately, breaking
up the module into two introduces a new problem. Now that we have two separate widget hierarchies, the manage()
callback can no longer reference the quit_dialog widget because it is defined in another hierarchy. One solution
to this problem is to export the widget ID of the dialog as a UIL identifier, using the MrmNcreateCallback
(illustrated in Chapter 25, Building an Application With UIL). The problem with this approach is that you must
maintain a list of identifiers for all of the exported widgets. Another solution, which avoids this problem, uses
XtNameToWidget() in the manage() and unmanage() callbacks to obtain a widget ID given a widget name.
The revised callbacks are shown in the source code
void
manage (w, client_data,call_data)
Widget w;
XtPointer client_data;
XtPointer call_data;
{
String name = (String) client_data;
Widget target = XtNameToWidget (toplevel, name);
27 Advanced UIL Programming 27.5.2 Creating Widgets
739
if (target != NULL)
XtManageChild (target);
else
fprintf (stderr, "Cannot manage widget named %s0, name);
}
void
unmanage (w, client_data, call_data)
Widget w;
XtPointer client_data;
XtPointer call_data;
{
String name = (String) client_data;
Widget target = XtNameToWidget (toplevel, name);
if (target != NULL)
XtUnmanageChild (target);
else
fprintf (stderr, "Cannot unmanage widget named %s0, name);
}
Now we can rewrite the quitbox example using two modules. The main window definition is listed in the source code
module mainwindow
procedure
manage (string);
create (asciz_table);
list confirm_quit : procedures {
create (asciz_table ("toplevel", "quit_dialog"));
manage ("*quit_dialog");
};
object quitb : XmPushButton {
arguments {
XmNlabelString = "Quit";
};
callbacks {
XmNactivateCallback = procedures confirm_quit;
};
};
object root : XmMainWindow {
controls {
XmPushButton quitb;
};
};
end module;
The XmNactivateCallback of the Quit PushButton now creates the confirmation dialog and manages it. The
parent and widget to be created are passed to the creation callback in an asciz_table. Because the create()
callback removes itself, subsequent invocations of the callback only manage the dialog. XtNameToWidget()
expects a qualified widget name, much like resource specifications, so we must precede the name passed to the
manage() callback with an asterisk. The quit_dialog is now defined in a separate module, shown in the source
code
module quitbox
27 Advanced UIL Programming 27.5.2 Creating Widgets
740
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.