Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

glut_event.c

Go to the documentation of this file.
00001 
00002 /* Copyright (c) Mark J. Kilgard, 1994, 1995, 1996, 1997, 1998. */
00003 
00004 /* This program is freely distributable without licensing fees
00005    and is provided without guarantee or warrantee expressed or
00006    implied. This program is -not- in the public domain. */
00007 
00008 #include <stdlib.h>
00009 #include <stdio.h>
00010 #include <errno.h>
00011 #include <assert.h>
00012 #include <string.h>  /* Some FD_ZERO macros use memset without
00013                         prototyping memset. */
00014 
00015 /* Much of the following #ifdef logic to include the proper
00016    prototypes for the select system call is based on logic
00017    from the X11R6.3 version of <X11/Xpoll.h>. */
00018 
00019 #if !defined(_WIN32)
00020 # ifdef __sgi
00021 #  include <bstring.h>    /* prototype for bzero used by FD_ZERO */
00022 # endif
00023 # if (defined(SVR4) || defined(CRAY) || defined(AIXV3)) && !defined(FD_SETSIZE)
00024 #  include <sys/select.h> /* select system call interface */
00025 #  ifdef luna
00026 #   include <sysent.h>
00027 #  endif
00028 # endif
00029   /* AIX 4.2 fubar-ed <sys/select.h>, so go to heroic measures to get it */
00030 # if defined(AIXV4) && !defined(NFDBITS)
00031 #  include <sys/select.h>
00032 # endif
00033 #endif /* !_WIN32 */
00034 
00035 #include <sys/types.h>
00036 
00037 #if !defined(_WIN32)
00038 # if defined(__vms) && ( __VMS_VER < 70000000 )
00039 #  include <sys/time.h>
00040 # else
00041 #  ifndef __vms
00042 #   include <sys/time.h>
00043 #  endif
00044 # endif
00045 # include <unistd.h>
00046 # include <X11/Xlib.h>
00047 # include <X11/keysym.h>
00048 #else
00049 # ifdef __CYGWIN32__
00050 #  include <sys/time.h>
00051 # else
00052 #  include <sys/timeb.h>
00053 # endif
00054 # ifdef __hpux
00055    /* XXX Bert Gijsbers <bert@mc.bio.uva.nl> reports that HP-UX
00056       needs different keysyms for the End, Insert, and Delete keys
00057       to work on an HP 715.  It would be better if HP generated
00058       standard keysyms for standard keys. */
00059 #  include <X11/HPkeysym.h>
00060 # endif
00061 #endif /* !_WIN32 */
00062 
00063 #if defined(__vms) && ( __VMS_VER < 70000000 )
00064 #include <ssdef.h>
00065 #include <psldef.h>
00066 extern int SYS$CLREF(int efn);
00067 extern int SYS$SETIMR(unsigned int efn, struct timeval *timeout, void *ast,
00068   unsigned int request_id, unsigned int flags);
00069 extern int SYS$WFLOR(unsigned int efn, unsigned int mask);
00070 extern int SYS$CANTIM(unsigned int request_id, unsigned int mode);
00071 #endif /* __vms, VMs 6.2 or earlier */
00072 
00073 #include "glutint.h"
00074 
00075 static GLUTtimer *freeTimerList = NULL;
00076 
00077 GLUTidleCB __glutIdleFunc = NULL;
00078 GLUTtimer *__glutTimerList = NULL;
00079 #ifdef SUPPORT_FORTRAN
00080 GLUTtimer *__glutNewTimer;
00081 #endif
00082 GLUTwindow *__glutWindowWorkList = NULL;
00083 GLUTmenu *__glutMappedMenu;
00084 GLUTmenu *__glutCurrentMenu = NULL;
00085 
00086 void (*__glutUpdateInputDeviceMaskFunc) (GLUTwindow *);
00087 #if !defined(_WIN32)
00088 void (*__glutMenuItemEnterOrLeave)(GLUTmenuItem * item, int num, int type) = NULL;
00089 void (*__glutFinishMenu)(Window win, int x, int y);
00090 void (*__glutPaintMenu)(GLUTmenu * menu);
00091 void (*__glutStartMenu)(GLUTmenu * menu, GLUTwindow * window, int x, int y, int x_win, int y_win);
00092 GLUTmenu * (*__glutGetMenuByNum)(int menunum);
00093 GLUTmenuItem * (*__glutGetMenuItem)(GLUTmenu * menu, Window win, int *which);
00094 GLUTmenu * (*__glutGetMenu)(Window win);
00095 #endif
00096 
00097 Atom __glutMotifHints = None;
00098 /* Modifier mask of ~0 implies not in core input callback. */
00099 unsigned int __glutModifierMask = (unsigned int) ~0;
00100 int __glutWindowDamaged = 0;
00101 
00102 void APIENTRY
00103 glutIdleFunc(GLUTidleCB idleFunc)
00104 {
00105   __glutIdleFunc = idleFunc;
00106 }
00107 
00108 void APIENTRY
00109 glutTimerFunc(unsigned int interval, GLUTtimerCB timerFunc, int value)
00110 {
00111   GLUTtimer *timer, *other;
00112   GLUTtimer **prevptr;
00113   struct timeval now;
00114 
00115   if (!timerFunc)
00116     return;
00117 
00118   if (freeTimerList) {
00119     timer = freeTimerList;
00120     freeTimerList = timer->next;
00121   } else {
00122     timer = (GLUTtimer *) malloc(sizeof(GLUTtimer));
00123     if (!timer)
00124       __glutFatalError("out of memory.");
00125   }
00126 
00127   timer->func = timerFunc;
00128 #if defined(__vms) && ( __VMS_VER < 70000000 )
00129   /* VMS time is expressed in units of 100 ns */
00130   timer->timeout.val = interval * TICKS_PER_MILLISECOND;
00131 #else
00132   timer->timeout.tv_sec = (int) interval / 1000;
00133   timer->timeout.tv_usec = (int) (interval % 1000) * 1000;
00134 #endif
00135   timer->value = value;
00136   timer->next = NULL;
00137   GETTIMEOFDAY(&now);
00138   ADD_TIME(timer->timeout, timer->timeout, now);
00139   prevptr = &__glutTimerList;
00140   other = *prevptr;
00141   while (other && IS_AFTER(other->timeout, timer->timeout)) {
00142     prevptr = &other->next;
00143     other = *prevptr;
00144   }
00145   timer->next = other;
00146 #ifdef SUPPORT_FORTRAN
00147   __glutNewTimer = timer;  /* for Fortran binding! */
00148 #endif
00149   *prevptr = timer;
00150 }
00151 
00152 void
00153 handleTimeouts(void)
00154 {
00155   struct timeval now;
00156   GLUTtimer *timer;
00157 
00158   /* Assumption is that __glutTimerList is already determined
00159      to be non-NULL. */
00160   GETTIMEOFDAY(&now);
00161   while (IS_AT_OR_AFTER(__glutTimerList->timeout, now)) {
00162     timer = __glutTimerList;
00163     timer->func(timer->value);
00164     __glutTimerList = timer->next;
00165     timer->next = freeTimerList;
00166     freeTimerList = timer;
00167     if (!__glutTimerList)
00168       break;
00169   }
00170 }
00171 
00172 void
00173 __glutPutOnWorkList(GLUTwindow * window, int workMask)
00174 {
00175   if (window->workMask) {
00176     /* Already on list; just OR in new workMask. */
00177     window->workMask |= workMask;
00178   } else {
00179     /* Update work mask and add to window work list. */
00180     window->workMask = workMask;
00181     /* Assert that if the window does not have a
00182        workMask already, the window should definitely
00183        not be the head of the work list. */
00184     assert(window != __glutWindowWorkList);
00185     window->prevWorkWin = __glutWindowWorkList;
00186     __glutWindowWorkList = window;
00187   }
00188 }
00189 
00190 void
00191 __glutPostRedisplay(GLUTwindow * window, int layerMask)
00192 {
00193   int shown = (layerMask & (GLUT_REDISPLAY_WORK | GLUT_REPAIR_WORK)) ?
00194     window->shownState : window->overlay->shownState;
00195 
00196   /* Post a redisplay if the window is visible (or the
00197      visibility of the window is unknown, ie. window->visState
00198      == -1) _and_ the layer is known to be shown. */
00199   if (window->visState != GLUT_HIDDEN
00200     && window->visState != GLUT_FULLY_COVERED && shown) {
00201     __glutPutOnWorkList(window, layerMask);
00202   }
00203 }
00204 
00205 /* CENTRY */
00206 void APIENTRY
00207 glutPostRedisplay(void)
00208 {
00209   __glutPostRedisplay(__glutCurrentWindow, GLUT_REDISPLAY_WORK);
00210 }
00211 
00212 /* The advantage of this routine is that it saves the cost of a
00213    glutSetWindow call (entailing an expensive OpenGL context switch),
00214    particularly useful when multiple windows need redisplays posted at
00215    the same times.  See also glutPostWindowOverlayRedisplay. */
00216 void APIENTRY
00217 glutPostWindowRedisplay(int win)
00218 {
00219   __glutPostRedisplay(__glutWindowList[win - 1], GLUT_REDISPLAY_WORK);
00220 }
00221 
00222 /* ENDCENTRY */
00223 static GLUTeventParser *eventParserList = NULL;
00224 
00225 /* __glutRegisterEventParser allows another module to register
00226    to intercept X events types not otherwise acted on by the
00227    GLUT processEventsAndTimeouts routine.  The X Input
00228    extension support code uses an event parser for handling X
00229    Input extension events.  */
00230 
00231 void
00232 __glutRegisterEventParser(GLUTeventParser * parser)
00233 {
00234   parser->next = eventParserList;
00235   eventParserList = parser;
00236 }
00237 
00238 static void
00239 markWindowHidden(GLUTwindow * window)
00240 {
00241   if (GLUT_HIDDEN != window->visState) {
00242     GLUTwindow *child;
00243 
00244     if (window->windowStatus) {
00245       window->visState = GLUT_HIDDEN;
00246       __glutSetWindow(window);
00247       window->windowStatus(GLUT_HIDDEN);
00248     }
00249     /* An unmap is only reported on a single window; its
00250        descendents need to know they are no longer visible. */
00251     child = window->children;
00252     while (child) {
00253       markWindowHidden(child);
00254       child = child->siblings;
00255     }
00256   }
00257 }
00258 
00259 #if !defined(_WIN32)
00260 
00261 static void
00262 purgeStaleWindow(Window win)
00263 {
00264   GLUTstale **pEntry = &__glutStaleWindowList;
00265   GLUTstale *entry = __glutStaleWindowList;
00266 
00267   /* Tranverse singly-linked stale window list look for the
00268      window ID. */
00269   while (entry) {
00270     if (entry->win == win) {
00271       /* Found it; delete it. */
00272       *pEntry = entry->next;
00273       free(entry);
00274       return;
00275     } else {
00276       pEntry = &entry->next;
00277       entry = *pEntry;
00278     }
00279   }
00280 }
00281 
00282 /* Unlike XNextEvent, if a signal arrives,
00283    interruptibleXNextEvent will return (with a zero return
00284    value).  This helps GLUT drop out of XNextEvent if a signal
00285    is delivered.  The intent is so that a GLUT program can call 
00286    glutIdleFunc in a signal handler to register an idle func
00287    and then immediately get dropped into the idle func (after
00288    returning from the signal handler).  The idea is to make
00289    GLUT's main loop reliably interruptible by signals. */
00290 static int
00291 interruptibleXNextEvent(Display * dpy, XEvent * event)
00292 {
00293   fd_set fds;
00294   int rc;
00295 
00296   /* Flush X protocol since XPending does not do this
00297      implicitly. */
00298   XFlush(__glutDisplay);
00299   for (;;) {
00300     if (XPending(__glutDisplay)) {
00301       XNextEvent(dpy, event);
00302       return 1;
00303     }
00304     FD_ZERO(&fds);
00305     FD_SET(__glutConnectionFD, &fds);
00306     rc = select(__glutConnectionFD + 1, &fds,
00307       NULL, NULL, NULL);
00308     if (rc < 0) {
00309       if (errno == EINTR) {
00310         return 0;
00311       } else {
00312         __glutFatalError("select error.");
00313       }
00314     }
00315   }
00316 }
00317 
00318 #endif
00319 
00320 static void
00321 processEventsAndTimeouts(void)
00322 {
00323   do {
00324 #if defined(_WIN32)
00325     MSG event;
00326 
00327     if(!GetMessage(&event, NULL, 0, 0))   /* bail if no more messages */
00328       exit(0);
00329     TranslateMessage(&event);    /* translate virtual-key messages */
00330     DispatchMessage(&event);     /* call the window proc */
00331     /* see win32_event.c for event (message) processing procedures */
00332 #else
00333     static int mappedMenuButton;
00334     GLUTeventParser *parser;
00335     XEvent event, ahead;
00336     GLUTwindow *window;
00337     GLUTkeyboardCB keyboard;
00338     GLUTspecialCB special;
00339     int gotEvent, x, y, width, height;
00340     static int is_first_configure_notify_event = 1; /* FIXME */
00341     static int x_first = 0, y_first = 0; /* FIXME */
00342 
00343     gotEvent = interruptibleXNextEvent(__glutDisplay, &event);
00344     if (gotEvent) {
00345       switch (event.type) {
00346       case MappingNotify:
00347         XRefreshKeyboardMapping((XMappingEvent *) & event);
00348         break;
00349       case ConfigureNotify:
00350    /* CAVEAT
00351       x and y values are wrong (more precisely, they are set to
00352       x_first and y_first) when width and height values are changing
00353       because of a window reshaping event! This occurs also when window
00354       is created. I wrote a partial workaround for this problem below.
00355     */
00356         window = __glutGetWindow(event.xconfigure.window);
00357         if (window) {
00358           if (window->win != event.xconfigure.window) {
00359             /* Ignore ConfigureNotify sent to the overlay
00360                planes. GLUT could get here because overlays
00361                select for StructureNotify events to receive
00362                DestroyNotify. */
00363             break;
00364           }
00365      x = event.xconfigure.x;
00366      y = event.xconfigure.y;
00367      if (is_first_configure_notify_event) { /* FIXME */
00368        is_first_configure_notify_event = 0;
00369        x_first = x;
00370        y_first = y;
00371        x += window->x;
00372        y += window->y;
00373      } else if (x == x_first && y == y_first) { /* FIXME */
00374        x = window->x;
00375        y = window->y;
00376      }
00377      if (x != window->x || y != window->y) {
00378        if (window->overlay) {
00379          XMoveWindow(__glutDisplay, window->overlay->win, x, y);
00380        }
00381        window->x = x;
00382        window->y = y;
00383        __glutSetWindow(window);
00384        glXWaitX();
00385        if (window->move) {
00386          window->move(x, y);
00387        }
00388        __glutWacomSetOffset(x, y);
00389        __glutPostRedisplay(window, GLUT_REPAIR_WORK); /* FIXME */
00390      }
00391           width = event.xconfigure.width;
00392           height = event.xconfigure.height;
00393           if (width != window->width || height != window->height) {
00394             if (window->overlay) {
00395               XResizeWindow(__glutDisplay, window->overlay->win, width, height);
00396             }
00397             window->width = width;
00398             window->height = height;
00399             __glutSetWindow(window);
00400             /* Do not execute OpenGL out of sequence with
00401                respect to the XResizeWindow request! */
00402             glXWaitX();
00403             window->reshape(width, height);
00404             window->forceReshape = False;
00405             /* A reshape should be considered like posting a
00406                repair; this is necessary for the "Mesa
00407                glXSwapBuffers to repair damage" hack to operate
00408                correctly.  Without it, there's not an initial
00409                back buffer render from which to blit from when
00410                damage happens to the window. */
00411             __glutPostRedisplay(window, GLUT_REPAIR_WORK);
00412           }
00413         }
00414         break;
00415       case Expose:
00416         /* compress expose events */
00417         while (XEventsQueued(__glutDisplay, QueuedAfterReading)
00418           > 0) {
00419           XPeekEvent(__glutDisplay, &ahead);
00420           if (ahead.type != Expose ||
00421             ahead.xexpose.window != event.xexpose.window) {
00422             break;
00423           }
00424           XNextEvent(__glutDisplay, &event);
00425         }
00426         if (event.xexpose.count == 0) {
00427           GLUTmenu *menu;
00428 
00429           if (__glutMappedMenu &&
00430             (menu = __glutGetMenu(event.xexpose.window))) {
00431             __glutPaintMenu(menu);
00432           } else {
00433             window = __glutGetWindow(event.xexpose.window);
00434             if (window) {
00435               if (window->win == event.xexpose.window) {
00436                 __glutPostRedisplay(window, GLUT_REPAIR_WORK);
00437               } else if (window->overlay && window->overlay->win == event.xexpose.window) {
00438                 __glutPostRedisplay(window, GLUT_OVERLAY_REPAIR_WORK);
00439               }
00440             }
00441           }
00442         } else {
00443           /* there are more exposes to read; wait to redisplay */
00444         }
00445         break;
00446       case ButtonPress:
00447       case ButtonRelease:
00448         if (__glutMappedMenu && event.type == ButtonRelease
00449           && mappedMenuButton == event.xbutton.button) {
00450           /* Menu is currently popped up and its button is
00451              released. */
00452           __glutFinishMenu(event.xbutton.window, event.xbutton.x, event.xbutton.y);
00453         } else {
00454           window = __glutGetWindow(event.xbutton.window);
00455           if (window) {
00456             GLUTmenu *menu;
00457        int menuNum;
00458 
00459             menuNum = window->menu[event.xbutton.button - 1];
00460             /* Make sure that __glutGetMenuByNum is only called if there
00461           really is a menu present. */
00462             if ((menuNum > 0) && (menu = __glutGetMenuByNum(menuNum))) {
00463               if (event.type == ButtonPress && !__glutMappedMenu) {
00464                 __glutStartMenu(menu, window,
00465                   event.xbutton.x_root, event.xbutton.y_root,
00466                   event.xbutton.x, event.xbutton.y);
00467                 mappedMenuButton = event.xbutton.button;
00468               } else {
00469                 /* Ignore a release of a button with a menu
00470                    attatched to it when no menu is popped up,
00471                    or ignore a press when another menu is
00472                    already popped up. */
00473               }
00474             } else if (window->mouse) {
00475               __glutSetWindow(window);
00476               __glutModifierMask = event.xbutton.state;
00477               window->mouse(event.xbutton.button - 1,
00478                 event.type == ButtonRelease ?
00479                 GLUT_UP : GLUT_DOWN,
00480                 event.xbutton.x, event.xbutton.y);
00481               __glutModifierMask = ~0;
00482             } else {
00483               /* Stray mouse events.  Ignore. */
00484             }
00485           } else {
00486             /* Window might have been destroyed and all the 
00487                events for the window may not yet be received. */
00488           }
00489         }
00490         break;
00491       case MotionNotify:
00492         if (!__glutMappedMenu) {
00493           window = __glutGetWindow(event.xmotion.window);
00494           if (window) {
00495             /* If motion function registered _and_ buttons held 
00496                * down, call motion function...  */
00497             if (window->motion && event.xmotion.state &
00498               (Button1Mask | Button2Mask | Button3Mask)) {
00499               __glutSetWindow(window);
00500               window->motion(event.xmotion.x, event.xmotion.y);
00501             }
00502             /* If passive motion function registered _and_
00503                buttons not held down, call passive motion
00504                function...  */
00505             else if (window->passive &&
00506                 ((event.xmotion.state &
00507                     (Button1Mask | Button2Mask | Button3Mask)) ==
00508                 0)) {
00509               __glutSetWindow(window);
00510               window->passive(event.xmotion.x,
00511                 event.xmotion.y);
00512             }
00513           }
00514         } else {
00515           /* Motion events are thrown away when a pop up menu
00516              is active. */
00517         }
00518         break;
00519       case KeyPress:
00520       case KeyRelease:
00521         window = __glutGetWindow(event.xkey.window);
00522         if (!window) {
00523           break;
00524         }
00525    if (event.type == KeyPress) {
00526      keyboard = window->keyboard;
00527    } else {
00528 
00529      /* If we are ignoring auto repeated keys for this window,
00530         check if the next event in the X event queue is a KeyPress
00531         for the exact same key (and at the exact same time) as the
00532         key being released.  The X11 protocol will send auto
00533         repeated keys as such KeyRelease/KeyPress pairs. */
00534 
00535      if (window->ignoreKeyRepeat) {
00536        if (XEventsQueued(__glutDisplay, QueuedAfterReading)) {
00537          XPeekEvent(__glutDisplay, &ahead);
00538          if (ahead.type == KeyPress
00539            && ahead.xkey.window == event.xkey.window
00540            && ahead.xkey.keycode == event.xkey.keycode
00541            && ahead.xkey.time == event.xkey.time) {
00542       /* Pop off the repeated KeyPress and ignore
00543          the auto repeated KeyRelease/KeyPress pair. */
00544            XNextEvent(__glutDisplay, &event);
00545            break;
00546          }
00547        }
00548      }
00549      keyboard = window->keyboardUp;
00550    }
00551         if (keyboard) {
00552           char tmp[1];
00553           int rc;
00554 
00555           rc = XLookupString(&event.xkey, tmp, sizeof(tmp),
00556             NULL, NULL);
00557           if (rc) {
00558             __glutSetWindow(window);
00559             __glutModifierMask = event.xkey.state;
00560             keyboard(tmp[0],
00561               event.xkey.x, event.xkey.y);
00562             __glutModifierMask = ~0;
00563             break;
00564           }
00565         }
00566    if (event.type == KeyPress) {
00567      special = window->special;
00568         } else {
00569      special = window->specialUp;
00570    }
00571         if (special) {
00572           KeySym ks;
00573           int key;
00574 
00575 /* Introduced in X11R6:  (Partial list of) Keypad Functions.  Define
00576    in place in case compiling against an older pre-X11R6
00577    X11/keysymdef.h file. */
00578 #ifndef XK_KP_Home
00579 #define XK_KP_Home              0xFF95
00580 #endif
00581 #ifndef XK_KP_Left
00582 #define XK_KP_Left              0xFF96
00583 #endif
00584 #ifndef XK_KP_Up
00585 #define XK_KP_Up                0xFF97
00586 #endif
00587 #ifndef XK_KP_Right
00588 #define XK_KP_Right             0xFF98
00589 #endif
00590 #ifndef XK_KP_Down
00591 #define XK_KP_Down              0xFF99
00592 #endif
00593 #ifndef XK_KP_Prior
00594 #define XK_KP_Prior             0xFF9A
00595 #endif
00596 #ifndef XK_KP_Next
00597 #define XK_KP_Next              0xFF9B
00598 #endif
00599 #ifndef XK_KP_End
00600 #define XK_KP_End               0xFF9C
00601 #endif
00602 #ifndef XK_KP_Insert
00603 #define XK_KP_Insert            0xFF9E
00604 #endif
00605 #ifndef XK_KP_Delete
00606 #define XK_KP_Delete            0xFF9F
00607 #endif
00608 
00609           ks = XLookupKeysym((XKeyEvent *) & event, 0);
00610           /* XXX Verbose, but makes no assumptions about keysym
00611              layout. */
00612           switch (ks) {
00613 /* *INDENT-OFF* */
00614           /* function keys */
00615           case XK_F1:    key = GLUT_KEY_F1; break;
00616           case XK_F2:    key = GLUT_KEY_F2; break;
00617           case XK_F3:    key = GLUT_KEY_F3; break;
00618           case XK_F4:    key = GLUT_KEY_F4; break;
00619           case XK_F5:    key = GLUT_KEY_F5; break;
00620           case XK_F6:    key = GLUT_KEY_F6; break;
00621           case XK_F7:    key = GLUT_KEY_F7; break;
00622           case XK_F8:    key = GLUT_KEY_F8; break;
00623           case XK_F9:    key = GLUT_KEY_F9; break;
00624           case XK_F10:   key = GLUT_KEY_F10; break;
00625           case XK_F11:   key = GLUT_KEY_F11; break;
00626           case XK_F12:   key = GLUT_KEY_F12; break;
00627           /* directional keys */
00628      case XK_KP_Left:
00629           case XK_Left:  key = GLUT_KEY_LEFT; break;
00630      case XK_KP_Up: /* Introduced in X11R6. */
00631           case XK_Up:    key = GLUT_KEY_UP; break;
00632      case XK_KP_Right: /* Introduced in X11R6. */
00633           case XK_Right: key = GLUT_KEY_RIGHT; break;
00634      case XK_KP_Down: /* Introduced in X11R6. */
00635           case XK_Down:  key = GLUT_KEY_DOWN; break;
00636 /* *INDENT-ON* */
00637 
00638      case XK_KP_Prior: /* Introduced in X11R6. */
00639           case XK_Prior:
00640             /* XK_Prior same as X11R6's XK_Page_Up */
00641             key = GLUT_KEY_PAGE_UP;
00642             break;
00643      case XK_KP_Next: /* Introduced in X11R6. */
00644           case XK_Next:
00645             /* XK_Next same as X11R6's XK_Page_Down */
00646             key = GLUT_KEY_PAGE_DOWN;
00647             break;
00648      case XK_KP_Home: /* Introduced in X11R6. */
00649           case XK_Home:
00650             key = GLUT_KEY_HOME;
00651             break;
00652 #ifdef __hpux
00653           case XK_Select:
00654 #endif
00655      case XK_KP_End: /* Introduced in X11R6. */
00656           case XK_End:
00657             key = GLUT_KEY_END;
00658             break;
00659 #ifdef __hpux
00660           case XK_InsertChar:
00661 #endif
00662      case XK_KP_Insert: /* Introduced in X11R6. */
00663           case XK_Insert:
00664             key = GLUT_KEY_INSERT;
00665             break;
00666 #ifdef __hpux
00667           case XK_DeleteChar:
00668 #endif
00669      case XK_KP_Delete: /* Introduced in X11R6. */
00670             /* The Delete character is really an ASCII key. */
00671             __glutSetWindow(window);
00672             keyboard(127,  /* ASCII Delete character. */
00673               event.xkey.x, event.xkey.y);
00674             goto skip;
00675           default:
00676             goto skip;
00677           }
00678           __glutSetWindow(window);
00679           __glutModifierMask = event.xkey.state;
00680           special(key, event.xkey.x, event.xkey.y);
00681           __glutModifierMask = ~0;
00682         skip:;
00683         }
00684         break;
00685       case EnterNotify:
00686       case LeaveNotify:
00687         if (event.xcrossing.mode != NotifyNormal ||
00688           event.xcrossing.detail == NotifyNonlinearVirtual ||
00689           event.xcrossing.detail == NotifyVirtual) {
00690 
00691           /* Careful to ignore Enter/LeaveNotify events that
00692              come from the pop-up menu pointer grab and ungrab. 
00693              Also, ignore "virtual" Enter/LeaveNotify events
00694              since they represent the pointer passing through
00695              the window hierarchy without actually entering or
00696              leaving the actual real estate of a window.  */
00697 
00698           break;
00699         }
00700         if (__glutMappedMenu) {
00701           GLUTmenuItem *item;
00702           int num;
00703 
00704           item = __glutGetMenuItem(__glutMappedMenu,
00705             event.xcrossing.window, &num);
00706           if (item) {
00707             __glutMenuItemEnterOrLeave(item, num, event.type);
00708             break;
00709           }
00710         }
00711         window = __glutGetWindow(event.xcrossing.window);
00712         if (window) {
00713           if (window->entry) {
00714             if (event.type == EnterNotify) {
00715 
00716               /* With overlays established, X can report two
00717                  enter events for both the overlay and normal
00718                  plane window. Do not generate a second enter
00719                  callback if we reported one without an
00720                  intervening leave. */
00721 
00722               if (window->entryState != EnterNotify) {
00723                 int num = window->num;
00724                 Window xid = window->win;
00725 
00726                 window->entryState = EnterNotify;
00727                 __glutSetWindow(window);
00728                 window->entry(GLUT_ENTERED);
00729 
00730                 if (__glutMappedMenu) {
00731 
00732                   /* Do not generate any passive motion events
00733                      when menus are in use. */
00734 
00735                 } else {
00736 
00737                   /* An EnterNotify event can result in a
00738                      "compound" callback if a passive motion
00739                      callback is also registered. In this case,
00740                      be a little paranoid about the possibility
00741                      the window could have been destroyed in the
00742                      entry callback. */
00743 
00744                   window = __glutWindowList[num];
00745                   if (window && window->passive && window->win == xid) {
00746                     __glutSetWindow(window);
00747                     window->passive(event.xcrossing.x, event.xcrossing.y);
00748                   }
00749                 }
00750               }
00751             } else {
00752               if (window->entryState != LeaveNotify) {
00753 
00754                 /* When an overlay is established for a window
00755                    already mapped and with the pointer in it,
00756                    the X server will generate a leave/enter
00757                    event pair as the pointer leaves (without
00758                    moving) from the normal plane X window to
00759                    the newly mapped overlay  X window (or vice
00760                    versa). This enter/leave pair should not be
00761                    reported to the GLUT program since the pair
00762                    is a consequence of creating (or destroying) 
00763                    the overlay, not an actual leave from the
00764                    GLUT window. */
00765 
00766                 if (XEventsQueued(__glutDisplay, QueuedAfterReading)) {
00767                   XPeekEvent(__glutDisplay, &ahead);
00768                   if (ahead.type == EnterNotify &&
00769                     __glutGetWindow(ahead.xcrossing.window) == window) {
00770                     XNextEvent(__glutDisplay, &event);
00771                     break;
00772                   }
00773                 }
00774                 window->entryState = LeaveNotify;
00775                 __glutSetWindow(window);
00776                 window->entry(GLUT_LEFT);
00777               }
00778             }
00779           } else if (window->passive) {
00780             __glutSetWindow(window);
00781             window->passive(event.xcrossing.x, event.xcrossing.y);
00782           }
00783         }
00784         break;
00785       case UnmapNotify:
00786         /* MapNotify events are not needed to maintain
00787            visibility state since VisibilityNotify events will
00788            be delivered when a window becomes visible from
00789            mapping.  However, VisibilityNotify events are not
00790            delivered when a window is unmapped (for the window
00791            or its children). */
00792         window = __glutGetWindow(event.xunmap.window);
00793         if (window) {
00794           if (window->win != event.xconfigure.window) {
00795             /* Ignore UnmapNotify sent to the overlay planes.
00796                GLUT could get here because overlays select for
00797                StructureNotify events to receive DestroyNotify. 
00798              */
00799             break;
00800           }
00801           markWindowHidden(window);
00802         }
00803         break;
00804       case VisibilityNotify:
00805         window = __glutGetWindow(event.xvisibility.window);
00806         if (window) {
00807           /* VisibilityUnobscured+1 = GLUT_FULLY_RETAINED,
00808              VisibilityPartiallyObscured+1 =
00809              GLUT_PARTIALLY_RETAINED, VisibilityFullyObscured+1 
00810              =  GLUT_FULLY_COVERED. */
00811           int visState = event.xvisibility.state + 1;
00812 
00813           if (visState != window->visState) {
00814             if (window->windowStatus) {
00815               window->visState = visState;
00816               __glutSetWindow(window);
00817               window->windowStatus(visState);
00818             }
00819           }
00820         }
00821         break;
00822       case ClientMessage:
00823         if (event.xclient.data.l[0] == __glutWMDeleteWindow)
00824           exit(0);
00825         break;
00826       case DestroyNotify:
00827         purgeStaleWindow(event.xdestroywindow.window);
00828         break;
00829       case CirculateNotify:
00830       case CreateNotify:
00831       case GravityNotify:
00832       case ReparentNotify:
00833         /* Uninteresting to GLUT (but possible for GLUT to
00834            receive). */
00835         break;
00836       default:
00837         /* Pass events not directly handled by the GLUT main
00838            event loop to any event parsers that have been
00839            registered.  In this way, X Input extension events
00840            are passed to the correct handler without forcing
00841            all GLUT programs to support X Input event handling. 
00842          */
00843         parser = eventParserList;
00844         while (parser) {
00845           if (parser->func(&event))
00846             break;
00847           parser = parser->next;
00848         }
00849         break;
00850       }
00851     }
00852 #endif /* _WIN32 */
00853     if (__glutTimerList) {
00854       handleTimeouts();
00855     }
00856   }
00857   while (XPending(__glutDisplay));
00858 }
00859 
00860 static void
00861 waitForSomething(void)
00862 {
00863 #if defined(__vms) && ( __VMS_VER < 70000000 )
00864   static struct timeval zerotime =
00865   {0};
00866   unsigned int timer_efn;
00867 #define timer_id 'glut' /* random :-) number */
00868   unsigned int wait_mask;
00869 #else
00870   static struct timeval zerotime =
00871   {0, 0};
00872 #if !defined(_WIN32)
00873   fd_set fds;
00874 #endif
00875 #endif
00876   struct timeval now, timeout, waittime;
00877 #if !defined(_WIN32)
00878   int rc;
00879 #endif
00880 
00881   /* Flush X protocol since XPending does not do this
00882      implicitly. */
00883   XFlush(__glutDisplay);
00884   if (XPending(__glutDisplay)) {
00885     /* It is possible (but quite rare) that XFlush may have
00886        needed to wait for a writable X connection file
00887        descriptor, and in the process, may have had to read off
00888        X protocol from the file descriptor. If XPending is true,
00889        this case occured and we should avoid waiting in select
00890        since X protocol buffered within Xlib is due to be
00891        processed and potentially no more X protocol is on the
00892        file descriptor, so we would risk waiting improperly in
00893        select. */
00894     goto immediatelyHandleXinput;
00895   }
00896 #if defined(__vms) && ( __VMS_VER < 70000000 )
00897   timeout = __glutTimerList->timeout;
00898   GETTIMEOFDAY(&now);
00899   wait_mask = 1 << (__glutConnectionFD & 31);
00900   if (IS_AFTER(now, timeout)) {
00901     /* We need an event flag for the timer. */
00902     /* XXX The `right' way to do this is to use LIB$GET_EF, but
00903        since it needs to be in the same cluster as the EFN for
00904        the display, we will have hack it. */
00905     timer_efn = __glutConnectionFD - 1;
00906     if ((timer_efn / 32) != (__glutConnectionFD / 32)) {
00907       timer_efn = __glutConnectionFD + 1;
00908     }
00909     rc = SYS$CLREF(timer_efn);
00910     rc = SYS$SETIMR(timer_efn, &timeout, NULL, timer_id, 0);
00911     wait_mask |= 1 << (timer_efn & 31);
00912   } else {
00913     timer_efn = 0;
00914   }
00915   rc = SYS$WFLOR(__glutConnectionFD, wait_mask);
00916   if (timer_efn != 0 && SYS$CLREF(timer_efn) == SS$_WASCLR) {
00917     rc = SYS$CANTIM(timer_id, PSL$C_USER);
00918   }
00919   /* XXX There does not seem to be checking of "rc" in the code
00920      above.  Can any of the SYS$ routines above fail? */
00921 #else /* not vms6.2 or lower */
00922 #if !defined(_WIN32)
00923   FD_ZERO(&fds);
00924   FD_SET(__glutConnectionFD, &fds);
00925 #endif
00926   timeout = __glutTimerList->timeout;
00927   GETTIMEOFDAY(&now);
00928   if (IS_AFTER(now, timeout)) {
00929     TIMEDELTA(waittime, timeout, now);
00930   } else {
00931     waittime = zerotime;
00932   }
00933 #if !defined(_WIN32)
00934   rc = select(__glutConnectionFD + 1, &fds,
00935     NULL, NULL, &waittime);
00936   if (rc < 0 && errno != EINTR)
00937     __glutFatalError("select error.");
00938 #else
00939 #if 0 /* XXX Nate, what is this junk? */
00940   /* Set up a timer to fire in at least a millisecond, then wait for
00941      the message.  This should act like a select. */
00942   SetTimer(NULL, 2, waittime.tv_usec, NULL);
00943   WaitMessage();
00944   KillTimer(NULL, 2);
00945 #endif
00946 
00947   /* Actually, a sleep seems to do the trick -- do we even need this? */
00948   Sleep(0);
00949 #endif
00950 #endif /* not vms6.2 or lower */
00951   /* Without considering the cause of select unblocking, check
00952      for pending X events and handle any timeouts (by calling
00953      processEventsAndTimeouts).  We always look for X events
00954      even if select returned with 0 (indicating a timeout);
00955      otherwise we risk starving X event processing by continous
00956      timeouts. */
00957   if (XPending(__glutDisplay)) {
00958   immediatelyHandleXinput:
00959     processEventsAndTimeouts();
00960   } else {
00961     if (__glutTimerList)
00962       handleTimeouts();
00963   }
00964 }
00965 
00966 static void
00967 idleWait(void)
00968 {
00969   if (XPending(__glutDisplay)) {
00970     processEventsAndTimeouts();
00971   } else {
00972     if (__glutTimerList) {
00973       handleTimeouts();
00974     }
00975   }
00976   /* Make sure idle func still exists! */
00977   if (__glutIdleFunc) {
00978     __glutIdleFunc();
00979   }
00980 }
00981 
00982 static GLUTwindow **beforeEnd;
00983 
00984 static GLUTwindow *
00985 processWindowWorkList(GLUTwindow * window)
00986 {
00987   int workMask;
00988 
00989   if (window->prevWorkWin) {
00990     window->prevWorkWin = processWindowWorkList(window->prevWorkWin);
00991   } else {
00992     beforeEnd = &window->prevWorkWin;
00993   }
00994 
00995   /* Capture work mask for work that needs to be done to this
00996      window, then clear the window's work mask (excepting the
00997      dummy work bit, see below).  Then, process the captured
00998      work mask.  This allows callbacks in the processing the
00999      captured work mask to set the window's work mask for
01000      subsequent processing. */
01001 
01002   workMask = window->workMask;
01003   assert((workMask & GLUT_DUMMY_WORK) == 0);
01004 
01005   /* Set the dummy work bit, clearing all other bits, to
01006      indicate that the window is currently on the window work
01007      list _and_ that the window's work mask is currently being
01008      processed.  This convinces __glutPutOnWorkList that this
01009      window is on the work list still. */
01010   window->workMask = GLUT_DUMMY_WORK;
01011 
01012   /* Optimization: most of the time, the work to do is a
01013      redisplay and not these other types of work.  Check for
01014      the following cases as a group to before checking each one
01015      individually one by one. This saves about 25 MIPS
01016      instructions in the common redisplay only case. */
01017   if (workMask & (GLUT_EVENT_MASK_WORK | GLUT_DEVICE_MASK_WORK |
01018       GLUT_CONFIGURE_WORK | GLUT_COLORMAP_WORK | GLUT_MAP_WORK)) {
01019 #if !defined(_WIN32)
01020     /* Be sure to set event mask BEFORE map window is done. */
01021     if (workMask & GLUT_EVENT_MASK_WORK) {
01022       long eventMask;
01023 
01024       /* Make sure children are not propogating events this
01025          window is selecting for.  Be sure to do this before
01026          enabling events on the children's parent. */
01027       if (window->children) {
01028         GLUTwindow *child = window->children;
01029         unsigned long attribMask = CWDontPropagate;
01030         XSetWindowAttributes wa;
01031 
01032         wa.do_not_propagate_mask = window->eventMask & GLUT_DONT_PROPAGATE_FILTER_MASK;
01033         if (window->eventMask & GLUT_HACK_STOP_PROPAGATE_MASK) {
01034           wa.event_mask = child->eventMask | (window->eventMask & GLUT_HACK_STOP_PROPAGATE_MASK);
01035           attribMask |= CWEventMask;
01036         }
01037         do {
01038           XChangeWindowAttributes(__glutDisplay, child->win,
01039             attribMask, &wa);
01040           child = child->siblings;
01041         } while (child);
01042       }
01043       eventMask = window->eventMask;
01044       if (window->parent && window->parent->eventMask & GLUT_HACK_STOP_PROPAGATE_MASK)
01045         eventMask |= (window->parent->eventMask & GLUT_HACK_STOP_PROPAGATE_MASK);
01046       XSelectInput(__glutDisplay, window->win, eventMask);
01047       if (window->overlay)
01048         XSelectInput(__glutDisplay, window->overlay->win,
01049           window->eventMask & GLUT_OVERLAY_EVENT_FILTER_MASK);
01050     }
01051 #endif /* !_WIN32 */
01052     /* Be sure to set device mask BEFORE map window is done. */
01053     if (workMask & GLUT_DEVICE_MASK_WORK) {
01054       __glutUpdateInputDeviceMaskFunc(window);
01055     }
01056     /* Be sure to configure window BEFORE map window is done. */
01057     if (workMask & GLUT_CONFIGURE_WORK) {
01058 #if defined(_WIN32)
01059       RECT changes;
01060       POINT point;
01061       UINT flags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER
01062    | SWP_NOSENDCHANGING | SWP_NOSIZE | SWP_NOZORDER;
01063 
01064       GetClientRect(window->win, &changes);
01065       
01066       /* If this window is a toplevel window, translate the 0,0 client
01067          coordinate into a screen coordinate for proper placement. */
01068       if (!window->parent) {
01069         point.x = 0;
01070         point.y = 0;
01071         ClientToScreen(window->win, &point);
01072         changes.left = point.x;
01073         changes.top = point.y;
01074       }
01075       if (window->desiredConfMask & (CWX | CWY)) {
01076         changes.left = window->desiredX;
01077         changes.top = window->desiredY;
01078    flags &= ~SWP_NOMOVE;
01079       }
01080       if (window->desiredConfMask & (CWWidth | CWHeight)) {
01081         changes.right = changes.left + window->desiredWidth;
01082         changes.bottom = changes.top + window->desiredHeight;
01083    flags &= ~SWP_NOSIZE;
01084    /* XXX If overlay exists, resize the overlay here, ie.
01085       if (window->overlay) ... */
01086       }
01087       if (window->desiredConfMask & CWStackMode) {
01088    flags &= ~SWP_NOZORDER;
01089    /* XXX Overlay support might require something special here. */
01090       }
01091 
01092       /* Adjust the window rectangle because Win32 thinks that the x, y,
01093          width & height are the WHOLE window (including decorations),
01094          whereas GLUT treats the x, y, width & height as only the CLIENT
01095          area of the window.  Only do this to top level windows
01096          that are not in game mode (since game mode windows do
01097          not have any decorations). */
01098       if (!window->parent && window != __glutGameModeWindow) {
01099         AdjustWindowRect(&changes,
01100           WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
01101           FALSE);
01102       }
01103 
01104       /* Do the repositioning, moving, and push/pop. */
01105       SetWindowPos(window->win,
01106         window->desiredStack == Above ? HWND_TOP : HWND_NOTOPMOST,
01107         changes.left, changes.top,
01108         changes.right - changes.left, changes.bottom - changes.top,
01109         flags);
01110 
01111       /* Zero out the mask. */
01112       window->desiredConfMask = 0;
01113 
01114       /* This hack causes the window to go back to the right position
01115          when it is taken out of fullscreen mode. */
01116       if (workMask & GLUT_FULL_SCREEN_WORK) {
01117         window->desiredConfMask |= CWX | CWY;
01118         window->desiredX = point.x;
01119         window->desiredY = point.y;
01120       }
01121 #else /* !_WIN32 */
01122       XWindowChanges changes;
01123 
01124       changes.x = window->desiredX;
01125       changes.y = window->desiredY;
01126       if (window->desiredConfMask & (CWWidth | CWHeight)) {
01127         changes.width = window->desiredWidth;
01128         changes.height = window->desiredHeight;
01129         if (window->overlay)
01130           XResizeWindow(__glutDisplay, window->overlay->win,
01131             window->desiredWidth, window->desiredHeight);
01132         if (__glutMotifHints != None) {
01133           if (workMask & GLUT_FULL_SCREEN_WORK) {
01134             MotifWmHints hints;
01135 
01136             hints.flags = MWM_HINTS_DECORATIONS;
01137             hints.decorations = 0;  /* Absolutely no
01138                                        decorations. */
01139             XChangeProperty(__glutDisplay, window->win,
01140               __glutMotifHints, __glutMotifHints, 32,
01141               PropModeReplace, (unsigned char *) &hints, 4);
01142             if (workMask & GLUT_MAP_WORK) {
01143               /* Handle case where glutFullScreen is called
01144                  before the first time that the window is
01145                  mapped. Some window managers will randomly or
01146                  interactively position the window the first
01147                  time it is mapped if the window's
01148                  WM_NORMAL_HINTS property does not request an
01149                  explicit position. We don't want any such
01150                  window manager interaction when going
01151                  fullscreen.  Overwrite the WM_NORMAL_HINTS
01152                  property installed by glutCreateWindow's
01153                  XSetWMProperties property with one explicitly
01154                  requesting a fullscreen window. */
01155               XSizeHints hints;
01156 
01157               hints.flags = USPosition | USSize;
01158               hints.x = 0;
01159               hints.y = 0;
01160               hints.width = window->desiredWidth;
01161               hints.height = window->desiredHeight;
01162               XSetWMNormalHints(__glutDisplay, window->win, &hints);
01163             }
01164           } else {
01165             XDeleteProperty(__glutDisplay, window->win, __glutMotifHints);
01166           }
01167         }
01168       }
01169       if (window->desiredConfMask & CWStackMode) {
01170         changes.stack_mode = window->desiredStack;
01171         /* Do not let glutPushWindow push window beneath the
01172            underlay. */
01173         if (window->parent && window->parent->overlay
01174           && window->desiredStack == Below) {
01175           changes.stack_mode = Above;
01176           changes.sibling = window->parent->overlay->win;
01177           window->desiredConfMask |= CWSibling;
01178         }
01179       }
01180       XConfigureWindow(__glutDisplay, window->win,
01181         window->desiredConfMask, &changes);
01182       window->desiredConfMask = 0;
01183 #endif
01184     }
01185 #if !defined(_WIN32)
01186     /* Be sure to establish the colormaps BEFORE map window is
01187        done. */
01188     if (workMask & GLUT_COLORMAP_WORK) {
01189       __glutEstablishColormapsProperty(window);
01190     }
01191 #endif
01192     if (workMask & GLUT_MAP_WORK) {
01193       switch (window->desiredMapState) {
01194       case WithdrawnState:
01195         if (window->parent) {
01196           XUnmapWindow(__glutDisplay, window->win);
01197         } else {
01198           XWithdrawWindow(__glutDisplay, window->win,
01199             __glutScreen);
01200         }
01201         window->shownState = 0;
01202         break;
01203       case NormalState:
01204         XMapWindow(__glutDisplay, window->win);
01205         window->shownState = 1;
01206         break;
01207 #ifdef _WIN32
01208       case GameModeState:  /* Not an Xlib value. */
01209         ShowWindow(window->win, SW_SHOW);
01210         window->shownState = 1;
01211         break;
01212 #endif
01213       case IconicState:
01214         XIconifyWindow(__glutDisplay, window->win, __glutScreen);
01215         window->shownState = 0;
01216         break;
01217       }
01218     }
01219   }
01220   if (workMask & (GLUT_REDISPLAY_WORK | GLUT_OVERLAY_REDISPLAY_WORK | GLUT_REPAIR_WORK | GLUT_OVERLAY_REPAIR_WORK)) {
01221     if (window->forceReshape) {
01222       /* Guarantee that before a display callback is generated
01223          for a window, a reshape callback must be generated. */
01224       __glutSetWindow(window);
01225       window->reshape(window->width, window->height);
01226       window->forceReshape = False;
01227 
01228       /* Setting the redisplay bit on the first reshape is
01229          necessary to make the "Mesa glXSwapBuffers to repair
01230          damage" hack operate correctly.  Without indicating a
01231          redisplay is necessary, there's not an initial back
01232          buffer render from which to blit from when damage
01233          happens to the window. */
01234       workMask |= GLUT_REDISPLAY_WORK;
01235     }
01236     /* The code below is more involved than otherwise necessary
01237        because it is paranoid about the overlay or entire window
01238        being removed or destroyed in the course of the callbacks.
01239        Notice how the global __glutWindowDamaged is used to record
01240        the layers' damage status.  See the code in glutLayerGet for
01241        how __glutWindowDamaged is used. The  point is to not have to
01242        update the "damaged" field after  the callback since the
01243        window (or overlay) may be destroyed (or removed) when the
01244        callback returns. */
01245 
01246     if (window->overlay && window->overlay->display) {
01247       int num = window->num;
01248       Window xid = window->overlay ? window->overlay->win : None;
01249 
01250       /* If an overlay display callback is registered, we
01251          differentiate between a redisplay needed for the
01252          overlay and/or normal plane.  If there is no overlay
01253          display callback registered, we simply use the
01254          standard display callback. */
01255 
01256       if (workMask & (GLUT_REDISPLAY_WORK | GLUT_REPAIR_WORK)) {
01257         if (__glutMesaSwapHackSupport) {
01258           if (window->usedSwapBuffers) {
01259             if ((workMask & (GLUT_REPAIR_WORK | GLUT_REDISPLAY_WORK)) == GLUT_REPAIR_WORK) {
01260          SWAP_BUFFERS_WINDOW(window);
01261               goto skippedDisplayCallback1;
01262             }
01263           }
01264         }
01265         /* Render to normal plane. */
01266 #ifdef _WIN32
01267         window->renderDc = window->hdc;
01268 #endif
01269         window->renderWin = window->win;
01270         window->renderCtx = window->ctx;
01271         __glutWindowDamaged = (workMask & GLUT_REPAIR_WORK);
01272         __glutSetWindow(window);
01273         window->usedSwapBuffers = 0;
01274         window->display();
01275         __glutWindowDamaged = 0;
01276 
01277       skippedDisplayCallback1:;
01278       }
01279       if (workMask & (GLUT_OVERLAY_REDISPLAY_WORK | GLUT_OVERLAY_REPAIR_WORK)) {
01280         window = __glutWindowList[num];
01281         if (window && window->overlay &&
01282           window->overlay->win == xid && window->overlay->display) {
01283 
01284           /* Render to overlay. */
01285 #ifdef _WIN32
01286           window->renderDc = window->overlay->hdc;
01287 #endif
01288           window->renderWin = window->overlay->win;
01289           window->renderCtx = window->overlay->ctx;
01290           __glutWindowDamaged = (workMask & GLUT_OVERLAY_REPAIR_WORK);
01291           __glutSetWindow(window);
01292           window->overlay->display();
01293           __glutWindowDamaged = 0;
01294         } else {
01295           /* Overlay may have since been destroyed or the
01296              overlay callback may have been disabled during
01297              normal display callback. */
01298         }
01299       }
01300     } else {
01301       if (__glutMesaSwapHackSupport) {
01302         if (!window->overlay && window->usedSwapBuffers) {
01303           if ((workMask & (GLUT_REPAIR_WORK | GLUT_REDISPLAY_WORK)) == GLUT_REPAIR_WORK) {
01304        SWAP_BUFFERS_WINDOW(window);
01305             goto skippedDisplayCallback2;
01306           }
01307         }
01308       }
01309       /* Render to normal plane (and possibly overlay). */
01310       __glutWindowDamaged = (workMask & (GLUT_OVERLAY_REPAIR_WORK | GLUT_REPAIR_WORK));
01311       __glutSetWindow(window);
01312       window->usedSwapBuffers = 0;
01313       window->display();
01314       __glutWindowDamaged = 0;
01315 
01316     skippedDisplayCallback2:;
01317     }
01318   }
01319   /* Combine workMask with window->workMask to determine what
01320      finish and debug work there is. */
01321   workMask |= window->workMask;
01322 
01323   if (workMask & GLUT_FINISH_WORK) {
01324     /* Finish work makes sure a glFinish gets done to indirect
01325        rendering contexts.  Indirect contexts tend to have much 
01326        longer latency because lots of OpenGL extension requests 
01327        can queue up in the X protocol stream. __glutSetWindow
01328        is where the finish works gets queued for indirect
01329        contexts. */
01330     __glutSetWindow(window);
01331     glFinish();
01332   }
01333   if (workMask & GLUT_DEBUG_WORK) {
01334     __glutSetWindow(window);
01335     glutReportErrors();
01336   }
01337   /* Strip out dummy, finish, and debug work bits. */
01338   window->workMask &= ~(GLUT_DUMMY_WORK | GLUT_FINISH_WORK | GLUT_DEBUG_WORK);
01339   if (window->workMask) {
01340     /* Leave on work list. */
01341     return window;
01342   } else {
01343     /* Remove current window from work list. */
01344     return window->prevWorkWin;
01345   }
01346 }
01347 
01348 /* CENTRY */
01349 void APIENTRY
01350 glutMainLoop(void)
01351 {
01352 #if !defined(_WIN32)
01353   if (!__glutDisplay)
01354     __glutFatalUsage("main loop entered with out proper initialization.");
01355 #endif
01356   if (!__glutWindowListSize)
01357     __glutFatalUsage(
01358       "main loop entered with no windows created.");
01359   for (;;) {
01360     if (__glutWindowWorkList) {
01361       GLUTwindow *remainder, *work;
01362 
01363       work = __glutWindowWorkList;
01364       __glutWindowWorkList = NULL;
01365       if (work) {
01366         remainder = processWindowWorkList(work);
01367         if (remainder) {
01368           *beforeEnd = __glutWindowWorkList;
01369           __glutWindowWorkList = remainder;
01370         }
01371       }
01372     }
01373     if (__glutIdleFunc || __glutWindowWorkList) {
01374       idleWait();
01375     } else {
01376       if (__glutTimerList) {
01377         waitForSomething();
01378       } else {
01379         processEventsAndTimeouts();
01380       }
01381     }
01382   }
01383 }
01384 /* ENDCENTRY */

Generated on Mon Sep 18 11:39:31 2006 for jot by  doxygen 1.4.4