glut_event.c
上传用户:xk288cn
上传日期:2007-05-28
资源大小:4876k
文件大小:47k
源码类别:

GIS编程

开发平台:

Visual C++

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