* 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.
*
* DESCRIPTION: all the routines for dealing with GlutWindows
***********************************************************/
#include <stdlib.h>
#include <GL/glut.h>
#include "glutint.h"
#include "glutState.h"
#include "glutBlocker.h"
static int
getUnusedWindowSlot()
{
int i;
for (i = 0; i < gState.windowListSize; i++) {
if (!gState.windowList[i])
return i;
}
gState.windowListSize++;
gState.windowList = (GlutWindow **)realloc(gState.windowList,
gState.windowListSize * sizeof(GlutWindow *));
if (gState.windowList == NULL)
__glutFatalError("out of memory.");
gState.windowList[gState.windowListSize - 1] = NULL;
return gState.windowListSize - 1;
}
static void
__glutDefaultDisplay(void)
{
__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)
{
glViewport(0, 0, (GLsizei) width, (GLsizei) height);
}
Note: subwindows don't resize, but top-level windows
follow all sides.
*/
GlutWindow::GlutWindow(GlutWindow *nparent, const char *name,
int x, int y, int width, int height, ulong options)
: BGLView(nparent != NULL ? BRect(x, y, x + width - 1, y + height - 1)
: BRect(0, 0, width - 1, height - 1), name,
nparent != NULL ? B_FOLLOW_NONE : B_FOLLOW_ALL_SIDES,
B_WILL_DRAW | B_FRAME_EVENTS | B_FULL_UPDATE_ON_RESIZE | B_PULSE_NEEDED,
options)
{
num = getUnusedWindowSlot();
gState.windowList[num] = this;
parent = nparent;
if (parent) {
siblings = parent->children;
parent->children = this;
} else {
siblings = 0;
}
children = 0;
cursor = GLUT_CURSOR_INHERIT;
for (int i = 0; i < GLUT_MAX_MENUS; i++) {
menu[i] = 0;
}
m_width = width;
m_height = height;
m_buttons = 0;
display = __glutDefaultDisplay;
reshape = __glutDefaultReshape;
mouse = NULL;
motion = NULL;
passive = NULL;
entry = NULL;
keyboard = NULL;
keyboardUp = NULL;
visibility = NULL;
special = NULL;
specialUp = NULL;
windowStatus = NULL;
anyevents = 1;
displayEvent = 1;
reshapeEvent = 1;
mouseEvent = 0;
motionEvent = 0;
passiveEvent = 0;
entryEvent = 0;
keybEvent = 0;
keybUpEvent = 0;
windowStatusEvent = 0;
visState = -1;
specialEvent = 0;
specialUpEvent = 0;
statusEvent = 0;
menuEvent = 0;
visible = true;
ignoreKeyRepeat = (gState.keyRepeatMode == GLUT_KEY_REPEAT_OFF);
gBlock.QuickNewEvent();
if (parent) {
parent->Window()->Lock();
parent->AddChild(this);
parent->Window()->Unlock();
} else {
GlutBWindow *mybwindow = new GlutBWindow(
BRect(x, y, x + width - 1, y + height - 1), name);
mybwindow->AddChild(this);
mybwindow->bgl = this;
mybwindow->Show();
}
Window()->Lock();
MakeFocus();
Window()->Unlock();
__glutSetWindow(this);
}
int
glutCreateWindow(const char *name)
{
if (!be_app)
__glutInit();
ulong options;
if (!__glutConvertDisplayMode(&options)) {
__glutWarning("visual with necessary capabilities not found.");
}
bool defaultxy = gState.initX < 0 || gState.initY < 0;
GlutWindow *window = new GlutWindow(0, name,
defaultxy ? 50 : gState.initX, defaultxy ? 50 : gState.initY,
gState.initWidth, gState.initHeight, options);
return window->num + 1;
}
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;
}
void
__glutSetWindow(GlutWindow *window)
{
if (gState.currentWindow)
gState.currentWindow->UnlockGL();
gState.currentWindow = window;
gState.currentWindow->LockGL();
}
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;
return 0;
}
static void
__glutDestroyWindow(GlutWindow *window, GlutWindow *initialWindow)
{
GlutWindow *cur = window->children;
while (cur) {
GlutWindow *siblings = cur->siblings;
__glutDestroyWindow(cur, initialWindow);
cur = siblings;
}
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;
}
}
if (gState.currentWindow == window)
gState.currentWindow = 0;
gState.windowList[window->num] = 0;
}
void
glutDestroyWindow(int win)
{
if (gState.currentWindow)
gState.currentWindow->UnlockGL();
GlutWindow *window = gState.windowList[win - 1];
BWindow *bwindow = window->Window();
bwindow->Lock();
if (gState.currentWindow == window)
gState.currentWindow = 0;
__glutDestroyWindow(window, window);
window->LockGL();
glFlush();
window->UnlockGL();
if (!window->parent) {
bwindow->Quit();
} else {
window->RemoveSelf();
delete window;
bwindow->Unlock();
}
if (gState.currentWindow)
gState.currentWindow->LockGL();
}
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();
gState.display->Unlock();
status_t ignored;
wait_for_thread(gState.appthread, &ignored);
}
void
glutPostRedisplay()
{
gState.currentWindow->Window()->Lock();
gState.currentWindow->anyevents = true;
gState.currentWindow->displayEvent = true;
gState.currentWindow->Window()->Unlock();
gBlock.QuickNewEvent();
}
void
glutPostWindowRedisplay(int win)
{
GlutWindow *gwin = gState.windowList[win - 1];
gwin->Window()->Lock();
gwin->anyevents = true;
gwin->displayEvent = true;
gwin->Window()->Unlock();
gBlock.QuickNewEvent();
}
void
glutSwapBuffers()
{
gState.currentWindow->SwapBuffers();
}
void
glutPositionWindow(int x, int y)
{
BDirectWindow *win = dynamic_cast<BDirectWindow*>(gState.currentWindow->Window());
if (win == NULL)
return;
win->Lock();
if (gState.currentWindow->parent)
gState.currentWindow->MoveTo(x, y);
else {
if (win->IsFullScreen())
win->SetFullScreen(false);
win->MoveTo(x, y);
}
win->Unlock();
}
a Draw() message).
*/
void
glutReshapeWindow(int width, int height)
{
BDirectWindow *win = dynamic_cast<BDirectWindow*>(gState.currentWindow->Window());
if (win == NULL)
return;
win->Lock();
if (gState.currentWindow->parent) {
gState.currentWindow->ResizeTo(width - 1, height - 1);
} else {
if (win->IsFullScreen())
win->SetFullScreen(false);
win->ResizeTo(width - 1, height - 1);
}
win->Unlock();
}
void
glutFullScreen()
{
BDirectWindow *win = dynamic_cast<BDirectWindow*>(gState.currentWindow->Window());
if (win == NULL)
return;
win->Lock();
win->SetFullScreen(true);
win->Unlock();
}
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()
{
}
void
glutShowWindow()
{
gState.currentWindow->Window()->Lock();
if (gState.currentWindow->parent)
gState.currentWindow->Show();
else {
if(gState.currentWindow->Window()->IsHidden())
gState.currentWindow->Window()->Show();
gState.currentWindow->Window()->Minimize(false);
}
gState.currentWindow->Window()->Unlock();
}
void
glutHideWindow()
{
gState.currentWindow->Window()->Lock();
if (gState.currentWindow->parent)
gState.currentWindow->Hide();
else
gState.currentWindow->Window()->Hide();
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();
}
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);
}
display mode, printing warnings as appropriate.
\param options if non-NULL, the current display mode is
returned in it.
\return 1 if the current display mode is possible, else 0
*/
int
__glutConvertDisplayMode(unsigned long *options)
{
if (gState.displayString) {
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;
}
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;
}
GlutBWindow::GlutBWindow(BRect frame, const 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)
{
if (!bgl)
return;
bgl->DirectConnected(info);
if (!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;
}
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;
}