Skip to content

AFNI/NIfTI Server

Sections
Personal tools
You are here: Home » AFNI » Documentation

Doxygen Source Code Documentation


Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals   Search  

glut_event.c

Go to the documentation of this file.
00001 
00002 /* Copyright (c) Mark J. Kilgard, 1994, 1995, 1996. */
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 <unistd.h>
00012 #include <assert.h>
00013 #ifdef __sgi
00014 #include <bstring.h>    /* prototype for bzero used by FD_ZERO */
00015 #endif
00016 #ifdef AIXV3
00017 #include <sys/select.h> /* select system call interface */
00018 #endif
00019 #include <sys/types.h>
00020 #ifndef __vms
00021 #include <sys/time.h>
00022 #endif
00023 #include <X11/Xlib.h>
00024 #include <X11/keysym.h>
00025 #ifdef __hpux
00026 /* XXX Bert Gijsbers <bert@mc.bio.uva.nl> reports that HP-UX
00027    needs different keysyms for the End, Insert, and Delete keys
00028    to work on an HP 715.  It would be better if HP generated
00029    standard keysyms for standard keys. */
00030 #include <X11/HPkeysym.h>
00031 #endif
00032 #ifdef __vms
00033 #include <ssdef.h>
00034 #include <psldef.h>
00035 extern int SYS$CLREF(int efn);
00036 extern int SYS$SETIMR(unsigned int efn, struct timeval *timeout, void *ast,
00037   unsigned int request_id, unsigned int flags);
00038 extern int SYS$WFLOR(unsigned int efn, unsigned int mask);
00039 extern int SYS$CANTIM(unsigned int request_id, unsigned int mode);
00040 #endif /* __vms */
00041 #include <GL/glut.h>
00042 #include "glutint.h"
00043 
00044 static GLUTtimer *freeTimerList = NULL;
00045 static int mappedMenuButton;
00046 
00047 GLUTidleCB __glutIdleFunc = NULL;
00048 GLUTtimer *__glutTimerList = NULL;
00049 #ifdef SUPPORT_FORTRAN
00050 GLUTtimer *__glutNewTimer;
00051 #endif
00052 GLUTwindow *__glutWindowWorkList = NULL;
00053 void (*__glutUpdateInputDeviceMaskFunc) (GLUTwindow *);
00054 Atom __glutMotifHints = None;
00055 unsigned int __glutModifierMask = ~0;  /* ~0 implies not in
00056                                           core input callback. */
00057 int __glutWindowDamaged = 0;
00058 
00059 void
00060 glutIdleFunc(GLUTidleCB idleFunc)
00061 {
00062   __glutIdleFunc = idleFunc;
00063 }
00064 
00065 void
00066 glutTimerFunc(unsigned int interval, GLUTtimerCB timerFunc, int value)
00067 {
00068   GLUTtimer *timer, *other;
00069   GLUTtimer **prevptr;
00070   struct timeval now;
00071 
00072   if (!timerFunc)
00073     return;
00074 
00075   if (freeTimerList) {
00076     timer = freeTimerList;
00077     freeTimerList = timer->next;
00078   } else {
00079     timer = (GLUTtimer *) malloc(sizeof(GLUTtimer));
00080     if (!timer)
00081       __glutFatalError("out of memory.");
00082   }
00083 
00084   timer->func = timerFunc;
00085 #ifdef __vms
00086   /* VMS time is expressed in units of 100 ns */
00087   timer->timeout.val = interval * TICKS_PER_MILLISECOND;
00088 #else
00089   timer->timeout.tv_sec = (int) interval / 1000;
00090   timer->timeout.tv_usec = (int) (interval % 1000) * 1000;
00091 #endif
00092   timer->value = value;
00093   timer->next = NULL;
00094   GETTIMEOFDAY(&now);
00095   ADD_TIME(timer->timeout, timer->timeout, now);
00096   prevptr = &__glutTimerList;
00097   other = *prevptr;
00098   while (other && IS_AFTER(other->timeout, timer->timeout)) {
00099     prevptr = &other->next;
00100     other = *prevptr;
00101   }
00102   timer->next = other;
00103 #ifdef SUPPORT_FORTRAN
00104   __glutNewTimer = timer;  /* for Fortran binding! */
00105 #endif
00106   *prevptr = timer;
00107 }
00108 
00109 static void
00110 handleTimeouts(void)
00111 {
00112   struct timeval now;
00113   GLUTtimer *timer;
00114 
00115   if (__glutTimerList) {
00116     GETTIMEOFDAY(&now);
00117     while (IS_AT_OR_AFTER(__glutTimerList->timeout, now)) {
00118       timer = __glutTimerList;
00119       timer->func(timer->value);
00120       __glutTimerList = timer->next;
00121       timer->next = freeTimerList;
00122       freeTimerList = timer;
00123       if (!__glutTimerList)
00124         break;
00125     }
00126   }
00127 }
00128 
00129 void
00130 __glutPutOnWorkList(GLUTwindow * window, int workMask)
00131 {
00132   if (window->workMask) {
00133     /* Already on list; just OR in new workMask. */
00134     window->workMask |= workMask;
00135   } else {
00136     /* Update work mask and add to window work list. */
00137     window->workMask = workMask;
00138     window->prevWorkWin = __glutWindowWorkList;
00139     __glutWindowWorkList = window;
00140   }
00141 }
00142 
00143 void
00144 __glutPostRedisplay(GLUTwindow * window, int layerMask)
00145 {
00146   int shown = (layerMask == GLUT_REDISPLAY_WORK) ? window->shownState : window->overlay->shownState;
00147 
00148   /* Post a redisplay if the window is visible (or the
00149      visibility of the window is unknown, ie. window->visState
00150      == -1) _and_ the layer is known to be shown. */
00151   if (window->visState != 0 && shown)
00152     __glutPutOnWorkList(window, layerMask);
00153 }
00154 
00155 void
00156 glutPostRedisplay(void)
00157 {
00158   __glutPostRedisplay(__glutCurrentWindow, GLUT_REDISPLAY_WORK);
00159 }
00160 
00161 static GLUTeventParser *eventParserList = NULL;
00162 
00163 /* __glutRegisterEventParser allows another module to register
00164    to intercept X events types not otherwise acted on by the
00165    GLUT processEvents routine.  The X Input extension support
00166    code uses an event parser for handling X Input extension
00167    events.  */
00168 
00169 void
00170 __glutRegisterEventParser(GLUTeventParser * parser)
00171 {
00172   parser->next = eventParserList;
00173   eventParserList = parser;
00174 }
00175 
00176 static void
00177 updateWindowVisibility(GLUTwindow * window, int visState)
00178 {
00179   if (window->shownState && visState != window->visState) {
00180     if (window->visibility) {
00181       window->visState = visState;
00182       __glutSetWindow(window);
00183       window->visibility(visState ?
00184         GLUT_VISIBLE : GLUT_NOT_VISIBLE);
00185     }
00186     /* An unmap is only reported on a single window; its
00187        descendents need to know they are no longer visible. */
00188     if (!visState) {
00189       GLUTwindow *child = window->children;
00190 
00191       while (child) {
00192         updateWindowVisibility(child, visState);
00193         child = child->siblings;
00194       }
00195     }
00196   }
00197 }
00198 
00199 static void
00200 purgeStaleWindow(Window win)
00201 {
00202   GLUTstale **pEntry = &__glutStaleWindowList;
00203   GLUTstale *entry = __glutStaleWindowList;
00204 
00205   /* Tranverse singly-linked stale window list look for the
00206      window ID. */
00207   while (entry) {
00208     if (entry->win == win) {
00209       /* Found it; delete it. */
00210       *pEntry = entry->next;
00211       free(entry);
00212       return;
00213     } else {
00214       pEntry = &entry->next;
00215       entry = *pEntry;
00216     }
00217   }
00218 }
00219 
00220 static void
00221 processEvents(void)
00222 {
00223   XEvent event, ahead;
00224   GLUTwindow *window;
00225   int width, height;
00226   GLUTeventParser *parser;
00227 
00228   do {
00229     XNextEvent(__glutDisplay, &event);
00230     switch (event.type) {
00231     case MappingNotify:
00232       XRefreshKeyboardMapping((XMappingEvent *) & event);
00233       break;
00234     case ConfigureNotify:
00235       window = __glutGetWindow(event.xconfigure.window);
00236       if (window) {
00237         if (window->win != event.xconfigure.window) {
00238           /* Ignore ConfigureNotify sent to the overlay planes.
00239              GLUT could get here because overlays select for
00240              StructureNotify events to receive DestroyNotify. */
00241           break;
00242         }
00243         width = event.xconfigure.width;
00244         height = event.xconfigure.height;
00245         if (width != window->width || height != window->height) {
00246           if (window->overlay) {
00247             XResizeWindow(__glutDisplay, window->overlay->win, width, height);
00248           }
00249           window->width = width;
00250           window->height = height;
00251           __glutSetWindow(window);
00252           /* Do not execute OpenGL out of sequence with respect
00253              to the XResizeWindow request! */
00254           glXWaitX();
00255           window->reshape(width, height);
00256           window->forceReshape = False;
00257         }
00258       }
00259       break;
00260     case Expose:
00261       /* compress expose events */
00262       while (XEventsQueued(__glutDisplay, QueuedAfterReading)
00263         > 0) {
00264         XPeekEvent(__glutDisplay, &ahead);
00265         if (ahead.type != Expose ||
00266           ahead.xexpose.window != event.xexpose.window)
00267           break;
00268         XNextEvent(__glutDisplay, &event);
00269       }
00270       if (event.xexpose.count == 0) {
00271         GLUTmenu *menu;
00272 
00273         if (__glutMappedMenu &&
00274           (menu = __glutGetMenu(event.xexpose.window))) {
00275           __glutPaintMenu(menu);
00276         } else {
00277           window = __glutGetWindow(event.xexpose.window);
00278           if (window) {
00279             if (window->win == event.xexpose.window) {
00280               window->damaged = 1;
00281               __glutPostRedisplay(window, GLUT_REDISPLAY_WORK);
00282             } else if (window->overlay && window->overlay->win == event.xexpose.window) {
00283               __glutPostRedisplay(window, GLUT_OVERLAY_REDISPLAY_WORK);
00284               window->overlay->damaged = 1;
00285             }
00286           }
00287         }
00288       } else {
00289         /* there are more exposes to read; wait to redisplay */
00290       }
00291       break;
00292     case ButtonPress:
00293     case ButtonRelease:
00294       if (__glutMappedMenu && event.type == ButtonRelease
00295         && mappedMenuButton == event.xbutton.button) {
00296         /* Menu is currently popped up and its button is
00297            released. */
00298         __glutFinishMenu(event.xbutton.window, event.xbutton.x, event.xbutton.y);
00299       } else {
00300         window = __glutGetWindow(event.xbutton.window);
00301         if (window) {
00302           GLUTmenu *menu;
00303 
00304           menu = __glutGetMenuByNum(
00305             window->menu[event.xbutton.button - 1]);
00306           if (menu) {
00307             if (event.type == ButtonPress && !__glutMappedMenu) {
00308               __glutStartMenu(menu, window,
00309                 event.xbutton.x_root, event.xbutton.y_root,
00310                 event.xbutton.x, event.xbutton.y);
00311               mappedMenuButton = event.xbutton.button;
00312             } else {
00313               /* Ignore a release of a button with a menu
00314                  attatched to it when no menu is popped up, or
00315                  ignore a press when another menu is already
00316                  popped up. */
00317             }
00318           } else if (window->mouse) {
00319             __glutSetWindow(window);
00320             __glutModifierMask = event.xbutton.state;
00321             window->mouse(event.xbutton.button - 1,
00322               event.type == ButtonRelease ?
00323               GLUT_UP : GLUT_DOWN,
00324               event.xbutton.x, event.xbutton.y);
00325             __glutModifierMask = ~0;
00326           } else {
00327             /* Stray mouse events.  Ignore. */
00328           }
00329         } else {
00330           /* Window might have been destroyed and all the 
00331              events for the window may not yet be received. */
00332         }
00333       }
00334       break;
00335     case MotionNotify:
00336       if (!__glutMappedMenu) {
00337         window = __glutGetWindow(event.xmotion.window);
00338         if (window) {
00339           /* If motion function registered _and_ buttons held *
00340              down, call motion function...  */
00341           if (window->motion && event.xmotion.state &
00342             (Button1Mask | Button2Mask | Button3Mask)) {
00343             __glutSetWindow(window);
00344             window->motion(event.xmotion.x, event.xmotion.y);
00345           }
00346           /* If passive motion function registered _and_
00347              buttons not held down, call passive motion
00348              function...  */
00349           else if (window->passive &&
00350               ((event.xmotion.state &
00351                   (Button1Mask | Button2Mask | Button3Mask)) ==
00352               0)) {
00353             __glutSetWindow(window);
00354             window->passive(event.xmotion.x,
00355               event.xmotion.y);
00356           }
00357         }
00358       } else {
00359         /* Motion events are thrown away when a pop up menu is
00360            active. */
00361       }
00362       break;
00363     case KeyPress:
00364       window = __glutGetWindow(event.xkey.window);
00365       if (!window) {
00366         break;
00367       }
00368       if (window->keyboard) {
00369         char tmp[1];
00370         int rc;
00371 
00372         rc = XLookupString(&event.xkey, tmp, sizeof(tmp),
00373           NULL, NULL);
00374         if (rc) {
00375           __glutSetWindow(window);
00376           __glutModifierMask = event.xkey.state;
00377           window->keyboard(tmp[0],
00378             event.xkey.x, event.xkey.y);
00379           __glutModifierMask = ~0;
00380           break;
00381         }
00382       }
00383       if (window->special) {
00384         KeySym ks;
00385         int key;
00386 
00387         ks = XLookupKeysym((XKeyEvent *) & event, 0);
00388         /* XXX Verbose, but makes no assumptions about keysym
00389            layout. */
00390         switch (ks) {
00391           /* function keys */
00392           case XK_F1:    key = GLUT_KEY_F1; break;
00393           case XK_F2:    key = GLUT_KEY_F2; break;
00394           case XK_F3:    key = GLUT_KEY_F3; break;
00395           case XK_F4:    key = GLUT_KEY_F4; break;
00396           case XK_F5:    key = GLUT_KEY_F5; break;
00397           case XK_F6:    key = GLUT_KEY_F6; break;
00398           case XK_F7:    key = GLUT_KEY_F7; break;
00399           case XK_F8:    key = GLUT_KEY_F8; break;
00400           case XK_F9:    key = GLUT_KEY_F9; break;
00401           case XK_F10:   key = GLUT_KEY_F10; break;
00402           case XK_F11:   key = GLUT_KEY_F11; break;
00403           case XK_F12:   key = GLUT_KEY_F12; break;
00404           /* directional keys */
00405           case XK_Left:  key = GLUT_KEY_LEFT; break;
00406           case XK_Up:    key = GLUT_KEY_UP; break;
00407           case XK_Right: key = GLUT_KEY_RIGHT; break;
00408           case XK_Down:  key = GLUT_KEY_DOWN; break;
00409         case XK_Prior:
00410           /* XK_Prior same as X11R6's XK_Page_Up */
00411           key = GLUT_KEY_PAGE_UP;
00412           break;
00413         case XK_Next:
00414           /* XK_Next same as X11R6's XK_Page_Down */
00415           key = GLUT_KEY_PAGE_DOWN;
00416           break;
00417         case XK_Home:
00418           key = GLUT_KEY_HOME;
00419           break;
00420         case XK_End:
00421 #ifdef __hpux
00422         case XK_Select:
00423 #endif
00424           key = GLUT_KEY_END;
00425           break;
00426         case XK_Insert:
00427 #ifdef __hpux
00428         case XK_InsertChar:
00429 #endif
00430           key = GLUT_KEY_INSERT;
00431           break;
00432 #ifdef __hpux
00433         case XK_DeleteChar:
00434           /* The Delete character is really an ASCII key. */
00435           __glutSetWindow(window);
00436           window->keyboard(127, /* ASCII Delete character. */
00437             event.xkey.x, event.xkey.y);
00438           goto skip;
00439 #endif
00440         default:
00441           goto skip;
00442         }
00443         __glutSetWindow(window);
00444         __glutModifierMask = event.xkey.state;
00445         window->special(key, event.xkey.x, event.xkey.y);
00446         __glutModifierMask = ~0;
00447       skip:;
00448       }
00449       break;
00450     case EnterNotify:
00451     case LeaveNotify:
00452       if (event.xcrossing.mode != NotifyNormal ||
00453         event.xcrossing.detail == NotifyNonlinearVirtual ||
00454         event.xcrossing.detail == NotifyVirtual) {
00455 
00456         /* Careful to ignore Enter/LeaveNotify events that come
00457            from the pop-up menu pointer grab and ungrab.  Also,
00458            ignore "virtual" Enter/LeaveNotify events since they
00459            represent the pointer passing through the window
00460            hierarchy without actually entering or leaving the
00461            actual real estate of a window.  */
00462 
00463         break;
00464       }
00465       if (__glutMappedMenu) {
00466         GLUTmenuItem *item;
00467         int num;
00468 
00469         item = __glutGetMenuItem(__glutMappedMenu,
00470           event.xcrossing.window, &num);
00471         if (item) {
00472           __glutMenuItemEnterOrLeave(item, num, event.type);
00473           break;
00474         }
00475       }
00476       window = __glutGetWindow(event.xcrossing.window);
00477       if (window) {
00478         if (window->entry) {
00479           if (event.type == EnterNotify) {
00480 
00481             /* With overlays established, X can report two
00482                enter events for both the overlay and normal
00483                plane window. Do not generate a second enter
00484                callback if we reported one without an
00485                intervening leave. */
00486 
00487             if (window->entryState != EnterNotify) {
00488               int num = window->num;
00489               Window xid = window->win;
00490 
00491               window->entryState = EnterNotify;
00492               __glutSetWindow(window);
00493               window->entry(GLUT_ENTERED);
00494 
00495               if (__glutMappedMenu) {
00496 
00497                 /* Do not generate any passive motion events
00498                    when menus are in use. */
00499 
00500               } else {
00501 
00502                 /* An EnterNotify event can result in a
00503                    "compound" callback if a passive motion
00504                    callback is also registered. In this case,
00505                    be a little paranoid about the possibility
00506                    the window could have been destroyed in the
00507                    entry callback. */
00508 
00509                 window = __glutWindowList[num];
00510                 if (window && window->passive && window->win == xid) {
00511                   __glutSetWindow(window);
00512                   window->passive(event.xcrossing.x, event.xcrossing.y);
00513                 }
00514               }
00515             }
00516           } else {
00517             if (window->entryState != LeaveNotify) {
00518 
00519               /* When an overlay is established for a window
00520                  already mapped and with the pointer in it, the
00521                  X server will generate a leave/enter event pair
00522                  as the pointer leaves (without moving) from the
00523                  normal plane X window to the newly mapped
00524                  overlay  X window (or vice versa). This
00525                  enter/leave pair should not be reported to the
00526                  GLUT program since the pair is a consequence of
00527                  creating (or destroying) the overlay, not an
00528                  actual leave from the GLUT window. */
00529 
00530               if (XEventsQueued(__glutDisplay, QueuedAfterReading)) {
00531                 XPeekEvent(__glutDisplay, &ahead);
00532                 if (ahead.type == EnterNotify &&
00533                   __glutGetWindow(ahead.xcrossing.window) == window) {
00534                   XNextEvent(__glutDisplay, &event);
00535                   break;
00536                 }
00537               }
00538               window->entryState = LeaveNotify;
00539               __glutSetWindow(window);
00540               window->entry(GLUT_LEFT);
00541             }
00542           }
00543         } else if (window->passive) {
00544           __glutSetWindow(window);
00545           window->passive(event.xcrossing.x, event.xcrossing.y);
00546         }
00547       }
00548       break;
00549     case UnmapNotify:
00550       /* MapNotify events are not needed to maintain visibility
00551          state since VisibilityNotify events will be delivered
00552          when a window becomes visible from mapping.  However,
00553          VisibilityNotify events are not delivered when a window
00554          is unmapped (for the window or its children). */
00555       window = __glutGetWindow(event.xunmap.window);
00556       if (window) {
00557         if (window->win != event.xconfigure.window) {
00558           /* Ignore UnmapNotify sent to the overlay planes.
00559              GLUT could get here because overlays select for
00560              StructureNotify events to receive DestroyNotify. */
00561           break;
00562         }
00563         updateWindowVisibility(window, 0);
00564       }
00565       break;
00566     case VisibilityNotify:
00567       window = __glutGetWindow(event.xvisibility.window);
00568       if (window) {
00569         int visState = (event.xvisibility.state != VisibilityFullyObscured);
00570 
00571         if (visState != window->visState) {
00572           if (window->visibility) {
00573             window->visState = visState;
00574             __glutSetWindow(window);
00575             window->visibility(visState ? GLUT_VISIBLE : GLUT_NOT_VISIBLE);
00576           }
00577         }
00578       }
00579       break;
00580     case ClientMessage:
00581       if (event.xclient.data.l[0] == __glutWMDeleteWindow)
00582         exit(0);
00583       break;
00584     case DestroyNotify:
00585       purgeStaleWindow(event.xdestroywindow.window);
00586       break;
00587     case CirculateNotify:
00588     case CreateNotify:
00589     case GravityNotify:
00590     case ReparentNotify:
00591       /* Uninteresting to GLUT (but possible for GLUT to
00592          receive). */
00593       break;
00594     default:
00595       /* Pass events not directly handled by the GLUT main
00596          event loop to any event parsers that have been
00597          registered.  In this way, X Input extension events are
00598          passed to the correct handler without forcing all GLUT
00599          programs to support X Input event handling. */
00600       parser = eventParserList;
00601       while (parser) {
00602         if (parser->func(&event))
00603           break;
00604         parser = parser->next;
00605       }
00606       break;
00607     }
00608   }
00609   while (XPending(__glutDisplay));
00610 }
00611 
00612 static void
00613 waitForSomething(void)
00614 {
00615 #ifdef __vms
00616   static struct timeval zerotime = {0};
00617   unsigned int timer_efn;
00618 #define timer_id 'glut'           /* random :-) number */
00619   unsigned int wait_mask;
00620 #else
00621   static struct timeval zerotime = {0, 0};
00622   fd_set fds;
00623 #endif
00624   struct timeval now, timeout, waittime;
00625   int rc;
00626 
00627   /* flush X protocol since XPending does not do this
00628      implicitly */
00629   XFlush(__glutDisplay);
00630   if (XPending(__glutDisplay)) {
00631     /* It is possible (but quite rare) that XFlush may have
00632        needed to wait for a writable X connection file
00633        descriptor, and in the process, may have had to read off
00634        X protocol from the file descriptor. If XPending is true,
00635        this case occured and we should avoid waiting in select
00636        since X protocol buffered within Xlib is due to be
00637        processed and potentially no more X protocol is on the
00638        file descriptor, so we would risk waiting improperly in
00639        select. */
00640     goto immediatelyHandleXinput;
00641   }
00642 #ifdef __vms
00643   timeout = __glutTimerList->timeout;
00644   GETTIMEOFDAY(&now);
00645   wait_mask = 1 << (__glutConnectionFD & 31);
00646   if (IS_AFTER(now, timeout)) {
00647     /* We need an event flag for the timer. */
00648     /* XXX The `right' way to do this is to use LIB$GET_EF, but since it needs
00649        to be in the same cluster as the EFN for the display, we will have
00650        hack it. */
00651     timer_efn = __glutConnectionFD - 1;
00652     if ((timer_efn / 32) != (__glutConnectionFD / 32) ) {
00653       timer_efn = __glutConnectionFD + 1;
00654     }
00655     rc = SYS$CLREF (timer_efn);
00656     rc = SYS$SETIMR (timer_efn, &timeout, NULL, timer_id, 0);
00657     wait_mask |= 1 << (timer_efn & 31);
00658   } else {
00659     timer_efn = 0;
00660   }
00661   rc = SYS$WFLOR (__glutConnectionFD, wait_mask);
00662   if (timer_efn != 0 && SYS$CLREF (timer_efn) == SS$_WASCLR) {
00663     rc = SYS$CANTIM (timer_id, PSL$C_USER);
00664   }
00665   /* XXX There does not seem to be checking of "rc" in the code
00666      above.  Can any of the SYS$ routines above fail? */
00667 #else /* not vms */
00668   FD_ZERO(&fds);
00669   FD_SET(__glutConnectionFD, &fds);
00670   timeout = __glutTimerList->timeout;
00671   GETTIMEOFDAY(&now);
00672   if (IS_AFTER(now, timeout)) {
00673     TIMEDELTA(waittime, timeout, now);
00674   } else {
00675     waittime = zerotime;
00676   }
00677   rc = select(__glutConnectionFD + 1, &fds,
00678     NULL, NULL, &waittime);
00679   if (rc < 0 && errno != EINTR)
00680     __glutFatalError("select error.");
00681 #endif /* not vms */
00682   /* Without considering the cause of select unblocking, check
00683      for pending X events *and* then handle any timeouts. We
00684      always look for X events even if select returned with 0
00685      (indicating a timeout); otherwise we risk starving X event
00686      processing by continous timeouts. */
00687   while (XPending(__glutDisplay)) {
00688   immediatelyHandleXinput:
00689     processEvents();
00690   }
00691   handleTimeouts();
00692 }
00693 
00694 static void
00695 idleWait(void)
00696 {
00697   while (XPending(__glutDisplay)) {
00698     processEvents();
00699   }
00700   if (__glutTimerList)
00701     handleTimeouts();
00702   /* Make sure idle func still exists! */
00703   if (__glutIdleFunc)
00704     __glutIdleFunc();
00705 }
00706 
00707 static GLUTwindow **beforeEnd;
00708 
00709 static GLUTwindow *
00710 processWindowWorkList(GLUTwindow * window)
00711 {
00712   int workMask;
00713 
00714   if (window->prevWorkWin)
00715     window->prevWorkWin = processWindowWorkList(window->prevWorkWin);
00716   else
00717     beforeEnd = &window->prevWorkWin;
00718 
00719   /* Capture work mask for work that needs to be done to this
00720      window, then clear the window's work mask (excepting the
00721      dummy work bit, see below).  Then, process the captured
00722      work mask.  This allows callbacks in the processing the
00723      captured work mask to set the window's work mask for
00724      subsequent processing. */
00725 
00726   workMask = window->workMask;
00727   assert((workMask & GLUT_DUMMY_WORK) == 0);
00728 
00729   /* Set the dummy work bit, clearing all other bits, to
00730      indicate that the window is currently on the window work
00731      list _and_ that the window's work mask is currently being
00732      processed.  This convinces __glutPutOnWorkList that this
00733      window is on the work list still. */
00734   window->workMask = GLUT_DUMMY_WORK;
00735 
00736   /* Optimization: most of the time, the work to do is a
00737      redisplay and not these other types of work.  Check for
00738      the following cases as a group to before checking each one 
00739      individually one by one. This saves about 25 MIPS
00740      instructions in the common redisplay only case. */
00741   if (workMask & (GLUT_EVENT_MASK_WORK | GLUT_DEVICE_MASK_WORK |
00742       GLUT_CONFIGURE_WORK | GLUT_COLORMAP_WORK | GLUT_MAP_WORK)) {
00743     /* Be sure to set event mask *BEFORE* map window is done. */
00744     if (workMask & GLUT_EVENT_MASK_WORK) {
00745       long eventMask;
00746 
00747       /* Make sure children are not propogating events this
00748          window is selecting for.  Be sure to do this before
00749          enabling events on the children's parent. */
00750       if (window->children) {
00751         GLUTwindow *child = window->children;
00752         unsigned long attribMask = CWDontPropagate;
00753         XSetWindowAttributes wa;
00754 
00755         wa.do_not_propagate_mask = window->eventMask & GLUT_DONT_PROPAGATE_FILTER_MASK;
00756         if (window->eventMask & GLUT_HACK_STOP_PROPAGATE_MASK) {
00757           wa.event_mask = child->eventMask | (window->eventMask & GLUT_HACK_STOP_PROPAGATE_MASK);
00758           attribMask |= CWEventMask;
00759         }
00760         do {
00761           XChangeWindowAttributes(__glutDisplay, child->win,
00762             attribMask, &wa);
00763           child = child->siblings;
00764         } while (child);
00765       }
00766       eventMask = window->eventMask;
00767       if (window->parent && window->parent->eventMask & GLUT_HACK_STOP_PROPAGATE_MASK)
00768         eventMask |= (window->parent->eventMask & GLUT_HACK_STOP_PROPAGATE_MASK);
00769       XSelectInput(__glutDisplay, window->win, eventMask);
00770 
00771       if (window->overlay)
00772         XSelectInput(__glutDisplay, window->overlay->win,
00773           window->eventMask & GLUT_OVERLAY_EVENT_FILTER_MASK);
00774     }
00775     /* Be sure to set device mask *BEFORE* map window is done. */
00776     if (workMask & GLUT_DEVICE_MASK_WORK) {
00777       __glutUpdateInputDeviceMaskFunc(window);
00778     }
00779     /* Be sure to configure window *BEFORE* map window is done. 
00780      */
00781     if (workMask & GLUT_CONFIGURE_WORK) {
00782       XWindowChanges changes;
00783 
00784       changes.x = window->desiredX;
00785       changes.y = window->desiredY;
00786       if (window->desiredConfMask & (CWWidth | CWHeight)) {
00787         changes.width = window->desiredWidth;
00788         changes.height = window->desiredHeight;
00789         if (window->overlay)
00790           XResizeWindow(__glutDisplay, window->overlay->win,
00791             window->desiredWidth, window->desiredHeight);
00792         if (__glutMotifHints != None) {
00793           if (workMask & GLUT_FULL_SCREEN_WORK) {
00794             MotifWmHints hints;
00795 
00796             hints.flags = MWM_HINTS_DECORATIONS;
00797             hints.decorations = 0;  /* Absolutely no
00798                                        decorations. */
00799             XChangeProperty(__glutDisplay, window->win,
00800               __glutMotifHints, __glutMotifHints, 32,
00801               PropModeReplace, (unsigned char *) &hints, 4);
00802           } else {
00803             XDeleteProperty(__glutDisplay, window->win, __glutMotifHints);
00804           }
00805         }
00806       }
00807       if (window->desiredConfMask & CWStackMode) {
00808         changes.stack_mode = window->desiredStack;
00809         /* Do not let glutPushWindow push window beneath the
00810            underlay. */
00811         if (window->parent && window->parent->overlay && window->desiredStack == Below) {
00812           changes.stack_mode = Above;
00813           changes.sibling = window->parent->overlay->win;
00814           window->desiredConfMask |= CWSibling;
00815         }
00816       }
00817       XConfigureWindow(__glutDisplay, window->win,
00818         window->desiredConfMask, &changes);
00819       window->desiredConfMask = 0;
00820     }
00821     /* Be sure to establish the colormaps *BEFORE* map window
00822        is done. */
00823     if (workMask & GLUT_COLORMAP_WORK) {
00824       __glutEstablishColormapsProperty(window);
00825     }
00826     if (workMask & GLUT_MAP_WORK) {
00827       switch (window->desiredMapState) {
00828       case WithdrawnState:
00829         if (window->parent) {
00830           XUnmapWindow(__glutDisplay, window->win);
00831         } else {
00832           XWithdrawWindow(__glutDisplay, window->win,
00833             __glutScreen);
00834         }
00835         window->shownState = 0;
00836         break;
00837       case NormalState:
00838         XMapWindow(__glutDisplay, window->win);
00839         window->shownState = 1;
00840         break;
00841       case IconicState:
00842         XIconifyWindow(__glutDisplay, window->win, __glutScreen);
00843         window->shownState = 0;
00844         break;
00845       }
00846     }
00847   }
00848   if (workMask & (GLUT_REDISPLAY_WORK | GLUT_OVERLAY_REDISPLAY_WORK)) {
00849     if (window->forceReshape) {
00850       /* Guarantee that before a display callback is generated
00851          for a window, a reshape callback must be generated. */
00852       __glutSetWindow(window);
00853       window->reshape(window->width, window->height);
00854       window->forceReshape = False;
00855     }
00856     /* The code below is more involved than otherwise necessary
00857        because it is paranoid about the overlay or entire window
00858        being removed or destroyed in the course of the callbacks.
00859        Notice how the global __glutWindowDamaged is used to
00860        record the layers' damage status.  See the code in
00861        glutLayerGet for how __glutWindowDamaged is used. The 
00862        point is to not have to update the "damaged" field after 
00863        the callback since the window (or overlay) may be
00864        destroyed (or removed) when the callback returns. */
00865 
00866     if (window->overlay && window->overlay->display) {
00867       int num = window->num;
00868       Window xid = window->overlay ? window->overlay->win : None;
00869 
00870       /* If an overlay display callback is registered, we
00871          differentiate between a redisplay needed for the
00872          overlay and/or normal plane.  If there is no overlay
00873          display callback registered, we simply use the
00874          standard display callback. */
00875 
00876       if (workMask & GLUT_REDISPLAY_WORK) {
00877 
00878         /* Render to normal plane. */
00879         window->renderWin = window->win;
00880         window->renderCtx = window->ctx;
00881         __glutWindowDamaged = window->damaged;
00882         window->damaged = 0;
00883         __glutSetWindow(window);
00884         window->display();
00885         __glutWindowDamaged = 0;
00886       }
00887       if (workMask & GLUT_OVERLAY_REDISPLAY_WORK) {
00888         window = __glutWindowList[num];
00889         if (window && window->overlay &&
00890           window->overlay->win == xid && window->overlay->display) {
00891 
00892           /* Render to overlay. */
00893           window->renderWin = window->overlay->win;
00894           window->renderCtx = window->overlay->ctx;
00895           __glutWindowDamaged = window->overlay->damaged;
00896           window->overlay->damaged = 0;
00897           __glutSetWindow(window);
00898           window->overlay->display();
00899           __glutWindowDamaged = 0;
00900         } else {
00901           /* Overlay may have since been destroyed or the
00902              overlay callback may have been disabled during
00903              normal display callback. */
00904         }
00905       }
00906     } else {
00907       __glutWindowDamaged = window->damaged;
00908       window->damaged = 0;
00909       if (window->overlay) {
00910         __glutWindowDamaged |= window->overlay->damaged;
00911         window->overlay->damaged = 0;
00912       }
00913       __glutSetWindow(window);
00914       window->display();
00915       __glutWindowDamaged = 0;
00916     }
00917   }
00918   /* Combine workMask with window->workMask to determine what
00919      finish and debug work there is. */
00920   workMask |= window->workMask;
00921 
00922   if (workMask & GLUT_FINISH_WORK) {
00923     __glutSetWindow(window);
00924     glFinish();
00925   }
00926   if (workMask & GLUT_DEBUG_WORK) {
00927     GLenum error;
00928 
00929     __glutSetWindow(window);
00930     while ((error = glGetError()) != GL_NO_ERROR)
00931       __glutWarning("GL error: %s", gluErrorString(error));
00932   }
00933   /* Strip out dummy, finish, and debug work bits. */
00934   window->workMask &= ~(GLUT_DUMMY_WORK | GLUT_FINISH_WORK | GLUT_DEBUG_WORK);
00935   if (window->workMask) {
00936     /* Leave on work list. */
00937     return window;
00938   } else {
00939     /* Remove current window from work list. */
00940     return window->prevWorkWin;
00941   }
00942 }
00943 
00944 void
00945 glutMainLoop(void)
00946 {
00947   if (!__glutDisplay)
00948     __glutFatalUsage("main loop entered with out X connection.");
00949   if (!__glutWindowListSize)
00950     __glutFatalUsage(
00951       "main loop entered with no windows created.");
00952   for (;;) {
00953     if (__glutWindowWorkList) {
00954       GLUTwindow *remainder, *work;
00955 
00956       work = __glutWindowWorkList;
00957       __glutWindowWorkList = NULL;
00958       if (work) {
00959         remainder = processWindowWorkList(work);
00960         if (remainder) {
00961           *beforeEnd = __glutWindowWorkList;
00962           __glutWindowWorkList = remainder;
00963         }
00964       }
00965     }
00966     if (__glutIdleFunc || __glutWindowWorkList) {
00967       idleWait();
00968     } else {
00969       if (__glutTimerList) {
00970         waitForSomething();
00971       } else {
00972         processEvents();
00973       }
00974     }
00975   }
00976 }
 

Powered by Plone

This site conforms to the following standards: