13f25267e5b385f55a8813abef4cce12bf2bf17a
[freeglut] / freeglut-1.3 / freeglut_gamemode.c
1 /*
2  * freeglut_gamemode.c
3  *
4  * The game mode handling code.
5  *
6  * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.
7  * Written by Pawel W. Olszta, <olszta@sourceforge.net>
8  * Creation date: Thu Dec 16 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 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31
32 #define  G_LOG_DOMAIN  "freeglut-gamemode"
33
34 #include "../include/GL/freeglut.h"
35 #include "../include/GL/freeglut_internal.h"
36
37 /*
38  * TODO BEFORE THE STABLE RELEASE:
39  *
40  *  glutGameModeString()    -- missing
41  *  glutEnterGameMode()     -- X11 version
42  *  glutLeaveGameMode()     -- is that correct?
43  *  glutGameModeGet()       -- is that correct?
44  */
45
46
47 /* -- PRIVATE FUNCTIONS ---------------------------------------------------- */
48
49 /*
50  * Remembers the current visual settings, so that
51  * we can change them and restore later...
52  */
53 void fghRememberState( void )
54 {
55 #if TARGET_HOST_UNIX_X11
56
57     /*
58      * This highly depends on the XFree86 extensions, not approved as X Consortium standards
59      */
60 #   ifdef X_XF86VidModeGetModeLine
61
62     /*
63      * Query the current display settings:
64      */
65     XF86VidModeGetModeLine(
66         fgDisplay.Display,
67         fgDisplay.Screen,
68         &fgDisplay.DisplayModeClock,
69         &fgDisplay.DisplayMode
70     );
71
72 #   else
73 #       warning fghRememberState: missing XFree86 video mode extensions, game mode will not change screen resolution when activated
74 #   endif
75
76 #elif TARGET_HOST_WIN32
77
78     DEVMODE devMode;
79
80     /*
81      * Grab the current desktop settings...
82      */
83
84 /* hack to get around my stupid cross-gcc headers */
85 #define ENUM_CURRENT_SETTINGS -1
86
87     EnumDisplaySettings( NULL, ENUM_CURRENT_SETTINGS, &fgDisplay.DisplayMode );
88
89     /*
90      * Make sure we will be restoring all settings needed
91      */
92     fgDisplay.DisplayMode.dmFields |= DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY;
93
94 #endif
95 }
96
97 /*
98  * Restores the previously remembered visual settings
99  */
100 void fghRestoreState( void )
101 {
102 #if TARGET_HOST_UNIX_X11
103
104     /*
105      * This highly depends on the XFree86 extensions, not approved as X Consortium standards
106      */
107 #   ifdef X_XF86VidModeGetAllModeLines
108
109     XF86VidModeModeInfo** displayModes;
110     int i, displayModesCount;
111
112     /*
113      * Query for all the display available...
114      */
115     XF86VidModeGetAllModeLines(
116         fgDisplay.Display,
117         fgDisplay.Screen,
118         &displayModesCount,
119         &displayModes
120     );
121
122     /*
123      * Check every of the modes looking for one that matches our demands
124      */
125     for( i=0; i<displayModesCount; i++ )
126     {
127         if( displayModes[ i ]->hdisplay == fgDisplay.DisplayMode.hdisplay &&
128             displayModes[ i ]->vdisplay == fgDisplay.DisplayMode.vdisplay &&
129             displayModes[ i ]->dotclock == fgDisplay.DisplayModeClock )
130         {
131             /*
132              * OKi, this is the display mode we have been looking for...
133              */
134             XF86VidModeSwitchToMode(
135                 fgDisplay.Display,
136                 fgDisplay.Screen,
137                 displayModes[ i ]
138             );
139
140             return;
141         }
142     }
143
144 #   else
145 #       warning fghRestoreState: missing XFree86 video mode extensions, game mode will not change screen resolution when activated
146 #   endif
147
148 #elif TARGET_HOST_WIN32
149
150     /*
151      * Restore the previously rememebered desktop display settings
152      */
153     ChangeDisplaySettings( &fgDisplay.DisplayMode, 0 );
154
155 #endif
156 }
157
158 /*
159  * Checks the display mode settings against user's preferences
160  */
161 GLboolean fghCheckDisplayMode( int width, int height, int depth, int refresh )
162 {
163     /*
164      * The desired values should be stored in fgState structure...
165      */
166     return( (width == fgState.GameModeSize.X) && (height == fgState.GameModeSize.Y) &&
167             (depth == fgState.GameModeDepth)  && (refresh == fgState.GameModeRefresh) );
168 }
169
170 /*
171  * Changes the current display mode to match user's settings
172  */
173 GLboolean fghChangeDisplayMode( GLboolean haveToTest )
174 {
175 #if TARGET_HOST_UNIX_X11
176
177     /*
178      * This highly depends on the XFree86 extensions, not approved as X Consortium standards
179      */
180 #   ifdef X_XF86VidModeGetAllModeLines
181
182     XF86VidModeModeInfo** displayModes;
183     int i, displayModesCount;
184
185     /*
186      * Query for all the display available...
187      */
188     XF86VidModeGetAllModeLines(
189         fgDisplay.Display,
190         fgDisplay.Screen,
191         &displayModesCount,
192         &displayModes
193     );
194
195     /*
196      * Check every of the modes looking for one that matches our demands
197      */
198     for( i=0; i<displayModesCount; i++ )
199     {
200         if( fghCheckDisplayMode( displayModes[ i ]->hdisplay, displayModes[ i ]->vdisplay,
201                                  fgState.GameModeDepth, fgState.GameModeRefresh ) )
202         {
203             /*
204              * OKi, this is the display mode we have been looking for...
205              */
206             XF86VidModeSwitchToMode(
207                 fgDisplay.Display,
208                 fgDisplay.Screen,
209                 displayModes[ i ]
210             );
211
212             /*
213              * Set the viewport's origin to (0,0) (the game mode window's top-left corner)
214              */
215             XF86VidModeSetViewPort(
216                 fgDisplay.Display,
217                 fgDisplay.Screen,
218                 0,
219                 0
220             );
221
222             /*
223              * Return successfull...
224              */
225             return( TRUE );
226         }
227     }
228
229     /*
230      * Something must have went wrong
231      */
232     return( FALSE );
233
234 #   else
235 #       warning fghChangeDisplayMode: missing XFree86 video mode extensions, game mode will not change screen resolution when activated
236 #   endif
237
238 #elif TARGET_HOST_WIN32
239
240     unsigned int    displayModes = 0, mode = 0xffffffff;
241     GLboolean success = FALSE;
242     HDC      desktopDC;
243     DEVMODE  devMode;
244
245     /*
246      * Enumerate the available display modes
247      */
248     while( EnumDisplaySettings( NULL, displayModes, &devMode ) == TRUE )
249     {
250         /*
251          * Does the enumerated display mode match the user's preferences?
252          */
253         if( fghCheckDisplayMode( devMode.dmPelsWidth,  devMode.dmPelsHeight,
254                                  devMode.dmBitsPerPel, fgState.GameModeRefresh ) )
255         {
256             /*
257              * OKi, we've found a matching display mode, remember it's number and break
258              */
259             mode = displayModes;
260             break;
261         }
262
263         /*
264          * Switch to the next display mode, if any
265          */
266         displayModes++;
267     }
268
269     /*
270      * Did we find a matching display mode?
271      */
272     if( mode != 0xffffffff )
273     {
274         int retVal = DISP_CHANGE_SUCCESSFUL;
275
276         /*
277          * Mark the values we want to modify in the display change call
278          */
279         devMode.dmFields |= DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY;
280
281         /*
282          * Change the current display mode (possibly in test mode only)
283          */
284         retVal = ChangeDisplaySettings( &devMode, haveToTest ? CDS_TEST : 0 );
285
286         /*
287          * I don't know if it's really needed, but looks nice:
288          */
289         success = (retVal == DISP_CHANGE_SUCCESSFUL) || (retVal == DISP_CHANGE_NOTUPDATED);
290
291         /*
292          * If it was not a test, remember the current screen settings
293          */
294         if( !haveToTest && success )
295         {
296             fgState.GameModeSize.X  = devMode.dmPelsWidth;
297             fgState.GameModeSize.Y  = devMode.dmPelsHeight;
298             fgState.GameModeDepth   = devMode.dmBitsPerPel;
299             fgState.GameModeRefresh = devMode.dmDisplayFrequency;
300         }
301     }
302
303     /*
304      * Otherwise we must have failed somewhere
305      */
306     return( success );
307
308 #endif
309 }
310
311
312 /* -- INTERFACE FUNCTIONS -------------------------------------------------- */
313
314 /*
315  * Sets the game mode display string
316  */
317 void FGAPIENTRY glutGameModeString( const char* string )
318 {
319     int width = 640, height = 480, depth = 16, refresh = 72;
320
321     /*
322      * This one seems a bit easier than glutInitDisplayString. The bad thing
323      * about it that I was unable to find the game mode string definition, so
324      * that I assumed it is: "[width]x[height]:[depth]@[refresh rate]", which
325      * appears in all GLUT game mode programs I have seen to date.
326      */
327     if( sscanf( string, "%ix%i:%i@%i", &width, &height, &depth, &refresh ) != 4 )
328         if( sscanf( string, "%ix%i:%i", &width, &height, &depth ) != 3 )
329             if( sscanf( string, "%ix%i@%i", &width, &height, &refresh ) != 3 )
330                 if( sscanf( string, "%ix%i", &width, &height ) != 2 )
331                     if( sscanf( string, ":%i@%i", &depth, &refresh ) != 2 )
332                         if( sscanf( string, ":%i", &depth ) != 1 )
333                             if( sscanf( string, "@%i", &refresh ) != 1 )
334                                 fgWarning( "unable to parse game mode string `%s'", string );
335
336     /*
337      * Hopefully it worked, and if not, we still have the default values
338      */
339     fgState.GameModeSize.X  = width;
340     fgState.GameModeSize.Y  = height;
341     fgState.GameModeDepth   = depth;
342     fgState.GameModeRefresh = refresh;
343 }
344
345 /*
346  * Enters the game mode
347  */
348 int FGAPIENTRY glutEnterGameMode( void )
349 {
350     /*
351      * Check if a game mode window already exists...
352      */
353     if( fgStructure.GameMode != NULL )
354     {
355         /*
356          * ...if so, delete it before proceeding...
357          */
358         fgDestroyWindow( fgStructure.GameMode, TRUE );
359     }
360     else
361     {
362         /*
363          * ...otherwise remember the current resolution, etc.
364          */
365         fghRememberState();
366     }
367
368     /*
369      * We are ready to change the current screen's resolution now
370      */
371     if( fghChangeDisplayMode( FALSE ) == FALSE )
372     {
373         fgWarning( "failed to change screen settings" );
374         return( FALSE );
375     }
376
377     /*
378      * Finally, have the game mode window created
379      */
380     fgStructure.GameMode = fgCreateWindow( 
381         NULL, "FREEGLUT", 0, 0, fgState.GameModeSize.X, fgState.GameModeSize.Y, TRUE 
382     );
383
384 #if TARGET_HOST_UNIX_X11
385
386     /*
387      * Move the mouse pointer over the game mode window
388      */
389     XSetInputFocus(
390         fgDisplay.Display,
391         fgStructure.GameMode->Window.Handle,
392         RevertToNone,
393         CurrentTime
394     );
395
396     /*
397      * Confine the mouse pointer to the window's client area
398      */
399     XGrabPointer(
400         fgDisplay.Display,
401         fgStructure.GameMode->Window.Handle,
402         TRUE,
403         ButtonPressMask|ButtonReleaseMask|ButtonMotionMask|PointerMotionMask,
404         GrabModeAsync, GrabModeAsync,
405         fgStructure.GameMode->Window.Handle,
406         None,
407         CurrentTime
408     );
409
410     /*
411      * Grab the keyboard, too
412      */
413     XGrabKeyboard(
414         fgDisplay.Display,
415         fgStructure.GameMode->Window.Handle,
416         FALSE,
417         GrabModeAsync, GrabModeAsync,
418         CurrentTime
419     );
420
421 #endif
422
423     /*
424      * Return successfull
425      */
426     return( TRUE );
427 }
428
429 /*
430  * Leaves the game mode
431  */
432 void FGAPIENTRY glutLeaveGameMode( void )
433 {
434     freeglut_return_if_fail( fgStructure.GameMode != NULL );
435
436     /*
437      * First of all, have the game mode window created
438      */
439     fgDestroyWindow( fgStructure.GameMode, TRUE );
440
441 #if TARGET_HOST_UNIX_X11
442
443     /*
444      * Ungrab the mouse and keyboard
445      */
446     XUngrabPointer( fgDisplay.Display, CurrentTime );
447     XUngrabKeyboard( fgDisplay.Display, CurrentTime );
448
449 #endif
450
451     /*
452      * Then, have the desktop visual settings restored
453      */
454     fghRestoreState();
455 }
456
457 /*
458  * Returns information concerning the freeglut game mode
459  */
460 int FGAPIENTRY glutGameModeGet( GLenum eWhat )
461 {
462     /*
463      * See why are we bothered
464      */
465     switch( eWhat )
466     {
467     case GLUT_GAME_MODE_ACTIVE:
468         /*
469          * Check if the game mode is currently active
470          */
471         return( fgStructure.GameMode != NULL );
472
473     case GLUT_GAME_MODE_POSSIBLE:
474         /*
475          * Check if the current game mode settings are valid
476          */
477         return( fghChangeDisplayMode( TRUE ) );
478
479     case GLUT_GAME_MODE_WIDTH:
480         /*
481          * The game mode screen width
482          */
483         return( fgState.GameModeSize.X );
484
485     case GLUT_GAME_MODE_HEIGHT:
486         /*
487          * The game mode screen height
488          */
489         return( fgState.GameModeSize.Y );
490
491     case GLUT_GAME_MODE_PIXEL_DEPTH:
492         /*
493          * The game mode pixel depth
494          */
495         return( fgState.GameModeDepth );
496
497     case GLUT_GAME_MODE_REFRESH_RATE:
498         /*
499          * The game mode refresh rate
500          */
501         return( fgState.GameModeRefresh );
502
503     case GLUT_GAME_MODE_DISPLAY_CHANGED:
504         /*
505          * This is true if the game mode has been activated successfully..
506          */
507         return( fgStructure.GameMode != NULL );
508     }
509
510     return( -1 );
511 }
512
513 /*** END OF FILE ***/
514
515
516
517