Widget widget;
XtPointer client_data;
XtPointer call_data;
{
Cursor cursor;
Display *display;
Widget help_widget;
XmAnyCallbackStruct *cbs, *newcbs;
XEvent *event;
cbs = (XmAnyCallbackStruct *) call_data;
display = XtDisplay (toplevel);
cursor = XCreateFontCursor (display, XC_hand2);
help_widget = XmTrackingEvent (toplevel, cursor, True, &event);
while (help_widget != NULL) {
if (XtHasCallbacks (help_widget, XmNhelpCallback) ==
XtCallbackHasSome ) {
newcbs−>reason = XmCR_HELP;
newcbs−>event = event;
XtCallCallbacks (help_widget, XmNhelpCallback,
(XtPointer) newcbs);
help_widget = NULL;
}
else
help_widget = XtParent (help_widget);
}
XFreeCursor (display, cursor);
}
When the user selects the menu item for context−sensitive help, query_for_help() is invoked. This routine calls
XmTrackingEvent() to allow the user to specify a widget on which to see help information. The confine_to
parameter is set to True, so the pointer is constrained to the window of the toplevel widget. We use toplevel
so that the user can select any component in the entire application.
XmTrackingEvent() changes the pointer to the specified cursor to provide visual feedback that the application is
in a new state. Since the user is expected to click on a object, the routine uses the XC_hand2 glyph that shows a
pointing hand. The cursor is created using XCreateFontCursor(). See Volume One, Xlib Programming
Manual, for more information.
If the user clicks on any valid widget within the application, XmTrackingEvent() returns the ID for that widget.
The widget itself is not activated and it does not receive any events that indicate that anything has happened at all. If
the user does not click on a valid widget, the function returns NULL. If XmTrackingEvent() returns a widget ID,
we use XtCallCallbacks() to activate the XmNhelpCallback for the widget. If the widget does not have a
help callback, query_for_help() climbs the widget tree looking for an ancestor widget with a help callback.
While the confine_to flag makes XmTrackingEvent() useful for constraining mouse movement, you should
use this feature with caution. Once the cursor is confined to the window, the server grab is not released until the user
presses the mouse button. We also advise caution if you are using a debugger while working with this function. If the
debugger stops at a breakpoint while the function is invoked, you will have to log in remotely and kill the debugger
process to release the pointer grab. If you kill the process, you will have to shut down the computer.
22.2 Working Dialogs
22 Advanced Dialog Programming 22.2 Working Dialogs
607
The Motif WorkingDialog is used to inform the user that an application is busy processing, so that it doesn't have the
time to handle other actions the user may take. For example, if your application is busy trying to figure out the
complete value of pi, the user is probably going to have to wait for the application to respond to her next action. The
delay occurs because the application code has control, rather than Xt. When Xt has control, it processes events and
dispatches them to the appropriate widgets in the application. If a widget has a callback installed for an event, Xt
returns control to the application. While the application has control, there is no way for the window system to service
any requests the user may happen to make.
In the meantime, the application is faced with the dilemma of how it is going to process events that happen in the
interim. While your application is busy number−crunching, the user is frantically pounding on the Stop button and
hoping that the application will figure out that she really didn't want it to figure out the complete value of pi, but
instead to print out the recipe for cherry pie.
What the application needs to do is to find a way to do the necessary work for callback routine and process events at
the same time. The solution is conceptually simple: the application should periodically check to see if there are any
events in the input queue, and if there are, process and dispatch them. The implementation of this solution, on the
other hand, is quite a different story. There are a number of different approaches you can take, depending on the
nature of the work you are trying to do. Let's examine four of the options:
If the task can be broken down into tiny chunks, you can set up work procedures that are invoked
automatically by Xt when there are no events on the event queue. Since events are very infrequent in terms of
processor time, this type of processing goes quite quickly. This technique works best for tasks that are not
critical to the application; the tasks can be done in the background and not interfere with the normal
event−processing loop. To minimize the effect on system performance, you should be sure to break the task
into small components time−wise.
You can set timer event handlers to go off periodically using XtAppAddTimeOut(). As each timer fires,
another chunk of work is done before control is returned to Xt. While this method is similar to using work
procedures, the time intervals may be more in tune with the type of processing you are doing. Timers are
typically used when the work being done is synchronous with the system clock or some other regular interval.
However, timers are not associated directly with the system clock, so a task should not rely on their accuracy.
You can choose to maintain control and use Xlib and Xt functions to process events yourself. In this case,
your application checks for events in the queue and processes them. This technique is appropriate for
applications that need to perform complex operations, as it is possible to handle sophisticated looping
constructs, process recursively, or manage complex state information.
You can simply choose to ignore events entirely. In this case, it is best to set the cursor to a stopwatch or hour
glass shape, and/or post a message that indicates that the user must wait. This solution is sometimes the only
one available if the task is dependent on some outside entity. Examples include device driver communication
(printer, disk drives), network communications (NFS), interprocess activity (forks and pipes), or anything that
puts the application in a state where it has no control over the object with which it is communicating.
You can mix and match some of these techniques. Say the user wants to send a large PostScript file to a laser printer.
When she clicks on the Print button, you can post a WorkingDialog that reports that the file is being printed and the
user must wait. Additionally, you could provide an option that allows the user to send the file to the printer in the
background. In this case, you can send the file to the printer in small chunks using work procedures.
The four methods fall into two basic categories:
Xt maintains control, processes events as normal, and periodically calls application -routines
The application takes control, performs the necessary tasks, and periodically calls Xlib functions to check the
event queue
22 Advanced Dialog Programming 22.2 Working Dialogs
608

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.