TORCS  1.3.9
The Open Racing Car Simulator
fg_gm.cpp
Go to the documentation of this file.
1 /***************************************************************************
2 
3  file : fg_gm.cpp
4  created : Sat Mar 8 14:40:50 CET 2003
5  copyright : (C) 2003 by Eric Espi�
6  email : eric.espie@torcs.org
7  version : $Id$
8 
9  ***************************************************************************/
10 
11 /*
12  * The freeglut library private include file.
13  *
14  * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.
15  * Written by Pawel W. Olszta, <olszta@sourceforge.net>
16  * Creation date: Thu Dec 2 1999
17  *
18  * Permission is hereby granted, free of charge, to any person obtaining a
19  * copy of this software and associated documentation files (the "Software"),
20  * to deal in the Software without restriction, including without limitation
21  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
22  * and/or sell copies of the Software, and to permit persons to whom the
23  * Software is furnished to do so, subject to the following conditions:
24  *
25  * The above copyright notice and this permission notice shall be included
26  * in all copies or substantial portions of the Software.
27  *
28  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
29  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
31  * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
32  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
33  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34  */
35 
41 /*
42  2004/10/03 Bernhard Wymann: Added Randr support, bugfixes.
43 */
44 
45 #include <GL/gl.h>
46 #include <GL/glu.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <math.h>
50 
51 #include <tgfclient.h>
52 #include "fg_gm.h"
53 
54 #ifndef WIN32
55 
56 #include <GL/glx.h>
57 #include <X11/Xlib.h>
58 #include <X11/Xatom.h>
59 #include <X11/keysym.h>
60 
61 #ifdef USE_RANDR_EXT
62 #include <X11/extensions/Xrandr.h>
63 #else // USE_RANDR_EXT
64 #include <X11/extensions/xf86vmode.h>
65 #endif // USE_RANDR_EXT
66 
67 
68 static int fgInitDone = 0;
69 
70 typedef struct tagSFG_Display SFG_Display;
72 {
73  Display* display; // The display we are being run in.
74  int Screen; // The screen we are about to use.
75  Window RootWindow; //The screen's root window.
76 
77  int ScreenWidth; // The screen's width in pixels.
78  int ScreenHeight; // The screen's height in pixels.
79  int error_base; // Base error number of the extension.
80  int event_base; // Base event number of the extension.
81 
82 #ifdef USE_RANDR_EXT
83  Rotation rotation; // The rotation mode.
84  short rate; // Display refresh rate.
85 #else //USE_RANDR_EXT
86  XF86VidModeModeLine DisplayMode; // Current screen's display settings.
87  int DisplayModeClock; // The display mode's refresh rate.
88 #endif //USE_RANDR_EXT
89 };
90 
91 
92 /*
93  * A helper structure holding two ints and a boolean
94  */
95 typedef struct tagSFG_XYUse SFG_XYUse;
97 {
98  int X, Y; /* The two integers... */
99 };
100 
101 /*
102  * This structure holds different freeglut settings
103  */
104 typedef struct tagSFG_State SFG_State;
106 {
107  SFG_XYUse GameModeSize; // The game mode screen's dimensions.
108  int GameModeDepth; // The pixel depth for game mode.
109  int GameModeRefresh; // The refresh rate for game mode.
110 };
111 
112 /*
113  * A structure pointed by g_pDisplay holds all information
114  * regarding the display, screen, root window etc.
115  */
117 
118 /*
119  * The settings for the current freeglut session
120  */
122 
123 
124 /*
125  * A call to this function should initialize all the display stuff...
126  */
127 static void fgInitialize(void)
128 {
129  const char* displayName;
130  displayName = getenv("DISPLAY");
131  if (!displayName) {
132  displayName = ":0.0";
133  }
134 
135  // Have the display created.
136  fgDisplay.display = XOpenDisplay(displayName);
137  if(fgDisplay.display == NULL) {
138  // Failed to open a display. That's no good.
139  GfOut( "failed to open display '%s'", XDisplayName( displayName ) );
140  }
141 
142  // Grab the default screen for the display we have just opened.
143  fgDisplay.Screen = DefaultScreen(fgDisplay.display);
144 
145  // The same applying to the root window
147 
148  // Grab the logical screen's geometry.
151 
152 #ifdef USE_RANDR_EXT
153  int major, minor;
154  XRRQueryVersion(fgDisplay.display, &major, &minor);
155  printf("Randr version: %d.%d\n", major, minor);
156  XRRQueryExtension(fgDisplay.display, &fgDisplay.event_base, &fgDisplay.error_base);
157 #else //USE_RANDR_EXT
158  int major, minor;
159  XF86VidModeQueryVersion(fgDisplay.display, &major, &minor);
160  printf("Xxf86vm version: %d.%d\n", major, minor);
161  XF86VidModeQueryExtension(fgDisplay.display, &fgDisplay.event_base, &fgDisplay.error_base);
162 #endif //USE_RANDR_EXT
163 }
164 
165 /*
166  * Remembers the current visual settings, so that
167  * we can change them and restore later...
168  */
169 static void fghRememberState( void )
170 {
171  // This highly depends on the XFree86 extensions, not approved as X Consortium standards.
172  if (!fgInitDone) {
173  fgInitialize();
174  fgInitDone = 1;
175 
176  // Query the current display settings.
177 #ifdef USE_RANDR_EXT
178  XRRScreenConfiguration *screenconfig = XRRGetScreenInfo(fgDisplay.display, fgDisplay.RootWindow);
179  if (screenconfig != NULL) {
180  SizeID size = XRRConfigCurrentConfiguration (screenconfig, &fgDisplay.rotation);
181  int nsize;
182  XRRScreenSize *sizes = XRRConfigSizes(screenconfig, &nsize);
183  fgDisplay.ScreenWidth = sizes[size].width;
184  fgDisplay.ScreenHeight = sizes[size].height;
185  fgDisplay.rate = XRRConfigCurrentRate(screenconfig);
186  //printf("x: %d, y: %d, rate: %d\n", fgDisplay.ScreenWidth, fgDisplay.ScreenHeight, fgDisplay.rate);
187  XRRFreeScreenConfigInfo(screenconfig);
188  } else {
189  // Hmm, what to do here, exit?
190  }
191 #else //USE_RANDR_EXT
192  XF86VidModeGetModeLine(
197  );
198 #endif //USE_RANDR_EXT
199  }
200 }
201 
202 /*
203  * Restores the previously remembered visual settings
204  */
205 static void fghRestoreState( void )
206 {
207 #ifdef USE_RANDR_EXT
208  XRRScreenConfiguration *screenconfig = XRRGetScreenInfo(fgDisplay.display, fgDisplay.RootWindow);
209  if (screenconfig != NULL) {
210  int nsize;
211  XRRScreenSize *sizes = XRRConfigSizes(screenconfig, &nsize);
212  // Search for the display resolution ID for the old video mode.
213  SizeID size;
214  for (size = 0; size < nsize; size++) {
215  if (sizes[size].width == fgDisplay.ScreenWidth && sizes[size].height == fgDisplay.ScreenHeight)
216  break;
217  }
218 
219  XSelectInput(fgDisplay.display, fgDisplay.RootWindow, StructureNotifyMask);
220  XRRSelectInput(fgDisplay.display, fgDisplay.RootWindow, RRScreenChangeNotifyMask);
221  Status status = RRSetConfigFailed;
222  status = XRRSetScreenConfigAndRate(
224  screenconfig,
226  size,
227  fgDisplay.rotation,
228  fgDisplay.rate,
229  CurrentTime
230  );
231 
232  if (status == RRSetConfigSuccess) {
233  XEvent ev;
234  do {
235  XNextEvent(fgDisplay.display, &ev);
236  XRRUpdateConfiguration(&ev);
237  } while ((ev.type != ConfigureNotify) && ((ev.type - fgDisplay.event_base) != RRScreenChangeNotify));
238  XSync(fgDisplay.display, True);
239  }
240  XRRFreeScreenConfigInfo(screenconfig);
241  } else {
242  // Hmm, what to do here, exit?
243  }
244 #else //USE_RANDR_EXT
245  /*
246  * This highly depends on the XFree86 extensions, not approved as X Consortium standards
247  */
248  XF86VidModeModeInfo** displayModes;
249  int i, displayModesCount;
250 
251  /*
252  * Query for all the display available...
253  */
254  XF86VidModeGetAllModeLines(
257  &displayModesCount,
258  &displayModes
259  );
260 
261  /*
262  * Check every of the modes looking for one that matches our demands
263  */
264  for( i=0; i<displayModesCount; i++ ) {
265  if( displayModes[ i ]->hdisplay == fgDisplay.DisplayMode.hdisplay &&
266  displayModes[ i ]->vdisplay == fgDisplay.DisplayMode.vdisplay &&
267  displayModes[ i ]->dotclock == (unsigned int)fgDisplay.DisplayModeClock )
268  {
269  /*
270  * OKi, this is the display mode we have been looking for...
271  */
272  XSync(fgDisplay.display, True);
273  XF86VidModeSwitchToMode(fgDisplay.display, fgDisplay.Screen, displayModes[ i ]);
274  // FIXME: usleep: Hack to avoid screen corruption (does not work always). Do you know a clean solution?
275  usleep(100000);
276  XSync(fgDisplay.display, False);
277  XF86VidModeSetViewPort(fgDisplay.display, fgDisplay.Screen, 0, 0);
278  // FIXME: usleep: Hack to avoid screen corruption (does not work always). Do you know a clean solution?
279  usleep(100000);
280  XSync(fgDisplay.display, False);
281  XWarpPointer(
283  None,
285  0, 0, 0, 0,
288  );
289 
290  XFree(displayModes);
291  if (fgDisplay.DisplayMode.privsize > 0) {
292  // Cannot compile with c++! --> private keyword.
293  //XFree(fgDisplay.DisplayMode.private);
294  }
295  XFlush(fgDisplay.display);
296  return;
297  }
298  }
299  XFree(displayModes);
300  XFlush(fgDisplay.display);
301 #endif //USE_RANDR_EXT
302 }
303 
304 #ifndef USE_RANDR_EXT
305 /*
306  * Checks the display mode settings against user's preferences
307  */
308 static int fghCheckDisplayMode( int width, int height, int depth, int refresh )
309 {
310  /*
311  * The desired values should be stored in fgState structure...
312  */
313  return( (width == fgState.GameModeSize.X) && (height == fgState.GameModeSize.Y) &&
314  (depth == fgState.GameModeDepth) && (refresh == fgState.GameModeRefresh) );
315 }
316 #endif //USE_RANDR_EXT
317 
318 /*
319  * Changes the current display mode to match user's settings
320  */
321 static int fghChangeDisplayMode( int /* haveToTest */ )
322 {
323 #ifdef USE_RANDR_EXT
324  XRRScreenConfiguration *screenconfig = XRRGetScreenInfo(fgDisplay.display, fgDisplay.RootWindow);
325  if (screenconfig != NULL) {
326  int nsize;
327  XRRScreenSize *sizes = XRRConfigSizes(screenconfig, &nsize);
328  // Search for the requested display resolution.
329  SizeID size;
330  for (size = 0; size < nsize; size++) {
331  if (sizes[size].width == fgState.GameModeSize.X && sizes[size].height == fgState.GameModeSize.Y) {
332  break;
333  }
334  }
335 
336  if (size >= nsize) {
337  // We did not find a matching resolution.
338  XRRFreeScreenConfigInfo(screenconfig);
339  return FALSE;
340  } else {
341  // Ok, resolution is ok, now check the refresh rate.
342  int nrate;
343  short *rates = XRRConfigRates(screenconfig, size, &nrate);
344  int rate;
345  for (rate = 0; rate < nrate; rate++) {
346  if (rates[rate] == fgState.GameModeRefresh) {
347  break;
348  }
349  }
350 
351  if (rate >= nrate) {
352  // We did not find a matching refresh rate.
353  XRRFreeScreenConfigInfo(screenconfig);
354  return FALSE;
355  } else {
356  // We have everything, try to switch.
357  XSelectInput(fgDisplay.display, fgDisplay.RootWindow, StructureNotifyMask);
358  XRRSelectInput(fgDisplay.display, fgDisplay.RootWindow, RRScreenChangeNotifyMask);
359  Status status = RRSetConfigFailed;
360  status = XRRSetScreenConfigAndRate(
362  screenconfig,
364  size,
365  fgDisplay.rotation,
366  rates[rate],
367  CurrentTime
368  );
369 
370  XRRFreeScreenConfigInfo(screenconfig);
371 
372  if (status == RRSetConfigSuccess) {
373  XEvent ev;
374  do {
375  XNextEvent(fgDisplay.display, &ev);
376  XRRUpdateConfiguration(&ev);
377  } while ((ev.type != ConfigureNotify) && ((ev.type - fgDisplay.event_base) != RRScreenChangeNotify));
378  XSync(fgDisplay.display, True);
379  return TRUE;
380  } else {
381  return FALSE;
382  }
383  }
384  }
385  }
386 
387  return FALSE;
388 #else //USE_RANDR_EXT
389  /*
390  * This highly depends on the XFree86 extensions, not approved as X Consortium standards
391  */
392  XF86VidModeModeInfo** displayModes;
393  int i, displayModesCount;
394 
395  /*
396  * Query for all the display available...
397  */
398  XF86VidModeGetAllModeLines(
401  &displayModesCount,
402  &displayModes
403  );
404 
405  /*
406  * Check every of the modes looking for one that matches our demands
407  */
408  for( i=0; i<displayModesCount; i++ )
409  {
410  // Compute the displays refresh rate, dotclock comes in kHz.
411  int refresh = displayModes[ i ]->dotclock*1000/(displayModes[ i ]->htotal*displayModes[ i ]->vtotal);
412 
413  if( fghCheckDisplayMode( displayModes[ i ]->hdisplay, displayModes[ i ]->vdisplay,
415  {
416  // Added failure code path, who can guarantee if that works always?
417  // If i == 0, then the videomode we prefer is already set, so the short circuit
418  // "||" does not evaluate the (in this case unnecessary) XF86VidModeSwitchToMode.
419  //XFlush(fgDisplay.display);
420  //XSync(fgDisplay.display, True);
421  if ((i == 0) || (XF86VidModeSwitchToMode(
424  displayModes[ i ]) > 0))
425  {
426  XF86VidModeSetViewPort(
431  );
432 
433  // Move the mouse pointer in the middle of the viewport.
434  XWarpPointer(
436  None,
438  0, 0, 0, 0,
441  );
442  XFree(displayModes);
443  XFlush(fgDisplay.display);
444  return TRUE;
445  } else {
446  XFree(displayModes);
447  XFlush(fgDisplay.display);
448  return( FALSE );
449  }
450  }
451  }
452 
453  /*
454  * Something must have went wrong
455  */
456  XFree(displayModes);
457  XFlush(fgDisplay.display);
458  return( FALSE );
459 #endif //USE_RANDR_EXT
460 }
461 
462 #endif /* WIN32 */
463 
464 /* -- INTERFACE FUNCTIONS -------------------------------------------------- */
465 
466 /*
467  * Sets the game mode display string
468  */
469 void fglutGameModeString( const char* string )
470 {
471 #ifndef WIN32
472  int width = 640, height = 480, depth = 16, refresh = 72;
473 
474  /*
475  * This one seems a bit easier than glutInitDisplayString. The bad thing
476  * about it that I was unable to find the game mode string definition, so
477  * that I assumed it is: "[width]x[height]:[depth]@[refresh rate]", which
478  * appears in all GLUT game mode programs I have seen to date.
479  */
480  if( sscanf( string, "%ix%i:%i@%i", &width, &height, &depth, &refresh ) != 4 )
481  if( sscanf( string, "%ix%i:%i", &width, &height, &depth ) != 3 )
482  if( sscanf( string, "%ix%i@%i", &width, &height, &refresh ) != 3 )
483  if( sscanf( string, "%ix%i", &width, &height ) != 2 )
484  if( sscanf( string, ":%i@%i", &depth, &refresh ) != 2 )
485  if( sscanf( string, ":%i", &depth ) != 1 )
486  if( sscanf( string, "@%i", &refresh ) != 1 )
487  GfOut( "unable to parse game mode string `%s'", string );
488 
489  /*
490  * Hopefully it worked, and if not, we still have the default values
491  */
492  fgState.GameModeSize.X = width;
493  fgState.GameModeSize.Y = height;
494  fgState.GameModeDepth = depth;
496 #endif /* WIN32 */
497 }
498 
499 /*
500  * Enters the game mode
501  */
503 {
504 #ifndef WIN32
505  /*
506  * Remember the current resolution, etc.
507  */
509  /*
510  * We are ready to change the current screen's resolution now
511  */
512  if( fghChangeDisplayMode( FALSE ) == FALSE )
513  {
514  GfOut( "failed to change screen settings" );
515  return( FALSE );
516  }
517 
518  /*
519  * Return successfull
520  */
521  return( TRUE );
522 #else /* WIN32 */
523  return( FALSE );
524 #endif /* WIN32 */
525 }
526 
527 /*
528  * Leaves the game mode
529  */
530 void fglutLeaveGameMode( void )
531 {
532 #ifndef WIN32
533  /*
534  * Then, have the desktop visual settings restored
535  */
536  fghRestoreState();
537 #endif /* WIN32 */
538 }
void fglutLeaveGameMode(void)
Definition: fg_gm.cpp:530
static void fghRestoreState(void)
Definition: fg_gm.cpp:205
static void fgInitialize(void)
Definition: fg_gm.cpp:127
int ScreenHeight
Definition: fg_gm.cpp:78
int DisplayModeClock
Definition: fg_gm.cpp:87
static int fghCheckDisplayMode(int width, int height, int depth, int refresh)
Definition: fg_gm.cpp:308
The Gaming Framework API (client part).
static int fghChangeDisplayMode(int)
Definition: fg_gm.cpp:321
static SFG_Display fgDisplay
Definition: fg_gm.cpp:116
int refresh(tSituation *s)
Definition: grmain.cpp:309
void fglutGameModeString(const char *string)
Definition: fg_gm.cpp:469
int event_base
Definition: fg_gm.cpp:80
static SFG_State fgState
Definition: fg_gm.cpp:121
int fglutEnterGameMode(void)
Definition: fg_gm.cpp:502
#define GfOut
Definition: tgf.h:373
Window RootWindow
Definition: fg_gm.cpp:75
int error_base
Definition: fg_gm.cpp:79
static int fgInitDone
Definition: fg_gm.cpp:68
int GameModeDepth
Definition: fg_gm.cpp:108
static void fghRememberState(void)
Definition: fg_gm.cpp:169
Display * display
Definition: fg_gm.cpp:73
SFG_XYUse GameModeSize
Definition: fg_gm.cpp:107
int GameModeRefresh
Definition: fg_gm.cpp:109
XF86VidModeModeLine DisplayMode
Definition: fg_gm.cpp:86
int ScreenWidth
Definition: fg_gm.cpp:77