[comp.windows.x] Client needs to block on files & events

bill@fedeva.UUCP (Bill Daniels) (03/09/90)

Caveat:  I am a very green X programmer.

I am working on an application in which the client application needs to
receive input from a file/socket as well as normal events.  In my environment,
which is DECwindows, I have access to a call, XtAppAddInput, that will allow
this to happen.  I cannot of course find this documented in any generic
X document which leads me to believe that it is not a portable construct.
My question is how to accomplish this maneuver in a portable fashion.  I hope
that I am not alone in needing this capability and that someone more versed
in X than I will be able to offer me some guidance.

Thanks
-- 
bill daniels
federal express, memphis, tn
{hplabs!csun,mit-eddie!premise}!fedeva!wrd3156

cjmchale@cs.tcd.ie (Ciaran McHale) (03/12/90)

In article <27@fedeva.UUCP> bill@fedeva.UUCP (Bill Daniels) writes:
>Caveat:  I am a very green X programmer.
>
>I am working on an application in which the client application needs to
>receive input from a file/socket as well as normal events.  In my environment,
>which is DECwindows, I have access to a call, XtAppAddInput, that will allow
>this to happen.  I cannot of course find this documented in any generic
>X document which leads me to believe that it is not a portable construct.
>My question is how to accomplish this maneuver in a portable fashion.  I hope
>that I am not alone in needing this capability and that someone more versed
>in X than I will be able to offer me some guidance.

The X User's group (XUG) post a "frequently asked questions & answers"
message to comp.windows.x once a month and they are thinking of doing so more
frequently. Your problem hasn't yet made it onto the list; but I think this is
more to do with the fact that the "frequently asked questions" posting
has just gotten off the ground rather than it being an uncommon question.
So, I'd advise you to do several things


	1. Keep an eye out for the regular posting since it may prove
	   useful for other problems.
	2. Look at what I've given below --- it may appear on a future
	   "frequently asked questions" posting.
	3. Learn the difference between "Xlib" based programs and
	   "Xt" based programs. Basically the "X Toolkit Intrinsics",
	   commonly abbreviated to Xt, is a library built on top of Xlib.
	   It is designed to take some of the burden off programmers.
	   Unfortunately for you, you can't just mix and match Xlib code
	   with Xt code at will so you won't be able to use XtAppAddInput()
	   (which is an Xt routine) in a program that doesn't otherwise
	   follow the Xt style of programming.

	   While it's can be useful to be able to program in Xlib, you
	   might find that learning how to use a toolkit will save you
	   time in the long run.


Ciaran.
------
cjmchale@cs.tcd.ie



To: xug@expo.lcs.mit.edu
cc:
Subject: Frequently asked questions posting: A contribution
--------
First off, I must say that the frequently asked questions posting is a
great idea. I just that people on the net will appreciate the large
amount of time it takes to maintain such a posting.

> [ ** Every two weeks is fine with XUG. Suggestions? **].
Yes, I agree that the frequently asked questions posting would be more useful
if posted more often. I guess that every 2 weeks is about right.

I've noticed that more and more X programmers want to write X clients as
graphical front ends to other compute bound process. Basically, they read data
from the back end process and display it in an X window. This involves being
able to handle X events and also listen for the arrival of data from the back
end process. Below is my solution to the problem. I'd be pleased if you could
incorporate it into the frequently asked questions posting (either in it's
entirety or cut and paste it as you see fit). Note that this solution
is for Xlib based programs. Perhaps somebody else will offer to tell the net
how to do something similar in Xt and non-Xt based toolkits.


Ciaran.
-------
cjmchale@cs.tcd.ie
"Send the kids off to war. At least it will keep them off the streets" --- FdB

---------------------------------- CUT HERE ---------------------------------
Question:
How can my Xlib based application communicate with more than one X
and/or some other input source simultanously?

Answer:
If you're programming on a BSD UNIX type system then the following code is
directly of relevence. If not, then you'll have to consult your
system's manual to find an equivalent of the select() system call.
To help you, the following is a brief overview of the select() call.

