[comp.windows.x] Sockets and Xlib

shire@ecst.csuchico.edu (Charles W Hooks) (01/23/91)

	I posted here a while ago asking for help with sockets and Xlib and
some kind soul gave me a big hand.  I also had LOTS of request for any info
I got.  So instead of just bounceing mail, etc.  I'm posting the info
here along with the two code examples, the first mine and the second one
from mazewars(was sent to me).

p.s. To easily jump from one example to another I have "====" preceding
	each example.  Enjoy!

========Here is a responce I got.

>>        Thanks for the example. I've put up severla post before this one and
>>and didn't get any responce so this last one I left out a lot of info in hopes
>>of a responce.  In my program I use select and Xpending, with out selecting on
>>teh X socket.  But I found that Xpending gave me alot more events than I got
>>through XNextEvent.  Was this due to me selecting Socket and Xevents without
>>give the X ones a certian priority?  
>
>That may well be it.  If you look at the code I sent you, you will
>notice that it works something like this:
>
>	do forever:
>		clear the fd mask
>			if there are no X events pending, select to see if
>			there are any X or socket events
>		if there are X events, handle them
>		if there are socker events, handle them
>	end
>
>In other words, if there are any X events pending, the current
>one is handled.  Otherwise, it gives both X and socket events an
>equal chance.
>
>In the case of mazewar, the external sockets are not particularly
>active, since each human action sends only one packet.  If you
>have lots of data, and wish to not have it back up too much when
>the user is messing around, you can change the "if there are no
>X events pending" to "if XQlength tells me that there are less
>than <threshold> events pending", and allow the <threshold> value
>to be set externally.
>
>All of this assumes you are using Xlib and avoiding Xt altogether.
>Xt's XtAppAddInput works very nicely with sockets, and handles
>all of the mess for you.
		
=====In my case I couldn't get XtAddInput to work, but that's me...
>
>...David Elliott
>...dce@smsc.sony.com | ...!{uunet,mips}!sonyusa!dce
>...(408)944-4073

======Here is the code I came up with and it works great, I'll also show you
the code from mazewar, very similar.

void MainLoop ()
{
	XEvent event;
	WinInfo win;

	int check;

	for(;;)
	{
		check = NextEvent(& event);

		if ((!StandardEvent (& event))&&(check != 1)&&(check != -1))
		{

			win = EventWindow (& event);

			switch (event.type)
			{

				case ButtonPress:

					if (win == map_win)
					{
						MapButton (& event);
puts("MapButton");
					}
					else if (win == work_win)
					{
						WorkButton (& event);
puts("WorkButton");
					}
					break;

				case ConfigureNotify:
					break;
		
				case KeyPress:
					GlobalKey (& event);
					break;

			}
		}
		if (check >= 1)
			ReadSocket();
	}

}

int NextEvent (event)
XEvent *event;
{
	int dpyfd;

	DESCR_MASK rd;
	struct timeval refresh_time, *timev;

	int check;
	int event_flag = 0;

	dpyfd = XConnectionNumber(display);

	if(!XPending(display))
	{
		FD_ZERO (&rd);
		FD_SET(dpyfd, &rd);
		FD_SET(sock, &rd);
		refresh_time.tv_sec = 0;
 		refresh_time.tv_usec = 500000;
		timev = &refresh_time;

		check = select(32, &rd, 0, 0, timev);
		if(check < 0)
			leave();
	}
	else
	{
		FD_ZERO(&rd);
		FD_CLR(dpyfd, &rd);
		FD_SET(sock, &rd);
		refresh_time.tv_sec = 0;
 		refresh_time.tv_usec = 0;
		timev = &refresh_time;

		check = select(32, &rd, 0, 0, timev);
		if(check < 0)
			leave();
	}

	if(XPending(display))
	{
		XNextEvent (display, event);
		event_flag = 1;

	}
	if(FD_ISSET(sock, &rd))
	{
		if(event_flag == 0)
			return 1;
		else
			return 2;
	}
	else
	{
		if(event_flag == 0)
			return -1;
		else
			return 0;
	}
}

=========This is the maze war example that was sent to me.


