/* $Id: sample_server2.c,v 1.2 2003/08/23 01:28:59 jonsmirl Exp $ */ /* * Sample server that just keeps first available window mapped. * * It also reads and echos anything that happens on stdin as an * example of tracking events from sources other than miniglx clients. * * It reads & writes without blocking, so that eg. piping a lot of * text to stdin and then hitting 'ctrl-S' on the output stream won't * cause it to stop handling miniglx events. * * See select_tut in the linux manual pages for a good overview of the * select(2) system call. */ #include #include #include #include #include #include #include #include struct client { struct client *next; Window windowid; int mappable; }; struct client *clients = 0, *mapped_client = 0; #define BUFSZ 4096 char rbuf[BUFSZ]; int rbuf_count; static struct client *find_client( Window id ) { struct client *c; for (c = clients ; c ; c = c->next) if (c->windowid == id) return c; return 0; } int main( int argc, char *argv[] ) { Display *dpy; XEvent ev; int autostart = 0; if (argc == 2 && strcmp(argv[1], "-autostart") == 0) autostart = 1; dpy = __miniglx_StartServer(NULL); if (!dpy) { fprintf(stderr, "Error: __miniglx_StartServer failed\n"); return 1; } /* How is vt switching communicated through the XNextEvent interface? */ while (1) { int r, n; struct timeval tv; fd_set rfds, wfds; int bored = 0; FD_ZERO(&rfds); FD_ZERO(&wfds); tv.tv_sec = 1; tv.tv_usec = 0; if (rbuf_count) { FD_SET( 1, &wfds ); /* notify when we can write out buffer */ n = 1; } else { FD_SET( 0, &rfds ); /* else notify when new data to read */ n = 0; } /* __miniglx_Select waits until any of these file groups becomes * readable/writable/etc (like regular select), until timeout * expires (like regular select), until a signal is received * (like regular select) or until an event is available for * XCheckMaskEvent(). */ r = __miniglx_Select( dpy, n+1, &rfds, &wfds, 0, &tv ); /* This can happen if select() is interrupted by a signal: */ if (r < 0 && errno != EINTR && errno != EAGAIN) { perror ("select()"); exit (1); } if (tv.tv_sec == 0 && tv.tv_usec == 0) bored = 1; /* Check and handle events on our local file descriptors */ if (FD_ISSET( 0, &rfds )) { /* Something on stdin */ assert(rbuf_count == 0); r = read(0, rbuf, BUFSZ); if (r < 1) { perror("read"); abort(); } rbuf_count = r; } if (FD_ISSET( 1, &wfds )) { /* Can write to stdout */ assert(rbuf_count > 0); r = write(1, rbuf, rbuf_count); if (r < 1) { perror("write"); abort(); } rbuf_count -= r; if (rbuf_count) memmove(rbuf + r, rbuf, rbuf_count); } /* Check and handle events generated by miniglx: */ while (XCheckMaskEvent( dpy, ~0, &ev )) { struct client *c; bored = 0; fprintf(stderr, "Received event %d\n", ev.type); switch (ev.type) { case CreateNotify: fprintf(stderr, "CreateNotify -- new client\n"); c = malloc(sizeof(*c)); c->next = clients; c->windowid = ev.xcreatewindow.window; c->mappable = False; clients = c; break; case DestroyNotify: fprintf(stderr, "DestroyNotify\n"); c = find_client(ev.xdestroywindow.window); if (!c) break; if (c == clients) clients = c->next; else { struct client *t; for (t = clients ; t->next != c ; t = t->next) ; t->next = c->next; } if (c == mapped_client) mapped_client = 0; free(c); break; case MapRequest: fprintf(stderr, "MapRequest\n"); c = find_client(ev.xmaprequest.window); if (!c) break; c->mappable = True; break; case UnmapNotify: fprintf(stderr, "UnmapNotify\n"); c = find_client(ev.xunmap.window); if (!c) break; c->mappable = False; if (c == mapped_client) mapped_client = 0; break; default: break; } } /* Search for first mappable client if none already mapped. */ if (!mapped_client) { struct client *c; for (c = clients ; c ; c = c->next) { if (c->mappable) { XMapWindow( dpy, c->windowid ); mapped_client = c; break; } } if (!clients && autostart) { system("nohup ./texline &"); system("nohup ./manytex &"); } } else if (bored) { struct client *c; /* bored of mapped client now, let's try & find another one */ for (c = mapped_client->next ; c && !c->mappable ; c = c->next) ; if (!c) for (c = clients ; c && !c->mappable ; c = c->next) ; if (c && c != mapped_client) { XUnmapWindow( dpy, mapped_client->windowid ); XMapWindow( dpy, c->windowid ); mapped_client = c; } else fprintf(stderr, "I'm bored!\n"); } } XCloseDisplay( dpy ); return 0; }