1 /***********************************************************
2 * Copyright (C) 1997, Be Inc. Copyright (C) 1999, Jake Hamby.
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 *
9 * FILE: glutEvent.cpp
10 *
11 * DESCRIPTION: here it is, the BeOS GLUT event loop
12 ***********************************************************/
13
14 /***********************************************************
15 * Headers
16 ***********************************************************/
17 #include <GL/glut.h>
18 #include "glutint.h"
19 #include "glutState.h"
20 #include "glutBlocker.h"
21 #include <stdio.h>
22 #include <stdlib.h>
23
24 #define MOUSE_WHEEL_UP 3
25 #define MOUSE_WHEEL_DOWN 4
26
27 /***********************************************************
28 * CLASS: GLUTtimer
29 *
30 * DESCRIPTION: list of timer callbacks
31 ***********************************************************/
32 struct GLUTtimer {
33 GLUTtimer *next; // list of timers
34 bigtime_t timeout; // time to be called
35 GLUTtimerCB func; // function to call
36 int value; // value
37 };
38
39 /***********************************************************
40 * Private variables
41 ***********************************************************/
42 static GLUTtimer *__glutTimerList = 0; // list of timer callbacks
43 static GLUTtimer *freeTimerList = 0;
44
45 /***********************************************************
46 * FUNCTION: glutTimerFunc (7.19)
47 *
48 * DESCRIPTION: register a new timer callback
49 ***********************************************************/
50 void APIENTRY
glutTimerFunc(unsigned int interval,GLUTtimerCB timerFunc,int value)51 glutTimerFunc(unsigned int interval, GLUTtimerCB timerFunc, int value)
52 {
53 GLUTtimer *timer, *other;
54 GLUTtimer **prevptr;
55
56 if (!timerFunc)
57 return;
58
59 if (freeTimerList) {
60 timer = freeTimerList;
61 freeTimerList = timer->next;
62 } else {
63 timer = new GLUTtimer();
64 if (!timer)
65 __glutFatalError("out of memory.");
66 }
67
68 timer->func = timerFunc;
69 timer->value = value;
70 timer->next = NULL;
71 timer->timeout = system_time() + (interval*1000); // 1000 ticks in a millisecond
72 prevptr = &__glutTimerList;
73 other = *prevptr;
74 while (other && (other->timeout < timer->timeout)) {
75 prevptr = &other->next;
76 other = *prevptr;
77 }
78 timer->next = other;
79 *prevptr = timer;
80 }
81
82 /***********************************************************
83 * FUNCTION: handleTimeouts
84 *
85 * DESCRIPTION: private function to handle outstanding timeouts
86 ***********************************************************/
87 static void
handleTimeouts(void)88 handleTimeouts(void)
89 {
90 bigtime_t now;
91 GLUTtimer *timer;
92
93 /* Assumption is that __glutTimerList is already determined
94 to be non-NULL. */
95 now = system_time();
96 while (__glutTimerList->timeout <= now) {
97 timer = __glutTimerList;
98 if(gState.currentWindow)
99 gState.currentWindow->LockGL();
100 timer->func(timer->value);
101 if(gState.currentWindow)
102 gState.currentWindow->UnlockGL();
103 __glutTimerList = timer->next;
104 timer->next = freeTimerList;
105 freeTimerList = timer;
106 if (!__glutTimerList)
107 break;
108 }
109 }
110
111
112 /***********************************************************
113 * FUNCTION: processEventsAndTimeouts
114 *
115 * DESCRIPTION: clear gBlock, then check all windows for events
116 ***********************************************************/
117 static void
processEventsAndTimeouts(void)118 processEventsAndTimeouts(void)
119 {
120 gBlock.WaitEvent(); // if there is already an event, returns
121 // immediately, otherwise wait forever
122 gBlock.ClearEvents();
123
124 if(gState.quitAll)
125 exit(0); // exit handler cleans up windows and quits nicely
126
127 if (gState.currentWindow)
128 gState.currentWindow->LockGL();
129 for(int i=0; i<gState.windowListSize; i++) {
130 if (gState.windowList[i]) {
131 GlutWindow *win = gState.windowList[i];
132 // NOTE: we can use win as a shortcut for gState.windowList[i]
133 // in callbacks, EXCEPT we need to check the original variable
134 // after each callback to make sure the window hasn't been destroyed
135 if (win->anyevents) {
136 win->anyevents = false;
137 if (win->reshapeEvent) {
138 win->reshapeEvent = false;
139 __glutSetWindow(win);
140 win->reshape(win->m_width, win->m_height);
141 }
142 if (!gState.windowList[i])
143 continue; // window was destroyed by callback!
144
145 if (win->displayEvent) {
146 win->displayEvent = false;
147 __glutSetWindow(win);
148 win->display();
149 }
150 if (!gState.windowList[i])
151 continue; // window was destroyed by callback!
152
153 if (win->mouseEvent) {
154 win->mouseEvent = false;
155 __glutSetWindow(win);
156 if (win->mouse) {
157 gState.modifierKeys = win->modifierKeys;
158 win->mouse(win->button, win->mouseState, win->mouseX, win->mouseY);
159 gState.modifierKeys = ~0;
160 }
161 }
162 if (!gState.windowList[i])
163 continue; // window was destroyed by callback!
164
165 if (win->menuEvent) {
166 win->menuEvent = false;
167 __glutSetWindow(win);
168 GlutMenu *menu = __glutGetMenuByNum(win->menuNumber);
169 if (menu) {
170 gState.currentMenu = menu;
171 menu->select(win->menuValue);
172 }
173 }
174 if (!gState.windowList[i])
175 continue; // window was destroyed by callback!
176
177 if (win->statusEvent) {
178 win->statusEvent = false;
179 __glutSetWindow(win);
180 if (gState.menuStatus) {
181 gState.currentMenu = __glutGetMenuByNum(win->menuNumber);
182 gState.menuStatus(win->menuStatus, win->statusX, win->statusY);
183 }
184 }
185 if (!gState.windowList[i])
186 continue; // window was destroyed by callback!
187
188 if (win->motionEvent) {
189 win->motionEvent = false;
190 __glutSetWindow(win);
191 if (win->motion)
192 win->motion(win->motionX, win->motionY);
193 }
194 if (!gState.windowList[i])
195 continue; // window was destroyed by callback!
196
197 if (win->passiveEvent) {
198 win->passiveEvent = false;
199 __glutSetWindow(win);
200 if (win->passive)
201 win->passive(win->passiveX, win->passiveY);
202 }
203 if (!gState.windowList[i])
204 continue; // window was destroyed by callback!
205
206 if (win->keybEvent) {
207 win->keybEvent = false;
208 __glutSetWindow(win);
209 if (win->keyboard) {
210 gState.modifierKeys = win->modifierKeys;
211 win->keyboard(win->key, win->keyX, win->keyY);
212 gState.modifierKeys = ~0;
213 }
214 }
215 if (!gState.windowList[i])
216 continue; // window was destroyed by callback!
217
218 if (win->specialEvent) {
219 win->specialEvent = false;
220 __glutSetWindow(win);
221 if (win->special) {
222 gState.modifierKeys = win->modifierKeys;
223 win->special(win->specialKey, win->specialX, win->specialY);
224 gState.modifierKeys = ~0;
225 }
226 }
227 if (!gState.windowList[i])
228 continue; // window was destroyed by callback!
229
230 if (win->keybUpEvent) {
231 win->keybUpEvent = false;
232 __glutSetWindow(win);
233 if (win->keyboardUp) {
234 gState.modifierKeys = win->modifierKeys;
235 win->keyboardUp(win->key, win->keyX, win->keyY);
236 gState.modifierKeys = ~0;
237 }
238 }
239 if (!gState.windowList[i])
240 continue; // window was destroyed by callback!
241
242 if (win->specialUpEvent) {
243 win->specialUpEvent = false;
244 __glutSetWindow(win);
245 if (win->specialUp) {
246 gState.modifierKeys = win->modifierKeys;
247 win->specialUp(win->specialKey, win->specialX, win->specialY);
248 gState.modifierKeys = ~0;
249 }
250 }
251 if (!gState.windowList[i])
252 continue; // window was destroyed by callback!
253
254
255 if (win->entryEvent) {
256 win->entryEvent = false;
257 __glutSetWindow(win);
258 if (win->entry)
259 win->entry(win->entryState);
260 }
261 if (!gState.windowList[i])
262 continue; // window was destroyed by callback!
263
264 if (win->windowStatusEvent) {
265 win->windowStatusEvent = false;
266 __glutSetWindow(win);
267 if (win->windowStatus)
268 win->windowStatus(win->visState);
269 }
270 if (!gState.windowList[i])
271 continue; // window was destroyed by callback!
272 }
273 }
274 }
275 if (gState.currentWindow)
276 gState.currentWindow->UnlockGL();
277
278 // This code isn't necessary since BGLView automatically traps errors
279 #if 0
280 if(gState.debug) {
281 for(int i=0; i<gState.windowListSize; i++) {
282 if (gState.windowList[i]) {
283 gState.windowList[i]->LockGL();
284 glutReportErrors();
285 gState.windowList[i]->UnlockGL();
286 }
287 }
288 }
289 #endif
290 if (__glutTimerList) {
291 handleTimeouts();
292 }
293 }
294
295 /***********************************************************
296 * FUNCTION: waitForSomething
297 *
298 * DESCRIPTION: use gBlock to wait for a new event or timeout
299 ***********************************************************/
300 static void
waitForSomething(void)301 waitForSomething(void)
302 {
303 bigtime_t timeout = __glutTimerList->timeout;
304 bigtime_t now = system_time();
305
306 if (gBlock.PendingEvent())
307 goto immediatelyHandleEvent;
308
309 if(timeout>now)
310 gBlock.WaitEvent(timeout-now);
311 if (gBlock.PendingEvent()) {
312 immediatelyHandleEvent:
313 processEventsAndTimeouts();
314 } else {
315 if (__glutTimerList)
316 handleTimeouts();
317 }
318 }
319
320 /***********************************************************
321 * FUNCTION: idleWait
322 *
323 * DESCRIPTION: check for events, then call idle function
324 ***********************************************************/
325 static void
idleWait(void)326 idleWait(void)
327 {
328 if (gBlock.PendingEvent()) {
329 processEventsAndTimeouts();
330 } else {
331 if (__glutTimerList)
332 handleTimeouts();
333 }
334 /* Make sure idle func still exists! */
335 if(gState.currentWindow)
336 gState.currentWindow->LockGL();
337 if (gState.idle) {
338 gState.idle();
339 }
340 if(gState.currentWindow)
341 gState.currentWindow->UnlockGL();
342 }
343
344 /***********************************************************
345 * FUNCTION: glutMainLoop (3.1)
346 *
347 * DESCRIPTION: enter the event processing loop
348 ***********************************************************/
glutMainLoop()349 void glutMainLoop()
350 {
351 if (!gState.windowListSize)
352 __glutFatalUsage("main loop entered with no windows created.");
353
354 if(gState.currentWindow)
355 gState.currentWindow->UnlockGL();
356
357 for (;;) {
358 if (gState.idle) {
359 idleWait();
360 } else {
361 if (__glutTimerList) {
362 waitForSomething();
363 } else {
364 processEventsAndTimeouts();
365 }
366 }
367 }
368 }
369
370
glutSetKeyRepeat(int repeatMode)371 void glutSetKeyRepeat(int repeatMode)
372 {
373 switch(repeatMode) {
374 case GLUT_KEY_REPEAT_DEFAULT:
375 gState.keyRepeatMode = GLUT_KEY_REPEAT_ON;
376 break;
377
378 case GLUT_KEY_REPEAT_ON:
379 case GLUT_KEY_REPEAT_OFF:
380 gState.keyRepeatMode = repeatMode;
381 break;
382
383 default:
384 __glutWarning("invalid glutSetKeyRepeat mode: %d", repeatMode);
385 }
386 }
387
388
glutIgnoreKeyRepeat(int ignore)389 void glutIgnoreKeyRepeat(int ignore)
390 {
391 if (gState.currentWindow)
392 gState.currentWindow->ignoreKeyRepeat = (ignore != 0);
393 }
394
395
396 /***********************************************************
397 * CLASS: GlutWindow
398 *
399 * FUNCTION: KeyDown
400 *
401 * DESCRIPTION: handles keyboard and special events
402 ***********************************************************/
KeyDown(const char * s,int32 slen)403 void GlutWindow::KeyDown(const char *s, int32 slen)
404 {
405 ulong aChar = s[0];
406 BGLView::KeyDown(s,slen);
407
408 BPoint p;
409
410 if (ignoreKeyRepeat
411 && Window()->CurrentMessage()->FindInt32("be:key_repeat") > 0)
412 return;
413
414 switch (aChar) {
415 case B_FUNCTION_KEY:
416 switch(Window()->CurrentMessage()->FindInt32("key")) {
417 case B_F1_KEY:
418 aChar = GLUT_KEY_F1;
419 goto specialLabel;
420 case B_F2_KEY:
421 aChar = GLUT_KEY_F2;
422 goto specialLabel;
423 case B_F3_KEY:
424 aChar = GLUT_KEY_F3;
425 goto specialLabel;
426 case B_F4_KEY:
427 aChar = GLUT_KEY_F4;
428 goto specialLabel;
429 case B_F5_KEY:
430 aChar = GLUT_KEY_F5;
431 goto specialLabel;
432 case B_F6_KEY:
433 aChar = GLUT_KEY_F6;
434 goto specialLabel;
435 case B_F7_KEY:
436 aChar = GLUT_KEY_F7;
437 goto specialLabel;
438 case B_F8_KEY:
439 aChar = GLUT_KEY_F8;
440 goto specialLabel;
441 case B_F9_KEY:
442 aChar = GLUT_KEY_F9;
443 goto specialLabel;
444 case B_F10_KEY:
445 aChar = GLUT_KEY_F10;
446 goto specialLabel;
447 case B_F11_KEY:
448 aChar = GLUT_KEY_F11;
449 goto specialLabel;
450 case B_F12_KEY:
451 aChar = GLUT_KEY_F12;
452 goto specialLabel;
453 default:
454 return;
455 }
456 case B_LEFT_ARROW:
457 aChar = GLUT_KEY_LEFT;
458 goto specialLabel;
459 case B_UP_ARROW:
460 aChar = GLUT_KEY_UP;
461 goto specialLabel;
462 case B_RIGHT_ARROW:
463 aChar = GLUT_KEY_RIGHT;
464 goto specialLabel;
465 case B_DOWN_ARROW:
466 aChar = GLUT_KEY_DOWN;
467 goto specialLabel;
468 case B_PAGE_UP:
469 aChar = GLUT_KEY_PAGE_UP;
470 goto specialLabel;
471 case B_PAGE_DOWN:
472 aChar = GLUT_KEY_PAGE_DOWN;
473 goto specialLabel;
474 case B_HOME:
475 aChar = GLUT_KEY_HOME;
476 goto specialLabel;
477 case B_END:
478 aChar = GLUT_KEY_END;
479 goto specialLabel;
480 case B_INSERT:
481 aChar = GLUT_KEY_INSERT;
482 specialLabel:
483 if (special) {
484 anyevents = specialEvent = true;
485 GetMouse(&p,&m_buttons);
486 specialKey = aChar;
487 specialX = (int)p.x;
488 specialY = (int)p.y;
489 goto setModifiers; // set the modifier variable
490 }
491 return;
492
493 default:
494 break;
495 }
496
497 if (keyboard) {
498 anyevents = keybEvent = true;
499 GetMouse(&p,&m_buttons);
500 key = aChar;
501 keyX = (int)p.x;
502 keyY = (int)p.y;
503 setModifiers:
504 modifierKeys = 0;
505 uint32 beMod = Window()->CurrentMessage()->FindInt32("modifiers");
506 if(beMod & B_SHIFT_KEY)
507 modifierKeys |= GLUT_ACTIVE_SHIFT;
508 if(beMod & B_CONTROL_KEY)
509 modifierKeys |= GLUT_ACTIVE_CTRL;
510 if(beMod & B_OPTION_KEY) {
511 // since the window traps B_COMMAND_KEY, we'll have to settle
512 // for the option key.. but we need to get the raw character,
513 // not the Unicode-enhanced version
514 key = Window()->CurrentMessage()->FindInt32("raw_char");
515 modifierKeys |= GLUT_ACTIVE_ALT;
516 }
517 gBlock.NewEvent();
518 }
519 }
520
521 /***********************************************************
522 * CLASS: GlutWindow
523 *
524 * FUNCTION: KeyUp
525 *
526 * DESCRIPTION: handles keyboard and special events
527 ***********************************************************/
KeyUp(const char * s,int32 slen)528 void GlutWindow::KeyUp(const char *s, int32 slen)
529 {
530 ulong aChar = s[0];
531 BGLView::KeyUp(s,slen);
532
533 BPoint p;
534
535 switch (aChar) {
536 case B_FUNCTION_KEY:
537 switch(Window()->CurrentMessage()->FindInt32("key")) {
538 case B_F1_KEY:
539 aChar = GLUT_KEY_F1;
540 goto specialLabel;
541 case B_F2_KEY:
542 aChar = GLUT_KEY_F2;
543 goto specialLabel;
544 case B_F3_KEY:
545 aChar = GLUT_KEY_F3;
546 goto specialLabel;
547 case B_F4_KEY:
548 aChar = GLUT_KEY_F4;
549 goto specialLabel;
550 case B_F5_KEY:
551 aChar = GLUT_KEY_F5;
552 goto specialLabel;
553 case B_F6_KEY:
554 aChar = GLUT_KEY_F6;
555 goto specialLabel;
556 case B_F7_KEY:
557 aChar = GLUT_KEY_F7;
558 goto specialLabel;
559 case B_F8_KEY:
560 aChar = GLUT_KEY_F8;
561 goto specialLabel;
562 case B_F9_KEY:
563 aChar = GLUT_KEY_F9;
564 goto specialLabel;
565 case B_F10_KEY:
566 aChar = GLUT_KEY_F10;
567 goto specialLabel;
568 case B_F11_KEY:
569 aChar = GLUT_KEY_F11;
570 goto specialLabel;
571 case B_F12_KEY:
572 aChar = GLUT_KEY_F12;
573 goto specialLabel;
574 default:
575 return;
576 }
577 case B_LEFT_ARROW:
578 aChar = GLUT_KEY_LEFT;
579 goto specialLabel;
580 case B_UP_ARROW:
581 aChar = GLUT_KEY_UP;
582 goto specialLabel;
583 case B_RIGHT_ARROW:
584 aChar = GLUT_KEY_RIGHT;
585 goto specialLabel;
586 case B_DOWN_ARROW:
587 aChar = GLUT_KEY_DOWN;
588 goto specialLabel;
589 case B_PAGE_UP:
590 aChar = GLUT_KEY_PAGE_UP;
591 goto specialLabel;
592 case B_PAGE_DOWN:
593 aChar = GLUT_KEY_PAGE_DOWN;
594 goto specialLabel;
595 case B_HOME:
596 aChar = GLUT_KEY_HOME;
597 goto specialLabel;
598 case B_END:
599 aChar = GLUT_KEY_END;
600 goto specialLabel;
601 case B_INSERT:
602 aChar = GLUT_KEY_INSERT;
603 specialLabel:
604 if (specialUp!=0) {
605 anyevents = specialUpEvent = true;
606 GetMouse(&p,&m_buttons);
607 specialKey = aChar;
608 specialX = (int)p.x;
609 specialY = (int)p.y;
610 goto setModifiers; // set the modifier variable
611 }
612 return;
613
614 default:
615 break;
616 }
617
618 if (keyboardUp!=0) {
619 anyevents = keybUpEvent = true;
620 GetMouse(&p,&m_buttons);
621 key = aChar;
622 keyX = (int)p.x;
623 keyY = (int)p.y;
624 setModifiers:
625 modifierKeys = 0;
626 uint32 beMod = Window()->CurrentMessage()->FindInt32("modifiers");
627 if(beMod & B_SHIFT_KEY)
628 modifierKeys |= GLUT_ACTIVE_SHIFT;
629 if(beMod & B_CONTROL_KEY)
630 modifierKeys |= GLUT_ACTIVE_CTRL;
631 if(beMod & B_OPTION_KEY) {
632 // since the window traps B_COMMAND_KEY, we'll have to settle
633 // for the option key.. but we need to get the raw character,
634 // not the Unicode-enhanced version
635 key = Window()->CurrentMessage()->FindInt32("raw_char");
636 modifierKeys |= GLUT_ACTIVE_ALT;
637 }
638 gBlock.NewEvent();
639 }
640 }
641
642 /***********************************************************
643 * CLASS: GlutWindow
644 *
645 * FUNCTION: MouseDown
646 *
647 * DESCRIPTION: handles mouse and menustatus events
648 ***********************************************************/
MouseDown(BPoint point)649 void GlutWindow::MouseDown(BPoint point)
650 {
651 BGLView::MouseDown(point);
652 MouseCheck();
653 }
654
655 /***********************************************************
656 * CLASS: GlutWindow
657 *
658 * FUNCTION: MouseCheck
659 *
660 * DESCRIPTION: checks for button state changes
661 ***********************************************************/
MouseCheck()662 void GlutWindow::MouseCheck()
663 {
664 if (mouseEvent)
665 return; // we already have an outstanding mouse event
666
667 BPoint point;
668 uint32 newButtons;
669 GetMouse(&point, &newButtons);
670 if (m_buttons != newButtons) {
671 if (newButtons&B_PRIMARY_MOUSE_BUTTON && !(m_buttons&B_PRIMARY_MOUSE_BUTTON)) {
672 button = GLUT_LEFT_BUTTON;
673 mouseState = GLUT_DOWN;
674 } else if (m_buttons&B_PRIMARY_MOUSE_BUTTON && !(newButtons&B_PRIMARY_MOUSE_BUTTON)) {
675 button = GLUT_LEFT_BUTTON;
676 mouseState = GLUT_UP;
677 } else if (newButtons&B_SECONDARY_MOUSE_BUTTON && !(m_buttons&B_SECONDARY_MOUSE_BUTTON)) {
678 button = GLUT_RIGHT_BUTTON;
679 mouseState = GLUT_DOWN;
680 } else if (m_buttons&B_SECONDARY_MOUSE_BUTTON && !(newButtons&B_SECONDARY_MOUSE_BUTTON)) {
681 button = GLUT_RIGHT_BUTTON;
682 mouseState = GLUT_UP;
683 } else if (newButtons&B_TERTIARY_MOUSE_BUTTON && !(m_buttons&B_TERTIARY_MOUSE_BUTTON)) {
684 button = GLUT_MIDDLE_BUTTON;
685 mouseState = GLUT_DOWN;
686 } else if (m_buttons&B_TERTIARY_MOUSE_BUTTON && !(newButtons&B_TERTIARY_MOUSE_BUTTON)) {
687 button = GLUT_MIDDLE_BUTTON;
688 mouseState = GLUT_UP;
689 }
690 } else {
691 return; // no change, return
692 }
693 m_buttons = newButtons;
694
695 if (mouseState == GLUT_DOWN) {
696 BWindow *w = Window();
697 GlutMenu *m = __glutGetMenuByNum(menu[button]);
698 if (m) {
699 if (gState.menuStatus) {
700 anyevents = statusEvent = true;
701 menuNumber = menu[button];
702 menuStatus = GLUT_MENU_IN_USE;
703 statusX = (int)point.x;
704 statusY = (int)point.y;
705 gBlock.NewEvent();
706 }
707 BRect bounds = w->Frame();
708 point.x += bounds.left;
709 point.y += bounds.top;
710 GlutPopUp *bmenu = static_cast<GlutPopUp*>(m->CreateBMenu()); // start menu
711 bmenu->point = point;
712 bmenu->win = this;
713 thread_id menu_thread = spawn_thread(MenuThread, "menu thread", B_NORMAL_PRIORITY, bmenu);
714 resume_thread(menu_thread);
715 return;
716 }
717 }
718
719 if (mouse) {
720 anyevents = mouseEvent = true;
721 mouseX = (int)point.x;
722 mouseY = (int)point.y;
723 modifierKeys = 0;
724 uint32 beMod = modifiers();
725 if(beMod & B_SHIFT_KEY)
726 modifierKeys |= GLUT_ACTIVE_SHIFT;
727 if(beMod & B_CONTROL_KEY)
728 modifierKeys |= GLUT_ACTIVE_CTRL;
729 if(beMod & B_OPTION_KEY) {
730 modifierKeys |= GLUT_ACTIVE_ALT;
731 }
732 gBlock.NewEvent();
733 }
734 }
735
736 /***********************************************************
737 * CLASS: GlutWindow
738 *
739 * FUNCTION: MouseMoved
740 *
741 * DESCRIPTION: handles entry, motion, and passive events
742 ***********************************************************/
MouseMoved(BPoint point,uint32 transit,const BMessage * msg)743 void GlutWindow::MouseMoved(BPoint point,
744 uint32 transit, const BMessage *msg)
745 {
746 BGLView::MouseMoved(point,transit,msg);
747
748 if(transit != B_INSIDE_VIEW) {
749 if (entry) {
750 anyevents = entryEvent = true;
751 gBlock.NewEvent();
752 }
753 if (transit == B_ENTERED_VIEW) {
754 entryState = GLUT_ENTERED;
755 MakeFocus(); // make me the current focus
756 __glutSetCursor(cursor);
757 } else
758 entryState = GLUT_LEFT;
759 }
760
761 MouseCheck();
762 if(m_buttons) {
763 if(motion) {
764 anyevents = motionEvent = true;
765 motionX = (int)point.x;
766 motionY = (int)point.y;
767 gBlock.NewEvent();
768 }
769 } else {
770 if(passive) {
771 anyevents = passiveEvent = true;
772 passiveX = (int)point.x;
773 passiveY = (int)point.y;
774 gBlock.NewEvent();
775 }
776 }
777 }
778
779 /***********************************************************
780 * CLASS: GlutWindow
781 *
782 * FUNCTION: MessageReceived
783 *
784 * DESCRIPTION: handles mouse wheel events
785 ***********************************************************/
786
MessageReceived(BMessage * message)787 void GlutWindow::MessageReceived(BMessage *message)
788 {
789 switch(message->what){
790 case B_MOUSE_WHEEL_CHANGED:
791 {
792 float shift=0;
793 if(message->FindFloat("be:wheel_delta_y",&shift)==B_OK) {
794 if(shift>0)button = MOUSE_WHEEL_UP;
795 if(shift<0)button = MOUSE_WHEEL_DOWN;
796 if(shift!=0) {
797 anyevents = mouseEvent = true;
798 gBlock.NewEvent();
799 }
800 }
801 break;
802 }
803 default:
804 BGLView::MessageReceived(message);
805 break;
806 }
807 }
808
809 /***********************************************************
810 * CLASS: GlutWindow
811 *
812 * FUNCTION: FrameResized
813 *
814 * DESCRIPTION: handles reshape event
815 ***********************************************************/
FrameResized(float width,float height)816 void GlutWindow::FrameResized(float width, float height)
817 {
818 BGLView::FrameResized(width, height);
819 if (visible) {
820 anyevents = reshapeEvent = true;
821 m_width = (int)(width)+1;
822 m_height = (int)(height)+1;
823 gBlock.NewEvent();
824 }
825 }
826
827 /***********************************************************
828 * CLASS: GlutWindow
829 *
830 * FUNCTION: Draw
831 *
832 * DESCRIPTION: handles reshape and display events
833 ***********************************************************/
Draw(BRect updateRect)834 void GlutWindow::Draw(BRect updateRect)
835 {
836 BGLView::Draw(updateRect);
837 BRect frame = Frame();
838 if (m_width != (frame.Width()+1) || m_height != (frame.Height()+1)) {
839 FrameResized(frame.Width(), frame.Height());
840 }
841 Window()->Lock();
842 if (visible) {
843 anyevents = displayEvent = true;
844 gBlock.NewEvent();
845 }
846 Window()->Unlock();
847 }
848
849 /***********************************************************
850 * CLASS: GlutWindow
851 *
852 * FUNCTION: Pulse
853 *
854 * DESCRIPTION: handles mouse up event (MouseUp is broken)
855 ***********************************************************/
Pulse()856 void GlutWindow::Pulse()
857 {
858 BGLView::Pulse();
859 if (m_buttons) { // if there are buttons pressed
860 MouseCheck();
861 }
862 }
863
864 /***********************************************************
865 * CLASS: GlutWindow
866 *
867 * FUNCTION: ErrorCallback
868 *
869 * DESCRIPTION: handles GL error messages
870 ***********************************************************/
ErrorCallback(unsigned long errorCode)871 void GlutWindow::ErrorCallback(unsigned long errorCode) {
872 __glutWarning("GL error: %s", gluErrorString(errorCode));
873 }
874
875 /***********************************************************
876 * CLASS: GlutWindow
877 *
878 * FUNCTION: MenuThread
879 *
880 * DESCRIPTION: a new thread to launch popup menu, wait
881 * wait for response, then clean up afterwards and
882 * send appropriate messages
883 ***********************************************************/
MenuThread(void * m)884 status_t GlutWindow::MenuThread(void *m) {
885 GlutPopUp *bmenu = static_cast<GlutPopUp*>(m);
886 GlutWindow *win = bmenu->win; // my window
887 GlutBMenuItem *result = (GlutBMenuItem*)bmenu->Go(bmenu->point);
888 win->Window()->Lock();
889 win->anyevents = win->statusEvent = true;
890 win->menuStatus = GLUT_MENU_NOT_IN_USE;
891 win->menuNumber = bmenu->menu;
892 BPoint cursor;
893 uint32 buttons;
894 win->GetMouse(&cursor, &buttons);
895 win->statusX = (int)cursor.x;
896 win->statusY = (int)cursor.y;
897 if(result && result->menu) {
898 win->menuEvent = true;
899 win->menuNumber = result->menu; // in case it was a submenu
900 win->menuValue = result->value;
901 }
902 win->Window()->Unlock();
903 gBlock.NewEvent();
904 delete bmenu;
905 return B_OK;
906 }
907