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