diff options
Diffstat (limited to 'src/glut/beos/glutWindow.cpp')
-rw-r--r-- | src/glut/beos/glutWindow.cpp | 633 |
1 files changed, 633 insertions, 0 deletions
diff --git a/src/glut/beos/glutWindow.cpp b/src/glut/beos/glutWindow.cpp new file mode 100644 index 000000000..66ea2a00a --- /dev/null +++ b/src/glut/beos/glutWindow.cpp @@ -0,0 +1,633 @@ +/*********************************************************** + * Copyright (C) 1997, Be Inc. Copyright (C) 1999, Jake Hamby. + * + * This program is freely distributable without licensing fees + * and is provided without guarantee or warrantee expressed or + * implied. This program is -not- in the public domain. + * + * + * FILE: glutWindow.cpp + * + * DESCRIPTION: all the routines for dealing with GlutWindows + ***********************************************************/ + +/*********************************************************** + * Headers + ***********************************************************/ +#include <GL/glut.h> +#include <stdlib.h> +#include "glutint.h" +#include "glutState.h" +#include "glutBlocker.h" + +/*********************************************************** + * FUNCTION: getUnusedWindowSlot + * + * DESCRIPTION: helper function to get a new window slot + ***********************************************************/ +static int +getUnusedWindowSlot() +{ + int i; + + /* Look for allocated, unused slot. */ + for (i = 0; i < gState.windowListSize; i++) { + if (!gState.windowList[i]) { + return i; + } + } + /* Allocate a new slot. */ + gState.windowListSize++; + gState.windowList = (GlutWindow **) + realloc(gState.windowList, + gState.windowListSize * sizeof(GlutWindow *)); + + if (!gState.windowList) + __glutFatalError("out of memory."); + gState.windowList[gState.windowListSize - 1] = NULL; + return gState.windowListSize - 1; +} + +/*********************************************************** + * FUNCTION: __glutDefaultDisplay + * __glutDefaultReshape + * + * DESCRIPTION: default display and reshape functions + ***********************************************************/ +static void +__glutDefaultDisplay(void) +{ + /* XXX Remove the warning after GLUT 3.0. */ + __glutWarning("The following is a new check for GLUT 3.0; update your code."); + __glutFatalError( + "redisplay needed for window %d, but no display callback.", + gState.currentWindow->num + 1); +} + +void +__glutDefaultReshape(int width, int height) +{ + /* Adjust the viewport of the window */ + glViewport(0, 0, (GLsizei) width, (GLsizei) height); +} + +/*********************************************************** + * CLASS: GlutWindow + * + * FUNCTION: (constructor) + * + * DESCRIPTION: creates a new GLUT window + * note: subwindows don't resize, but top-level windows + * follow all sides + ***********************************************************/ +GlutWindow::GlutWindow(GlutWindow *nparent, char *name, + int x, int y, int width, int height, ulong options) : + BGLView( + (nparent ? BRect(x,y,x+width-1,y+height-1) : + BRect(0,0,width-1,height-1)), name, + (nparent ? B_FOLLOW_NONE : B_FOLLOW_ALL_SIDES), + B_WILL_DRAW|B_FRAME_EVENTS|B_FULL_UPDATE_ON_RESIZE|B_PULSE_NEEDED, + options) +{ + // add myself to window list + num = getUnusedWindowSlot(); + gState.windowList[num] = this; + + // set up parent/children relationships + parent = nparent; + if (parent) { + siblings = parent->children; + parent->children = this; + } else { + siblings = 0; + } + children = 0; + + // initialize variables + cursor = GLUT_CURSOR_INHERIT; // default cursor + for (int i = 0; i < GLUT_MAX_MENUS; i++) { + menu[i] = 0; + } + m_width = width; + m_height = height; + m_buttons = 0; + + // clear callbacks + display = __glutDefaultDisplay; + reshape = __glutDefaultReshape; + mouse = 0; + motion = 0; + passive = 0; + entry = 0; + keyboard = 0; + visibility = 0; + special = 0; + windowStatus = 0; + + // clear event counters + anyevents = 1; + displayEvent = 1; // get a reshape and a display event right away + reshapeEvent = 1; + mouseEvent = 0; + motionEvent = 0; + passiveEvent = 0; + entryEvent = 0; + keybEvent = 0; + windowStatusEvent = 0; // DirectConnected() will report change in + visState = -1; // visibility + specialEvent = 0; + statusEvent = 0; + menuEvent = 0; + visible = true; + gBlock.QuickNewEvent(); + + // if i'm a subwindow, add me to my parent view + if (parent) { + parent->Window()->Lock(); + parent->AddChild(this); + parent->Window()->Unlock(); + } else { + // if I'm a top-level window, create my BWindow + GlutBWindow *mybwindow = new GlutBWindow( + BRect(x,y,x+width-1,y+height-1), name); + mybwindow->AddChild(this); + mybwindow->bgl = this; + mybwindow->Show(); + } + + // give me the keyboard focus (focus follows mouse, X style, as + // implemented in GlutWindow::MouseMoved()) + Window()->Lock(); + MakeFocus(); + Window()->Unlock(); + + // make myself the default window + __glutSetWindow(this); +} + +/*********************************************************** + * FUNCTION: glutCreateWindow (4.1) + * + * DESCRIPTION: creates a new GLUT window + ***********************************************************/ +int glutCreateWindow(const char *name) { + if (!be_app) + __glutInit(); + + ulong options; + if (!__glutConvertDisplayMode(&options)) { + __glutWarning("visual with necessary capabilities not found."); + } + + // if X or Y is negative, then start at a reasonable position + bool defaultxy = (gState.initX < 0) || (gState.initY < 0); + + GlutWindow *window = new GlutWindow(0, const_cast<char*>(name), + (defaultxy ? 50 : gState.initX), (defaultxy ? 50 : gState.initY), + gState.initWidth, gState.initHeight, options); + + return window->num + 1; +} + +/*********************************************************** + * FUNCTION: glutCreateSubWindow (4.2) + * + * DESCRIPTION: creates a new GLUT subwindow + * Note: a subwindow is a GlutWindow (which is actually + * a BGLView) without its own BWindow + ***********************************************************/ +int glutCreateSubWindow(int win, int x, int y, int width, int height) { + ulong options; + if (!__glutConvertDisplayMode(&options)) { + __glutFatalError("visual with necessary capabilities not found."); + } + + GlutWindow *window = new GlutWindow(gState.windowList[win-1], "child", + x, y, width, height, options); + + return window->num + 1; +} + +/*********************************************************** + * FUNCTION: __glutSetWindow + * + * DESCRIPTION: set the current window (utility function) + ***********************************************************/ +void +__glutSetWindow(GlutWindow * window) +{ + if (gState.currentWindow) + gState.currentWindow->UnlockGL(); + gState.currentWindow = window; + gState.currentWindow->LockGL(); +} + +/*********************************************************** + * FUNCTION: glutSetWindow (4.3) + * glutGetWindow + * + * DESCRIPTION: set and get the current window + ***********************************************************/ +void glutSetWindow(int win) { + GlutWindow *window; + + if (win < 1 || win > gState.windowListSize) { + __glutWarning("glutSetWindow attempted on bogus window."); + return; + } + window = gState.windowList[win - 1]; + if (!window) { + __glutWarning("glutSetWindow attempted on bogus window."); + return; + } + __glutSetWindow(window); +} + +int glutGetWindow() { + if (gState.currentWindow) { + return gState.currentWindow->num + 1; + } else { + return 0; + } +} + +/*********************************************************** + * FUNCTION: __glutDestroyWindow + * + * DESCRIPTION: recursively set entries to 0 + ***********************************************************/ +static void +__glutDestroyWindow(GlutWindow *window, GlutWindow *initialWindow) { + // first, find all children recursively and set their entries to 0 + GlutWindow *cur = window->children; + while (cur) { + GlutWindow *siblings = cur->siblings; + __glutDestroyWindow(cur, initialWindow); + cur = siblings; + } + + /* Remove from parent's children list (only necessary for + non-initial windows and subwindows!). */ + GlutWindow *parent = window->parent; + if (parent && parent == initialWindow->parent) { + GlutWindow **prev = &parent->children; + cur = parent->children; + while (cur) { + if (cur == window) { + *prev = cur->siblings; + break; + } + prev = &(cur->siblings); + cur = cur->siblings; + } + } + + // finally, check if we are the current window, and set to 0 + if (gState.currentWindow == window) { + gState.currentWindow = 0; + } + gState.windowList[window->num] = 0; +} + +/*********************************************************** + * FUNCTION: glutDestroyWindow (4.4) + * + * DESCRIPTION: destroy window and all its children + ***********************************************************/ +void glutDestroyWindow(int win) { + // can't destroy a window if another window has the GL context + if (gState.currentWindow) + gState.currentWindow->UnlockGL(); + + // lock the window + GlutWindow *window = gState.windowList[win-1]; + BWindow *bwindow = window->Window(); + bwindow->Lock(); + + // if win is the current window, set current window to 0 + if (gState.currentWindow == window) { + gState.currentWindow = 0; + } + + // recursively set child entries to 0 + __glutDestroyWindow(window, window); + + // try flushing OpenGL + window->LockGL(); + glFlush(); + window->UnlockGL(); + + // now, if the window was top-level, delete its BWindow + if(!window->parent) { + bwindow->Quit(); + } else { + // else, detach it from the BWindow and delete it + window->RemoveSelf(); + delete window; + bwindow->Unlock(); + } + // relock GL if the current window is still valid + if(gState.currentWindow) + gState.currentWindow->LockGL(); +} + +/*********************************************************** + * FUNCTION: __glutDestroyAllWindows + * + * DESCRIPTION: destroy all windows when exit() is called + * this seems to be necessary to avoid delays + * and crashes when using BDirectWindow + ***********************************************************/ +void __glutDestroyAllWindows() { + for(int i=0; i<gState.windowListSize; i++) { + if (gState.windowList[i]) { + glutDestroyWindow(i + 1); + } + } + gState.display->Lock(); + gState.display->Quit(); + status_t ignored; + wait_for_thread(gState.appthread, &ignored); +} + +/*********************************************************** + * FUNCTION: glutPostRedisplay (4.5) + * + * DESCRIPTION: mark window as needing redisplay + ***********************************************************/ +void glutPostRedisplay() { + gState.currentWindow->Window()->Lock(); + gState.currentWindow->anyevents = true; + gState.currentWindow->displayEvent = true; + gState.currentWindow->Window()->Unlock(); + gBlock.QuickNewEvent(); +} + +/*********************************************************** + * FUNCTION: glutPostWindowRedisplay + * + * DESCRIPTION: mark window as needing redisplay + ***********************************************************/ +void glutPostWindowRedisplay(int win) { + GlutWindow *gwin = gState.windowList[win - 1]; + gwin->Window()->Lock(); + gwin->anyevents = true; + gwin->displayEvent = true; + gwin->Window()->Unlock(); + gBlock.QuickNewEvent(); +} + +/*********************************************************** + * FUNCTION: glutSwapBuffers (4.6) + * + * DESCRIPTION: swap buffers + ***********************************************************/ +void glutSwapBuffers() { + gState.currentWindow->SwapBuffers(); +} + +/*********************************************************** + * FUNCTION: glutPositionWindow (4.7) + * + * DESCRIPTION: move window + ***********************************************************/ +void glutPositionWindow(int x, int y) { + BDirectWindow *win = dynamic_cast<BDirectWindow*>(gState.currentWindow->Window()); + win->Lock(); + if (gState.currentWindow->parent) + gState.currentWindow->MoveTo(x, y); // move the child view + else { + if(win->IsFullScreen()) { + win->SetFullScreen(false); + } + win->MoveTo(x, y); // move the window + } + win->Unlock(); +} + +/*********************************************************** + * FUNCTION: glutReshapeWindow (4.8) + * + * DESCRIPTION: reshape window (we'll catch the callback + * when the view gets a Draw() message + ***********************************************************/ +void glutReshapeWindow(int width, int height) { + BDirectWindow *win = dynamic_cast<BDirectWindow*>(gState.currentWindow->Window()); + win->Lock(); + if (gState.currentWindow->parent) + gState.currentWindow->ResizeTo(width-1, height-1); // resize the child + else { + if(win->IsFullScreen()) { + win->SetFullScreen(false); + } + win->ResizeTo(width-1, height-1); // resize the parent + } + win->Unlock(); +} + +/*********************************************************** + * FUNCTION: glutFullScreen (4.9) + * + * DESCRIPTION: makes the window full screen + ***********************************************************/ +void glutFullScreen() { + BDirectWindow *win = dynamic_cast<BDirectWindow*>(gState.currentWindow->Window()); + win->Lock(); + win->SetFullScreen(true); + win->Unlock(); +} + +/*********************************************************** + * FUNCTION: glutPopWindow (4.10) + * glutPushWindow + * + * DESCRIPTION: change the stacking order of the current window + * NOTE: I can't figure out how to do this for windows, + * and there is no concept of "stacking order" for + * subwindows, so these are currently no-ops. + ***********************************************************/ +void glutPopWindow() { } +void glutPushWindow() { } + +/*********************************************************** + * FUNCTION: glutShowWindow (4.11) + * glutHideWindow + * glutIconifyWindow + * + * DESCRIPTION: change display status of current window + ***********************************************************/ +void glutShowWindow() { + gState.currentWindow->Window()->Lock(); + if (gState.currentWindow->parent) // subwindow + gState.currentWindow->Show(); + else { + if(gState.currentWindow->Window()->IsHidden()) + gState.currentWindow->Window()->Show(); // show the actual BWindow + gState.currentWindow->Window()->Minimize(false); + } + gState.currentWindow->Window()->Unlock(); +} + +void glutHideWindow() { + gState.currentWindow->Window()->Lock(); + if (gState.currentWindow->parent) // subwindow + gState.currentWindow->Hide(); + else + gState.currentWindow->Window()->Hide(); // show the actual BWindow + gState.currentWindow->Window()->Unlock(); +} + +void glutIconifyWindow() { + if(gState.currentWindow->parent) + __glutFatalError("can't iconify a subwindow"); + + gState.currentWindow->Window()->Lock(); + gState.currentWindow->Window()->Minimize(true); + gState.currentWindow->Window()->Unlock(); +} + +/*********************************************************** + * FUNCTION: glutSetWindowTitle (4.12) + * glutSetIconTitle + * + * DESCRIPTION: set the window title (icon title is same) + ***********************************************************/ +void glutSetWindowTitle(const char *name) { + if (gState.currentWindow->parent) + __glutFatalError("glutSetWindowTitle: isn't a top-level window"); + + gState.currentWindow->Window()->Lock(); + gState.currentWindow->Window()->SetTitle(name); + gState.currentWindow->Window()->Unlock(); +} + +void glutSetIconTitle(const char *name) { + glutSetWindowTitle(name); +} + +/*********************************************************** + * FUNCTION: __glutConvertDisplayMode + * + * DESCRIPTION: converts the current display mode into a BGLView + * display mode, printing warnings as appropriate. + * + * PARAMETERS: if options is non-NULL, the current display mode is + * returned in it. + * + * RETURNS: 1 if the current display mode is possible, else 0 + ***********************************************************/ +int __glutConvertDisplayMode(unsigned long *options) { + if (gState.displayString) { + /* __glutDisplayString should be NULL except if + glutInitDisplayString has been called to register a + different display string. Calling glutInitDisplayString + means using a string instead of an integer mask determine + the visual to use. This big ugly code is in glutDstr.cpp */ + return __glutConvertDisplayModeFromString(options); + } + + if(options) { + ulong newoptions = 0; + if(gState.displayMode & GLUT_ACCUM) + newoptions |= BGL_ACCUM; + if(gState.displayMode & GLUT_ALPHA) + newoptions |= BGL_ALPHA; + if(gState.displayMode & GLUT_DEPTH) + newoptions |= BGL_DEPTH; + if(gState.displayMode & GLUT_DOUBLE) + newoptions |= BGL_DOUBLE; + if(gState.displayMode & GLUT_STENCIL) + newoptions |= BGL_STENCIL; + *options = newoptions; + } + + if(gState.displayMode & GLUT_INDEX) { + __glutWarning("BeOS doesn't support indexed color"); + return 0; + } + if(gState.displayMode & GLUT_MULTISAMPLE) { + return 1; // try to go without multisampling + } + if(gState.displayMode & GLUT_STEREO) { + __glutWarning("BeOS doesn't support stereo windows"); + return 0; + } + if(gState.displayMode & GLUT_LUMINANCE) { + __glutWarning("BeOS doesn't support luminance color model"); + return 0; + } + return 1; // visual supported +} + +/*********************************************************** + * CLASS: GlutBWindow + * + * DESCRIPTION: very thin wrapper around BWindow + ***********************************************************/ +GlutBWindow::GlutBWindow(BRect frame, char *name) : + BDirectWindow(frame, name, B_TITLED_WINDOW, 0) { + fConnectionDisabled = false; + bgl = 0; + SetPulseRate(100000); + + if (!SupportsWindowMode()) { + __glutFatalError("video card doesn't support windowed operation"); + } +} + +void GlutBWindow::DirectConnected( direct_buffer_info *info ) { + bgl->DirectConnected(info); + if(bgl && !fConnectionDisabled) { + bgl->EnableDirectMode(true); + } + int newVisState; + if((info->buffer_state & B_DIRECT_MODE_MASK) == B_DIRECT_START) { + bgl->visible = true; + } + if(!bgl->visible || info->buffer_state == B_DIRECT_STOP) + newVisState = GLUT_HIDDEN; + else { + if (info->clip_list_count == 0) + newVisState = GLUT_FULLY_COVERED; + else if (info->clip_list_count == 1) + newVisState = GLUT_FULLY_RETAINED; + else + newVisState = GLUT_PARTIALLY_RETAINED; + } + if(newVisState != bgl->visState) { + bgl->visState = newVisState; + bgl->anyevents = bgl->windowStatusEvent = true; + gBlock.NewEvent(); + } +} + +GlutBWindow::~GlutBWindow() { + fConnectionDisabled = true; + if(bgl) { + bgl->EnableDirectMode(false); + } + if(!IsHidden()) + Hide(); + Sync(); +} + +bool GlutBWindow::QuitRequested() { + gState.quitAll = true; + gBlock.NewEvent(); + return false; // don't quit now, wait for main thread to do it +} + +void GlutBWindow::Minimize(bool minimize) { + bgl->visible = !minimize; + BWindow::Minimize(minimize); +} + +void GlutBWindow::Hide() { + BWindow::Hide(); + bgl->visible = false; +} + +void GlutBWindow::Show() { + BWindow::Show(); + bgl->visible = true; +} |