66ea2a00a83ee601c262e56116d301e6d854b3b8
[mesa.git] / src / glut / beos / glutWindow.cpp
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 ***********************************************************/
28 static int
29 getUnusedWindowSlot()
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 ***********************************************************/
57 static 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
67 void
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 ***********************************************************/
83 GlutWindow::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 ***********************************************************/
173 int 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 ***********************************************************/
199 int 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 ***********************************************************/
216 void
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 ***********************************************************/
231 void 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
246 int 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 ***********************************************************/
259 static 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 ***********************************************************/
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();
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 ***********************************************************/
341 void __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 ***********************************************************/
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();
364 }
365
366 /***********************************************************
367 * FUNCTION: glutPostWindowRedisplay
368 *
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();
378 }
379
380 /***********************************************************
381 * FUNCTION: glutSwapBuffers (4.6)
382 *
383 * DESCRIPTION: swap buffers
384 ***********************************************************/
385 void glutSwapBuffers() {
386 gState.currentWindow->SwapBuffers();
387 }
388
389 /***********************************************************
390 * FUNCTION: glutPositionWindow (4.7)
391 *
392 * DESCRIPTION: move window
393 ***********************************************************/
394 void 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 ***********************************************************/
414 void 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 ***********************************************************/
433 void 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 ***********************************************************/
449 void glutPopWindow() { }
450 void glutPushWindow() { }
451
452 /***********************************************************
453 * FUNCTION: glutShowWindow (4.11)
454 * glutHideWindow
455 * glutIconifyWindow
456 *
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();
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
471 void 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
480 void 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 ***********************************************************/
495 void 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
504 void 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 ***********************************************************/
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);
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 ***********************************************************/
567 GlutBWindow::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
578 void 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
604 GlutBWindow::~GlutBWindow() {
605 fConnectionDisabled = true;
606 if(bgl) {
607 bgl->EnableDirectMode(false);
608 }
609 if(!IsHidden())
610 Hide();
611 Sync();
612 }
613
614 bool 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
620 void GlutBWindow::Minimize(bool minimize) {
621 bgl->visible = !minimize;
622 BWindow::Minimize(minimize);
623 }
624
625 void GlutBWindow::Hide() {
626 BWindow::Hide();
627 bgl->visible = false;
628 }
629
630 void GlutBWindow::Show() {
631 BWindow::Show();
632 bgl->visible = true;
633 }