f69595c3b37aaaa80502b9068eca215c7d9701c5
[freeglut] / src / Common / freeglut_gamemode.c
1 /*\r
2  * freeglut_gamemode.c\r
3  *\r
4  * The game mode handling code.\r
5  *\r
6  * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.\r
7  * Written by Pawel W. Olszta, <olszta@sourceforge.net>\r
8  * Creation date: Thu Dec 16 1999\r
9  *\r
10  * Permission is hereby granted, free of charge, to any person obtaining a\r
11  * copy of this software and associated documentation files (the "Software"),\r
12  * to deal in the Software without restriction, including without limitation\r
13  * the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
14  * and/or sell copies of the Software, and to permit persons to whom the\r
15  * Software is furnished to do so, subject to the following conditions:\r
16  *\r
17  * The above copyright notice and this permission notice shall be included\r
18  * in all copies or substantial portions of the Software.\r
19  *\r
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS\r
21  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL\r
23  * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
24  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
25  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
26  */\r
27 \r
28 #include <GL/freeglut.h>\r
29 #include "freeglut_internal.h"\r
30 \r
31 /*\r
32  * TODO BEFORE THE STABLE RELEASE:\r
33  *\r
34  *  glutGameModeString()    -- missing\r
35  *  glutEnterGameMode()     -- X11 version\r
36  *  glutLeaveGameMode()     -- is that correct?\r
37  *  glutGameModeGet()       -- is that correct?\r
38  */\r
39 \r
40 \r
41 /* -- PRIVATE FUNCTIONS ---------------------------------------------------- */\r
42 extern void fgPlatformRememberState( void );\r
43 extern void fgPlatformRestoreState( void );\r
44 extern GLboolean fgPlatformChangeDisplayMode( GLboolean haveToTest );\r
45 \r
46 \r
47 #if TARGET_HOST_POSIX_X11\r
48 static int xrandr_resize(int xsz, int ysz, int rate, int just_checking)\r
49 {\r
50 #ifdef HAVE_X11_EXTENSIONS_XRANDR_H\r
51     int event_base, error_base, ver_major, ver_minor, use_rate;\r
52     XRRScreenConfiguration *xrr_config = 0;\r
53     Status result = -1;\r
54 \r
55     /* must check at runtime for the availability of the extension */\r
56     if(!XRRQueryExtension(fgDisplay.pDisplay.Display, &event_base, &error_base)) {\r
57         return -1;\r
58     }\r
59 \r
60     XRRQueryVersion(fgDisplay.pDisplay.Display, &ver_major, &ver_minor);\r
61 \r
62     /* we only heed the rate if we CAN actually use it (Xrandr >= 1.1) and\r
63      * the user actually cares about it (rate > 0)\r
64      */\r
65     use_rate = ( rate > 0 ) && ( ( ver_major >= 1 ) ||\r
66                                          ( ( ver_major == 1 ) && ( ver_minor >= 1 ) ) );\r
67 \r
68     /* this loop is only so that the whole thing will be repeated if someone\r
69      * else changes video mode between our query of the current information and\r
70      * the attempt to change it.\r
71      */\r
72     do {\r
73         XRRScreenSize *ssizes;\r
74         short *rates;\r
75         Rotation rot;\r
76         int i, ssizes_count, rates_count, curr, res_idx = -1;\r
77         Time timestamp, cfg_timestamp;\r
78 \r
79         if(xrr_config) {\r
80             XRRFreeScreenConfigInfo(xrr_config);\r
81         }\r
82 \r
83         if(!(xrr_config = XRRGetScreenInfo(fgDisplay.pDisplay.Display, fgDisplay.pDisplay.RootWindow))) {\r
84             fgWarning("XRRGetScreenInfo failed");\r
85             break;\r
86         }\r
87         ssizes = XRRConfigSizes(xrr_config, &ssizes_count);\r
88         curr = XRRConfigCurrentConfiguration(xrr_config, &rot);\r
89         timestamp = XRRConfigTimes(xrr_config, &cfg_timestamp);\r
90 \r
91         /* if either of xsz or ysz are unspecified, use the current values */\r
92         if(xsz <= 0)\r
93             xsz = fgState.GameModeSize.X = ssizes[curr].width;\r
94         if(ysz <= 0)\r
95             ysz = fgState.GameModeSize.Y = ssizes[curr].height;\r
96 \r
97 \r
98         if(xsz == ssizes[curr].width && ysz == ssizes[curr].height) {\r
99             /* no need to switch, we're already in the requested resolution */\r
100             res_idx = curr;\r
101         } else {\r
102             for(i=0; i<ssizes_count; i++) {\r
103                 if(ssizes[i].width == xsz && ssizes[i].height == ysz) {\r
104                     res_idx = i;\r
105                     break;  /* found it */\r
106                 }\r
107             }\r
108         }\r
109         if(res_idx == -1)\r
110             break;  /* no matching resolution */\r
111 \r
112 #if ( RANDR_MAJOR >= 1 ) || ( ( RANDR_MAJOR == 1 ) && ( RANDR_MINOR >= 1 ) )\r
113         if(use_rate) {\r
114             rate = fgState.GameModeRefresh;\r
115 \r
116             /* for the selected resolution, let's find out if there is\r
117              * a matching refresh rate available.\r
118              */\r
119             rates = XRRConfigRates(xrr_config, res_idx, &rates_count);\r
120 \r
121             for(i=0; i<rates_count; i++) {\r
122                 if(rates[i] == rate) {\r
123                     break;\r
124                 }\r
125             }\r
126             if(i == rates_count) {\r
127                 break; /* no matching rate */\r
128             }\r
129         }\r
130 #endif\r
131 \r
132         if(just_checking) {\r
133             result = 0;\r
134             break;\r
135         }\r
136 \r
137 #if ( RANDR_MAJOR >= 1 ) || ( ( RANDR_MAJOR == 1 ) && ( RANDR_MINOR >= 1 ) )\r
138         if(use_rate)\r
139             result = XRRSetScreenConfigAndRate(fgDisplay.pDisplay.Display, xrr_config,\r
140                     fgDisplay.pDisplay.RootWindow, res_idx, rot, rate, timestamp);\r
141         else\r
142 #endif\r
143             result = XRRSetScreenConfig(fgDisplay.pDisplay.Display, xrr_config,\r
144                     fgDisplay.pDisplay.RootWindow, res_idx, rot, timestamp);\r
145 \r
146     } while(result == RRSetConfigInvalidTime);\r
147 \r
148     if(xrr_config) {\r
149         XRRFreeScreenConfigInfo(xrr_config);\r
150     }\r
151 \r
152     if(result == 0) {\r
153         return 0;\r
154     }\r
155 \r
156 #endif  /* HAVE_X11_EXTENSIONS_XRANDR_H */\r
157     return -1;\r
158 }\r
159 #endif  /* TARGET_HOST_POSIX_X11 */\r
160 \r
161 #if TARGET_HOST_POSIX_X11\r
162 /*\r
163  * Remembers the current visual settings, so that\r
164  * we can change them and restore later...\r
165  */\r
166 void fgPlatformRememberState( void )\r
167 {\r
168     int event_base, error_base;\r
169 \r
170     /*\r
171      * Remember the current pointer location before going fullscreen\r
172      * for restoring it later:\r
173      */\r
174     Window junk_window;\r
175     unsigned int junk_mask;\r
176 \r
177     XQueryPointer(fgDisplay.pDisplay.Display, fgDisplay.pDisplay.RootWindow,\r
178             &junk_window, &junk_window,\r
179             &fgDisplay.pDisplay.DisplayPointerX, &fgDisplay.pDisplay.DisplayPointerY,\r
180             &fgDisplay.pDisplay.DisplayPointerX, &fgDisplay.pDisplay.DisplayPointerY, &junk_mask);\r
181 \r
182 #   ifdef HAVE_X11_EXTENSIONS_XRANDR_H\r
183     if(XRRQueryExtension(fgDisplay.pDisplay.Display, &event_base, &error_base)) {\r
184         XRRScreenConfiguration *xrr_config;\r
185         XRRScreenSize *ssizes;\r
186         Rotation rot;\r
187         int ssize_count, curr;\r
188 \r
189         if((xrr_config = XRRGetScreenInfo(fgDisplay.pDisplay.Display, fgDisplay.pDisplay.RootWindow))) {\r
190             ssizes = XRRConfigSizes(xrr_config, &ssize_count);\r
191             curr = XRRConfigCurrentConfiguration(xrr_config, &rot);\r
192 \r
193             fgDisplay.pDisplay.prev_xsz = ssizes[curr].width;\r
194             fgDisplay.pDisplay.prev_ysz = ssizes[curr].height;\r
195             fgDisplay.pDisplay.prev_refresh = -1;\r
196 \r
197 #       if ( RANDR_MAJOR >= 1 ) || ( ( RANDR_MAJOR == 1 ) && ( RANDR_MINOR >= 1 ) )\r
198             if(fgState.GameModeRefresh != -1) {\r
199                 fgDisplay.pDisplay.prev_refresh = XRRConfigCurrentRate(xrr_config);\r
200             }\r
201 #       endif\r
202 \r
203             fgDisplay.pDisplay.prev_size_valid = 1;\r
204 \r
205             XRRFreeScreenConfigInfo(xrr_config);\r
206         }\r
207     }\r
208 #   endif\r
209 \r
210     /*\r
211      * This highly depends on the XFree86 extensions,\r
212      * not approved as X Consortium standards\r
213      */\r
214 #   ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H\r
215     if(!XF86VidModeQueryExtension(fgDisplay.pDisplay.Display, &event_base, &error_base)) {\r
216         return;\r
217     }\r
218 \r
219     /*\r
220      * Remember the current ViewPort location of the screen to be able to\r
221      * restore the ViewPort on LeaveGameMode():\r
222      */\r
223     if( !XF86VidModeGetViewPort(\r
224              fgDisplay.pDisplay.Display,\r
225              fgDisplay.pDisplay.Screen,\r
226              &fgDisplay.pDisplay.DisplayViewPortX,\r
227              &fgDisplay.pDisplay.DisplayViewPortY ) )\r
228         fgWarning( "XF86VidModeGetViewPort failed" );\r
229 \r
230 \r
231     /* Query the current display settings: */\r
232     fgDisplay.pDisplay.DisplayModeValid =\r
233       XF86VidModeGetModeLine(\r
234         fgDisplay.pDisplay.Display,\r
235         fgDisplay.pDisplay.Screen,\r
236         &fgDisplay.pDisplay.DisplayModeClock,\r
237         &fgDisplay.pDisplay.DisplayMode\r
238     );\r
239 \r
240     if( !fgDisplay.pDisplay.DisplayModeValid )\r
241         fgWarning( "XF86VidModeGetModeLine failed" );\r
242 #   endif\r
243 \r
244 }\r
245 #endif\r
246 \r
247 #if TARGET_HOST_POSIX_X11\r
248 /*\r
249  * Restores the previously remembered visual settings\r
250  */\r
251 void fgPlatformRestoreState( void )\r
252 {\r
253     /* Restore the remembered pointer position: */\r
254     XWarpPointer(\r
255         fgDisplay.pDisplay.Display, None, fgDisplay.pDisplay.RootWindow, 0, 0, 0, 0,\r
256         fgDisplay.pDisplay.DisplayPointerX, fgDisplay.pDisplay.DisplayPointerY\r
257     );\r
258 \r
259 \r
260 #   ifdef HAVE_X11_EXTENSIONS_XRANDR_H\r
261     if(fgDisplay.pDisplay.prev_size_valid) {\r
262         if(xrandr_resize(fgDisplay.pDisplay.prev_xsz, fgDisplay.pDisplay.prev_ysz, fgDisplay.pDisplay.prev_refresh, 0) != -1) {\r
263             fgDisplay.pDisplay.prev_size_valid = 0;\r
264 #       ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H\r
265             fgDisplay.pDisplay.DisplayModeValid = 0;\r
266 #       endif\r
267             return;\r
268         }\r
269     }\r
270 #   endif\r
271 \r
272 \r
273 \r
274 #   ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H\r
275     /*\r
276      * This highly depends on the XFree86 extensions,\r
277      * not approved as X Consortium standards\r
278      */\r
279 \r
280     if( fgDisplay.pDisplay.DisplayModeValid )\r
281     {\r
282         XF86VidModeModeInfo** displayModes;\r
283         int i, displayModesCount;\r
284 \r
285         if( !XF86VidModeGetAllModeLines(\r
286                  fgDisplay.pDisplay.Display,\r
287                  fgDisplay.pDisplay.Screen,\r
288                  &displayModesCount,\r
289                  &displayModes ) )\r
290         {\r
291             fgWarning( "XF86VidModeGetAllModeLines failed" );\r
292             return;\r
293         }\r
294 \r
295 \r
296         /*\r
297          * Check every of the modes looking for one that matches our demands.\r
298          * If we find one, switch to it and restore the remembered viewport.\r
299          */\r
300         for( i = 0; i < displayModesCount; i++ )\r
301         {\r
302             if(displayModes[ i ]->hdisplay == fgDisplay.pDisplay.DisplayMode.hdisplay &&\r
303                displayModes[ i ]->vdisplay == fgDisplay.pDisplay.DisplayMode.vdisplay &&\r
304                displayModes[ i ]->dotclock == fgDisplay.pDisplay.DisplayModeClock )\r
305             {\r
306                 if( !XF86VidModeSwitchToMode(\r
307                          fgDisplay.pDisplay.Display,\r
308                          fgDisplay.pDisplay.Screen,\r
309                          displayModes[ i ] ) )\r
310                 {\r
311                     fgWarning( "XF86VidModeSwitchToMode failed" );\r
312                     break;\r
313                 }\r
314 \r
315                 if( !XF86VidModeSetViewPort(\r
316                          fgDisplay.pDisplay.Display,\r
317                          fgDisplay.pDisplay.Screen,\r
318                          fgDisplay.pDisplay.DisplayViewPortX,\r
319                          fgDisplay.pDisplay.DisplayViewPortY ) )\r
320                     fgWarning( "XF86VidModeSetViewPort failed" );\r
321 \r
322 \r
323                 /*\r
324                  * For the case this would be the last X11 call the application\r
325                  * calls exit() we've to flush the X11 output queue to have the\r
326                  * commands sent to the X server before the application exits.\r
327                  */\r
328                 XFlush( fgDisplay.pDisplay.Display );\r
329 \r
330                 fgDisplay.pDisplay.DisplayModeValid = 0;\r
331 #       ifdef HAVE_X11_EXTENSIONS_XRANDR_H\r
332                 fgDisplay.pDisplay.prev_size_valid = 0;\r
333 #       endif\r
334 \r
335                 break;\r
336             }\r
337         }\r
338         XFree( displayModes );\r
339     }\r
340 \r
341 #   endif\r
342 \r
343 }\r
344 #endif\r
345 \r
346 #if TARGET_HOST_POSIX_X11\r
347 #ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H\r
348 \r
349 /*\r
350  * Checks a single display mode settings against user's preferences.\r
351  */\r
352 static GLboolean fghCheckDisplayMode( int width, int height, int depth, int refresh )\r
353 {\r
354     /* The desired values should be stored in fgState structure... */\r
355     return ( width == fgState.GameModeSize.X ) &&\r
356            ( height == fgState.GameModeSize.Y ) &&\r
357            ( depth == fgState.GameModeDepth ) &&\r
358            ( refresh == fgState.GameModeRefresh );\r
359 }\r
360 \r
361 /*\r
362  * Checks all display modes settings against user's preferences.\r
363  * Returns the mode number found or -1 if none could be found.\r
364  */\r
365 static int fghCheckDisplayModes( GLboolean exactMatch, int displayModesCount, XF86VidModeModeInfo** displayModes )\r
366 {\r
367     int i;\r
368     for( i = 0; i < displayModesCount; i++ )\r
369     {\r
370         /* Compute the displays refresh rate, dotclock comes in kHz. */\r
371         int refresh = ( displayModes[ i ]->dotclock * 1000 ) /\r
372                       ( displayModes[ i ]->htotal * displayModes[ i ]->vtotal );\r
373 \r
374         if( fghCheckDisplayMode( displayModes[ i ]->hdisplay,\r
375                                  displayModes[ i ]->vdisplay,\r
376                                  fgState.GameModeDepth,\r
377                                  ( exactMatch ? refresh : fgState.GameModeRefresh ) ) ) {\r
378             if (!exactMatch)\r
379             {\r
380                 /* Update the chosen refresh rate, otherwise a\r
381                  * glutGameModeGet(GLUT_GAME_MODE_REFRESH_RATE) would not\r
382                  * return the right values\r
383                  */\r
384                 fgState.GameModeRefresh = refresh;\r
385             }\r
386 \r
387             return i;\r
388         }\r
389     }\r
390     return -1;\r
391 }\r
392 \r
393 #endif\r
394 #endif\r
395 \r
396 #if TARGET_HOST_POSIX_X11\r
397 \r
398 /*\r
399  * Changes the current display mode to match user's settings\r
400  */\r
401 GLboolean fgPlatformChangeDisplayMode( GLboolean haveToTest )\r
402 {\r
403     GLboolean success = GL_FALSE;\r
404     /* first try to use XRandR, then fallback to XF86VidMode */\r
405 #   ifdef HAVE_X11_EXTENSIONS_XRANDR_H\r
406     if(xrandr_resize(fgState.GameModeSize.X, fgState.GameModeSize.Y,\r
407                 fgState.GameModeRefresh, haveToTest) != -1) {\r
408         return GL_TRUE;\r
409     }\r
410 #   endif\r
411 \r
412 \r
413     /*\r
414      * This highly depends on the XFree86 extensions,\r
415      * not approved as X Consortium standards\r
416      */\r
417 #   ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H\r
418 \r
419     /*\r
420      * This is also used by applications which check modes by calling\r
421      * glutGameModeGet(GLUT_GAME_MODE_POSSIBLE), so allow the check:\r
422      */\r
423     if( haveToTest || fgDisplay.pDisplay.DisplayModeValid )\r
424     {\r
425         XF86VidModeModeInfo** displayModes;\r
426         int i, displayModesCount;\r
427 \r
428         /* If we don't have a valid modeline in the display structure, which\r
429          * can happen if this is called from glutGameModeGet instead of\r
430          * glutEnterGameMode, then we need to query the current mode, to make\r
431          * unspecified settings to default to their current values.\r
432          */\r
433         if(!fgDisplay.pDisplay.DisplayModeValid) {\r
434             if(!XF86VidModeGetModeLine(fgDisplay.pDisplay.Display, fgDisplay.pDisplay.Screen,\r
435                     &fgDisplay.pDisplay.DisplayModeClock, &fgDisplay.pDisplay.DisplayMode)) {\r
436                 return success;\r
437             }\r
438         }\r
439 \r
440         if (fgState.GameModeSize.X == -1)\r
441         {\r
442             fgState.GameModeSize.X = fgDisplay.pDisplay.DisplayMode.hdisplay;\r
443         }\r
444         if (fgState.GameModeSize.Y == -1)\r
445         {\r
446             fgState.GameModeSize.Y = fgDisplay.pDisplay.DisplayMode.vdisplay;\r
447         }\r
448         if (fgState.GameModeDepth == -1)\r
449         {\r
450             /* can't get color depth from this, nor can we change it, do nothing\r
451              * TODO: get with XGetVisualInfo()? but then how to set?\r
452              */\r
453         }\r
454         if (fgState.GameModeRefresh == -1)\r
455         {\r
456             /* Compute the displays refresh rate, dotclock comes in kHz. */\r
457             int refresh = ( fgDisplay.pDisplay.DisplayModeClock * 1000 ) /\r
458                 ( fgDisplay.pDisplay.DisplayMode.htotal * fgDisplay.pDisplay.DisplayMode.vtotal );\r
459 \r
460             fgState.GameModeRefresh = refresh;\r
461         }\r
462 \r
463         /* query all possible display modes */\r
464         if( !XF86VidModeGetAllModeLines(\r
465                  fgDisplay.pDisplay.Display,\r
466                  fgDisplay.pDisplay.Screen,\r
467                  &displayModesCount,\r
468                  &displayModes ) )\r
469         {\r
470             fgWarning( "XF86VidModeGetAllModeLines failed" );\r
471             return success;\r
472         }\r
473 \r
474 \r
475         /*\r
476          * Check every of the modes looking for one that matches our demands,\r
477          * ignoring the refresh rate if no exact match could be found.\r
478          */\r
479         i = fghCheckDisplayModes( GL_TRUE, displayModesCount, displayModes );\r
480         if( i < 0 ) {\r
481             i = fghCheckDisplayModes( GL_FALSE, displayModesCount, displayModes );\r
482         }\r
483         success = ( i < 0 ) ? GL_FALSE : GL_TRUE;\r
484 \r
485         if( !haveToTest && success ) {\r
486             if( !XF86VidModeSwitchToMode(\r
487                      fgDisplay.pDisplay.Display,\r
488                      fgDisplay.pDisplay.Screen,\r
489                      displayModes[ i ] ) )\r
490                 fgWarning( "XF86VidModeSwitchToMode failed" );\r
491         }\r
492 \r
493         XFree( displayModes );\r
494     }\r
495 \r
496 #   endif\r
497 \r
498     return success;\r
499 }\r
500 \r
501 #endif\r
502 \r
503 /* -- INTERFACE FUNCTIONS -------------------------------------------------- */\r
504 \r
505 /*\r
506  * Sets the game mode display string\r
507  */\r
508 void FGAPIENTRY glutGameModeString( const char* string )\r
509 {\r
510     int width = -1, height = -1, depth = -1, refresh = -1;\r
511 \r
512     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutGameModeString" );\r
513 \r
514     /*\r
515      * This one seems a bit easier than glutInitDisplayString. The bad thing\r
516      * about it that I was unable to find the game mode string definition, so\r
517      * that I assumed it is: "[width]x[height]:[depth]@[refresh rate]", which\r
518      * appears in all GLUT game mode programs I have seen to date.\r
519      */\r
520     if( sscanf( string, "%ix%i:%i@%i", &width, &height, &depth, &refresh ) !=\r
521         4 )\r
522         if( sscanf( string, "%ix%i:%i", &width, &height, &depth ) != 3 )\r
523             if( sscanf( string, "%ix%i@%i", &width, &height, &refresh ) != 3 )\r
524                 if( sscanf( string, "%ix%i", &width, &height ) != 2 )\r
525                     if( sscanf( string, ":%i@%i", &depth, &refresh ) != 2 )\r
526                         if( sscanf( string, ":%i", &depth ) != 1 )\r
527                             if( sscanf( string, "@%i", &refresh ) != 1 )\r
528                                 fgWarning(\r
529                                     "unable to parse game mode string `%s'",\r
530                                     string\r
531                                 );\r
532 \r
533     /* All values not specified are now set to -1, which means those\r
534      * aspects of the current display mode are not changed in\r
535      * fgPlatformChangeDisplayMode() above.\r
536      */\r
537     fgState.GameModeSize.X  = width;\r
538     fgState.GameModeSize.Y  = height;\r
539     fgState.GameModeDepth   = depth;\r
540     fgState.GameModeRefresh = refresh;\r
541 }\r
542 \r
543 \r
544 \r
545 /*\r
546  * Enters the game mode\r
547  */\r
548 int FGAPIENTRY glutEnterGameMode( void )\r
549 {\r
550     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutEnterGameMode" );\r
551 \r
552     if( fgStructure.GameModeWindow )\r
553         fgAddToWindowDestroyList( fgStructure.GameModeWindow );\r
554     else\r
555         fgPlatformRememberState( );\r
556 \r
557     if( ! fgPlatformChangeDisplayMode( GL_FALSE ) )\r
558     {\r
559         fgWarning( "failed to change screen settings" );\r
560         return 0;\r
561     }\r
562 \r
563     fgStructure.GameModeWindow = fgCreateWindow(\r
564         NULL, "FREEGLUT", GL_TRUE, 0, 0,\r
565         GL_TRUE, fgState.GameModeSize.X, fgState.GameModeSize.Y,\r
566         GL_TRUE, GL_FALSE\r
567     );\r
568 \r
569     fgStructure.GameModeWindow->State.Width  = fgState.GameModeSize.X;\r
570     fgStructure.GameModeWindow->State.Height = fgState.GameModeSize.Y;\r
571     fgStructure.GameModeWindow->State.NeedToResize = GL_TRUE;\r
572 \r
573 #if TARGET_HOST_POSIX_X11\r
574 \r
575     /*\r
576      * Sync needed to avoid a real race, the Xserver must have really created\r
577      * the window before we can grab the pointer into it:\r
578      */\r
579     XSync( fgDisplay.pDisplay.Display, False );\r
580     /*\r
581      * Grab the pointer to confine it into the window after the calls to\r
582      * XWrapPointer() which ensure that the pointer really enters the window.\r
583      *\r
584      * We also need to wait here until XGrabPointer() returns GrabSuccess,\r
585      * otherwise the new window is not viewable yet and if the next function\r
586      * (XSetInputFocus) is called with a not yet viewable window, it will exit\r
587      * the application which we have to aviod, so wait until it's viewable:\r
588      */\r
589     while( GrabSuccess != XGrabPointer(\r
590                fgDisplay.pDisplay.Display, fgStructure.GameModeWindow->Window.Handle,\r
591                TRUE,\r
592                ButtonPressMask | ButtonReleaseMask | ButtonMotionMask\r
593                | PointerMotionMask,\r
594                GrabModeAsync, GrabModeAsync,\r
595                fgStructure.GameModeWindow->Window.Handle, None, CurrentTime) )\r
596         usleep( 100 );\r
597     /*\r
598      * Change input focus to the new window. This will exit the application\r
599      * if the new window is not viewable yet, see the XGrabPointer loop above.\r
600      */\r
601     XSetInputFocus(\r
602         fgDisplay.pDisplay.Display,\r
603         fgStructure.GameModeWindow->Window.Handle,\r
604         RevertToNone,\r
605         CurrentTime\r
606     );\r
607 \r
608     /* Move the Pointer to the middle of the fullscreen window */\r
609     XWarpPointer(\r
610         fgDisplay.pDisplay.Display,\r
611         None,\r
612         fgDisplay.pDisplay.RootWindow,\r
613         0, 0, 0, 0,\r
614         fgState.GameModeSize.X/2, fgState.GameModeSize.Y/2\r
615     );\r
616 \r
617 #   ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H\r
618 \r
619     if( fgDisplay.pDisplay.DisplayModeValid )\r
620     {\r
621         int x, y;\r
622         Window child;\r
623 \r
624         /* Change to viewport to the window topleft edge: */\r
625         if( !XF86VidModeSetViewPort( fgDisplay.pDisplay.Display, fgDisplay.pDisplay.Screen, 0, 0 ) )\r
626             fgWarning( "XF86VidModeSetViewPort failed" );\r
627 \r
628         /*\r
629          * Final window repositioning: It could be avoided using an undecorated\r
630          * window using override_redirect, but this * would possily require\r
631          * more changes and investigation.\r
632          */\r
633 \r
634         /* Get the current postion of the drawable area on screen */\r
635         XTranslateCoordinates(\r
636             fgDisplay.pDisplay.Display,\r
637             fgStructure.CurrentWindow->Window.Handle,\r
638             fgDisplay.pDisplay.RootWindow,\r
639             0, 0, &x, &y,\r
640             &child\r
641         );\r
642 \r
643         /* Move the decorataions out of the topleft corner of the display */\r
644         XMoveWindow( fgDisplay.pDisplay.Display, fgStructure.CurrentWindow->Window.Handle,\r
645                      -x, -y);\r
646     }\r
647 \r
648 #endif\r
649 \r
650     /* Grab the keyboard, too */\r
651     XGrabKeyboard(\r
652         fgDisplay.pDisplay.Display,\r
653         fgStructure.GameModeWindow->Window.Handle,\r
654         FALSE,\r
655         GrabModeAsync, GrabModeAsync,\r
656         CurrentTime\r
657     );\r
658 \r
659 #endif\r
660 \r
661     return fgStructure.GameModeWindow->ID;\r
662 }\r
663 \r
664 /*\r
665  * Leaves the game mode\r
666  */\r
667 void FGAPIENTRY glutLeaveGameMode( void )\r
668 {\r
669     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutLeaveGameMode" );\r
670 \r
671     freeglut_return_if_fail( fgStructure.GameModeWindow );\r
672 \r
673     fgAddToWindowDestroyList( fgStructure.GameModeWindow );\r
674     fgStructure.GameModeWindow = NULL;\r
675 \r
676 #if TARGET_HOST_POSIX_X11\r
677 \r
678     XUngrabPointer( fgDisplay.pDisplay.Display, CurrentTime );\r
679     XUngrabKeyboard( fgDisplay.pDisplay.Display, CurrentTime );\r
680 \r
681 #endif\r
682 \r
683     fgPlatformRestoreState();\r
684 }\r
685 \r
686 /*\r
687  * Returns information concerning the freeglut game mode\r
688  */\r
689 int FGAPIENTRY glutGameModeGet( GLenum eWhat )\r
690 {\r
691     FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutGameModeGet" );\r
692 \r
693     switch( eWhat )\r
694     {\r
695     case GLUT_GAME_MODE_ACTIVE:\r
696         return !!fgStructure.GameModeWindow;\r
697 \r
698     case GLUT_GAME_MODE_POSSIBLE:\r
699         return fgPlatformChangeDisplayMode( GL_TRUE );\r
700 \r
701     case GLUT_GAME_MODE_WIDTH:\r
702         return fgState.GameModeSize.X;\r
703 \r
704     case GLUT_GAME_MODE_HEIGHT:\r
705         return fgState.GameModeSize.Y;\r
706 \r
707     case GLUT_GAME_MODE_PIXEL_DEPTH:\r
708         return fgState.GameModeDepth;\r
709 \r
710     case GLUT_GAME_MODE_REFRESH_RATE:\r
711         return fgState.GameModeRefresh;\r
712 \r
713     case GLUT_GAME_MODE_DISPLAY_CHANGED:\r
714         /*\r
715          * This is true if the game mode has been activated successfully..\r
716          */\r
717         return !!fgStructure.GameModeWindow;\r
718     }\r
719 \r
720     fgWarning( "Unknown gamemode get: %d", eWhat );\r
721     return -1;\r
722 }\r
723 \r
724 /*** END OF FILE ***/\r