This discussion is merely presented as an overview, since the implementation details are beyond the scope of this
book. For example, UNIX signals cause problems in a number of ways. The parent process is sent signals when the
child dies or its process state changes. The child is also sent signals that are delivered to the parent by the user or other
outside forces. Different forms of UNIX require that process groups be set up in different ways to avoid other
problems with signals.
Another problem involves file descriptors that are set up as non−blocking files. If read() returns 0 with one of these
descriptors, you may not know whether there is nothing to read or the end of the file has been reached, which means
that the child process has terminated. Incidentally, popen() does not deal with any of these issues correctly, so
building a new solution is the best thing to do in the long run.
You should really consult the programmer's guide for your UNIX system for more information on the techniques used
to spawn new processes and communicate with them appropriately. Once you have a handle on those issues, it should
be relatively easy to redirect text from file descriptors using the toolkit. For more information on
XtAppAddInput(), including examples of how it can be used, see Volume Four, X Toolkit Intrinsics
Programming Manual.
22.3 Dynamic Message Symbols
The MessageDialog is used to display many different types of messages; the image in the dialog helps the user
identify the purpose of the dialog. The pixmaps used by the standard MessageDialogs are predefined by the Motif
toolkit. When you are using the standard dialogs, you typically change the dialog's type rather than its symbol, since
changing its type effectively changes the symbol that it displays. However, you can change the MessageDialog's
symbol to a customized image using the XmNsymbolPixmap resource.
The resource takes a pixmap value that must be created before the resource is set. When the resource is set, the
pixmap is not copied by the dialog widget. If the dialog is destroyed, you should be sure to free the pixmap unless you
are using it elsewhere. If you are going to destroy the dialog using XtDestroyWidget() directly, you should get
the pixmap by calling XtVaGetValues(), so that you can free it. However, the dialog can also be destroyed
automatically, so you should also specify an XmNdestroyCallback procedure that is called whenever the dialog
is destroyed.
the source code shows an example of using a custom image in a standard MessageDialog. The program also
demonstrates how the dialog should clean up after itself. 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. XmFONTLIST_DEFAULT_TAG replaces
XmSTRING_DEFAULT_CHARSET in Motif 1.2.
/* warn_msg.c −− display a very urgent warning message.
* Really catch the user's attention by flashing an urgent−
* looking pixmap every 250 milliseconds.
* The program demonstrates how to set the XmNsymbolPixmap
* resource, how to destroy the pixmap and how to use timers.
*/
#include <Xm/MessageB.h>
#include <Xm/PushB.h>
#include "bang0.symbol"
#include "bang1.symbol"
#define TEXT "Alert!0he computer room is ON FIRE!0ll of your e−mail will be lost."
/* define the data structure we need to implement flashing effect */
22 Advanced Dialog Programming 22.3 Dynamic Message Symbols
622
typedef struct {
XtIntervalId id;
int which;
Pixmap pix1, pix2;
Widget dialog;
XtAppContext app;
} TimeOutClientData;
main(argc, argv)
int argc;
char *argv[];
{
XtAppContext app;
Widget toplevel, button;
XmString label;
void warning();
XtSetLanguageProc (NULL, NULL, NULL);
toplevel = XtVaAppInitialize (&app, "Demos",
NULL, 0, &argc, argv, NULL, NULL);
label = XmStringCreateLocalized (
"Don't Even Think About Pressing This Button");
button = XtVaCreateManagedWidget ("button",
xmPushButtonWidgetClass, toplevel,
XmNlabelString, label,
NULL);
XmStringFree (label);
/* set up callback to popup warning */
XtAddCallback (button, XmNactivateCallback, warning, NULL);
XtRealizeWidget (toplevel);
XtAppMainLoop (app);
}
/* warning() −− callback routine for the button. Create a message
* dialog and set the message string. Allocate an instance of
* the TimeOutClientData structure and set a timer to alternate
* between the two pixmaps. The data is passed to the timeout
* routine and the callback for when the user presses "OK".
*/
void
warning(parent, client_data, call_data)
Widget parent;
XtPointer client_data;
XtPointer call_data;
{
Widget dialog;
XtAppContext app = XtWidgetToApplicationContext (parent);
XmString text;
extern void done(), destroy_it(), blink();
Display *dpy = XtDisplay (parent);
Screen *screen = XtScreen (parent);
Pixel fg, bg;
Arg args[5];
int n, depth;
TimeOutClientData *data = XtNew (TimeOutClientData);
/* Create the dialog */
22 Advanced Dialog Programming 22.3 Dynamic Message Symbols
623
n = 0;
XtSetArg (args[n], XmNdeleteResponse, XmDESTROY); n++;
dialog = XmCreateMessageDialog (parent, "danger", args, n);
XtUnmanageChild (XmMessageBoxGetChild (dialog, XmDIALOG_CANCEL_BUTTON));
XtUnmanageChild (XmMessageBoxGetChild (dialog, XmDIALOG_HELP_BUTTON));
XtAddCallback (dialog, XmNokCallback, done, NULL);
XtAddCallback (dialog, XmNdestroyCallback, destroy_it, data);
/* now that dialog has been created, it's colors are initialized */
XtVaGetValues (dialog,
XmNforeground, &fg,
XmNbackground, &bg,
XmNdepth, &depth,
NULL);
/* Create pixmaps that are going to be used as symbolPixmaps.
* Use the foreground and background colors of the dialog.
*/
data−>pix1 = XCreatePixmapFromBitmapData (dpy, XtWindow (parent),
bang0_bits, bang0_width, bang0_height, fg, bg, depth);
data−>pix2 = XCreatePixmapFromBitmapData (dpy, XtWindow (parent),
bang1_bits, bang1_width, bang1_height, fg, bg, depth);
/* complete the timeout client data */
data−>dialog = dialog;
data−>app = app;
/* Add the timeout for blinking effect */
data−>id = XtAppAddTimeOut (app, 1000L, blink, data);
/* display the help text and the appropriate pixmap */
text = XmStringCreateLtoR (TEXT, XmFONTLIST_DEFAULT_TAG);
XtVaSetValues (dialog,
XmNmessageString, text,
XmNsymbolPixmap, data−>pix2,
NULL);
XmStringFree (text);
XtManageChild (dialog);
XtPopup (XtParent (dialog), XtGrabNone);
}
/* blink() −− visual blinking effect for dialog's symbol. Displays
* flashing ! symbol, restarts timer and saves timer id.
*/
void
blink(client_data, id)
XtPointer client_data;
XtIntervalId *id;
{
TimeOutClientData *data = (TimeOutClientData *) client_data;
data−>id = XtAppAddTimeOut (data−>app, 250L, blink, data);
XtVaSetValues (data−>dialog,
XmNsymbolPixmap, (data−>which = !data−>which) ?
data−>pix1 : data−>pix2,
NULL);
}
/* done() −− called when user presses "OK" in dialog or
22 Advanced Dialog Programming 22.3 Dynamic Message Symbols
624
* if the user picked the Close button in system menu.
* Remove the timeout id stored in data, free pixmaps and
* make sure the widget is destroyed (which is only when
* the user presses the "OK" button.
*/
void
done(dialog, client_data, call_data)
Widget dialog;
XtPointer client_data;
XtPointer call_data;
{
XtDestroyWidget(dialog);
}
/* destroy_it() −− called when dialog is destroyed. Removes
* timer and frees allocated data.
*/
void
destroy_it(dialog, client_data, call_data)
Widget dialog;
XtPointer client_data;
XtPointer call_data;
{
TimeOutClientData *data = (TimeOutClientData *) client_data;
Pixmap symbol;
XtRemoveTimeOut (data−>id);
XFreePixmap (XtDisplay (data−>dialog), data−>pix1);
XFreePixmap (XtDisplay (data−>dialog), data−>pix2);
XtFree (data);
}
The dialog is created in warning(), the callback routine for the PushButton in the main window. We create a
simple MessageDialog that does not have a predefined symbol so we can specify a custom image. The dialog actually
uses two symbols that are exchanged every 250 milliseconds by a timer callback routine. The output of this program is
shown in the figure.
Output of warn_msg.c
22 Advanced Dialog Programming 22.3 Dynamic Message Symbols
625
To implement the flashing symbol, we must associate certain information with the dialog. Basically, we need to keep
track of the two pixmaps and the timer routine. All of the information is placed in a single data structure, so we can
pass the structure around as client data. We can also use multiple structure variables to store information about
multiple dialogs. The TimeOutClientData is defined as follows:
typedef struct {
XtIntervalId id;
int which;
Pixmap pix1, pix2;
Widget dialog;
XtAppContext app;
} TimeOutClientData;
The warning() routine allocates a new instance of the structure using XtNew(), since it is going to create a new
dialog and it needs a unique structure for the dialog. The routine uses XmCreateMessageDialog() to create the
dialog. We unmanage the Cancel and Help buttons and specify a callback for the OK button. The done() callback
simply calls XtDestroyWidget(), which causes the XmNdestroyCallback to be called. We also set the
XmNdeleteResponse resource for the dialog to XmDESTROY. This setting causes the Motif toolkit to destroy the
dialog if the user dismisses it using the Close button on the window menu,
Since we are not reusing the dialog or its data, we must be sure to free the pixmaps, release the timer, and free the
allocated data structure when the dialog is destroyed. To be sure that these tasks take place, we install a callback
function for the XmNdestroyCallback resource. The destroy_it() routine handles all of the cleanup for the
dialog.
Before we create the pixmaps that are used in the dialog, we retrieve the dialog's foreground and background colors
using XtVaGetValues() so that the new pixmaps can use the same colors. Once the colors are known, we can
create the pixmaps and finish initializing the fields in the TimeOutClientData structure. The dialog field of the
structure points to the MessageDialog. We call XtAppAddTimeOut() to start the timer that controls the flashing
effect and set the id field to the timer ID.
We perform a final bit of setup for the dialog by specifying the XmNsymbolPixmap and XmNmessageString
resources. Once everything is set up, the function returns, Xt regains control, and normal event processing resumes.
After the initial one−second interval times out, the blink() function is called. This routine adds another timeout for
250 milliseconds and switches the pixmaps displayed in the dialog. This loop continues until the user dismisses the
dialog, at which time it is destroyed, the pixmaps are freed, the timer is removed, and the TimeOutClientData
structure is freed.
Since we created a simple MessageDialog that does not have a predefined image, we did not have to get a handle to
the XmNsymbolPixmap for the dialog and destroy it. However, if you decide to change the pixmap for one of the
standard dialogs that has a predefined symbol, like the ErrorDialog, you should get its pixmap and free it. In this case,
you should use XmDestroyPixmap() rather than XFreePixmap(). The Motif dialogs use XmGetPixmap() to
create their images, so the pixmaps must be freed with the companion routine XmDestroyPixmap(). See Section
#spixmaps in Chapter 3, Overview of the Motif Toolkit, for a discussion on XmGetPixmap().
Although changing the symbol pixmap in a dialog is quite simple, using the feature effectively requires a careful
design to make sure that all of the pointers and data structures are destroyed appropriately. Being meticulous about
cleaning up after destroyed widgets and other objects is sometimes a difficult task because of the many ways in which
the user can destroy them. However, eliminating these possible memory leaks enables a program to run longer and
more efficiently.
22 Advanced Dialog Programming 22.3 Dynamic Message Symbols
626
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.