resetting manifest requested domain to floor
[platform/upstream/freeglut.git] / src / 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 #include <GL/freeglut.h>
29 #include "freeglut_internal.h"
30
31 /*
32  * TODO BEFORE THE STABLE RELEASE:
33  *
34  *  glutGameModeString()    -- missing
35  *  glutEnterGameMode()     -- X11 version
36  *  glutLeaveGameMode()     -- is that correct?
37  *  glutGameModeGet()       -- is that correct?
38  */
39
40
41 /* -- PRIVATE FUNCTIONS ---------------------------------------------------- */
42
43 #if TARGET_HOST_POSIX_X11
44 static int xrandr_resize(int xsz, int ysz, int rate, int just_checking)
45 {
46 #ifdef HAVE_X11_EXTENSIONS_XRANDR_H
47     int event_base, error_base, ver_major, ver_minor, use_rate;
48     XRRScreenConfiguration *xrr_config = 0;
49     Status result = -1;
50
51     /* must check at runtime for the availability of the extension */
52     if(!XRRQueryExtension(fgDisplay.Display, &event_base, &error_base)) {
53         return -1;
54     }
55
56     XRRQueryVersion(fgDisplay.Display, &ver_major, &ver_minor);
57
58     /* we only heed the rate if we CAN actually use it (Xrandr >= 1.1) and
59      * the user actually cares about it (rate > 0)
60      */
61     use_rate = ( rate > 0 ) && ( ( ver_major >= 1 ) ||
62                                          ( ( ver_major == 1 ) && ( ver_minor >= 1 ) ) );
63
64     /* this loop is only so that the whole thing will be repeated if someone
65      * else changes video mode between our query of the current information and
66      * the attempt to change it.
67      */
68     do {
69         XRRScreenSize *ssizes;
70         short *rates;
71         Rotation rot;
72         int i, ssizes_count, rates_count, curr, res_idx = -1;
73         Time timestamp, cfg_timestamp;
74
75         if(xrr_config) {
76             XRRFreeScreenConfigInfo(xrr_config);
77         }
78
79         if(!(xrr_config = XRRGetScreenInfo(fgDisplay.Display, fgDisplay.RootWindow))) {
80             fgWarning("XRRGetScreenInfo failed");
81             break;
82         }
83         ssizes = XRRConfigSizes(xrr_config, &ssizes_count);
84         curr = XRRConfigCurrentConfiguration(xrr_config, &rot);
85         timestamp = XRRConfigTimes(xrr_config, &cfg_timestamp);
86
87         /* if either of xsz or ysz are unspecified, use the current values */
88         if(xsz <= 0)
89             xsz = fgState.GameModeSize.X = ssizes[curr].width;
90         if(ysz <= 0)
91             ysz = fgState.GameModeSize.Y = ssizes[curr].height;
92
93
94         if(xsz == ssizes[curr].width && ysz == ssizes[curr].height) {
95             /* no need to switch, we're already in the requested resolution */
96             res_idx = curr;
97         } else {
98             for(i=0; i<ssizes_count; i++) {
99                 if(ssizes[i].width == xsz && ssizes[i].height == ysz) {
100                     res_idx = i;
101                     break;  /* found it */
102                 }
103             }
104         }
105         if(res_idx == -1)
106             break;  /* no matching resolution */
107
108 #if ( RANDR_MAJOR >= 1 ) || ( ( RANDR_MAJOR == 1 ) && ( RANDR_MINOR >= 1 ) )
109         if(use_rate) {
110             rate = fgState.GameModeRefresh;
111
112             /* for the selected resolution, let's find out if there is
113              * a matching refresh rate available.
114              */
115             rates = XRRConfigRates(xrr_config, res_idx, &rates_count);
116
117             for(i=0; i<rates_count; i++) {
118                 if(rates[i] == rate) {
119                     break;
120                 }
121             }
122             if(i == rates_count) {
123                 break; /* no matching rate */
124             }
125         }
126 #endif
127
128         if(just_checking) {
129             result = 0;
130             break;
131         }
132
133 #if ( RANDR_MAJOR >= 1 ) || ( ( RANDR_MAJOR == 1 ) && ( RANDR_MINOR >= 1 ) )
134         if(use_rate)
135             result = XRRSetScreenConfigAndRate(fgDisplay.Display, xrr_config,
136                     fgDisplay.RootWindow, res_idx, rot, rate, timestamp);
137         else
138 #endif
139             result = XRRSetScreenConfig(fgDisplay.Display, xrr_config,
140                     fgDisplay.RootWindow, res_idx, rot, timestamp);
141
142     } while(result == RRSetConfigInvalidTime);
143
144     if(xrr_config) {
145         XRRFreeScreenConfigInfo(xrr_config);
146     }
147
148     if(result == 0) {
149         return 0;
150     }
151
152 #endif  /* HAVE_X11_EXTENSIONS_XRANDR_H */
153     return -1;
154 }
155 #endif  /* TARGET_HOST_POSIX_X11 */
156
157 /*
158  * Remembers the current visual settings, so that
159  * we can change them and restore later...
160  */
161 static void fghRememberState( void )
162 {
163 #if TARGET_HOST_POSIX_X11
164     int event_base, error_base;
165
166     /*
167      * Remember the current pointer location before going fullscreen
168      * for restoring it later:
169      */
170     Window junk_window;
171     unsigned int junk_mask;
172
173     XQueryPointer(fgDisplay.Display, fgDisplay.RootWindow,
174             &junk_window, &junk_window,
175             &fgDisplay.DisplayPointerX, &fgDisplay.DisplayPointerY,
176             &fgDisplay.DisplayPointerX, &fgDisplay.DisplayPointerY, &junk_mask);
177
178 #   ifdef HAVE_X11_EXTENSIONS_XRANDR_H
179     if(XRRQueryExtension(fgDisplay.Display, &event_base, &error_base)) {
180         XRRScreenConfiguration *xrr_config;
181         XRRScreenSize *ssizes;
182         Rotation rot;
183         int ssize_count, curr;
184
185         if((xrr_config = XRRGetScreenInfo(fgDisplay.Display, fgDisplay.RootWindow))) {
186             ssizes = XRRConfigSizes(xrr_config, &ssize_count);
187             curr = XRRConfigCurrentConfiguration(xrr_config, &rot);
188
189             fgDisplay.prev_xsz = ssizes[curr].width;
190             fgDisplay.prev_ysz = ssizes[curr].height;
191             fgDisplay.prev_refresh = -1;
192
193 #       if ( RANDR_MAJOR >= 1 ) || ( ( RANDR_MAJOR == 1 ) && ( RANDR_MINOR >= 1 ) )
194             if(fgState.GameModeRefresh != -1) {
195                 fgDisplay.prev_refresh = XRRConfigCurrentRate(xrr_config);
196             }
197 #       endif
198
199             fgDisplay.prev_size_valid = 1;
200
201             XRRFreeScreenConfigInfo(xrr_config);
202         }
203     }
204 #   endif
205
206     /*
207      * This highly depends on the XFree86 extensions,
208      * not approved as X Consortium standards
209      */
210 #   ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H
211     if(!XF86VidModeQueryExtension(fgDisplay.Display, &event_base, &error_base)) {
212         return;
213     }
214
215     /*
216      * Remember the current ViewPort location of the screen to be able to
217      * restore the ViewPort on LeaveGameMode():
218      */
219     if( !XF86VidModeGetViewPort(
220              fgDisplay.Display,
221              fgDisplay.Screen,
222              &fgDisplay.DisplayViewPortX,
223              &fgDisplay.DisplayViewPortY ) )
224         fgWarning( "XF86VidModeGetViewPort failed" );
225
226
227     /* Query the current display settings: */
228     fgDisplay.DisplayModeValid =
229       XF86VidModeGetModeLine(
230         fgDisplay.Display,
231         fgDisplay.Screen,
232         &fgDisplay.DisplayModeClock,
233         &fgDisplay.DisplayMode
234     );
235
236     if( !fgDisplay.DisplayModeValid )
237         fgWarning( "XF86VidModeGetModeLine failed" );
238 #   endif
239
240 #elif TARGET_HOST_MS_WINDOWS
241
242 /*    DEVMODE devMode; */
243
244     /* Grab the current desktop settings... */
245
246 /* hack to get around my stupid cross-gcc headers */
247 #define FREEGLUT_ENUM_CURRENT_SETTINGS -1
248
249     EnumDisplaySettings( fgDisplay.DisplayName, FREEGLUT_ENUM_CURRENT_SETTINGS,
250                          &fgDisplay.DisplayMode );
251
252     /* Make sure we will be restoring all settings needed */
253     fgDisplay.DisplayMode.dmFields |=
254         DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY;
255
256 #endif
257 }
258
259 /*
260  * Restores the previously remembered visual settings
261  */
262 static void fghRestoreState( void )
263 {
264 #if TARGET_HOST_POSIX_X11
265     /* Restore the remembered pointer position: */
266     XWarpPointer(
267         fgDisplay.Display, None, fgDisplay.RootWindow, 0, 0, 0, 0,
268         fgDisplay.DisplayPointerX, fgDisplay.DisplayPointerY
269     );
270
271
272 #   ifdef HAVE_X11_EXTENSIONS_XRANDR_H
273     if(fgDisplay.prev_size_valid) {
274         if(xrandr_resize(fgDisplay.prev_xsz, fgDisplay.prev_ysz, fgDisplay.prev_refresh, 0) != -1) {
275             fgDisplay.prev_size_valid = 0;
276 #       ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H
277             fgDisplay.DisplayModeValid = 0;
278 #       endif
279             return;
280         }
281     }
282 #   endif
283
284
285
286 #   ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H
287     /*
288      * This highly depends on the XFree86 extensions,
289      * not approved as X Consortium standards
290      */
291
292     if( fgDisplay.DisplayModeValid )
293     {
294         XF86VidModeModeInfo** displayModes;
295         int i, displayModesCount;
296
297         if( !XF86VidModeGetAllModeLines(
298                  fgDisplay.Display,
299                  fgDisplay.Screen,
300                  &displayModesCount,
301                  &displayModes ) )
302         {
303             fgWarning( "XF86VidModeGetAllModeLines failed" );
304             return;
305         }
306
307
308         /*
309          * Check every of the modes looking for one that matches our demands.
310          * If we find one, switch to it and restore the remembered viewport.
311          */
312         for( i = 0; i < displayModesCount; i++ )
313         {
314             if(displayModes[ i ]->hdisplay == fgDisplay.DisplayMode.hdisplay &&
315                displayModes[ i ]->vdisplay == fgDisplay.DisplayMode.vdisplay &&
316                displayModes[ i ]->dotclock == fgDisplay.DisplayModeClock )
317             {
318                 if( !XF86VidModeSwitchToMode(
319                          fgDisplay.Display,
320                          fgDisplay.Screen,
321                          displayModes[ i ] ) )
322                 {
323                     fgWarning( "XF86VidModeSwitchToMode failed" );
324                     break;
325                 }
326
327                 if( !XF86VidModeSetViewPort(
328                          fgDisplay.Display,
329                          fgDisplay.Screen,
330                          fgDisplay.DisplayViewPortX,
331                          fgDisplay.DisplayViewPortY ) )
332                     fgWarning( "XF86VidModeSetViewPort failed" );
333
334
335                 /*
336                  * For the case this would be the last X11 call the application
337                  * calls exit() we've to flush the X11 output queue to have the
338                  * commands sent to the X server before the application exits.
339                  */
340                 XFlush( fgDisplay.Display );
341
342                 fgDisplay.DisplayModeValid = 0;
343 #       ifdef HAVE_X11_EXTENSIONS_XRANDR_H
344                 fgDisplay.prev_size_valid = 0;
345 #       endif
346
347                 break;
348             }
349         }
350         XFree( displayModes );
351     }
352
353 #   endif
354
355 #elif TARGET_HOST_MS_WINDOWS
356
357     /* Restore the previously remembered desktop display settings */
358     ChangeDisplaySettingsEx( fgDisplay.DisplayName,&fgDisplay.DisplayMode, 0,0,0 );
359
360 #endif
361 }
362
363 #if TARGET_HOST_POSIX_X11
364 #ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H
365
366 /*
367  * Checks a single display mode settings against user's preferences.
368  */
369 static GLboolean fghCheckDisplayMode( int width, int height, int depth, int refresh )
370 {
371     /* The desired values should be stored in fgState structure... */
372     return ( width == fgState.GameModeSize.X ) &&
373            ( height == fgState.GameModeSize.Y ) &&
374            ( depth == fgState.GameModeDepth ) &&
375            ( refresh == fgState.GameModeRefresh );
376 }
377
378 /*
379  * Checks all display modes settings against user's preferences.
380  * Returns the mode number found or -1 if none could be found.
381  */
382 static int fghCheckDisplayModes( GLboolean exactMatch, int displayModesCount, XF86VidModeModeInfo** displayModes )
383 {
384     int i;
385     for( i = 0; i < displayModesCount; i++ )
386     {
387         /* Compute the displays refresh rate, dotclock comes in kHz. */
388         int refresh = ( displayModes[ i ]->dotclock * 1000 ) /
389                       ( displayModes[ i ]->htotal * displayModes[ i ]->vtotal );
390
391         if( fghCheckDisplayMode( displayModes[ i ]->hdisplay,
392                                  displayModes[ i ]->vdisplay,
393                                  fgState.GameModeDepth,
394                                  ( exactMatch ? refresh : fgState.GameModeRefresh ) ) ) {
395             if (!exactMatch)
396             {
397                 /* Update the chosen refresh rate, otherwise a
398                  * glutGameModeGet(GLUT_GAME_MODE_REFRESH_RATE) would not
399                  * return the right values
400                  */
401                 fgState.GameModeRefresh = refresh;
402             }
403
404             return i;
405         }
406     }
407     return -1;
408 }
409
410 #endif
411 #endif
412
413 /*
414  * Changes the current display mode to match user's settings
415  */
416 static GLboolean fghChangeDisplayMode( GLboolean haveToTest )
417 {
418     GLboolean success = GL_FALSE;
419 #if TARGET_HOST_POSIX_X11
420
421     /* first try to use XRandR, then fallback to XF86VidMode */
422 #   ifdef HAVE_X11_EXTENSIONS_XRANDR_H
423     if(xrandr_resize(fgState.GameModeSize.X, fgState.GameModeSize.Y,
424                 fgState.GameModeRefresh, haveToTest) != -1) {
425         return GL_TRUE;
426     }
427 #   endif
428
429
430     /*
431      * This highly depends on the XFree86 extensions,
432      * not approved as X Consortium standards
433      */
434 #   ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H
435
436     /*
437      * This is also used by applications which check modes by calling
438      * glutGameModeGet(GLUT_GAME_MODE_POSSIBLE), so allow the check:
439      */
440     if( haveToTest || fgDisplay.DisplayModeValid )
441     {
442         XF86VidModeModeInfo** displayModes;
443         int i, displayModesCount;
444
445         /* If we don't have a valid modeline in the display structure, which
446          * can happen if this is called from glutGameModeGet instead of
447          * glutEnterGameMode, then we need to query the current mode, to make
448          * unspecified settings to default to their current values.
449          */
450         if(!fgDisplay.DisplayModeValid) {
451             if(!XF86VidModeGetModeLine(fgDisplay.Display, fgDisplay.Screen,
452                     &fgDisplay.DisplayModeClock, &fgDisplay.DisplayMode)) {
453                 return success;
454             }
455         }
456
457         if (fgState.GameModeSize.X == -1)
458         {
459             fgState.GameModeSize.X = fgDisplay.DisplayMode.hdisplay;
460         }
461         if (fgState.GameModeSize.Y == -1)
462         {
463             fgState.GameModeSize.Y = fgDisplay.DisplayMode.vdisplay;
464         }
465         if (fgState.GameModeDepth == -1)
466         {
467             /* can't get color depth from this, nor can we change it, do nothing
468              * TODO: get with XGetVisualInfo()? but then how to set?
469              */
470         }
471         if (fgState.GameModeRefresh == -1)
472         {
473             /* Compute the displays refresh rate, dotclock comes in kHz. */
474             int refresh = ( fgDisplay.DisplayModeClock * 1000 ) /
475                 ( fgDisplay.DisplayMode.htotal * fgDisplay.DisplayMode.vtotal );
476
477             fgState.GameModeRefresh = refresh;
478         }
479
480         /* query all possible display modes */
481         if( !XF86VidModeGetAllModeLines(
482                  fgDisplay.Display,
483                  fgDisplay.Screen,
484                  &displayModesCount,
485                  &displayModes ) )
486         {
487             fgWarning( "XF86VidModeGetAllModeLines failed" );
488             return success;
489         }
490
491
492         /*
493          * Check every of the modes looking for one that matches our demands,
494          * ignoring the refresh rate if no exact match could be found.
495          */
496         i = fghCheckDisplayModes( GL_TRUE, displayModesCount, displayModes );
497         if( i < 0 ) {
498             i = fghCheckDisplayModes( GL_FALSE, displayModesCount, displayModes );
499         }
500         success = ( i < 0 ) ? GL_FALSE : GL_TRUE;
501
502         if( !haveToTest && success ) {
503             if( !XF86VidModeSwitchToMode(
504                      fgDisplay.Display,
505                      fgDisplay.Screen,
506                      displayModes[ i ] ) )
507                 fgWarning( "XF86VidModeSwitchToMode failed" );
508         }
509
510         XFree( displayModes );
511     }
512
513 #   endif
514
515
516 #elif TARGET_HOST_MS_WINDOWS
517
518     DEVMODE  devMode;
519     char *fggmstr = NULL;
520     char displayMode[300];
521
522     success = GL_FALSE;
523
524     EnumDisplaySettings( fgDisplay.DisplayName, -1, &devMode ); 
525     devMode.dmFields = 0;
526
527     if (fgState.GameModeSize.X!=-1)
528     {
529         devMode.dmPelsWidth  = fgState.GameModeSize.X;
530         devMode.dmFields |= DM_PELSWIDTH;
531     }
532     if (fgState.GameModeSize.Y!=-1)
533     {
534         devMode.dmPelsHeight  = fgState.GameModeSize.Y;
535         devMode.dmFields |= DM_PELSHEIGHT;
536     }
537     if (fgState.GameModeDepth!=-1)
538     {
539         devMode.dmBitsPerPel  = fgState.GameModeDepth;
540         devMode.dmFields |= DM_BITSPERPEL;
541     }
542     if (fgState.GameModeRefresh!=-1)
543     {
544         devMode.dmDisplayFrequency  = fgState.GameModeRefresh;
545         devMode.dmFields |= DM_DISPLAYFREQUENCY;
546     }
547
548     switch ( ChangeDisplaySettingsEx(fgDisplay.DisplayName, &devMode, NULL, haveToTest ? CDS_TEST : CDS_FULLSCREEN , NULL) )
549     {
550     case DISP_CHANGE_SUCCESSFUL:
551         success = GL_TRUE;
552
553         if (!haveToTest)
554         {
555             /* update vars in case if windows switched to proper mode */
556             EnumDisplaySettings( fgDisplay.DisplayName, FREEGLUT_ENUM_CURRENT_SETTINGS, &devMode );
557             fgState.GameModeSize.X  = devMode.dmPelsWidth;        
558             fgState.GameModeSize.Y  = devMode.dmPelsHeight;
559             fgState.GameModeDepth   = devMode.dmBitsPerPel;
560             fgState.GameModeRefresh = devMode.dmDisplayFrequency;
561         }
562                 break;
563     case DISP_CHANGE_RESTART:
564         fggmstr = "The computer must be restarted for the graphics mode to work.";
565         break;
566     case DISP_CHANGE_BADFLAGS:
567         fggmstr = "An invalid set of flags was passed in.";
568         break;
569     case DISP_CHANGE_BADPARAM:
570         fggmstr = "An invalid parameter was passed in. This can include an invalid flag or combination of flags.";
571         break;
572     case DISP_CHANGE_FAILED:
573         fggmstr = "The display driver failed the specified graphics mode.";
574         break;
575     case DISP_CHANGE_BADMODE:
576         fggmstr = "The graphics mode is not supported.";
577         break;
578     default:
579         fggmstr = "Unknown error in graphics mode???"; /* dunno if it is possible,MSDN does not mention any other error */
580         break;
581     }
582
583     if ( !success )
584     {
585         /* I'd rather get info whats going on in my program than wonder about */
586         /* magic happenings behind my back, its lib for devels at last ;) */
587         
588         /* append display mode to error to make things more informative */
589         sprintf(displayMode,"%s Problem with requested mode: %ix%i:%i@%i", fggmstr, devMode.dmPelsWidth, devMode.dmPelsHeight, devMode.dmBitsPerPel, devMode.dmDisplayFrequency);
590         fgWarning(displayMode);
591     }
592 #endif
593
594     return success;
595 }
596
597
598 /* -- INTERFACE FUNCTIONS -------------------------------------------------- */
599
600 /*
601  * Sets the game mode display string
602  */
603 void FGAPIENTRY glutGameModeString( const char* string )
604 {
605     int width = -1, height = -1, depth = -1, refresh = -1;
606
607     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutGameModeString" );
608
609     /*
610      * This one seems a bit easier than glutInitDisplayString. The bad thing
611      * about it that I was unable to find the game mode string definition, so
612      * that I assumed it is: "[width]x[height]:[depth]@[refresh rate]", which
613      * appears in all GLUT game mode programs I have seen to date.
614      */
615     if( sscanf( string, "%ix%i:%i@%i", &width, &height, &depth, &refresh ) !=
616         4 )
617         if( sscanf( string, "%ix%i:%i", &width, &height, &depth ) != 3 )
618             if( sscanf( string, "%ix%i@%i", &width, &height, &refresh ) != 3 )
619                 if( sscanf( string, "%ix%i", &width, &height ) != 2 )
620                     if( sscanf( string, ":%i@%i", &depth, &refresh ) != 2 )
621                         if( sscanf( string, ":%i", &depth ) != 1 )
622                             if( sscanf( string, "@%i", &refresh ) != 1 )
623                                 fgWarning(
624                                     "unable to parse game mode string `%s'",
625                                     string
626                                 );
627
628     /* All values not specified are now set to -1, which means those
629      * aspects of the current display mode are not changed in
630      * fghChangeDisplayMode() above.
631      */
632     fgState.GameModeSize.X  = width;
633     fgState.GameModeSize.Y  = height;
634     fgState.GameModeDepth   = depth;
635     fgState.GameModeRefresh = refresh;
636 }
637
638
639
640 /*
641  * Enters the game mode
642  */
643 int FGAPIENTRY glutEnterGameMode( void )
644 {
645     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutEnterGameMode" );
646
647     if( fgStructure.GameModeWindow )
648         fgAddToWindowDestroyList( fgStructure.GameModeWindow );
649     else
650         fghRememberState( );
651
652     if( ! fghChangeDisplayMode( GL_FALSE ) )
653     {
654         fgWarning( "failed to change screen settings" );
655         return 0;
656     }
657
658     fgStructure.GameModeWindow = fgCreateWindow(
659         NULL, "FREEGLUT", GL_TRUE, 0, 0,
660         GL_TRUE, fgState.GameModeSize.X, fgState.GameModeSize.Y,
661         GL_TRUE, GL_FALSE
662     );
663
664     fgStructure.GameModeWindow->State.Width  = fgState.GameModeSize.X;
665     fgStructure.GameModeWindow->State.Height = fgState.GameModeSize.Y;
666     fgStructure.GameModeWindow->State.NeedToResize = GL_TRUE;
667
668 #if TARGET_HOST_POSIX_X11
669
670     /*
671      * Sync needed to avoid a real race, the Xserver must have really created
672      * the window before we can grab the pointer into it:
673      */
674     XSync( fgDisplay.Display, False );
675     /*
676      * Grab the pointer to confine it into the window after the calls to
677      * XWrapPointer() which ensure that the pointer really enters the window.
678      *
679      * We also need to wait here until XGrabPointer() returns GrabSuccess,
680      * otherwise the new window is not viewable yet and if the next function
681      * (XSetInputFocus) is called with a not yet viewable window, it will exit
682      * the application which we have to aviod, so wait until it's viewable:
683      */
684     while( GrabSuccess != XGrabPointer(
685                fgDisplay.Display, fgStructure.GameModeWindow->Window.Handle,
686                TRUE,
687                ButtonPressMask | ButtonReleaseMask | ButtonMotionMask
688                | PointerMotionMask,
689                GrabModeAsync, GrabModeAsync,
690                fgStructure.GameModeWindow->Window.Handle, None, CurrentTime) )
691         usleep( 100 );
692     /*
693      * Change input focus to the new window. This will exit the application
694      * if the new window is not viewable yet, see the XGrabPointer loop above.
695      */
696     XSetInputFocus(
697         fgDisplay.Display,
698         fgStructure.GameModeWindow->Window.Handle,
699         RevertToNone,
700         CurrentTime
701     );
702
703     /* Move the Pointer to the middle of the fullscreen window */
704     XWarpPointer(
705         fgDisplay.Display,
706         None,
707         fgDisplay.RootWindow,
708         0, 0, 0, 0,
709         fgState.GameModeSize.X/2, fgState.GameModeSize.Y/2
710     );
711
712 #   ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H
713
714     if( fgDisplay.DisplayModeValid )
715     {
716         int x, y;
717         Window child;
718
719         /* Change to viewport to the window topleft edge: */
720         if( !XF86VidModeSetViewPort( fgDisplay.Display, fgDisplay.Screen, 0, 0 ) )
721             fgWarning( "XF86VidModeSetViewPort failed" );
722
723         /*
724          * Final window repositioning: It could be avoided using an undecorated
725          * window using override_redirect, but this * would possily require
726          * more changes and investigation.
727          */
728
729         /* Get the current postion of the drawable area on screen */
730         XTranslateCoordinates(
731             fgDisplay.Display,
732             fgStructure.CurrentWindow->Window.Handle,
733             fgDisplay.RootWindow,
734             0, 0, &x, &y,
735             &child
736         );
737
738         /* Move the decorataions out of the topleft corner of the display */
739         XMoveWindow( fgDisplay.Display, fgStructure.CurrentWindow->Window.Handle,
740                      -x, -y);
741     }
742
743 #endif
744
745     /* Grab the keyboard, too */
746     XGrabKeyboard(
747         fgDisplay.Display,
748         fgStructure.GameModeWindow->Window.Handle,
749         FALSE,
750         GrabModeAsync, GrabModeAsync,
751         CurrentTime
752     );
753
754 #endif
755
756     return fgStructure.GameModeWindow->ID;
757 }
758
759 /*
760  * Leaves the game mode
761  */
762 void FGAPIENTRY glutLeaveGameMode( void )
763 {
764     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutLeaveGameMode" );
765
766     freeglut_return_if_fail( fgStructure.GameModeWindow );
767
768     fgAddToWindowDestroyList( fgStructure.GameModeWindow );
769     fgStructure.GameModeWindow = NULL;
770
771 #if TARGET_HOST_POSIX_X11
772
773     XUngrabPointer( fgDisplay.Display, CurrentTime );
774     XUngrabKeyboard( fgDisplay.Display, CurrentTime );
775
776 #endif
777
778     fghRestoreState();
779 }
780
781 /*
782  * Returns information concerning the freeglut game mode
783  */
784 int FGAPIENTRY glutGameModeGet( GLenum eWhat )
785 {
786     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutGameModeGet" );
787
788     switch( eWhat )
789     {
790     case GLUT_GAME_MODE_ACTIVE:
791         return !!fgStructure.GameModeWindow;
792
793     case GLUT_GAME_MODE_POSSIBLE:
794         return fghChangeDisplayMode( GL_TRUE );
795
796     case GLUT_GAME_MODE_WIDTH:
797         return fgState.GameModeSize.X;
798
799     case GLUT_GAME_MODE_HEIGHT:
800         return fgState.GameModeSize.Y;
801
802     case GLUT_GAME_MODE_PIXEL_DEPTH:
803         return fgState.GameModeDepth;
804
805     case GLUT_GAME_MODE_REFRESH_RATE:
806         return fgState.GameModeRefresh;
807
808     case GLUT_GAME_MODE_DISPLAY_CHANGED:
809         /*
810          * This is true if the game mode has been activated successfully..
811          */
812         return !!fgStructure.GameModeWindow;
813     }
814
815     fgWarning( "Unknown gamemode get: %d", eWhat );
816     return -1;
817 }
818
819 /*** END OF FILE ***/