Work procedures and timers return control to Xt and allow it to process events as normal. In turn, Xt gives control
back to the application for short intervals every now and then. When the application maintains control, it can query
and process X events whenever it wants. While this process is more complicated, it does make it easier for the
application to control its own processing.
In all four situations, you can decide whether or not to display a WorkingDialog. If you want to give the user the
ability to terminate the work in progress, you can provide a Stop button in the dialog. Otherwise, you can simply
display the dialog for informational purposes. If you do not want the user to interact with other windows in the
application while the WorkingDialog is being displayed, you can make the dialog modal as described in Section
#smodaldlg.
22.2.1 Using Work Procedures
Work procedures in Xt are extremely simple in design. They are typically used by applications that can process tasks
in the background. When a work procedure is used in conjunction with a WorkingDialog, the application can provide
feedback on the status of the task. Say the user wants to load a large bitmap into a window. The nature of your
application requires you to load the file from disk into client−side memory, perform some bitmap manipulation, and
then send the bitmap to the X server to be loaded into a pixmap. If you suspect that this task might take a long time
and you want to allow the user to interrupt it, you can use work procedures and a WorkingDialog.
Unfortunately, demonstrating such a task is difficult, due to its extremely complex nature. The bitmap loading
operation requires a great deal of image−handling code that is a distraction from the issue at hand, which is installing a
work procedure. To get around this problem, we present a short, abstract program that demonstrates the use of a work
procedure. In the source code we represent a time−consuming task by counting from 0 to 20000.
XtSetLanguageProc() is only available in X11R5; there is no corresponding function in X11R4.
XmStringCreateLocalized() is only available in Motif 1.2; XmStringCreateSimple() is the
corresponding function in Motif 1.1.
/* working.c −− represent a complicated, time−consuming task by
* counting from 0 to 20000 and provide feedback to the user about
* how far we are in the process. The user may terminate the process
* at any time by selecting the Stop button in the WorkingDialog.
* This demonstrates how a WorkingDialog can be used to allow the
* user to interrupt lengthy procedures.
*/
#include <Xm/MessageB.h>
#include <Xm/PushB.h>
#define MAXNUM 20000
void done();
/* Global variables */
static int i = 0;
static XtWorkProcId work_id;
main(argc, argv)
int argc;
char *argv[];
{
XtAppContext app;
Widget toplevel, button;
XmString label;
void pushed();
22 Advanced Dialog Programming 22.2.1 Using Work Procedures
609
XtSetLanguageProc (NULL, NULL, NULL);
toplevel = XtVaAppInitialize (&app, "Demos",
NULL, 0, &argc, argv, NULL, NULL);
label = XmStringCreateLocalized ("Press Here To Start A Long Task");
button = XtVaCreateManagedWidget ("button",
xmPushButtonWidgetClass, toplevel,
XmNlabelString, label,
NULL);
XtAddCallback (button, XmNactivateCallback, pushed, app);
XmStringFree (label);
XtRealizeWidget (toplevel);
XtAppMainLoop (app);
}
/* pushed() −− the callback routine for the main app's pushbutton. */
void
pushed(w, client_data, call_data)
Widget w;
XtPointer client_data;
XtPointer call_data;
{
XtAppContext app = (XtAppContext) client_data;
Widget dialog;
XmString stop_txt;
Arg args[5];
int n;
Boolean count();
/* Create the dialog −− the "cancel" button says "Stop" */
n = 0;
stop_txt = XmStringCreateLocalized ("Stop");
XtSetArg(args[n], XmNcancelLabelString, stop_txt); n++;
dialog = XmCreateWorkingDialog (w, "working", args, n);
XmStringFree (stop_txt);
work_id = XtAppAddWorkProc (app, count, dialog);
XtUnmanageChild (XmMessageBoxGetChild (dialog, XmDIALOG_OK_BUTTON));
XtUnmanageChild (XmMessageBoxGetChild (dialog, XmDIALOG_HELP_BUTTON));
/* Use cancel button to stop counting. True = remove work proc */
XtAddCallback (dialog, XmNcancelCallback, done, True);
XtManageChild (dialog);
XtPopup (XtParent (dialog), XtGrabNone);
}
/* count() −− work procedure that counts to MAXNUM. When we get there,
* change the "Stop" button to say "Done".
*/
Boolean
count(client_data)
XtPointer client_data;
{
Widget dialog = (Widget) client_data;
char buf[64];
XmString str, button;
Boolean finished = False;
22 Advanced Dialog Programming 22.2.1 Using Work Procedures
610
/* If we printed every number, the flicker is too fast to read.
* Therefore, just print every 1000 ticks for smoother feedback.
*/
if (++i % 1000 != 0)
return finished;
/* display where we are in the counter. */
sprintf (buf, "Counter: %d", i);
str = XmStringCreateLocalized (buf);
XtVaSetValues (dialog, XmNmessageString, str, NULL);
XmStringFree (str);
if (i == MAXNUM) {
i = 0;
finished = True;
button = XmStringCreateLocalized ("Done");
XtVaSetValues (dialog, XmNcancelLabelString, button, NULL);
XmStringFree (button);
XtRemoveCallback (dialog, XmNcancelCallback, done, True);
XtAddCallback (dialog, XmNcancelCallback, done, False);
XMapRaised (XtDisplay (dialog), XtWindow (XtParent (dialog)));
}
/* Return either True, meaning we're done and remove the work proc,
* or False, meaning continue working by calling this function.
*/
return finished;
}
/* done () −− user pressed "Stop" or "Done" in WorkingDialog. */
void
done(dialog, client_data, call_data)
Widget dialog;
XtPointer client_data;
XtPointer call_data;
{
Boolean remove_work_proc = (Boolean) client_data;
if (remove_work_proc) {
i = 0;
XtRemoveWorkProc (work_id);
}
XtDestroyWidget (dialog);
}
The main application simply displays a button. When the user presses the button, the application starts counting and
displays a WorkingDialog. The user can press Stop at any time during the process. If the user allows the application to
finish counting, the button is changed from Stop to Done. the figure shows both states of the WorkingDialog.
22 Advanced Dialog Programming 22.2.1 Using Work Procedures
611
Output of working.c
This program is designed to demonstrate how a work procedure and a WorkingDialog can interact. The callback for
the button in the application creates a WorkingDialog using -XmCreateWorkingDialog(). The callback routine
also installs a work procedure using XtAppAddWorkProc(). This function takes the following form:
XtWorkProcId
XtAppAddWorkProc(app_context, proc, client_data)
XtAppContext app_context;
XtWorkProc proc;
XtPointer client_data;
The WorkingDialog is used as the client data for the count() work procedure, so that the procedure can update the
dialog. To allow the user to interrupt the counting operation, we install done() as the XmNcancelCallback
resource. If the user presses the Stop button, this routine is invoked. The routine stops the counting operation by
removing the work procedure using XtRemoveWorkProc().
During the counting operation, Xt calls the work procedure when there are no events that need to be processed. The
work procedure increments the global counter variable, i. Each time i reaches an increment of 1000, the
XmNmessageString for the WorkingDialog is updated to inform the user about the progress of the operation. The
work procedure returns True when the task is complete, which causes Xt to remove the procedure from the list of
work procedures being called. When count() returns False, Xt continues to call the routine when the application
is idle.
If the user allows the task to complete, the work procedure changes the action button to say Done and removes the
XmNcancelCallback. The procedure then reinstalls the callback in order to change the client data from True to
False. The client data must be set to False so that done() does not try to remove the work procedure. Since the
work procedure returns True in this case, Xt removes the procedure for us.
The work procedure also calls XMapRaised() to ensure that the dialog is visible when the operation completes. The
user must explicitly press the Done button to remove the dialog. Another approach is to call XtDestroyWidget()
to remove the dialog when the processing is done. In this case, the user is not notified that the operation has finished,
but she also does not have to respond to the dialog.
An application can install multiple work procedures, but Xt only processes one procedure at a time. The last work
procedure installed has the highest priority, so it is the first one called, except if one work procedure installs another
work procedure. In this case, the new procedure has a lower priority than the current one.
22 Advanced Dialog Programming 22.2.1 Using Work Procedures
612
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.