home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / mesa5.zip / mesa5src.zip / MesaDLL / glut_event.cpp < prev    next >
C/C++ Source or Header  |  2002-12-14  |  48KB  |  1,400 lines

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