1 | /* |
2 | * fg_window.c |
3 | * |
4 | * Window management methods. |
5 | * |
6 | * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. |
7 | * Written by Pawel W. Olszta, <olszta@sourceforge.net> |
8 | * Creation date: Fri Dec 3 1999 |
9 | * |
10 | * Permission is hereby granted, free of charge, to any person obtaining a |
11 | * copy of this software and associated documentation files (the "Software"), |
12 | * to deal in the Software without restriction, including without limitation |
13 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
14 | * and/or sell copies of the Software, and to permit persons to whom the |
15 | * Software is furnished to do so, subject to the following conditions: |
16 | * |
17 | * The above copyright notice and this permission notice shall be included |
18 | * in all copies or substantial portions of the Software. |
19 | * |
20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
21 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
23 | * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER |
24 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
25 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
26 | */ |
27 | |
28 | #define FREEGLUT_BUILDING_LIB |
29 | #include <GL/freeglut.h> |
30 | #include "fg_internal.h" |
31 | #include "fg_gl2.h" |
32 | |
33 | /* |
34 | * TODO BEFORE THE STABLE RELEASE: |
35 | * |
36 | * fgSetupPixelFormat -- ignores the display mode settings |
37 | * fgOpenWindow() -- check the Win32 version, -iconic handling! |
38 | * fgCloseWindow() -- check the Win32 version |
39 | * glutCreateWindow() -- Check when default position and size is {-1,-1} |
40 | * glutCreateSubWindow() -- Check when default position and size is {-1,-1} |
41 | * glutDestroyWindow() -- check the Win32 version |
42 | * glutSetWindow() -- check the Win32 version |
43 | * glutSetWindowTitle() -- check the Win32 version |
44 | * glutSetIconTitle() -- check the Win32 version |
45 | * glutShowWindow() -- check the Win32 version |
46 | * glutHideWindow() -- check the Win32 version |
47 | * glutIconifyWindow() -- check the Win32 version |
48 | * glutPushWindow() -- check the Win32 version |
49 | * glutPopWindow() -- check the Win32 version |
50 | */ |
51 | |
52 | |
53 | extern void fgPlatformSetWindow ( SFG_Window *window ); |
54 | extern void fgPlatformOpenWindow( SFG_Window* window, const char* title, |
55 | GLboolean positionUse, int x, int y, |
56 | GLboolean sizeUse, int w, int h, |
57 | GLboolean gameMode, GLboolean isSubWindow ); |
58 | extern void fgPlatformCloseWindow( SFG_Window* window ); |
59 | extern void fgPlatformGlutSetWindowTitle( const char* title ); |
60 | extern void fgPlatformGlutSetIconTitle( const char* title ); |
61 | |
62 | |
63 | /* -- PRIVATE FUNCTIONS ---------------------------------------------------- */ |
64 | |
65 | int fghIsLegacyContextRequested( void ) |
66 | { |
67 | return fgState.MajorVersion < 2 || (fgState.MajorVersion == 2 && fgState.MinorVersion <= 1); |
68 | } |
69 | |
70 | int fghNumberOfAuxBuffersRequested( void ) |
71 | { |
72 | if ( fgState.DisplayMode & GLUT_AUX4 ) { |
73 | return 4; |
74 | } |
75 | if ( fgState.DisplayMode & GLUT_AUX3 ) { |
76 | return 3; |
77 | } |
78 | if ( fgState.DisplayMode & GLUT_AUX2 ) { |
79 | return 2; |
80 | } |
81 | if ( fgState.DisplayMode & GLUT_AUX1 ) { /* NOTE: Same as GLUT_AUX! */ |
82 | return fgState.AuxiliaryBufferNumber; |
83 | } |
84 | return 0; |
85 | } |
86 | |
87 | int fghMapBit( int mask, int from, int to ) |
88 | { |
89 | return ( mask & from ) ? to : 0; |
90 | |
91 | } |
92 | |
93 | void fghContextCreationError( void ) |
94 | { |
95 | fgError( "Unable to create OpenGL %d.%d context (flags %x, profile %x)" , |
96 | fgState.MajorVersion, fgState.MinorVersion, fgState.ContextFlags, |
97 | fgState.ContextProfile ); |
98 | } |
99 | |
100 | |
101 | /* -- SYSTEM-DEPENDENT PRIVATE FUNCTIONS ------------------------------------ */ |
102 | |
103 | /* |
104 | * Sets the OpenGL context and the fgStructure "Current Window" pointer to |
105 | * the window structure passed in. |
106 | */ |
107 | void fgSetWindow ( SFG_Window *window ) |
108 | { |
109 | fgPlatformSetWindow ( window ); |
110 | |
111 | fgStructure.CurrentWindow = window; |
112 | } |
113 | |
114 | /* |
115 | * Opens a window. Requires a SFG_Window object created and attached |
116 | * to the freeglut structure. OpenGL context is created here. |
117 | */ |
118 | void fgOpenWindow( SFG_Window* window, const char* title, |
119 | GLboolean positionUse, int x, int y, |
120 | GLboolean sizeUse, int w, int h, |
121 | GLboolean gameMode, GLboolean isSubWindow ) |
122 | { |
123 | fgPlatformOpenWindow( window, title, |
124 | positionUse, x, y, |
125 | sizeUse, w, h, |
126 | gameMode, isSubWindow ); |
127 | |
128 | fgSetWindow( window ); |
129 | |
130 | #ifndef EGL_VERSION_1_0 |
131 | window->Window.DoubleBuffered = |
132 | ( fgState.DisplayMode & GLUT_DOUBLE ) ? 1 : 0; |
133 | |
134 | if ( ! window->Window.DoubleBuffered ) |
135 | { |
136 | glDrawBuffer ( GL_FRONT ); |
137 | glReadBuffer ( GL_FRONT ); |
138 | } |
139 | #else |
140 | /* - EGL is always double-buffered */ |
141 | /* - No glDrawBuffer/glReadBuffer in GLES */ |
142 | window->Window.DoubleBuffered = 1; |
143 | #endif |
144 | window->Window.attribute_v_coord = -1; |
145 | window->Window.attribute_v_normal = -1; |
146 | window->Window.attribute_v_texture = -1; |
147 | |
148 | fgInitGL2(); |
149 | |
150 | window->State.WorkMask |= GLUT_INIT_WORK; |
151 | } |
152 | |
153 | /* |
154 | * Closes a window, destroying the frame and OpenGL context |
155 | */ |
156 | void fgCloseWindow( SFG_Window* window ) |
157 | { |
158 | /* if we're in gamemode and we're closing the gamemode window, |
159 | * call glutLeaveGameMode first to make sure the gamemode is |
160 | * properly closed before closing the window |
161 | */ |
162 | if (fgStructure.GameModeWindow != NULL && fgStructure.GameModeWindow->ID==window->ID) |
163 | glutLeaveGameMode(); |
164 | |
165 | fgPlatformCloseWindow ( window ); |
166 | } |
167 | |
168 | |
169 | /* -- INTERFACE FUNCTIONS -------------------------------------------------- */ |
170 | |
171 | /* |
172 | * Creates a new top-level freeglut window |
173 | */ |
174 | int FGAPIENTRY glutCreateWindow( const char* title ) |
175 | { |
176 | /* XXX GLUT does not exit; it simply calls "glutInit" quietly if the |
177 | * XXX application has not already done so. The "freeglut" community |
178 | * XXX decided not to go this route (freeglut-developer e-mail from |
179 | * XXX Steve Baker, 12/16/04, 4:22 PM CST, "Re: [Freeglut-developer] |
180 | * XXX Desired 'freeglut' behaviour when there is no current window" |
181 | */ |
182 | FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutCreateWindow" ); |
183 | |
184 | return fgCreateWindow( NULL, title, fgState.Position.Use, |
185 | fgState.Position.X, fgState.Position.Y, |
186 | fgState.Size.Use, fgState.Size.X, fgState.Size.Y, |
187 | GL_FALSE, GL_FALSE )->ID; |
188 | } |
189 | |
190 | /* |
191 | * This function creates a sub window. |
192 | */ |
193 | int FGAPIENTRY glutCreateSubWindow( int parentID, int x, int y, int w, int h ) |
194 | { |
195 | int ret = 0; |
196 | SFG_Window* window = NULL; |
197 | SFG_Window* parent = NULL; |
198 | |
199 | FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutCreateSubWindow" ); |
200 | parent = fgWindowByID( parentID ); |
201 | freeglut_return_val_if_fail( parent != NULL, 0 ); |
202 | if ( x < 0 ) |
203 | { |
204 | x = parent->State.Width + x ; |
205 | if ( w >= 0 ) x -= w ; |
206 | } |
207 | |
208 | if ( w < 0 ) w = parent->State.Width - x + w ; |
209 | if ( w < 0 ) |
210 | { |
211 | x += w ; |
212 | w = -w ; |
213 | } |
214 | |
215 | if ( y < 0 ) |
216 | { |
217 | y = parent->State.Height + y ; |
218 | if ( h >= 0 ) y -= h ; |
219 | } |
220 | |
221 | if ( h < 0 ) h = parent->State.Height - y + h ; |
222 | if ( h < 0 ) |
223 | { |
224 | y += h ; |
225 | h = -h ; |
226 | } |
227 | |
228 | window = fgCreateWindow( parent, "" , GL_TRUE, x, y, GL_TRUE, w, h, GL_FALSE, GL_FALSE ); |
229 | ret = window->ID; |
230 | |
231 | return ret; |
232 | } |
233 | |
234 | /* |
235 | * Destroys a window and all of its subwindows |
236 | */ |
237 | void FGAPIENTRY glutDestroyWindow( int windowID ) |
238 | { |
239 | SFG_Window* window; |
240 | FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutDestroyWindow" ); |
241 | window = fgWindowByID( windowID ); |
242 | freeglut_return_if_fail( window != NULL ); |
243 | { |
244 | fgExecutionState ExecState = fgState.ExecState; |
245 | fgAddToWindowDestroyList( window ); |
246 | fgState.ExecState = ExecState; |
247 | } |
248 | } |
249 | |
250 | /* |
251 | * This function selects the specified window as the current window |
252 | */ |
253 | void FGAPIENTRY glutSetWindow( int ID ) |
254 | { |
255 | SFG_Window* window = NULL; |
256 | |
257 | FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetWindow" ); |
258 | if( fgStructure.CurrentWindow != NULL ) |
259 | if( fgStructure.CurrentWindow->ID == ID ) |
260 | return; |
261 | |
262 | window = fgWindowByID( ID ); |
263 | if( window == NULL ) |
264 | { |
265 | fgWarning( "glutSetWindow(): window ID %d not found!" , ID ); |
266 | return; |
267 | } |
268 | |
269 | fgSetWindow( window ); |
270 | } |
271 | |
272 | /* |
273 | * This function returns the ID number of the current window, 0 if none exists |
274 | */ |
275 | int FGAPIENTRY glutGetWindow( void ) |
276 | { |
277 | SFG_Window *win = fgStructure.CurrentWindow; |
278 | /* |
279 | * Since GLUT did not throw an error if this function was called without a prior call to |
280 | * "glutInit", this function shouldn't do so here. Instead let us return a zero. |
281 | * See Feature Request "[ 1307049 ] glutInit check". |
282 | */ |
283 | if ( ! fgState.Initialised ) |
284 | return 0; |
285 | |
286 | while ( win && win->IsMenu ) |
287 | win = win->Parent; |
288 | return win ? win->ID : 0; |
289 | } |
290 | |
291 | /* |
292 | * This function makes the current window visible |
293 | */ |
294 | void FGAPIENTRY glutShowWindow( void ) |
295 | { |
296 | FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutShowWindow" ); |
297 | FREEGLUT_EXIT_IF_NO_WINDOW ( "glutShowWindow" ); |
298 | |
299 | fgStructure.CurrentWindow->State.WorkMask |= GLUT_VISIBILITY_WORK; |
300 | fgStructure.CurrentWindow->State.DesiredVisibility = DesireNormalState; |
301 | |
302 | fgStructure.CurrentWindow->State.WorkMask |= GLUT_DISPLAY_WORK; |
303 | } |
304 | |
305 | /* |
306 | * This function hides the current window |
307 | */ |
308 | void FGAPIENTRY glutHideWindow( void ) |
309 | { |
310 | FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutHideWindow" ); |
311 | FREEGLUT_EXIT_IF_NO_WINDOW ( "glutHideWindow" ); |
312 | |
313 | fgStructure.CurrentWindow->State.WorkMask |= GLUT_VISIBILITY_WORK; |
314 | fgStructure.CurrentWindow->State.DesiredVisibility = DesireHiddenState; |
315 | |
316 | fgStructure.CurrentWindow->State.WorkMask &= ~GLUT_DISPLAY_WORK; |
317 | } |
318 | |
319 | /* |
320 | * Iconify the current window (top-level windows only) |
321 | */ |
322 | void FGAPIENTRY glutIconifyWindow( void ) |
323 | { |
324 | FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutIconifyWindow" ); |
325 | FREEGLUT_EXIT_IF_NO_WINDOW ( "glutIconifyWindow" ); |
326 | |
327 | fgStructure.CurrentWindow->State.WorkMask |= GLUT_VISIBILITY_WORK; |
328 | fgStructure.CurrentWindow->State.DesiredVisibility = DesireIconicState; |
329 | |
330 | fgStructure.CurrentWindow->State.WorkMask &= ~GLUT_DISPLAY_WORK; |
331 | } |
332 | |
333 | /* |
334 | * Set the current window's title |
335 | */ |
336 | void FGAPIENTRY glutSetWindowTitle( const char* title ) |
337 | { |
338 | FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetWindowTitle" ); |
339 | FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetWindowTitle" ); |
340 | if( ! fgStructure.CurrentWindow->Parent ) |
341 | { |
342 | fgPlatformGlutSetWindowTitle ( title ); |
343 | } |
344 | } |
345 | |
346 | /* |
347 | * Set the current window's iconified title |
348 | */ |
349 | void FGAPIENTRY glutSetIconTitle( const char* title ) |
350 | { |
351 | FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetIconTitle" ); |
352 | FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetIconTitle" ); |
353 | |
354 | if( ! fgStructure.CurrentWindow->Parent ) |
355 | { |
356 | fgPlatformGlutSetIconTitle ( title ); |
357 | } |
358 | } |
359 | |
360 | /* |
361 | * This function sets the clipboard content to the UTF-8 encoded text. |
362 | */ |
363 | void FGAPIENTRY glutSetClipboard(int selection, const char *text) |
364 | { |
365 | FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetClipboard" ); |
366 | FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetClipboard" ); |
367 | |
368 | fgPlatformSetClipboard(selection, text); |
369 | } |
370 | |
371 | /* |
372 | * This function returns the clipboard content as UTF-8 encoded text, |
373 | * or NULL if no content was available. |
374 | */ |
375 | const char* FGAPIENTRY glutGetClipboard(int selection) |
376 | { |
377 | FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutGetClipboard" ); |
378 | FREEGLUT_EXIT_IF_NO_WINDOW ( "glutGetClipboard" ); |
379 | |
380 | return fgPlatformGetClipboard(selection); |
381 | } |
382 | |
383 | /* |
384 | * Change the current window's size |
385 | */ |
386 | void FGAPIENTRY glutReshapeWindow( int width, int height ) |
387 | { |
388 | FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutReshapeWindow" ); |
389 | FREEGLUT_EXIT_IF_NO_WINDOW ( "glutReshapeWindow" ); |
390 | |
391 | if (glutGet(GLUT_FULL_SCREEN)) |
392 | { |
393 | /* Leave full screen state before resizing. */ |
394 | glutLeaveFullScreen(); |
395 | } |
396 | |
397 | fgStructure.CurrentWindow->State.WorkMask |= GLUT_SIZE_WORK; |
398 | fgStructure.CurrentWindow->State.DesiredWidth = width ; |
399 | fgStructure.CurrentWindow->State.DesiredHeight = height; |
400 | } |
401 | |
402 | /* |
403 | * Change the current window's position |
404 | */ |
405 | void FGAPIENTRY glutPositionWindow( int x, int y ) |
406 | { |
407 | FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPositionWindow" ); |
408 | FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPositionWindow" ); |
409 | |
410 | if (glutGet(GLUT_FULL_SCREEN)) |
411 | { |
412 | /* Leave full screen state before moving. */ |
413 | glutLeaveFullScreen(); |
414 | } |
415 | |
416 | fgStructure.CurrentWindow->State.WorkMask |= GLUT_POSITION_WORK; |
417 | fgStructure.CurrentWindow->State.DesiredXpos = x; |
418 | fgStructure.CurrentWindow->State.DesiredYpos = y; |
419 | } |
420 | |
421 | /* |
422 | * Lowers the current window (by Z order change) |
423 | */ |
424 | void FGAPIENTRY glutPushWindow( void ) |
425 | { |
426 | FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPushWindow" ); |
427 | FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPushWindow" ); |
428 | |
429 | fgStructure.CurrentWindow->State.WorkMask |= GLUT_ZORDER_WORK; |
430 | fgStructure.CurrentWindow->State.DesiredZOrder = -1; |
431 | } |
432 | |
433 | /* |
434 | * Raises the current window (by Z order change) |
435 | */ |
436 | void FGAPIENTRY glutPopWindow( void ) |
437 | { |
438 | FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPopWindow" ); |
439 | FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPopWindow" ); |
440 | |
441 | fgStructure.CurrentWindow->State.WorkMask |= GLUT_ZORDER_WORK; |
442 | fgStructure.CurrentWindow->State.DesiredZOrder = 1; |
443 | } |
444 | |
445 | /* |
446 | * Resize the current window so that it fits the whole screen |
447 | */ |
448 | void FGAPIENTRY glutFullScreen( void ) |
449 | { |
450 | SFG_Window *win; |
451 | |
452 | FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutFullScreen" ); |
453 | FREEGLUT_EXIT_IF_NO_WINDOW ( "glutFullScreen" ); |
454 | |
455 | win = fgStructure.CurrentWindow; |
456 | |
457 | if (win->Parent) |
458 | { |
459 | /* Child windows cannot be made fullscreen, consistent with GLUT's behavior |
460 | * Also, what would it mean for a child window to be fullscreen, given that it |
461 | * is confined to its parent? |
462 | */ |
463 | fgWarning("glutFullScreen called on a child window, ignoring..." ); |
464 | return; |
465 | } |
466 | else if (fgStructure.GameModeWindow != NULL && fgStructure.GameModeWindow->ID==win->ID && win->State.IsFullscreen) |
467 | { |
468 | /* Ignore fullscreen call on GameMode window, those are always fullscreen already |
469 | * only exception is when first entering GameMode |
470 | */ |
471 | return; |
472 | } |
473 | |
474 | if (!win->State.IsFullscreen) |
475 | win->State.WorkMask |= GLUT_FULL_SCREEN_WORK; |
476 | } |
477 | |
478 | /* |
479 | * If we are fullscreen, resize the current window back to its original size |
480 | */ |
481 | void FGAPIENTRY glutLeaveFullScreen( void ) |
482 | { |
483 | FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutFullScreen" ); |
484 | FREEGLUT_EXIT_IF_NO_WINDOW ( "glutFullScreen" ); |
485 | |
486 | if (fgStructure.CurrentWindow->State.IsFullscreen) |
487 | fgStructure.CurrentWindow->State.WorkMask |= GLUT_FULL_SCREEN_WORK; |
488 | } |
489 | |
490 | /* |
491 | * Toggle the window's full screen state. |
492 | */ |
493 | void FGAPIENTRY glutFullScreenToggle( void ) |
494 | { |
495 | FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutFullScreenToggle" ); |
496 | FREEGLUT_EXIT_IF_NO_WINDOW ( "glutFullScreenToggle" ); |
497 | |
498 | fgStructure.CurrentWindow->State.WorkMask |= GLUT_FULL_SCREEN_WORK; |
499 | } |
500 | |
501 | /* |
502 | * A.Donev: Set and retrieve the window's user data |
503 | */ |
504 | void* FGAPIENTRY glutGetWindowData( void ) |
505 | { |
506 | FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutGetWindowData" ); |
507 | FREEGLUT_EXIT_IF_NO_WINDOW ( "glutGetWindowData" ); |
508 | return fgStructure.CurrentWindow->UserData; |
509 | } |
510 | |
511 | void FGAPIENTRY glutSetWindowData(void* data) |
512 | { |
513 | FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetWindowData" ); |
514 | FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetWindowData" ); |
515 | fgStructure.CurrentWindow->UserData = data; |
516 | } |
517 | |
518 | /*** END OF FILE ***/ |
519 | |