* becomes visible.
*/
void
ForceUpdate(w)
Widget w; /* This widget must be visible before the function returns */
{
Widget diashell, topshell;
Window diawindow, topwindow;
XtAppContext cxt = XtWidgetToApplicationContext (w);
Display *dpy;
XWindowAttributes xwa;
XEvent event;
/* Locate the shell we are interested in */
for (diashell = w; !XtIsShell (diashell); diashell = XtParent (diashell))
;
/* Locate its primary window's shell (which may be the same) */
for (topshell = diashell; !XtIsTopLevelShell (topshell);
topshell = XtParent (topshell))
;
/* If the dialog shell (or its primary shell window) is not realized,
* don't bother ... nothing can possibly happen.
*/
if (XtIsRealized (diashell) && XtIsRealized (topshell)) {
dpy = XtDisplay (topshell);
diawindow = XtWindow (diashell);
topwindow = XtWindow (topshell);
/* Wait for the dialog to be mapped. It's guaranteed to become so */
while (XGetWindowAttributes (dpy, diawindow, &xwa) &&
xwa.map_state != IsViewable) {
/* ...if the primary is (or becomes) unviewable or unmapped,
* it's probably iconic, and nothing will happen.
*/
if (XGetWindowAttributes (dpy, topwindow, &xwa) &&
xwa.map_state != IsViewable)
break;
/* we are guaranteed there will be an event of some kind. */
XtAppNextEvent (cxt, &event);
XtDispatchEvent (&event);
}
}
/* The next XSync() will get an expose event. */
XmUpdateDisplay (topshell);
}
This routine makes sure that a dialog is visible by waiting for the window of the dialog to be mapped to the screen.
22.2.5 Avoiding Forks
Before we close out this section, there is one more method of of executing tasks in the background that we should
discuss. Beginning programmers tend to use library functions and system calls such as system(), popen(),
fork(), and exec() to invoke external commands. Although these functions are perfectly reasonable, they can
backfire quite easily on virtually any error condition. Recovering from these errors is the GUI programmer's
22 Advanced Dialog Programming 22.2.5 Avoiding Forks
620
nightmare, since there are so many different possible conditions to deal with.
The purpose of using these functions, of course, is to call another UNIX program and have it run concurrently with the
main application. The system() and popen() functions fork a new process using the fork() system call. They
also use some form of exec() so the new child process can invoke the external UNIX program. If the new process
cannot fork, if there is something wrong with the external UNIX command, if there is a communications protocol
error, or any one of a dozen other possible error conditions, there is no way for the external program to display an
error message as a part of the main application.
It is unlikely that the external program would display a dialog box or any sort of reasonable user−interface element. It
is illegal for a new process to use any of the widgets or windows in the main application because only one connection
to the server is allowed per process. If the child process wants to post a dialog, it must establish a new connection to
the X server and create an entirely new widget tree, as it is a separate application. Since most system utilities do not
have graphical user interface front ends, this scenario is very unlikely. It is also entirely unreasonable to have any
expectations of the external process, especially since other solutions are much easier.
If a separate process is necessary in order to accomplish a particular task, setting up pipes between the child
application and the parent is usually the best alternative. The popen() function uses this method superficially, but it
is not the most elegant solution. The routine only handles forking the new process and setting up half of a two−way
pipe. The popen() function is used in several places throughout the book; check the index for those uses.
To really handle external processes and pipes properly, an application should do the following:
The parent process calls pipe() to set up entry points for the expected child process' input and output
channels. Two pipes for both input and output are usually needed.
The parent process calls fork() to spawn the new child process.
The child uses dup2() to redirect its own stdin, stdout, and stderr to the other ends of the pipes set
up by the parent. The communication pipeline between the parent and the child is now established.
The parent calls XtAppAddInput() to tell Xt to monitor an additional file descriptor while it is waiting for
input events from the X server.
The parent can read data (e.g., output, error conditions, etc.) sent by the child using read() on the
appropriate pipe.
The parent can display the output from the pipe to a dialog, a ScrolledText object, or some other widget
because it is still in connection with the X server.
If the parent calls XtAppAddInput(), Xt can see the data the child sends through the pipe and invoke the callback
routine associated with the file descriptor. XtAppAddInput() takes the following form:
XtInputId
XtAppAddInput(app_context, source, mask, proc, client_data)
XtAppContext app_context;
int source;
XtPointer mask;
XtInputCallbackProc proc;
XtPointer client_data;
The source parameter should be the side of the pipe that the parent uses to read data sent by the child process. The
proc function is called when there is data to read on the pipe. When the function is called, the client_data is
passed to the callback. For example, you can pass the process ID returned by fork(), so you can see if the process is
still alive and read the data using read().
22 Advanced Dialog Programming 22.2.5 Avoiding Forks
621

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.