366bbf31120ccfb8565911991452dfe8c9c62636
[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, 
185                            fgState.Position.Use, 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
203     if ( fgState.AllowNegativeWindowPosition )
204     {
205         /* XXX This results in different widths/heights than if AllowNegativeWindowPosition
206          * XXX was false. The "freeglut" community defined this logic.
207          * XXX (freeglut-developer e-mail from Diederick C. Niehorster, 11/15/2015, 4:06 PM EST.
208          * XXX "Re: [Freeglut-developer] glutInitWindowPosition with negative coordinate(s)")
209          */
210
211         if ( w < 0 ) w = parent->State.Width + w ;
212         if ( h < 0 ) h = parent->State.Height + h ;
213     }
214     else
215     {
216         if ( ( x < 0 ) )
217         {
218             x = parent->State.Width + x ;
219             if ( w > 0 ) x -= w ;
220         }
221
222         if ( w < 0 ) w = parent->State.Width - x + w ;
223         if ( w < 0 )
224         {
225             x += w ;
226             w = -w ;
227         }
228
229         if ( ( y < 0 ) )
230         {
231             y = parent->State.Height + y ;
232             if ( h > 0 ) y -= h ;
233         }
234
235         if ( h < 0 ) h = parent->State.Height - y + h ;
236         if ( h < 0 )
237         {
238             y += h ;
239             h = -h ;
240         }
241     }
242
243     window = fgCreateWindow( parent, "", 
244                              GL_TRUE, x, y, 
245                              GL_TRUE, w, h, 
246                              GL_FALSE, GL_FALSE );
247     ret = window->ID;
248
249     return ret;
250 }
251
252 /*
253  * Destroys a window and all of its subwindows
254  */
255 void FGAPIENTRY glutDestroyWindow( int windowID )
256 {
257     SFG_Window* window;
258     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutDestroyWindow" );
259     window = fgWindowByID( windowID );
260     freeglut_return_if_fail( window != NULL );
261     {
262         fgExecutionState ExecState = fgState.ExecState;
263         fgAddToWindowDestroyList( window );
264         fgState.ExecState = ExecState;
265     }
266 }
267
268 /*
269  * This function selects the specified window as the current window
270  */
271 void FGAPIENTRY glutSetWindow( int ID )
272 {
273     SFG_Window* window = NULL;
274
275     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetWindow" );
276     if( fgStructure.CurrentWindow != NULL )
277         if( fgStructure.CurrentWindow->ID == ID )
278             return;
279
280     window = fgWindowByID( ID );
281     if( window == NULL )
282     {
283         fgWarning( "glutSetWindow(): window ID %d not found!", ID );
284         return;
285     }
286
287     fgSetWindow( window );
288 }
289
290 /*
291  * This function returns the ID number of the current window, 0 if none exists
292  */
293 int FGAPIENTRY glutGetWindow( void )
294 {
295     SFG_Window *win = fgStructure.CurrentWindow;
296     /*
297      * Since GLUT did not throw an error if this function was called without a prior call to
298      * "glutInit", this function shouldn't do so here.  Instead let us return a zero.
299      * See Feature Request "[ 1307049 ] glutInit check".
300      */
301     if ( ! fgState.Initialised )
302         return 0;
303
304     while ( win && win->IsMenu )
305         win = win->Parent;
306     return win ? win->ID : 0;
307 }
308
309 /*
310  * This function makes the current window visible
311  */
312 void FGAPIENTRY glutShowWindow( void )
313 {
314     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutShowWindow" );
315     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutShowWindow" );
316
317     fgStructure.CurrentWindow->State.WorkMask |= GLUT_VISIBILITY_WORK;
318     fgStructure.CurrentWindow->State.DesiredVisibility = DesireNormalState;
319
320     fgStructure.CurrentWindow->State.WorkMask |= GLUT_DISPLAY_WORK;
321 }
322
323 /*
324  * This function hides the current window
325  */
326 void FGAPIENTRY glutHideWindow( void )
327 {
328     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutHideWindow" );
329     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutHideWindow" );
330
331     fgStructure.CurrentWindow->State.WorkMask |= GLUT_VISIBILITY_WORK;
332     fgStructure.CurrentWindow->State.DesiredVisibility = DesireHiddenState;
333
334     fgStructure.CurrentWindow->State.WorkMask &= ~GLUT_DISPLAY_WORK;
335 }
336
337 /*
338  * Iconify the current window (top-level windows only)
339  */
340 void FGAPIENTRY glutIconifyWindow( void )
341 {
342     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutIconifyWindow" );
343     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutIconifyWindow" );
344
345     fgStructure.CurrentWindow->State.WorkMask |= GLUT_VISIBILITY_WORK;
346     fgStructure.CurrentWindow->State.DesiredVisibility = DesireIconicState;
347
348     fgStructure.CurrentWindow->State.WorkMask &= ~GLUT_DISPLAY_WORK;
349 }
350
351 /*
352  * Set the current window's title
353  */
354 void FGAPIENTRY glutSetWindowTitle( const char* title )
355 {
356     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetWindowTitle" );
357     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetWindowTitle" );
358     if( ! fgStructure.CurrentWindow->Parent )
359     {
360         fgPlatformGlutSetWindowTitle ( title );
361     }
362 }
363
364 /*
365  * Set the current window's iconified title
366  */
367 void FGAPIENTRY glutSetIconTitle( const char* title )
368 {
369     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetIconTitle" );
370     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetIconTitle" );
371
372     if( ! fgStructure.CurrentWindow->Parent )
373     {
374         fgPlatformGlutSetIconTitle ( title );
375     }
376 }
377
378 /*
379  * Change the current window's size
380  */
381 void FGAPIENTRY glutReshapeWindow( int width, int height )
382 {
383     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutReshapeWindow" );
384     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutReshapeWindow" );
385
386     if (glutGet(GLUT_FULL_SCREEN))
387     {
388       /*  Leave full screen state before resizing. */
389       glutLeaveFullScreen();
390     }
391
392     fgStructure.CurrentWindow->State.WorkMask |= GLUT_SIZE_WORK;
393     fgStructure.CurrentWindow->State.DesiredWidth  = width ;
394     fgStructure.CurrentWindow->State.DesiredHeight = height;
395 }
396
397 /*
398  * Change the current window's position
399  */
400 void FGAPIENTRY glutPositionWindow( int x, int y )
401 {
402     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPositionWindow" );
403     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPositionWindow" );
404
405     if (glutGet(GLUT_FULL_SCREEN))
406     {
407       /*  Leave full screen state before moving. */
408       glutLeaveFullScreen();
409     }
410
411     fgStructure.CurrentWindow->State.WorkMask |= GLUT_POSITION_WORK;
412     fgStructure.CurrentWindow->State.DesiredXpos = x;
413     fgStructure.CurrentWindow->State.DesiredYpos = y;
414 }
415
416 /*
417  * Lowers the current window (by Z order change)
418  */
419 void FGAPIENTRY glutPushWindow( void )
420 {
421     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPushWindow" );
422     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPushWindow" );
423
424     fgStructure.CurrentWindow->State.WorkMask |= GLUT_ZORDER_WORK;
425     fgStructure.CurrentWindow->State.DesiredZOrder = -1;
426 }
427
428 /*
429  * Raises the current window (by Z order change)
430  */
431 void FGAPIENTRY glutPopWindow( void )
432 {
433     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPopWindow" );
434     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutPopWindow" );
435
436     fgStructure.CurrentWindow->State.WorkMask |= GLUT_ZORDER_WORK;
437     fgStructure.CurrentWindow->State.DesiredZOrder = 1;
438 }
439
440 /*
441  * Resize the current window so that it fits the whole screen
442  */
443 void FGAPIENTRY glutFullScreen( void )
444 {
445     SFG_Window *win;
446
447     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutFullScreen" );
448     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutFullScreen" );
449
450     win = fgStructure.CurrentWindow;
451
452     if (win->Parent)
453     {
454         /* Child windows cannot be made fullscreen, consistent with GLUT's behavior
455          * Also, what would it mean for a child window to be fullscreen, given that it
456          * is confined to its parent?
457          */
458         fgWarning("glutFullScreen called on a child window, ignoring...");
459         return;
460     }
461     else if (fgStructure.GameModeWindow != NULL && fgStructure.GameModeWindow->ID==win->ID && win->State.IsFullscreen)
462     {
463         /* Ignore fullscreen call on GameMode window, those are always fullscreen already
464          * only exception is when first entering GameMode
465          */
466         return;
467     }
468
469     if (!win->State.IsFullscreen)
470         win->State.WorkMask |= GLUT_FULL_SCREEN_WORK;
471 }
472
473 /*
474  * If we are fullscreen, resize the current window back to its original size
475  */
476 void FGAPIENTRY glutLeaveFullScreen( void )
477 {
478     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutFullScreen" );
479     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutFullScreen" );
480
481     if (fgStructure.CurrentWindow->State.IsFullscreen)
482         fgStructure.CurrentWindow->State.WorkMask |= GLUT_FULL_SCREEN_WORK;
483 }
484
485 /*
486  * Toggle the window's full screen state.
487  */
488 void FGAPIENTRY glutFullScreenToggle( void )
489 {
490     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutFullScreenToggle" );
491     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutFullScreenToggle" );
492
493     fgStructure.CurrentWindow->State.WorkMask |= GLUT_FULL_SCREEN_WORK;
494 }
495
496 /*
497  * A.Donev: Set and retrieve the window's user data
498  */
499 void* FGAPIENTRY glutGetWindowData( void )
500 {
501     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutGetWindowData" );
502     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutGetWindowData" );
503     return fgStructure.CurrentWindow->UserData;
504 }
505
506 void FGAPIENTRY glutSetWindowData(void* data)
507 {
508     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetWindowData" );
509     FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetWindowData" );
510     fgStructure.CurrentWindow->UserData = data;
511 }
512
513 /*** END OF FILE ***/