summaryrefslogtreecommitdiff
path: root/src/glut/beos/glutEvent.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/glut/beos/glutEvent.cpp')
-rw-r--r--src/glut/beos/glutEvent.cpp721
1 files changed, 721 insertions, 0 deletions
diff --git a/src/glut/beos/glutEvent.cpp b/src/glut/beos/glutEvent.cpp
new file mode 100644
index 00000000000..20b1cad23f4
--- /dev/null
+++ b/src/glut/beos/glutEvent.cpp
@@ -0,0 +1,721 @@
+/***********************************************************
+ * Copyright (C) 1997, Be Inc. All rights reserved.
+ *
+ * FILE: glutEvent.cpp
+ *
+ * DESCRIPTION: here it is, the BeOS GLUT event loop
+ ***********************************************************/
+
+/***********************************************************
+ * Headers
+ ***********************************************************/
+#include <GL/glut.h>
+#include "glutint.h"
+#include "glutState.h"
+#include "glutBlocker.h"
+
+/***********************************************************
+ * CLASS: GLUTtimer
+ *
+ * DESCRIPTION: list of timer callbacks
+ ***********************************************************/
+struct GLUTtimer {
+ GLUTtimer *next; // list of timers
+ bigtime_t timeout; // time to be called
+ GLUTtimerCB func; // function to call
+ int value; // value
+};
+
+/***********************************************************
+ * Private variables
+ ***********************************************************/
+static GLUTtimer *__glutTimerList = 0; // list of timer callbacks
+static GLUTtimer *freeTimerList = 0;
+
+/***********************************************************
+ * FUNCTION: glutTimerFunc (7.19)
+ *
+ * DESCRIPTION: register a new timer callback
+ ***********************************************************/
+void APIENTRY
+glutTimerFunc(unsigned int interval, GLUTtimerCB timerFunc, int value)
+{
+ GLUTtimer *timer, *other;
+ GLUTtimer **prevptr;
+
+ if (!timerFunc)
+ return;
+
+ if (freeTimerList) {
+ timer = freeTimerList;
+ freeTimerList = timer->next;
+ } else {
+ timer = new GLUTtimer();
+ if (!timer)
+ __glutFatalError("out of memory.");
+ }
+
+ timer->func = timerFunc;
+ timer->value = value;
+ timer->next = NULL;
+ timer->timeout = system_time() + (interval*1000); // 1000 ticks in a millisecond
+ prevptr = &__glutTimerList;
+ other = *prevptr;
+ while (other && (other->timeout < timer->timeout)) {
+ prevptr = &other->next;
+ other = *prevptr;
+ }
+ timer->next = other;
+ *prevptr = timer;
+}
+
+/***********************************************************
+ * FUNCTION: handleTimeouts
+ *
+ * DESCRIPTION: private function to handle outstanding timeouts
+ ***********************************************************/
+static void
+handleTimeouts(void)
+{
+ bigtime_t now;
+ GLUTtimer *timer;
+
+ /* Assumption is that __glutTimerList is already determined
+ to be non-NULL. */
+ now = system_time();
+ while (__glutTimerList->timeout <= now) {
+ timer = __glutTimerList;
+ if(gState.currentWindow)
+ gState.currentWindow->LockGL();
+ timer->func(timer->value);
+ if(gState.currentWindow)
+ gState.currentWindow->UnlockGL();
+ __glutTimerList = timer->next;
+ timer->next = freeTimerList;
+ freeTimerList = timer;
+ if (!__glutTimerList)
+ break;
+ }
+}
+
+
+/***********************************************************
+ * FUNCTION: processEventsAndTimeouts
+ *
+ * DESCRIPTION: clear gBlock, then check all windows for events
+ ***********************************************************/
+static void
+processEventsAndTimeouts(void)
+{
+ gBlock.WaitEvent(); // if there is already an event, returns
+ // immediately, otherwise wait forever
+ gBlock.ClearEvents();
+
+ if (gState.currentWindow)
+ gState.currentWindow->LockGL();
+ for(int i=0; i<gState.windowListSize; i++) {
+ if (gState.windowList[i]) {
+ GlutWindow *win = gState.windowList[i];
+ win->Window()->Lock();
+ // NOTE: we can use win as a shortcut for gState.windowList[i]
+ // in callbacks, EXCEPT we need to check the original variable
+ // after each callback to make sure the window hasn't been destroyed
+ if (win->anyevents) {
+ win->anyevents = false;
+ if (win->reshapeEvent) {
+ win->reshapeEvent = false;
+ __glutSetWindow(win);
+ win->reshape(win->m_width, win->m_height);
+ }
+ if (!gState.windowList[i])
+ continue; // window was destroyed by callback!
+
+ if (win->displayEvent) {
+ win->displayEvent = false;
+ __glutSetWindow(win);
+ win->display();
+ if (gState.windowList[i] && win->swapHack) {
+ // fake single buffering by swapping buffers
+ __glutSetWindow(win);
+ win->SwapBuffers();
+ }
+ }
+ if (!gState.windowList[i])
+ continue; // window was destroyed by callback!
+
+ if (win->mouseEvent) {
+ win->mouseEvent = false;
+ __glutSetWindow(win);
+ if (win->mouse) {
+ gState.modifierKeys = win->modifierKeys;
+ win->mouse(win->button, win->mouseState, win->mouseX, win->mouseY);
+ gState.modifierKeys = ~0;
+ }
+ }
+ if (!gState.windowList[i])
+ continue; // window was destroyed by callback!
+
+ if (win->menuEvent) {
+ win->menuEvent = false;
+ __glutSetWindow(win);
+ GlutMenu *menu = __glutGetMenuByNum(win->menuNumber);
+ if (menu) {
+ gState.currentMenu = menu;
+ menu->select(win->menuValue);
+ }
+ }
+ if (!gState.windowList[i])
+ continue; // window was destroyed by callback!
+
+ if (win->statusEvent) {
+ win->statusEvent = false;
+ __glutSetWindow(win);
+ if (gState.menuStatus) {
+ gState.currentMenu = __glutGetMenuByNum(win->menuNumber);
+ gState.menuStatus(win->menuStatus, win->statusX, win->statusY);
+ }
+ }
+ if (!gState.windowList[i])
+ continue; // window was destroyed by callback!
+
+ if (win->motionEvent) {
+ win->motionEvent = false;
+ __glutSetWindow(win);
+ if (win->motion)
+ win->motion(win->motionX, win->motionY);
+ }
+ if (!gState.windowList[i])
+ continue; // window was destroyed by callback!
+
+ if (win->passiveEvent) {
+ win->passiveEvent = false;
+ __glutSetWindow(win);
+ if (win->passive)
+ win->passive(win->passiveX, win->passiveY);
+ }
+ if (!gState.windowList[i])
+ continue; // window was destroyed by callback!
+
+ if (win->keybEvent) {
+ win->keybEvent = false;
+ __glutSetWindow(win);
+ if (win->keyboard) {
+ gState.modifierKeys = win->modifierKeys;
+ win->keyboard(win->key, win->keyX, win->keyY);
+ gState.modifierKeys = ~0;
+ }
+ }
+ if (!gState.windowList[i])
+ continue; // window was destroyed by callback!
+
+ if (win->specialEvent) {
+ win->specialEvent = false;
+ __glutSetWindow(win);
+ if (win->special) {
+ gState.modifierKeys = win->modifierKeys;
+ win->special(win->specialKey, win->specialX, win->specialY);
+ gState.modifierKeys = ~0;
+ }
+ }
+ if (!gState.windowList[i])
+ continue; // window was destroyed by callback!
+
+ if (win->entryEvent) {
+ win->entryEvent = false;
+ __glutSetWindow(win);
+ if (win->entry)
+ win->entry(win->entryState);
+ }
+ if (!gState.windowList[i])
+ continue; // window was destroyed by callback!
+
+ if (win->visEvent) {
+ win->visEvent = false;
+ __glutSetWindow(win);
+ if (win->visibility)
+ win->visibility(win->visState);
+ }
+ if (!gState.windowList[i])
+ continue; // window was destroyed by callback!
+ }
+ if(gState.windowList[i]) // window hasn't been destroyed
+ win->Window()->Unlock();
+ }
+ }
+ if (gState.currentWindow)
+ gState.currentWindow->UnlockGL();
+
+ // This code isn't necessary since BGLView automatically traps errors
+#if 0
+ if(gState.debug) {
+ for(int i=0; i<gState.windowListSize; i++) {
+ if (gState.windowList[i]) {
+ gState.windowList[i]->LockGL();
+ glutReportErrors();
+ gState.windowList[i]->UnlockGL();
+ }
+ }
+ }
+#endif
+ if (__glutTimerList) {
+ handleTimeouts();
+ }
+}
+
+/***********************************************************
+ * FUNCTION: waitForSomething
+ *
+ * DESCRIPTION: use gBlock to wait for a new event or timeout
+ ***********************************************************/
+static void
+waitForSomething(void)
+{
+ bigtime_t timeout = __glutTimerList->timeout;
+ bigtime_t now = system_time();
+
+ if (gBlock.PendingEvent())
+ goto immediatelyHandleEvent;
+
+ if(timeout>now)
+ gBlock.WaitEvent(timeout-now);
+ if (gBlock.PendingEvent()) {
+ immediatelyHandleEvent:
+ processEventsAndTimeouts();
+ } else {
+ if (__glutTimerList)
+ handleTimeouts();
+ }
+}
+
+/***********************************************************
+ * FUNCTION: idleWait
+ *
+ * DESCRIPTION: check for events, then call idle function
+ ***********************************************************/
+static void
+idleWait(void)
+{
+ if (gBlock.PendingEvent()) {
+ processEventsAndTimeouts();
+ } else {
+ if (__glutTimerList)
+ handleTimeouts();
+ }
+ /* Make sure idle func still exists! */
+ if(gState.currentWindow)
+ gState.currentWindow->LockGL();
+ if (gState.idle)
+ gState.idle();
+ if(gState.currentWindow)
+ gState.currentWindow->UnlockGL();
+}
+
+/***********************************************************
+ * FUNCTION: glutMainLoop (3.1)
+ *
+ * DESCRIPTION: enter the event processing loop
+ ***********************************************************/
+void glutMainLoop()
+{
+ if (!gState.windowListSize)
+ __glutFatalUsage("main loop entered with no windows created.");
+
+ if(gState.currentWindow)
+ gState.currentWindow->UnlockGL();
+
+ for (;;) {
+ if (gState.idle) {
+ idleWait();
+ } else {
+ if (__glutTimerList) {
+ waitForSomething();
+ } else {
+ processEventsAndTimeouts();
+ }
+ }
+ }
+}
+
+/***********************************************************
+ * CLASS: GlutWindow
+ *
+ * FUNCTION: KeyDown
+ *
+ * DESCRIPTION: handles keyboard and special events
+ ***********************************************************/
+void GlutWindow::KeyDown(const char *s, int32 slen)
+{
+ ulong aChar = s[0];
+ BGLView::KeyDown(s,slen);
+
+ BPoint p;
+
+ switch (aChar) {
+ case B_FUNCTION_KEY:
+ switch(Window()->CurrentMessage()->FindInt32("key")) {
+ case B_F1_KEY:
+ aChar = GLUT_KEY_F1;
+ goto specialLabel;
+ case B_F2_KEY:
+ aChar = GLUT_KEY_F2;
+ goto specialLabel;
+ case B_F3_KEY:
+ aChar = GLUT_KEY_F3;
+ goto specialLabel;
+ case B_F4_KEY:
+ aChar = GLUT_KEY_F4;
+ goto specialLabel;
+ case B_F5_KEY:
+ aChar = GLUT_KEY_F5;
+ goto specialLabel;
+ case B_F6_KEY:
+ aChar = GLUT_KEY_F6;
+ goto specialLabel;
+ case B_F7_KEY:
+ aChar = GLUT_KEY_F7;
+ goto specialLabel;
+ case B_F8_KEY:
+ aChar = GLUT_KEY_F8;
+ goto specialLabel;
+ case B_F9_KEY:
+ aChar = GLUT_KEY_F9;
+ goto specialLabel;
+ case B_F10_KEY:
+ aChar = GLUT_KEY_F10;
+ goto specialLabel;
+ case B_F11_KEY:
+ aChar = GLUT_KEY_F11;
+ goto specialLabel;
+ case B_F12_KEY:
+ aChar = GLUT_KEY_F12;
+ goto specialLabel;
+ default:
+ return;
+ }
+ case B_LEFT_ARROW:
+ aChar = GLUT_KEY_LEFT;
+ goto specialLabel;
+ case B_UP_ARROW:
+ aChar = GLUT_KEY_UP;
+ goto specialLabel;
+ case B_RIGHT_ARROW:
+ aChar = GLUT_KEY_RIGHT;
+ goto specialLabel;
+ case B_DOWN_ARROW:
+ aChar = GLUT_KEY_DOWN;
+ goto specialLabel;
+ case B_PAGE_UP:
+ aChar = GLUT_KEY_PAGE_UP;
+ goto specialLabel;
+ case B_PAGE_DOWN:
+ aChar = GLUT_KEY_PAGE_DOWN;
+ goto specialLabel;
+ case B_HOME:
+ aChar = GLUT_KEY_HOME;
+ goto specialLabel;
+ case B_END:
+ aChar = GLUT_KEY_END;
+ goto specialLabel;
+ case B_INSERT:
+ aChar = GLUT_KEY_INSERT;
+specialLabel:
+ if (special) {
+ anyevents = specialEvent = true;
+ GetMouse(&p,&m_buttons);
+ specialKey = aChar;
+ specialX = (int)p.x;
+ specialY = (int)p.y;
+ goto setModifiers; // set the modifier variable
+ }
+ return;
+
+ default:
+ break;
+ }
+
+ if (keyboard) {
+ anyevents = keybEvent = true;
+ GetMouse(&p,&m_buttons);
+ key = aChar;
+ keyX = (int)p.x;
+ keyY = (int)p.y;
+setModifiers:
+ modifierKeys = 0;
+ uint32 beMod = Window()->CurrentMessage()->FindInt32("modifiers");
+ if(beMod & B_SHIFT_KEY)
+ modifierKeys |= GLUT_ACTIVE_SHIFT;
+ if(beMod & B_CONTROL_KEY)
+ modifierKeys |= GLUT_ACTIVE_CTRL;
+ if(beMod & B_OPTION_KEY) {
+ // since the window traps B_COMMAND_KEY, we'll have to settle
+ // for the option key.. but we need to get the raw character,
+ // not the Unicode-enhanced version
+ key = Window()->CurrentMessage()->FindInt32("raw_char");
+ modifierKeys |= GLUT_ACTIVE_ALT;
+ }
+ gBlock.NewEvent();
+ }
+}
+
+/***********************************************************
+ * CLASS: GlutWindow
+ *
+ * FUNCTION: MouseDown
+ *
+ * DESCRIPTION: handles mouse and menustatus events
+ ***********************************************************/
+void GlutWindow::MouseDown(BPoint point)
+{
+ BGLView::MouseDown(point);
+ MouseCheck();
+}
+
+/***********************************************************
+ * CLASS: GlutWindow
+ *
+ * FUNCTION: MouseCheck
+ *
+ * DESCRIPTION: checks for button state changes
+ ***********************************************************/
+void GlutWindow::MouseCheck()
+{
+ if (mouseEvent)
+ return; // we already have an outstanding mouse event
+
+ BPoint point;
+ uint32 newButtons;
+ GetMouse(&point, &newButtons);
+ if (m_buttons != newButtons) {
+ if (newButtons&B_PRIMARY_MOUSE_BUTTON && !(m_buttons&B_PRIMARY_MOUSE_BUTTON)) {
+ button = GLUT_LEFT_BUTTON;
+ mouseState = GLUT_DOWN;
+ } else if (m_buttons&B_PRIMARY_MOUSE_BUTTON && !(newButtons&B_PRIMARY_MOUSE_BUTTON)) {
+ button = GLUT_LEFT_BUTTON;
+ mouseState = GLUT_UP;
+ } else if (newButtons&B_SECONDARY_MOUSE_BUTTON && !(m_buttons&B_SECONDARY_MOUSE_BUTTON)) {
+ button = GLUT_RIGHT_BUTTON;
+ mouseState = GLUT_DOWN;
+ } else if (m_buttons&B_SECONDARY_MOUSE_BUTTON && !(newButtons&B_SECONDARY_MOUSE_BUTTON)) {
+ button = GLUT_RIGHT_BUTTON;
+ mouseState = GLUT_UP;
+ } else if (newButtons&B_TERTIARY_MOUSE_BUTTON && !(m_buttons&B_TERTIARY_MOUSE_BUTTON)) {
+ button = GLUT_MIDDLE_BUTTON;
+ mouseState = GLUT_DOWN;
+ } else if (m_buttons&B_TERTIARY_MOUSE_BUTTON && !(newButtons&B_TERTIARY_MOUSE_BUTTON)) {
+ button = GLUT_MIDDLE_BUTTON;
+ mouseState = GLUT_UP;
+ }
+ } else {
+ return; // no change, return
+ }
+ m_buttons = newButtons;
+
+ if (mouseState == GLUT_DOWN) {
+ BWindow *w = Window();
+ GlutMenu *m = __glutGetMenuByNum(menu[button]);
+ if (m) {
+ if (gState.menuStatus) {
+ anyevents = statusEvent = true;
+ menuNumber = menu[button];
+ menuStatus = GLUT_MENU_IN_USE;
+ statusX = (int)point.x;
+ statusY = (int)point.y;
+ gBlock.NewEvent();
+ }
+ BRect bounds = w->Frame();
+ point.x += bounds.left;
+ point.y += bounds.top;
+ GlutPopUp *bmenu = static_cast<GlutPopUp*>(m->CreateBMenu()); // start menu
+ bmenu->point = point;
+ bmenu->win = this;
+ thread_id menu_thread = spawn_thread(MenuThread, "menu thread", B_NORMAL_PRIORITY, bmenu);
+ resume_thread(menu_thread);
+ return;
+ }
+ }
+
+ if (mouse) {
+ anyevents = mouseEvent = true;
+ mouseX = (int)point.x;
+ mouseY = (int)point.y;
+ modifierKeys = 0;
+ uint32 beMod = modifiers();
+ if(beMod & B_SHIFT_KEY)
+ modifierKeys |= GLUT_ACTIVE_SHIFT;
+ if(beMod & B_CONTROL_KEY)
+ modifierKeys |= GLUT_ACTIVE_CTRL;
+ if(beMod & B_OPTION_KEY) {
+ modifierKeys |= GLUT_ACTIVE_ALT;
+ }
+ gBlock.NewEvent();
+ }
+}
+
+/***********************************************************
+ * CLASS: GlutWindow
+ *
+ * FUNCTION: MouseMoved
+ *
+ * DESCRIPTION: handles entry, motion, and passive events
+ ***********************************************************/
+void GlutWindow::MouseMoved(BPoint point,
+ ulong transit, const BMessage *msg)
+{
+ BGLView::MouseMoved(point,transit,msg);
+
+ if(transit != B_INSIDE_VIEW) {
+ if (entry) {
+ anyevents = entryEvent = true;
+ gBlock.NewEvent();
+ }
+ if (transit == B_ENTERED_VIEW) {
+ entryState = GLUT_ENTERED;
+ MakeFocus(); // make me the current focus
+ __glutSetCursor(cursor);
+ } else
+ entryState = GLUT_LEFT;
+ }
+
+ MouseCheck();
+ if(m_buttons) {
+ if(motion) {
+ anyevents = motionEvent = true;
+ motionX = (int)point.x;
+ motionY = (int)point.y;
+ gBlock.NewEvent();
+ }
+ } else {
+ if(passive) {
+ anyevents = passiveEvent = true;
+ passiveX = (int)point.x;
+ passiveY = (int)point.y;
+ gBlock.NewEvent();
+ }
+ }
+}
+
+/***********************************************************
+ * CLASS: GlutWindow
+ *
+ * FUNCTION: FrameResized
+ *
+ * DESCRIPTION: handles reshape event
+ ***********************************************************/
+void GlutWindow::FrameResized(float width, float height)
+{
+ BGLView::FrameResized(width, height);
+ if (visState == GLUT_VISIBLE) {
+ anyevents = reshapeEvent = true;
+ m_width = (int)(width)+1;
+ m_height = (int)(height)+1;
+ gBlock.NewEvent();
+ }
+}
+
+/***********************************************************
+ * CLASS: GlutWindow
+ *
+ * FUNCTION: Draw
+ *
+ * DESCRIPTION: handles reshape and display events
+ ***********************************************************/
+void GlutWindow::Draw(BRect updateRect)
+{
+ BGLView::Draw(updateRect);
+ BRect frame = Frame();
+ if (m_width != (frame.Width()+1) || m_height != (frame.Height()+1)) {
+ FrameResized(frame.Width(), frame.Height());
+ }
+ if (visState == GLUT_VISIBLE) {
+ anyevents = displayEvent = true;
+ gBlock.NewEvent();
+ }
+}
+
+/***********************************************************
+ * CLASS: GlutWindow
+ *
+ * FUNCTION: Hide
+ * Show
+ *
+ * DESCRIPTION: handles visibility event
+ ***********************************************************/
+void GlutWindow::Hide()
+{
+ BGLView::Hide();
+ if (visibility) {
+ anyevents = visEvent = true;
+ visState = GLUT_NOT_VISIBLE;
+ displayEvent = false; // display callbacks not allowed when hidden
+ gBlock.NewEvent();
+ }
+}
+
+void GlutWindow::Show()
+{
+ BGLView::Show();
+ if (visibility) {
+ anyevents = visEvent = true;
+ visState = GLUT_VISIBLE;
+ gBlock.NewEvent();
+ }
+}
+
+/***********************************************************
+ * CLASS: GlutWindow
+ *
+ * FUNCTION: Pulse
+ *
+ * DESCRIPTION: handles mouse up event (MouseUp is broken)
+ ***********************************************************/
+void GlutWindow::Pulse()
+{
+ BGLView::Pulse();
+ if (m_buttons) { // if there are buttons pressed
+ MouseCheck();
+ }
+}
+
+/***********************************************************
+ * CLASS: GlutWindow
+ *
+ * FUNCTION: ErrorCallback
+ *
+ * DESCRIPTION: handles GL error messages
+ ***********************************************************/
+void GlutWindow::ErrorCallback(GLenum errorCode) {
+ __glutWarning("GL error: %s", gluErrorString(errorCode));
+}
+
+/***********************************************************
+ * CLASS: GlutWindow
+ *
+ * FUNCTION: MenuThread
+ *
+ * DESCRIPTION: a new thread to launch popup menu, wait
+ * wait for response, then clean up afterwards and
+ * send appropriate messages
+ ***********************************************************/
+long GlutWindow::MenuThread(void *m) {
+ GlutPopUp *bmenu = static_cast<GlutPopUp*>(m);
+ GlutWindow *win = bmenu->win; // my window
+ GlutBMenuItem *result = (GlutBMenuItem*)bmenu->Go(bmenu->point);
+ win->Window()->Lock();
+ win->anyevents = win->statusEvent = true;
+ win->menuStatus = GLUT_MENU_NOT_IN_USE;
+ win->menuNumber = bmenu->menu;
+ BPoint cursor;
+ uint32 buttons;
+ win->GetMouse(&cursor, &buttons);
+ win->statusX = (int)cursor.x;
+ win->statusY = (int)cursor.y;
+ if(result && result->menu) {
+ win->menuEvent = true;
+ win->menuNumber = result->menu; // in case it was a submenu
+ win->menuValue = result->value;
+ }
+ win->Window()->Unlock();
+ gBlock.NewEvent();
+ delete bmenu;
+ return 0;
+}