void
NextEvent(event)
MWEvent	*event;
{

#ifdef SVR4
	fd_set	fdmask;
#else
	int	fdmask;
#endif
	XEvent	xev;
	struct timeval timeout;
	int	ret;
	char	c;

#ifdef SVR4
    FD_ZERO(&fdmask);
#endif
    while (1) {
	icon_flash = (++icon_flash) % ICON_FLASH_PERIOD;

	if (!XPending(dpy))	/* this does an XFlush, too */
		if (flashIcon && !icon_flash && !mapped) {
			/* invert the icon  */
			iconInverted = !iconInverted;
			repaintIcon();
		}

	/*
	 * 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 sever
	 * events, leading to sluggish keyboard response and lots of local
	 * death.
	 *
	 * Also, can't just ignore network events -- if the server is slow and
	 * lots of X events get queued, someone else's ratDoctor will time you
	 * out if you never answer.
	 */

	if (!XPending(dpy)) {
#ifdef SVR4
		FD_SET(displayFD, &fdmask);
		FD_SET(M.theSocket, &fdmask);
#else
		fdmask = (1 << displayFD) | (1 << M.theSocket);
#endif
		timeout.tv_sec = 0;
		timeout.tv_usec = 500000;
		while ((ret = select(32, &fdmask, NULL, NULL, &timeout)) == -1)
			if (errno != EINTR)
				MWError("select error on events");
		if (ret == 0) {
			event->eventType = EVENT_TIMEOUT;
			return;
		}
	} else {
#ifdef SVR4
		FD_CLR(displayFD, &fdmask);
		FD_SET(M.theSocket, &fdmask);
#else
		fdmask = 1 << M.theSocket;
#endif
		timeout.tv_sec = 0;
		timeout.tv_usec = 0;
		while ((ret = select(32, &fdmask, NULL, NULL, &timeout)) == -1)
			if (errno != EINTR)
				MWError("select error on events");
	}
	if (XPending(dpy)) {
		XNextEvent(dpy, &xev);
		switch (xev.type) {
		case KeyPress:
			event->eventType = 0;
			XLookupString((XKeyEvent *) &xev, &c, 1, 
					NULL, NULL);
			
			switch(c) {
			case 'a':
			case '4':	/* keypad */
				event->eventType = EVENT_A;
				return;

			case 's':
			case '5':
				event->eventType = EVENT_S;
				return;

			case 'd':
			case '6':
				event->eventType = EVENT_D;
				return;

			case 'f':
			case ',':
				event->eventType = EVENT_F;
				return;

			case ' ':
			case '\033':	/* ESC lead in of arrow */
				event->eventType = EVENT_BAR;
				return;

			case 'i':
				event->eventType = EVENT_I;
				return;

			case 'k':
				event->eventType = EVENT_K;
				return;

			case 'o':
				event->eventType = EVENT_O;
				return;

			case 'l':
				event->eventType = EVENT_L;
				return;

			case 'q':
			case '\177':	/* DEL */
			case '\003':	/* ^C */
				event->eventType = EVENT_INT;
				return;
			}
			break;

#define	RightButton	Button3
#define	MiddleButton	Button2
#define	LeftButton	Button1
		case ButtonPress:
			event->eventType = 0;
			switch(((XButtonPressedEvent *) 
				&xev)->button & 0xff) {
			case RightButton:
				event->eventType = EVENT_RIGHT_D;
				return;

			case MiddleButton:
				event->eventType = EVENT_MIDDLE_D;
				return;

			case LeftButton:
				event->eventType = EVENT_LEFT_D;
				return;
			}
			break;

		case ButtonRelease:
			event->eventType = 0;
			switch(((XButtonReleasedEvent *) 
				&xev)->button&0xff) {
			case RightButton:
				event->eventType = EVENT_RIGHT_U;
				return;

			case LeftButton:
				event->eventType = EVENT_LEFT_U;
				return;
			}
			break;

		case Expose:
			repaintWindow();
			break;

		case FocusIn:
		case MapNotify:
			mapped = TRUE;
			iconInverted = FALSE;
			flashIcon = FALSE;
			repaintIcon();
			break;

		case FocusOut:
		case UnmapNotify:
			mapped = FALSE;
			break;
		}
	}

#ifdef SVR4
	if (FD_ISSET(M.theSocket, &fdmask)) {
#else
	if (fdmask & (1 << M.theSocket)) {
#endif
		int fromLen = sizeof(event->eventSource);
		int cc;

#ifdef SVR4
#include <stropts.h>
long numtoread;
ioctl(M.theSocket, I_NREAD, &numtoread);
if (numtoread > 0) {
#endif
		event->eventType = EVENT_NETWORK;
		cc = recvfrom(M.theSocket, event->eventDetail,
			sizeof(RatPacket), 0, &event->eventSource, &fromLen);
		if (cc <= 0) {
			if (cc < 0 && errno != EINTR)
				perror("event recvfrom");
			continue;
		}
		if (fromLen != sizeof(struct sockaddr_in))
			continue;
		ConvertIncoming(event->eventDetail);
		return;
#ifdef SVR4
}	/* end if numtoread */
#endif
	}
    }
}

-- 
Charles W. Hooks  aka Tribbles                         _   /|
                  aka Moonshae                         \'o.O'
                  aka (shire@ecst.csuchico.edu)        =(___)=
California State University, Chico                        U