mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-24 10:38:11 +02:00
1399 lines
47 KiB
C++
1399 lines
47 KiB
C++
/* 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 <bert@mc.bio.uva.nl> 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 */
|