home *** CD-ROM | disk | FTP | other *** search
/ ftp.freefriends.org / ftp.freefriends.org.tar / ftp.freefriends.org / arnold / Source / 9wm-1.1.shar.gz / 9wm-1.1.shar / 9wm.c next >
C/C++ Source or Header  |  1995-01-15  |  18KB  |  762 lines

  1. /* Copyright (c) 1994 David Hogan, see README for licence details */
  2. #include <stdio.h>
  3. #include <signal.h>
  4. #include <errno.h>
  5. #include <X11/X.h>
  6. #include <X11/Xos.h>
  7. #include <X11/Xlib.h>
  8. #include <X11/Xutil.h>
  9. #include <X11/Xatom.h>
  10. #include <X11/extensions/shape.h>
  11. #include "dat.h"
  12. #include "fns.h"
  13. #include "patchlevel.h"
  14.  
  15. char    *version[] = 
  16. {
  17.     "9wm version 1.1, Copyright (c) 1994 David Hogan", 0,
  18. };
  19.  
  20. Display         *dpy;
  21. int             screen;
  22. Window          root;
  23. Window          menuwin;
  24. Colormap        def_cmap;
  25. int             initting;
  26. GC              gc;
  27. unsigned long   black;
  28. unsigned long   white;
  29. XFontStruct     *font;
  30. int             nostalgia;
  31. char            **myargv;
  32. char            *termprog;
  33. char            *shell;
  34. Bool            shape;
  35. int             shape_event;
  36. int             _border = 4;
  37. int             min_cmaps;
  38. int             curtime;
  39. int             debug;
  40. int             signalled;
  41.  
  42. Atom        exit_9wm;
  43. Atom        restart_9wm;
  44. Atom        wm_state;
  45. Atom        wm_change_state;
  46. Atom        wm_protocols;
  47. Atom        wm_delete;
  48. Atom        wm_take_focus;
  49. Atom        wm_colormaps;
  50. Atom        _9wm_running;
  51. Atom        _9wm_hold_mode;
  52.  
  53. void    usage(), sighandler(), getevent();
  54.  
  55. char    *fontlist[] = {
  56.     "lucm.latin1.9",
  57.     "blit",
  58.     "9x15bold",
  59.     "lucidasanstypewriter-12",
  60.     "fixed",
  61.     0,
  62. };
  63.  
  64. main(argc, argv)
  65. int argc;
  66. char    *argv[];
  67. {
  68.     int i, status, background, do_exit, do_restart, dummy;
  69.     unsigned long mask;
  70.     XEvent ev;
  71.     XGCValues gv;
  72.     XSetWindowAttributes attr;
  73.     char *fname;
  74.  
  75.     myargv = argv;          /* for restart */
  76.  
  77.     background = do_exit = do_restart = 0;
  78.     font = 0;
  79.     fname = 0;
  80.     for (i = 1; i < argc; i++)
  81.         if (strcmp(argv[i], "-nostalgia") == 0)
  82.             nostalgia++;
  83.         else if (strcmp(argv[i], "-grey") == 0)
  84.             background = 1;
  85.         else if (strcmp(argv[i], "-debug") == 0)
  86.             debug++;
  87.         else if (strcmp(argv[i], "-font") == 0 && i+1<argc) {
  88.             i++;
  89.             fname = argv[i];
  90.         }
  91.         else if (strcmp(argv[i], "-term") == 0 && i+1<argc)
  92.             termprog = argv[++i];
  93.         else if (strcmp(argv[i], "-version") == 0) {
  94.             fprintf(stderr, "%s", version[0]);
  95.             if (PATCHLEVEL > 0)
  96.                 fprintf(stderr, "; patch level %d", PATCHLEVEL);
  97.             putc('\n', stderr);
  98.             exit(0);
  99.         }
  100.         else if (argv[i][0] == '-')
  101.             usage();
  102.         else
  103.             break;
  104.     for (; i < argc; i++)
  105.         if (strcmp(argv[i], "exit") == 0)
  106.             do_exit++;
  107.         else if (strcmp(argv[i], "restart") == 0)
  108.             do_restart++;
  109.         else
  110.             usage();
  111.  
  112.     if (do_exit && do_restart)
  113.         usage();
  114.  
  115.     shell = (char *)getenv("SHELL");
  116.     if (shell == NULL)
  117.         shell = DEFSHELL;
  118.  
  119.     dpy = XOpenDisplay("");
  120.     if (dpy == 0)
  121.         fatal("can't open display");
  122.     screen = DefaultScreen(dpy);
  123.     root = RootWindow(dpy, screen);
  124.     def_cmap = DefaultColormap(dpy, screen);
  125.     min_cmaps = MinCmapsOfScreen(ScreenOfDisplay(dpy, screen));
  126.  
  127.     initting = 1;
  128.     XSetErrorHandler(handler);
  129.     if (signal(SIGTERM, sighandler) == SIG_IGN)
  130.         signal(SIGTERM, SIG_IGN);
  131.     if (signal(SIGINT, sighandler) == SIG_IGN)
  132.         signal(SIGINT, SIG_IGN);
  133.     if (signal(SIGHUP, sighandler) == SIG_IGN)
  134.         signal(SIGHUP, SIG_IGN);
  135.  
  136.     exit_9wm = XInternAtom(dpy, "9WM_EXIT", False);
  137.     restart_9wm = XInternAtom(dpy, "9WM_RESTART", False);
  138.  
  139.     curtime = -1;       /* don't care */
  140.     if (do_exit) {
  141.         sendcmessage(root, exit_9wm, 0L);
  142.         XSync(dpy, False);
  143.         exit(0);
  144.     }
  145.     if (do_restart) {
  146.         sendcmessage(root, restart_9wm, 0L);
  147.         XSync(dpy, False);
  148.         exit(0);
  149.     }
  150.  
  151.     wm_state = XInternAtom(dpy, "WM_STATE", False);
  152.     wm_change_state = XInternAtom(dpy, "WM_CHANGE_STATE", False);
  153.     wm_protocols = XInternAtom(dpy, "WM_PROTOCOLS", False);
  154.     wm_delete = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
  155.     wm_take_focus = XInternAtom(dpy, "WM_TAKE_FOCUS", False);
  156.     wm_colormaps = XInternAtom(dpy, "WM_COLORMAP_WINDOWS", False);
  157.     _9wm_running = XInternAtom(dpy, "_9WM_RUNNING", False);
  158.     _9wm_hold_mode = XInternAtom(dpy, "_9WM_HOLD_MODE", False);
  159.  
  160.     black = BlackPixel(dpy, screen);
  161.     white = WhitePixel(dpy, screen);
  162.  
  163.     if (fname != 0)
  164.         if ((font = XLoadQueryFont(dpy, fname)) == 0)
  165.             fprintf(stderr, "9wm: warning: can't load font %s\n", fname);
  166.  
  167.     if (font == 0) {
  168.         i = 0;
  169.         for (;;) {
  170.             fname = fontlist[i++];
  171.             if (fname == 0) {
  172.                 fprintf(stderr, "9wm: can't find a font\n");
  173.                 exit(1);
  174.             }
  175.             font = XLoadQueryFont(dpy, fname);
  176.             if (font != 0)
  177.                 break;
  178.         }
  179.     }
  180.     if (nostalgia)
  181.         _border--;
  182.  
  183.     gv.foreground = black^white;
  184.     gv.background = white;
  185.     gv.font = font->fid;
  186.     gv.function = GXxor;
  187.     gv.line_width = 0;
  188.     gv.subwindow_mode = IncludeInferiors;
  189.     mask = GCForeground | GCBackground | GCFunction | GCFont | GCLineWidth
  190.         | GCSubwindowMode;
  191.     gc = XCreateGC(dpy, root, mask, &gv);
  192.  
  193.     initcurs();
  194.  
  195. #ifdef  SHAPE
  196.     shape = XShapeQueryExtension(dpy, &shape_event, &dummy);
  197. #endif
  198.  
  199.     attr.cursor = arrow;
  200.     attr.event_mask = SubstructureRedirectMask
  201.         | SubstructureNotifyMask | ColormapChangeMask
  202.         | ButtonPressMask | ButtonReleaseMask | PropertyChangeMask;
  203.     mask = CWCursor|CWEventMask;
  204.     XChangeWindowAttributes(dpy, root, mask, &attr);
  205.     XSync(dpy, False);
  206.  
  207.     if (background) {
  208.         XSetWindowBackgroundPixmap(dpy, root, root_pixmap);
  209.         XClearWindow(dpy, root);
  210.     }
  211.  
  212.     menuwin = XCreateSimpleWindow(dpy, root, 0, 0, 1, 1, 1, black, white);
  213.  
  214.     /* set selection so that 9term knows we're running */
  215.     curtime = CurrentTime;
  216.     XSetSelectionOwner(dpy, _9wm_running, menuwin, timestamp());
  217.  
  218.     XSync(dpy, False);
  219.     initting = 0;
  220.  
  221.     nofocus();
  222.     scanwins();
  223.  
  224.     for (;;) {
  225.         getevent(&ev);
  226.  
  227. #ifdef  DEBUG_EV
  228.         if (debug) {
  229.             ShowEvent(&ev);
  230.             printf("\n");
  231.         }
  232. #endif
  233.         switch (ev.type) {
  234.         default:
  235. #ifdef  SHAPE
  236.             if (shape && ev.type == shape_event)
  237.                 shapenotify((XShapeEvent *)&ev);
  238.             else
  239. #endif
  240.                 fprintf(stderr, "9wm: unknown ev.type %d\n", ev.type);
  241.             break;
  242.         case ButtonPress:
  243.             button(&ev.xbutton);
  244.             break;
  245.         case ButtonRelease:
  246.             break;
  247.         case MapRequest:
  248.             mapreq(&ev.xmaprequest);
  249.             break;
  250.         case ConfigureRequest:
  251.             configurereq(&ev.xconfigurerequest);
  252.             break;
  253.         case CirculateRequest:
  254.             circulatereq(&ev.xcirculaterequest);
  255.             break;
  256.         case UnmapNotify:
  257.             unmap(&ev.xunmap);
  258.             break;
  259.         case CreateNotify:
  260.             newwindow(&ev.xcreatewindow);
  261.             break;
  262.         case DestroyNotify:
  263.             destroy(ev.xdestroywindow.window);
  264.             break;
  265.         case ClientMessage:
  266.             clientmesg(&ev.xclient);
  267.             break;
  268.         case ColormapNotify:
  269.             cmap(&ev.xcolormap);
  270.             break;
  271.         case PropertyNotify:
  272.             property(&ev.xproperty);
  273.             break;
  274.         case SelectionClear:
  275.             fprintf(stderr, "9wm: SelectionClear (this should not happen)\n");
  276.             break;
  277.         case SelectionNotify:
  278.             fprintf(stderr, "9wm: SelectionNotify (this should not happen)\n");
  279.             break;
  280.         case SelectionRequest:
  281.             fprintf(stderr, "9wm: SelectionRequest (this should not happen)\n");
  282.             break;
  283.         case EnterNotify:
  284.             enter(&ev.xcrossing);
  285.             break;
  286.         case ReparentNotify:
  287.             reparent(&ev.xreparent);
  288.             break;
  289.         case MotionNotify:
  290.         case Expose:
  291.         case FocusIn:
  292.         case FocusOut:
  293.         case ConfigureNotify:
  294.         case MapNotify:
  295.         case MappingNotify:
  296.             /* not interested */
  297.             break;
  298.         }
  299.     }
  300. }
  301.  
  302. void
  303. usage()
  304. {
  305.     fprintf(stderr, "usage: 9wm [-grey] [-version] [-font fname] [-term prog] [exit|restart]\n");
  306.     exit(1);
  307. }
  308.  
  309. void
  310. sendcmessage(w, a, x)
  311. Window w;
  312. Atom a;
  313. long x;
  314. {
  315.     XEvent ev;
  316.     int status;
  317.     long mask;
  318.  
  319.     memset(&ev, 0, sizeof(ev));
  320.     ev.xclient.type = ClientMessage;
  321.     ev.xclient.window = w;
  322.     ev.xclient.message_type = a;
  323.     ev.xclient.format = 32;
  324.     ev.xclient.data.l[0] = x;
  325.     ev.xclient.data.l[1] = timestamp();
  326.     mask = 0L;
  327.     if (w == root)
  328.         mask = SubstructureRedirectMask;        /* magic! */
  329.     status = XSendEvent(dpy, w, False, mask, &ev);
  330.     if (status == 0)
  331.         fprintf(stderr, "9wm: sendcmessage failed\n");
  332. }
  333.  
  334. Time
  335. timestamp()
  336. {
  337.     XEvent ev;
  338.  
  339.     if (curtime == CurrentTime) {
  340.         XChangeProperty(dpy, root, _9wm_running, _9wm_running, 8,
  341.                 PropModeAppend, (unsigned char *)"", 0);
  342.         XMaskEvent(dpy, PropertyChangeMask, &ev);
  343.         curtime = ev.xproperty.time;
  344.     }
  345.     return curtime;
  346. }
  347.  
  348. void
  349. sendconfig(c)
  350. Client *c;
  351. {
  352.     XConfigureEvent ce;
  353.  
  354.     ce.type = ConfigureNotify;
  355.     ce.event = c->window;
  356.     ce.window = c->window;
  357.     ce.x = c->x;
  358.     ce.y = c->y;
  359.     ce.width = c->dx;
  360.     ce.height = c->dy;
  361.     ce.border_width = c->border;
  362.     ce.above = None;
  363.     ce.override_redirect = 0;
  364.     XSendEvent(dpy, c->window, False, StructureNotifyMask, (XEvent*)&ce);
  365. }
  366.  
  367. void
  368. scanwins()
  369. {
  370.     unsigned int i, nwins;
  371.     Client *c;
  372.     Window dw1, dw2, *wins;
  373.     XWindowAttributes attr;
  374.  
  375.     XQueryTree(dpy, root, &dw1, &dw2, &wins, &nwins);
  376.     for (i = 0; i < nwins; i++) {
  377.         XGetWindowAttributes(dpy, wins[i], &attr);
  378.         if (attr.override_redirect || wins[i] == menuwin)
  379.             continue;
  380.         c = getclient(wins[i], 1);
  381.         if (c != 0 && c->window == wins[i]) {
  382.             c->x = attr.x;
  383.             c->y = attr.y;
  384.             c->dx = attr.width;
  385.             c->dy = attr.height;
  386.             c->border = attr.border_width;
  387.             if (attr.map_state == IsViewable)
  388.                 manage(c, 1);
  389.         }
  390.     }
  391.     XFree((void *) wins);   /* cast is to shut stoopid compiler up */
  392. }
  393.  
  394. void
  395. configurereq(e)
  396. XConfigureRequestEvent *e;
  397. {
  398.     XWindowChanges wc;
  399.     XConfigureEvent ce;
  400.     Client *c;
  401.  
  402.     /* we don't set curtime as nothing here uses it */
  403.     c = getclient(e->window, 0);
  404.     if (c) {
  405.         gravitate(c, 1);
  406.         if (e->value_mask & CWX)
  407.             c->x = e->x;
  408.         if (e->value_mask & CWY)
  409.             c->y = e->y;
  410.         if (e->value_mask & CWWidth)
  411.             c->dx = e->width;
  412.         if (e->value_mask & CWHeight)
  413.             c->dy = e->height;
  414.         if (e->value_mask & CWBorderWidth)
  415.             c->border = e->border_width;
  416.         gravitate(c, 0);
  417.         if (c->parent != root && c->window == e->window) {
  418.             wc.x = c->x-BORDER;
  419.             wc.y = c->y-BORDER;
  420.             wc.width = c->dx+2*(BORDER-1);
  421.             wc.height = c->dy+2*(BORDER-1);
  422.             wc.border_width = 1;
  423.             wc.sibling = e->above;
  424.             wc.stack_mode = e->detail;
  425.             XConfigureWindow(dpy, e->parent, e->value_mask, &wc);
  426.             sendconfig(c);
  427.         }
  428.     }
  429.  
  430.     if (c && c->init) {
  431.         wc.x = BORDER-1;
  432.         wc.y = BORDER-1;
  433.     }
  434.     else {
  435.         wc.x = e->x;
  436.         wc.y = e->y;
  437.     }
  438.     wc.width = e->width;
  439.     wc.height = e->height;
  440.     wc.border_width = 0;
  441.     wc.sibling = e->above;
  442.     wc.stack_mode = e->detail;
  443.     e->value_mask |= CWBorderWidth;
  444.  
  445.     XConfigureWindow(dpy, e->window, e->value_mask, &wc);
  446. }
  447.  
  448. void
  449. mapreq(e)
  450. XMapRequestEvent *e;
  451. {
  452.     Client *c;
  453.  
  454.     curtime = CurrentTime;
  455.     c = getclient(e->window, 0);
  456.     if (c == 0 || c->window != e->window) {
  457.         fprintf(stderr, "9wm: bogus mapreq %x %x\n", c, e->window);
  458.         return;
  459.     }
  460.  
  461.     switch (c->state) {
  462.     case WithdrawnState:
  463.         if (c->parent == root) {
  464.             if (!manage(c, 0))
  465.                 return;
  466.             break;
  467.         }
  468.         XReparentWindow(dpy, c->window, c->parent, BORDER-1, BORDER-1);
  469.         XAddToSaveSet(dpy, c->window);
  470.         /* fall through... */
  471.     case NormalState:
  472.         XMapRaised(dpy, c->parent);
  473.         XMapWindow(dpy, c->window);
  474.         setstate(c, NormalState);
  475.         if (c->trans != None && current && c->trans == current->window)
  476.                 active(c);
  477.         break;
  478.     case IconicState:
  479.         unhidec(c, 1);
  480.         break;
  481.     }
  482. }
  483.  
  484. void
  485. unmap(e)
  486. XUnmapEvent *e;
  487. {
  488.     Client *c;
  489.  
  490.     curtime = CurrentTime;
  491.     c = getclient(e->window, 0);
  492.     if (c) {
  493.         switch (c->state) {
  494.         case IconicState:
  495.             if (e->send_event) {
  496.                 unhidec(c, 0);
  497.                 withdraw(c);
  498.             }
  499.             break;
  500.         case NormalState:
  501.             if (c == current)
  502.                 nofocus();
  503.             if (!c->reparenting)
  504.                 withdraw(c);
  505.             break;
  506.         }
  507.         c->reparenting = 0;
  508.     }
  509. }
  510.  
  511. void
  512. circulatereq(e)
  513. XCirculateRequestEvent *e;
  514. {
  515.     fprintf(stderr, "It must be the warlock Krill!\n");  /* :-) */
  516. }
  517.  
  518. void
  519. newwindow(e)
  520. XCreateWindowEvent *e;
  521. {
  522.     Client *c;
  523.  
  524.     /* we don't set curtime as nothing here uses it */
  525.     if (e->override_redirect)
  526.         return;
  527.     c = getclient(e->window, 1);
  528.     if (c && c->parent == root) {
  529.         c->x = e->x;
  530.         c->y = e->y;
  531.         c->dx = e->width;
  532.         c->dy = e->height;
  533.         c->border = e->border_width;
  534.     }
  535. }
  536.  
  537. void
  538. destroy(w)
  539. Window w;
  540. {
  541.     Client *c, **l;
  542.  
  543.     curtime = CurrentTime;
  544.     c = getclient(w, 0);
  545.     if (c == 0)
  546.         return;
  547.  
  548.     rmclient(c);
  549.  
  550.     /* flush any errors generated by the window's sudden demise */
  551.     ignore_badwindow = 1;
  552.     XSync(dpy, False);
  553.     ignore_badwindow = 0;
  554. }
  555.  
  556. void
  557. clientmesg(e)
  558. XClientMessageEvent *e;
  559. {
  560.     Client *c;
  561.  
  562.     curtime = CurrentTime;
  563.     if (e->window == root && e->message_type == exit_9wm) {
  564.         cleanup();
  565.         exit(0);
  566.     }
  567.     if (e->window == root && e->message_type == restart_9wm) {
  568.         fprintf(stderr, "*** 9wm restarting ***\n");
  569.         cleanup();
  570.         execvp(myargv[0], myargv);
  571.         perror("9wm: exec failed");
  572.         exit(1);
  573.     }
  574.     if (e->message_type == wm_change_state) {
  575.         c = getclient(e->window, 0);
  576.         if (e->format == 32 && e->data.l[0] == IconicState && c != 0) {
  577.             if (normal(c))
  578.                 hide(c);
  579.         }
  580.         else
  581.             fprintf(stderr, "9wm: WM_CHANGE_STATE: format %d data %d w 0x%x\n",
  582.                 e->format, e->data.l[0], e->window);
  583.         return;
  584.     }
  585.     fprintf(stderr, "9wm: strange ClientMessage, type 0x%x window 0x%x\n",
  586.         e->message_type, e->window);
  587. }
  588.  
  589. void
  590. cmap(e)
  591. XColormapEvent *e;
  592. {
  593.     Client *c;
  594.     int i;
  595.  
  596.     /* we don't set curtime as nothing here uses it */
  597.     if (e->new) {
  598.         c = getclient(e->window, 0);
  599.         if (c) {
  600.             c->cmap = e->colormap;
  601.             if (c == current)
  602.                 cmapfocus(c);
  603.         }
  604.         else
  605.             for (c = clients; c; c = c->next)
  606.                 for (i = 0; i < c->ncmapwins; i++)
  607.                     if (c->cmapwins[i] == e->window) {
  608.                         c->wmcmaps[i] = e->colormap;
  609.                         if (c == current)
  610.                             cmapfocus(c);
  611.                         return;
  612.                     }
  613.     }
  614. }
  615.  
  616. void
  617. property(e)
  618. XPropertyEvent *e;
  619. {
  620.     Atom a;
  621.     int delete;
  622.     Client *c;
  623.  
  624.     /* we don't set curtime as nothing here uses it */
  625.     a = e->atom;
  626.     delete = (e->state == PropertyDelete);
  627.     c = getclient(e->window, 0);
  628.     if (c == 0)
  629.         return;
  630.  
  631.     switch (a) {
  632.     case XA_WM_ICON_NAME:
  633.         if (c->iconname != 0)
  634.             XFree((char*) c->iconname);
  635.         c->iconname = getprop(c->window, XA_WM_ICON_NAME);
  636.         setlabel(c);
  637.         renamec(c, c->label);
  638.         return;
  639.     case XA_WM_NAME:
  640.         if (c->name != 0)
  641.             XFree((char*) c->name);
  642.         c->name = getprop(c->window, XA_WM_NAME);
  643.         setlabel(c);
  644.         renamec(c, c->label);
  645.         return;
  646.     case XA_WM_TRANSIENT_FOR:
  647.         gettrans(c);
  648.         return;
  649.     }
  650.     if (a == _9wm_hold_mode) {
  651.         c->hold = getiprop(c->window, _9wm_hold_mode);
  652.         if (c == current)
  653.             draw_border(c, 1);
  654.     }
  655.     else if (a == wm_colormaps) {
  656.         getcmaps(c);
  657.         if (c == current)
  658.             cmapfocus(c);
  659.     }
  660. }
  661.  
  662. void
  663. reparent(e)
  664. XReparentEvent *e;
  665. {
  666.     Client *c;
  667.     XWindowAttributes attr;
  668.  
  669.     if (e->event != root || e->override_redirect)
  670.         return;
  671.     if (e->parent == root) {
  672.         c = getclient(e->window, 1);
  673.         if (c != 0 && (c->dx == 0 || c->dy == 0)) {
  674.             XGetWindowAttributes(dpy, c->window, &attr);
  675.             c->x = attr.x;
  676.             c->y = attr.y;
  677.             c->dx = attr.width;
  678.             c->dy = attr.height;
  679.             c->border = attr.border_width;
  680.         }
  681.     }
  682.     else {
  683.         c = getclient(e->window, 0);
  684.         if (c != 0 && (c->parent == root || withdrawn(c))) 
  685.             rmclient(c);
  686.     }
  687. }
  688.  
  689. #ifdef  SHAPE
  690. void
  691. shapenotify(e)
  692. XShapeEvent *e;
  693. {
  694.     Client *c;
  695.  
  696.     c = getclient(e->window, 0);
  697.     if (c == 0)
  698.         return;
  699.  
  700.     setshape(c);
  701. }
  702. #endif
  703.  
  704. void
  705. enter(e)
  706. XCrossingEvent *e;
  707. {
  708.     Client *c;
  709.  
  710.     curtime = e->time;
  711.     if (e->mode != NotifyGrab || e->detail != NotifyNonlinearVirtual)
  712.         return;
  713.     c = getclient(e->window, 0);
  714.     if (c != 0 && c != current) {
  715.         XMapRaised(dpy, c->parent);
  716.         active(c);
  717.     }
  718. }
  719.  
  720. void
  721. sighandler()
  722. {
  723.     signalled = 1;
  724. }
  725.  
  726. void
  727. getevent(e)
  728. XEvent *e;
  729. {
  730.     int fd;
  731.     fd_set rfds;
  732.     struct timeval t;
  733.  
  734.     if (!signalled) {
  735.         if (QLength(dpy) > 0) {
  736.             XNextEvent(dpy, e);
  737.             return;
  738.         }
  739.         fd = ConnectionNumber(dpy);
  740.         FD_ZERO(&rfds);
  741.         FD_SET(fd, &rfds);
  742.         t.tv_sec = t.tv_usec = 0;
  743.         if (select(fd+1, &rfds, NULL, NULL, &t) == 1) {
  744.             XNextEvent(dpy, e);
  745.             return;
  746.         }
  747.         XFlush(dpy);
  748.         FD_SET(fd, &rfds);
  749.         if (select(fd+1, &rfds, NULL, NULL, NULL) == 1) {
  750.             XNextEvent(dpy, e);
  751.             return;
  752.         }
  753.         if (errno != EINTR || !signalled) {
  754.             perror("9wm: select failed");
  755.             exit(1);
  756.         }
  757.     }
  758.     cleanup();
  759.     fprintf(stderr, "9wm: exiting on signal\n");
  760.     exit(1);
  761. }
  762.