[comp.windows.x] How Do You Monitor Events For More Than 1 Display?

achoi@cory.Berkeley.EDU (Andrew Choi) (12/03/90)

Hi everyone.

I am writing this program which is supposed to wait for KeyPress
events from more than 1 display, however, after thinking about
it for a long long time, I don't really know how to do it.
Please enlighten me.

To be more concrete, here's what I will do if I only have 1 
display:

	for (;;) {
		XNextEvent(display, &event);
	}

However, how do you achieve the same thing for multiple displays?
I don't want to do a wait on all the displays, I want it to return
when there is at least 1 display which has the event available.

Thanks in advance.
Name:  Andrew Choi	Internet Address:  achoi@cory.berkeley.edu
Tel:   (415)848-5658
#include <standard/disclaimer.h>

truesdel@nas.nasa.gov (David A. Truesdell) (12/03/90)

achoi@cory.Berkeley.EDU (Andrew Choi) writes:
>I am writing this program which is supposed to wait for KeyPress
>events from more than 1 display, however, after thinking about
>it for a long long time, I don't really know how to do it.
>Please enlighten me.

>To be more concrete, here's what I will do if I only have 1 
>display:

>	for (;;) {
>		XNextEvent(display, &event);
>	}

>However, how do you achieve the same thing for multiple displays?
>I don't want to do a wait on all the displays, I want it to return
>when there is at least 1 display which has the event available.

If you are running on a system which supports select(2), you can use it and
ConnectionNumber() to monitor multiple displays.

An example of how to do this is in "Introduction to the X Window System" by
Oliver Jones.

(Not an endorsement, I just happen to have it laying on my desk.)

--
T.T.F.N.,
dave truesdell (truesdel@prandtl.nas.nasa.gov)
"Courage is the willingness of a person to stand up for his beliefs in the face
 of great odds. Chutzpah is doing the same thing wearing a Mickey Mouse hat."

jimf@SABER.COM (12/03/90)

|I am writing this program which is supposed to wait for KeyPress
|events from more than 1 display, however, after thinking about
|it for a long long time, I don't really know how to do it.
|Please enlighten me.

You should use select, something like this:

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

	fd_set readfds;

	FD_ZERO(&readfds);
	FS_SET(ConnectionNumber(display1), &readfds);
	FS_SET(ConnectionNumber(display2), &readfds);

	for (;;) {
	  switch(select(dtablesize(), &readfds, NULL, NULL, NULL)) {
	  case -1:
	    if (errno == EINTR)
	      continue;
	    perror("select");
	    exit(1);
	  case 0:
	    continue;
	  default:
	    if (FD_ISSET(ConnectionNumber(display1), &readfds)) {
	      while (XPending(display1))
	        XNextEvent(display1, &event);
	      /* do your thing here */
	    }
	    if (FD_ISSET(ConnectionNumber(display2), &readfds)) {
	      while (XPending(display1))
	        XNextEvent(display1, &event);
	      /* do your thing here */
	    }
	  }
	}

jim frost
saber software
jimf@saber.com

etaylor@wilkins.iaims.bcm.tmc.edu (Eric Taylor) (12/04/90)

With mulitple displays, you have to use select.
If you are not familiar with it, refer to UNIX documentation.
Essentially, use select on all of the file descriptors of the
displays you have open.  When data is avaliable on one of them,
do your XNextEvent on it.

Be careful to make sure that XPending is 0 on all displays before
calling select.

for ever
	busy = False ;
	for each display dpy
		if XPending(dpy) > 0
			XNextEvent(dpy,&event)
			Process event
			busy = True
		end if
	end for
	if not busy
		Construct fdset of all displays
		select(...,&fdset,...)
		for each display dpy that had activity
			XNextEvent(dpy,&event)
			Process event
		end for
	end if
end for
--
					Eric Taylor
					Baylor College of Medicine
					etaylor@wilkins.bcm.tmc.edu
					(713) 798-3776

etaylor@wilkins.iaims.bcm.tmc.edu (Eric Taylor) (12/04/90)

Does XPending actually check the connection for
requests or does it merely look at the queue of
events stored in memory?

