1 /***********************************************************
2 * Copyright (C) 1997, Be Inc. Copyright (C) 1999, Jake Hamby.
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.
11 * DESCRIPTION: all the routines for dealing with GlutWindows
12 ***********************************************************/
14 /***********************************************************
16 ***********************************************************/
20 #include "glutState.h"
21 #include "glutBlocker.h"
23 /***********************************************************
24 * FUNCTION: getUnusedWindowSlot
26 * DESCRIPTION: helper function to get a new window slot
27 ***********************************************************/
33 /* Look for allocated, unused slot. */
34 for (i
= 0; i
< gState
.windowListSize
; i
++) {
35 if (!gState
.windowList
[i
]) {
39 /* Allocate a new slot. */
40 gState
.windowListSize
++;
41 gState
.windowList
= (GlutWindow
**)
42 realloc(gState
.windowList
,
43 gState
.windowListSize
* sizeof(GlutWindow
*));
45 if (!gState
.windowList
)
46 __glutFatalError("out of memory.");
47 gState
.windowList
[gState
.windowListSize
- 1] = NULL
;
48 return gState
.windowListSize
- 1;
51 /***********************************************************
52 * FUNCTION: __glutDefaultDisplay
53 * __glutDefaultReshape
55 * DESCRIPTION: default display and reshape functions
56 ***********************************************************/
58 __glutDefaultDisplay(void)
60 /* XXX Remove the warning after GLUT 3.0. */
61 __glutWarning("The following is a new check for GLUT 3.0; update your code.");
63 "redisplay needed for window %d, but no display callback.",
64 gState
.currentWindow
->num
+ 1);
68 __glutDefaultReshape(int width
, int height
)
70 /* Adjust the viewport of the window */
71 glViewport(0, 0, (GLsizei
) width
, (GLsizei
) height
);
74 /***********************************************************
77 * FUNCTION: (constructor)
79 * DESCRIPTION: creates a new GLUT window
80 * note: subwindows don't resize, but top-level windows
82 ***********************************************************/
83 GlutWindow::GlutWindow(GlutWindow
*nparent
, char *name
,
84 int x
, int y
, int width
, int height
, ulong options
) :
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
,
92 // add myself to window list
93 num
= getUnusedWindowSlot();
94 gState
.windowList
[num
] = this;
96 // set up parent/children relationships
99 siblings
= parent
->children
;
100 parent
->children
= this;
106 // initialize variables
107 cursor
= GLUT_CURSOR_INHERIT
; // default cursor
108 for (int i
= 0; i
< GLUT_MAX_MENUS
; i
++) {
116 display
= __glutDefaultDisplay
;
117 reshape
= __glutDefaultReshape
;
127 // clear event counters
129 displayEvent
= 1; // get a reshape and a display event right away
136 windowStatusEvent
= 0; // DirectConnected() will report change in
137 visState
= -1; // visibility
142 gBlock
.QuickNewEvent();
144 // if i'm a subwindow, add me to my parent view
146 parent
->Window()->Lock();
147 parent
->AddChild(this);
148 parent
->Window()->Unlock();
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;
158 // give me the keyboard focus (focus follows mouse, X style, as
159 // implemented in GlutWindow::MouseMoved())
164 // make myself the default window
165 __glutSetWindow(this);
168 /***********************************************************
169 * FUNCTION: glutCreateWindow (4.1)
171 * DESCRIPTION: creates a new GLUT window
172 ***********************************************************/
173 int glutCreateWindow(const char *name
) {
178 if (!__glutConvertDisplayMode(&options
)) {
179 __glutWarning("visual with necessary capabilities not found.");
182 // if X or Y is negative, then start at a reasonable position
183 bool defaultxy
= (gState
.initX
< 0) || (gState
.initY
< 0);
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
);
189 return window
->num
+ 1;
192 /***********************************************************
193 * FUNCTION: glutCreateSubWindow (4.2)
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 ***********************************************************/
199 int glutCreateSubWindow(int win
, int x
, int y
, int width
, int height
) {
201 if (!__glutConvertDisplayMode(&options
)) {
202 __glutFatalError("visual with necessary capabilities not found.");
205 GlutWindow
*window
= new GlutWindow(gState
.windowList
[win
-1], "child",
206 x
, y
, width
, height
, options
);
208 return window
->num
+ 1;
211 /***********************************************************
212 * FUNCTION: __glutSetWindow
214 * DESCRIPTION: set the current window (utility function)
215 ***********************************************************/
217 __glutSetWindow(GlutWindow
* window
)
219 if (gState
.currentWindow
)
220 gState
.currentWindow
->UnlockGL();
221 gState
.currentWindow
= window
;
222 gState
.currentWindow
->LockGL();
225 /***********************************************************
226 * FUNCTION: glutSetWindow (4.3)
229 * DESCRIPTION: set and get the current window
230 ***********************************************************/
231 void glutSetWindow(int win
) {
234 if (win
< 1 || win
> gState
.windowListSize
) {
235 __glutWarning("glutSetWindow attempted on bogus window.");
238 window
= gState
.windowList
[win
- 1];
240 __glutWarning("glutSetWindow attempted on bogus window.");
243 __glutSetWindow(window
);
246 int glutGetWindow() {
247 if (gState
.currentWindow
) {
248 return gState
.currentWindow
->num
+ 1;
254 /***********************************************************
255 * FUNCTION: __glutDestroyWindow
257 * DESCRIPTION: recursively set entries to 0
258 ***********************************************************/
260 __glutDestroyWindow(GlutWindow
*window
, GlutWindow
*initialWindow
) {
261 // first, find all children recursively and set their entries to 0
262 GlutWindow
*cur
= window
->children
;
264 GlutWindow
*siblings
= cur
->siblings
;
265 __glutDestroyWindow(cur
, initialWindow
);
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
;
277 *prev
= cur
->siblings
;
280 prev
= &(cur
->siblings
);
285 // finally, check if we are the current window, and set to 0
286 if (gState
.currentWindow
== window
) {
287 gState
.currentWindow
= 0;
289 gState
.windowList
[window
->num
] = 0;
292 /***********************************************************
293 * FUNCTION: glutDestroyWindow (4.4)
295 * DESCRIPTION: destroy window and all its children
296 ***********************************************************/
297 void glutDestroyWindow(int win
) {
298 // can't destroy a window if another window has the GL context
299 if (gState
.currentWindow
)
300 gState
.currentWindow
->UnlockGL();
303 GlutWindow
*window
= gState
.windowList
[win
-1];
304 BWindow
*bwindow
= window
->Window();
307 // if win is the current window, set current window to 0
308 if (gState
.currentWindow
== window
) {
309 gState
.currentWindow
= 0;
312 // recursively set child entries to 0
313 __glutDestroyWindow(window
, window
);
315 // try flushing OpenGL
320 // now, if the window was top-level, delete its BWindow
321 if(!window
->parent
) {
324 // else, detach it from the BWindow and delete it
325 window
->RemoveSelf();
329 // relock GL if the current window is still valid
330 if(gState
.currentWindow
)
331 gState
.currentWindow
->LockGL();
334 /***********************************************************
335 * FUNCTION: __glutDestroyAllWindows
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 ***********************************************************/
341 void __glutDestroyAllWindows() {
342 for(int i
=0; i
<gState
.windowListSize
; i
++) {
343 if (gState
.windowList
[i
]) {
344 glutDestroyWindow(i
+ 1);
347 gState
.display
->Lock();
348 gState
.display
->Quit();
350 wait_for_thread(gState
.appthread
, &ignored
);
353 /***********************************************************
354 * FUNCTION: glutPostRedisplay (4.5)
356 * DESCRIPTION: mark window as needing redisplay
357 ***********************************************************/
358 void glutPostRedisplay() {
359 gState
.currentWindow
->Window()->Lock();
360 gState
.currentWindow
->anyevents
= true;
361 gState
.currentWindow
->displayEvent
= true;
362 gState
.currentWindow
->Window()->Unlock();
363 gBlock
.QuickNewEvent();
366 /***********************************************************
367 * FUNCTION: glutPostWindowRedisplay
369 * DESCRIPTION: mark window as needing redisplay
370 ***********************************************************/
371 void 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();
380 /***********************************************************
381 * FUNCTION: glutSwapBuffers (4.6)
383 * DESCRIPTION: swap buffers
384 ***********************************************************/
385 void glutSwapBuffers() {
386 gState
.currentWindow
->SwapBuffers();
389 /***********************************************************
390 * FUNCTION: glutPositionWindow (4.7)
392 * DESCRIPTION: move window
393 ***********************************************************/
394 void glutPositionWindow(int x
, int y
) {
395 BDirectWindow
*win
= dynamic_cast<BDirectWindow
*>(gState
.currentWindow
->Window());
397 if (gState
.currentWindow
->parent
)
398 gState
.currentWindow
->MoveTo(x
, y
); // move the child view
400 if(win
->IsFullScreen()) {
401 win
->SetFullScreen(false);
403 win
->MoveTo(x
, y
); // move the window
408 /***********************************************************
409 * FUNCTION: glutReshapeWindow (4.8)
411 * DESCRIPTION: reshape window (we'll catch the callback
412 * when the view gets a Draw() message
413 ***********************************************************/
414 void glutReshapeWindow(int width
, int height
) {
415 BDirectWindow
*win
= dynamic_cast<BDirectWindow
*>(gState
.currentWindow
->Window());
417 if (gState
.currentWindow
->parent
)
418 gState
.currentWindow
->ResizeTo(width
-1, height
-1); // resize the child
420 if(win
->IsFullScreen()) {
421 win
->SetFullScreen(false);
423 win
->ResizeTo(width
-1, height
-1); // resize the parent
428 /***********************************************************
429 * FUNCTION: glutFullScreen (4.9)
431 * DESCRIPTION: makes the window full screen
432 ***********************************************************/
433 void glutFullScreen() {
434 BDirectWindow
*win
= dynamic_cast<BDirectWindow
*>(gState
.currentWindow
->Window());
436 win
->SetFullScreen(true);
440 /***********************************************************
441 * FUNCTION: glutPopWindow (4.10)
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 ***********************************************************/
449 void glutPopWindow() { }
450 void glutPushWindow() { }
452 /***********************************************************
453 * FUNCTION: glutShowWindow (4.11)
457 * DESCRIPTION: change display status of current window
458 ***********************************************************/
459 void glutShowWindow() {
460 gState
.currentWindow
->Window()->Lock();
461 if (gState
.currentWindow
->parent
) // subwindow
462 gState
.currentWindow
->Show();
464 if(gState
.currentWindow
->Window()->IsHidden())
465 gState
.currentWindow
->Window()->Show(); // show the actual BWindow
466 gState
.currentWindow
->Window()->Minimize(false);
468 gState
.currentWindow
->Window()->Unlock();
471 void glutHideWindow() {
472 gState
.currentWindow
->Window()->Lock();
473 if (gState
.currentWindow
->parent
) // subwindow
474 gState
.currentWindow
->Hide();
476 gState
.currentWindow
->Window()->Hide(); // show the actual BWindow
477 gState
.currentWindow
->Window()->Unlock();
480 void glutIconifyWindow() {
481 if(gState
.currentWindow
->parent
)
482 __glutFatalError("can't iconify a subwindow");
484 gState
.currentWindow
->Window()->Lock();
485 gState
.currentWindow
->Window()->Minimize(true);
486 gState
.currentWindow
->Window()->Unlock();
489 /***********************************************************
490 * FUNCTION: glutSetWindowTitle (4.12)
493 * DESCRIPTION: set the window title (icon title is same)
494 ***********************************************************/
495 void glutSetWindowTitle(const char *name
) {
496 if (gState
.currentWindow
->parent
)
497 __glutFatalError("glutSetWindowTitle: isn't a top-level window");
499 gState
.currentWindow
->Window()->Lock();
500 gState
.currentWindow
->Window()->SetTitle(name
);
501 gState
.currentWindow
->Window()->Unlock();
504 void glutSetIconTitle(const char *name
) {
505 glutSetWindowTitle(name
);
508 /***********************************************************
509 * FUNCTION: __glutConvertDisplayMode
511 * DESCRIPTION: converts the current display mode into a BGLView
512 * display mode, printing warnings as appropriate.
514 * PARAMETERS: if options is non-NULL, the current display mode is
517 * RETURNS: 1 if the current display mode is possible, else 0
518 ***********************************************************/
519 int __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
);
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
;
544 if(gState
.displayMode
& GLUT_INDEX
) {
545 __glutWarning("BeOS doesn't support indexed color");
548 if(gState
.displayMode
& GLUT_MULTISAMPLE
) {
549 return 1; // try to go without multisampling
551 if(gState
.displayMode
& GLUT_STEREO
) {
552 __glutWarning("BeOS doesn't support stereo windows");
555 if(gState
.displayMode
& GLUT_LUMINANCE
) {
556 __glutWarning("BeOS doesn't support luminance color model");
559 return 1; // visual supported
562 /***********************************************************
565 * DESCRIPTION: very thin wrapper around BWindow
566 ***********************************************************/
567 GlutBWindow::GlutBWindow(BRect frame
, char *name
) :
568 BDirectWindow(frame
, name
, B_TITLED_WINDOW
, 0) {
569 fConnectionDisabled
= false;
571 SetPulseRate(100000);
573 if (!SupportsWindowMode()) {
574 __glutFatalError("video card doesn't support windowed operation");
578 void GlutBWindow::DirectConnected( direct_buffer_info
*info
) {
579 bgl
->DirectConnected(info
);
580 if(bgl
&& !fConnectionDisabled
) {
581 bgl
->EnableDirectMode(true);
584 if((info
->buffer_state
& B_DIRECT_MODE_MASK
) == B_DIRECT_START
) {
587 if(!bgl
->visible
|| info
->buffer_state
== B_DIRECT_STOP
)
588 newVisState
= GLUT_HIDDEN
;
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
;
595 newVisState
= GLUT_PARTIALLY_RETAINED
;
597 if(newVisState
!= bgl
->visState
) {
598 bgl
->visState
= newVisState
;
599 bgl
->anyevents
= bgl
->windowStatusEvent
= true;
604 GlutBWindow::~GlutBWindow() {
605 fConnectionDisabled
= true;
607 bgl
->EnableDirectMode(false);
614 bool GlutBWindow::QuitRequested() {
615 gState
.quitAll
= true;
617 return false; // don't quit now, wait for main thread to do it
620 void GlutBWindow::Minimize(bool minimize
) {
621 bgl
->visible
= !minimize
;
622 BWindow::Minimize(minimize
);
625 void GlutBWindow::Hide() {
627 bgl
->visible
= false;
630 void GlutBWindow::Show() {