BTRFS: Reimplement TreeIterator, add some error checks and remove redundancies.
[haiku.git] / src / libs / glut / glutWindow.cpp
blob0f47402f49b4bd52007a42f9c2aaa3b231e88426
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 ***********************************************************/
11 #include <stdlib.h>
13 #include <GL/glut.h>
15 #include "glutint.h"
16 #include "glutState.h"
17 #include "glutBlocker.h"
20 /*! Helper function to get a new window slot */
21 static int
22 getUnusedWindowSlot()
24 int i;
26 /* Look for allocated, unused slot. */
27 for (i = 0; i < gState.windowListSize; i++) {
28 if (!gState.windowList[i])
29 return 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 */
45 static void
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 "
50 "code.");
51 __glutFatalError("redisplay needed for window %d, but no display callback.",
52 gState.currentWindow->num + 1);
56 /*! Default reshape function */
57 void
58 __glutDefaultReshape(int width, int height)
60 /* Adjust the viewport of the window */
61 glViewport(0, 0, (GLsizei) width, (GLsizei) height);
65 // #pragma mark -
68 /*! Creates a new GLUT window
69 Note: subwindows don't resize, but top-level windows
70 follow all sides.
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,
78 options)
80 // add myself to window list
81 num = getUnusedWindowSlot();
82 gState.windowList[num] = this;
84 // set up parent/children relationships
85 parent = nparent;
86 if (parent) {
87 siblings = parent->children;
88 parent->children = this;
89 } else {
90 siblings = 0;
92 children = 0;
94 // initialize variables
95 cursor = GLUT_CURSOR_INHERIT; // default cursor
96 for (int i = 0; i < GLUT_MAX_MENUS; i++) {
97 menu[i] = 0;
99 m_width = width;
100 m_height = height;
101 m_buttons = 0;
103 // clear callbacks
104 display = __glutDefaultDisplay;
105 reshape = __glutDefaultReshape;
106 mouse = NULL;
107 motion = NULL;
108 passive = NULL;
109 entry = NULL;
110 keyboard = NULL;
111 keyboardUp = NULL;
112 visibility = NULL;
113 special = NULL;
114 specialUp = NULL;
115 windowStatus = NULL;
117 // clear event counters
118 anyevents = 1;
119 displayEvent = 1; // get a reshape and a display event right away
120 reshapeEvent = 1;
121 mouseEvent = 0;
122 motionEvent = 0;
123 passiveEvent = 0;
124 entryEvent = 0;
125 keybEvent = 0;
126 keybUpEvent = 0;
127 windowStatusEvent = 0; // DirectConnected() will report change in
128 visState = -1; // visibility
129 specialEvent = 0;
130 specialUpEvent = 0;
131 statusEvent = 0;
132 menuEvent = 0;
133 visible = true;
134 ignoreKeyRepeat = (gState.keyRepeatMode == GLUT_KEY_REPEAT_OFF);
136 gBlock.QuickNewEvent();
138 // if i'm a subwindow, add me to my parent view
139 if (parent) {
140 parent->Window()->Lock();
141 parent->AddChild(this);
142 parent->Window()->Unlock();
143 } else {
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;
149 mybwindow->Show();
152 // give me the keyboard focus (focus follows mouse, X style, as
153 // implemented in GlutWindow::MouseMoved())
154 Window()->Lock();
155 MakeFocus();
156 Window()->Unlock();
158 // make myself the default window
159 __glutSetWindow(this);
163 /*! Creates a new GLUT window */
165 glutCreateWindow(const char *name)
167 if (!be_app)
168 __glutInit();
170 ulong options;
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)
193 ulong options;
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) */
206 void
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 */
217 void
218 glutSetWindow(int win)
220 GlutWindow *window;
222 if (win < 1 || win > gState.windowListSize) {
223 __glutWarning("glutSetWindow attempted on bogus window.");
224 return;
227 window = gState.windowList[win - 1];
228 if (!window) {
229 __glutWarning("glutSetWindow attempted on bogus window.");
230 return;
232 __glutSetWindow(window);
237 glutGetWindow()
239 if (gState.currentWindow)
240 return gState.currentWindow->num + 1;
242 return 0;
246 /*! Recursively set entries to 0. */
247 static void
248 __glutDestroyWindow(GlutWindow *window, GlutWindow *initialWindow)
250 // first, find all children recursively and set their entries to 0
251 GlutWindow *cur = window->children;
252 while (cur) {
253 GlutWindow *siblings = cur->siblings;
254 __glutDestroyWindow(cur, initialWindow);
255 cur = siblings;
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;
264 while (cur) {
265 if (cur == window) {
266 *prev = cur->siblings;
267 break;
269 prev = &(cur->siblings);
270 cur = 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. */
283 void
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();
290 // lock the window
291 GlutWindow *window = gState.windowList[win - 1];
292 BWindow *bwindow = window->Window();
293 bwindow->Lock();
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
303 window->LockGL();
304 glFlush();
305 window->UnlockGL();
307 // now, if the window was top-level, delete its BWindow
308 if (!window->parent) {
309 bwindow->Quit();
310 } else {
311 // else, detach it from the BWindow and delete it
312 window->RemoveSelf();
313 delete window;
314 bwindow->Unlock();
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.
326 void
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();
337 status_t ignored;
338 wait_for_thread(gState.appthread, &ignored);
342 /*! Mark window as needing redisplay */
343 void
344 glutPostRedisplay()
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 */
355 void
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();
367 void
368 glutSwapBuffers()
370 gState.currentWindow->SwapBuffers();
374 /*! Move window */
375 void
376 glutPositionWindow(int x, int y)
378 BDirectWindow *win = dynamic_cast<BDirectWindow*>(gState.currentWindow->Window());
379 if (win == NULL)
380 return;
382 win->Lock();
383 if (gState.currentWindow->parent)
384 gState.currentWindow->MoveTo(x, y); // move the child view
385 else {
386 if (win->IsFullScreen())
387 win->SetFullScreen(false);
389 win->MoveTo(x, y); // move the window
391 win->Unlock();
395 /*! Reshape window (we'll catch the callback when the view gets
396 a Draw() message).
398 void
399 glutReshapeWindow(int width, int height)
401 BDirectWindow *win = dynamic_cast<BDirectWindow*>(gState.currentWindow->Window());
402 if (win == NULL)
403 return;
405 win->Lock();
406 if (gState.currentWindow->parent) {
407 // resize the child
408 gState.currentWindow->ResizeTo(width - 1, height - 1);
409 } else {
410 if (win->IsFullScreen())
411 win->SetFullScreen(false);
413 // resize the parent
414 win->ResizeTo(width - 1, height - 1);
416 win->Unlock();
420 /*! Makes the window full screen */
421 void
422 glutFullScreen()
424 BDirectWindow *win = dynamic_cast<BDirectWindow*>(gState.currentWindow->Window());
425 if (win == NULL)
426 return;
428 win->Lock();
429 win->SetFullScreen(true);
430 win->Unlock();
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.
439 void
440 glutPopWindow()
445 /*! Same problem as glutPopWindow() */
446 void
447 glutPushWindow()
452 void
453 glutShowWindow()
455 gState.currentWindow->Window()->Lock();
456 if (gState.currentWindow->parent) // subwindow
457 gState.currentWindow->Show();
458 else {
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();
467 void
468 glutHideWindow()
470 gState.currentWindow->Window()->Lock();
472 if (gState.currentWindow->parent) // subwindow
473 gState.currentWindow->Hide();
474 else
475 gState.currentWindow->Window()->Hide(); // show the actual BWindow
477 gState.currentWindow->Window()->Unlock();
481 /*! Minimizes window */
482 void
483 glutIconifyWindow()
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 */
495 void
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() */
508 void
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
519 returned in it.
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);
534 if (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");
551 return 0;
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");
558 return 0;
560 if (gState.displayMode & GLUT_LUMINANCE) {
561 __glutWarning("BeOS doesn't support luminance color model");
562 return 0;
564 return 1; // visual supported
568 // #pragma mark -
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;
576 bgl = 0;
577 SetPulseRate(100000);
579 if (!SupportsWindowMode()) {
580 __glutFatalError("video card doesn't support windowed operation");
585 void
586 GlutBWindow::DirectConnected(direct_buffer_info *info)
588 if (!bgl)
589 return;
591 bgl->DirectConnected(info);
592 if (!fConnectionDisabled)
593 bgl->EnableDirectMode(true);
595 int newVisState;
596 if ((info->buffer_state & B_DIRECT_MODE_MASK) == B_DIRECT_START)
597 bgl->visible = true;
599 if (!bgl->visible || info->buffer_state == B_DIRECT_STOP)
600 newVisState = GLUT_HIDDEN;
601 else {
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;
606 else
607 newVisState = GLUT_PARTIALLY_RETAINED;
610 if (newVisState != bgl->visState) {
611 bgl->visState = newVisState;
612 bgl->anyevents = bgl->windowStatusEvent = true;
613 gBlock.NewEvent();
618 GlutBWindow::~GlutBWindow()
620 fConnectionDisabled = true;
621 if (bgl)
622 bgl->EnableDirectMode(false);
624 if (!IsHidden())
625 Hide();
627 Sync();
631 bool
632 GlutBWindow::QuitRequested()
634 gState.quitAll = true;
635 gBlock.NewEvent();
636 return false;
637 // don't quit now, wait for main thread to do it
641 void
642 GlutBWindow::Minimize(bool minimize)
644 bgl->visible = !minimize;
645 BWindow::Minimize(minimize);
649 void
650 GlutBWindow::Hide()
652 BWindow::Hide();
653 bgl->visible = false;
657 void
658 GlutBWindow::Show()
660 BWindow::Show();
661 bgl->visible = true;