[comp.windows.x.motif] XmUpdateDisplay - the little engine that couldn't?

montnaro@spyder.crd.ge.com (Skip Montanaro) (06/18/91)

In my application I popup an XmMessageDialog widget before launching into a
long operation. I've experimented with calling XmUpdateDisplay one or more
times before the operation, in an attempt to force the message to display
properly. My experiments have been unsuccessful thusfar.

The mental picture I have of the situation is that there is an expose event
for the outer DialogShell widget in the input queue when XmUpdateDisplay is
called initially. The call processes that expose event, which generates one
or more other expose events for the XmMessageBox child of the DialogShell.
These aren't seen by the first call to XmUpdateDisplay, so you have to call
it again. Unfortunately, there is a race between the client and server to
see whether the server can send the expose event(s) before the next call to
XmUpdateDisplay. If it can, the second call will cause the message to be
displayed. If not, the second call will see no expose events in the queue
and return without doing any useful work.

Can someone comment on my perception of the situation? Whether my ideas are
right or wrong, are there any techniques I can use to remedy my problem?
Currently I just execute several XFlush's in the client after the first
XmUpdateDisplay call to slow the client down. Naturally, this doesn't always
work either. (I could have the client sleep for awhile, but for how long?)

Thx,

--
Skip (montanaro@crdgw1.ge.com)

tsang@ISI.COM (Kam C. Tsang) (06/18/91)

> In my application I popup an XmMessageDialog widget before launching into a
> long operation. I've experimented with calling XmUpdateDisplay one or more
> times before the operation, in an attempt to force the message to display
> properly. My experiments have been unsuccessful thusfar.

Try this:

void ProcessAllExposeEvents()
{ // somehow you have to get to your own appContext
   // see pp 312, 6.10, "X Window System Toolkit"
   //                   by Paul Asente and Ralph Swick
   while (XtAppPending(appContext) & XtIMXEvent) {
      XEvent event;
      XtAppPeekEvent(appContext, &event);
      if ((event.type == Expose) || (event.type == MapNotify))
	 XtAppProcessEvent(appContext, XtIMXEvent);
      else
	 break;
   }
}

-kam
     ----------------------------+-----------------------------
                      Kam Tsang  |  User Interface Group
           (408) 980-1590 x 275  |  Integrated Systems, Inc.
           (408) 980-0400 [Fax]  |  3620 Jay Street
                  tsang@isi.com  |  Santa Clara, CA  94054
     ----------------------------+-----------------------------

masa@hpsciz.sc.hp.com (Masayoshi Habu) (06/18/91)

In comp.windows.x.motif, montnaro@spyder.crd.ge.com (Skip Montanaro) writes:

    Can someone comment on my perception of the situation? Whether my ideas are
    right or wrong, are there any techniques I can use to remedy my problem?
    Currently I just execute several XFlush's in the client after the first
    XmUpdateDisplay call to slow the client down. Naturally, this doesn't always
    work either. (I could have the client sleep for awhile, but for how long?)

I have experienced similar problems. Instead of XFlush, I called XSync.
Calling a pair of XSync and XmUpdateDisplay once ot twice took care of
my problems. As you see, this depends on the relative speed of our server
and client. Asynchronous parallel processes give me interesting problems.

Masa

bazavan@hpdtczb.HP.COM (Valentin Bazavan) (06/19/91)

The sequence below always works for me:

XmUpdateDisplay
sleep
XmUpdateDisplay

The problem with this approach is that the shortest suspension time you
can set using sleep(3) is one second; that's too long. You will have 
to write your own sleep() to allow shorter suspension times.

Valentin Bazavan
vbazavan@dtc.hp.com

gabe@hpcvlx.cv.hp.com. (Gabe Begeddov) (06/23/91)

>  / hpcvlx.cv.hp.com:comp.windows.x.motif / bazavan@hpdtczb.HP.COM (Valentin Bazavan) /  7:37 am  Jun 19, 1991 /
>  
>  The sequence below always works for me:
>  
>  XmUpdateDisplay
>  sleep
>  XmUpdateDisplay
>  
>  The problem with this approach is that the shortest suspension time you
>  can set using sleep(3) is one second; that's too long. You will have 
>  to write your own sleep() to allow shorter suspension times.
>  

