summaryrefslogtreecommitdiffstats
path: root/src/glut/os2/glut_event.cpp
diff options
context:
space:
mode:
authorJosé Fonseca <[email protected]>2008-02-28 16:34:32 +0900
committerJosé Fonseca <[email protected]>2008-02-28 16:34:32 +0900
commit60159c1b09c73c19f798035a15d4ef3b434f2fa0 (patch)
treedc2afed450f50c071249a431e6bb7cd876d0bbf3 /src/glut/os2/glut_event.cpp
parent90a036b337fc41c25ee6ff89eb9422efd3d9f110 (diff)
Convert crlf->lf line endings.
Windows/DOS users should enable core.autocrlf from now on: git config --global core.autocrlf true
Diffstat (limited to 'src/glut/os2/glut_event.cpp')
-rw-r--r--src/glut/os2/glut_event.cpp2798
1 files changed, 1399 insertions, 1399 deletions
diff --git a/src/glut/os2/glut_event.cpp b/src/glut/os2/glut_event.cpp
index c556ef28265..4ece82e52b6 100644
--- a/src/glut/os2/glut_event.cpp
+++ b/src/glut/os2/glut_event.cpp
@@ -1,1399 +1,1399 @@
-/* glut_event.c */
-/* Copyright (c) Mark J. Kilgard, 1994, 1995, 1996, 1997, 1998. */
-
-/* This program is freely distributable without licensing fees
- and is provided without guarantee or warrantee expressed or
- implied. This program is -not- in the public domain. */
-
-#ifdef __VMS
-#include <GL/vms_x_fix.h>
-#endif
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <errno.h>
-#include <assert.h>
-#include <string.h> /* Some FD_ZERO macros use memset without
- prototyping memset. */
-
-/* Much of the following #ifdef logic to include the proper
- prototypes for the select system call is based on logic
- from the X11R6.3 version of <X11/Xpoll.h>. */
-
-#if !defined(_WIN32)
-# ifdef __sgi
-# include <bstring.h> /* prototype for bzero used by FD_ZERO */
-# endif
-# if (defined(SVR4) || defined(CRAY) || defined(AIXV3)) && !defined(FD_SETSIZE)
-# include <sys/select.h> /* select system call interface */
-# ifdef luna
-# include <sysent.h>
-# endif
-# endif
- /* AIX 4.2 fubar-ed <sys/select.h>, so go to heroic measures to get it */
-# if defined(AIXV4) && !defined(NFDBITS)
-# include <sys/select.h>
-# endif
-#endif /* !_WIN32 */
-
-#include <sys/types.h>
-
-#if defined(__OS2__)
-//??? ��䨣� ?? # include <sys/time.h>
-#elif !defined(_WIN32)
-# if defined(__vms) && ( __VMS_VER < 70000000 )
-# include <sys/time.h>
-# else
-# ifndef __vms
-# include <sys/time.h>
-# endif
-# endif
-# include <unistd.h>
-# include <X11/Xlib.h>
-# include <X11/keysym.h>
-#else
-# ifdef __CYGWIN32__
-# include <sys/time.h>
-# else
-# include <sys/timeb.h>
-# endif
-# ifdef __hpux
- /* XXX Bert Gijsbers <[email protected]> reports that HP-UX
- needs different keysyms for the End, Insert, and Delete keys
- to work on an HP 715. It would be better if HP generated
- standard keysyms for standard keys. */
-# include <X11/HPkeysym.h>
-# endif
-#endif /* !_WIN32 */
-
-#include "glutint.h"
-
-#if defined(__vms) && ( __VMS_VER < 70000000 )
-#include <ssdef.h>
-#include <psldef.h>
-extern int SYS$CLREF(int efn);
-extern int SYS$SETIMR(unsigned int efn, struct timeval6 *timeout, void *ast,
- unsigned int request_id, unsigned int flags);
-extern int SYS$WFLOR(unsigned int efn, unsigned int mask);
-extern int SYS$CANTIM(unsigned int request_id, unsigned int mode);
-#endif /* __vms, VMs 6.2 or earlier */
-
-static GLUTtimer *freeTimerList = NULL;
-
-GLUTidleCB __glutIdleFunc = NULL;
-GLUTtimer *__glutTimerList = NULL;
-#ifdef SUPPORT_FORTRAN
-GLUTtimer *__glutNewTimer;
-#endif
-GLUTwindow *__glutWindowWorkList = NULL;
-GLUTmenu *__glutMappedMenu;
-GLUTmenu *__glutCurrentMenu = NULL;
-
-void (*__glutUpdateInputDeviceMaskFunc) (GLUTwindow *);
-#if !defined(_WIN32) && !defined(__OS2__)
-void (*__glutMenuItemEnterOrLeave)(GLUTmenuItem * item, int num, int type) = NULL;
-void (*__glutFinishMenu)(Window win, int x, int y);
-void (*__glutPaintMenu)(GLUTmenu * menu);
-void (*__glutStartMenu)(GLUTmenu * menu, GLUTwindow * window, int x, int y, int x_win, int y_win);
-GLUTmenu * (*__glutGetMenuByNum)(int menunum);
-GLUTmenuItem * (*__glutGetMenuItem)(GLUTmenu * menu, Window win, int *which);
-GLUTmenu * (*__glutGetMenu)(Window win);
-#endif
-
-Atom __glutMotifHints = None;
-/* Modifier mask of ~0 implies not in core input callback. */
-unsigned int __glutModifierMask = (unsigned int) ~0;
-int __glutWindowDamaged = 0;
-
-void GLUTAPIENTRY
-glutIdleFunc(GLUTidleCB idleFunc)
-{
- __glutIdleFunc = idleFunc;
-}
-
-void GLUTAPIENTRY
-glutTimerFunc(unsigned int interval, GLUTtimerCB timerFunc, int value)
-{
- GLUTtimer *timer, *other;
- GLUTtimer **prevptr;
-#ifdef OLD_VMS
- struct timeval6 now;
-#else
- struct timeval now;
-#endif
-
- if (!timerFunc)
- return;
-
- if (freeTimerList) {
- timer = freeTimerList;
- freeTimerList = timer->next;
- } else {
- timer = (GLUTtimer *) malloc(sizeof(GLUTtimer));
- if (!timer)
- __glutFatalError("out of memory.");
- }
-
- timer->func = timerFunc;
-#if defined(__vms) && ( __VMS_VER < 70000000 )
- /* VMS time is expressed in units of 100 ns */
- timer->timeout.val = interval * TICKS_PER_MILLISECOND;
-#else
- timer->timeout.tv_sec = (int) interval / 1000;
- timer->timeout.tv_usec = (int) (interval % 1000) * 1000;
-#endif
- timer->value = value;
- timer->next = NULL;
- GETTIMEOFDAY(&now);
- ADD_TIME(timer->timeout, timer->timeout, now);
- prevptr = &__glutTimerList;
- other = *prevptr;
- while (other && IS_AFTER(other->timeout, timer->timeout)) {
- prevptr = &other->next;
- other = *prevptr;
- }
- timer->next = other;
-#ifdef SUPPORT_FORTRAN
- __glutNewTimer = timer; /* for Fortran binding! */
-#endif
- *prevptr = timer;
-}
-
-void
-handleTimeouts(void)
-{
-#ifdef OLD_VMS
- struct timeval6 now;
-#else
- struct timeval now;
-#endif
- GLUTtimer *timer;
-
- /* Assumption is that __glutTimerList is already determined
- to be non-NULL. */
- GETTIMEOFDAY(&now);
- while (IS_AT_OR_AFTER(__glutTimerList->timeout, now)) {
- timer = __glutTimerList;
- timer->func(timer->value);
- __glutTimerList = timer->next;
- timer->next = freeTimerList;
- freeTimerList = timer;
- if (!__glutTimerList)
- break;
- }
-}
-
-void
-__glutPutOnWorkList(GLUTwindow * window, int workMask)
-{
- if (window->workMask) {
- /* Already on list; just OR in new workMask. */
- window->workMask |= workMask;
- } else {
- /* Update work mask and add to window work list. */
- window->workMask = workMask;
- /* Assert that if the window does not have a
- workMask already, the window should definitely
- not be the head of the work list. */
- assert(window != __glutWindowWorkList);
- window->prevWorkWin = __glutWindowWorkList;
- __glutWindowWorkList = window;
- }
-}
-
-void
-__glutPostRedisplay(GLUTwindow * window, int layerMask)
-{
- int shown = (layerMask & (GLUT_REDISPLAY_WORK | GLUT_REPAIR_WORK)) ?
- window->shownState : window->overlay->shownState;
-
- /* Post a redisplay if the window is visible (or the
- visibility of the window is unknown, ie. window->visState
- == -1) _and_ the layer is known to be shown. */
- if (window->visState != GLUT_HIDDEN
- && window->visState != GLUT_FULLY_COVERED && shown) {
- __glutPutOnWorkList(window, layerMask);
- }
-}
-
-/* CENTRY */
-void GLUTAPIENTRY
-glutPostRedisplay(void)
-{
- __glutPostRedisplay(__glutCurrentWindow, GLUT_REDISPLAY_WORK);
-}
-
-/* The advantage of this routine is that it saves the cost of a
- glutSetWindow call (entailing an expensive OpenGL context switch),
- particularly useful when multiple windows need redisplays posted at
- the same times. See also glutPostWindowOverlayRedisplay. */
-void GLUTAPIENTRY
-glutPostWindowRedisplay(int win)
-{
- __glutPostRedisplay(__glutWindowList[win - 1], GLUT_REDISPLAY_WORK);
-}
-
-/* ENDCENTRY */
-static GLUTeventParser *eventParserList = NULL;
-
-/* __glutRegisterEventParser allows another module to register
- to intercept X events types not otherwise acted on by the
- GLUT processEventsAndTimeouts routine. The X Input
- extension support code uses an event parser for handling X
- Input extension events. */
-
-void
-__glutRegisterEventParser(GLUTeventParser * parser)
-{
- parser->next = eventParserList;
- eventParserList = parser;
-}
-
-static void
-markWindowHidden(GLUTwindow * window)
-{
- if (GLUT_HIDDEN != window->visState) {
- GLUTwindow *child;
-
- if (window->windowStatus) {
- window->visState = GLUT_HIDDEN;
- __glutSetWindow(window);
- window->windowStatus(GLUT_HIDDEN);
- }
- /* An unmap is only reported on a single window; its
- descendents need to know they are no longer visible. */
- child = window->children;
- while (child) {
- markWindowHidden(child);
- child = child->siblings;
- }
- }
-}
-
-#if !defined(_WIN32) && !defined(__OS2__)
-
-static void
-purgeStaleWindow(Window win)
-{
- GLUTstale **pEntry = &__glutStaleWindowList;
- GLUTstale *entry = __glutStaleWindowList;
-
- /* Tranverse singly-linked stale window list look for the
- window ID. */
- while (entry) {
- if (entry->win == win) {
- /* Found it; delete it. */
- *pEntry = entry->next;
- free(entry);
- return;
- } else {
- pEntry = &entry->next;
- entry = *pEntry;
- }
- }
-}
-
-/* Unlike XNextEvent, if a signal arrives,
- interruptibleXNextEvent will return (with a zero return
- value). This helps GLUT drop out of XNextEvent if a signal
- is delivered. The intent is so that a GLUT program can call
- glutIdleFunc in a signal handler to register an idle func
- and then immediately get dropped into the idle func (after
- returning from the signal handler). The idea is to make
- GLUT's main loop reliably interruptible by signals. */
-static int
-interruptibleXNextEvent(Display * dpy, XEvent * event)
-{
- fd_set fds;
- int rc;
-
- /* Flush X protocol since XPending does not do this
- implicitly. */
- XFlush(__glutDisplay);
- for (;;) {
- if (XPending(__glutDisplay)) {
- XNextEvent(dpy, event);
- return 1;
- }
-#ifndef VMS
- /* the combination ConectionNumber-select is buggy on VMS. Sometimes it
- * fails. This part of the code hangs the program on VMS7.2. But even
- * without it the program seems to run correctly.
- * Note that this is a bug in the VMS/DECWindows run-time-libraries.
- * Compaq engeneering does not want or is not able to make a fix.
- * (last sentence is a quotation from Compaq when I reported the
- * problem January 2000) */
- FD_ZERO(&fds);
- FD_SET(__glutConnectionFD, &fds);
- rc = select(__glutConnectionFD + 1, &fds, NULL, NULL, NULL);
- if (rc < 0) {
- if (errno == EINTR) {
- return 0;
- } else {
- __glutFatalError("select error.");
- }
- }
-#endif
- }
-}
-
-#endif
-
-static void
-processEventsAndTimeouts(void)
-{
- do {
-#if defined(__OS2__)
- QMSG qmsg; /* message from message queue */
- extern HAB hab; /* PM anchor block handle */
-
- if(! WinGetMsg( hab, &qmsg, 0UL, 0UL, 0UL ) )
- exit(0);
- WinDispatchMsg( hab, /* PM anchor block handle */
- &qmsg ); /* pointer to message */
-
-#elif defined(_WIN32)
- MSG event;
-
- if(!GetMessage(&event, NULL, 0, 0)) /* bail if no more messages */
- exit(0);
- TranslateMessage(&event); /* translate virtual-key messages */
- DispatchMessage(&event); /* call the window proc */
- /* see win32_event.c for event (message) processing procedures */
-#else
- static int mappedMenuButton;
- GLUTeventParser *parser;
- XEvent event, ahead;
- GLUTwindow *window;
- GLUTkeyboardCB keyboard;
- GLUTspecialCB special;
- int gotEvent, width, height;
-
- gotEvent = interruptibleXNextEvent(__glutDisplay, &event);
- if (gotEvent) {
- switch (event.type) {
- case MappingNotify:
- XRefreshKeyboardMapping((XMappingEvent *) & event);
- break;
- case ConfigureNotify:
- window = __glutGetWindow(event.xconfigure.window);
- if (window) {
- if (window->win != event.xconfigure.window) {
- /* Ignore ConfigureNotify sent to the overlay
- planes. GLUT could get here because overlays
- select for StructureNotify events to receive
- DestroyNotify. */
- break;
- }
- width = event.xconfigure.width;
- height = event.xconfigure.height;
- if (width != window->width || height != window->height) {
- if (window->overlay) {
- XResizeWindow(__glutDisplay, window->overlay->win, width, height);
- }
- window->width = width;
- window->height = height;
- __glutSetWindow(window);
- /* Do not execute OpenGL out of sequence with
- respect to the XResizeWindow request! */
- glXWaitX();
- window->reshape(width, height);
- window->forceReshape = False;
- /* A reshape should be considered like posting a
- repair; this is necessary for the "Mesa
- glXSwapBuffers to repair damage" hack to operate
- correctly. Without it, there's not an initial
- back buffer render from which to blit from when
- damage happens to the window. */
- __glutPostRedisplay(window, GLUT_REPAIR_WORK);
- }
- }
- break;
- case Expose:
- /* compress expose events */
- while (XEventsQueued(__glutDisplay, QueuedAfterReading)
- > 0) {
- XPeekEvent(__glutDisplay, &ahead);
- if (ahead.type != Expose ||
- ahead.xexpose.window != event.xexpose.window) {
- break;
- }
- XNextEvent(__glutDisplay, &event);
- }
- if (event.xexpose.count == 0) {
- GLUTmenu *menu;
-
- if (__glutMappedMenu &&
- (menu = __glutGetMenu(event.xexpose.window))) {
- __glutPaintMenu(menu);
- } else {
- window = __glutGetWindow(event.xexpose.window);
- if (window) {
- if (window->win == event.xexpose.window) {
- __glutPostRedisplay(window, GLUT_REPAIR_WORK);
- } else if (window->overlay && window->overlay->win == event.xexpose.window) {
- __glutPostRedisplay(window, GLUT_OVERLAY_REPAIR_WORK);
- }
- }
- }
- } else {
- /* there are more exposes to read; wait to redisplay */
- }
- break;
- case ButtonPress:
- case ButtonRelease:
- if (__glutMappedMenu && event.type == ButtonRelease
- && mappedMenuButton == event.xbutton.button) {
- /* Menu is currently popped up and its button is
- released. */
- __glutFinishMenu(event.xbutton.window, event.xbutton.x, event.xbutton.y);
- } else {
- window = __glutGetWindow(event.xbutton.window);
- if (window) {
- GLUTmenu *menu;
- int menuNum;
-
- menuNum = window->menu[event.xbutton.button - 1];
- /* Make sure that __glutGetMenuByNum is only called if there
- really is a menu present. */
- if ((menuNum > 0) && (menu = __glutGetMenuByNum(menuNum))) {
- if (event.type == ButtonPress && !__glutMappedMenu) {
- __glutStartMenu(menu, window,
- event.xbutton.x_root, event.xbutton.y_root,
- event.xbutton.x, event.xbutton.y);
- mappedMenuButton = event.xbutton.button;
- } else {
- /* Ignore a release of a button with a menu
- attatched to it when no menu is popped up,
- or ignore a press when another menu is
- already popped up. */
- }
- } else if (window->mouse) {
- __glutSetWindow(window);
- __glutModifierMask = event.xbutton.state;
- window->mouse(event.xbutton.button - 1,
- event.type == ButtonRelease ?
- GLUT_UP : GLUT_DOWN,
- event.xbutton.x, event.xbutton.y);
- __glutModifierMask = ~0;
- } else {
- /* Stray mouse events. Ignore. */
- }
- } else {
- /* Window might have been destroyed and all the
- events for the window may not yet be received. */
- }
- }
- break;
- case MotionNotify:
- if (!__glutMappedMenu) {
- window = __glutGetWindow(event.xmotion.window);
- if (window) {
- /* If motion function registered _and_ buttons held
- * down, call motion function... */
- if (window->motion && event.xmotion.state &
- (Button1Mask | Button2Mask | Button3Mask)) {
- __glutSetWindow(window);
- window->motion(event.xmotion.x, event.xmotion.y);
- }
- /* If passive motion function registered _and_
- buttons not held down, call passive motion
- function... */
- else if (window->passive &&
- ((event.xmotion.state &
- (Button1Mask | Button2Mask | Button3Mask)) ==
- 0)) {
- __glutSetWindow(window);
- window->passive(event.xmotion.x,
- event.xmotion.y);
- }
- }
- } else {
- /* Motion events are thrown away when a pop up menu
- is active. */
- }
- break;
- case KeyPress:
- case KeyRelease:
- window = __glutGetWindow(event.xkey.window);
- if (!window) {
- break;
- }
- if (event.type == KeyPress) {
- keyboard = window->keyboard;
- } else {
-
- /* If we are ignoring auto repeated keys for this window,
- check if the next event in the X event queue is a KeyPress
- for the exact same key (and at the exact same time) as the
- key being released. The X11 protocol will send auto
- repeated keys as such KeyRelease/KeyPress pairs. */
-
- if (window->ignoreKeyRepeat) {
- if (XEventsQueued(__glutDisplay, QueuedAfterReading)) {
- XPeekEvent(__glutDisplay, &ahead);
- if (ahead.type == KeyPress
- && ahead.xkey.window == event.xkey.window
- && ahead.xkey.keycode == event.xkey.keycode
- && ahead.xkey.time == event.xkey.time) {
- /* Pop off the repeated KeyPress and ignore
- the auto repeated KeyRelease/KeyPress pair. */
- XNextEvent(__glutDisplay, &event);
- break;
- }
- }
- }
- keyboard = window->keyboardUp;
- }
- if (keyboard) {
- char tmp[1];
- int rc;
-
- rc = XLookupString(&event.xkey, tmp, sizeof(tmp),
- NULL, NULL);
- if (rc) {
- __glutSetWindow(window);
- __glutModifierMask = event.xkey.state;
- keyboard(tmp[0],
- event.xkey.x, event.xkey.y);
- __glutModifierMask = ~0;
- break;
- }
- }
- if (event.type == KeyPress) {
- special = window->special;
- } else {
- special = window->specialUp;
- }
- if (special) {
- KeySym ks;
- int key;
-
-/* Introduced in X11R6: (Partial list of) Keypad Functions. Define
- in place in case compiling against an older pre-X11R6
- X11/keysymdef.h file. */
-#ifndef XK_KP_Home
-#define XK_KP_Home 0xFF95
-#endif
-#ifndef XK_KP_Left
-#define XK_KP_Left 0xFF96
-#endif
-#ifndef XK_KP_Up
-#define XK_KP_Up 0xFF97
-#endif
-#ifndef XK_KP_Right
-#define XK_KP_Right 0xFF98
-#endif
-#ifndef XK_KP_Down
-#define XK_KP_Down 0xFF99
-#endif
-#ifndef XK_KP_Prior
-#define XK_KP_Prior 0xFF9A
-#endif
-#ifndef XK_KP_Next
-#define XK_KP_Next 0xFF9B
-#endif
-#ifndef XK_KP_End
-#define XK_KP_End 0xFF9C
-#endif
-#ifndef XK_KP_Insert
-#define XK_KP_Insert 0xFF9E
-#endif
-#ifndef XK_KP_Delete
-#define XK_KP_Delete 0xFF9F
-#endif
-
- ks = XLookupKeysym((XKeyEvent *) & event, 0);
- /* XXX Verbose, but makes no assumptions about keysym
- layout. */
- switch (ks) {
-/* *INDENT-OFF* */
- /* function keys */
- case XK_F1: key = GLUT_KEY_F1; break;
- case XK_F2: key = GLUT_KEY_F2; break;
- case XK_F3: key = GLUT_KEY_F3; break;
- case XK_F4: key = GLUT_KEY_F4; break;
- case XK_F5: key = GLUT_KEY_F5; break;
- case XK_F6: key = GLUT_KEY_F6; break;
- case XK_F7: key = GLUT_KEY_F7; break;
- case XK_F8: key = GLUT_KEY_F8; break;
- case XK_F9: key = GLUT_KEY_F9; break;
- case XK_F10: key = GLUT_KEY_F10; break;
- case XK_F11: key = GLUT_KEY_F11; break;
- case XK_F12: key = GLUT_KEY_F12; break;
- /* directional keys */
- case XK_KP_Left:
- case XK_Left: key = GLUT_KEY_LEFT; break;
- case XK_KP_Up: /* Introduced in X11R6. */
- case XK_Up: key = GLUT_KEY_UP; break;
- case XK_KP_Right: /* Introduced in X11R6. */
- case XK_Right: key = GLUT_KEY_RIGHT; break;
- case XK_KP_Down: /* Introduced in X11R6. */
- case XK_Down: key = GLUT_KEY_DOWN; break;
-/* *INDENT-ON* */
-
- case XK_KP_Prior: /* Introduced in X11R6. */
- case XK_Prior:
- /* XK_Prior same as X11R6's XK_Page_Up */
- key = GLUT_KEY_PAGE_UP;
- break;
- case XK_KP_Next: /* Introduced in X11R6. */
- case XK_Next:
- /* XK_Next same as X11R6's XK_Page_Down */
- key = GLUT_KEY_PAGE_DOWN;
- break;
- case XK_KP_Home: /* Introduced in X11R6. */
- case XK_Home:
- key = GLUT_KEY_HOME;
- break;
-#ifdef __hpux
- case XK_Select:
-#endif
- case XK_KP_End: /* Introduced in X11R6. */
- case XK_End:
- key = GLUT_KEY_END;
- break;
-#ifdef __hpux
- case XK_InsertChar:
-#endif
- case XK_KP_Insert: /* Introduced in X11R6. */
- case XK_Insert:
- key = GLUT_KEY_INSERT;
- break;
-#ifdef __hpux
- case XK_DeleteChar:
-#endif
- case XK_KP_Delete: /* Introduced in X11R6. */
- /* The Delete character is really an ASCII key. */
- __glutSetWindow(window);
- keyboard(127, /* ASCII Delete character. */
- event.xkey.x, event.xkey.y);
- goto skip;
- default:
- goto skip;
- }
- __glutSetWindow(window);
- __glutModifierMask = event.xkey.state;
- special(key, event.xkey.x, event.xkey.y);
- __glutModifierMask = ~0;
- skip:;
- }
- break;
- case EnterNotify:
- case LeaveNotify:
- if (event.xcrossing.mode != NotifyNormal ||
- event.xcrossing.detail == NotifyNonlinearVirtual ||
- event.xcrossing.detail == NotifyVirtual) {
-
- /* Careful to ignore Enter/LeaveNotify events that
- come from the pop-up menu pointer grab and ungrab.
- Also, ignore "virtual" Enter/LeaveNotify events
- since they represent the pointer passing through
- the window hierarchy without actually entering or
- leaving the actual real estate of a window. */
-
- break;
- }
- if (__glutMappedMenu) {
- GLUTmenuItem *item;
- int num;
-
- item = __glutGetMenuItem(__glutMappedMenu,
- event.xcrossing.window, &num);
- if (item) {
- __glutMenuItemEnterOrLeave(item, num, event.type);
- break;
- }
- }
- window = __glutGetWindow(event.xcrossing.window);
- if (window) {
- if (window->entry) {
- if (event.type == EnterNotify) {
-
- /* With overlays established, X can report two
- enter events for both the overlay and normal
- plane window. Do not generate a second enter
- callback if we reported one without an
- intervening leave. */
-
- if (window->entryState != EnterNotify) {
- int num = window->num;
- Window xid = window->win;
-
- window->entryState = EnterNotify;
- __glutSetWindow(window);
- window->entry(GLUT_ENTERED);
-
- if (__glutMappedMenu) {
-
- /* Do not generate any passive motion events
- when menus are in use. */
-
- } else {
-
- /* An EnterNotify event can result in a
- "compound" callback if a passive motion
- callback is also registered. In this case,
- be a little paranoid about the possibility
- the window could have been destroyed in the
- entry callback. */
-
- window = __glutWindowList[num];
- if (window && window->passive && window->win == xid) {
- __glutSetWindow(window);
- window->passive(event.xcrossing.x, event.xcrossing.y);
- }
- }
- }
- } else {
- if (window->entryState != LeaveNotify) {
-
- /* When an overlay is established for a window
- already mapped and with the pointer in it,
- the X server will generate a leave/enter
- event pair as the pointer leaves (without
- moving) from the normal plane X window to
- the newly mapped overlay X window (or vice
- versa). This enter/leave pair should not be
- reported to the GLUT program since the pair
- is a consequence of creating (or destroying)
- the overlay, not an actual leave from the
- GLUT window. */
-
- if (XEventsQueued(__glutDisplay, QueuedAfterReading)) {
- XPeekEvent(__glutDisplay, &ahead);
- if (ahead.type == EnterNotify &&
- __glutGetWindow(ahead.xcrossing.window) == window) {
- XNextEvent(__glutDisplay, &event);
- break;
- }
- }
- window->entryState = LeaveNotify;
- __glutSetWindow(window);
- window->entry(GLUT_LEFT);
- }
- }
- } else if (window->passive) {
- __glutSetWindow(window);
- window->passive(event.xcrossing.x, event.xcrossing.y);
- }
- }
- break;
- case UnmapNotify:
- /* MapNotify events are not needed to maintain
- visibility state since VisibilityNotify events will
- be delivered when a window becomes visible from
- mapping. However, VisibilityNotify events are not
- delivered when a window is unmapped (for the window
- or its children). */
- window = __glutGetWindow(event.xunmap.window);
- if (window) {
- if (window->win != event.xconfigure.window) {
- /* Ignore UnmapNotify sent to the overlay planes.
- GLUT could get here because overlays select for
- StructureNotify events to receive DestroyNotify.
- */
- break;
- }
- markWindowHidden(window);
- }
- break;
- case VisibilityNotify:
- window = __glutGetWindow(event.xvisibility.window);
- if (window) {
- /* VisibilityUnobscured+1 = GLUT_FULLY_RETAINED,
- VisibilityPartiallyObscured+1 =
- GLUT_PARTIALLY_RETAINED, VisibilityFullyObscured+1
- = GLUT_FULLY_COVERED. */
- int visState = event.xvisibility.state + 1;
-
- if (visState != window->visState) {
- if (window->windowStatus) {
- window->visState = visState;
- __glutSetWindow(window);
- window->windowStatus(visState);
- }
- }
- }
- break;
- case ClientMessage:
- if (event.xclient.data.l[0] == __glutWMDeleteWindow)
- exit(0);
- break;
- case DestroyNotify:
- purgeStaleWindow(event.xdestroywindow.window);
- break;
- case CirculateNotify:
- case CreateNotify:
- case GravityNotify:
- case ReparentNotify:
- /* Uninteresting to GLUT (but possible for GLUT to
- receive). */
- break;
- default:
- /* Pass events not directly handled by the GLUT main
- event loop to any event parsers that have been
- registered. In this way, X Input extension events
- are passed to the correct handler without forcing
- all GLUT programs to support X Input event handling.
- */
- parser = eventParserList;
- while (parser) {
- if (parser->func(&event))
- break;
- parser = parser->next;
- }
- break;
- }
- }
-#endif /* _WIN32 */
- if (__glutTimerList) {
- handleTimeouts();
- }
- }
- while (XPending(__glutDisplay));
-}
-
-static void
-waitForSomething(void)
-{
-#if defined(__vms) && ( __VMS_VER < 70000000 )
- static struct timeval6 zerotime =
- {0};
- unsigned int timer_efn;
-#define timer_id 'glut' /* random :-) number */
- unsigned int wait_mask;
-#else
- static struct timeval zerotime =
- {0, 0};
-#if defined(__OS2__)
-
-#elif !defined(_WIN32)
- fd_set fds;
-#endif
-#endif
-#ifdef OLD_VMS
- struct timeval6 now, timeout, waittime;
-#else
- struct timeval now, timeout, waittime;
-#endif
-#if !defined(_WIN32)
- int rc;
-#endif
-
- /* Flush X protocol since XPending does not do this
- implicitly. */
- XFlush(__glutDisplay);
- if (XPending(__glutDisplay)) {
- /* It is possible (but quite rare) that XFlush may have
- needed to wait for a writable X connection file
- descriptor, and in the process, may have had to read off
- X protocol from the file descriptor. If XPending is true,
- this case occured and we should avoid waiting in select
- since X protocol buffered within Xlib is due to be
- processed and potentially no more X protocol is on the
- file descriptor, so we would risk waiting improperly in
- select. */
- goto immediatelyHandleXinput;
- }
-#if defined(__vms) && ( __VMS_VER < 70000000 )
- timeout = __glutTimerList->timeout;
- GETTIMEOFDAY(&now);
- wait_mask = 1 << (__glutConnectionFD & 31);
- if (IS_AFTER(now, timeout)) {
- /* We need an event flag for the timer. */
- /* XXX The `right' way to do this is to use LIB$GET_EF, but
- since it needs to be in the same cluster as the EFN for
- the display, we will have hack it. */
- timer_efn = __glutConnectionFD - 1;
- if ((timer_efn / 32) != (__glutConnectionFD / 32)) {
- timer_efn = __glutConnectionFD + 1;
- }
- rc = SYS$CLREF(timer_efn);
- rc = SYS$SETIMR(timer_efn, &timeout, NULL, timer_id, 0);
- wait_mask |= 1 << (timer_efn & 31);
- } else {
- timer_efn = 0;
- }
- rc = SYS$WFLOR(__glutConnectionFD, wait_mask);
- if (timer_efn != 0 && SYS$CLREF(timer_efn) == SS$_WASCLR) {
- rc = SYS$CANTIM(timer_id, PSL$C_USER);
- }
- /* XXX There does not seem to be checking of "rc" in the code
- above. Can any of the SYS$ routines above fail? */
-#else /* not vms6.2 or lower */
-#if defined(__OS2__)
-
-#elif !defined(_WIN32)
- FD_ZERO(&fds);
- FD_SET(__glutConnectionFD, &fds);
-#endif
- timeout = __glutTimerList->timeout;
- GETTIMEOFDAY(&now);
- if (IS_AFTER(now, timeout)) {
- TIMEDELTA(waittime, timeout, now);
- } else {
- waittime = zerotime;
- }
-
-#if defined(__OS2__)
- DosSleep(0);
-#elif !defined(_WIN32)
- rc = select(__glutConnectionFD + 1, &fds,
- NULL, NULL, &waittime);
- if (rc < 0 && errno != EINTR)
- __glutFatalError("select error.");
-#else
-
- MsgWaitForMultipleObjects(0, NULL, FALSE,
- waittime.tv_sec*1000 + waittime.tv_usec/1000, QS_ALLINPUT);
-
-#endif
-#endif /* not vms6.2 or lower */
- /* Without considering the cause of select unblocking, check
- for pending X events and handle any timeouts (by calling
- processEventsAndTimeouts). We always look for X events
- even if select returned with 0 (indicating a timeout);
- otherwise we risk starving X event processing by continous
- timeouts. */
- if (XPending(__glutDisplay)) {
- immediatelyHandleXinput:
- processEventsAndTimeouts();
- } else {
- if (__glutTimerList)
- handleTimeouts();
- }
-}
-
-static void
-idleWait(void)
-{
- if (XPending(__glutDisplay)) {
- processEventsAndTimeouts();
- } else {
- if (__glutTimerList) {
- handleTimeouts();
- }
- }
- /* Make sure idle func still exists! */
- if (__glutIdleFunc) {
- __glutIdleFunc();
- }
-}
-
-static GLUTwindow **beforeEnd;
-
-static GLUTwindow *
-processWindowWorkList(GLUTwindow * window)
-{
- int workMask;
-
- if (window->prevWorkWin) {
- window->prevWorkWin = processWindowWorkList(window->prevWorkWin);
- } else {
- beforeEnd = &window->prevWorkWin;
- }
-
- /* Capture work mask for work that needs to be done to this
- window, then clear the window's work mask (excepting the
- dummy work bit, see below). Then, process the captured
- work mask. This allows callbacks in the processing the
- captured work mask to set the window's work mask for
- subsequent processing. */
-
- workMask = window->workMask;
- assert((workMask & GLUT_DUMMY_WORK) == 0);
-
- /* Set the dummy work bit, clearing all other bits, to
- indicate that the window is currently on the window work
- list _and_ that the window's work mask is currently being
- processed. This convinces __glutPutOnWorkList that this
- window is on the work list still. */
- window->workMask = GLUT_DUMMY_WORK;
-
- /* Optimization: most of the time, the work to do is a
- redisplay and not these other types of work. Check for
- the following cases as a group to before checking each one
- individually one by one. This saves about 25 MIPS
- instructions in the common redisplay only case. */
- if (workMask & (GLUT_EVENT_MASK_WORK | GLUT_DEVICE_MASK_WORK |
- GLUT_CONFIGURE_WORK | GLUT_COLORMAP_WORK | GLUT_MAP_WORK)) {
-
-#if !defined(_WIN32) && !defined(__OS2__)
- /* Be sure to set event mask BEFORE map window is done. */
- if (workMask & GLUT_EVENT_MASK_WORK) {
- long eventMask;
-
- /* Make sure children are not propogating events this
- window is selecting for. Be sure to do this before
- enabling events on the children's parent. */
- if (window->children) {
- GLUTwindow *child = window->children;
- unsigned long attribMask = CWDontPropagate;
- XSetWindowAttributes wa;
-
- wa.do_not_propagate_mask = window->eventMask & GLUT_DONT_PROPAGATE_FILTER_MASK;
- if (window->eventMask & GLUT_HACK_STOP_PROPAGATE_MASK) {
- wa.event_mask = child->eventMask | (window->eventMask & GLUT_HACK_STOP_PROPAGATE_MASK);
- attribMask |= CWEventMask;
- }
- do {
- XChangeWindowAttributes(__glutDisplay, child->win,
- attribMask, &wa);
- child = child->siblings;
- } while (child);
- }
- eventMask = window->eventMask;
- if (window->parent && window->parent->eventMask & GLUT_HACK_STOP_PROPAGATE_MASK)
- eventMask |= (window->parent->eventMask & GLUT_HACK_STOP_PROPAGATE_MASK);
- XSelectInput(__glutDisplay, window->win, eventMask);
- if (window->overlay)
- XSelectInput(__glutDisplay, window->overlay->win,
- window->eventMask & GLUT_OVERLAY_EVENT_FILTER_MASK);
- }
-#endif /* !_WIN32 */
- /* Be sure to set device mask BEFORE map window is done. */
- if (workMask & GLUT_DEVICE_MASK_WORK) {
- __glutUpdateInputDeviceMaskFunc(window);
- }
- /* Be sure to configure window BEFORE map window is done. */
- if (workMask & GLUT_CONFIGURE_WORK) {
-#if defined(__OS2__)
- RECTL changes;
-
-#elif defined(_WIN32)
- RECT changes;
- POINT point;
- UINT flags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER
- | SWP_NOSENDCHANGING | SWP_NOSIZE | SWP_NOZORDER;
-
- GetClientRect(window->win, &changes);
-
- /* If this window is a toplevel window, translate the 0,0 client
- coordinate into a screen coordinate for proper placement. */
- if (!window->parent) {
- point.x = 0;
- point.y = 0;
- ClientToScreen(window->win, &point);
- changes.left = point.x;
- changes.top = point.y;
- }
- if (window->desiredConfMask & (CWX | CWY)) {
- changes.left = window->desiredX;
- changes.top = window->desiredY;
- flags &= ~SWP_NOMOVE;
- }
- if (window->desiredConfMask & (CWWidth | CWHeight)) {
- changes.right = changes.left + window->desiredWidth;
- changes.bottom = changes.top + window->desiredHeight;
- flags &= ~SWP_NOSIZE;
- /* XXX If overlay exists, resize the overlay here, ie.
- if (window->overlay) ... */
- }
- if (window->desiredConfMask & CWStackMode) {
- flags &= ~SWP_NOZORDER;
- /* XXX Overlay support might require something special here. */
- }
-
- /* Adjust the window rectangle because Win32 thinks that the x, y,
- width & height are the WHOLE window (including decorations),
- whereas GLUT treats the x, y, width & height as only the CLIENT
- area of the window. Only do this to top level windows
- that are not in game mode (since game mode windows do
- not have any decorations). */
- if (!window->parent && window != __glutGameModeWindow) {
- AdjustWindowRect(&changes,
- WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
- FALSE);
- }
-
- /* Do the repositioning, moving, and push/pop. */
- SetWindowPos(window->win,
- window->desiredStack == Above ? HWND_TOP : HWND_NOTOPMOST,
- changes.left, changes.top,
- changes.right - changes.left, changes.bottom - changes.top,
- flags);
-
- /* Zero out the mask. */
- window->desiredConfMask = 0;
-
- /* This hack causes the window to go back to the right position
- when it is taken out of fullscreen mode. */
- if (workMask & GLUT_FULL_SCREEN_WORK) {
- window->desiredConfMask |= CWX | CWY;
- window->desiredX = point.x;
- window->desiredY = point.y;
- }
-#else /* !_WIN32 */
- XWindowChanges changes;
-
- changes.x = window->desiredX;
- changes.y = window->desiredY;
- if (window->desiredConfMask & (CWWidth | CWHeight)) {
- changes.width = window->desiredWidth;
- changes.height = window->desiredHeight;
- if (window->overlay)
- XResizeWindow(__glutDisplay, window->overlay->win,
- window->desiredWidth, window->desiredHeight);
- if (__glutMotifHints != None) {
- if (workMask & GLUT_FULL_SCREEN_WORK) {
- MotifWmHints hints;
-
- hints.flags = MWM_HINTS_DECORATIONS;
- hints.decorations = 0; /* Absolutely no
- decorations. */
- XChangeProperty(__glutDisplay, window->win,
- __glutMotifHints, __glutMotifHints, 32,
- PropModeReplace, (unsigned char *) &hints, 4);
- if (workMask & GLUT_MAP_WORK) {
- /* Handle case where glutFullScreen is called
- before the first time that the window is
- mapped. Some window managers will randomly or
- interactively position the window the first
- time it is mapped if the window's
- WM_NORMAL_HINTS property does not request an
- explicit position. We don't want any such
- window manager interaction when going
- fullscreen. Overwrite the WM_NORMAL_HINTS
- property installed by glutCreateWindow's
- XSetWMProperties property with one explicitly
- requesting a fullscreen window. */
- XSizeHints hints;
-
- hints.flags = USPosition | USSize;
- hints.x = 0;
- hints.y = 0;
- hints.width = window->desiredWidth;
- hints.height = window->desiredHeight;
- XSetWMNormalHints(__glutDisplay, window->win, &hints);
- }
- } else {
- XDeleteProperty(__glutDisplay, window->win, __glutMotifHints);
- }
- }
- }
- if (window->desiredConfMask & CWStackMode) {
- changes.stack_mode = window->desiredStack;
- /* Do not let glutPushWindow push window beneath the
- underlay. */
- if (window->parent && window->parent->overlay
- && window->desiredStack == Below) {
- changes.stack_mode = Above;
- changes.sibling = window->parent->overlay->win;
- window->desiredConfMask |= CWSibling;
- }
- }
- XConfigureWindow(__glutDisplay, window->win,
- window->desiredConfMask, &changes);
- window->desiredConfMask = 0;
-#endif
- }
-#if !defined(_WIN32) && !defined(__OS2__)
- /* Be sure to establish the colormaps BEFORE map window is
- done. */
- if (workMask & GLUT_COLORMAP_WORK) {
- __glutEstablishColormapsProperty(window);
- }
-#endif
- if (workMask & GLUT_MAP_WORK) {
- switch (window->desiredMapState) {
- case WithdrawnState:
- if (window->parent) {
- XUnmapWindow(__glutDisplay, window->win);
- } else {
- XWithdrawWindow(__glutDisplay, window->win,
- __glutScreen);
- }
- window->shownState = 0;
- break;
- case NormalState:
- XMapWindow(__glutDisplay, window->win);
- window->shownState = 1;
- break;
-#ifdef _WIN32
- case GameModeState: /* Not an Xlib value. */
- ShowWindow(window->win, SW_SHOW);
- window->shownState = 1;
- break;
-#endif
- case IconicState:
- XIconifyWindow(__glutDisplay, window->win, __glutScreen);
- window->shownState = 0;
- break;
- }
- }
- }
- if (workMask & (GLUT_REDISPLAY_WORK | GLUT_OVERLAY_REDISPLAY_WORK | GLUT_REPAIR_WORK | GLUT_OVERLAY_REPAIR_WORK)) {
- if (window->forceReshape) {
- /* Guarantee that before a display callback is generated
- for a window, a reshape callback must be generated. */
- __glutSetWindow(window);
- window->reshape(window->width, window->height);
- window->forceReshape = False;
-
- /* Setting the redisplay bit on the first reshape is
- necessary to make the "Mesa glXSwapBuffers to repair
- damage" hack operate correctly. Without indicating a
- redisplay is necessary, there's not an initial back
- buffer render from which to blit from when damage
- happens to the window. */
- workMask |= GLUT_REDISPLAY_WORK;
- }
- /* The code below is more involved than otherwise necessary
- because it is paranoid about the overlay or entire window
- being removed or destroyed in the course of the callbacks.
- Notice how the global __glutWindowDamaged is used to record
- the layers' damage status. See the code in glutLayerGet for
- how __glutWindowDamaged is used. The point is to not have to
- update the "damaged" field after the callback since the
- window (or overlay) may be destroyed (or removed) when the
- callback returns. */
-
- if (window->overlay && window->overlay->display) {
- int num = window->num;
- Window xid = window->overlay ? window->overlay->win : None;
-
- /* If an overlay display callback is registered, we
- differentiate between a redisplay needed for the
- overlay and/or normal plane. If there is no overlay
- display callback registered, we simply use the
- standard display callback. */
-
- if (workMask & (GLUT_REDISPLAY_WORK | GLUT_REPAIR_WORK)) {
- if (__glutMesaSwapHackSupport) {
- if (window->usedSwapBuffers) {
- if ((workMask & (GLUT_REPAIR_WORK | GLUT_REDISPLAY_WORK)) == GLUT_REPAIR_WORK) {
- SWAP_BUFFERS_WINDOW(window);
- goto skippedDisplayCallback1;
- }
- }
- }
- /* Render to normal plane. */
-#ifdef _WIN32
- window->renderDc = window->hdc;
-#endif
- window->renderWin = window->win;
- window->renderCtx = window->ctx;
- __glutWindowDamaged = (workMask & GLUT_REPAIR_WORK);
- __glutSetWindow(window);
- window->usedSwapBuffers = 0;
- window->display();
- __glutWindowDamaged = 0;
-
- skippedDisplayCallback1:;
- }
- if (workMask & (GLUT_OVERLAY_REDISPLAY_WORK | GLUT_OVERLAY_REPAIR_WORK)) {
- window = __glutWindowList[num];
- if (window && window->overlay &&
- window->overlay->win == xid && window->overlay->display) {
-
- /* Render to overlay. */
-#ifdef _WIN32
- window->renderDc = window->overlay->hdc;
-#endif
- window->renderWin = window->overlay->win;
- window->renderCtx = window->overlay->ctx;
- __glutWindowDamaged = (workMask & GLUT_OVERLAY_REPAIR_WORK);
- __glutSetWindow(window);
- window->overlay->display();
- __glutWindowDamaged = 0;
- } else {
- /* Overlay may have since been destroyed or the
- overlay callback may have been disabled during
- normal display callback. */
- }
- }
- } else {
- if (__glutMesaSwapHackSupport) {
- if (!window->overlay && window->usedSwapBuffers) {
- if ((workMask & (GLUT_REPAIR_WORK | GLUT_REDISPLAY_WORK)) == GLUT_REPAIR_WORK) {
- SWAP_BUFFERS_WINDOW(window);
- goto skippedDisplayCallback2;
- }
- }
- }
- /* Render to normal plane (and possibly overlay). */
- __glutWindowDamaged = (workMask & (GLUT_OVERLAY_REPAIR_WORK | GLUT_REPAIR_WORK));
- __glutSetWindow(window);
- window->usedSwapBuffers = 0;
- window->display();
- __glutWindowDamaged = 0;
-
- skippedDisplayCallback2:;
- }
- }
- /* Combine workMask with window->workMask to determine what
- finish and debug work there is. */
- workMask |= window->workMask;
-
- if (workMask & GLUT_FINISH_WORK) {
- /* Finish work makes sure a glFinish gets done to indirect
- rendering contexts. Indirect contexts tend to have much
- longer latency because lots of OpenGL extension requests
- can queue up in the X protocol stream. __glutSetWindow
- is where the finish works gets queued for indirect
- contexts. */
- __glutSetWindow(window);
- glFinish();
- }
- if (workMask & GLUT_DEBUG_WORK) {
- __glutSetWindow(window);
- glutReportErrors();
- }
- /* Strip out dummy, finish, and debug work bits. */
- window->workMask &= ~(GLUT_DUMMY_WORK | GLUT_FINISH_WORK | GLUT_DEBUG_WORK);
- if (window->workMask) {
- /* Leave on work list. */
- return window;
- } else {
- /* Remove current window from work list. */
- return window->prevWorkWin;
- }
-}
-
-#ifndef _WIN32
-static /* X11 implementations do not need this global. */
-#endif
-void
-__glutProcessWindowWorkLists(void)
-{
- if (__glutWindowWorkList) {
- GLUTwindow *remainder, *work;
-
- work = __glutWindowWorkList;
- __glutWindowWorkList = NULL;
- if (work) {
- remainder = processWindowWorkList(work);
- if (remainder) {
- *beforeEnd = __glutWindowWorkList;
- __glutWindowWorkList = remainder;
- }
- }
- }
-}
-
-/* CENTRY */
-void GLUTAPIENTRY
-glutMainLoop(void)
-{
-#if !defined(_WIN32)
- if (!__glutDisplay)
- __glutFatalUsage("main loop entered with out proper initialization.");
-#endif
- if (!__glutWindowListSize)
- __glutFatalUsage(
- "main loop entered with no windows created.");
- for (;;) {
- __glutProcessWindowWorkLists();
- if (__glutIdleFunc || __glutWindowWorkList) {
- idleWait();
- } else {
- if (__glutTimerList) {
- waitForSomething();
- } else {
- processEventsAndTimeouts();
- }
- }
- }
-}
-/* ENDCENTRY */
+/* glut_event.c */
+/* Copyright (c) Mark J. Kilgard, 1994, 1995, 1996, 1997, 1998. */
+
+/* This program is freely distributable without licensing fees
+ and is provided without guarantee or warrantee expressed or
+ implied. This program is -not- in the public domain. */
+
+#ifdef __VMS
+#include <GL/vms_x_fix.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <assert.h>
+#include <string.h> /* Some FD_ZERO macros use memset without
+ prototyping memset. */
+
+/* Much of the following #ifdef logic to include the proper
+ prototypes for the select system call is based on logic
+ from the X11R6.3 version of <X11/Xpoll.h>. */
+
+#if !defined(_WIN32)
+# ifdef __sgi
+# include <bstring.h> /* prototype for bzero used by FD_ZERO */
+# endif
+# if (defined(SVR4) || defined(CRAY) || defined(AIXV3)) && !defined(FD_SETSIZE)
+# include <sys/select.h> /* select system call interface */
+# ifdef luna
+# include <sysent.h>
+# endif
+# endif
+ /* AIX 4.2 fubar-ed <sys/select.h>, so go to heroic measures to get it */
+# if defined(AIXV4) && !defined(NFDBITS)
+# include <sys/select.h>
+# endif
+#endif /* !_WIN32 */
+
+#include <sys/types.h>
+
+#if defined(__OS2__)
+//??? ��䨣� ?? # include <sys/time.h>
+#elif !defined(_WIN32)
+# if defined(__vms) && ( __VMS_VER < 70000000 )
+# include <sys/time.h>
+# else
+# ifndef __vms
+# include <sys/time.h>
+# endif
+# endif
+# include <unistd.h>
+# include <X11/Xlib.h>
+# include <X11/keysym.h>
+#else
+# ifdef __CYGWIN32__
+# include <sys/time.h>
+# else
+# include <sys/timeb.h>
+# endif
+# ifdef __hpux
+ /* XXX Bert Gijsbers <[email protected]> reports that HP-UX
+ needs different keysyms for the End, Insert, and Delete keys
+ to work on an HP 715. It would be better if HP generated
+ standard keysyms for standard keys. */
+# include <X11/HPkeysym.h>
+# endif
+#endif /* !_WIN32 */
+
+#include "glutint.h"
+
+#if defined(__vms) && ( __VMS_VER < 70000000 )
+#include <ssdef.h>
+#include <psldef.h>
+extern int SYS$CLREF(int efn);
+extern int SYS$SETIMR(unsigned int efn, struct timeval6 *timeout, void *ast,
+ unsigned int request_id, unsigned int flags);
+extern int SYS$WFLOR(unsigned int efn, unsigned int mask);
+extern int SYS$CANTIM(unsigned int request_id, unsigned int mode);
+#endif /* __vms, VMs 6.2 or earlier */
+
+static GLUTtimer *freeTimerList = NULL;
+
+GLUTidleCB __glutIdleFunc = NULL;
+GLUTtimer *__glutTimerList = NULL;
+#ifdef SUPPORT_FORTRAN
+GLUTtimer *__glutNewTimer;
+#endif
+GLUTwindow *__glutWindowWorkList = NULL;
+GLUTmenu *__glutMappedMenu;
+GLUTmenu *__glutCurrentMenu = NULL;
+
+void (*__glutUpdateInputDeviceMaskFunc) (GLUTwindow *);
+#if !defined(_WIN32) && !defined(__OS2__)
+void (*__glutMenuItemEnterOrLeave)(GLUTmenuItem * item, int num, int type) = NULL;
+void (*__glutFinishMenu)(Window win, int x, int y);
+void (*__glutPaintMenu)(GLUTmenu * menu);
+void (*__glutStartMenu)(GLUTmenu * menu, GLUTwindow * window, int x, int y, int x_win, int y_win);
+GLUTmenu * (*__glutGetMenuByNum)(int menunum);
+GLUTmenuItem * (*__glutGetMenuItem)(GLUTmenu * menu, Window win, int *which);
+GLUTmenu * (*__glutGetMenu)(Window win);
+#endif
+
+Atom __glutMotifHints = None;
+/* Modifier mask of ~0 implies not in core input callback. */
+unsigned int __glutModifierMask = (unsigned int) ~0;
+int __glutWindowDamaged = 0;
+
+void GLUTAPIENTRY
+glutIdleFunc(GLUTidleCB idleFunc)
+{
+ __glutIdleFunc = idleFunc;
+}
+
+void GLUTAPIENTRY
+glutTimerFunc(unsigned int interval, GLUTtimerCB timerFunc, int value)
+{
+ GLUTtimer *timer, *other;
+ GLUTtimer **prevptr;
+#ifdef OLD_VMS
+ struct timeval6 now;
+#else
+ struct timeval now;
+#endif
+
+ if (!timerFunc)
+ return;
+
+ if (freeTimerList) {
+ timer = freeTimerList;
+ freeTimerList = timer->next;
+ } else {
+ timer = (GLUTtimer *) malloc(sizeof(GLUTtimer));
+ if (!timer)
+ __glutFatalError("out of memory.");
+ }
+
+ timer->func = timerFunc;
+#if defined(__vms) && ( __VMS_VER < 70000000 )
+ /* VMS time is expressed in units of 100 ns */
+ timer->timeout.val = interval * TICKS_PER_MILLISECOND;
+#else
+ timer->timeout.tv_sec = (int) interval / 1000;
+ timer->timeout.tv_usec = (int) (interval % 1000) * 1000;
+#endif
+ timer->value = value;
+ timer->next = NULL;
+ GETTIMEOFDAY(&now);
+ ADD_TIME(timer->timeout, timer->timeout, now);
+ prevptr = &__glutTimerList;
+ other = *prevptr;
+ while (other && IS_AFTER(other->timeout, timer->timeout)) {
+ prevptr = &other->next;
+ other = *prevptr;
+ }
+ timer->next = other;
+#ifdef SUPPORT_FORTRAN
+ __glutNewTimer = timer; /* for Fortran binding! */
+#endif
+ *prevptr = timer;
+}
+
+void
+handleTimeouts(void)
+{
+#ifdef OLD_VMS
+ struct timeval6 now;
+#else
+ struct timeval now;
+#endif
+ GLUTtimer *timer;
+
+ /* Assumption is that __glutTimerList is already determined
+ to be non-NULL. */
+ GETTIMEOFDAY(&now);
+ while (IS_AT_OR_AFTER(__glutTimerList->timeout, now)) {
+ timer = __glutTimerList;
+ timer->func(timer->value);
+ __glutTimerList = timer->next;
+ timer->next = freeTimerList;
+ freeTimerList = timer;
+ if (!__glutTimerList)
+ break;
+ }
+}
+
+void
+__glutPutOnWorkList(GLUTwindow * window, int workMask)
+{
+ if (window->workMask) {
+ /* Already on list; just OR in new workMask. */
+ window->workMask |= workMask;
+ } else {
+ /* Update work mask and add to window work list. */
+ window->workMask = workMask;
+ /* Assert that if the window does not have a
+ workMask already, the window should definitely
+ not be the head of the work list. */
+ assert(window != __glutWindowWorkList);
+ window->prevWorkWin = __glutWindowWorkList;
+ __glutWindowWorkList = window;
+ }
+}
+
+void
+__glutPostRedisplay(GLUTwindow * window, int layerMask)
+{
+ int shown = (layerMask & (GLUT_REDISPLAY_WORK | GLUT_REPAIR_WORK)) ?
+ window->shownState : window->overlay->shownState;
+
+ /* Post a redisplay if the window is visible (or the
+ visibility of the window is unknown, ie. window->visState
+ == -1) _and_ the layer is known to be shown. */
+ if (window->visState != GLUT_HIDDEN
+ && window->visState != GLUT_FULLY_COVERED && shown) {
+ __glutPutOnWorkList(window, layerMask);
+ }
+}
+
+/* CENTRY */
+void GLUTAPIENTRY
+glutPostRedisplay(void)
+{
+ __glutPostRedisplay(__glutCurrentWindow, GLUT_REDISPLAY_WORK);
+}
+
+/* The advantage of this routine is that it saves the cost of a
+ glutSetWindow call (entailing an expensive OpenGL context switch),
+ particularly useful when multiple windows need redisplays posted at
+ the same times. See also glutPostWindowOverlayRedisplay. */
+void GLUTAPIENTRY
+glutPostWindowRedisplay(int win)
+{
+ __glutPostRedisplay(__glutWindowList[win - 1], GLUT_REDISPLAY_WORK);
+}
+
+/* ENDCENTRY */
+static GLUTeventParser *eventParserList = NULL;
+
+/* __glutRegisterEventParser allows another module to register
+ to intercept X events types not otherwise acted on by the
+ GLUT processEventsAndTimeouts routine. The X Input
+ extension support code uses an event parser for handling X
+ Input extension events. */
+
+void
+__glutRegisterEventParser(GLUTeventParser * parser)
+{
+ parser->next = eventParserList;
+ eventParserList = parser;
+}
+
+static void
+markWindowHidden(GLUTwindow * window)
+{
+ if (GLUT_HIDDEN != window->visState) {
+ GLUTwindow *child;
+
+ if (window->windowStatus) {
+ window->visState = GLUT_HIDDEN;
+ __glutSetWindow(window);
+ window->windowStatus(GLUT_HIDDEN);
+ }
+ /* An unmap is only reported on a single window; its
+ descendents need to know they are no longer visible. */
+ child = window->children;
+ while (child) {
+ markWindowHidden(child);
+ child = child->siblings;
+ }
+ }
+}
+
+#if !defined(_WIN32) && !defined(__OS2__)
+
+static void
+purgeStaleWindow(Window win)
+{
+ GLUTstale **pEntry = &__glutStaleWindowList;
+ GLUTstale *entry = __glutStaleWindowList;
+
+ /* Tranverse singly-linked stale window list look for the
+ window ID. */
+ while (entry) {
+ if (entry->win == win) {
+ /* Found it; delete it. */
+ *pEntry = entry->next;
+ free(entry);
+ return;
+ } else {
+ pEntry = &entry->next;
+ entry = *pEntry;
+ }
+ }
+}
+
+/* Unlike XNextEvent, if a signal arrives,
+ interruptibleXNextEvent will return (with a zero return
+ value). This helps GLUT drop out of XNextEvent if a signal
+ is delivered. The intent is so that a GLUT program can call
+ glutIdleFunc in a signal handler to register an idle func
+ and then immediately get dropped into the idle func (after
+ returning from the signal handler). The idea is to make
+ GLUT's main loop reliably interruptible by signals. */
+static int
+interruptibleXNextEvent(Display * dpy, XEvent * event)
+{
+ fd_set fds;
+ int rc;
+
+ /* Flush X protocol since XPending does not do this
+ implicitly. */
+ XFlush(__glutDisplay);
+ for (;;) {
+ if (XPending(__glutDisplay)) {
+ XNextEvent(dpy, event);
+ return 1;
+ }
+#ifndef VMS
+ /* the combination ConectionNumber-select is buggy on VMS. Sometimes it
+ * fails. This part of the code hangs the program on VMS7.2. But even
+ * without it the program seems to run correctly.
+ * Note that this is a bug in the VMS/DECWindows run-time-libraries.
+ * Compaq engeneering does not want or is not able to make a fix.
+ * (last sentence is a quotation from Compaq when I reported the
+ * problem January 2000) */
+ FD_ZERO(&fds);
+ FD_SET(__glutConnectionFD, &fds);
+ rc = select(__glutConnectionFD + 1, &fds, NULL, NULL, NULL);
+ if (rc < 0) {
+ if (errno == EINTR) {
+ return 0;
+ } else {
+ __glutFatalError("select error.");
+ }
+ }
+#endif
+ }
+}
+
+#endif
+
+static void
+processEventsAndTimeouts(void)
+{
+ do {
+#if defined(__OS2__)
+ QMSG qmsg; /* message from message queue */
+ extern HAB hab; /* PM anchor block handle */
+
+ if(! WinGetMsg( hab, &qmsg, 0UL, 0UL, 0UL ) )
+ exit(0);
+ WinDispatchMsg( hab, /* PM anchor block handle */
+ &qmsg ); /* pointer to message */
+
+#elif defined(_WIN32)
+ MSG event;
+
+ if(!GetMessage(&event, NULL, 0, 0)) /* bail if no more messages */
+ exit(0);
+ TranslateMessage(&event); /* translate virtual-key messages */
+ DispatchMessage(&event); /* call the window proc */
+ /* see win32_event.c for event (message) processing procedures */
+#else
+ static int mappedMenuButton;
+ GLUTeventParser *parser;
+ XEvent event, ahead;
+ GLUTwindow *window;
+ GLUTkeyboardCB keyboard;
+ GLUTspecialCB special;
+ int gotEvent, width, height;
+
+ gotEvent = interruptibleXNextEvent(__glutDisplay, &event);
+ if (gotEvent) {
+ switch (event.type) {
+ case MappingNotify:
+ XRefreshKeyboardMapping((XMappingEvent *) & event);
+ break;
+ case ConfigureNotify:
+ window = __glutGetWindow(event.xconfigure.window);
+ if (window) {
+ if (window->win != event.xconfigure.window) {
+ /* Ignore ConfigureNotify sent to the overlay
+ planes. GLUT could get here because overlays
+ select for StructureNotify events to receive
+ DestroyNotify. */
+ break;
+ }
+ width = event.xconfigure.width;
+ height = event.xconfigure.height;
+ if (width != window->width || height != window->height) {
+ if (window->overlay) {
+ XResizeWindow(__glutDisplay, window->overlay->win, width, height);
+ }
+ window->width = width;
+ window->height = height;
+ __glutSetWindow(window);
+ /* Do not execute OpenGL out of sequence with
+ respect to the XResizeWindow request! */
+ glXWaitX();
+ window->reshape(width, height);
+ window->forceReshape = False;
+ /* A reshape should be considered like posting a
+ repair; this is necessary for the "Mesa
+ glXSwapBuffers to repair damage" hack to operate
+ correctly. Without it, there's not an initial
+ back buffer render from which to blit from when
+ damage happens to the window. */
+ __glutPostRedisplay(window, GLUT_REPAIR_WORK);
+ }
+ }
+ break;
+ case Expose:
+ /* compress expose events */
+ while (XEventsQueued(__glutDisplay, QueuedAfterReading)
+ > 0) {
+ XPeekEvent(__glutDisplay, &ahead);
+ if (ahead.type != Expose ||
+ ahead.xexpose.window != event.xexpose.window) {
+ break;
+ }
+ XNextEvent(__glutDisplay, &event);
+ }
+ if (event.xexpose.count == 0) {
+ GLUTmenu *menu;
+
+ if (__glutMappedMenu &&
+ (menu = __glutGetMenu(event.xexpose.window))) {
+ __glutPaintMenu(menu);
+ } else {
+ window = __glutGetWindow(event.xexpose.window);
+ if (window) {
+ if (window->win == event.xexpose.window) {
+ __glutPostRedisplay(window, GLUT_REPAIR_WORK);
+ } else if (window->overlay && window->overlay->win == event.xexpose.window) {
+ __glutPostRedisplay(window, GLUT_OVERLAY_REPAIR_WORK);
+ }
+ }
+ }
+ } else {
+ /* there are more exposes to read; wait to redisplay */
+ }
+ break;
+ case ButtonPress:
+ case ButtonRelease:
+ if (__glutMappedMenu && event.type == ButtonRelease
+ && mappedMenuButton == event.xbutton.button) {
+ /* Menu is currently popped up and its button is
+ released. */
+ __glutFinishMenu(event.xbutton.window, event.xbutton.x, event.xbutton.y);
+ } else {
+ window = __glutGetWindow(event.xbutton.window);
+ if (window) {
+ GLUTmenu *menu;
+ int menuNum;
+
+ menuNum = window->menu[event.xbutton.button - 1];
+ /* Make sure that __glutGetMenuByNum is only called if there
+ really is a menu present. */
+ if ((menuNum > 0) && (menu = __glutGetMenuByNum(menuNum))) {
+ if (event.type == ButtonPress && !__glutMappedMenu) {
+ __glutStartMenu(menu, window,
+ event.xbutton.x_root, event.xbutton.y_root,
+ event.xbutton.x, event.xbutton.y);
+ mappedMenuButton = event.xbutton.button;
+ } else {
+ /* Ignore a release of a button with a menu
+ attatched to it when no menu is popped up,
+ or ignore a press when another menu is
+ already popped up. */
+ }
+ } else if (window->mouse) {
+ __glutSetWindow(window);
+ __glutModifierMask = event.xbutton.state;
+ window->mouse(event.xbutton.button - 1,
+ event.type == ButtonRelease ?
+ GLUT_UP : GLUT_DOWN,
+ event.xbutton.x, event.xbutton.y);
+ __glutModifierMask = ~0;
+ } else {
+ /* Stray mouse events. Ignore. */
+ }
+ } else {
+ /* Window might have been destroyed and all the
+ events for the window may not yet be received. */
+ }
+ }
+ break;
+ case MotionNotify:
+ if (!__glutMappedMenu) {
+ window = __glutGetWindow(event.xmotion.window);
+ if (window) {
+ /* If motion function registered _and_ buttons held
+ * down, call motion function... */
+ if (window->motion && event.xmotion.state &
+ (Button1Mask | Button2Mask | Button3Mask)) {
+ __glutSetWindow(window);
+ window->motion(event.xmotion.x, event.xmotion.y);
+ }
+ /* If passive motion function registered _and_
+ buttons not held down, call passive motion
+ function... */
+ else if (window->passive &&
+ ((event.xmotion.state &
+ (Button1Mask | Button2Mask | Button3Mask)) ==
+ 0)) {
+ __glutSetWindow(window);
+ window->passive(event.xmotion.x,
+ event.xmotion.y);
+ }
+ }
+ } else {
+ /* Motion events are thrown away when a pop up menu
+ is active. */
+ }
+ break;
+ case KeyPress:
+ case KeyRelease:
+ window = __glutGetWindow(event.xkey.window);
+ if (!window) {
+ break;
+ }
+ if (event.type == KeyPress) {
+ keyboard = window->keyboard;
+ } else {
+
+ /* If we are ignoring auto repeated keys for this window,
+ check if the next event in the X event queue is a KeyPress
+ for the exact same key (and at the exact same time) as the
+ key being released. The X11 protocol will send auto
+ repeated keys as such KeyRelease/KeyPress pairs. */
+
+ if (window->ignoreKeyRepeat) {
+ if (XEventsQueued(__glutDisplay, QueuedAfterReading)) {
+ XPeekEvent(__glutDisplay, &ahead);
+ if (ahead.type == KeyPress
+ && ahead.xkey.window == event.xkey.window
+ && ahead.xkey.keycode == event.xkey.keycode
+ && ahead.xkey.time == event.xkey.time) {
+ /* Pop off the repeated KeyPress and ignore
+ the auto repeated KeyRelease/KeyPress pair. */
+ XNextEvent(__glutDisplay, &event);
+ break;
+ }
+ }
+ }
+ keyboard = window->keyboardUp;
+ }
+ if (keyboard) {
+ char tmp[1];
+ int rc;
+
+ rc = XLookupString(&event.xkey, tmp, sizeof(tmp),
+ NULL, NULL);
+ if (rc) {
+ __glutSetWindow(window);
+ __glutModifierMask = event.xkey.state;
+ keyboard(tmp[0],
+ event.xkey.x, event.xkey.y);
+ __glutModifierMask = ~0;
+ break;
+ }
+ }
+ if (event.type == KeyPress) {
+ special = window->special;
+ } else {
+ special = window->specialUp;
+ }
+ if (special) {
+ KeySym ks;
+ int key;
+
+/* Introduced in X11R6: (Partial list of) Keypad Functions. Define
+ in place in case compiling against an older pre-X11R6
+ X11/keysymdef.h file. */
+#ifndef XK_KP_Home
+#define XK_KP_Home 0xFF95
+#endif
+#ifndef XK_KP_Left
+#define XK_KP_Left 0xFF96
+#endif
+#ifndef XK_KP_Up
+#define XK_KP_Up 0xFF97
+#endif
+#ifndef XK_KP_Right
+#define XK_KP_Right 0xFF98
+#endif
+#ifndef XK_KP_Down
+#define XK_KP_Down 0xFF99
+#endif
+#ifndef XK_KP_Prior
+#define XK_KP_Prior 0xFF9A
+#endif
+#ifndef XK_KP_Next
+#define XK_KP_Next 0xFF9B
+#endif
+#ifndef XK_KP_End
+#define XK_KP_End 0xFF9C
+#endif
+#ifndef XK_KP_Insert
+#define XK_KP_Insert 0xFF9E
+#endif
+#ifndef XK_KP_Delete
+#define XK_KP_Delete 0xFF9F
+#endif
+
+ ks = XLookupKeysym((XKeyEvent *) & event, 0);
+ /* XXX Verbose, but makes no assumptions about keysym
+ layout. */
+ switch (ks) {
+/* *INDENT-OFF* */
+ /* function keys */
+ case XK_F1: key = GLUT_KEY_F1; break;
+ case XK_F2: key = GLUT_KEY_F2; break;
+ case XK_F3: key = GLUT_KEY_F3; break;
+ case XK_F4: key = GLUT_KEY_F4; break;
+ case XK_F5: key = GLUT_KEY_F5; break;
+ case XK_F6: key = GLUT_KEY_F6; break;
+ case XK_F7: key = GLUT_KEY_F7; break;
+ case XK_F8: key = GLUT_KEY_F8; break;
+ case XK_F9: key = GLUT_KEY_F9; break;
+ case XK_F10: key = GLUT_KEY_F10; break;
+ case XK_F11: key = GLUT_KEY_F11; break;
+ case XK_F12: key = GLUT_KEY_F12; break;
+ /* directional keys */
+ case XK_KP_Left:
+ case XK_Left: key = GLUT_KEY_LEFT; break;
+ case XK_KP_Up: /* Introduced in X11R6. */
+ case XK_Up: key = GLUT_KEY_UP; break;
+ case XK_KP_Right: /* Introduced in X11R6. */
+ case XK_Right: key = GLUT_KEY_RIGHT; break;
+ case XK_KP_Down: /* Introduced in X11R6. */
+ case XK_Down: key = GLUT_KEY_DOWN; break;
+/* *INDENT-ON* */
+
+ case XK_KP_Prior: /* Introduced in X11R6. */
+ case XK_Prior:
+ /* XK_Prior same as X11R6's XK_Page_Up */
+ key = GLUT_KEY_PAGE_UP;
+ break;
+ case XK_KP_Next: /* Introduced in X11R6. */
+ case XK_Next:
+ /* XK_Next same as X11R6's XK_Page_Down */
+ key = GLUT_KEY_PAGE_DOWN;
+ break;
+ case XK_KP_Home: /* Introduced in X11R6. */
+ case XK_Home:
+ key = GLUT_KEY_HOME;
+ break;
+#ifdef __hpux
+ case XK_Select:
+#endif
+ case XK_KP_End: /* Introduced in X11R6. */
+ case XK_End:
+ key = GLUT_KEY_END;
+ break;
+#ifdef __hpux
+ case XK_InsertChar:
+#endif
+ case XK_KP_Insert: /* Introduced in X11R6. */
+ case XK_Insert:
+ key = GLUT_KEY_INSERT;
+ break;
+#ifdef __hpux
+ case XK_DeleteChar:
+#endif
+ case XK_KP_Delete: /* Introduced in X11R6. */
+ /* The Delete character is really an ASCII key. */
+ __glutSetWindow(window);
+ keyboard(127, /* ASCII Delete character. */
+ event.xkey.x, event.xkey.y);
+ goto skip;
+ default:
+ goto skip;
+ }
+ __glutSetWindow(window);
+ __glutModifierMask = event.xkey.state;
+ special(key, event.xkey.x, event.xkey.y);
+ __glutModifierMask = ~0;
+ skip:;
+ }
+ break;
+ case EnterNotify:
+ case LeaveNotify:
+ if (event.xcrossing.mode != NotifyNormal ||
+ event.xcrossing.detail == NotifyNonlinearVirtual ||
+ event.xcrossing.detail == NotifyVirtual) {
+
+ /* Careful to ignore Enter/LeaveNotify events that
+ come from the pop-up menu pointer grab and ungrab.
+ Also, ignore "virtual" Enter/LeaveNotify events
+ since they represent the pointer passing through
+ the window hierarchy without actually entering or
+ leaving the actual real estate of a window. */
+
+ break;
+ }
+ if (__glutMappedMenu) {
+ GLUTmenuItem *item;
+ int num;
+
+ item = __glutGetMenuItem(__glutMappedMenu,
+ event.xcrossing.window, &num);
+ if (item) {
+ __glutMenuItemEnterOrLeave(item, num, event.type);
+ break;
+ }
+ }
+ window = __glutGetWindow(event.xcrossing.window);
+ if (window) {
+ if (window->entry) {
+ if (event.type == EnterNotify) {
+
+ /* With overlays established, X can report two
+ enter events for both the overlay and normal
+ plane window. Do not generate a second enter
+ callback if we reported one without an
+ intervening leave. */
+
+ if (window->entryState != EnterNotify) {
+ int num = window->num;
+ Window xid = window->win;
+
+ window->entryState = EnterNotify;
+ __glutSetWindow(window);
+ window->entry(GLUT_ENTERED);
+
+ if (__glutMappedMenu) {
+
+ /* Do not generate any passive motion events
+ when menus are in use. */
+
+ } else {
+
+ /* An EnterNotify event can result in a
+ "compound" callback if a passive motion
+ callback is also registered. In this case,
+ be a little paranoid about the possibility
+ the window could have been destroyed in the
+ entry callback. */
+
+ window = __glutWindowList[num];
+ if (window && window->passive && window->win == xid) {
+ __glutSetWindow(window);
+ window->passive(event.xcrossing.x, event.xcrossing.y);
+ }
+ }
+ }
+ } else {
+ if (window->entryState != LeaveNotify) {
+
+ /* When an overlay is established for a window
+ already mapped and with the pointer in it,
+ the X server will generate a leave/enter
+ event pair as the pointer leaves (without
+ moving) from the normal plane X window to
+ the newly mapped overlay X window (or vice
+ versa). This enter/leave pair should not be
+ reported to the GLUT program since the pair
+ is a consequence of creating (or destroying)
+ the overlay, not an actual leave from the
+ GLUT window. */
+
+ if (XEventsQueued(__glutDisplay, QueuedAfterReading)) {
+ XPeekEvent(__glutDisplay, &ahead);
+ if (ahead.type == EnterNotify &&
+ __glutGetWindow(ahead.xcrossing.window) == window) {
+ XNextEvent(__glutDisplay, &event);
+ break;
+ }
+ }
+ window->entryState = LeaveNotify;
+ __glutSetWindow(window);
+ window->entry(GLUT_LEFT);
+ }
+ }
+ } else if (window->passive) {
+ __glutSetWindow(window);
+ window->passive(event.xcrossing.x, event.xcrossing.y);
+ }
+ }
+ break;
+ case UnmapNotify:
+ /* MapNotify events are not needed to maintain
+ visibility state since VisibilityNotify events will
+ be delivered when a window becomes visible from
+ mapping. However, VisibilityNotify events are not
+ delivered when a window is unmapped (for the window
+ or its children). */
+ window = __glutGetWindow(event.xunmap.window);
+ if (window) {
+ if (window->win != event.xconfigure.window) {
+ /* Ignore UnmapNotify sent to the overlay planes.
+ GLUT could get here because overlays select for
+ StructureNotify events to receive DestroyNotify.
+ */
+ break;
+ }
+ markWindowHidden(window);
+ }
+ break;
+ case VisibilityNotify:
+ window = __glutGetWindow(event.xvisibility.window);
+ if (window) {
+ /* VisibilityUnobscured+1 = GLUT_FULLY_RETAINED,
+ VisibilityPartiallyObscured+1 =
+ GLUT_PARTIALLY_RETAINED, VisibilityFullyObscured+1
+ = GLUT_FULLY_COVERED. */
+ int visState = event.xvisibility.state + 1;
+
+ if (visState != window->visState) {
+ if (window->windowStatus) {
+ window->visState = visState;
+ __glutSetWindow(window);
+ window->windowStatus(visState);
+ }
+ }
+ }
+ break;
+ case ClientMessage:
+ if (event.xclient.data.l[0] == __glutWMDeleteWindow)
+ exit(0);
+ break;
+ case DestroyNotify:
+ purgeStaleWindow(event.xdestroywindow.window);
+ break;
+ case CirculateNotify:
+ case CreateNotify:
+ case GravityNotify:
+ case ReparentNotify:
+ /* Uninteresting to GLUT (but possible for GLUT to
+ receive). */
+ break;
+ default:
+ /* Pass events not directly handled by the GLUT main
+ event loop to any event parsers that have been
+ registered. In this way, X Input extension events
+ are passed to the correct handler without forcing
+ all GLUT programs to support X Input event handling.
+ */
+ parser = eventParserList;
+ while (parser) {
+ if (parser->func(&event))
+ break;
+ parser = parser->next;
+ }
+ break;
+ }
+ }
+#endif /* _WIN32 */
+ if (__glutTimerList) {
+ handleTimeouts();
+ }
+ }
+ while (XPending(__glutDisplay));
+}
+
+static void
+waitForSomething(void)
+{
+#if defined(__vms) && ( __VMS_VER < 70000000 )
+ static struct timeval6 zerotime =
+ {0};
+ unsigned int timer_efn;
+#define timer_id 'glut' /* random :-) number */
+ unsigned int wait_mask;
+#else
+ static struct timeval zerotime =
+ {0, 0};
+#if defined(__OS2__)
+
+#elif !defined(_WIN32)
+ fd_set fds;
+#endif
+#endif
+#ifdef OLD_VMS
+ struct timeval6 now, timeout, waittime;
+#else
+ struct timeval now, timeout, waittime;
+#endif
+#if !defined(_WIN32)
+ int rc;
+#endif
+
+ /* Flush X protocol since XPending does not do this
+ implicitly. */
+ XFlush(__glutDisplay);
+ if (XPending(__glutDisplay)) {
+ /* It is possible (but quite rare) that XFlush may have
+ needed to wait for a writable X connection file
+ descriptor, and in the process, may have had to read off
+ X protocol from the file descriptor. If XPending is true,
+ this case occured and we should avoid waiting in select
+ since X protocol buffered within Xlib is due to be
+ processed and potentially no more X protocol is on the
+ file descriptor, so we would risk waiting improperly in
+ select. */
+ goto immediatelyHandleXinput;
+ }
+#if defined(__vms) && ( __VMS_VER < 70000000 )
+ timeout = __glutTimerList->timeout;
+ GETTIMEOFDAY(&now);
+ wait_mask = 1 << (__glutConnectionFD & 31);
+ if (IS_AFTER(now, timeout)) {
+ /* We need an event flag for the timer. */
+ /* XXX The `right' way to do this is to use LIB$GET_EF, but
+ since it needs to be in the same cluster as the EFN for
+ the display, we will have hack it. */
+ timer_efn = __glutConnectionFD - 1;
+ if ((timer_efn / 32) != (__glutConnectionFD / 32)) {
+ timer_efn = __glutConnectionFD + 1;
+ }
+ rc = SYS$CLREF(timer_efn);
+ rc = SYS$SETIMR(timer_efn, &timeout, NULL, timer_id, 0);
+ wait_mask |= 1 << (timer_efn & 31);
+ } else {
+ timer_efn = 0;
+ }
+ rc = SYS$WFLOR(__glutConnectionFD, wait_mask);
+ if (timer_efn != 0 && SYS$CLREF(timer_efn) == SS$_WASCLR) {
+ rc = SYS$CANTIM(timer_id, PSL$C_USER);
+ }
+ /* XXX There does not seem to be checking of "rc" in the code
+ above. Can any of the SYS$ routines above fail? */
+#else /* not vms6.2 or lower */
+#if defined(__OS2__)
+
+#elif !defined(_WIN32)
+ FD_ZERO(&fds);
+ FD_SET(__glutConnectionFD, &fds);
+#endif
+ timeout = __glutTimerList->timeout;
+ GETTIMEOFDAY(&now);
+ if (IS_AFTER(now, timeout)) {
+ TIMEDELTA(waittime, timeout, now);
+ } else {
+ waittime = zerotime;
+ }
+
+#if defined(__OS2__)
+ DosSleep(0);
+#elif !defined(_WIN32)
+ rc = select(__glutConnectionFD + 1, &fds,
+ NULL, NULL, &waittime);
+ if (rc < 0 && errno != EINTR)
+ __glutFatalError("select error.");
+#else
+
+ MsgWaitForMultipleObjects(0, NULL, FALSE,
+ waittime.tv_sec*1000 + waittime.tv_usec/1000, QS_ALLINPUT);
+
+#endif
+#endif /* not vms6.2 or lower */
+ /* Without considering the cause of select unblocking, check
+ for pending X events and handle any timeouts (by calling
+ processEventsAndTimeouts). We always look for X events
+ even if select returned with 0 (indicating a timeout);
+ otherwise we risk starving X event processing by continous
+ timeouts. */
+ if (XPending(__glutDisplay)) {
+ immediatelyHandleXinput:
+ processEventsAndTimeouts();
+ } else {
+ if (__glutTimerList)
+ handleTimeouts();
+ }
+}
+
+static void
+idleWait(void)
+{
+ if (XPending(__glutDisplay)) {
+ processEventsAndTimeouts();
+ } else {
+ if (__glutTimerList) {
+ handleTimeouts();
+ }
+ }
+ /* Make sure idle func still exists! */
+ if (__glutIdleFunc) {
+ __glutIdleFunc();
+ }
+}
+
+static GLUTwindow **beforeEnd;
+
+static GLUTwindow *
+processWindowWorkList(GLUTwindow * window)
+{
+ int workMask;
+
+ if (window->prevWorkWin) {
+ window->prevWorkWin = processWindowWorkList(window->prevWorkWin);
+ } else {
+ beforeEnd = &window->prevWorkWin;
+ }
+
+ /* Capture work mask for work that needs to be done to this
+ window, then clear the window's work mask (excepting the
+ dummy work bit, see below). Then, process the captured
+ work mask. This allows callbacks in the processing the
+ captured work mask to set the window's work mask for
+ subsequent processing. */
+
+ workMask = window->workMask;
+ assert((workMask & GLUT_DUMMY_WORK) == 0);
+
+ /* Set the dummy work bit, clearing all other bits, to
+ indicate that the window is currently on the window work
+ list _and_ that the window's work mask is currently being
+ processed. This convinces __glutPutOnWorkList that this
+ window is on the work list still. */
+ window->workMask = GLUT_DUMMY_WORK;
+
+ /* Optimization: most of the time, the work to do is a
+ redisplay and not these other types of work. Check for
+ the following cases as a group to before checking each one
+ individually one by one. This saves about 25 MIPS
+ instructions in the common redisplay only case. */
+ if (workMask & (GLUT_EVENT_MASK_WORK | GLUT_DEVICE_MASK_WORK |
+ GLUT_CONFIGURE_WORK | GLUT_COLORMAP_WORK | GLUT_MAP_WORK)) {
+
+#if !defined(_WIN32) && !defined(__OS2__)
+ /* Be sure to set event mask BEFORE map window is done. */
+ if (workMask & GLUT_EVENT_MASK_WORK) {
+ long eventMask;
+
+ /* Make sure children are not propogating events this
+ window is selecting for. Be sure to do this before
+ enabling events on the children's parent. */
+ if (window->children) {
+ GLUTwindow *child = window->children;
+ unsigned long attribMask = CWDontPropagate;
+ XSetWindowAttributes wa;
+
+ wa.do_not_propagate_mask = window->eventMask & GLUT_DONT_PROPAGATE_FILTER_MASK;
+ if (window->eventMask & GLUT_HACK_STOP_PROPAGATE_MASK) {
+ wa.event_mask = child->eventMask | (window->eventMask & GLUT_HACK_STOP_PROPAGATE_MASK);
+ attribMask |= CWEventMask;
+ }
+ do {
+ XChangeWindowAttributes(__glutDisplay, child->win,
+ attribMask, &wa);
+ child = child->siblings;
+ } while (child);
+ }
+ eventMask = window->eventMask;
+ if (window->parent && window->parent->eventMask & GLUT_HACK_STOP_PROPAGATE_MASK)
+ eventMask |= (window->parent->eventMask & GLUT_HACK_STOP_PROPAGATE_MASK);
+ XSelectInput(__glutDisplay, window->win, eventMask);
+ if (window->overlay)
+ XSelectInput(__glutDisplay, window->overlay->win,
+ window->eventMask & GLUT_OVERLAY_EVENT_FILTER_MASK);
+ }
+#endif /* !_WIN32 */
+ /* Be sure to set device mask BEFORE map window is done. */
+ if (workMask & GLUT_DEVICE_MASK_WORK) {
+ __glutUpdateInputDeviceMaskFunc(window);
+ }
+ /* Be sure to configure window BEFORE map window is done. */
+ if (workMask & GLUT_CONFIGURE_WORK) {
+#if defined(__OS2__)
+ RECTL changes;
+
+#elif defined(_WIN32)
+ RECT changes;
+ POINT point;
+ UINT flags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER
+ | SWP_NOSENDCHANGING | SWP_NOSIZE | SWP_NOZORDER;
+
+ GetClientRect(window->win, &changes);
+
+ /* If this window is a toplevel window, translate the 0,0 client
+ coordinate into a screen coordinate for proper placement. */
+ if (!window->parent) {
+ point.x = 0;
+ point.y = 0;
+ ClientToScreen(window->win, &point);
+ changes.left = point.x;
+ changes.top = point.y;
+ }
+ if (window->desiredConfMask & (CWX | CWY)) {
+ changes.left = window->desiredX;
+ changes.top = window->desiredY;
+ flags &= ~SWP_NOMOVE;
+ }
+ if (window->desiredConfMask & (CWWidth | CWHeight)) {
+ changes.right = changes.left + window->desiredWidth;
+ changes.bottom = changes.top + window->desiredHeight;
+ flags &= ~SWP_NOSIZE;
+ /* XXX If overlay exists, resize the overlay here, ie.
+ if (window->overlay) ... */
+ }
+ if (window->desiredConfMask & CWStackMode) {
+ flags &= ~SWP_NOZORDER;
+ /* XXX Overlay support might require something special here. */
+ }
+
+ /* Adjust the window rectangle because Win32 thinks that the x, y,
+ width & height are the WHOLE window (including decorations),
+ whereas GLUT treats the x, y, width & height as only the CLIENT
+ area of the window. Only do this to top level windows
+ that are not in game mode (since game mode windows do
+ not have any decorations). */
+ if (!window->parent && window != __glutGameModeWindow) {
+ AdjustWindowRect(&changes,
+ WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
+ FALSE);
+ }
+
+ /* Do the repositioning, moving, and push/pop. */
+ SetWindowPos(window->win,
+ window->desiredStack == Above ? HWND_TOP : HWND_NOTOPMOST,
+ changes.left, changes.top,
+ changes.right - changes.left, changes.bottom - changes.top,
+ flags);
+
+ /* Zero out the mask. */
+ window->desiredConfMask = 0;
+
+ /* This hack causes the window to go back to the right position
+ when it is taken out of fullscreen mode. */
+ if (workMask & GLUT_FULL_SCREEN_WORK) {
+ window->desiredConfMask |= CWX | CWY;
+ window->desiredX = point.x;
+ window->desiredY = point.y;
+ }
+#else /* !_WIN32 */
+ XWindowChanges changes;
+
+ changes.x = window->desiredX;
+ changes.y = window->desiredY;
+ if (window->desiredConfMask & (CWWidth | CWHeight)) {
+ changes.width = window->desiredWidth;
+ changes.height = window->desiredHeight;
+ if (window->overlay)
+ XResizeWindow(__glutDisplay, window->overlay->win,
+ window->desiredWidth, window->desiredHeight);
+ if (__glutMotifHints != None) {
+ if (workMask & GLUT_FULL_SCREEN_WORK) {
+ MotifWmHints hints;
+
+ hints.flags = MWM_HINTS_DECORATIONS;
+ hints.decorations = 0; /* Absolutely no
+ decorations. */
+ XChangeProperty(__glutDisplay, window->win,
+ __glutMotifHints, __glutMotifHints, 32,
+ PropModeReplace, (unsigned char *) &hints, 4);
+ if (workMask & GLUT_MAP_WORK) {
+ /* Handle case where glutFullScreen is called
+ before the first time that the window is
+ mapped. Some window managers will randomly or
+ interactively position the window the first
+ time it is mapped if the window's
+ WM_NORMAL_HINTS property does not request an
+ explicit position. We don't want any such
+ window manager interaction when going
+ fullscreen. Overwrite the WM_NORMAL_HINTS
+ property installed by glutCreateWindow's
+ XSetWMProperties property with one explicitly
+ requesting a fullscreen window. */
+ XSizeHints hints;
+
+ hints.flags = USPosition | USSize;
+ hints.x = 0;
+ hints.y = 0;
+ hints.width = window->desiredWidth;
+ hints.height = window->desiredHeight;
+ XSetWMNormalHints(__glutDisplay, window->win, &hints);
+ }
+ } else {
+ XDeleteProperty(__glutDisplay, window->win, __glutMotifHints);
+ }
+ }
+ }
+ if (window->desiredConfMask & CWStackMode) {
+ changes.stack_mode = window->desiredStack;
+ /* Do not let glutPushWindow push window beneath the
+ underlay. */
+ if (window->parent && window->parent->overlay
+ && window->desiredStack == Below) {
+ changes.stack_mode = Above;
+ changes.sibling = window->parent->overlay->win;
+ window->desiredConfMask |= CWSibling;
+ }
+ }
+ XConfigureWindow(__glutDisplay, window->win,
+ window->desiredConfMask, &changes);
+ window->desiredConfMask = 0;
+#endif
+ }
+#if !defined(_WIN32) && !defined(__OS2__)
+ /* Be sure to establish the colormaps BEFORE map window is
+ done. */
+ if (workMask & GLUT_COLORMAP_WORK) {
+ __glutEstablishColormapsProperty(window);
+ }
+#endif
+ if (workMask & GLUT_MAP_WORK) {
+ switch (window->desiredMapState) {
+ case WithdrawnState:
+ if (window->parent) {
+ XUnmapWindow(__glutDisplay, window->win);
+ } else {
+ XWithdrawWindow(__glutDisplay, window->win,
+ __glutScreen);
+ }
+ window->shownState = 0;
+ break;
+ case NormalState:
+ XMapWindow(__glutDisplay, window->win);
+ window->shownState = 1;
+ break;
+#ifdef _WIN32
+ case GameModeState: /* Not an Xlib value. */
+ ShowWindow(window->win, SW_SHOW);
+ window->shownState = 1;
+ break;
+#endif
+ case IconicState:
+ XIconifyWindow(__glutDisplay, window->win, __glutScreen);
+ window->shownState = 0;
+ break;
+ }
+ }
+ }
+ if (workMask & (GLUT_REDISPLAY_WORK | GLUT_OVERLAY_REDISPLAY_WORK | GLUT_REPAIR_WORK | GLUT_OVERLAY_REPAIR_WORK)) {
+ if (window->forceReshape) {
+ /* Guarantee that before a display callback is generated
+ for a window, a reshape callback must be generated. */
+ __glutSetWindow(window);
+ window->reshape(window->width, window->height);
+ window->forceReshape = False;
+
+ /* Setting the redisplay bit on the first reshape is
+ necessary to make the "Mesa glXSwapBuffers to repair
+ damage" hack operate correctly. Without indicating a
+ redisplay is necessary, there's not an initial back
+ buffer render from which to blit from when damage
+ happens to the window. */
+ workMask |= GLUT_REDISPLAY_WORK;
+ }
+ /* The code below is more involved than otherwise necessary
+ because it is paranoid about the overlay or entire window
+ being removed or destroyed in the course of the callbacks.
+ Notice how the global __glutWindowDamaged is used to record
+ the layers' damage status. See the code in glutLayerGet for
+ how __glutWindowDamaged is used. The point is to not have to
+ update the "damaged" field after the callback since the
+ window (or overlay) may be destroyed (or removed) when the
+ callback returns. */
+
+ if (window->overlay && window->overlay->display) {
+ int num = window->num;
+ Window xid = window->overlay ? window->overlay->win : None;
+
+ /* If an overlay display callback is registered, we
+ differentiate between a redisplay needed for the
+ overlay and/or normal plane. If there is no overlay
+ display callback registered, we simply use the
+ standard display callback. */
+
+ if (workMask & (GLUT_REDISPLAY_WORK | GLUT_REPAIR_WORK)) {
+ if (__glutMesaSwapHackSupport) {
+ if (window->usedSwapBuffers) {
+ if ((workMask & (GLUT_REPAIR_WORK | GLUT_REDISPLAY_WORK)) == GLUT_REPAIR_WORK) {
+ SWAP_BUFFERS_WINDOW(window);
+ goto skippedDisplayCallback1;
+ }
+ }
+ }
+ /* Render to normal plane. */
+#ifdef _WIN32
+ window->renderDc = window->hdc;
+#endif
+ window->renderWin = window->win;
+ window->renderCtx = window->ctx;
+ __glutWindowDamaged = (workMask & GLUT_REPAIR_WORK);
+ __glutSetWindow(window);
+ window->usedSwapBuffers = 0;
+ window->display();
+ __glutWindowDamaged = 0;
+
+ skippedDisplayCallback1:;
+ }
+ if (workMask & (GLUT_OVERLAY_REDISPLAY_WORK | GLUT_OVERLAY_REPAIR_WORK)) {
+ window = __glutWindowList[num];
+ if (window && window->overlay &&
+ window->overlay->win == xid && window->overlay->display) {
+
+ /* Render to overlay. */
+#ifdef _WIN32
+ window->renderDc = window->overlay->hdc;
+#endif
+ window->renderWin = window->overlay->win;
+ window->renderCtx = window->overlay->ctx;
+ __glutWindowDamaged = (workMask & GLUT_OVERLAY_REPAIR_WORK);
+ __glutSetWindow(window);
+ window->overlay->display();
+ __glutWindowDamaged = 0;
+ } else {
+ /* Overlay may have since been destroyed or the
+ overlay callback may have been disabled during
+ normal display callback. */
+ }
+ }
+ } else {
+ if (__glutMesaSwapHackSupport) {
+ if (!window->overlay && window->usedSwapBuffers) {
+ if ((workMask & (GLUT_REPAIR_WORK | GLUT_REDISPLAY_WORK)) == GLUT_REPAIR_WORK) {
+ SWAP_BUFFERS_WINDOW(window);
+ goto skippedDisplayCallback2;
+ }
+ }
+ }
+ /* Render to normal plane (and possibly overlay). */
+ __glutWindowDamaged = (workMask & (GLUT_OVERLAY_REPAIR_WORK | GLUT_REPAIR_WORK));
+ __glutSetWindow(window);
+ window->usedSwapBuffers = 0;
+ window->display();
+ __glutWindowDamaged = 0;
+
+ skippedDisplayCallback2:;
+ }
+ }
+ /* Combine workMask with window->workMask to determine what
+ finish and debug work there is. */
+ workMask |= window->workMask;
+
+ if (workMask & GLUT_FINISH_WORK) {
+ /* Finish work makes sure a glFinish gets done to indirect
+ rendering contexts. Indirect contexts tend to have much
+ longer latency because lots of OpenGL extension requests
+ can queue up in the X protocol stream. __glutSetWindow
+ is where the finish works gets queued for indirect
+ contexts. */
+ __glutSetWindow(window);
+ glFinish();
+ }
+ if (workMask & GLUT_DEBUG_WORK) {
+ __glutSetWindow(window);
+ glutReportErrors();
+ }
+ /* Strip out dummy, finish, and debug work bits. */
+ window->workMask &= ~(GLUT_DUMMY_WORK | GLUT_FINISH_WORK | GLUT_DEBUG_WORK);
+ if (window->workMask) {
+ /* Leave on work list. */
+ return window;
+ } else {
+ /* Remove current window from work list. */
+ return window->prevWorkWin;
+ }
+}
+
+#ifndef _WIN32
+static /* X11 implementations do not need this global. */
+#endif
+void
+__glutProcessWindowWorkLists(void)
+{
+ if (__glutWindowWorkList) {
+ GLUTwindow *remainder, *work;
+
+ work = __glutWindowWorkList;
+ __glutWindowWorkList = NULL;
+ if (work) {
+ remainder = processWindowWorkList(work);
+ if (remainder) {
+ *beforeEnd = __glutWindowWorkList;
+ __glutWindowWorkList = remainder;
+ }
+ }
+ }
+}
+
+/* CENTRY */
+void GLUTAPIENTRY
+glutMainLoop(void)
+{
+#if !defined(_WIN32)
+ if (!__glutDisplay)
+ __glutFatalUsage("main loop entered with out proper initialization.");
+#endif
+ if (!__glutWindowListSize)
+ __glutFatalUsage(
+ "main loop entered with no windows created.");
+ for (;;) {
+ __glutProcessWindowWorkLists();
+ if (__glutIdleFunc || __glutWindowWorkList) {
+ idleWait();
+ } else {
+ if (__glutTimerList) {
+ waitForSomething();
+ } else {
+ processEventsAndTimeouts();
+ }
+ }
+ }
+}
+/* ENDCENTRY */