2 /* Copyright (c) Mark J. Kilgard, 1994, 1995, 1996, 1997, 1998. */
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. */
9 #include <GL/vms_x_fix.h>
16 #include <string.h> /* Some FD_ZERO macros use memset without
17 prototyping memset. */
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>. */
25 # include <bstring.h> /* prototype for bzero used by FD_ZERO */
27 # if (defined(SVR4) || defined(CRAY) || defined(AIXV3)) && !defined(FD_SETSIZE)
28 # include <sys/select.h> /* select system call interface */
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>
39 #include <sys/types.h>
42 //??? 䨣 ?? # include <sys/time.h>
43 #elif !defined(_WIN32)
44 # if defined(__vms) && ( __VMS_VER < 70000000 )
45 # include <sys/time.h>
48 # include <sys/time.h>
52 # include <X11/Xlib.h>
53 # include <X11/keysym.h>
56 # include <sys/time.h>
58 # include <sys/timeb.h>
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>
71 #if defined(__vms) && ( __VMS_VER < 70000000 )
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 */
81 static GLUTtimer
*freeTimerList
= NULL
;
83 GLUTidleCB __glutIdleFunc
= NULL
;
84 GLUTtimer
*__glutTimerList
= NULL
;
85 #ifdef SUPPORT_FORTRAN
86 GLUTtimer
*__glutNewTimer
;
88 GLUTwindow
*__glutWindowWorkList
= NULL
;
89 GLUTmenu
*__glutMappedMenu
;
90 GLUTmenu
*__glutCurrentMenu
= NULL
;
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
);
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;
109 glutIdleFunc(GLUTidleCB idleFunc
)
111 __glutIdleFunc
= idleFunc
;
115 glutTimerFunc(unsigned int interval
, GLUTtimerCB timerFunc
, int value
)
117 GLUTtimer
*timer
, *other
;
129 timer
= freeTimerList
;
130 freeTimerList
= timer
->next
;
132 timer
= (GLUTtimer
*) malloc(sizeof(GLUTtimer
));
134 __glutFatalError("out of memory.");
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
;
142 timer
->timeout
.tv_sec
= (int) interval
/ 1000;
143 timer
->timeout
.tv_usec
= (int) (interval
% 1000) * 1000;
145 timer
->value
= value
;
148 ADD_TIME(timer
->timeout
, timer
->timeout
, now
);
149 prevptr
= &__glutTimerList
;
151 while (other
&& IS_AFTER(other
->timeout
, timer
->timeout
)) {
152 prevptr
= &other
->next
;
156 #ifdef SUPPORT_FORTRAN
157 __glutNewTimer
= timer
; /* for Fortran binding! */
172 /* Assumption is that __glutTimerList is already determined
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
)
187 __glutPutOnWorkList(GLUTwindow
* window
, int workMask
)
189 if (window
->workMask
) {
190 /* Already on list; just OR in new workMask. */
191 window
->workMask
|= workMask
;
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
;
205 __glutPostRedisplay(GLUTwindow
* window
, int layerMask
)
207 int shown
= (layerMask
& (GLUT_REDISPLAY_WORK
| GLUT_REPAIR_WORK
)) ?
208 window
->shownState
: window
->overlay
->shownState
;
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
);
221 glutPostRedisplay(void)
223 __glutPostRedisplay(__glutCurrentWindow
, GLUT_REDISPLAY_WORK
);
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. */
231 glutPostWindowRedisplay(int win
)
233 __glutPostRedisplay(__glutWindowList
[win
- 1], GLUT_REDISPLAY_WORK
);
237 static GLUTeventParser
*eventParserList
= NULL
;
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. */
246 __glutRegisterEventParser(GLUTeventParser
* parser
)
248 parser
->next
= eventParserList
;
249 eventParserList
= parser
;
253 markWindowHidden(GLUTwindow
* window
)
255 if (GLUT_HIDDEN
!= window
->visState
) {
258 if (window
->windowStatus
) {
259 window
->visState
= GLUT_HIDDEN
;
260 __glutSetWindow(window
);
261 window
->windowStatus(GLUT_HIDDEN
);
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
;
267 markWindowHidden(child
);
268 child
= child
->siblings
;
273 #if !defined(_WIN32) && !defined(__OS2__)
276 purgeStaleWindow(Window win
)
278 GLUTstale
**pEntry
= &__glutStaleWindowList
;
279 GLUTstale
*entry
= __glutStaleWindowList
;
281 /* Tranverse singly-linked stale window list look for the
284 if (entry
->win
== win
) {
285 /* Found it; delete it. */
286 *pEntry
= entry
->next
;
290 pEntry
= &entry
->next
;
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. */
305 interruptibleXNextEvent(Display
* dpy
, XEvent
* event
)
310 /* Flush X protocol since XPending does not do this
312 XFlush(__glutDisplay
);
314 if (XPending(__glutDisplay
)) {
315 XNextEvent(dpy
, event
);
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) */
327 FD_SET(__glutConnectionFD
, &fds
);
328 rc
= select(__glutConnectionFD
+ 1, &fds
, NULL
, NULL
, NULL
);
330 if (errno
== EINTR
) {
333 __glutFatalError("select error.");
343 processEventsAndTimeouts(void)
347 QMSG qmsg
; /* message from message queue */
348 extern HAB hab
; /* PM anchor block handle */
350 if(! WinGetMsg( hab
, &qmsg
, 0UL, 0UL, 0UL ) )
352 WinDispatchMsg( hab
, /* PM anchor block handle */
353 &qmsg
); /* pointer to message */
355 #elif defined(_WIN32)
358 if(!GetMessage(&event
, NULL
, 0, 0)) /* bail if no more messages */
360 TranslateMessage(&event
); /* translate virtual-key messages */
361 DispatchMessage(&event
); /* call the window proc */
362 /* see win32_event.c for event (message) processing procedures */
364 static int mappedMenuButton
;
365 GLUTeventParser
*parser
;
368 GLUTkeyboardCB keyboard
;
369 GLUTspecialCB special
;
370 int gotEvent
, width
, height
;
372 gotEvent
= interruptibleXNextEvent(__glutDisplay
, &event
);
374 switch (event
.type
) {
376 XRefreshKeyboardMapping((XMappingEvent
*) & event
);
378 case ConfigureNotify
:
379 window
= __glutGetWindow(event
.xconfigure
.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
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
);
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! */
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
);
413 /* compress expose events */
414 while (XEventsQueued(__glutDisplay
, QueuedAfterReading
)
416 XPeekEvent(__glutDisplay
, &ahead
);
417 if (ahead
.type
!= Expose
||
418 ahead
.xexpose
.window
!= event
.xexpose
.window
) {
421 XNextEvent(__glutDisplay
, &event
);
423 if (event
.xexpose
.count
== 0) {
426 if (__glutMappedMenu
&&
427 (menu
= __glutGetMenu(event
.xexpose
.window
))) {
428 __glutPaintMenu(menu
);
430 window
= __glutGetWindow(event
.xexpose
.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
);
440 /* there are more exposes to read; wait to redisplay */
445 if (__glutMappedMenu
&& event
.type
== ButtonRelease
446 && mappedMenuButton
== event
.xbutton
.button
) {
447 /* Menu is currently popped up and its button is
449 __glutFinishMenu(event
.xbutton
.window
, event
.xbutton
.x
, event
.xbutton
.y
);
451 window
= __glutGetWindow(event
.xbutton
.window
);
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
;
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. */
471 } else if (window
->mouse
) {
472 __glutSetWindow(window
);
473 __glutModifierMask
= event
.xbutton
.state
;
474 window
->mouse(event
.xbutton
.button
- 1,
475 event
.type
== ButtonRelease
?
477 event
.xbutton
.x
, event
.xbutton
.y
);
478 __glutModifierMask
= ~0;
480 /* Stray mouse events. Ignore. */
483 /* Window might have been destroyed and all the
484 events for the window may not yet be received. */
489 if (!__glutMappedMenu
) {
490 window
= __glutGetWindow(event
.xmotion
.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
);
499 /* If passive motion function registered _and_
500 buttons not held down, call passive motion
502 else if (window
->passive
&&
503 ((event
.xmotion
.state
&
504 (Button1Mask
| Button2Mask
| Button3Mask
)) ==
506 __glutSetWindow(window
);
507 window
->passive(event
.xmotion
.x
,
512 /* Motion events are thrown away when a pop up menu
518 window
= __glutGetWindow(event
.xkey
.window
);
522 if (event
.type
== KeyPress
) {
523 keyboard
= window
->keyboard
;
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. */
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
);
546 keyboard
= window
->keyboardUp
;
552 rc
= XLookupString(&event
.xkey
, tmp
, sizeof(tmp
),
555 __glutSetWindow(window
);
556 __glutModifierMask
= event
.xkey
.state
;
558 event
.xkey
.x
, event
.xkey
.y
);
559 __glutModifierMask
= ~0;
563 if (event
.type
== KeyPress
) {
564 special
= window
->special
;
566 special
= window
->specialUp
;
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. */
576 #define XK_KP_Home 0xFF95
579 #define XK_KP_Left 0xFF96
582 #define XK_KP_Up 0xFF97
585 #define XK_KP_Right 0xFF98
588 #define XK_KP_Down 0xFF99
591 #define XK_KP_Prior 0xFF9A
594 #define XK_KP_Next 0xFF9B
597 #define XK_KP_End 0xFF9C
600 #define XK_KP_Insert 0xFF9E
603 #define XK_KP_Delete 0xFF9F
606 ks
= XLookupKeysym((XKeyEvent
*) & event
, 0);
607 /* XXX Verbose, but makes no assumptions about keysym
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 */
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;
635 case XK_KP_Prior
: /* Introduced in X11R6. */
637 /* XK_Prior same as X11R6's XK_Page_Up */
638 key
= GLUT_KEY_PAGE_UP
;
640 case XK_KP_Next
: /* Introduced in X11R6. */
642 /* XK_Next same as X11R6's XK_Page_Down */
643 key
= GLUT_KEY_PAGE_DOWN
;
645 case XK_KP_Home
: /* Introduced in X11R6. */
652 case XK_KP_End
: /* Introduced in X11R6. */
659 case XK_KP_Insert
: /* Introduced in X11R6. */
661 key
= GLUT_KEY_INSERT
;
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
);
675 __glutSetWindow(window
);
676 __glutModifierMask
= event
.xkey
.state
;
677 special(key
, event
.xkey
.x
, event
.xkey
.y
);
678 __glutModifierMask
= ~0;
684 if (event
.xcrossing
.mode
!= NotifyNormal
||
685 event
.xcrossing
.detail
== NotifyNonlinearVirtual
||
686 event
.xcrossing
.detail
== NotifyVirtual
) {
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. */
697 if (__glutMappedMenu
) {
701 item
= __glutGetMenuItem(__glutMappedMenu
,
702 event
.xcrossing
.window
, &num
);
704 __glutMenuItemEnterOrLeave(item
, num
, event
.type
);
708 window
= __glutGetWindow(event
.xcrossing
.window
);
711 if (event
.type
== EnterNotify
) {
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. */
719 if (window
->entryState
!= EnterNotify
) {
720 int num
= window
->num
;
721 Window xid
= window
->win
;
723 window
->entryState
= EnterNotify
;
724 __glutSetWindow(window
);
725 window
->entry(GLUT_ENTERED
);
727 if (__glutMappedMenu
) {
729 /* Do not generate any passive motion events
730 when menus are in use. */
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
741 window
= __glutWindowList
[num
];
742 if (window
&& window
->passive
&& window
->win
== xid
) {
743 __glutSetWindow(window
);
744 window
->passive(event
.xcrossing
.x
, event
.xcrossing
.y
);
749 if (window
->entryState
!= LeaveNotify
) {
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
763 if (XEventsQueued(__glutDisplay
, QueuedAfterReading
)) {
764 XPeekEvent(__glutDisplay
, &ahead
);
765 if (ahead
.type
== EnterNotify
&&
766 __glutGetWindow(ahead
.xcrossing
.window
) == window
) {
767 XNextEvent(__glutDisplay
, &event
);
771 window
->entryState
= LeaveNotify
;
772 __glutSetWindow(window
);
773 window
->entry(GLUT_LEFT
);
776 } else if (window
->passive
) {
777 __glutSetWindow(window
);
778 window
->passive(event
.xcrossing
.x
, event
.xcrossing
.y
);
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
789 window
= __glutGetWindow(event
.xunmap
.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.
798 markWindowHidden(window
);
801 case VisibilityNotify
:
802 window
= __glutGetWindow(event
.xvisibility
.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;
810 if (visState
!= window
->visState
) {
811 if (window
->windowStatus
) {
812 window
->visState
= visState
;
813 __glutSetWindow(window
);
814 window
->windowStatus(visState
);
820 if (event
.xclient
.data
.l
[0] == __glutWMDeleteWindow
)
824 purgeStaleWindow(event
.xdestroywindow
.window
);
826 case CirculateNotify
:
830 /* Uninteresting to GLUT (but possible for GLUT to
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.
840 parser
= eventParserList
;
842 if (parser
->func(&event
))
844 parser
= parser
->next
;
850 if (__glutTimerList
) {
854 while (XPending(__glutDisplay
));
858 waitForSomething(void)
860 #if defined(__vms) && ( __VMS_VER < 70000000 )
861 static struct timeval6 zerotime
=
863 unsigned int timer_efn
;
864 #define timer_id 'glut' /* random :-) number */
865 unsigned int wait_mask
;
867 static struct timeval zerotime
=
871 #elif !defined(_WIN32)
876 struct timeval6 now
, timeout
, waittime
;
878 struct timeval now
, timeout
, waittime
;
884 /* Flush X protocol since XPending does not do this
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
897 goto immediatelyHandleXinput
;
899 #if defined(__vms) && ( __VMS_VER < 70000000 )
900 timeout
= __glutTimerList
->timeout
;
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;
912 rc
= SYS$
CLREF(timer_efn
);
913 rc
= SYS$
SETIMR(timer_efn
, &timeout
, NULL
, timer_id
, 0);
914 wait_mask
|= 1 << (timer_efn
& 31);
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
);
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 */
927 #elif !defined(_WIN32)
929 FD_SET(__glutConnectionFD
, &fds
);
931 timeout
= __glutTimerList
->timeout
;
933 if (IS_AFTER(now
, timeout
)) {
934 TIMEDELTA(waittime
, timeout
, now
);
941 #elif !defined(_WIN32)
942 rc
= select(__glutConnectionFD
+ 1, &fds
,
943 NULL
, NULL
, &waittime
);
944 if (rc
< 0 && errno
!= EINTR
)
945 __glutFatalError("select error.");
948 MsgWaitForMultipleObjects(0, NULL
, FALSE
,
949 waittime
.tv_sec
*1000 + waittime
.tv_usec
/1000, QS_ALLINPUT
);
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
959 if (XPending(__glutDisplay
)) {
960 immediatelyHandleXinput
:
961 processEventsAndTimeouts();
971 if (XPending(__glutDisplay
)) {
972 processEventsAndTimeouts();
974 if (__glutTimerList
) {
978 /* Make sure idle func still exists! */
979 if (__glutIdleFunc
) {
984 static GLUTwindow
**beforeEnd
;
987 processWindowWorkList(GLUTwindow
* window
)
991 if (window
->prevWorkWin
) {
992 window
->prevWorkWin
= processWindowWorkList(window
->prevWorkWin
);
994 beforeEnd
= &window
->prevWorkWin
;
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. */
1004 workMask
= window
->workMask
;
1005 assert((workMask
& GLUT_DUMMY_WORK
) == 0);
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
;
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
)) {
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
) {
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
;
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
;
1041 XChangeWindowAttributes(__glutDisplay
, child
->win
,
1043 child
= child
->siblings
;
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
);
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
);
1059 /* Be sure to configure window BEFORE map window is done. */
1060 if (workMask
& GLUT_CONFIGURE_WORK
) {
1061 #if defined(__OS2__)
1064 #elif defined(_WIN32)
1067 UINT flags
= SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOOWNERZORDER
1068 | SWP_NOSENDCHANGING
| SWP_NOSIZE
| SWP_NOZORDER
;
1070 GetClientRect(window
->win
, &changes
);
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
) {
1077 ClientToScreen(window
->win
, &point
);
1078 changes
.left
= point
.x
;
1079 changes
.top
= point
.y
;
1081 if (window
->desiredConfMask
& (CWX
| CWY
)) {
1082 changes
.left
= window
->desiredX
;
1083 changes
.top
= window
->desiredY
;
1084 flags
&= ~SWP_NOMOVE
;
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) ... */
1093 if (window
->desiredConfMask
& CWStackMode
) {
1094 flags
&= ~SWP_NOZORDER
;
1095 /* XXX Overlay support might require something special here. */
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
,
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
,
1117 /* Zero out the mask. */
1118 window
->desiredConfMask
= 0;
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
;
1128 XWindowChanges changes
;
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
) {
1142 hints
.flags
= MWM_HINTS_DECORATIONS
;
1143 hints
.decorations
= 0; /* Absolutely no
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. */
1163 hints
.flags
= USPosition
| USSize
;
1166 hints
.width
= window
->desiredWidth
;
1167 hints
.height
= window
->desiredHeight
;
1168 XSetWMNormalHints(__glutDisplay
, window
->win
, &hints
);
1171 XDeleteProperty(__glutDisplay
, window
->win
, __glutMotifHints
);
1175 if (window
->desiredConfMask
& CWStackMode
) {
1176 changes
.stack_mode
= window
->desiredStack
;
1177 /* Do not let glutPushWindow push window beneath the
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
;
1186 XConfigureWindow(__glutDisplay
, window
->win
,
1187 window
->desiredConfMask
, &changes
);
1188 window
->desiredConfMask
= 0;
1191 #if !defined(_WIN32) && !defined(__OS2__)
1192 /* Be sure to establish the colormaps BEFORE map window is
1194 if (workMask
& GLUT_COLORMAP_WORK
) {
1195 __glutEstablishColormapsProperty(window
);
1198 if (workMask
& GLUT_MAP_WORK
) {
1199 switch (window
->desiredMapState
) {
1200 case WithdrawnState
:
1201 if (window
->parent
) {
1202 XUnmapWindow(__glutDisplay
, window
->win
);
1204 XWithdrawWindow(__glutDisplay
, window
->win
,
1207 window
->shownState
= 0;
1210 XMapWindow(__glutDisplay
, window
->win
);
1211 window
->shownState
= 1;
1214 case GameModeState
: /* Not an Xlib value. */
1215 ShowWindow(window
->win
, SW_SHOW
);
1216 window
->shownState
= 1;
1220 XIconifyWindow(__glutDisplay
, window
->win
, __glutScreen
);
1221 window
->shownState
= 0;
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
;
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
;
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. */
1252 if (window
->overlay
&& window
->overlay
->display
) {
1253 int num
= window
->num
;
1254 Window xid
= window
->overlay
? window
->overlay
->win
: None
;
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. */
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
;
1271 /* Render to normal plane. */
1273 window
->renderDc
= window
->hdc
;
1275 window
->renderWin
= window
->win
;
1276 window
->renderCtx
= window
->ctx
;
1277 __glutWindowDamaged
= (workMask
& GLUT_REPAIR_WORK
);
1278 __glutSetWindow(window
);
1279 window
->usedSwapBuffers
= 0;
1281 __glutWindowDamaged
= 0;
1283 skippedDisplayCallback1
:;
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
) {
1290 /* Render to overlay. */
1292 window
->renderDc
= window
->overlay
->hdc
;
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;
1301 /* Overlay may have since been destroyed or the
1302 overlay callback may have been disabled during
1303 normal display callback. */
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
;
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;
1320 __glutWindowDamaged
= 0;
1322 skippedDisplayCallback2
:;
1325 /* Combine workMask with window->workMask to determine what
1326 finish and debug work there is. */
1327 workMask
|= window
->workMask
;
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
1336 __glutSetWindow(window
);
1339 if (workMask
& GLUT_DEBUG_WORK
) {
1340 __glutSetWindow(window
);
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. */
1349 /* Remove current window from work list. */
1350 return window
->prevWorkWin
;
1355 static /* X11 implementations do not need this global. */
1358 __glutProcessWindowWorkLists(void)
1360 if (__glutWindowWorkList
) {
1361 GLUTwindow
*remainder
, *work
;
1363 work
= __glutWindowWorkList
;
1364 __glutWindowWorkList
= NULL
;
1366 remainder
= processWindowWorkList(work
);
1368 *beforeEnd
= __glutWindowWorkList
;
1369 __glutWindowWorkList
= remainder
;
1379 #if !defined(_WIN32)
1381 __glutFatalUsage("main loop entered with out proper initialization.");
1383 if (!__glutWindowListSize
)
1385 "main loop entered with no windows created.");
1387 __glutProcessWindowWorkLists();
1388 if (__glutIdleFunc
|| __glutWindowWorkList
) {
1391 if (__glutTimerList
) {
1394 processEventsAndTimeouts();