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