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