[comp.windows.x] Incremental Display of Widget Tree

rick@pcrat.uucp (Rick Richardson) (08/08/90)

I want to create a Box (or RowColumn in Motif) widget that contains
a bunch of Command (or PushButton in Motif) widgets.  But with a
twist.

The labels on the buttons themselves take anywhere from 1-3 seconds
apiece to compute, and are information that the user can read in
and of themselves.  The buttons represent pages of a document.

As each button widget is created, I'd like to process events
ala XtMainLoop, but only until I'm sure the newly created button
has been displayed.  Once the button is displayed, I need
to continue parsing an input file until the next button is
ready to be added and displayed.

I want to do this displaying as each button is created so that
the user has something to look at and think about rather than
a dumb hourglass or Please Wait message.

I've scoped out the pseudo code, as indicated below, but
there are a few things I haven't figured out how to do,
marked by ***'s.

Does anybody have any ideas or pointers on how I can accomplish
this?  Is there some event I have to wait for that says that
everything created so far has been displayed?  What is it?

main	# main program
{
	- box = XtCreateManagedWidget( ...Box..., toplevel, ... )
	  (and other widgets)

	- XtRealizeWidget(toplevel)

	- Now, process events until widgets are displayed
	  **** How do I do this ****

	- call parse(document)

	- call regular XtMainLoop()
}

parse_ready	# called from "parse", usually many times
{
	- button[n++] = XtCreateManagedWidget( ...Command..., box, ... )
          The 'label' on this button is information in itself.

	- XtRealizeWidget(button[n++])
	  *** is this correct? ***

	- Now, process events until this new button has been fully
	  displayed.
	  *** how do I do this ***

	- return back to parse();
}

parse
{
	While there are more pages to process
	{
		- format the page (somewhat CPU intensive)
		- call parse_ready
	}
}

-Rick
-- 
Rick Richardson - PC Research, Inc., uunet!pcrat!rick, (201) 389-8963

swick@ATHENA.MIT.EDU (Ralph Swick) (08/08/90)

	- Now, process events until widgets are displayed
	  **** How do I do this ****

You process events with a loop consisting of

	while (XtAppPending(...)) {
	    ...
	    XtAppNextEvent(...);
	    ...
	    XtDispatchEvent(...);
	    ...
	}

(this is precisely XtAppMainLoop, substituting XtAppPending
for True).  You might find it desirable to call XFlush before
the loop in some circumstances, or even XSync just before
XtAppPending to insure that the client and server queues are
completely emptied before continuing.

But have you considered using "work procedures"?
See XtAppAddWorkProc().

swick@ATHENA.MIT.EDU (Ralph Swick) (08/08/90)

    The "guts" does the work and is orders of magnitude larger** (in any
    significant application).  Keeping the "guts" clean, comprehensible,
    and maintainable is what is most important in my mind.

I certainly don't disagree with this! :-)  Nor do I have any
argument with your general observations about work procs.  They're
a very simplistic attempt to ameliorate a problem whose proper
solution really needs lower-level OS suport.  (So let's get
better OS's :-)

rlh2@ukc.ac.uk (Richard Hesketh) (08/09/90)

In article <1990Aug8.025339.3419@pcrat.uucp> rick@pcrat.uucp (Rick Richardson) writes:
>I want to create a Box (or RowColumn in Motif) widget that contains
>	- Now, process events until widgets are displayed
>	  **** How do I do this ****

I thought of a routine that would wait for a particular event.  Here's
the routine.  It works for me (I've tried waiting for various events).
I'd like to know if I've missed anything.  Specifically will this
routine break the Intrinsics when a translation table has been set on
this widget .. and what about grabs?


Boolean
XukcWaitForWidgetEvent(widget, eventmask, type)
Widget widget;
long eventmask;
int type;
{
	XEvent ev;
	long oldmask;
	XWindowAttributes atts;

	if (!XGetWindowAttributes(XtDisplay(widget), XtWindow(widget), &atts))
		return (FALSE); /* Help! .. failed X request */

	oldmask = atts.your_event_mask;
	XSelectInput(XtDisplay(widget), XtWindow(widget), oldmask | eventmask);
	while (1) {
		if (XtAppPeekEvent(XtWidgetToApplicationContext(widget), &ev)
		    && (ev.type == type)
		    && (ev.xany.window == XtWindow(widget)))
			break;
		XtAppNextEvent(XtWidgetToApplicationContext(widget), &ev);
		XtDispatchEvent(&ev);
	}
	if (!(oldmask & eventmask))
		/* eat up this event if the widget didn't select for it */
		XtAppNextEvent(XtWidgetToApplicationContext(widget), &ev);
	XSelectInput(XtDisplay(widget), XtWindow(widget), oldmask);
	return (TRUE);
}

Richard Hesketh   :   @nsfnet-relay.ac.uk:rlh2@ukc.ac.uk
		  :   rlh2@ukc.ac.uk    ..!mcsun!ukc!rlh2
---                                               
Computing Lab., University of Kent at Canterbury,
Canterbury, Kent, CT2 7NF, United Kingdom.    Tel: +44 227 764000 ext 7620/3682

rick@pcrat.uucp (Rick Richardson) (08/09/90)

Thanks to all who mailed me concerning "Incremental Display of Widget
Tree".  There were several answers that included using expose event
callbacks and waiting in a modified XtAppMainLoop for particular events.
However, the simplest solution came from Ralph Swick, and does the
trick for my application:

	XFlush(TheDisplay);
	for(;;)
	{
		XEvent	event;

		XSync(TheDisplay, 0);
		if (!XtAppPending(Context))
			break;
		XtAppNextEvent(Context, &event);
		XtDispatchEvent(&event);
	}

-Rick
-- 
Rick Richardson - PC Research, Inc., uunet!pcrat!rick, (201) 389-8963

swick@ATHENA.MIT.EDU (Ralph Swick) (08/10/90)

You fleshed-out my pseudo-code just fine, but the performance
can be improved considerably with an inner loop:

	for(;;)
	{
		XEvent	event;
		while (XtAppPending(Context)) {
		    XtAppNextEvent(Context, &event);
		    XtDispatchEvent(&event);
		}
		XSync(TheDisplay, 0);
		if (!XtAppPending(Context))
			break;
	}

-Ralph