extern void fgPlatformRememberState( void );\r
extern void fgPlatformRestoreState( void );\r
extern GLboolean fgPlatformChangeDisplayMode( GLboolean haveToTest );\r
+extern void fgPlatformEnterGameMode( void );\r
+extern void fgPlatformLeaveGameMode( void );\r
\r
\r
-#if TARGET_HOST_POSIX_X11\r
-static int xrandr_resize(int xsz, int ysz, int rate, int just_checking)\r
-{\r
-#ifdef HAVE_X11_EXTENSIONS_XRANDR_H\r
- int event_base, error_base, ver_major, ver_minor, use_rate;\r
- XRRScreenConfiguration *xrr_config = 0;\r
- Status result = -1;\r
-\r
- /* must check at runtime for the availability of the extension */\r
- if(!XRRQueryExtension(fgDisplay.pDisplay.Display, &event_base, &error_base)) {\r
- return -1;\r
- }\r
-\r
- XRRQueryVersion(fgDisplay.pDisplay.Display, &ver_major, &ver_minor);\r
-\r
- /* we only heed the rate if we CAN actually use it (Xrandr >= 1.1) and\r
- * the user actually cares about it (rate > 0)\r
- */\r
- use_rate = ( rate > 0 ) && ( ( ver_major >= 1 ) ||\r
- ( ( ver_major == 1 ) && ( ver_minor >= 1 ) ) );\r
-\r
- /* this loop is only so that the whole thing will be repeated if someone\r
- * else changes video mode between our query of the current information and\r
- * the attempt to change it.\r
- */\r
- do {\r
- XRRScreenSize *ssizes;\r
- short *rates;\r
- Rotation rot;\r
- int i, ssizes_count, rates_count, curr, res_idx = -1;\r
- Time timestamp, cfg_timestamp;\r
-\r
- if(xrr_config) {\r
- XRRFreeScreenConfigInfo(xrr_config);\r
- }\r
-\r
- if(!(xrr_config = XRRGetScreenInfo(fgDisplay.pDisplay.Display, fgDisplay.pDisplay.RootWindow))) {\r
- fgWarning("XRRGetScreenInfo failed");\r
- break;\r
- }\r
- ssizes = XRRConfigSizes(xrr_config, &ssizes_count);\r
- curr = XRRConfigCurrentConfiguration(xrr_config, &rot);\r
- timestamp = XRRConfigTimes(xrr_config, &cfg_timestamp);\r
-\r
- /* if either of xsz or ysz are unspecified, use the current values */\r
- if(xsz <= 0)\r
- xsz = fgState.GameModeSize.X = ssizes[curr].width;\r
- if(ysz <= 0)\r
- ysz = fgState.GameModeSize.Y = ssizes[curr].height;\r
-\r
-\r
- if(xsz == ssizes[curr].width && ysz == ssizes[curr].height) {\r
- /* no need to switch, we're already in the requested resolution */\r
- res_idx = curr;\r
- } else {\r
- for(i=0; i<ssizes_count; i++) {\r
- if(ssizes[i].width == xsz && ssizes[i].height == ysz) {\r
- res_idx = i;\r
- break; /* found it */\r
- }\r
- }\r
- }\r
- if(res_idx == -1)\r
- break; /* no matching resolution */\r
-\r
-#if ( RANDR_MAJOR >= 1 ) || ( ( RANDR_MAJOR == 1 ) && ( RANDR_MINOR >= 1 ) )\r
- if(use_rate) {\r
- rate = fgState.GameModeRefresh;\r
-\r
- /* for the selected resolution, let's find out if there is\r
- * a matching refresh rate available.\r
- */\r
- rates = XRRConfigRates(xrr_config, res_idx, &rates_count);\r
-\r
- for(i=0; i<rates_count; i++) {\r
- if(rates[i] == rate) {\r
- break;\r
- }\r
- }\r
- if(i == rates_count) {\r
- break; /* no matching rate */\r
- }\r
- }\r
-#endif\r
-\r
- if(just_checking) {\r
- result = 0;\r
- break;\r
- }\r
-\r
-#if ( RANDR_MAJOR >= 1 ) || ( ( RANDR_MAJOR == 1 ) && ( RANDR_MINOR >= 1 ) )\r
- if(use_rate)\r
- result = XRRSetScreenConfigAndRate(fgDisplay.pDisplay.Display, xrr_config,\r
- fgDisplay.pDisplay.RootWindow, res_idx, rot, rate, timestamp);\r
- else\r
-#endif\r
- result = XRRSetScreenConfig(fgDisplay.pDisplay.Display, xrr_config,\r
- fgDisplay.pDisplay.RootWindow, res_idx, rot, timestamp);\r
-\r
- } while(result == RRSetConfigInvalidTime);\r
-\r
- if(xrr_config) {\r
- XRRFreeScreenConfigInfo(xrr_config);\r
- }\r
-\r
- if(result == 0) {\r
- return 0;\r
- }\r
-\r
-#endif /* HAVE_X11_EXTENSIONS_XRANDR_H */\r
- return -1;\r
-}\r
-#endif /* TARGET_HOST_POSIX_X11 */\r
-\r
-#if TARGET_HOST_POSIX_X11\r
-/*\r
- * Remembers the current visual settings, so that\r
- * we can change them and restore later...\r
- */\r
-void fgPlatformRememberState( void )\r
-{\r
- int event_base, error_base;\r
-\r
- /*\r
- * Remember the current pointer location before going fullscreen\r
- * for restoring it later:\r
- */\r
- Window junk_window;\r
- unsigned int junk_mask;\r
-\r
- XQueryPointer(fgDisplay.pDisplay.Display, fgDisplay.pDisplay.RootWindow,\r
- &junk_window, &junk_window,\r
- &fgDisplay.pDisplay.DisplayPointerX, &fgDisplay.pDisplay.DisplayPointerY,\r
- &fgDisplay.pDisplay.DisplayPointerX, &fgDisplay.pDisplay.DisplayPointerY, &junk_mask);\r
-\r
-# ifdef HAVE_X11_EXTENSIONS_XRANDR_H\r
- if(XRRQueryExtension(fgDisplay.pDisplay.Display, &event_base, &error_base)) {\r
- XRRScreenConfiguration *xrr_config;\r
- XRRScreenSize *ssizes;\r
- Rotation rot;\r
- int ssize_count, curr;\r
-\r
- if((xrr_config = XRRGetScreenInfo(fgDisplay.pDisplay.Display, fgDisplay.pDisplay.RootWindow))) {\r
- ssizes = XRRConfigSizes(xrr_config, &ssize_count);\r
- curr = XRRConfigCurrentConfiguration(xrr_config, &rot);\r
-\r
- fgDisplay.pDisplay.prev_xsz = ssizes[curr].width;\r
- fgDisplay.pDisplay.prev_ysz = ssizes[curr].height;\r
- fgDisplay.pDisplay.prev_refresh = -1;\r
-\r
-# if ( RANDR_MAJOR >= 1 ) || ( ( RANDR_MAJOR == 1 ) && ( RANDR_MINOR >= 1 ) )\r
- if(fgState.GameModeRefresh != -1) {\r
- fgDisplay.pDisplay.prev_refresh = XRRConfigCurrentRate(xrr_config);\r
- }\r
-# endif\r
-\r
- fgDisplay.pDisplay.prev_size_valid = 1;\r
-\r
- XRRFreeScreenConfigInfo(xrr_config);\r
- }\r
- }\r
-# endif\r
-\r
- /*\r
- * This highly depends on the XFree86 extensions,\r
- * not approved as X Consortium standards\r
- */\r
-# ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H\r
- if(!XF86VidModeQueryExtension(fgDisplay.pDisplay.Display, &event_base, &error_base)) {\r
- return;\r
- }\r
-\r
- /*\r
- * Remember the current ViewPort location of the screen to be able to\r
- * restore the ViewPort on LeaveGameMode():\r
- */\r
- if( !XF86VidModeGetViewPort(\r
- fgDisplay.pDisplay.Display,\r
- fgDisplay.pDisplay.Screen,\r
- &fgDisplay.pDisplay.DisplayViewPortX,\r
- &fgDisplay.pDisplay.DisplayViewPortY ) )\r
- fgWarning( "XF86VidModeGetViewPort failed" );\r
-\r
-\r
- /* Query the current display settings: */\r
- fgDisplay.pDisplay.DisplayModeValid =\r
- XF86VidModeGetModeLine(\r
- fgDisplay.pDisplay.Display,\r
- fgDisplay.pDisplay.Screen,\r
- &fgDisplay.pDisplay.DisplayModeClock,\r
- &fgDisplay.pDisplay.DisplayMode\r
- );\r
-\r
- if( !fgDisplay.pDisplay.DisplayModeValid )\r
- fgWarning( "XF86VidModeGetModeLine failed" );\r
-# endif\r
-\r
-}\r
-#endif\r
-\r
-#if TARGET_HOST_POSIX_X11\r
-/*\r
- * Restores the previously remembered visual settings\r
- */\r
-void fgPlatformRestoreState( void )\r
-{\r
- /* Restore the remembered pointer position: */\r
- XWarpPointer(\r
- fgDisplay.pDisplay.Display, None, fgDisplay.pDisplay.RootWindow, 0, 0, 0, 0,\r
- fgDisplay.pDisplay.DisplayPointerX, fgDisplay.pDisplay.DisplayPointerY\r
- );\r
-\r
-\r
-# ifdef HAVE_X11_EXTENSIONS_XRANDR_H\r
- if(fgDisplay.pDisplay.prev_size_valid) {\r
- if(xrandr_resize(fgDisplay.pDisplay.prev_xsz, fgDisplay.pDisplay.prev_ysz, fgDisplay.pDisplay.prev_refresh, 0) != -1) {\r
- fgDisplay.pDisplay.prev_size_valid = 0;\r
-# ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H\r
- fgDisplay.pDisplay.DisplayModeValid = 0;\r
-# endif\r
- return;\r
- }\r
- }\r
-# endif\r
-\r
-\r
-\r
-# ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H\r
- /*\r
- * This highly depends on the XFree86 extensions,\r
- * not approved as X Consortium standards\r
- */\r
-\r
- if( fgDisplay.pDisplay.DisplayModeValid )\r
- {\r
- XF86VidModeModeInfo** displayModes;\r
- int i, displayModesCount;\r
-\r
- if( !XF86VidModeGetAllModeLines(\r
- fgDisplay.pDisplay.Display,\r
- fgDisplay.pDisplay.Screen,\r
- &displayModesCount,\r
- &displayModes ) )\r
- {\r
- fgWarning( "XF86VidModeGetAllModeLines failed" );\r
- return;\r
- }\r
-\r
-\r
- /*\r
- * Check every of the modes looking for one that matches our demands.\r
- * If we find one, switch to it and restore the remembered viewport.\r
- */\r
- for( i = 0; i < displayModesCount; i++ )\r
- {\r
- if(displayModes[ i ]->hdisplay == fgDisplay.pDisplay.DisplayMode.hdisplay &&\r
- displayModes[ i ]->vdisplay == fgDisplay.pDisplay.DisplayMode.vdisplay &&\r
- displayModes[ i ]->dotclock == fgDisplay.pDisplay.DisplayModeClock )\r
- {\r
- if( !XF86VidModeSwitchToMode(\r
- fgDisplay.pDisplay.Display,\r
- fgDisplay.pDisplay.Screen,\r
- displayModes[ i ] ) )\r
- {\r
- fgWarning( "XF86VidModeSwitchToMode failed" );\r
- break;\r
- }\r
-\r
- if( !XF86VidModeSetViewPort(\r
- fgDisplay.pDisplay.Display,\r
- fgDisplay.pDisplay.Screen,\r
- fgDisplay.pDisplay.DisplayViewPortX,\r
- fgDisplay.pDisplay.DisplayViewPortY ) )\r
- fgWarning( "XF86VidModeSetViewPort failed" );\r
-\r
-\r
- /*\r
- * For the case this would be the last X11 call the application\r
- * calls exit() we've to flush the X11 output queue to have the\r
- * commands sent to the X server before the application exits.\r
- */\r
- XFlush( fgDisplay.pDisplay.Display );\r
-\r
- fgDisplay.pDisplay.DisplayModeValid = 0;\r
-# ifdef HAVE_X11_EXTENSIONS_XRANDR_H\r
- fgDisplay.pDisplay.prev_size_valid = 0;\r
-# endif\r
-\r
- break;\r
- }\r
- }\r
- XFree( displayModes );\r
- }\r
-\r
-# endif\r
-\r
-}\r
-#endif\r
-\r
-#if TARGET_HOST_POSIX_X11\r
-#ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H\r
-\r
-/*\r
- * Checks a single display mode settings against user's preferences.\r
- */\r
-static GLboolean fghCheckDisplayMode( int width, int height, int depth, int refresh )\r
-{\r
- /* The desired values should be stored in fgState structure... */\r
- return ( width == fgState.GameModeSize.X ) &&\r
- ( height == fgState.GameModeSize.Y ) &&\r
- ( depth == fgState.GameModeDepth ) &&\r
- ( refresh == fgState.GameModeRefresh );\r
-}\r
-\r
-/*\r
- * Checks all display modes settings against user's preferences.\r
- * Returns the mode number found or -1 if none could be found.\r
- */\r
-static int fghCheckDisplayModes( GLboolean exactMatch, int displayModesCount, XF86VidModeModeInfo** displayModes )\r
-{\r
- int i;\r
- for( i = 0; i < displayModesCount; i++ )\r
- {\r
- /* Compute the displays refresh rate, dotclock comes in kHz. */\r
- int refresh = ( displayModes[ i ]->dotclock * 1000 ) /\r
- ( displayModes[ i ]->htotal * displayModes[ i ]->vtotal );\r
-\r
- if( fghCheckDisplayMode( displayModes[ i ]->hdisplay,\r
- displayModes[ i ]->vdisplay,\r
- fgState.GameModeDepth,\r
- ( exactMatch ? refresh : fgState.GameModeRefresh ) ) ) {\r
- if (!exactMatch)\r
- {\r
- /* Update the chosen refresh rate, otherwise a\r
- * glutGameModeGet(GLUT_GAME_MODE_REFRESH_RATE) would not\r
- * return the right values\r
- */\r
- fgState.GameModeRefresh = refresh;\r
- }\r
-\r
- return i;\r
- }\r
- }\r
- return -1;\r
-}\r
-\r
-#endif\r
-#endif\r
-\r
-#if TARGET_HOST_POSIX_X11\r
-\r
-/*\r
- * Changes the current display mode to match user's settings\r
- */\r
-GLboolean fgPlatformChangeDisplayMode( GLboolean haveToTest )\r
-{\r
- GLboolean success = GL_FALSE;\r
- /* first try to use XRandR, then fallback to XF86VidMode */\r
-# ifdef HAVE_X11_EXTENSIONS_XRANDR_H\r
- if(xrandr_resize(fgState.GameModeSize.X, fgState.GameModeSize.Y,\r
- fgState.GameModeRefresh, haveToTest) != -1) {\r
- return GL_TRUE;\r
- }\r
-# endif\r
-\r
-\r
- /*\r
- * This highly depends on the XFree86 extensions,\r
- * not approved as X Consortium standards\r
- */\r
-# ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H\r
-\r
- /*\r
- * This is also used by applications which check modes by calling\r
- * glutGameModeGet(GLUT_GAME_MODE_POSSIBLE), so allow the check:\r
- */\r
- if( haveToTest || fgDisplay.pDisplay.DisplayModeValid )\r
- {\r
- XF86VidModeModeInfo** displayModes;\r
- int i, displayModesCount;\r
-\r
- /* If we don't have a valid modeline in the display structure, which\r
- * can happen if this is called from glutGameModeGet instead of\r
- * glutEnterGameMode, then we need to query the current mode, to make\r
- * unspecified settings to default to their current values.\r
- */\r
- if(!fgDisplay.pDisplay.DisplayModeValid) {\r
- if(!XF86VidModeGetModeLine(fgDisplay.pDisplay.Display, fgDisplay.pDisplay.Screen,\r
- &fgDisplay.pDisplay.DisplayModeClock, &fgDisplay.pDisplay.DisplayMode)) {\r
- return success;\r
- }\r
- }\r
-\r
- if (fgState.GameModeSize.X == -1)\r
- {\r
- fgState.GameModeSize.X = fgDisplay.pDisplay.DisplayMode.hdisplay;\r
- }\r
- if (fgState.GameModeSize.Y == -1)\r
- {\r
- fgState.GameModeSize.Y = fgDisplay.pDisplay.DisplayMode.vdisplay;\r
- }\r
- if (fgState.GameModeDepth == -1)\r
- {\r
- /* can't get color depth from this, nor can we change it, do nothing\r
- * TODO: get with XGetVisualInfo()? but then how to set?\r
- */\r
- }\r
- if (fgState.GameModeRefresh == -1)\r
- {\r
- /* Compute the displays refresh rate, dotclock comes in kHz. */\r
- int refresh = ( fgDisplay.pDisplay.DisplayModeClock * 1000 ) /\r
- ( fgDisplay.pDisplay.DisplayMode.htotal * fgDisplay.pDisplay.DisplayMode.vtotal );\r
-\r
- fgState.GameModeRefresh = refresh;\r
- }\r
-\r
- /* query all possible display modes */\r
- if( !XF86VidModeGetAllModeLines(\r
- fgDisplay.pDisplay.Display,\r
- fgDisplay.pDisplay.Screen,\r
- &displayModesCount,\r
- &displayModes ) )\r
- {\r
- fgWarning( "XF86VidModeGetAllModeLines failed" );\r
- return success;\r
- }\r
-\r
-\r
- /*\r
- * Check every of the modes looking for one that matches our demands,\r
- * ignoring the refresh rate if no exact match could be found.\r
- */\r
- i = fghCheckDisplayModes( GL_TRUE, displayModesCount, displayModes );\r
- if( i < 0 ) {\r
- i = fghCheckDisplayModes( GL_FALSE, displayModesCount, displayModes );\r
- }\r
- success = ( i < 0 ) ? GL_FALSE : GL_TRUE;\r
-\r
- if( !haveToTest && success ) {\r
- if( !XF86VidModeSwitchToMode(\r
- fgDisplay.pDisplay.Display,\r
- fgDisplay.pDisplay.Screen,\r
- displayModes[ i ] ) )\r
- fgWarning( "XF86VidModeSwitchToMode failed" );\r
- }\r
-\r
- XFree( displayModes );\r
- }\r
-\r
-# endif\r
-\r
- return success;\r
-}\r
-\r
-#endif\r
-\r
/* -- INTERFACE FUNCTIONS -------------------------------------------------- */\r
\r
/*\r
fgStructure.GameModeWindow->State.Height = fgState.GameModeSize.Y;\r
fgStructure.GameModeWindow->State.NeedToResize = GL_TRUE;\r
\r
-#if TARGET_HOST_POSIX_X11\r
-\r
- /*\r
- * Sync needed to avoid a real race, the Xserver must have really created\r
- * the window before we can grab the pointer into it:\r
- */\r
- XSync( fgDisplay.pDisplay.Display, False );\r
- /*\r
- * Grab the pointer to confine it into the window after the calls to\r
- * XWrapPointer() which ensure that the pointer really enters the window.\r
- *\r
- * We also need to wait here until XGrabPointer() returns GrabSuccess,\r
- * otherwise the new window is not viewable yet and if the next function\r
- * (XSetInputFocus) is called with a not yet viewable window, it will exit\r
- * the application which we have to aviod, so wait until it's viewable:\r
- */\r
- while( GrabSuccess != XGrabPointer(\r
- fgDisplay.pDisplay.Display, fgStructure.GameModeWindow->Window.Handle,\r
- TRUE,\r
- ButtonPressMask | ButtonReleaseMask | ButtonMotionMask\r
- | PointerMotionMask,\r
- GrabModeAsync, GrabModeAsync,\r
- fgStructure.GameModeWindow->Window.Handle, None, CurrentTime) )\r
- usleep( 100 );\r
- /*\r
- * Change input focus to the new window. This will exit the application\r
- * if the new window is not viewable yet, see the XGrabPointer loop above.\r
- */\r
- XSetInputFocus(\r
- fgDisplay.pDisplay.Display,\r
- fgStructure.GameModeWindow->Window.Handle,\r
- RevertToNone,\r
- CurrentTime\r
- );\r
-\r
- /* Move the Pointer to the middle of the fullscreen window */\r
- XWarpPointer(\r
- fgDisplay.pDisplay.Display,\r
- None,\r
- fgDisplay.pDisplay.RootWindow,\r
- 0, 0, 0, 0,\r
- fgState.GameModeSize.X/2, fgState.GameModeSize.Y/2\r
- );\r
-\r
-# ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H\r
-\r
- if( fgDisplay.pDisplay.DisplayModeValid )\r
- {\r
- int x, y;\r
- Window child;\r
-\r
- /* Change to viewport to the window topleft edge: */\r
- if( !XF86VidModeSetViewPort( fgDisplay.pDisplay.Display, fgDisplay.pDisplay.Screen, 0, 0 ) )\r
- fgWarning( "XF86VidModeSetViewPort failed" );\r
-\r
- /*\r
- * Final window repositioning: It could be avoided using an undecorated\r
- * window using override_redirect, but this * would possily require\r
- * more changes and investigation.\r
- */\r
-\r
- /* Get the current postion of the drawable area on screen */\r
- XTranslateCoordinates(\r
- fgDisplay.pDisplay.Display,\r
- fgStructure.CurrentWindow->Window.Handle,\r
- fgDisplay.pDisplay.RootWindow,\r
- 0, 0, &x, &y,\r
- &child\r
- );\r
-\r
- /* Move the decorataions out of the topleft corner of the display */\r
- XMoveWindow( fgDisplay.pDisplay.Display, fgStructure.CurrentWindow->Window.Handle,\r
- -x, -y);\r
- }\r
-\r
-#endif\r
-\r
- /* Grab the keyboard, too */\r
- XGrabKeyboard(\r
- fgDisplay.pDisplay.Display,\r
- fgStructure.GameModeWindow->Window.Handle,\r
- FALSE,\r
- GrabModeAsync, GrabModeAsync,\r
- CurrentTime\r
- );\r
-\r
-#endif\r
+ fgPlatformEnterGameMode();\r
\r
return fgStructure.GameModeWindow->ID;\r
}\r
fgAddToWindowDestroyList( fgStructure.GameModeWindow );\r
fgStructure.GameModeWindow = NULL;\r
\r
-#if TARGET_HOST_POSIX_X11\r
-\r
- XUngrabPointer( fgDisplay.pDisplay.Display, CurrentTime );\r
- XUngrabKeyboard( fgDisplay.pDisplay.Display, CurrentTime );\r
-\r
-#endif\r
+ fgPlatformLeaveGameMode();\r
\r
fgPlatformRestoreState();\r
}\r
+/*\r
+ * freeglut_gamemode_x11.c\r
+ *\r
+ * The game mode handling code.\r
+ *\r
+ * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.\r
+ * Written by Pawel W. Olszta, <olszta@sourceforge.net>\r
+ * Copied for Platform code by Evan Felix <karcaw at gmail.com>\r
+ * Creation date: Thur Feb 2 2012\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person obtaining a\r
+ * copy of this software and associated documentation files (the "Software"),\r
+ * to deal in the Software without restriction, including without limitation\r
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
+ * and/or sell copies of the Software, and to permit persons to whom the\r
+ * Software is furnished to do so, subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be included\r
+ * in all copies or substantial portions of the Software.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS\r
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\r
+ * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
+ */\r
+\r
+#include <GL/freeglut.h>\r
+#include "freeglut_internal.h"\r
+\r
+static int xrandr_resize(int xsz, int ysz, int rate, int just_checking)\r
+{\r
+#ifdef HAVE_X11_EXTENSIONS_XRANDR_H\r
+ int event_base, error_base, ver_major, ver_minor, use_rate;\r
+ XRRScreenConfiguration *xrr_config = 0;\r
+ Status result = -1;\r
+\r
+ /* must check at runtime for the availability of the extension */\r
+ if(!XRRQueryExtension(fgDisplay.pDisplay.Display, &event_base, &error_base)) {\r
+ return -1;\r
+ }\r
+\r
+ XRRQueryVersion(fgDisplay.pDisplay.Display, &ver_major, &ver_minor);\r
+\r
+ /* we only heed the rate if we CAN actually use it (Xrandr >= 1.1) and\r
+ * the user actually cares about it (rate > 0)\r
+ */\r
+ use_rate = ( rate > 0 ) && ( ( ver_major >= 1 ) ||\r
+ ( ( ver_major == 1 ) && ( ver_minor >= 1 ) ) );\r
+\r
+ /* this loop is only so that the whole thing will be repeated if someone\r
+ * else changes video mode between our query of the current information and\r
+ * the attempt to change it.\r
+ */\r
+ do {\r
+ XRRScreenSize *ssizes;\r
+ short *rates;\r
+ Rotation rot;\r
+ int i, ssizes_count, rates_count, curr, res_idx = -1;\r
+ Time timestamp, cfg_timestamp;\r
+\r
+ if(xrr_config) {\r
+ XRRFreeScreenConfigInfo(xrr_config);\r
+ }\r
+\r
+ if(!(xrr_config = XRRGetScreenInfo(fgDisplay.pDisplay.Display, fgDisplay.pDisplay.RootWindow))) {\r
+ fgWarning("XRRGetScreenInfo failed");\r
+ break;\r
+ }\r
+ ssizes = XRRConfigSizes(xrr_config, &ssizes_count);\r
+ curr = XRRConfigCurrentConfiguration(xrr_config, &rot);\r
+ timestamp = XRRConfigTimes(xrr_config, &cfg_timestamp);\r
+\r
+ /* if either of xsz or ysz are unspecified, use the current values */\r
+ if(xsz <= 0)\r
+ xsz = fgState.GameModeSize.X = ssizes[curr].width;\r
+ if(ysz <= 0)\r
+ ysz = fgState.GameModeSize.Y = ssizes[curr].height;\r
+\r
+\r
+ if(xsz == ssizes[curr].width && ysz == ssizes[curr].height) {\r
+ /* no need to switch, we're already in the requested resolution */\r
+ res_idx = curr;\r
+ } else {\r
+ for(i=0; i<ssizes_count; i++) {\r
+ if(ssizes[i].width == xsz && ssizes[i].height == ysz) {\r
+ res_idx = i;\r
+ break; /* found it */\r
+ }\r
+ }\r
+ }\r
+ if(res_idx == -1)\r
+ break; /* no matching resolution */\r
+\r
+#if ( RANDR_MAJOR >= 1 ) || ( ( RANDR_MAJOR == 1 ) && ( RANDR_MINOR >= 1 ) )\r
+ if(use_rate) {\r
+ rate = fgState.GameModeRefresh;\r
+\r
+ /* for the selected resolution, let's find out if there is\r
+ * a matching refresh rate available.\r
+ */\r
+ rates = XRRConfigRates(xrr_config, res_idx, &rates_count);\r
+\r
+ for(i=0; i<rates_count; i++) {\r
+ if(rates[i] == rate) {\r
+ break;\r
+ }\r
+ }\r
+ if(i == rates_count) {\r
+ break; /* no matching rate */\r
+ }\r
+ }\r
+#endif\r
+\r
+ if(just_checking) {\r
+ result = 0;\r
+ break;\r
+ }\r
+\r
+#if ( RANDR_MAJOR >= 1 ) || ( ( RANDR_MAJOR == 1 ) && ( RANDR_MINOR >= 1 ) )\r
+ if(use_rate)\r
+ result = XRRSetScreenConfigAndRate(fgDisplay.pDisplay.Display, xrr_config,\r
+ fgDisplay.pDisplay.RootWindow, res_idx, rot, rate, timestamp);\r
+ else\r
+#endif\r
+ result = XRRSetScreenConfig(fgDisplay.pDisplay.Display, xrr_config,\r
+ fgDisplay.pDisplay.RootWindow, res_idx, rot, timestamp);\r
+\r
+ } while(result == RRSetConfigInvalidTime);\r
+\r
+ if(xrr_config) {\r
+ XRRFreeScreenConfigInfo(xrr_config);\r
+ }\r
+\r
+ if(result == 0) {\r
+ return 0;\r
+ }\r
+\r
+#endif /* HAVE_X11_EXTENSIONS_XRANDR_H */\r
+ return -1;\r
+}\r
+\r
+/*\r
+ * Remembers the current visual settings, so that\r
+ * we can change them and restore later...\r
+ */\r
+void fgPlatformRememberState( void )\r
+{\r
+ int event_base, error_base;\r
+\r
+ /*\r
+ * Remember the current pointer location before going fullscreen\r
+ * for restoring it later:\r
+ */\r
+ Window junk_window;\r
+ unsigned int junk_mask;\r
+\r
+ XQueryPointer(fgDisplay.pDisplay.Display, fgDisplay.pDisplay.RootWindow,\r
+ &junk_window, &junk_window,\r
+ &fgDisplay.pDisplay.DisplayPointerX, &fgDisplay.pDisplay.DisplayPointerY,\r
+ &fgDisplay.pDisplay.DisplayPointerX, &fgDisplay.pDisplay.DisplayPointerY, &junk_mask);\r
+\r
+# ifdef HAVE_X11_EXTENSIONS_XRANDR_H\r
+ if(XRRQueryExtension(fgDisplay.pDisplay.Display, &event_base, &error_base)) {\r
+ XRRScreenConfiguration *xrr_config;\r
+ XRRScreenSize *ssizes;\r
+ Rotation rot;\r
+ int ssize_count, curr;\r
+\r
+ if((xrr_config = XRRGetScreenInfo(fgDisplay.pDisplay.Display, fgDisplay.pDisplay.RootWindow))) {\r
+ ssizes = XRRConfigSizes(xrr_config, &ssize_count);\r
+ curr = XRRConfigCurrentConfiguration(xrr_config, &rot);\r
+\r
+ fgDisplay.pDisplay.prev_xsz = ssizes[curr].width;\r
+ fgDisplay.pDisplay.prev_ysz = ssizes[curr].height;\r
+ fgDisplay.pDisplay.prev_refresh = -1;\r
+\r
+# if ( RANDR_MAJOR >= 1 ) || ( ( RANDR_MAJOR == 1 ) && ( RANDR_MINOR >= 1 ) )\r
+ if(fgState.GameModeRefresh != -1) {\r
+ fgDisplay.pDisplay.prev_refresh = XRRConfigCurrentRate(xrr_config);\r
+ }\r
+# endif\r
+\r
+ fgDisplay.pDisplay.prev_size_valid = 1;\r
+\r
+ XRRFreeScreenConfigInfo(xrr_config);\r
+ }\r
+ }\r
+# endif\r
+\r
+ /*\r
+ * This highly depends on the XFree86 extensions,\r
+ * not approved as X Consortium standards\r
+ */\r
+# ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H\r
+ if(!XF86VidModeQueryExtension(fgDisplay.pDisplay.Display, &event_base, &error_base)) {\r
+ return;\r
+ }\r
+\r
+ /*\r
+ * Remember the current ViewPort location of the screen to be able to\r
+ * restore the ViewPort on LeaveGameMode():\r
+ */\r
+ if( !XF86VidModeGetViewPort(\r
+ fgDisplay.pDisplay.Display,\r
+ fgDisplay.pDisplay.Screen,\r
+ &fgDisplay.pDisplay.DisplayViewPortX,\r
+ &fgDisplay.pDisplay.DisplayViewPortY ) )\r
+ fgWarning( "XF86VidModeGetViewPort failed" );\r
+\r
+\r
+ /* Query the current display settings: */\r
+ fgDisplay.pDisplay.DisplayModeValid =\r
+ XF86VidModeGetModeLine(\r
+ fgDisplay.pDisplay.Display,\r
+ fgDisplay.pDisplay.Screen,\r
+ &fgDisplay.pDisplay.DisplayModeClock,\r
+ &fgDisplay.pDisplay.DisplayMode\r
+ );\r
+\r
+ if( !fgDisplay.pDisplay.DisplayModeValid )\r
+ fgWarning( "XF86VidModeGetModeLine failed" );\r
+# endif\r
+\r
+}\r
+\r
+/*\r
+ * Restores the previously remembered visual settings\r
+ */\r
+void fgPlatformRestoreState( void )\r
+{\r
+ /* Restore the remembered pointer position: */\r
+ XWarpPointer(\r
+ fgDisplay.pDisplay.Display, None, fgDisplay.pDisplay.RootWindow, 0, 0, 0, 0,\r
+ fgDisplay.pDisplay.DisplayPointerX, fgDisplay.pDisplay.DisplayPointerY\r
+ );\r
+\r
+\r
+# ifdef HAVE_X11_EXTENSIONS_XRANDR_H\r
+ if(fgDisplay.pDisplay.prev_size_valid) {\r
+ if(xrandr_resize(fgDisplay.pDisplay.prev_xsz, fgDisplay.pDisplay.prev_ysz, fgDisplay.pDisplay.prev_refresh, 0) != -1) {\r
+ fgDisplay.pDisplay.prev_size_valid = 0;\r
+# ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H\r
+ fgDisplay.pDisplay.DisplayModeValid = 0;\r
+# endif\r
+ return;\r
+ }\r
+ }\r
+# endif\r
+\r
+\r
+\r
+# ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H\r
+ /*\r
+ * This highly depends on the XFree86 extensions,\r
+ * not approved as X Consortium standards\r
+ */\r
+\r
+ if( fgDisplay.pDisplay.DisplayModeValid )\r
+ {\r
+ XF86VidModeModeInfo** displayModes;\r
+ int i, displayModesCount;\r
+\r
+ if( !XF86VidModeGetAllModeLines(\r
+ fgDisplay.pDisplay.Display,\r
+ fgDisplay.pDisplay.Screen,\r
+ &displayModesCount,\r
+ &displayModes ) )\r
+ {\r
+ fgWarning( "XF86VidModeGetAllModeLines failed" );\r
+ return;\r
+ }\r
+\r
+\r
+ /*\r
+ * Check every of the modes looking for one that matches our demands.\r
+ * If we find one, switch to it and restore the remembered viewport.\r
+ */\r
+ for( i = 0; i < displayModesCount; i++ )\r
+ {\r
+ if(displayModes[ i ]->hdisplay == fgDisplay.pDisplay.DisplayMode.hdisplay &&\r
+ displayModes[ i ]->vdisplay == fgDisplay.pDisplay.DisplayMode.vdisplay &&\r
+ displayModes[ i ]->dotclock == fgDisplay.pDisplay.DisplayModeClock )\r
+ {\r
+ if( !XF86VidModeSwitchToMode(\r
+ fgDisplay.pDisplay.Display,\r
+ fgDisplay.pDisplay.Screen,\r
+ displayModes[ i ] ) )\r
+ {\r
+ fgWarning( "XF86VidModeSwitchToMode failed" );\r
+ break;\r
+ }\r
+\r
+ if( !XF86VidModeSetViewPort(\r
+ fgDisplay.pDisplay.Display,\r
+ fgDisplay.pDisplay.Screen,\r
+ fgDisplay.pDisplay.DisplayViewPortX,\r
+ fgDisplay.pDisplay.DisplayViewPortY ) )\r
+ fgWarning( "XF86VidModeSetViewPort failed" );\r
+\r
+\r
+ /*\r
+ * For the case this would be the last X11 call the application\r
+ * calls exit() we've to flush the X11 output queue to have the\r
+ * commands sent to the X server before the application exits.\r
+ */\r
+ XFlush( fgDisplay.pDisplay.Display );\r
+\r
+ fgDisplay.pDisplay.DisplayModeValid = 0;\r
+# ifdef HAVE_X11_EXTENSIONS_XRANDR_H\r
+ fgDisplay.pDisplay.prev_size_valid = 0;\r
+# endif\r
+\r
+ break;\r
+ }\r
+ }\r
+ XFree( displayModes );\r
+ }\r
+\r
+# endif\r
+\r
+}\r
+\r
+#ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H\r
+\r
+/*\r
+ * Checks a single display mode settings against user's preferences.\r
+ */\r
+static GLboolean fghCheckDisplayMode( int width, int height, int depth, int refresh )\r
+{\r
+ /* The desired values should be stored in fgState structure... */\r
+ return ( width == fgState.GameModeSize.X ) &&\r
+ ( height == fgState.GameModeSize.Y ) &&\r
+ ( depth == fgState.GameModeDepth ) &&\r
+ ( refresh == fgState.GameModeRefresh );\r
+}\r
+\r
+/*\r
+ * Checks all display modes settings against user's preferences.\r
+ * Returns the mode number found or -1 if none could be found.\r
+ */\r
+static int fghCheckDisplayModes( GLboolean exactMatch, int displayModesCount, XF86VidModeModeInfo** displayModes )\r
+{\r
+ int i;\r
+ for( i = 0; i < displayModesCount; i++ )\r
+ {\r
+ /* Compute the displays refresh rate, dotclock comes in kHz. */\r
+ int refresh = ( displayModes[ i ]->dotclock * 1000 ) /\r
+ ( displayModes[ i ]->htotal * displayModes[ i ]->vtotal );\r
+\r
+ if( fghCheckDisplayMode( displayModes[ i ]->hdisplay,\r
+ displayModes[ i ]->vdisplay,\r
+ fgState.GameModeDepth,\r
+ ( exactMatch ? refresh : fgState.GameModeRefresh ) ) ) {\r
+ if (!exactMatch)\r
+ {\r
+ /* Update the chosen refresh rate, otherwise a\r
+ * glutGameModeGet(GLUT_GAME_MODE_REFRESH_RATE) would not\r
+ * return the right values\r
+ */\r
+ fgState.GameModeRefresh = refresh;\r
+ }\r
+\r
+ return i;\r
+ }\r
+ }\r
+ return -1;\r
+}\r
+\r
+#endif\r
+\r
+/*\r
+ * Changes the current display mode to match user's settings\r
+ */\r
+GLboolean fgPlatformChangeDisplayMode( GLboolean haveToTest )\r
+{\r
+ GLboolean success = GL_FALSE;\r
+ /* first try to use XRandR, then fallback to XF86VidMode */\r
+# ifdef HAVE_X11_EXTENSIONS_XRANDR_H\r
+ if(xrandr_resize(fgState.GameModeSize.X, fgState.GameModeSize.Y,\r
+ fgState.GameModeRefresh, haveToTest) != -1) {\r
+ return GL_TRUE;\r
+ }\r
+# endif\r
+\r
+\r
+ /*\r
+ * This highly depends on the XFree86 extensions,\r
+ * not approved as X Consortium standards\r
+ */\r
+# ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H\r
+\r
+ /*\r
+ * This is also used by applications which check modes by calling\r
+ * glutGameModeGet(GLUT_GAME_MODE_POSSIBLE), so allow the check:\r
+ */\r
+ if( haveToTest || fgDisplay.pDisplay.DisplayModeValid )\r
+ {\r
+ XF86VidModeModeInfo** displayModes;\r
+ int i, displayModesCount;\r
+\r
+ /* If we don't have a valid modeline in the display structure, which\r
+ * can happen if this is called from glutGameModeGet instead of\r
+ * glutEnterGameMode, then we need to query the current mode, to make\r
+ * unspecified settings to default to their current values.\r
+ */\r
+ if(!fgDisplay.pDisplay.DisplayModeValid) {\r
+ if(!XF86VidModeGetModeLine(fgDisplay.pDisplay.Display, fgDisplay.pDisplay.Screen,\r
+ &fgDisplay.pDisplay.DisplayModeClock, &fgDisplay.pDisplay.DisplayMode)) {\r
+ return success;\r
+ }\r
+ }\r
+\r
+ if (fgState.GameModeSize.X == -1)\r
+ {\r
+ fgState.GameModeSize.X = fgDisplay.pDisplay.DisplayMode.hdisplay;\r
+ }\r
+ if (fgState.GameModeSize.Y == -1)\r
+ {\r
+ fgState.GameModeSize.Y = fgDisplay.pDisplay.DisplayMode.vdisplay;\r
+ }\r
+ if (fgState.GameModeDepth == -1)\r
+ {\r
+ /* can't get color depth from this, nor can we change it, do nothing\r
+ * TODO: get with XGetVisualInfo()? but then how to set?\r
+ */\r
+ }\r
+ if (fgState.GameModeRefresh == -1)\r
+ {\r
+ /* Compute the displays refresh rate, dotclock comes in kHz. */\r
+ int refresh = ( fgDisplay.pDisplay.DisplayModeClock * 1000 ) /\r
+ ( fgDisplay.pDisplay.DisplayMode.htotal * fgDisplay.pDisplay.DisplayMode.vtotal );\r
+\r
+ fgState.GameModeRefresh = refresh;\r
+ }\r
+\r
+ /* query all possible display modes */\r
+ if( !XF86VidModeGetAllModeLines(\r
+ fgDisplay.pDisplay.Display,\r
+ fgDisplay.pDisplay.Screen,\r
+ &displayModesCount,\r
+ &displayModes ) )\r
+ {\r
+ fgWarning( "XF86VidModeGetAllModeLines failed" );\r
+ return success;\r
+ }\r
+\r
+\r
+ /*\r
+ * Check every of the modes looking for one that matches our demands,\r
+ * ignoring the refresh rate if no exact match could be found.\r
+ */\r
+ i = fghCheckDisplayModes( GL_TRUE, displayModesCount, displayModes );\r
+ if( i < 0 ) {\r
+ i = fghCheckDisplayModes( GL_FALSE, displayModesCount, displayModes );\r
+ }\r
+ success = ( i < 0 ) ? GL_FALSE : GL_TRUE;\r
+\r
+ if( !haveToTest && success ) {\r
+ if( !XF86VidModeSwitchToMode(\r
+ fgDisplay.pDisplay.Display,\r
+ fgDisplay.pDisplay.Screen,\r
+ displayModes[ i ] ) )\r
+ fgWarning( "XF86VidModeSwitchToMode failed" );\r
+ }\r
+\r
+ XFree( displayModes );\r
+ }\r
+\r
+# endif\r
+\r
+ return success;\r
+}\r
+\r
+\r
+void fgPlatformEnterGameMode( void ) \r
+{\r
+\r
+ /*\r
+ * Sync needed to avoid a real race, the Xserver must have really created\r
+ * the window before we can grab the pointer into it:\r
+ */\r
+ XSync( fgDisplay.pDisplay.Display, False );\r
+ /*\r
+ * Grab the pointer to confine it into the window after the calls to\r
+ * XWrapPointer() which ensure that the pointer really enters the window.\r
+ *\r
+ * We also need to wait here until XGrabPointer() returns GrabSuccess,\r
+ * otherwise the new window is not viewable yet and if the next function\r
+ * (XSetInputFocus) is called with a not yet viewable window, it will exit\r
+ * the application which we have to aviod, so wait until it's viewable:\r
+ */\r
+ while( GrabSuccess != XGrabPointer(\r
+ fgDisplay.pDisplay.Display, fgStructure.GameModeWindow->Window.Handle,\r
+ TRUE,\r
+ ButtonPressMask | ButtonReleaseMask | ButtonMotionMask\r
+ | PointerMotionMask,\r
+ GrabModeAsync, GrabModeAsync,\r
+ fgStructure.GameModeWindow->Window.Handle, None, CurrentTime) )\r
+ usleep( 100 );\r
+ /*\r
+ * Change input focus to the new window. This will exit the application\r
+ * if the new window is not viewable yet, see the XGrabPointer loop above.\r
+ */\r
+ XSetInputFocus(\r
+ fgDisplay.pDisplay.Display,\r
+ fgStructure.GameModeWindow->Window.Handle,\r
+ RevertToNone,\r
+ CurrentTime\r
+ );\r
+\r
+ /* Move the Pointer to the middle of the fullscreen window */\r
+ XWarpPointer(\r
+ fgDisplay.pDisplay.Display,\r
+ None,\r
+ fgDisplay.pDisplay.RootWindow,\r
+ 0, 0, 0, 0,\r
+ fgState.GameModeSize.X/2, fgState.GameModeSize.Y/2\r
+ );\r
+\r
+# ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H\r
+\r
+ if( fgDisplay.pDisplay.DisplayModeValid )\r
+ {\r
+ int x, y;\r
+ Window child;\r
+\r
+ /* Change to viewport to the window topleft edge: */\r
+ if( !XF86VidModeSetViewPort( fgDisplay.pDisplay.Display, fgDisplay.pDisplay.Screen, 0, 0 ) )\r
+ fgWarning( "XF86VidModeSetViewPort failed" );\r
+\r
+ /*\r
+ * Final window repositioning: It could be avoided using an undecorated\r
+ * window using override_redirect, but this * would possily require\r
+ * more changes and investigation.\r
+ */\r
+\r
+ /* Get the current postion of the drawable area on screen */\r
+ XTranslateCoordinates(\r
+ fgDisplay.pDisplay.Display,\r
+ fgStructure.CurrentWindow->Window.Handle,\r
+ fgDisplay.pDisplay.RootWindow,\r
+ 0, 0, &x, &y,\r
+ &child\r
+ );\r
+\r
+ /* Move the decorataions out of the topleft corner of the display */\r
+ XMoveWindow( fgDisplay.pDisplay.Display, fgStructure.CurrentWindow->Window.Handle,\r
+ -x, -y);\r
+ }\r
+\r
+#endif\r
+\r
+ /* Grab the keyboard, too */\r
+ XGrabKeyboard(\r
+ fgDisplay.pDisplay.Display,\r
+ fgStructure.GameModeWindow->Window.Handle,\r
+ FALSE,\r
+ GrabModeAsync, GrabModeAsync,\r
+ CurrentTime\r
+ );\r
+\r
+}\r
+\r
+void fgPlatformLeaveGameMode( void ) \r
+{\r
+ XUngrabPointer( fgDisplay.pDisplay.Display, CurrentTime );\r
+ XUngrabKeyboard( fgDisplay.pDisplay.Display, CurrentTime );\r
+}\r
+\r