home *** CD-ROM | disk | FTP | other *** search
/ Magazyn Amiga 5 / MA_Cover_5.iso / ppc / mesa / src-glut / glut_event.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-01-31  |  41.0 KB  |  1,247 lines

  1. /* Copyright (c) Mark J. Kilgard, 1994, 1995, 1996. */
  2.  
  3. /* This program is freely distributable without licensing fees
  4.    and is provided without guarantee or warrantee expressed or
  5.    implied. This program is -not- in the public domain. */
  6.  
  7. #include <stdlib.h>
  8. #include <stdio.h>
  9. #include <errno.h>
  10. #include <assert.h>
  11. #ifdef __sgi
  12. #include <bstring.h>    /* prototype for bzero used by FD_ZERO */
  13. #endif
  14. #ifdef AIXV3
  15. #include <sys/select.h> /* select system call interface */
  16. #endif
  17. #include <sys/types.h>
  18. #if !defined(WIN32) 
  19. #ifndef __vms
  20. #include <sys/time.h>
  21. #endif
  22. #include <unistd.h>
  23. #include <X11/Xlib.h>
  24. #include <X11/keysym.h>
  25. #else
  26. #ifdef __CYGWIN32__
  27. #include <sys/time.h>
  28. #else
  29. #include <sys/timeb.h>
  30. #endif
  31. #endif /* !WIN32 */
  32. #ifdef __hpux
  33. /* XXX Bert Gijsbers <bert@mc.bio.uva.nl> reports that HP-UX
  34.    needs different keysyms for the End, Insert, and Delete keys
  35.    to work on an HP 715.  It would be better if HP generated
  36.    standard keysyms for standard keys. */
  37. #include <X11/HPkeysym.h>
  38. #endif
  39. #ifdef __vms
  40. #include <ssdef.h>
  41. #include <psldef.h>
  42. extern int SYS$CLREF(int efn);
  43. extern int SYS$SETIMR(unsigned int efn, struct timeval *timeout, void *ast,
  44.   unsigned int request_id, unsigned int flags);
  45. extern int SYS$WFLOR(unsigned int efn, unsigned int mask);
  46. extern int SYS$CANTIM(unsigned int request_id, unsigned int mode);
  47. #endif /* __vms */
  48. #include <GL/glut.h>
  49. #include "glutint.h"
  50.  
  51. static GLUTtimer *freeTimerList = NULL;
  52. static int mappedMenuButton;
  53.  
  54. GLUTidleCB __glutIdleFunc = NULL;
  55. GLUTtimer *__glutTimerList = NULL;
  56. #ifdef SUPPORT_FORTRAN
  57. GLUTtimer *__glutNewTimer;
  58. #endif
  59. GLUTwindow *__glutWindowWorkList = NULL;
  60. void (*__glutUpdateInputDeviceMaskFunc) (GLUTwindow *);
  61. Atom __glutMotifHints = None;
  62. /* Modifier mask of ~0 implies not in core input callback. */
  63. unsigned int __glutModifierMask = (unsigned int) ~0;
  64. int __glutWindowDamaged = 0;
  65.  
  66. void APIENTRY
  67. glutIdleFunc(GLUTidleCB idleFunc)
  68. {
  69.   __glutIdleFunc = idleFunc;
  70. }
  71.  
  72. void APIENTRY
  73. glutTimerFunc(unsigned int interval, GLUTtimerCB timerFunc, int value)
  74. {
  75.   GLUTtimer *timer, *other;
  76.   GLUTtimer **prevptr;
  77.   struct timeval now;
  78.  
  79.   if (!timerFunc)
  80.     return;
  81.  
  82.   if (freeTimerList) {
  83.     timer = freeTimerList;
  84.     freeTimerList = timer->next;
  85.   } else {
  86.     timer = (GLUTtimer *) malloc(sizeof(GLUTtimer));
  87.     if (!timer)
  88.       __glutFatalError("out of memory.");
  89.   }
  90.  
  91.   timer->func = timerFunc;
  92. #ifdef __vms
  93.   /* VMS time is expressed in units of 100 ns */
  94.   timer->timeout.val = interval * TICKS_PER_MILLISECOND;
  95. #else
  96.   timer->timeout.tv_sec = (int) interval / 1000;
  97.   timer->timeout.tv_usec = (int) (interval % 1000) * 1000;
  98. #endif
  99.   timer->value = value;
  100.   timer->next = NULL;
  101.   GETTIMEOFDAY(&now);
  102.   ADD_TIME(timer->timeout, timer->timeout, now);
  103.   prevptr = &__glutTimerList;
  104.   other = *prevptr;
  105.   while (other && IS_AFTER(other->timeout, timer->timeout)) {
  106.     prevptr = &other->next;
  107.     other = *prevptr;
  108.   }
  109.   timer->next = other;
  110. #ifdef SUPPORT_FORTRAN
  111.   __glutNewTimer = timer;  /* for Fortran binding! */
  112. #endif
  113.   *prevptr = timer;
  114. }
  115.  
  116. void
  117. handleTimeouts(void)
  118. {
  119.   struct timeval now;
  120.   GLUTtimer *timer;
  121.  
  122.   /* Assumption is that __glutTimerList is already determined
  123.      to be non-NULL. */
  124.   GETTIMEOFDAY(&now);
  125.   while (IS_AT_OR_AFTER(__glutTimerList->timeout, now)) {
  126.     timer = __glutTimerList;
  127.     timer->func(timer->value);
  128.     __glutTimerList = timer->next;
  129.     timer->next = freeTimerList;
  130.     freeTimerList = timer;
  131.     if (!__glutTimerList)
  132.       break;
  133.   }
  134. }
  135.  
  136. void
  137. __glutPutOnWorkList(GLUTwindow * window, int workMask)
  138. {
  139.   if (window->workMask) {
  140.     /* Already on list; just OR in new workMask. */
  141.     window->workMask |= workMask;
  142.   } else {
  143.     /* Update work mask and add to window work list. */
  144.     window->workMask = workMask;
  145.     window->prevWorkWin = __glutWindowWorkList;
  146.     __glutWindowWorkList = window;
  147.   }
  148. }
  149.  
  150. void
  151. __glutPostRedisplay(GLUTwindow * window, int layerMask)
  152. {
  153.   int shown = (layerMask & (GLUT_REDISPLAY_WORK | GLUT_REPAIR_WORK)) ?
  154.   window->shownState : window->overlay->shownState;
  155.  
  156.   /* Post a redisplay if the window is visible (or the
  157.      visibility of the window is unknown, ie. window->visState
  158.      == -1) _and_ the layer is known to be shown. */
  159.   if (window->visState != GLUT_HIDDEN && window->visState != GLUT_FULLY_COVERED && shown)
  160.     __glutPutOnWorkList(window, layerMask);
  161. }
  162.  
  163. /* CENTRY */
  164. void APIENTRY
  165. glutPostRedisplay(void)
  166. {
  167.   __glutPostRedisplay(__glutCurrentWindow, GLUT_REDISPLAY_WORK);
  168. }
  169.  
  170. /* ENDCENTRY */
  171. static GLUTeventParser *eventParserList = NULL;
  172.  
  173. /* __glutRegisterEventParser allows another module to register
  174.    to intercept X events types not otherwise acted on by the
  175.    GLUT processEventsAndTimeouts routine.  The X Input
  176.    extension support code uses an event parser for handling X
  177.    Input extension events.  */
  178.  
  179. void
  180. __glutRegisterEventParser(GLUTeventParser * parser)
  181. {
  182.   parser->next = eventParserList;
  183.   eventParserList = parser;
  184. }
  185.  
  186. static void
  187. markWindowHidden(GLUTwindow * window)
  188. {
  189.   if (GLUT_HIDDEN != window->visState) {
  190.     GLUTwindow *child;
  191.  
  192.     if (window->windowStatus) {
  193.       window->visState = GLUT_HIDDEN;
  194.       __glutSetWindow(window);
  195.       window->windowStatus(GLUT_HIDDEN);
  196.     }
  197.     /* An unmap is only reported on a single window; its
  198.        descendents need to know they are no longer visible. */
  199.     child = window->children;
  200.     while (child) {
  201.       markWindowHidden(child);
  202.       child = child->siblings;
  203.     }
  204.   }
  205. }
  206.  
  207. static void
  208. purgeStaleWindow(Window win)
  209. {
  210.   GLUTstale **pEntry = &__glutStaleWindowList;
  211.   GLUTstale *entry = __glutStaleWindowList;
  212.  
  213.   /* Tranverse singly-linked stale window list look for the
  214.      window ID. */
  215.   while (entry) {
  216.     if (entry->win == win) {
  217.       /* Found it; delete it. */
  218.       *pEntry = entry->next;
  219.       free(entry);
  220.       return;
  221.     } else {
  222.       pEntry = &entry->next;
  223.       entry = *pEntry;
  224.     }
  225.   }
  226. }
  227.  
  228. #if !defined(WIN32)
  229.  
  230. /* Unlike XNextEvent, if a signal arrives,
  231.    interruptibleXNextEvent will return (with a zero return
  232.    value).  This helps GLUT drop out of XNextEvent if a signal
  233.    is delivered.  The intent is so that a GLUT program can call 
  234.    glutIdleFunc in a signal handler to register an idle func
  235.    and then immediately get dropped into the idle func (after
  236.    returning from the signal handler).  The idea is to make
  237.    GLUT's main loop reliably interruptible by signals. */
  238. static int
  239. interruptibleXNextEvent(Display * dpy, XEvent * event)
  240. {
  241.   fd_set fds;
  242.   int rc;
  243.  
  244.   /* Flush X protocol since XPending does not do this
  245.      implicitly. */
  246.   XFlush(__glutDisplay);
  247.   for (;;) {
  248.     if (XPending(__glutDisplay)) {
  249.       XNextEvent(dpy, event);
  250.       return 1;
  251.     }
  252.     FD_ZERO(&fds);
  253.     FD_SET(__glutConnectionFD, &fds);
  254.     rc = select(__glutConnectionFD + 1, &fds,
  255.       NULL, NULL, NULL);
  256.     if (rc < 0) {
  257.       if (errno == EINTR) {
  258.         return 0;
  259.       } else {
  260.         __glutFatalError("select error.");
  261.       }
  262.     }
  263.   }
  264. }
  265.  
  266. #endif
  267.  
  268. static void
  269. processEventsAndTimeouts(void)
  270. {
  271.   XEvent event, ahead;
  272.   GLUTwindow *window;
  273.   int gotEvent, width, height;
  274.   GLUTeventParser *parser;
  275.  
  276.   do {
  277. #if defined(WIN32)
  278.     if(!GetMessage(&event, NULL, 0, 0))    /* bail if no more messages */
  279.       exit(0);
  280.     TranslateMessage(&event);        /* translate virtual-key messages */
  281.     DispatchMessage(&event);        /* call the window proc */
  282.     /* see win32_event.c for event (message) processing procedures */
  283. #else
  284.     gotEvent = interruptibleXNextEvent(__glutDisplay, &event);
  285.     if (gotEvent) {
  286.       switch (event.type) {
  287.       case MappingNotify:
  288.         XRefreshKeyboardMapping((XMappingEvent *) & event);
  289.         break;
  290.       case ConfigureNotify:
  291.         window = __glutGetWindow(event.xconfigure.window);
  292.         if (window) {
  293.           if (window->win != event.xconfigure.window) {
  294.             /* Ignore ConfigureNotify sent to the overlay
  295.                planes. GLUT could get here because overlays
  296.                select for StructureNotify events to receive
  297.                DestroyNotify. */
  298.             break;
  299.           }
  300.           width = event.xconfigure.width;
  301.           height = event.xconfigure.height;
  302.           if (width != window->width || height != window->height) {
  303.             if (window->overlay) {
  304.               XResizeWindow(__glutDisplay, window->overlay->win, width, height);
  305.             }
  306.             window->width = width;
  307.             window->height = height;
  308.             __glutSetWindow(window);
  309.             /* Do not execute OpenGL out of sequence with
  310.                respect to the XResizeWindow request! */
  311.             glXWaitX();
  312.             window->reshape(width, height);
  313.             window->forceReshape = False;
  314.             /* A reshape should be considered like posting a
  315.                redisplay; this is necessary for the "Mesa
  316.                glXSwapBuffers to repair damage" hack to operate
  317.                correctly.  Without it, there's not an initial
  318.                back buffer render from which to blit from when
  319.                damage happens to the window. */
  320.             __glutPostRedisplay(window, GLUT_REDISPLAY_WORK);
  321.           }
  322.         }
  323.         break;
  324.       case Expose:
  325.         /* compress expose events */
  326.         while (XEventsQueued(__glutDisplay, QueuedAfterReading)
  327.           > 0) {
  328.           XPeekEvent(__glutDisplay, &ahead);
  329.           if (ahead.type != Expose ||
  330.             ahead.xexpose.window != event.xexpose.window)
  331.             break;
  332.           XNextEvent(__glutDisplay, &event);
  333.         }
  334.         if (event.xexpose.count == 0) {
  335.           GLUTmenu *menu;
  336.  
  337.           if (__glutMappedMenu &&
  338.             (menu = __glutGetMenu(event.xexpose.window))) {
  339.             __glutPaintMenu(menu);
  340.           } else {
  341.             window = __glutGetWindow(event.xexpose.window);
  342.             if (window) {
  343.               if (window->win == event.xexpose.window) {
  344.                 __glutPostRedisplay(window, GLUT_REPAIR_WORK);
  345.               } else if (window->overlay && window->overlay->win == event.xexpose.window) {
  346.                 __glutPostRedisplay(window, GLUT_OVERLAY_REPAIR_WORK);
  347.               }
  348.             }
  349.           }
  350.         } else {
  351.           /* there are more exposes to read; wait to redisplay */
  352.         }
  353.         break;
  354.       case ButtonPress:
  355.       case ButtonRelease:
  356.         if (__glutMappedMenu && event.type == ButtonRelease
  357.           && mappedMenuButton == event.xbutton.button) {
  358.           /* Menu is currently popped up and its button is
  359.              released. */
  360.           __glutFinishMenu(event.xbutton.window, event.xbutton.x, event.xbutton.y);
  361.         } else {
  362.           window = __glutGetWindow(event.xbutton.window);
  363.           if (window) {
  364.             GLUTmenu *menu;
  365.  
  366.             menu = __glutGetMenuByNum(
  367.               window->menu[event.xbutton.button - 1]);
  368.             if (menu) {
  369.               if (event.type == ButtonPress && !__glutMappedMenu) {
  370.                 __glutStartMenu(menu, window,
  371.                   event.xbutton.x_root, event.xbutton.y_root,
  372.                   event.xbutton.x, event.xbutton.y);
  373.                 mappedMenuButton = event.xbutton.button;
  374.               } else {
  375.                 /* Ignore a release of a button with a menu
  376.                    attatched to it when no menu is popped up,
  377.                    or ignore a press when another menu is
  378.                    already popped up. */
  379.               }
  380.             } else if (window->mouse) {
  381.               __glutSetWindow(window);
  382.               __glutModifierMask = event.xbutton.state;
  383.               window->mouse(event.xbutton.button - 1,
  384.                 event.type == ButtonRelease ?
  385.                 GLUT_UP : GLUT_DOWN,
  386.                 event.xbutton.x, event.xbutton.y);
  387.               __glutModifierMask = ~0;
  388.             } else {
  389.               /* Stray mouse events.  Ignore. */
  390.             }
  391.           } else {
  392.             /* Window might have been destroyed and all the 
  393.                events for the window may not yet be received. */
  394.           }
  395.         }
  396.         break;
  397.       case MotionNotify:
  398.         if (!__glutMappedMenu) {
  399.           window = __glutGetWindow(event.xmotion.window);
  400.           if (window) {
  401.             /* If motion function registered _and_ buttons held 
  402.                * down, call motion function...  */
  403.             if (window->motion && event.xmotion.state &
  404.               (Button1Mask | Button2Mask | Button3Mask)) {
  405.               __glutSetWindow(window);
  406.               window->motion(event.xmotion.x, event.xmotion.y);
  407.             }
  408.             /* If passive motion function registered _and_
  409.                buttons not held down, call passive motion
  410.                function...  */
  411.             else if (window->passive &&
  412.                 ((event.xmotion.state &
  413.                     (Button1Mask | Button2Mask | Button3Mask)) ==
  414.                 0)) {
  415.               __glutSetWindow(window);
  416.               window->passive(event.xmotion.x,
  417.                 event.xmotion.y);
  418.             }
  419.           }
  420.         } else {
  421.           /* Motion events are thrown away when a pop up menu
  422.              is active. */
  423.         }
  424.         break;
  425.       case KeyPress:
  426.         window = __glutGetWindow(event.xkey.window);
  427.         if (!window) {
  428.           break;
  429.         }
  430.         if (window->keyboard) {
  431.           char tmp[1];
  432.           int rc;
  433.  
  434.           rc = XLookupString(&event.xkey, tmp, sizeof(tmp),
  435.             NULL, NULL);
  436.           if (rc) {
  437.             __glutSetWindow(window);
  438.             __glutModifierMask = event.xkey.state;
  439.             window->keyboard(tmp[0],
  440.               event.xkey.x, event.xkey.y);
  441.             __glutModifierMask = ~0;
  442.             break;
  443.           }
  444.         }
  445.         if (window->special) {
  446.           KeySym ks;
  447.           int key;
  448.  
  449. /* Introduced in X11R6:  (Partial list of) Keypad Functions.  Define
  450.    in place in case compiling against an older pre-X11R6
  451.    X11/keysymdef.h file. */
  452. #ifndef XK_KP_Home
  453. #define XK_KP_Home              0xFF95
  454. #endif
  455. #ifndef XK_KP_Left
  456. #define XK_KP_Left              0xFF96
  457. #endif
  458. #ifndef XK_KP_Up
  459. #define XK_KP_Up                0xFF97
  460. #endif
  461. #ifndef XK_KP_Right
  462. #define XK_KP_Right             0xFF98
  463. #endif
  464. #ifndef XK_KP_Down
  465. #define XK_KP_Down              0xFF99
  466. #endif
  467. #ifndef XK_KP_Prior
  468. #define XK_KP_Prior             0xFF9A
  469. #endif
  470. #ifndef XK_KP_Next
  471. #define XK_KP_Next              0xFF9B
  472. #endif
  473. #ifndef XK_KP_End
  474. #define XK_KP_End               0xFF9C
  475. #endif
  476. #ifndef XK_KP_Insert
  477. #define XK_KP_Insert            0xFF9E
  478. #endif
  479. #ifndef XK_KP_Delete
  480. #define XK_KP_Delete            0xFF9F
  481. #endif
  482.  
  483.           ks = XLookupKeysym((XKeyEvent *) & event, 0);
  484.           /* XXX Verbose, but makes no assumptions about keysym
  485.              layout. */
  486.           switch (ks) {
  487. /* *INDENT-OFF* */
  488.           /* function keys */
  489.           case XK_F1:    key = GLUT_KEY_F1; break;
  490.           case XK_F2:    key = GLUT_KEY_F2; break;
  491.           case XK_F3:    key = GLUT_KEY_F3; break;
  492.           case XK_F4:    key = GLUT_KEY_F4; break;
  493.           case XK_F5:    key = GLUT_KEY_F5; break;
  494.           case XK_F6:    key = GLUT_KEY_F6; break;
  495.           case XK_F7:    key = GLUT_KEY_F7; break;
  496.           case XK_F8:    key = GLUT_KEY_F8; break;
  497.           case XK_F9:    key = GLUT_KEY_F9; break;
  498.           case XK_F10:   key = GLUT_KEY_F10; break;
  499.           case XK_F11:   key = GLUT_KEY_F11; break;
  500.           case XK_F12:   key = GLUT_KEY_F12; break;
  501.           /* directional keys */
  502.       case XK_KP_Left:
  503.           case XK_Left:  key = GLUT_KEY_LEFT; break;
  504.       case XK_KP_Up: /* Introduced in X11R6. */
  505.           case XK_Up:    key = GLUT_KEY_UP; break;
  506.       case XK_KP_Right: /* Introduced in X11R6. */
  507.           case XK_Right: key = GLUT_KEY_RIGHT; break;
  508.       case XK_KP_Down: /* Introduced in X11R6. */
  509.           case XK_Down:  key = GLUT_KEY_DOWN; break;
  510. /* *INDENT-ON* */
  511.  
  512.       case XK_KP_Prior: /* Introduced in X11R6. */
  513.           case XK_Prior:
  514.             /* XK_Prior same as X11R6's XK_Page_Up */
  515.             key = GLUT_KEY_PAGE_UP;
  516.             break;
  517.       case XK_KP_Next: /* Introduced in X11R6. */
  518.           case XK_Next:
  519.             /* XK_Next same as X11R6's XK_Page_Down */
  520.             key = GLUT_KEY_PAGE_DOWN;
  521.             break;
  522.       case XK_KP_Home: /* Introduced in X11R6. */
  523.           case XK_Home:
  524.             key = GLUT_KEY_HOME;
  525.             break;
  526. #ifdef __hpux
  527.           case XK_Select:
  528. #endif
  529.       case XK_KP_End: /* Introduced in X11R6. */
  530.           case XK_End:
  531.             key = GLUT_KEY_END;
  532.             break;
  533. #ifdef __hpux
  534.           case XK_InsertChar:
  535. #endif
  536.       case XK_KP_Insert: /* Introduced in X11R6. */
  537.           case XK_Insert:
  538.             key = GLUT_KEY_INSERT;
  539.             break;
  540. #ifdef __hpux
  541.           case XK_DeleteChar:
  542. #endif
  543.       case XK_KP_Delete: /* Introduced in X11R6. */
  544.             /* The Delete character is really an ASCII key. */
  545.             __glutSetWindow(window);
  546.             window->keyboard(127,  /* ASCII Delete character. */
  547.               event.xkey.x, event.xkey.y);
  548.             goto skip;
  549.           default:
  550.             goto skip;
  551.           }
  552.           __glutSetWindow(window);
  553.           __glutModifierMask = event.xkey.state;
  554.           window->special(key, event.xkey.x, event.xkey.y);
  555.           __glutModifierMask = ~0;
  556.         skip:;
  557.         }
  558.         break;
  559.       case EnterNotify:
  560.       case LeaveNotify:
  561.         if (event.xcrossing.mode != NotifyNormal ||
  562.           event.xcrossing.detail == NotifyNonlinearVirtual ||
  563.           event.xcrossing.detail == NotifyVirtual) {
  564.  
  565.           /* Careful to ignore Enter/LeaveNotify events that
  566.              come from the pop-up menu pointer grab and ungrab. 
  567.              Also, ignore "virtual" Enter/LeaveNotify events
  568.              since they represent the pointer passing through
  569.              the window hierarchy without actually entering or
  570.              leaving the actual real estate of a window.  */
  571.  
  572.           break;
  573.         }
  574.         if (__glutMappedMenu) {
  575.           GLUTmenuItem *item;
  576.           int num;
  577.  
  578.           item = __glutGetMenuItem(__glutMappedMenu,
  579.             event.xcrossing.window, &num);
  580.           if (item) {
  581.             __glutMenuItemEnterOrLeave(item, num, event.type);
  582.             break;
  583.           }
  584.         }
  585.         window = __glutGetWindow(event.xcrossing.window);
  586.         if (window) {
  587.           if (window->entry) {
  588.             if (event.type == EnterNotify) {
  589.  
  590.               /* With overlays established, X can report two
  591.                  enter events for both the overlay and normal
  592.                  plane window. Do not generate a second enter
  593.                  callback if we reported one without an
  594.                  intervening leave. */
  595.  
  596.               if (window->entryState != EnterNotify) {
  597.                 int num = window->num;
  598.                 Window xid = window->win;
  599.  
  600.                 window->entryState = EnterNotify;
  601.                 __glutSetWindow(window);
  602.                 window->entry(GLUT_ENTERED);
  603.  
  604.                 if (__glutMappedMenu) {
  605.  
  606.                   /* Do not generate any passive motion events
  607.                      when menus are in use. */
  608.  
  609.                 } else {
  610.  
  611.                   /* An EnterNotify event can result in a
  612.                      "compound" callback if a passive motion
  613.                      callback is also registered. In this case,
  614.                      be a little paranoid about the possibility
  615.                      the window could have been destroyed in the
  616.                      entry callback. */
  617.  
  618.                   window = __glutWindowList[num];
  619.                   if (window && window->passive && window->win == xid) {
  620.                     __glutSetWindow(window);
  621.                     window->passive(event.xcrossing.x, event.xcrossing.y);
  622.                   }
  623.                 }
  624.               }
  625.             } else {
  626.               if (window->entryState != LeaveNotify) {
  627.  
  628.                 /* When an overlay is established for a window
  629.                    already mapped and with the pointer in it,
  630.                    the X server will generate a leave/enter
  631.                    event pair as the pointer leaves (without
  632.                    moving) from the normal plane X window to
  633.                    the newly mapped overlay  X window (or vice
  634.                    versa). This enter/leave pair should not be
  635.                    reported to the GLUT program since the pair
  636.                    is a consequence of creating (or destroying) 
  637.                    the overlay, not an actual leave from the
  638.                    GLUT window. */
  639.  
  640.                 if (XEventsQueued(__glutDisplay, QueuedAfterReading)) {
  641.                   XPeekEvent(__glutDisplay, &ahead);
  642.                   if (ahead.type == EnterNotify &&
  643.                     __glutGetWindow(ahead.xcrossing.window) == window) {
  644.                     XNextEvent(__glutDisplay, &event);
  645.                     break;
  646.                   }
  647.                 }
  648.                 window->entryState = LeaveNotify;
  649.                 __glutSetWindow(window);
  650.                 window->entry(GLUT_LEFT);
  651.               }
  652.             }
  653.           } else if (window->passive) {
  654.             __glutSetWindow(window);
  655.             window->passive(event.xcrossing.x, event.xcrossing.y);
  656.           }
  657.         }
  658.         break;
  659.       case UnmapNotify:
  660.         /* MapNotify events are not needed to maintain
  661.            visibility state since VisibilityNotify events will
  662.            be delivered when a window becomes visible from
  663.            mapping.  However, VisibilityNotify events are not
  664.            delivered when a window is unmapped (for the window
  665.            or its children). */
  666.         window = __glutGetWindow(event.xunmap.window);
  667.         if (window) {
  668.           if (window->win != event.xconfigure.window) {
  669.             /* Ignore UnmapNotify sent to the overlay planes.
  670.                GLUT could get here because overlays select for
  671.                StructureNotify events to receive DestroyNotify. 
  672.              */
  673.             break;
  674.           }
  675.           markWindowHidden(window);
  676.         }
  677.         break;
  678.       case VisibilityNotify:
  679.         window = __glutGetWindow(event.xvisibility.window);
  680.         if (window) {
  681.           /* VisibilityUnobscured+1 = GLUT_FULLY_RETAINED,
  682.              VisibilityPartiallyObscured+1 =
  683.              GLUT_PARTIALLY_RETAINED, VisibilityFullyObscured+1 
  684.              =  GLUT_FULLY_COVERED. */
  685.           int visState = event.xvisibility.state + 1;
  686.  
  687.           if (visState != window->visState) {
  688.             if (window->windowStatus) {
  689.               window->visState = visState;
  690.               __glutSetWindow(window);
  691.               window->windowStatus(visState);
  692.             }
  693.           }
  694.         }
  695.         break;
  696.       case ClientMessage:
  697.         if (event.xclient.data.l[0] == __glutWMDeleteWindow)
  698.           exit(0);
  699.         break;
  700.       case DestroyNotify:
  701.         purgeStaleWindow(event.xdestroywindow.window);
  702.         break;
  703.       case CirculateNotify:
  704.       case CreateNotify:
  705.       case GravityNotify:
  706.       case ReparentNotify:
  707.         /* Uninteresting to GLUT (but possible for GLUT to
  708.            receive). */
  709.         break;
  710.       default:
  711.         /* Pass events not directly handled by the GLUT main
  712.            event loop to any event parsers that have been
  713.            registered.  In this way, X Input extension events
  714.            are passed to the correct handler without forcing
  715.            all GLUT programs to support X Input event handling. 
  716.          */
  717.         parser = eventParserList;
  718.         while (parser) {
  719.           if (parser->func(&event))
  720.             break;
  721.           parser = parser->next;
  722.         }
  723.         break;
  724.       }
  725.     }
  726. #endif /* WIN32 */
  727.     if (__glutTimerList) {
  728.       handleTimeouts();
  729.     }
  730.   }
  731.   while (XPending(__glutDisplay));
  732. }
  733.  
  734. static void
  735. waitForSomething(void)
  736. {
  737. #ifdef __vms
  738.   static struct timeval zerotime =
  739.   {0};
  740.   unsigned int timer_efn;
  741. #define timer_id 'glut' /* random :-) number */
  742.   unsigned int wait_mask;
  743. #else
  744.   static struct timeval zerotime =
  745.   {0, 0};
  746.   fd_set fds;
  747. #endif
  748.   struct timeval now, timeout, waittime;
  749.   int rc;
  750.  
  751.   /* Flush X protocol since XPending does not do this
  752.      implicitly. */
  753.   XFlush(__glutDisplay);
  754.   if (XPending(__glutDisplay)) {
  755.     /* It is possible (but quite rare) that XFlush may have
  756.        needed to wait for a writable X connection file
  757.        descriptor, and in the process, may have had to read off
  758.        X protocol from the file descriptor. If XPending is true,
  759.        this case occured and we should avoid waiting in select
  760.        since X protocol buffered within Xlib is due to be
  761.        processed and potentially no more X protocol is on the
  762.        file descriptor, so we would risk waiting improperly in
  763.        select. */
  764.     goto immediatelyHandleXinput;
  765.   }
  766. #ifdef __vms
  767.   timeout = __glutTimerList->timeout;
  768.   GETTIMEOFDAY(&now);
  769.   wait_mask = 1 << (__glutConnectionFD & 31);
  770.   if (IS_AFTER(now, timeout)) {
  771.     /* We need an event flag for the timer. */
  772.     /* XXX The `right' way to do this is to use LIB$GET_EF, but
  773.        since it needs to be in the same cluster as the EFN for
  774.        the display, we will have hack it. */
  775.     timer_efn = __glutConnectionFD - 1;
  776.     if ((timer_efn / 32) != (__glutConnectionFD / 32)) {
  777.       timer_efn = __glutConnectionFD + 1;
  778.     }
  779.     rc = SYS$CLREF(timer_efn);
  780.     rc = SYS$SETIMR(timer_efn, &timeout, NULL, timer_id, 0);
  781.     wait_mask |= 1 << (timer_efn & 31);
  782.   } else {
  783.     timer_efn = 0;
  784.   }
  785.   rc = SYS$WFLOR(__glutConnectionFD, wait_mask);
  786.   if (timer_efn != 0 && SYS$CLREF(timer_efn) == SS$_WASCLR) {
  787.     rc = SYS$CANTIM(timer_id, PSL$C_USER);
  788.   }
  789.   /* XXX There does not seem to be checking of "rc" in the code
  790.      above.  Can any of the SYS$ routines above fail? */
  791. #else /* not vms */
  792. #if !defined(WIN32)
  793.   FD_ZERO(&fds);
  794.   FD_SET(__glutConnectionFD, &fds);
  795. #endif
  796.   timeout = __glutTimerList->timeout;
  797.   GETTIMEOFDAY(&now);
  798.   if (IS_AFTER(now, timeout)) {
  799.     TIMEDELTA(waittime, timeout, now);
  800.   } else {
  801.     waittime = zerotime;
  802.   }
  803. #if !defined(WIN32)
  804.   rc = select(__glutConnectionFD + 1, &fds,
  805.     NULL, NULL, &waittime);
  806.   if (rc < 0 && errno != EINTR)
  807.     __glutFatalError("select error.");
  808. #else
  809.   /* set up a timer to fire in at least a millisecond, then wait for
  810.      the message.  This should act like a select. */
  811. //    SetTimer(NULL, 2, waittime.tv_usec, NULL);
  812. //    WaitMessage();
  813. //    KillTimer(NULL, 2);
  814.  
  815.   /* actually, a sleep seems to do the trick -- do we even need this? */
  816.   Sleep(0);
  817. #endif
  818. #endif /* not vms */
  819.   /* Without considering the cause of select unblocking, check
  820.      for pending X events and handle any timeouts (by calling
  821.      processEventsAndTimeouts).  We always look for X events
  822.      even if select returned with 0 (indicating a timeout);
  823.      otherwise we risk starving X event processing by continous
  824.      timeouts. */
  825.   if (XPending(__glutDisplay)) {
  826.   immediatelyHandleXinput:
  827.     processEventsAndTimeouts();
  828.   } else {
  829.     if (__glutTimerList)
  830.       handleTimeouts();
  831.   }
  832. }
  833.  
  834. static void
  835. idleWait(void)
  836. {
  837.   if (XPending(__glutDisplay)) {
  838.     processEventsAndTimeouts();
  839.   } else {
  840.     if (__glutTimerList)
  841.       handleTimeouts();
  842.   }
  843.   /* Make sure idle func still exists! */
  844.   if (__glutIdleFunc)
  845.     __glutIdleFunc();
  846. }
  847.  
  848. static GLUTwindow **beforeEnd;
  849.  
  850. static GLUTwindow *
  851. processWindowWorkList(GLUTwindow * window)
  852. {
  853.   int workMask;
  854.  
  855.   if (window->prevWorkWin)
  856.     window->prevWorkWin = processWindowWorkList(window->prevWorkWin);
  857.   else
  858.     beforeEnd = &window->prevWorkWin;
  859.  
  860.   /* Capture work mask for work that needs to be done to this
  861.      window, then clear the window's work mask (excepting the
  862.      dummy work bit, see below).  Then, process the captured
  863.      work mask.  This allows callbacks in the processing the
  864.      captured work mask to set the window's work mask for
  865.      subsequent processing. */
  866.  
  867.   workMask = window->workMask;
  868.   assert((workMask & GLUT_DUMMY_WORK) == 0);
  869.  
  870.   /* Set the dummy work bit, clearing all other bits, to
  871.      indicate that the window is currently on the window work
  872.      list _and_ that the window's work mask is currently being
  873.      processed.  This convinces __glutPutOnWorkList that this
  874.      window is on the work list still. */
  875.   window->workMask = GLUT_DUMMY_WORK;
  876.  
  877.   /* Optimization: most of the time, the work to do is a
  878.      redisplay and not these other types of work.  Check for
  879.      the following cases as a group to before checking each one
  880.      individually one by one. This saves about 25 MIPS
  881.      instructions in the common redisplay only case. */
  882.   if (workMask & (GLUT_EVENT_MASK_WORK | GLUT_DEVICE_MASK_WORK |
  883.       GLUT_CONFIGURE_WORK | GLUT_COLORMAP_WORK | GLUT_MAP_WORK)) {
  884. #if !defined(WIN32)
  885.     /* Be sure to set event mask BEFORE map window is done. */
  886.     if (workMask & GLUT_EVENT_MASK_WORK) {
  887.       long eventMask;
  888.  
  889.       /* Make sure children are not propogating events this
  890.          window is selecting for.  Be sure to do this before
  891.          enabling events on the children's parent. */
  892.       if (window->children) {
  893.         GLUTwindow *child = window->children;
  894.         unsigned long attribMask = CWDontPropagate;
  895.         XSetWindowAttributes wa;
  896.  
  897.         wa.do_not_propagate_mask = window->eventMask & GLUT_DONT_PROPAGATE_FILTER_MASK;
  898.         if (window->eventMask & GLUT_HACK_STOP_PROPAGATE_MASK) {
  899.           wa.event_mask = child->eventMask | (window->eventMask & GLUT_HACK_STOP_PROPAGATE_MASK);
  900.           attribMask |= CWEventMask;
  901.         }
  902.         do {
  903.           XChangeWindowAttributes(__glutDisplay, child->win,
  904.             attribMask, &wa);
  905.           child = child->siblings;
  906.         } while (child);
  907.       }
  908.       eventMask = window->eventMask;
  909.       if (window->parent && window->parent->eventMask & GLUT_HACK_STOP_PROPAGATE_MASK)
  910.         eventMask |= (window->parent->eventMask & GLUT_HACK_STOP_PROPAGATE_MASK);
  911.       XSelectInput(__glutDisplay, window->win, eventMask);
  912.       if (window->overlay)
  913.         XSelectInput(__glutDisplay, window->overlay->win,
  914.           window->eventMask & GLUT_OVERLAY_EVENT_FILTER_MASK);
  915.     }
  916. #endif /* !WIN32 */
  917.     /* Be sure to set device mask BEFORE map window is done. */
  918.     if (workMask & GLUT_DEVICE_MASK_WORK) {
  919.       __glutUpdateInputDeviceMaskFunc(window);
  920.     }
  921.     /* Be sure to configure window BEFORE map window is done. */
  922.     if (workMask & GLUT_CONFIGURE_WORK) {
  923. #if defined(WIN32)
  924.       RECT changes;
  925.       POINT point;
  926.       int stack_mode;
  927.  
  928.       GetClientRect(window->win, &changes);
  929.       
  930.       // if this window is a toplevel window, translate the 0,0 client
  931.       // coordinate into a screen coordinate for proper placement
  932.       if (!window->parent) {
  933.         point.x = 0;
  934.         point.y = 0;
  935.         ClientToScreen(window->win, &point);
  936.         changes.left = point.x;
  937.         changes.top = point.y;
  938.       }
  939.       if (window->desiredConfMask & (CWX | CWY)) {
  940.         changes.left = window->desiredX;
  941.         changes.top = window->desiredY;
  942.       }
  943.       if (window->desiredConfMask & (CWWidth | CWHeight)) {
  944.         changes.right = changes.left + window->desiredWidth;
  945.         changes.bottom = changes.top + window->desiredHeight;
  946.     //         if (window->overlay)
  947.     //           XResizeWindow(__glutDisplay, window->overlay->win,
  948.     //             window->desiredWidth, window->desiredHeight);
  949.       }
  950.       if (window->desiredConfMask & CWStackMode) {
  951.         stack_mode = window->desiredStack;
  952.         /* Do not let glutPushWindow push window beneath the
  953.            underlay. */
  954.         if (window->parent && window->parent->overlay && window->desiredStack == Below) {
  955.           stack_mode = Above;
  956.         }
  957.       }
  958.       
  959.       // adjust the window rectangle because Win32 thinks that the x, y,
  960.       // width & height are the WHOLE window (including decorations),
  961.       // whereas GLUT treats the x, y, width & height as only the CLIENT
  962.       // area of the window.  ONLY DO THIS IF TOPLEVEL WINDOW.
  963.       if (!window->parent) {
  964.         AdjustWindowRect(&changes,
  965.           WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
  966.           FALSE);
  967. #if 0
  968.         // readjust if the x and y are offscreen
  969.         if (changes.left < 0) {
  970.           changes.right = changes.right - changes.left;
  971.           changes.left = 0;
  972.         }
  973.         if (changes.top < 0) {
  974.           changes.bottom = changes.bottom - changes.top;
  975.           changes.top = 0;
  976.         }
  977. #endif
  978.       }
  979.       // do the repositioning and moving
  980.       SetWindowPos(window->win, 0, changes.left, changes.top,
  981.         changes.right - changes.left, changes.bottom - changes.top,
  982.         SWP_NOZORDER);
  983.  
  984.       // do the Z ordering.
  985.       SetWindowPos(window->win, stack_mode == Above ? HWND_TOP : HWND_NOTOPMOST,
  986.         0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOREPOSITION);
  987.  
  988.       // zero out the mask
  989.       window->desiredConfMask = 0;
  990.       
  991.       // this hack causes the window to go back to the right position
  992.       // when it is taken out of fullscreen mode.
  993.       if (workMask & GLUT_FULL_SCREEN_WORK) {
  994.         window->desiredConfMask |= CWX | CWY;
  995.         window->desiredX = point.x;
  996.         window->desiredY = point.y;
  997.       }
  998. #else /* !WIN32 */
  999.       XWindowChanges changes;
  1000.  
  1001.       changes.x = window->desiredX;
  1002.       changes.y = window->desiredY;
  1003.       if (window->desiredConfMask & (CWWidth | CWHeight)) {
  1004.         changes.width = window->desiredWidth;
  1005.         changes.height = window->desiredHeight;
  1006.         if (window->overlay)
  1007.           XResizeWindow(__glutDisplay, window->overlay->win,
  1008.             window->desiredWidth, window->desiredHeight);
  1009.         if (__glutMotifHints != None) {
  1010.           if (workMask & GLUT_FULL_SCREEN_WORK) {
  1011.             MotifWmHints hints;
  1012.  
  1013.             hints.flags = MWM_HINTS_DECORATIONS;
  1014.             hints.decorations = 0;  /* Absolutely no
  1015.                                        decorations. */
  1016.             XChangeProperty(__glutDisplay, window->win,
  1017.               __glutMotifHints, __glutMotifHints, 32,
  1018.               PropModeReplace, (unsigned char *) &hints, 4);
  1019.             if (workMask & GLUT_MAP_WORK) {
  1020.               /* Handle case where glutFullScreen is called
  1021.                  before the first time that the window is
  1022.                  mapped. Some window managers will randomly or
  1023.                  interactively position the window the first
  1024.                  time it is mapped if the window's
  1025.                  WM_NORMAL_HINTS property does not request an
  1026.                  explicit position. We don't want any such
  1027.                  window manager interaction when going
  1028.                  fullscreen.  Overwrite the WM_NORMAL_HINTS
  1029.                  property installed by glutCreateWindow's
  1030.                  XSetWMProperties property with one explicitly
  1031.                  requesting a fullscreen window. */
  1032.               XSizeHints hints;
  1033.  
  1034.               hints.flags = USPosition | USSize;
  1035.               hints.x = 0;
  1036.               hints.y = 0;
  1037.               hints.width = window->desiredWidth;
  1038.               hints.height = window->desiredHeight;
  1039.               XSetWMNormalHints(__glutDisplay, window->win, &hints);
  1040.             }
  1041.           } else {
  1042.             XDeleteProperty(__glutDisplay, window->win, __glutMotifHints);
  1043.           }
  1044.         }
  1045.       }
  1046.       if (window->desiredConfMask & CWStackMode) {
  1047.         changes.stack_mode = window->desiredStack;
  1048.         /* Do not let glutPushWindow push window beneath the
  1049.            underlay. */
  1050.         if (window->parent && window->parent->overlay && window->desiredStack == Below) {
  1051.           changes.stack_mode = Above;
  1052.           changes.sibling = window->parent->overlay->win;
  1053.           window->desiredConfMask |= CWSibling;
  1054.         }
  1055.       }
  1056.       XConfigureWindow(__glutDisplay, window->win,
  1057.         window->desiredConfMask, &changes);
  1058.       window->desiredConfMask = 0;
  1059. #endif
  1060.     }
  1061.     /* Be sure to establish the colormaps BEFORE map window is
  1062.        done. */
  1063.     if (workMask & GLUT_COLORMAP_WORK) {
  1064.       __glutEstablishColormapsProperty(window);
  1065.     }
  1066.     if (workMask & GLUT_MAP_WORK) {
  1067.       switch (window->desiredMapState) {
  1068.       case WithdrawnState:
  1069.         if (window->parent) {
  1070.           XUnmapWindow(__glutDisplay, window->win);
  1071.         } else {
  1072.           XWithdrawWindow(__glutDisplay, window->win,
  1073.             __glutScreen);
  1074.         }
  1075.         window->shownState = 0;
  1076.         break;
  1077.       case NormalState:
  1078.         XMapWindow(__glutDisplay, window->win);
  1079.         window->shownState = 1;
  1080.         break;
  1081.       case IconicState:
  1082.         XIconifyWindow(__glutDisplay, window->win, __glutScreen);
  1083.         window->shownState = 0;
  1084.         break;
  1085.       }
  1086.     }
  1087.   }
  1088.   if (workMask & (GLUT_REDISPLAY_WORK | GLUT_OVERLAY_REDISPLAY_WORK | GLUT_REPAIR_WORK | GLUT_OVERLAY_REPAIR_WORK)) {
  1089.     if (window->forceReshape) {
  1090.       /* Guarantee that before a display callback is generated
  1091.          for a window, a reshape callback must be generated. */
  1092.       __glutSetWindow(window);
  1093.       window->reshape(window->width, window->height);
  1094.       window->forceReshape = False;
  1095.  
  1096.       /* Setting the redisplay bit on the first reshape is
  1097.          necessary to make the "Mesa glXSwapBuffers to repair
  1098.          damage" hack operate correctly.  Without indicating a
  1099.          redisplay is necessary, there's not an initial back
  1100.          buffer render from which to blit from when damage
  1101.          happens to the window. */
  1102.       workMask |= GLUT_REDISPLAY_WORK;
  1103.     }
  1104.     /* The code below is more involved than otherwise necessary
  1105.        because it is paranoid about the overlay or entire window
  1106.        being removed or destroyed in the course of the callbacks.
  1107.        Notice how the global __glutWindowDamaged is used to record
  1108.        the layers' damage status.  See the code in glutLayerGet for
  1109.        how __glutWindowDamaged is used. The  point is to not have to
  1110.        update the "damaged" field after  the callback since the
  1111.        window (or overlay) may be destroyed (or removed) when the
  1112.        callback returns. */
  1113.  
  1114.     if (window->overlay && window->overlay->display) {
  1115.       int num = window->num;
  1116.       Window xid = window->overlay ? window->overlay->win : None;
  1117.  
  1118.       /* If an overlay display callback is registered, we
  1119.          differentiate between a redisplay needed for the
  1120.          overlay and/or normal plane.  If there is no overlay
  1121.          display callback registered, we simply use the
  1122.          standard display callback. */
  1123.  
  1124.       if (workMask & (GLUT_REDISPLAY_WORK | GLUT_REPAIR_WORK)) {
  1125.         if (__glutMesaSwapHackSupport) {
  1126.           if (window->usedSwapBuffers) {
  1127.             if ((workMask & (GLUT_REPAIR_WORK | GLUT_REDISPLAY_WORK)) == GLUT_REPAIR_WORK) {
  1128.               glXSwapBuffers(__glutDisplay, window->win);
  1129.               goto skippedDisplayCallback1;
  1130.             }
  1131.           }
  1132.         }
  1133.         /* Render to normal plane. */
  1134.         window->renderWin = window->win;
  1135.         window->renderCtx = window->ctx;
  1136.         __glutWindowDamaged = (workMask & GLUT_REPAIR_WORK);
  1137.         __glutSetWindow(window);
  1138.         window->usedSwapBuffers = 0;
  1139.         window->display();
  1140.         __glutWindowDamaged = 0;
  1141.  
  1142.       skippedDisplayCallback1:;
  1143.       }
  1144.       if (workMask & (GLUT_OVERLAY_REDISPLAY_WORK | GLUT_OVERLAY_REPAIR_WORK)) {
  1145.         window = __glutWindowList[num];
  1146.         if (window && window->overlay &&
  1147.           window->overlay->win == xid && window->overlay->display) {
  1148.  
  1149.           /* Render to overlay. */
  1150.           window->renderWin = window->overlay->win;
  1151.           window->renderCtx = window->overlay->ctx;
  1152.           __glutWindowDamaged = (workMask & GLUT_OVERLAY_REPAIR_WORK);
  1153.           __glutSetWindow(window);
  1154.           window->overlay->display();
  1155.           __glutWindowDamaged = 0;
  1156.         } else {
  1157.           /* Overlay may have since been destroyed or the
  1158.              overlay callback may have been disabled during
  1159.              normal display callback. */
  1160.         }
  1161.       }
  1162.     } else {
  1163.       if (__glutMesaSwapHackSupport) {
  1164.         if (!window->overlay && window->usedSwapBuffers) {
  1165.           if ((workMask & (GLUT_REPAIR_WORK | GLUT_REDISPLAY_WORK)) == GLUT_REPAIR_WORK) {
  1166.             glXSwapBuffers(__glutDisplay, window->win);
  1167.             goto skippedDisplayCallback2;
  1168.           }
  1169.         }
  1170.       }
  1171.       /* Render to normal plane (and possibly overlay). */
  1172.       __glutWindowDamaged = (workMask & (GLUT_OVERLAY_REPAIR_WORK | GLUT_REPAIR_WORK));
  1173.       __glutSetWindow(window);
  1174.       window->usedSwapBuffers = 0;
  1175.       window->display();
  1176.       __glutWindowDamaged = 0;
  1177.  
  1178.     skippedDisplayCallback2:;
  1179.     }
  1180.   }
  1181.   /* Combine workMask with window->workMask to determine what
  1182.      finish and debug work there is. */
  1183.   workMask |= window->workMask;
  1184.  
  1185.   if (workMask & GLUT_FINISH_WORK) {
  1186.     /* Finish work makes sure a glFinish gets done to indirect
  1187.        rendering contexts.  Indirect contexts tend to have much 
  1188.        longer latency because lots of OpenGL extension requests 
  1189.        can queue up in the X protocol stream. __glutSetWindow
  1190.        is where the finish works gets queued for indirect
  1191.        contexts. */
  1192.     __glutSetWindow(window);
  1193.     glFinish();
  1194.   }
  1195.   if (workMask & GLUT_DEBUG_WORK) {
  1196.     __glutSetWindow(window);
  1197.     glutReportErrors();
  1198.   }
  1199.   /* Strip out dummy, finish, and debug work bits. */
  1200.   window->workMask &= ~(GLUT_DUMMY_WORK | GLUT_FINISH_WORK | GLUT_DEBUG_WORK);
  1201.   if (window->workMask) {
  1202.     /* Leave on work list. */
  1203.     return window;
  1204.   } else {
  1205.     /* Remove current window from work list. */
  1206.     return window->prevWorkWin;
  1207.   }
  1208. }
  1209.  
  1210. /* CENTRY */
  1211. void APIENTRY
  1212. glutMainLoop(void)
  1213. {
  1214. #if !defined(WIN32)
  1215.   if (!__glutDisplay)
  1216.     __glutFatalUsage("main loop entered with out proper initialization.");
  1217. #endif
  1218.   if (!__glutWindowListSize)
  1219.     __glutFatalUsage(
  1220.       "main loop entered with no windows created.");
  1221.   for (;;) {
  1222.     if (__glutWindowWorkList) {
  1223.       GLUTwindow *remainder, *work;
  1224.  
  1225.       work = __glutWindowWorkList;
  1226.       __glutWindowWorkList = NULL;
  1227.       if (work) {
  1228.         remainder = processWindowWorkList(work);
  1229.         if (remainder) {
  1230.           *beforeEnd = __glutWindowWorkList;
  1231.           __glutWindowWorkList = remainder;
  1232.         }
  1233.       }
  1234.     }
  1235.     if (__glutIdleFunc || __glutWindowWorkList) {
  1236.       idleWait();
  1237.     } else {
  1238.       if (__glutTimerList) {
  1239.         waitForSomething();
  1240.       } else {
  1241.         processEventsAndTimeouts();
  1242.       }
  1243.     }
  1244.   }
  1245. }
  1246. /* ENDCENTRY */
  1247.