09fcddfe66b55e1489c55ccc1bd6fcc4f9b2f717
[freeglut] / src / fg_window.c
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  * Change the current window's size
362  */
363 void FGAPIENTRY glutReshapeWindow( int width, int height )
364 {
365     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutReshapeWindow" );
366     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutReshapeWindow" );
367
368     if (glutGet(GLUT_FULL_SCREEN))
369     {
370       /*  Leave full screen state before resizing. */
371       glutLeaveFullScreen();
372     }
373
374     fgStructure.CurrentWindow->State.WorkMask |= GLUT_SIZE_WORK;
375     fgStructure.CurrentWindow->State.DesiredWidth  = width ;
376     fgStructure.CurrentWindow->State.DesiredHeight = height;
377 }
378
379 /*
380  * Change the current window's position
381  */
382 void FGAPIENTRY glutPositionWindow( int x, int y )
383 {
384     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPositionWindow" );
385     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPositionWindow" );
386
387     if (glutGet(GLUT_FULL_SCREEN))
388     {
389       /*  Leave full screen state before moving. */
390       glutLeaveFullScreen();
391     }
392
393     fgStructure.CurrentWindow->State.WorkMask |= GLUT_POSITION_WORK;
394     fgStructure.CurrentWindow->State.DesiredXpos = x;
395     fgStructure.CurrentWindow->State.DesiredYpos = y;
396 }
397
398 /*
399  * Lowers the current window (by Z order change)
400  */
401 void FGAPIENTRY glutPushWindow( void )
402 {
403     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPushWindow" );
404     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPushWindow" );
405
406     fgStructure.CurrentWindow->State.WorkMask |= GLUT_ZORDER_WORK;
407     fgStructure.CurrentWindow->State.DesiredZOrder = -1;
408 }
409
410 /*
411  * Raises the current window (by Z order change)
412  */
413 void FGAPIENTRY glutPopWindow( void )
414 {
415     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPopWindow" );
416     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPopWindow" );
417
418     fgStructure.CurrentWindow->State.WorkMask |= GLUT_ZORDER_WORK;
419     fgStructure.CurrentWindow->State.DesiredZOrder = 1;
420 }
421
422 /*
423  * Resize the current window so that it fits the whole screen
424  */
425 void FGAPIENTRY glutFullScreen( void )
426 {
427     SFG_Window *win;
428
429     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutFullScreen" );
430     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutFullScreen" );
431
432     win = fgStructure.CurrentWindow;
433
434     if (win->Parent)
435     {
436         /* Child windows cannot be made fullscreen, consistent with GLUT's behavior
437          * Also, what would it mean for a child window to be fullscreen, given that it
438          * is confined to its parent?
439          */
440         fgWarning("glutFullScreen called on a child window, ignoring...");
441         return;
442     }
443     else if (fgStructure.GameModeWindow != NULL && fgStructure.GameModeWindow->ID==win->ID && win->State.IsFullscreen)
444     {
445         /* Ignore fullscreen call on GameMode window, those are always fullscreen already
446          * only exception is when first entering GameMode
447          */
448         return;
449     }
450
451     if (!win->State.IsFullscreen)
452         win->State.WorkMask |= GLUT_FULL_SCREEN_WORK;
453 }
454
455 /*
456  * If we are fullscreen, resize the current window back to its original size
457  */
458 void FGAPIENTRY glutLeaveFullScreen( void )
459 {
460     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutFullScreen" );
461     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutFullScreen" );
462
463     if (fgStructure.CurrentWindow->State.IsFullscreen)
464         fgStructure.CurrentWindow->State.WorkMask |= GLUT_FULL_SCREEN_WORK;
465 }
466
467 /*
468  * Toggle the window's full screen state.
469  */
470 void FGAPIENTRY glutFullScreenToggle( void )
471 {
472     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutFullScreenToggle" );
473     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutFullScreenToggle" );
474
475     fgStructure.CurrentWindow->State.WorkMask |= GLUT_FULL_SCREEN_WORK;
476 }
477
478 /*
479  * A.Donev: Set and retrieve the window's user data
480  */
481 void* FGAPIENTRY glutGetWindowData( void )
482 {
483     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutGetWindowData" );
484     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutGetWindowData" );
485     return fgStructure.CurrentWindow->UserData;
486 }
487
488 void FGAPIENTRY glutSetWindowData(void* data)
489 {
490     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetWindowData" );
491     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetWindowData" );
492     fgStructure.CurrentWindow->UserData = data;
493 }
494
495 /*** END OF FILE ***/