[comp.windows.x] Receiving XEvents asynchronously

logan@crystel.UUCP (Mark) (01/16/91)

I am trying to write a program, using Xlib right now, which receives
input from several sockets and displays them on the screen.
(I am using a SPARCstation SLC with SunOS 4.1 and OpenWindows.)
The only way I can think of doing this is polling, which I am unhappy
with for performance reasons.

I call XCheckMaskEvent() to check for an event, and then I call
select() on the socket file descriptors with a timeout of 1 second.
I would rather use something like select() to check for input from
the XEvent list at the same time as the sockets.

Can anyone think of a way to do this?

Thanks in advance,
Mark Logan  uunet!lcc!turnkey!crystel!logan

tbecker@sirius.informatik.uni-kl.de (Thomas Becker) (01/18/91)

In comp.windows.x you write:

>I am trying to write a program, using Xlib right now, which receives
>input from several sockets and displays them on the screen.

I have had the same problem some time ago (using Xlib only).
In fact X events are nothing else but messages coming in through a socket.
By the macro
        socket = ConnectionNumber(display)
you get the socket connection id to the X server, which you can use as any
other socket for setting up masks required in select().
However, I had some slight trouble with this: calling select() for the FIRST
time, select() told me that an X event is ready to be received, but
XNextEvent() couldn't find any.
I have solved the problem by looking for the first X event with XPpending()
or some other non-blocking function, and then using select() only. So your
program should roughly look like that:

        x_socket = (1 << ConnectionNumber(display));
        sockwet_mask |= x_socket;

        if (XPending(display)) {
                /* handle event */
        }

        do {
                i = select(..., &socket_mask, ...);
                if (socket_mask & x_socket) {
                        XNextEvent(display, &event);
                        /* handle event */
                }
                else {
                        /* ... */
                }
        }


Hope that helps.

Thomas Becker
-- 
Thomas Becker		     +---------+ acoustic:
Computer Science Department  |  /"""\  |	+49 631 205 3295
University of Kaiserslautern | { O~O } | electronic:
P.O.Box 3049		     |  \ U /  |        tbecker@informatik.uni-kl.de

dvb@emisle.uucp (David Van Beveren) (01/19/91)

In article <tbecker.664209752@sirius> tbecker@sirius.informatik.uni-kl.de (Thomas Becker) writes:
.
.
>I have had the same problem some time ago (using Xlib only).
>In fact X events are nothing else but messages coming in through a socket.
.
.
.
Is this true? That seems like a implementation-dependant thing. In fact,
I know that ISC X rev 1.2 can run without the ISC TCP/IP package. They
have a (dummy?) libinet.a that you link, that comes with the X package.
When you get TCP/IP (if), then you get a "real" libinet.a. 

I have always assumed that you cannot depend on the Xprotocol messages being
delivered over a socket. What about machines that support AT&T TLI only? I
am very interested in this. I have an X application that uses a XtWorkProcess
in the background of the event loop to do a select on an open socket.

The following code is from an application I inherited at one time, and this
(an event loop trying to monitor other sockets besides the 'x socket' does
not work (does not compile if I remember correcty) in the Interactive
configuration that does not include TCP/IP. But, when you add that package,
it works fine.

If someone at Interactive could clear this up I would appreciate it. In
any case, if your application needs to be portable, I would not assume that
X is implemented on top of some BSD socket transport mechanism.

when you add the TCP/IP package, it runs fine.

#include "common.h"
#include <sys/socket.h>


mainloop (dpy, tcpsock)
Display	*dpy;
int	tcpsock;
{
	fd_set		fdmask;
	XEvent		event;
	struct timeval	timeout;
	int		displayFD;
	int		ret;

	/* get file descriptor of TCP stream connection to server */
	displayFD = XConnectionNumber (dpy);

    while (1) {
allock();
	/*
	 * Look for events.  Try to arrange that X events have priority over
	 * network traffic.  See if there's an X event pending.  If so, check
	 * for a net event, too; if not, select on both the network and the X
	 * connection.  If that doesn't time out, but there's no X event
	 * pending, try again, just selecting on the X connection.  If that
	 * times out, let the network event get processed.
	 *
	 * Can't just select on the two fds, because there may be X events
	 * pending in the queue that have already been read.
	 *
	 * This may look baroque, but we've seen some instances where X server
	 * latency seems to let the network events take priority over server
	 * events, leading to sluggish keyboard response and lots of local
	 * death.
	 */

	FD_ZERO (&fdmask);
	tcp_setfds (&fdmask);		/* enable all client fds */

	if (! XPending (dpy)) {		/* nothing on the X connection */
		FD_SET (displayFD, &fdmask);
		while ((ret = select (32, &fdmask, NULL, NULL, (struct timeval *)0)) == -1)
			if (errno != EINTR)
				perror("select error on events(1)");
		if (ret == 0) {
			continue;
		}
	}				/* *** */
	else {
		timeout.tv_sec = 0;
		timeout.tv_usec = 0;
		while ((ret = select (32, &fdmask, NULL, NULL, &timeout)) == -1)
			if (errno != EINTR)
				perror("select error on events(2)");
	}

	/* handle X events */
	if (XPending (dpy)) {
		XNextEvent (dpy, &event);
		HandleEvent (dpy, &event);
	}

	/* handle TCP listener and clients */
	tcp_service_fds (&fdmask);
    }
    /*NOTREACHED*/
}

dvb

David Van Beveren                           INTERNET: emisle!dvb@ism.isc.com
EIS ltd. Professional Software Services     UUCP:   ..uunet!emisle!dvb
voice: (818) 587-1247