----------------------- start of overview on select() ---------------------
	int select(int nfds, int *readfds, int *writefds, int *execptfds,
		   struct timeval *timeout);
	
	The select() call is passed in 3 bitmasks - "readfds", "writefds"
	and "execptfds" - the size of these bitmasks in "nfds".
	The bitmasks represent the file descriptors that select() is
	to pay attention to. It will block until there is something
	waiting to be read on any of the "readfds" file descriptors,
	or it is possible to write to any of the "writefds" file
	descriptors or an exception (such as "end of file") is
	encountered on any of the "exceptfds" file descriptors. File
	descriptor N is indicated by "1 << N" in the appropiate
	bitmask. The "timeout" parameter is used to determine the
	maximun amount of time that select() should block for. If
	a NULL pointer is passed in then select() will block
	indefinitely. Upon return, the select() call will overwrite
	the bitmasks to indicate which file descriptors are ready.
	Also the return value is -1 on error, or the number of
	ready file descriptors on success.
------------------------ end of overview on select() -----------------------


You can use the select() system call to wait until there is something
waiting to be read on one of several file descriptors - it's more effecient
than waiting via busy looping. So to manage 2 display connections and
a socket/pipe connection simultaneously you might use a main loop of
the form ...
(disclaimer: I haven't tested this code)

	Display *display_1 = XOpenDisplay(...);
	Display *display_2 = XOpenDisplay(...);
	int other_fd = ... /* code to open a socket or pipe etc */
	struct timeval zero_time;

	zero_time.tv_sec = 0;
	zero_time.tv_usec = 0;

	while (1) {
		int	fd_1, fd_2;
		long	read_mask; /* A 32 bit bitmask - HOPEFULLY big enough */
		int	num_fds, result;
		boolean	got_event = FALSE;

		/*
		** check if there are any X events waiting to be processed.
		** But don't block if there isn't.
		*/

		if (XPending(display_1)) {
			got_event = TRUE;
			XNextEvent(display_1, &event);
			... /* process it */
		}
		if (XPending(display_2)) {
			got_event = TRUE;
			XNextEvent(display_2, &event);
			... /* process it */
		}
		/* ditto for display_3, display_4 ... */

		/*
		** check if there is any data to be read on "other_fd".
		** But don't block if there isn't.
		*/
		read_mask = 1 << other_fd;
		num_fds = other_fd + 1;
		result = select(num_fds, &read_mask,	/* read mask */
					 (int *)0,	/* no write mask */
					 (int *)0,	/* no exception mask */
					 &zero_time);	/* don't block */
		if (read_mask & (1 << other_fd)) {
			got_event = TRUE;
			/* code to read and process data */
			...
		}
		/* ditto for any other socket/pipe connections */

		if (got_event) {
			/* back to top of while loop */
			continue;
		}
		
		/*
		** There's no events to be processed so wait until there is.
		** The select system call is used for this.
		*/

		/* get the file descriptor of the Display connections */
		fd_1 = ConnectionNumber(display_1);
		fd_2 = ConnectionNumber(display_2);

		/* set up the read mask for select() */
		read_mask = (1 << fd_1) | (1 << fd_2) | (1 << other_fd);
		num_fds = max(fd_1, max(fd_2, other_fd)) + 1;

		result = select(num_fds, &read_mask,	/* read mask */
					 (int *)0,	/* no write mask */
					 (int *)0,	/* no exception mask */
					 (struct timeval *)0);	/* no timeout */

		/*
		** The value of "read_mask" could be checked to see
		** which of the file descriptors have data waiting to
		** be read. However, falling back to the top of the while
		** loop will suffice .
		*/
	} /*of while*/


If you modify the above loop style then beware of the following:

For various reasons (including network effeciency, I suppose) some X events
which are yet to be seen are stored in a queue in main memory. Hence, even
though there may be nothing to read on ConnectionNumber(display), there might
be X events held locally by the Xlib data structures. So make sure to use
XPending(display) before doing a blocking select call. Otherwise your program
is likely to hang.

The chapter on event processing in "Introduction to the X Window System",
by Oliver Jones, Prentice-Hall, 1988 (ISBN 0-13-499997-5) also discusses this.
---------------------------------- CUT HERE ---------------------------------

asente@decwrl.dec.com (Paul Asente) (03/13/90)

In article <27@fedeva.UUCP> bill@fedeva.UUCP (Bill Daniels) writes:
I cannot of course find this [XtAppAddInput] documented in any generic
>X document which leads me to believe that it is not a portable construct.

You must have very old documentation.  XtAppAddInput has been in the
Intrinsics since at least R3.

	-paul asente
	    asente@decwrl.dec.com	decwrl!asente