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 ***********************************************************/
32struct 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 ***********************************************************/
42static GLUTtimer *__glutTimerList = 0;			// list of timer callbacks
43static GLUTtimer *freeTimerList = 0;
44
45/***********************************************************
46 *	FUNCTION:	glutTimerFunc (7.19)
47 *
48 *	DESCRIPTION:  register a new timer callback
49 ***********************************************************/
50void APIENTRY
51glutTimerFunc(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 ***********************************************************/
87static void
88handleTimeouts(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 ***********************************************************/
117static void
118processEventsAndTimeouts(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 ***********************************************************/
300static void
301waitForSomething(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 ***********************************************************/
325static void
326idleWait(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 ***********************************************************/
349void 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
371void 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
389void 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 ***********************************************************/
403void 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;
482specialLabel:
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;
503setModifiers:
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 ***********************************************************/
528void 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;
603specialLabel:
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;
624setModifiers:
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 ***********************************************************/
649void 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 ***********************************************************/
662void 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 ***********************************************************/
743void 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
787void 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 ***********************************************************/
816void 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 ***********************************************************/
834void 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 ***********************************************************/
856void 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 ***********************************************************/
871void 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 ***********************************************************/
884status_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