glutWindow.cpp revision c041511d
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: glutWindow.cpp 10 * 11 * DESCRIPTION: all the routines for dealing with GlutWindows 12 ***********************************************************/ 13 14/*********************************************************** 15 * Headers 16 ***********************************************************/ 17#include <GL/glut.h> 18#include <stdlib.h> 19#include "glutint.h" 20#include "glutState.h" 21#include "glutBlocker.h" 22 23/*********************************************************** 24 * FUNCTION: getUnusedWindowSlot 25 * 26 * DESCRIPTION: helper function to get a new window slot 27 ***********************************************************/ 28static int 29getUnusedWindowSlot() 30{ 31 int i; 32 33 /* Look for allocated, unused slot. */ 34 for (i = 0; i < gState.windowListSize; i++) { 35 if (!gState.windowList[i]) { 36 return i; 37 } 38 } 39 /* Allocate a new slot. */ 40 gState.windowListSize++; 41 gState.windowList = (GlutWindow **) 42 realloc(gState.windowList, 43 gState.windowListSize * sizeof(GlutWindow *)); 44 45 if (!gState.windowList) 46 __glutFatalError("out of memory."); 47 gState.windowList[gState.windowListSize - 1] = NULL; 48 return gState.windowListSize - 1; 49} 50 51/*********************************************************** 52 * FUNCTION: __glutDefaultDisplay 53 * __glutDefaultReshape 54 * 55 * DESCRIPTION: default display and reshape functions 56 ***********************************************************/ 57static void 58__glutDefaultDisplay(void) 59{ 60 /* XXX Remove the warning after GLUT 3.0. */ 61 __glutWarning("The following is a new check for GLUT 3.0; update your code."); 62 __glutFatalError( 63 "redisplay needed for window %d, but no display callback.", 64 gState.currentWindow->num + 1); 65} 66 67void 68__glutDefaultReshape(int width, int height) 69{ 70 /* Adjust the viewport of the window */ 71 glViewport(0, 0, (GLsizei) width, (GLsizei) height); 72} 73 74/*********************************************************** 75 * CLASS: GlutWindow 76 * 77 * FUNCTION: (constructor) 78 * 79 * DESCRIPTION: creates a new GLUT window 80 * note: subwindows don't resize, but top-level windows 81 * follow all sides 82 ***********************************************************/ 83GlutWindow::GlutWindow(GlutWindow *nparent, char *name, 84 int x, int y, int width, int height, ulong options) : 85 BGLView( 86 (nparent ? BRect(x,y,x+width-1,y+height-1) : 87 BRect(0,0,width-1,height-1)), name, 88 (nparent ? B_FOLLOW_NONE : B_FOLLOW_ALL_SIDES), 89 B_WILL_DRAW|B_FRAME_EVENTS|B_FULL_UPDATE_ON_RESIZE|B_PULSE_NEEDED, 90 options) 91{ 92 // add myself to window list 93 num = getUnusedWindowSlot(); 94 gState.windowList[num] = this; 95 96 // set up parent/children relationships 97 parent = nparent; 98 if (parent) { 99 siblings = parent->children; 100 parent->children = this; 101 } else { 102 siblings = 0; 103 } 104 children = 0; 105 106 // initialize variables 107 cursor = GLUT_CURSOR_INHERIT; // default cursor 108 for (int i = 0; i < GLUT_MAX_MENUS; i++) { 109 menu[i] = 0; 110 } 111 m_width = width; 112 m_height = height; 113 m_buttons = 0; 114 115 // clear callbacks 116 display = __glutDefaultDisplay; 117 reshape = __glutDefaultReshape; 118 mouse = 0; 119 motion = 0; 120 passive = 0; 121 entry = 0; 122 keyboard = 0; 123 visibility = 0; 124 special = 0; 125 windowStatus = 0; 126 127 // clear event counters 128 anyevents = 1; 129 displayEvent = 1; // get a reshape and a display event right away 130 reshapeEvent = 1; 131 mouseEvent = 0; 132 motionEvent = 0; 133 passiveEvent = 0; 134 entryEvent = 0; 135 keybEvent = 0; 136 windowStatusEvent = 0; // DirectConnected() will report change in 137 visState = -1; // visibility 138 specialEvent = 0; 139 statusEvent = 0; 140 menuEvent = 0; 141 visible = true; 142 gBlock.QuickNewEvent(); 143 144 // if i'm a subwindow, add me to my parent view 145 if (parent) { 146 parent->Window()->Lock(); 147 parent->AddChild(this); 148 parent->Window()->Unlock(); 149 } else { 150 // if I'm a top-level window, create my BWindow 151 GlutBWindow *mybwindow = new GlutBWindow( 152 BRect(x,y,x+width-1,y+height-1), name); 153 mybwindow->AddChild(this); 154 mybwindow->bgl = this; 155 mybwindow->Show(); 156 } 157 158 // give me the keyboard focus (focus follows mouse, X style, as 159 // implemented in GlutWindow::MouseMoved()) 160 Window()->Lock(); 161 MakeFocus(); 162 Window()->Unlock(); 163 164 // make myself the default window 165 __glutSetWindow(this); 166} 167 168/*********************************************************** 169 * FUNCTION: glutCreateWindow (4.1) 170 * 171 * DESCRIPTION: creates a new GLUT window 172 ***********************************************************/ 173int glutCreateWindow(const char *name) { 174 if (!be_app) 175 __glutInit(); 176 177 ulong options; 178 if (!__glutConvertDisplayMode(&options)) { 179 __glutWarning("visual with necessary capabilities not found."); 180 } 181 182 // if X or Y is negative, then start at a reasonable position 183 bool defaultxy = (gState.initX < 0) || (gState.initY < 0); 184 185 GlutWindow *window = new GlutWindow(0, const_cast<char*>(name), 186 (defaultxy ? 50 : gState.initX), (defaultxy ? 50 : gState.initY), 187 gState.initWidth, gState.initHeight, options); 188 189 return window->num + 1; 190} 191 192/*********************************************************** 193 * FUNCTION: glutCreateSubWindow (4.2) 194 * 195 * DESCRIPTION: creates a new GLUT subwindow 196 * Note: a subwindow is a GlutWindow (which is actually 197 * a BGLView) without its own BWindow 198 ***********************************************************/ 199int glutCreateSubWindow(int win, int x, int y, int width, int height) { 200 ulong options; 201 if (!__glutConvertDisplayMode(&options)) { 202 __glutFatalError("visual with necessary capabilities not found."); 203 } 204 205 GlutWindow *window = new GlutWindow(gState.windowList[win-1], "child", 206 x, y, width, height, options); 207 208 return window->num + 1; 209} 210 211/*********************************************************** 212 * FUNCTION: __glutSetWindow 213 * 214 * DESCRIPTION: set the current window (utility function) 215 ***********************************************************/ 216void 217__glutSetWindow(GlutWindow * window) 218{ 219 if (gState.currentWindow) 220 gState.currentWindow->UnlockGL(); 221 gState.currentWindow = window; 222 gState.currentWindow->LockGL(); 223} 224 225/*********************************************************** 226 * FUNCTION: glutSetWindow (4.3) 227 * glutGetWindow 228 * 229 * DESCRIPTION: set and get the current window 230 ***********************************************************/ 231void glutSetWindow(int win) { 232 GlutWindow *window; 233 234 if (win < 1 || win > gState.windowListSize) { 235 __glutWarning("glutSetWindow attempted on bogus window."); 236 return; 237 } 238 window = gState.windowList[win - 1]; 239 if (!window) { 240 __glutWarning("glutSetWindow attempted on bogus window."); 241 return; 242 } 243 __glutSetWindow(window); 244} 245 246int glutGetWindow() { 247 if (gState.currentWindow) { 248 return gState.currentWindow->num + 1; 249 } else { 250 return 0; 251 } 252} 253 254/*********************************************************** 255 * FUNCTION: __glutDestroyWindow 256 * 257 * DESCRIPTION: recursively set entries to 0 258 ***********************************************************/ 259static void 260__glutDestroyWindow(GlutWindow *window, GlutWindow *initialWindow) { 261 // first, find all children recursively and set their entries to 0 262 GlutWindow *cur = window->children; 263 while (cur) { 264 GlutWindow *siblings = cur->siblings; 265 __glutDestroyWindow(cur, initialWindow); 266 cur = siblings; 267 } 268 269 /* Remove from parent's children list (only necessary for 270 non-initial windows and subwindows!). */ 271 GlutWindow *parent = window->parent; 272 if (parent && parent == initialWindow->parent) { 273 GlutWindow **prev = &parent->children; 274 cur = parent->children; 275 while (cur) { 276 if (cur == window) { 277 *prev = cur->siblings; 278 break; 279 } 280 prev = &(cur->siblings); 281 cur = cur->siblings; 282 } 283 } 284 285 // finally, check if we are the current window, and set to 0 286 if (gState.currentWindow == window) { 287 gState.currentWindow = 0; 288 } 289 gState.windowList[window->num] = 0; 290} 291 292/*********************************************************** 293 * FUNCTION: glutDestroyWindow (4.4) 294 * 295 * DESCRIPTION: destroy window and all its children 296 ***********************************************************/ 297void glutDestroyWindow(int win) { 298 // can't destroy a window if another window has the GL context 299 if (gState.currentWindow) 300 gState.currentWindow->UnlockGL(); 301 302 // lock the window 303 GlutWindow *window = gState.windowList[win-1]; 304 BWindow *bwindow = window->Window(); 305 bwindow->Lock(); 306 307 // if win is the current window, set current window to 0 308 if (gState.currentWindow == window) { 309 gState.currentWindow = 0; 310 } 311 312 // recursively set child entries to 0 313 __glutDestroyWindow(window, window); 314 315 // try flushing OpenGL 316 window->LockGL(); 317 glFlush(); 318 window->UnlockGL(); 319 320 // now, if the window was top-level, delete its BWindow 321 if(!window->parent) { 322 bwindow->Quit(); 323 } else { 324 // else, detach it from the BWindow and delete it 325 window->RemoveSelf(); 326 delete window; 327 bwindow->Unlock(); 328 } 329 // relock GL if the current window is still valid 330 if(gState.currentWindow) 331 gState.currentWindow->LockGL(); 332} 333 334/*********************************************************** 335 * FUNCTION: __glutDestroyAllWindows 336 * 337 * DESCRIPTION: destroy all windows when exit() is called 338 * this seems to be necessary to avoid delays 339 * and crashes when using BDirectWindow 340 ***********************************************************/ 341void __glutDestroyAllWindows() { 342 for(int i=0; i<gState.windowListSize; i++) { 343 if (gState.windowList[i]) { 344 glutDestroyWindow(i + 1); 345 } 346 } 347 gState.display->Lock(); 348 gState.display->Quit(); 349 status_t ignored; 350 wait_for_thread(gState.appthread, &ignored); 351} 352 353/*********************************************************** 354 * FUNCTION: glutPostRedisplay (4.5) 355 * 356 * DESCRIPTION: mark window as needing redisplay 357 ***********************************************************/ 358void glutPostRedisplay() { 359 gState.currentWindow->Window()->Lock(); 360 gState.currentWindow->anyevents = true; 361 gState.currentWindow->displayEvent = true; 362 gState.currentWindow->Window()->Unlock(); 363 gBlock.QuickNewEvent(); 364} 365 366/*********************************************************** 367 * FUNCTION: glutPostWindowRedisplay 368 * 369 * DESCRIPTION: mark window as needing redisplay 370 ***********************************************************/ 371void glutPostWindowRedisplay(int win) { 372 GlutWindow *gwin = gState.windowList[win - 1]; 373 gwin->Window()->Lock(); 374 gwin->anyevents = true; 375 gwin->displayEvent = true; 376 gwin->Window()->Unlock(); 377 gBlock.QuickNewEvent(); 378} 379 380/*********************************************************** 381 * FUNCTION: glutSwapBuffers (4.6) 382 * 383 * DESCRIPTION: swap buffers 384 ***********************************************************/ 385void glutSwapBuffers() { 386 gState.currentWindow->SwapBuffers(); 387} 388 389/*********************************************************** 390 * FUNCTION: glutPositionWindow (4.7) 391 * 392 * DESCRIPTION: move window 393 ***********************************************************/ 394void glutPositionWindow(int x, int y) { 395 BDirectWindow *win = dynamic_cast<BDirectWindow*>(gState.currentWindow->Window()); 396 win->Lock(); 397 if (gState.currentWindow->parent) 398 gState.currentWindow->MoveTo(x, y); // move the child view 399 else { 400 if(win->IsFullScreen()) { 401 win->SetFullScreen(false); 402 } 403 win->MoveTo(x, y); // move the window 404 } 405 win->Unlock(); 406} 407 408/*********************************************************** 409 * FUNCTION: glutReshapeWindow (4.8) 410 * 411 * DESCRIPTION: reshape window (we'll catch the callback 412 * when the view gets a Draw() message 413 ***********************************************************/ 414void glutReshapeWindow(int width, int height) { 415 BDirectWindow *win = dynamic_cast<BDirectWindow*>(gState.currentWindow->Window()); 416 win->Lock(); 417 if (gState.currentWindow->parent) 418 gState.currentWindow->ResizeTo(width-1, height-1); // resize the child 419 else { 420 if(win->IsFullScreen()) { 421 win->SetFullScreen(false); 422 } 423 win->ResizeTo(width-1, height-1); // resize the parent 424 } 425 win->Unlock(); 426} 427 428/*********************************************************** 429 * FUNCTION: glutFullScreen (4.9) 430 * 431 * DESCRIPTION: makes the window full screen 432 ***********************************************************/ 433void glutFullScreen() { 434 BDirectWindow *win = dynamic_cast<BDirectWindow*>(gState.currentWindow->Window()); 435 win->Lock(); 436 win->SetFullScreen(true); 437 win->Unlock(); 438} 439 440/*********************************************************** 441 * FUNCTION: glutPopWindow (4.10) 442 * glutPushWindow 443 * 444 * DESCRIPTION: change the stacking order of the current window 445 * NOTE: I can't figure out how to do this for windows, 446 * and there is no concept of "stacking order" for 447 * subwindows, so these are currently no-ops. 448 ***********************************************************/ 449void glutPopWindow() { } 450void glutPushWindow() { } 451 452/*********************************************************** 453 * FUNCTION: glutShowWindow (4.11) 454 * glutHideWindow 455 * glutIconifyWindow 456 * 457 * DESCRIPTION: change display status of current window 458 ***********************************************************/ 459void glutShowWindow() { 460 gState.currentWindow->Window()->Lock(); 461 if (gState.currentWindow->parent) // subwindow 462 gState.currentWindow->Show(); 463 else { 464 if(gState.currentWindow->Window()->IsHidden()) 465 gState.currentWindow->Window()->Show(); // show the actual BWindow 466 gState.currentWindow->Window()->Minimize(false); 467 } 468 gState.currentWindow->Window()->Unlock(); 469} 470 471void glutHideWindow() { 472 gState.currentWindow->Window()->Lock(); 473 if (gState.currentWindow->parent) // subwindow 474 gState.currentWindow->Hide(); 475 else 476 gState.currentWindow->Window()->Hide(); // show the actual BWindow 477 gState.currentWindow->Window()->Unlock(); 478} 479 480void glutIconifyWindow() { 481 if(gState.currentWindow->parent) 482 __glutFatalError("can't iconify a subwindow"); 483 484 gState.currentWindow->Window()->Lock(); 485 gState.currentWindow->Window()->Minimize(true); 486 gState.currentWindow->Window()->Unlock(); 487} 488 489/*********************************************************** 490 * FUNCTION: glutSetWindowTitle (4.12) 491 * glutSetIconTitle 492 * 493 * DESCRIPTION: set the window title (icon title is same) 494 ***********************************************************/ 495void glutSetWindowTitle(const char *name) { 496 if (gState.currentWindow->parent) 497 __glutFatalError("glutSetWindowTitle: isn't a top-level window"); 498 499 gState.currentWindow->Window()->Lock(); 500 gState.currentWindow->Window()->SetTitle(name); 501 gState.currentWindow->Window()->Unlock(); 502} 503 504void glutSetIconTitle(const char *name) { 505 glutSetWindowTitle(name); 506} 507 508/*********************************************************** 509 * FUNCTION: __glutConvertDisplayMode 510 * 511 * DESCRIPTION: converts the current display mode into a BGLView 512 * display mode, printing warnings as appropriate. 513 * 514 * PARAMETERS: if options is non-NULL, the current display mode is 515 * returned in it. 516 * 517 * RETURNS: 1 if the current display mode is possible, else 0 518 ***********************************************************/ 519int __glutConvertDisplayMode(unsigned long *options) { 520 if (gState.displayString) { 521 /* __glutDisplayString should be NULL except if 522 glutInitDisplayString has been called to register a 523 different display string. Calling glutInitDisplayString 524 means using a string instead of an integer mask determine 525 the visual to use. This big ugly code is in glutDstr.cpp */ 526 return __glutConvertDisplayModeFromString(options); 527 } 528 529 if(options) { 530 ulong newoptions = 0; 531 if(gState.displayMode & GLUT_ACCUM) 532 newoptions |= BGL_ACCUM; 533 if(gState.displayMode & GLUT_ALPHA) 534 newoptions |= BGL_ALPHA; 535 if(gState.displayMode & GLUT_DEPTH) 536 newoptions |= BGL_DEPTH; 537 if(gState.displayMode & GLUT_DOUBLE) 538 newoptions |= BGL_DOUBLE; 539 if(gState.displayMode & GLUT_STENCIL) 540 newoptions |= BGL_STENCIL; 541 *options = newoptions; 542 } 543 544 if(gState.displayMode & GLUT_INDEX) { 545 __glutWarning("BeOS doesn't support indexed color"); 546 return 0; 547 } 548 if(gState.displayMode & GLUT_MULTISAMPLE) { 549 return 1; // try to go without multisampling 550 } 551 if(gState.displayMode & GLUT_STEREO) { 552 __glutWarning("BeOS doesn't support stereo windows"); 553 return 0; 554 } 555 if(gState.displayMode & GLUT_LUMINANCE) { 556 __glutWarning("BeOS doesn't support luminance color model"); 557 return 0; 558 } 559 return 1; // visual supported 560} 561 562/*********************************************************** 563 * CLASS: GlutBWindow 564 * 565 * DESCRIPTION: very thin wrapper around BWindow 566 ***********************************************************/ 567GlutBWindow::GlutBWindow(BRect frame, char *name) : 568 BDirectWindow(frame, name, B_TITLED_WINDOW, 0) { 569 fConnectionDisabled = false; 570 bgl = 0; 571 SetPulseRate(100000); 572 573 if (!SupportsWindowMode()) { 574 __glutFatalError("video card doesn't support windowed operation"); 575 } 576} 577 578void GlutBWindow::DirectConnected( direct_buffer_info *info ) { 579 bgl->DirectConnected(info); 580 if(bgl && !fConnectionDisabled) { 581 bgl->EnableDirectMode(true); 582 } 583 int newVisState; 584 if((info->buffer_state & B_DIRECT_MODE_MASK) == B_DIRECT_START) { 585 bgl->visible = true; 586 } 587 if(!bgl->visible || info->buffer_state == B_DIRECT_STOP) 588 newVisState = GLUT_HIDDEN; 589 else { 590 if (info->clip_list_count == 0) 591 newVisState = GLUT_FULLY_COVERED; 592 else if (info->clip_list_count == 1) 593 newVisState = GLUT_FULLY_RETAINED; 594 else 595 newVisState = GLUT_PARTIALLY_RETAINED; 596 } 597 if(newVisState != bgl->visState) { 598 bgl->visState = newVisState; 599 bgl->anyevents = bgl->windowStatusEvent = true; 600 gBlock.NewEvent(); 601 } 602} 603 604GlutBWindow::~GlutBWindow() { 605 fConnectionDisabled = true; 606 if(bgl) { 607 bgl->EnableDirectMode(false); 608 } 609 if(!IsHidden()) 610 Hide(); 611 Sync(); 612} 613 614bool GlutBWindow::QuitRequested() { 615 gState.quitAll = true; 616 gBlock.NewEvent(); 617 return false; // don't quit now, wait for main thread to do it 618} 619 620void GlutBWindow::Minimize(bool minimize) { 621 bgl->visible = !minimize; 622 BWindow::Minimize(minimize); 623} 624 625void GlutBWindow::Hide() { 626 BWindow::Hide(); 627 bgl->visible = false; 628} 629 630void GlutBWindow::Show() { 631 BWindow::Show(); 632 bgl->visible = true; 633} 634