If it only looks at memory, you have to check
XPending for all connections before using select.
--
					Eric Taylor
					Baylor College of Medicine
					etaylor@wilkins.bcm.tmc.edu
					(713) 798-3776

mouse@LARRY.MCRCIM.MCGILL.EDU (12/04/90)

> I am writing this program which is supposed to wait for KeyPress
> events from more than 1 display, however, after thinking about it for
> a long long time, I don't really know how to do it.  Please enlighten
> me.

It's system-dependent.  I don't know enough about toolkits to say for
sure, but I would hope that most/all toolkits would provide some way of
doing this.

On BSD UNIX (or other Unices which have been BSDified enough to have
select()), the canonical way of doing this is to gobble up all events
that are available on the connections, then select() waiting for
something to arrive.

> To be more concrete, here's what I will do if I only have 1 display:

> 	for (;;) {
> 		XNextEvent(display, &event);
> 	}

Well, you also need to do something with the event; just reading it
isn't going to be very useful.

I have a program that speaks to multiple displays.  Here is its event
loop, with irrelevant code stripped out.  (The real function is about
twice as big as what you see here; it does input from another file
descriptor, and timeouts, in this loop as well.)

(DISP_INFO is a typedef referring to my structure containing all the
interesting information about each connection.  disps is a global
pointer to a linked list of these structures.)

	#define EACH_DISP(var) var=disps;var;var=var->link

	run()
	{
	 XEvent e;
	 DISP_INFO *d;
	 int selrv;
	 int wantflush;
	 int wantupd;
	 fd_set fds;
	 int selcnt;
	 int mustcontinue;
	 struct timeval *tvp;
	
	 for (EACH_DISP(d)) d->xfd = XConnectionNumber(d->disp);
	 wantflush = 1;
	 wantupd = 0;
	 while (1)
	  { mustcontinue = 0;
	    for (EACH_DISP(d))
	     { if (XQLength(d->disp) > 0)
		{ do
		   { XNextEvent(d->disp,&e);
		     handle_event(&e);
		   } while (XQLength(d->disp) > 0);
		  wantupd = 1;
		  mustcontinue = 1;
		}
	     }
	    if (mustcontinue) continue;
	    FD_ZERO(&fds);
	    for (EACH_DISP(d)) FD_SET(d->xfd,&fds);
	    if (wantflush || wantupd)
	     { static struct timeval ztv;
	       ztv.tv_sec = 0;
	       ztv.tv_usec = 0;
	       tvp = &ztv;
	     }
	    else
	     { tvp = 0;
	     }
	    selrv = select(FD_SETSIZE,&fds,(fd_set *)0,(fd_set *)0,tvp);
	    if (selrv < 0)
	     { if (errno == EINTR) continue;
	       perror("select");
	       utexit(1);
	     }
	    if (selrv == 0)
	     { if (wantupd)
		{ update_display();
		  wantflush = 1;
		  wantupd = 0;
		}
	       if (wantflush)
		{ for (EACH_DISP(d)) XFlush(d->disp);
		  if (debugging) fflush(stdout);
		  wantflush = 0;
		}
	       continue;
	     }
	    for (EACH_DISP(d))
	     { if (FD_ISSET(d->xfd,&fds))
		{ int bpend;
		  ioctl(d->xfd,FIONREAD,&bpend);
		  if (bpend == 0) /* socket EOF */
		   { utexit(0);
		   }
		  XEventsQueued(d->disp,QueuedAfterReading);
		}
	     }
	  }
	}

					der Mouse

			old: mcgill-vision!mouse
			new: mouse@larry.mcrcim.mcgill.edu

black@yoyodyne..westford.ccur.com (Sam Black) (12/04/90)

One thing to be careful of (I just got caught by this yesterday) is to call
XFlush(dpy) on each display before calling select.  You can't just call XFlush
after processing all events on a display, because an event on one display may
cause activity on another display.

		- sam

-------------------------------------------------------------------------------
Once you remove the absurdity from human existence, there isn't much left.
		     __________
		    /  _______/__	...!{decvax,uunet}!masscomp!black
		   /__/______/  /	black@westford.ccur.com
	  Concurrent /_________/
	Computer Corporation
-------------------------------------------------------------------------------