Newsgroups: comp.windows.x
Path: utzoo!utgpu!news-server.csri.toronto.edu!rpi!zaphod.mps.ohio-state.edu!van-bc!ubc-cs!mprgate.mpr.ca!mprgate.mpr.ca!janzen
From: janzen@mprgate.mpr.ca (Martin Janzen)
Subject: Re: Event Loops
Message-ID: <1991Apr18.000420.7600@mprgate.mpr.ca>
Sender: news@mprgate.mpr.ca
Reply-To: janzen@mprgate.mpr.ca (Martin Janzen)
Organization: MPR Teltech Ltd.
References: <MALBERT.91Apr12135341@jeeves.shearson.com> <24267@well.sf.ca.us>
Distribution: na
Date: Thu, 18 Apr 91 00:04:20 GMT

In article <24267@well.sf.ca.us>, bschoen@well.sf.ca.us (Brook Schoenfield) writes:
>malbert@jeeves.shearson.com (Marc Albert) writes:
>>I have an application that has multiple top level windows.  The event
>>loop looks something like this:
>
>>	for (;;) {
>>		if (XtAppPending(WindowOne))
>>			XtDispatch();
>
>>		if (XtAppPending(WindowTwo))
>>			XtDispatch();
>>	}
>>
>>This method works fine.  The only problem I have is that 
>>I have to poll for events; this means I am never really 
>>waiting (blocking) and I am burning a lot of CPU.  
>
>XtAppPending() returns whether or not an event is avaliable:
>why not use XtAppNextEvent(), which blocks until an event is
>available?

(I've just been digging through NextEvent.c, trying to get X apps to work as
RPC clients and servers -- so I'll throw in my $0.02 worth.)

Be careful with this.  If your application contexts (call them app1 and app2)
are connected to different displays, and you call XtAppNextEvent(app1, &event)
when no events are pending on the display connection for app1, then your
process will block until the next event is received on *that* connection.
No events in app2 will be processed until an event occurs on the display
connection for app1.

This happens because XtAppNextEvent() does a select() on the file descriptors
for all displays *in the specified application context*.  Iff both of your
application contexts share the same display connection (Is this possible?  How
would you set this up anyway?), then XtAppNextEvent() should work.

O'Reilly (Vol. 4, 13.6) discusses multiple application contexts a little, but
doesn't present a real solution to this problem, so get ready for some
experimentation!

You could try blocking by doing your own select() on the file descriptors for
the display connections in each application context, something like this:

  #include <sys/types.h>
  #include <sys/time.h>

  int     dtablesize;
  fd_set  display_fds;
  int     fd_width;
  fd_set  read_mask;
    ...

  /* after you've opened displays d1 and d2 in each application context: */
  fd_width = getdtablesize();
  FD_ZERO(&display_fds);
  FD_SET(ConnectionNumber(d1), &display_fds);
  FD_SET(ConnectionNumber(d2), &display_fds);
    ...

  /* in your main loop, if no events are pending in either app context: */
  read_mask = display_fds;
  select(fd_width, &read_mask, NULL, NULL, NULL);

(Note that if you want to use XtAddTimeOut, XtAddInput, or XtAddWorkProc as well,
then things become even more complicated -- see NextEvent.c for the gory details!)

Alternatively, you could just try adding a short usleep() if no events are
pending in either application context.  Not pretty, but better than burning
all your CPU cycles!

>If you need to do processing while waiting for user events, you
>can set up a timer event and callback to do the background processing.
>[...]

You didn't mention this in the original message, but anyone who needs to do
background processing should check out XtAddWorkProc/XtRemoveWorkProc...

>Happy Coding
Ditto!

-- 
Martin Janzen                     janzen@mprgate.mpr.ca (134.87.131.13)
MPR Teltech Ltd.                  Phone: (604) 293-5309
8999 Nelson Way                   Fax: (604) 293-5787
Burnaby, BC, CANADA  V5A 4B5
