cffbc1aa543c5656143797a3baf59c17a545f94c
1 /***********************************************************
2 * Copyright (C) 1997, Be Inc. Copyright (C) 1999, Jake Hamby.
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.
11 * DESCRIPTION: here it is, the BeOS GLUT event loop
12 ***********************************************************/
14 /***********************************************************
16 ***********************************************************/
19 #include "glutState.h"
20 #include "glutBlocker.h"
22 /***********************************************************
25 * DESCRIPTION: list of timer callbacks
26 ***********************************************************/
28 GLUTtimer
*next
; // list of timers
29 bigtime_t timeout
; // time to be called
30 GLUTtimerCB func
; // function to call
34 /***********************************************************
36 ***********************************************************/
37 static GLUTtimer
*__glutTimerList
= 0; // list of timer callbacks
38 static GLUTtimer
*freeTimerList
= 0;
40 /***********************************************************
41 * FUNCTION: glutTimerFunc (7.19)
43 * DESCRIPTION: register a new timer callback
44 ***********************************************************/
46 glutTimerFunc(unsigned int interval
, GLUTtimerCB timerFunc
, int value
)
48 GLUTtimer
*timer
, *other
;
55 timer
= freeTimerList
;
56 freeTimerList
= timer
->next
;
58 timer
= new GLUTtimer();
60 __glutFatalError("out of memory.");
63 timer
->func
= timerFunc
;
66 timer
->timeout
= system_time() + (interval
*1000); // 1000 ticks in a millisecond
67 prevptr
= &__glutTimerList
;
69 while (other
&& (other
->timeout
< timer
->timeout
)) {
70 prevptr
= &other
->next
;
77 /***********************************************************
78 * FUNCTION: handleTimeouts
80 * DESCRIPTION: private function to handle outstanding timeouts
81 ***********************************************************/
88 /* Assumption is that __glutTimerList is already determined
91 while (__glutTimerList
->timeout
<= now
) {
92 timer
= __glutTimerList
;
93 if(gState
.currentWindow
)
94 gState
.currentWindow
->LockGL();
95 timer
->func(timer
->value
);
96 if(gState
.currentWindow
)
97 gState
.currentWindow
->UnlockGL();
98 __glutTimerList
= timer
->next
;
99 timer
->next
= freeTimerList
;
100 freeTimerList
= timer
;
101 if (!__glutTimerList
)
107 /***********************************************************
108 * FUNCTION: processEventsAndTimeouts
110 * DESCRIPTION: clear gBlock, then check all windows for events
111 ***********************************************************/
113 processEventsAndTimeouts(void)
115 gBlock
.WaitEvent(); // if there is already an event, returns
116 // immediately, otherwise wait forever
117 gBlock
.ClearEvents();
120 exit(0); // exit handler cleans up windows and quits nicely
122 if (gState
.currentWindow
)
123 gState
.currentWindow
->LockGL();
124 for(int i
=0; i
<gState
.windowListSize
; i
++) {
125 if (gState
.windowList
[i
]) {
126 GlutWindow
*win
= gState
.windowList
[i
];
127 // NOTE: we can use win as a shortcut for gState.windowList[i]
128 // in callbacks, EXCEPT we need to check the original variable
129 // after each callback to make sure the window hasn't been destroyed
130 if (win
->anyevents
) {
131 win
->anyevents
= false;
132 if (win
->reshapeEvent
) {
133 win
->reshapeEvent
= false;
134 __glutSetWindow(win
);
135 win
->reshape(win
->m_width
, win
->m_height
);
137 if (!gState
.windowList
[i
])
138 continue; // window was destroyed by callback!
140 if (win
->displayEvent
) {
141 win
->displayEvent
= false;
142 __glutSetWindow(win
);
145 if (!gState
.windowList
[i
])
146 continue; // window was destroyed by callback!
148 if (win
->mouseEvent
) {
149 win
->mouseEvent
= false;
150 __glutSetWindow(win
);
152 gState
.modifierKeys
= win
->modifierKeys
;
153 win
->mouse(win
->button
, win
->mouseState
, win
->mouseX
, win
->mouseY
);
154 gState
.modifierKeys
= ~0;
157 if (!gState
.windowList
[i
])
158 continue; // window was destroyed by callback!
160 if (win
->menuEvent
) {
161 win
->menuEvent
= false;
162 __glutSetWindow(win
);
163 GlutMenu
*menu
= __glutGetMenuByNum(win
->menuNumber
);
165 gState
.currentMenu
= menu
;
166 menu
->select(win
->menuValue
);
169 if (!gState
.windowList
[i
])
170 continue; // window was destroyed by callback!
172 if (win
->statusEvent
) {
173 win
->statusEvent
= false;
174 __glutSetWindow(win
);
175 if (gState
.menuStatus
) {
176 gState
.currentMenu
= __glutGetMenuByNum(win
->menuNumber
);
177 gState
.menuStatus(win
->menuStatus
, win
->statusX
, win
->statusY
);
180 if (!gState
.windowList
[i
])
181 continue; // window was destroyed by callback!
183 if (win
->motionEvent
) {
184 win
->motionEvent
= false;
185 __glutSetWindow(win
);
187 win
->motion(win
->motionX
, win
->motionY
);
189 if (!gState
.windowList
[i
])
190 continue; // window was destroyed by callback!
192 if (win
->passiveEvent
) {
193 win
->passiveEvent
= false;
194 __glutSetWindow(win
);
196 win
->passive(win
->passiveX
, win
->passiveY
);
198 if (!gState
.windowList
[i
])
199 continue; // window was destroyed by callback!
201 if (win
->keybEvent
) {
202 win
->keybEvent
= false;
203 __glutSetWindow(win
);
205 gState
.modifierKeys
= win
->modifierKeys
;
206 win
->keyboard(win
->key
, win
->keyX
, win
->keyY
);
207 gState
.modifierKeys
= ~0;
210 if (!gState
.windowList
[i
])
211 continue; // window was destroyed by callback!
213 if (win
->specialEvent
) {
214 win
->specialEvent
= false;
215 __glutSetWindow(win
);
217 gState
.modifierKeys
= win
->modifierKeys
;
218 win
->special(win
->specialKey
, win
->specialX
, win
->specialY
);
219 gState
.modifierKeys
= ~0;
222 if (!gState
.windowList
[i
])
223 continue; // window was destroyed by callback!
225 if (win
->entryEvent
) {
226 win
->entryEvent
= false;
227 __glutSetWindow(win
);
229 win
->entry(win
->entryState
);
231 if (!gState
.windowList
[i
])
232 continue; // window was destroyed by callback!
234 if (win
->windowStatusEvent
) {
235 win
->windowStatusEvent
= false;
236 __glutSetWindow(win
);
237 if (win
->windowStatus
)
238 win
->windowStatus(win
->visState
);
240 if (!gState
.windowList
[i
])
241 continue; // window was destroyed by callback!
245 if (gState
.currentWindow
)
246 gState
.currentWindow
->UnlockGL();
248 // This code isn't necessary since BGLView automatically traps errors
251 for(int i
=0; i
<gState
.windowListSize
; i
++) {
252 if (gState
.windowList
[i
]) {
253 gState
.windowList
[i
]->LockGL();
255 gState
.windowList
[i
]->UnlockGL();
260 if (__glutTimerList
) {
265 /***********************************************************
266 * FUNCTION: waitForSomething
268 * DESCRIPTION: use gBlock to wait for a new event or timeout
269 ***********************************************************/
271 waitForSomething(void)
273 bigtime_t timeout
= __glutTimerList
->timeout
;
274 bigtime_t now
= system_time();
276 if (gBlock
.PendingEvent())
277 goto immediatelyHandleEvent
;
280 gBlock
.WaitEvent(timeout
-now
);
281 if (gBlock
.PendingEvent()) {
282 immediatelyHandleEvent
:
283 processEventsAndTimeouts();
290 /***********************************************************
293 * DESCRIPTION: check for events, then call idle function
294 ***********************************************************/
298 if (gBlock
.PendingEvent()) {
299 processEventsAndTimeouts();
304 /* Make sure idle func still exists! */
305 if(gState
.currentWindow
)
306 gState
.currentWindow
->LockGL();
310 if(gState
.currentWindow
)
311 gState
.currentWindow
->UnlockGL();
314 /***********************************************************
315 * FUNCTION: glutMainLoop (3.1)
317 * DESCRIPTION: enter the event processing loop
318 ***********************************************************/
321 if (!gState
.windowListSize
)
322 __glutFatalUsage("main loop entered with no windows created.");
324 if(gState
.currentWindow
)
325 gState
.currentWindow
->UnlockGL();
331 if (__glutTimerList
) {
334 processEventsAndTimeouts();
340 /***********************************************************
345 * DESCRIPTION: handles keyboard and special events
346 ***********************************************************/
347 void GlutWindow::KeyDown(const char *s
, int32 slen
)
350 BGLView::KeyDown(s
,slen
);
356 switch(Window()->CurrentMessage()->FindInt32("key")) {
385 aChar
= GLUT_KEY_F10
;
388 aChar
= GLUT_KEY_F11
;
391 aChar
= GLUT_KEY_F12
;
397 aChar
= GLUT_KEY_LEFT
;
403 aChar
= GLUT_KEY_RIGHT
;
406 aChar
= GLUT_KEY_DOWN
;
409 aChar
= GLUT_KEY_PAGE_UP
;
412 aChar
= GLUT_KEY_PAGE_DOWN
;
415 aChar
= GLUT_KEY_HOME
;
418 aChar
= GLUT_KEY_END
;
421 aChar
= GLUT_KEY_INSERT
;
424 anyevents
= specialEvent
= true;
425 GetMouse(&p
,&m_buttons
);
429 goto setModifiers
; // set the modifier variable
438 anyevents
= keybEvent
= true;
439 GetMouse(&p
,&m_buttons
);
445 uint32 beMod
= Window()->CurrentMessage()->FindInt32("modifiers");
446 if(beMod
& B_SHIFT_KEY
)
447 modifierKeys
|= GLUT_ACTIVE_SHIFT
;
448 if(beMod
& B_CONTROL_KEY
)
449 modifierKeys
|= GLUT_ACTIVE_CTRL
;
450 if(beMod
& B_OPTION_KEY
) {
451 // since the window traps B_COMMAND_KEY, we'll have to settle
452 // for the option key.. but we need to get the raw character,
453 // not the Unicode-enhanced version
454 key
= Window()->CurrentMessage()->FindInt32("raw_char");
455 modifierKeys
|= GLUT_ACTIVE_ALT
;
461 /***********************************************************
464 * FUNCTION: MouseDown
466 * DESCRIPTION: handles mouse and menustatus events
467 ***********************************************************/
468 void GlutWindow::MouseDown(BPoint point
)
470 BGLView::MouseDown(point
);
474 /***********************************************************
477 * FUNCTION: MouseCheck
479 * DESCRIPTION: checks for button state changes
480 ***********************************************************/
481 void GlutWindow::MouseCheck()
484 return; // we already have an outstanding mouse event
488 GetMouse(&point
, &newButtons
);
489 if (m_buttons
!= newButtons
) {
490 if (newButtons
&B_PRIMARY_MOUSE_BUTTON
&& !(m_buttons
&B_PRIMARY_MOUSE_BUTTON
)) {
491 button
= GLUT_LEFT_BUTTON
;
492 mouseState
= GLUT_DOWN
;
493 } else if (m_buttons
&B_PRIMARY_MOUSE_BUTTON
&& !(newButtons
&B_PRIMARY_MOUSE_BUTTON
)) {
494 button
= GLUT_LEFT_BUTTON
;
495 mouseState
= GLUT_UP
;
496 } else if (newButtons
&B_SECONDARY_MOUSE_BUTTON
&& !(m_buttons
&B_SECONDARY_MOUSE_BUTTON
)) {
497 button
= GLUT_RIGHT_BUTTON
;
498 mouseState
= GLUT_DOWN
;
499 } else if (m_buttons
&B_SECONDARY_MOUSE_BUTTON
&& !(newButtons
&B_SECONDARY_MOUSE_BUTTON
)) {
500 button
= GLUT_RIGHT_BUTTON
;
501 mouseState
= GLUT_UP
;
502 } else if (newButtons
&B_TERTIARY_MOUSE_BUTTON
&& !(m_buttons
&B_TERTIARY_MOUSE_BUTTON
)) {
503 button
= GLUT_MIDDLE_BUTTON
;
504 mouseState
= GLUT_DOWN
;
505 } else if (m_buttons
&B_TERTIARY_MOUSE_BUTTON
&& !(newButtons
&B_TERTIARY_MOUSE_BUTTON
)) {
506 button
= GLUT_MIDDLE_BUTTON
;
507 mouseState
= GLUT_UP
;
510 return; // no change, return
512 m_buttons
= newButtons
;
514 if (mouseState
== GLUT_DOWN
) {
515 BWindow
*w
= Window();
516 GlutMenu
*m
= __glutGetMenuByNum(menu
[button
]);
518 if (gState
.menuStatus
) {
519 anyevents
= statusEvent
= true;
520 menuNumber
= menu
[button
];
521 menuStatus
= GLUT_MENU_IN_USE
;
522 statusX
= (int)point
.x
;
523 statusY
= (int)point
.y
;
526 BRect bounds
= w
->Frame();
527 point
.x
+= bounds
.left
;
528 point
.y
+= bounds
.top
;
529 GlutPopUp
*bmenu
= static_cast<GlutPopUp
*>(m
->CreateBMenu()); // start menu
530 bmenu
->point
= point
;
532 thread_id menu_thread
= spawn_thread(MenuThread
, "menu thread", B_NORMAL_PRIORITY
, bmenu
);
533 resume_thread(menu_thread
);
539 anyevents
= mouseEvent
= true;
540 mouseX
= (int)point
.x
;
541 mouseY
= (int)point
.y
;
543 uint32 beMod
= modifiers();
544 if(beMod
& B_SHIFT_KEY
)
545 modifierKeys
|= GLUT_ACTIVE_SHIFT
;
546 if(beMod
& B_CONTROL_KEY
)
547 modifierKeys
|= GLUT_ACTIVE_CTRL
;
548 if(beMod
& B_OPTION_KEY
) {
549 modifierKeys
|= GLUT_ACTIVE_ALT
;
555 /***********************************************************
558 * FUNCTION: MouseMoved
560 * DESCRIPTION: handles entry, motion, and passive events
561 ***********************************************************/
562 void GlutWindow::MouseMoved(BPoint point
,
563 ulong transit
, const BMessage
*msg
)
565 BGLView::MouseMoved(point
,transit
,msg
);
567 if(transit
!= B_INSIDE_VIEW
) {
569 anyevents
= entryEvent
= true;
572 if (transit
== B_ENTERED_VIEW
) {
573 entryState
= GLUT_ENTERED
;
574 MakeFocus(); // make me the current focus
575 __glutSetCursor(cursor
);
577 entryState
= GLUT_LEFT
;
583 anyevents
= motionEvent
= true;
584 motionX
= (int)point
.x
;
585 motionY
= (int)point
.y
;
590 anyevents
= passiveEvent
= true;
591 passiveX
= (int)point
.x
;
592 passiveY
= (int)point
.y
;
598 /***********************************************************
601 * FUNCTION: FrameResized
603 * DESCRIPTION: handles reshape event
604 ***********************************************************/
605 void GlutWindow::FrameResized(float width
, float height
)
607 BGLView::FrameResized(width
, height
);
609 anyevents
= reshapeEvent
= true;
610 m_width
= (int)(width
)+1;
611 m_height
= (int)(height
)+1;
616 /***********************************************************
621 * DESCRIPTION: handles reshape and display events
622 ***********************************************************/
623 void GlutWindow::Draw(BRect updateRect
)
625 BGLView::Draw(updateRect
);
626 BRect frame
= Frame();
627 if (m_width
!= (frame
.Width()+1) || m_height
!= (frame
.Height()+1)) {
628 FrameResized(frame
.Width(), frame
.Height());
632 anyevents
= displayEvent
= true;
638 /***********************************************************
643 * DESCRIPTION: handles mouse up event (MouseUp is broken)
644 ***********************************************************/
645 void GlutWindow::Pulse()
648 if (m_buttons
) { // if there are buttons pressed
653 /***********************************************************
656 * FUNCTION: ErrorCallback
658 * DESCRIPTION: handles GL error messages
659 ***********************************************************/
660 void GlutWindow::ErrorCallback(GLenum errorCode
) {
661 __glutWarning("GL error: %s", gluErrorString(errorCode
));
664 /***********************************************************
667 * FUNCTION: MenuThread
669 * DESCRIPTION: a new thread to launch popup menu, wait
670 * wait for response, then clean up afterwards and
671 * send appropriate messages
672 ***********************************************************/
673 long GlutWindow::MenuThread(void *m
) {
674 GlutPopUp
*bmenu
= static_cast<GlutPopUp
*>(m
);
675 GlutWindow
*win
= bmenu
->win
; // my window
676 GlutBMenuItem
*result
= (GlutBMenuItem
*)bmenu
->Go(bmenu
->point
);
677 win
->Window()->Lock();
678 win
->anyevents
= win
->statusEvent
= true;
679 win
->menuStatus
= GLUT_MENU_NOT_IN_USE
;
680 win
->menuNumber
= bmenu
->menu
;
683 win
->GetMouse(&cursor
, &buttons
);
684 win
->statusX
= (int)cursor
.x
;
685 win
->statusY
= (int)cursor
.y
;
686 if(result
&& result
->menu
) {
687 win
->menuEvent
= true;
688 win
->menuNumber
= result
->menu
; // in case it was a submenu
689 win
->menuValue
= result
->value
;
691 win
->Window()->Unlock();