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