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.
8 * DESCRIPTION: all the routines for dealing with GlutWindows
9 ***********************************************************/
16 #include "glutState.h"
17 #include "glutBlocker.h"
20 /*! Helper function to get a new window slot */
26 /* Look for allocated, unused slot. */
27 for (i
= 0; i
< gState
.windowListSize
; i
++) {
28 if (!gState
.windowList
[i
])
32 /* Allocate a new slot. */
33 gState
.windowListSize
++;
34 gState
.windowList
= (GlutWindow
**)realloc(gState
.windowList
,
35 gState
.windowListSize
* sizeof(GlutWindow
*));
36 if (gState
.windowList
== NULL
)
37 __glutFatalError("out of memory.");
39 gState
.windowList
[gState
.windowListSize
- 1] = NULL
;
40 return gState
.windowListSize
- 1;
44 /*! Default display function */
46 __glutDefaultDisplay(void)
48 /* XXX Remove the warning after GLUT 3.0. */
49 __glutWarning("The following is a new check for GLUT 3.0; update your "
51 __glutFatalError("redisplay needed for window %d, but no display callback.",
52 gState
.currentWindow
->num
+ 1);
56 /*! Default reshape function */
58 __glutDefaultReshape(int width
, int height
)
60 /* Adjust the viewport of the window */
61 glViewport(0, 0, (GLsizei
) width
, (GLsizei
) height
);
68 /*! Creates a new GLUT window
69 Note: subwindows don't resize, but top-level windows
72 GlutWindow::GlutWindow(GlutWindow
*nparent
, const char *name
,
73 int x
, int y
, int width
, int height
, ulong options
)
74 : BGLView(nparent
!= NULL
? BRect(x
, y
, x
+ width
- 1, y
+ height
- 1)
75 : BRect(0, 0, width
- 1, height
- 1), name
,
76 nparent
!= NULL
? B_FOLLOW_NONE
: B_FOLLOW_ALL_SIDES
,
77 B_WILL_DRAW
| B_FRAME_EVENTS
| B_FULL_UPDATE_ON_RESIZE
| B_PULSE_NEEDED
,
80 // add myself to window list
81 num
= getUnusedWindowSlot();
82 gState
.windowList
[num
] = this;
84 // set up parent/children relationships
87 siblings
= parent
->children
;
88 parent
->children
= this;
94 // initialize variables
95 cursor
= GLUT_CURSOR_INHERIT
; // default cursor
96 for (int i
= 0; i
< GLUT_MAX_MENUS
; i
++) {
104 display
= __glutDefaultDisplay
;
105 reshape
= __glutDefaultReshape
;
117 // clear event counters
119 displayEvent
= 1; // get a reshape and a display event right away
127 windowStatusEvent
= 0; // DirectConnected() will report change in
128 visState
= -1; // visibility
134 ignoreKeyRepeat
= (gState
.keyRepeatMode
== GLUT_KEY_REPEAT_OFF
);
136 gBlock
.QuickNewEvent();
138 // if i'm a subwindow, add me to my parent view
140 parent
->Window()->Lock();
141 parent
->AddChild(this);
142 parent
->Window()->Unlock();
144 // if I'm a top-level window, create my BWindow
145 GlutBWindow
*mybwindow
= new GlutBWindow(
146 BRect(x
, y
, x
+ width
- 1, y
+ height
- 1), name
);
147 mybwindow
->AddChild(this);
148 mybwindow
->bgl
= this;
152 // give me the keyboard focus (focus follows mouse, X style, as
153 // implemented in GlutWindow::MouseMoved())
158 // make myself the default window
159 __glutSetWindow(this);
163 /*! Creates a new GLUT window */
165 glutCreateWindow(const char *name
)
171 if (!__glutConvertDisplayMode(&options
)) {
172 __glutWarning("visual with necessary capabilities not found.");
175 // if X or Y is negative, then start at a reasonable position
176 bool defaultxy
= gState
.initX
< 0 || gState
.initY
< 0;
178 GlutWindow
*window
= new GlutWindow(0, name
,
179 defaultxy
? 50 : gState
.initX
, defaultxy
? 50 : gState
.initY
,
180 gState
.initWidth
, gState
.initHeight
, options
);
182 return window
->num
+ 1;
186 /*! Creates a new GLUT subwindow
187 Note: a subwindow is a GlutWindow (which is actually
188 a BGLView) without its own BWindow
191 glutCreateSubWindow(int win
, int x
, int y
, int width
, int height
)
194 if (!__glutConvertDisplayMode(&options
)) {
195 __glutFatalError("visual with necessary capabilities not found.");
198 GlutWindow
*window
= new GlutWindow(gState
.windowList
[win
-1], "child",
199 x
, y
, width
, height
, options
);
201 return window
->num
+ 1;
205 /*! Set the current window (utility function) */
207 __glutSetWindow(GlutWindow
*window
)
209 if (gState
.currentWindow
)
210 gState
.currentWindow
->UnlockGL();
211 gState
.currentWindow
= window
;
212 gState
.currentWindow
->LockGL();
216 /*! Set and get the current window */
218 glutSetWindow(int win
)
222 if (win
< 1 || win
> gState
.windowListSize
) {
223 __glutWarning("glutSetWindow attempted on bogus window.");
227 window
= gState
.windowList
[win
- 1];
229 __glutWarning("glutSetWindow attempted on bogus window.");
232 __glutSetWindow(window
);
239 if (gState
.currentWindow
)
240 return gState
.currentWindow
->num
+ 1;
246 /*! Recursively set entries to 0. */
248 __glutDestroyWindow(GlutWindow
*window
, GlutWindow
*initialWindow
)
250 // first, find all children recursively and set their entries to 0
251 GlutWindow
*cur
= window
->children
;
253 GlutWindow
*siblings
= cur
->siblings
;
254 __glutDestroyWindow(cur
, initialWindow
);
258 /* Remove from parent's children list (only necessary for
259 non-initial windows and subwindows!). */
260 GlutWindow
*parent
= window
->parent
;
261 if (parent
&& parent
== initialWindow
->parent
) {
262 GlutWindow
**prev
= &parent
->children
;
263 cur
= parent
->children
;
266 *prev
= cur
->siblings
;
269 prev
= &(cur
->siblings
);
274 // finally, check if we are the current window, and set to 0
275 if (gState
.currentWindow
== window
)
276 gState
.currentWindow
= 0;
278 gState
.windowList
[window
->num
] = 0;
282 /*! Destroy window and all its children. */
284 glutDestroyWindow(int win
)
286 // can't destroy a window if another window has the GL context
287 if (gState
.currentWindow
)
288 gState
.currentWindow
->UnlockGL();
291 GlutWindow
*window
= gState
.windowList
[win
- 1];
292 BWindow
*bwindow
= window
->Window();
295 // if win is the current window, set current window to 0
296 if (gState
.currentWindow
== window
)
297 gState
.currentWindow
= 0;
299 // recursively set child entries to 0
300 __glutDestroyWindow(window
, window
);
302 // try flushing OpenGL
307 // now, if the window was top-level, delete its BWindow
308 if (!window
->parent
) {
311 // else, detach it from the BWindow and delete it
312 window
->RemoveSelf();
317 // relock GL if the current window is still valid
318 if (gState
.currentWindow
)
319 gState
.currentWindow
->LockGL();
323 /*! Destroy all windows when exit() is called this seems to be necessary
324 to avoid delays and crashes when using BDirectWindow.
327 __glutDestroyAllWindows()
329 for (int i
= 0; i
< gState
.windowListSize
; i
++) {
330 if (gState
.windowList
[i
])
331 glutDestroyWindow(i
+ 1);
333 gState
.display
->Lock();
334 gState
.display
->Quit();
335 gState
.display
->Unlock();
338 wait_for_thread(gState
.appthread
, &ignored
);
342 /*! Mark window as needing redisplay */
346 gState
.currentWindow
->Window()->Lock();
347 gState
.currentWindow
->anyevents
= true;
348 gState
.currentWindow
->displayEvent
= true;
349 gState
.currentWindow
->Window()->Unlock();
350 gBlock
.QuickNewEvent();
354 /*! Mark window as needing redisplay */
356 glutPostWindowRedisplay(int win
)
358 GlutWindow
*gwin
= gState
.windowList
[win
- 1];
359 gwin
->Window()->Lock();
360 gwin
->anyevents
= true;
361 gwin
->displayEvent
= true;
362 gwin
->Window()->Unlock();
363 gBlock
.QuickNewEvent();
370 gState
.currentWindow
->SwapBuffers();
376 glutPositionWindow(int x
, int y
)
378 BDirectWindow
*win
= dynamic_cast<BDirectWindow
*>(gState
.currentWindow
->Window());
383 if (gState
.currentWindow
->parent
)
384 gState
.currentWindow
->MoveTo(x
, y
); // move the child view
386 if (win
->IsFullScreen())
387 win
->SetFullScreen(false);
389 win
->MoveTo(x
, y
); // move the window
395 /*! Reshape window (we'll catch the callback when the view gets
399 glutReshapeWindow(int width
, int height
)
401 BDirectWindow
*win
= dynamic_cast<BDirectWindow
*>(gState
.currentWindow
->Window());
406 if (gState
.currentWindow
->parent
) {
408 gState
.currentWindow
->ResizeTo(width
- 1, height
- 1);
410 if (win
->IsFullScreen())
411 win
->SetFullScreen(false);
414 win
->ResizeTo(width
- 1, height
- 1);
420 /*! Makes the window full screen */
424 BDirectWindow
*win
= dynamic_cast<BDirectWindow
*>(gState
.currentWindow
->Window());
429 win
->SetFullScreen(true);
434 /*! Supposed to change the stacking order of the current window
435 NOTE: I can't figure out how to do this for windows,
436 and there is no concept of "stacking order" for
437 subwindows, so these are currently no-ops.
445 /*! Same problem as glutPopWindow() */
455 gState
.currentWindow
->Window()->Lock();
456 if (gState
.currentWindow
->parent
) // subwindow
457 gState
.currentWindow
->Show();
459 if(gState
.currentWindow
->Window()->IsHidden())
460 gState
.currentWindow
->Window()->Show(); // show the actual BWindow
461 gState
.currentWindow
->Window()->Minimize(false);
463 gState
.currentWindow
->Window()->Unlock();
470 gState
.currentWindow
->Window()->Lock();
472 if (gState
.currentWindow
->parent
) // subwindow
473 gState
.currentWindow
->Hide();
475 gState
.currentWindow
->Window()->Hide(); // show the actual BWindow
477 gState
.currentWindow
->Window()->Unlock();
481 /*! Minimizes window */
485 if (gState
.currentWindow
->parent
)
486 __glutFatalError("can't iconify a subwindow");
488 gState
.currentWindow
->Window()->Lock();
489 gState
.currentWindow
->Window()->Minimize(true);
490 gState
.currentWindow
->Window()->Unlock();
494 /*! Sets the window title */
496 glutSetWindowTitle(const char *name
)
498 if (gState
.currentWindow
->parent
)
499 __glutFatalError("glutSetWindowTitle: isn't a top-level window");
501 gState
.currentWindow
->Window()->Lock();
502 gState
.currentWindow
->Window()->SetTitle(name
);
503 gState
.currentWindow
->Window()->Unlock();
507 /*! Same as glutSetWindowTitle() */
509 glutSetIconTitle(const char *name
)
511 glutSetWindowTitle(name
);
515 /*! Converts the current display mode into a BGLView
516 display mode, printing warnings as appropriate.
518 \param options if non-NULL, the current display mode is
520 \return 1 if the current display mode is possible, else 0
523 __glutConvertDisplayMode(unsigned long *options
)
525 if (gState
.displayString
) {
526 /* __glutDisplayString should be NULL except if
527 glutInitDisplayString has been called to register a
528 different display string. Calling glutInitDisplayString
529 means using a string instead of an integer mask determine
530 the visual to use. This big ugly code is in glutDstr.cpp */
531 return __glutConvertDisplayModeFromString(options
);
535 ulong newoptions
= 0;
536 if (gState
.displayMode
& GLUT_ACCUM
)
537 newoptions
|= BGL_ACCUM
;
538 if (gState
.displayMode
& GLUT_ALPHA
)
539 newoptions
|= BGL_ALPHA
;
540 if (gState
.displayMode
& GLUT_DEPTH
)
541 newoptions
|= BGL_DEPTH
;
542 if (gState
.displayMode
& GLUT_DOUBLE
)
543 newoptions
|= BGL_DOUBLE
;
544 if (gState
.displayMode
& GLUT_STENCIL
)
545 newoptions
|= BGL_STENCIL
;
546 *options
= newoptions
;
549 if (gState
.displayMode
& GLUT_INDEX
) {
550 __glutWarning("BeOS doesn't support indexed color");
553 if (gState
.displayMode
& GLUT_MULTISAMPLE
) {
554 return 1; // try to go without multisampling
556 if (gState
.displayMode
& GLUT_STEREO
) {
557 __glutWarning("BeOS doesn't support stereo windows");
560 if (gState
.displayMode
& GLUT_LUMINANCE
) {
561 __glutWarning("BeOS doesn't support luminance color model");
564 return 1; // visual supported
571 /*! Very thin wrapper around BWindow */
572 GlutBWindow::GlutBWindow(BRect frame
, const char *name
)
573 : BDirectWindow(frame
, name
, B_TITLED_WINDOW
, 0)
575 fConnectionDisabled
= false;
577 SetPulseRate(100000);
579 if (!SupportsWindowMode()) {
580 __glutFatalError("video card doesn't support windowed operation");
586 GlutBWindow::DirectConnected(direct_buffer_info
*info
)
591 bgl
->DirectConnected(info
);
592 if (!fConnectionDisabled
)
593 bgl
->EnableDirectMode(true);
596 if ((info
->buffer_state
& B_DIRECT_MODE_MASK
) == B_DIRECT_START
)
599 if (!bgl
->visible
|| info
->buffer_state
== B_DIRECT_STOP
)
600 newVisState
= GLUT_HIDDEN
;
602 if (info
->clip_list_count
== 0)
603 newVisState
= GLUT_FULLY_COVERED
;
604 else if (info
->clip_list_count
== 1)
605 newVisState
= GLUT_FULLY_RETAINED
;
607 newVisState
= GLUT_PARTIALLY_RETAINED
;
610 if (newVisState
!= bgl
->visState
) {
611 bgl
->visState
= newVisState
;
612 bgl
->anyevents
= bgl
->windowStatusEvent
= true;
618 GlutBWindow::~GlutBWindow()
620 fConnectionDisabled
= true;
622 bgl
->EnableDirectMode(false);
632 GlutBWindow::QuitRequested()
634 gState
.quitAll
= true;
637 // don't quit now, wait for main thread to do it
642 GlutBWindow::Minimize(bool minimize
)
644 bgl
->visible
= !minimize
;
645 BWindow::Minimize(minimize
);
653 bgl
->visible
= false;