Another problem is that it isn't guaranteed to work.  Since the dialog
is a non-override redirect window it is mapped by the wm rather than by
the client.  Since the wm could be swapped out or on a slow link you 
are not quaranteed that it will respond in 1 second.  

A local event loop waiting for a MapNotify on the dialog is probably your
best bet. Something like:

	while (1) {
		XtAppNextEvent(app, &event);
		if (event.xany.type == MapNotify && 
		    event.xany.window == XtWindow(dialogShell)) {
			XmUpdateDisplay(dialogShell);
			return;
		}
		else
		    XtDispatchEvent(&event);
		}

>  Valentin Bazavan
>  vbazavan@dtc.hp.com
>  ----------
>  
>  

Gabe Beged-Dov
gabe@cv.hp.com

dbrooks@osf.org (06/27/91)

I just got back from vacation (11 days with a youth orchestra in 11 cities in
Europe; clearly some strange new meaning of the word "vacation") so apologies
for joining in too late.

As Gabe suggested, the problem of a dialog not displaying before the client
goes "busy" is a kind of race.  The server tells the client that its request to
map a window has been honored; unfortunately, in this case, this means only
that the request has been sent on to the (reparenting) window manager.  The wm
is now at liberty to yawn, scratch, thrash the paging disk a little, decorate
the window, walk the dog, pay its bills, and finally map the entire decorated
concoction (whereupon the server will yawn, scratch -- etc).

There is one problem with solutions like the two posted.  We know from a
separate, recent thread, that it's possible to "pop-up" a dialog from an
iconified main window, and it will then not be actually mapped.  I think the
following works a little better.  It may be over-general for your requirement;
note in particular it climbs a tree to find shell widgets, and the chances are
you already know these.

It doesn't work with olwm, as noted.  This isn't deliberate OSF policy ;-)
It's just because olwm has a different approach to transient children of
iconified parents.  It could be made to work.

David Brooks
Systems Engineering
Open Software Foundation

/*
 * This procedure will ensure that, if a dialog window is being mapped,
 * its contents become visible before returning.  It is intended to be
 * used just before a bout of computing that doesn't service the display.
 * You should still call XmUpdateDisplay() at intervals during this
 * computing if possible.
 *
 * The monitoring of window states is necessary because attempts to map
 * the dialog are redirected to the window manager (if there is one) and
 * this introduces a significant delay before the window is actually mapped
 * and exposed.  This code works under mwm, twm, uwm, and no-wm.  It
 * doesn't work with olwm if the mainwindow is iconified.
 *
 * The argument to ForceDialog is any widget in the dialog (often it
 * will be the BulletinBoard child of a DialogShell).
 */

ForceDialog(w)
     Widget w;
{
  Widget diashell, topshell;
  Window diawindow, topwindow;
  Display *dpy;
  XWindowAttributes xwa;
  XEvent event;
  XtAppContext cxt;

/* 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 (XtIsRealized(diashell) && XtIsRealized(topshell)) {
    dpy = XtDisplay(topshell);
    diawindow = XtWindow(diashell);
    topwindow = XtWindow(topshell);
    cxt = XtWidgetToApplicationContext(diashell);

/* Wait for the dialog to be mapped.  It's guaranteed to become so unless... */

    while (XGetWindowAttributes(dpy, diawindow, &xwa),
	   xwa.map_state != IsViewable) {

/* ...if the primary is (or becomes) unviewable or unmapped, it's
   probably iconified, and nothing will happen. */

      if (XGetWindowAttributes(dpy, topwindow, &xwa),
	  xwa.map_state != IsViewable)
	break;

/* At this stage, we are guaranteed there will be an event of some kind.
   BEWARE; we are presumably in a callback, so this can recurse. */

      XtAppNextEvent(cxt, &event);
      XtDispatchEvent(&event);
    }
  }

/* The next XSync() will get an expose event if the dialog was unmapped. */

  XmUpdateDisplay(topshell);
}