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