gtoye@supernet.haus.com (Gene Toye) (08/25/90)
I am new to X programming. I have been reading the O'Reilly books as well as others. The concepts of X programming are clear enough based on my experience with other windowing systems. I am designing a terminal emulator and have a design issue I cannot find a good answer for: How can I code a X event loop that also watches for traffic on a second socket connection? I would like to implement the program as a single process without polling loops. Is there some way to do it with select()? I have already considered these options: a second process to watch the socket and signal the main. a polling loop to poll the X event queue and the socket. If anybody knows of a good example of this type of program (terminal emulation) on the X distribution (R4) other than the standard xterm client, please let me know. Thanks. -- Gene Toye: Harris Adacom Corporation / 16001 Dallas Pkwy. / Dallas, TX 75248 Internet: gtoye@supernet.haus.com or gtoye@supernet.lonestar.org Usenet: uunet!{iex,ntvax}!supernet!gtoye DISCLAIMER: My employer never knows what I am going to say next.
mouse@LARRY.MCRCIM.MCGILL.EDU (08/26/90)
> I am designing a terminal emulator and have a design issue I cannot > find a good answer for: > How can I code a X event loop that also watches for traffic on a > second socket connection? There is no portable way to do this. The UNIX way is, as far as I can tell, to use XConnectionNumber(dpy) to get the file descriptor corresponding to the server connection and then toss that into the pot when you do your select(). > If anybody knows of a good example of this type of program (terminal > emulation) on the X distribution (R4) other than the standard xterm > client, please let me know. It's not on the R4 distribution, but I have one. Here's its main loop, for your edification and amusement. (I've edited this down to the pieces more-or-less relevant to the question at hand.) #define SECUSEC 1000000 /* # of tv_usec in a tv_sec */ #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 mustcontinue; int poll; struct timeval timeout; struct timeval then; 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 (!d->have_focus || (d->flash.time == 0)) d->want_cursor_up = 1; } FD_SET(ptyfd,&fds); then = now; gettimeofday(&now,(struct timezone *)0); /* sleep no longer than about 1000 seconds (exactly: 1073 seconds = 17 minutes 53 seconds). */ /* this is so that now minus then can (normally) be converted to usec and */ /* fit in a signed long int, with room for adding small-integer*SECUSEC without overflow. */ timeout = now; timeout.tv_sec += 0x40000000 / SECUSEC; #define TVGTR(t1,t2) ((t1.tv_sec > t2.tv_sec) || ((t1.tv_sec == t2.tv_sec) && (t1.tv_usec > t2.tv_usec))) poll = 0; for (EACH_DISP(d)) { ...check timer-based stuff and possibly modify timeout... } if (wantflush || wantupd) poll = 1; if (! TVGTR(timeout,now)) poll = 1; /* eg, timer expired during other code */ if (poll) { timeout.tv_sec = 0; timeout.tv_usec = 0; } else { timeout.tv_sec -= now.tv_sec; timeout.tv_usec -= now.tv_usec; if (timeout.tv_usec < 0) { timeout.tv_usec += SECUSEC; timeout.tv_sec --; } } selrv = select(FD_SETSIZE,&fds,(fd_set *)0,(fd_set *)0,&timeout); if (childpid == 0) { utexit(0); } if (selrv < 0) { if (errno == EINTR) continue; perror("select"); utexit(1); } for (EACH_DISP(d)) { int t; TIMER *tm; for (t=0;t<NTIMERS;t++) { tm = &d->timers[t]; if (tm->want) { ...check and handle timers for this display... } } if (d->want_cursor_up != d->cursor_up) { resetcursor(d); wantflush = 1; } } if (selrv == 0) { if (wantupd) { update_display(); wantflush = 1; wantupd = 0; } if (wantflush) { for (EACH_DISP(d)) { /* there's a race in scrolling. using XSync instead of XFlush helps but doesn't cure. */ /* basic problem: no timestamps on chars from pty, so can't interleave properly */ /* with events in event stream coming from X server. */ /* basic race is fixable, but requires a lot of hairy code to handle GraphicsExpose */ /* and/or NoExpose events from all the blitting going on in do_line_motion */ XFlush(d->disp); } if (debugging) fflush(stdout); wantflush = 0; } continue; } mustcontinue = 0; for (EACH_DISP(d)) { if (FD_ISSET(d->xfd,&fds)) { int bpend; ioctl(d->xfd,FIONREAD,&bpend); if (bpend == 0) utexit(0); /* socket EOF */ XEventsQueued(d->disp,QueuedAfterReading); mustcontinue = 1; } } if (mustcontinue) continue; if (FD_ISSET(ptyfd,&fds)) { unsigned char obuf[256]; int nr; nr = read(ptyfd,(char *)&obuf[0],sizeof(obuf)); if (nr < 0) if (errno != EINTR) utexit(0); if (nr == 0) utexit(0); if (nr > 0) (*type->typeout)(&obuf[0],nr); wantupd = 1; for (EACH_DISP(d)) { d->flash.phase = 0; d->flash.next = now; d->want_cursor_up = 0; } } } } der Mouse old: mcgill-vision!mouse new: mouse@larry.mcrcim.mcgill.edu