1 /***************************************************************************
2                            screen.cpp -- screen init
3                              -------------------
4     created              : Fri Aug 13 22:29:56 CEST 1999
5     copyright            : (C) 1999, 2014 by Eric Espie, Bernhard Wymann
6     email                : torcs@free.fr
7     version              : $Id: screen.cpp,v 1.23.2.11 2014/05/23 08:38:32 berniw Exp $
8 ***************************************************************************/
9 
10 /***************************************************************************
11  *                                                                         *
12  *   This program is free software; you can redistribute it and/or modify  *
13  *   it under the terms of the GNU General Public License as published by  *
14  *   the Free Software Foundation; either version 2 of the License, or     *
15  *   (at your option) any later version.                                   *
16  *                                                                         *
17  ***************************************************************************/
18 
19 /** @file
20     Screen management.
21     @author bernhard Wymann, Eric Espie
22     @version $Id: screen.cpp,v 1.23.2.11 2014/05/23 08:38:32 berniw Exp $
23 */
24 
25 #include <stdio.h>
26 #ifdef WIN32
27 #include <windows.h>
28 #endif
29 #include <GL/glut.h>
30 #include <math.h>
31 #ifndef WIN32
32 #include <unistd.h>
33 #else
34 #include <process.h>
35 #endif /* WIN32 */
36 
37 #include <tgfclient.h>
38 #include <portability.h>
39 #include <musicplayer/musicplayer.h>
40 #include <portability.h>
41 
42 #include "gui.h"
43 #include "fg_gm.h"
44 #include "glfeatures.h"
45 
46 //#ifndef WIN32
47 //#define USE_RANDR_EXT
48 //#endif // WIN32
49 
50 #ifdef USE_RANDR_EXT
51 #include <GL/glx.h>
52 #include <X11/Xlib.h>
53 #include <X11/Xatom.h>
54 #include <X11/keysym.h>
55 #include <X11/extensions/Xrandr.h>
56 #endif // USE_RANDR_EXT
57 
58 static int GfScrWidth;
59 static int GfScrHeight;
60 static int GfViewWidth;
61 static int GfViewHeight;
62 static int GfScrCenX;
63 static int GfScrCenY;
64 
65 static void	*scrHandle = NULL;
66 
67 static int usedGM = 0;
68 #if !defined(FREEGLUT) && !defined(WIN32)
69 static int usedFG = 0;
70 #endif
71 
72 #ifdef USE_RANDR_EXT
73 static char	**Res = NULL;
74 static int nbRes = 0;
75 #else // USE_RANDR_EXT
76 static char	*Res[] = {"640x480", "800x600", "1024x768", "1152x768", "1152x864", "1200x854", "1200x960", "1280x720", "1280x1024", "1400x900", "1600x900", "1600x1200", "1680x1050", "1920x1200", "320x200"};
77 static const int nbRes = sizeof(Res) / sizeof(Res[0]);
78 #endif // USE_RANDR_EXT
79 
80 static const char *Mode[] = {"Full-screen mode", "Window mode"};
81 static const char *VInit[] = {GFSCR_VAL_VINIT_COMPATIBLE, GFSCR_VAL_VINIT_BEST};
82 static const char *Depthlist[] = {"24", "32", "16"};
83 
84 //static const int nbRes = sizeof(Res) / sizeof(Res[0]);
85 static const int nbMode = sizeof(Mode) / sizeof(Mode[0]);
86 static const int nbVInit = sizeof(VInit) / sizeof(VInit[0]);
87 static const int nbDepth = sizeof(Depthlist) / sizeof(Depthlist[0]);
88 
89 static int	curRes = 0;
90 static int	curMode = 0;
91 static int	curDepth = 0;
92 static int curVInit = 0;
93 
94 static int	curMaxFreq = 75;
95 #ifdef WIN32
96 static int	MaxFreqId;
97 #endif
98 
99 static int	ResLabelId;
100 static int	DepthLabelId;
101 static int	ModeLabelId;
102 static int VInitLabelId;
103 
104 static float LabelColor[] = {1.0, 0.0, 1.0, 1.0};
105 
106 
107 void
gfScreenInit(void)108 gfScreenInit(void)
109 {
110 #ifdef USE_RANDR_EXT
111 	// Get display, screen and root window handles.
112 	const char *displayname = getenv("DISPLAY");
113 	if (displayname == NULL) {
114 		displayname = strdup(":0.0");
115 	}
116 
117 	Display *display = XOpenDisplay(displayname);
118 
119 	if( display != NULL) {
120 		// If we have a display fill in the resolutions advertised by Xrandr.
121 		int screen = DefaultScreen(display);
122     	Window root = RootWindow(display, screen);
123 
124 		XRRScreenConfiguration *screenconfig = XRRGetScreenInfo (display, root);
125 		if (screenconfig != NULL) {
126 			int i, j, nsize;
127 			XRRScreenSize *sizes = XRRConfigSizes(screenconfig, &nsize);
128 
129 			if (nsize > 0) {
130 				// Check if 320x200, 640x480, 800x600 are available, construct a mode wish list.
131 				int check_resx[] = {320, 640, 800};
132 				int check_resy[] = {240, 480, 600};
133 				bool mode_in_list[] = {false, false, false};
134 				int add_modes = sizeof(check_resx)/sizeof(check_resx[0]);
135 
136 				for (i = 0; i < nsize; i++) {
137 					for (j = 0; j < 3; j++) {
138 						if ((mode_in_list[j] == false) && (sizes[i].width == check_resx[j])) {
139 							if (sizes[i].height == check_resy[j]) {
140 								// Mode already in list.
141 								mode_in_list[j] = true;
142 								add_modes--;
143 							}
144 						}
145 					}
146 				}
147 
148 				const int bufsize = 20;
149 				char buffer[bufsize];
150 				Res = (char**) malloc(sizeof(char *)*(nsize+add_modes));
151 				int resx[nsize+add_modes];
152 				int resy[nsize+add_modes];
153 				for (i = 0; i < nsize+add_modes; i++) {
154 					if (i < nsize) {
155 						// Add mode from screenconfig (system).
156 						snprintf(buffer, bufsize, "%dx%d", sizes[i].width, sizes[i].height);
157 						Res[i] = strndup(buffer, bufsize);
158 						resx[i] = sizes[i].width;
159 						resy[i] = sizes[i].height;
160 					} else {
161 						// Add mode from wish list.
162 						unsigned int j;
163 						for (j = 0; j < sizeof(check_resx)/sizeof(check_resx[0]); j++) {
164 							if (mode_in_list[j] == false) {
165 								mode_in_list[j] = true;
166 								snprintf(buffer, bufsize, "%dx%d", check_resx[j], check_resy[j]);
167 								Res[i] = strndup(buffer, bufsize);
168 								resx[i] = check_resx[j];
169 								resy[i] = check_resy[j];
170 								break;
171 							}
172 						}
173 					}
174 
175 					// Stupid sorting (not much elements, don't worry).
176 					int j;
177 					for (j = i; j > 0; j--) {
178 						if ((resx[j] < resx[j-1]) ||
179 							(resx[j] == resx[j-1] && resy[j] < resy[j-1]))
180 						{
181 							int tx, ty;
182 							char *tc;
183 							tx = resx[j-1];
184 							ty = resy[j-1];
185 							resx[j-1] = resx[j];
186 							resy[j-1] = resy[j];
187 							resx[j] = tx;
188 							resy[j] = ty;
189 							tc = Res[j-1];
190 							Res[j-1] = Res[j];
191 							Res[j] = tc;
192 						} else {
193 							break;
194 						}
195 					}
196 				}
197 
198 				nbRes = nsize + add_modes;
199 			}
200 
201 			XRRFreeScreenConfigInfo(screenconfig);
202 		}
203 		XCloseDisplay(display);
204 	}
205 
206 	if (Res == NULL || nbRes == 0) {
207 		// We failed to get a handle to the display, so fill in some defaults.
208 		GfOut("Failed to initialize resolutions for display '%s'", XDisplayName(displayname));
209 		nbRes = 8;
210 		Res = (char **) malloc(sizeof(char *)*nbRes);
211 		Res[0] = strdup("640x480");
212 		Res[1] = strdup("800x600");
213 		Res[2] = strdup("1024x768");
214 		Res[3] = strdup("1152x864");
215 		Res[4] = strdup("1200x960");
216 		Res[5] = strdup("1280x1024");
217 		Res[6] = strdup("1600x1200");
218 		Res[7] = strdup("320x200");
219 	}
220 #endif // USE_RANDR_EXT
221 }
222 
Reshape(int width,int height)223 static void Reshape(int width, int height)
224 {
225     glViewport( (width-GfViewWidth)/2, (height-GfViewHeight)/2, GfViewWidth,  GfViewHeight);
226     glMatrixMode( GL_PROJECTION );
227     glLoadIdentity();
228     glOrtho( 0.0, 640.0, 0.0, 480.0, -1.0, 1.0 );
229     glMatrixMode( GL_MODELVIEW );
230     glLoadIdentity();
231 
232     GfScrWidth = width;
233     GfScrHeight = height;
234     GfScrCenX = width / 2;
235     GfScrCenY = height / 2;
236 }
237 
GfScrInit(int argc,char * argv[])238 void GfScrInit(int argc, char *argv[])
239 {
240 	int Window;
241 	int xw, yw;
242 	int winX, winY;
243 	void *handle;
244 	int fullscreen;
245 	int maxfreq;
246 	int i, depth;
247 	const int BUFSIZE = 1024;
248 	char buf[BUFSIZE];
249 
250 	snprintf(buf, BUFSIZE, "%s%s", GetLocalDir(), GFSCR_CONF_FILE);
251 	handle = GfParmReadFile(buf, GFPARM_RMODE_STD | GFPARM_RMODE_CREAT);
252 	xw = (int)GfParmGetNum(handle, GFSCR_SECT_PROP, GFSCR_ATT_X, (char*)NULL, 640);
253 	yw = (int)GfParmGetNum(handle, GFSCR_SECT_PROP, GFSCR_ATT_Y, (char*)NULL, 480);
254 	winX = (int)GfParmGetNum(handle, GFSCR_SECT_PROP, GFSCR_ATT_WIN_X, (char*)NULL, xw);
255 	winY = (int)GfParmGetNum(handle, GFSCR_SECT_PROP, GFSCR_ATT_WIN_Y, (char*)NULL, yw);
256 	depth = (int)GfParmGetNum(handle, GFSCR_SECT_PROP, GFSCR_ATT_BPP, (char*)NULL, 32);
257 	maxfreq = (int)GfParmGetNum(handle, GFSCR_SECT_PROP, GFSCR_ATT_MAXREFRESH, (char*)NULL, 160);
258 	GfViewWidth = xw;
259 	GfViewHeight = yw;
260 	GfScrCenX = xw / 2;
261 	GfScrCenY = yw / 2;
262 
263 	// The fullscreen hack must be run before glutInit, such that glut gets the right screen size, etc.
264 	const char* fscr = GfParmGetStr(handle, GFSCR_SECT_PROP, GFSCR_ATT_FSCR, GFSCR_VAL_NO);
265 	fullscreen = 0;
266 #if !defined(FREEGLUT) && !defined(WIN32)
267 	if (strcmp(fscr, GFSCR_VAL_YES) == 0) {	// Resize the screen
268 		GfOut ("Freeglut not detected...\n");
269 		for (i = maxfreq; i > 59; i--) {
270 			snprintf(buf, BUFSIZE, "%dx%d:%d@%d", winX, winY, depth, i);
271 			GfOut("Trying %s mode\n", buf);
272 			fglutGameModeString(buf);
273 			if (fglutEnterGameMode()) {
274 				GfOut("OK done for %s\n", buf);
275 				usedFG = 1;
276 				break;
277 			}
278 		}
279 	}
280 #endif
281 
282 	const char* vinit = GfParmGetStr(handle, GFSCR_SECT_PROP, GFSCR_ATT_VINIT, GFSCR_VAL_VINIT_COMPATIBLE);
283 
284     glutInit(&argc, argv);
285 
286 	// Depending on "video mode init" setting try to get the best mode or try to get a mode in a safe way...
287 	// This is a workaround for driver/glut/glx bug, which lie about the capabilites of the visual.
288 
289 	if (strcmp(vinit, GFSCR_VAL_VINIT_BEST) == 0) {
290 
291 		// Try to get "best" videomode, z-buffer >= 24bit, visual with alpha channel,
292 		// antialiasing support.
293 
294 		int visualDepthBits = 24;
295 		bool visualSupportsMultisample = true;
296 		bool visualSupportsAlpha = true;
297 
298 		glutInitDisplayString("rgba double depth>=24 samples alpha");
299 
300 		if (!glutGet(GLUT_DISPLAY_MODE_POSSIBLE)) {
301 			// Failed, try without antialiasing support.
302 			visualDepthBits = 24;
303 			visualSupportsMultisample = false;
304 			visualSupportsAlpha = true;
305 			glutInitDisplayString("rgba double depth>=24 alpha");
306 		}
307 
308 		if (!glutGet(GLUT_DISPLAY_MODE_POSSIBLE)) {
309 			// Failed, try without alpha channel.
310 			visualDepthBits = 24;
311 			visualSupportsMultisample = true;
312 			visualSupportsAlpha = false;
313 			glutInitDisplayString("rgb double depth>=24 samples");
314 		}
315 
316 		if (!glutGet(GLUT_DISPLAY_MODE_POSSIBLE)) {
317 			// Failed, try without antialiasing and alpha support.
318 			visualDepthBits = 24;
319 			visualSupportsMultisample = false;
320 			visualSupportsAlpha = false;
321 			glutInitDisplayString("rgb double depth>=24");
322 		}
323 
324 		if (!glutGet(GLUT_DISPLAY_MODE_POSSIBLE)) {
325 			// Failed, try without 24 bit z-Buffer and without antialiasing.
326 			visualDepthBits = 16;
327 			visualSupportsMultisample = false;
328 			visualSupportsAlpha = true;
329 			glutInitDisplayString("rgba double depth>=16 alpha");
330 		}
331 
332 		if (!glutGet(GLUT_DISPLAY_MODE_POSSIBLE)) {
333 			// Failed, try without 24 bit z-Buffer, without antialiasing and without alpha.
334 			visualDepthBits = 16;
335 			visualSupportsMultisample = false;
336 			visualSupportsAlpha = false;
337 			glutInitDisplayString("rgb double depth>=16");
338 		}
339 
340 		printf("Visual Properties Report\n");
341 		printf("------------------------\n");
342 
343 		if (!glutGet(GLUT_DISPLAY_MODE_POSSIBLE)) {
344 			// All failed.
345 			printf("The minimum display requirements are not fulfilled.\n");
346 			printf("We need a double buffered RGB visual with a 16 bit depth buffer at least.\n");
347 			// Try fallback as last resort.
348 			printf("Trying generic initialization, fallback.\n");
349 			glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
350 		} else {
351 			// We have got a mode, report the properties.
352 			printf("z-buffer depth: %d (%s)\n", visualDepthBits, visualDepthBits < 24 ? "bad" : "good");
353 			printf("multisampling : %s\n", visualSupportsMultisample ? "available" : "no");
354 			printf("alpha bits    : %s\n", visualSupportsAlpha ? "available" : "no");
355 			if (visualDepthBits < 24) {
356 				// Show a hint if the z-buffer depth is not optimal.
357 				printf("The z-buffer resolution is below 24 bit, you will experience rendering\n");
358 				printf("artefacts. Try to improve the setup of your graphics board or look\n");
359 				printf("for an alternate driver.\n");
360 			}
361 		}
362 	} else {
363 		// Compatibility mode.
364 		glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
365 		printf("Visual Properties Report\n");
366 		printf("------------------------\n");
367 		printf("Compatibility mode, properties unknown.\n");
368 	}
369 
370 
371 	if (strcmp(fscr, GFSCR_VAL_YES) == 0) {
372 		for (i = maxfreq; i > 59; i--) {
373 			snprintf(buf, BUFSIZE, "%dx%d:%d@%d", winX, winY, depth, i);
374 			glutGameModeString(buf);
375 			GfOut("2 - Trying %s mode\n", buf);
376 			if (glutGameModeGet(GLUT_GAME_MODE_POSSIBLE)) {
377 				GfOut("2- %s mode Possible\n", buf);
378 				glutEnterGameMode();
379 				if (glutGameModeGet(GLUT_GAME_MODE_DISPLAY_CHANGED)) {
380 					GfOut("Use GameMode %s\n", buf);
381 					usedGM = 1;
382 					fullscreen = 1;
383 					break;
384 				} else {
385 					glutLeaveGameMode();
386 				}
387 			}
388 		}
389 	}
390 
391 	if (!fullscreen) {
392 	/* Give an initial size and position so user doesn't have to place window */
393 		glutInitWindowPosition(0, 0);
394 		glutInitWindowSize(winX, winY);
395 		Window = glutCreateWindow(argv[0]);
396 		if (!Window) {
397 			printf("Error, couldn't open window\n");
398 			GfScrShutdown();
399 			exit(1);
400 		}
401 	}
402 
403 	if ((strcmp(fscr, GFSCR_VAL_YES) == 0) && (!fullscreen)) {
404 		/* glutVideoResize(0, 0, winX, winY); */
405 		glutFullScreen();
406 	}
407 
408     GfParmReleaseHandle(handle);
409 
410     glutReshapeFunc( Reshape );
411 
412 	checkGLFeatures();
413 }
414 
415 /** Shutdown the screen
416     @ingroup	screen
417     @return	none
418 */
GfScrShutdown(void)419 void GfScrShutdown(void)
420 {
421     if (usedGM) {
422 	glutLeaveGameMode();
423     }
424 #if !defined(FREEGLUT) && !defined(WIN32)
425     if (usedFG) {
426 	fglutLeaveGameMode();
427     }
428 #endif
429 
430 #ifdef USE_RANDR_EXT
431 	int i;
432 	for (i = 0; i < nbRes; i++) {
433 		free(Res[i]);
434 	}
435 	free(Res);
436 #endif // USE_RANDR_EXT
437 }
438 
439 
440 /** Get the screen and viewport sizes.
441     @ingroup	screen
442     @param	scrw	address of screen with
443     @param	scrh	address of screen height
444     @param	vieww	address of viewport with
445     @param	viewh	address of viewport height
446     @return	none
447  */
GfScrGetSize(int * scrw,int * scrh,int * vieww,int * viewh)448 void GfScrGetSize(int *scrw, int *scrh, int *vieww, int *viewh)
449 {
450     *scrw = GfScrWidth;
451     *scrh = GfScrHeight;
452     *vieww = GfViewWidth;
453     *viewh = GfViewHeight;
454 }
455 
456 static void
saveParams(void)457 saveParams(void)
458 {
459 	int x, y, bpp;
460 
461 	sscanf(Res[curRes], "%dx%d", &x, &y);
462 	sscanf(Depthlist[curDepth], "%d", &bpp);
463 
464 	const int BUFSIZE = 1024;
465 	char buf[BUFSIZE];
466 	snprintf(buf, BUFSIZE, "%s%s", GetLocalDir(), GFSCR_CONF_FILE);
467 	void *paramHdle = GfParmReadFile(buf, GFPARM_RMODE_STD | GFPARM_RMODE_CREAT);
468 
469 	GfParmSetNum(paramHdle, GFSCR_SECT_PROP, GFSCR_ATT_X, (char*)NULL, x);
470 	GfParmSetNum(paramHdle, GFSCR_SECT_PROP, GFSCR_ATT_Y, (char*)NULL, y);
471 	GfParmSetNum(paramHdle, GFSCR_SECT_PROP, GFSCR_ATT_WIN_X, (char*)NULL, x);
472 	GfParmSetNum(paramHdle, GFSCR_SECT_PROP, GFSCR_ATT_WIN_Y, (char*)NULL, y);
473 	GfParmSetNum(paramHdle, GFSCR_SECT_PROP, GFSCR_ATT_BPP, (char*)NULL, bpp);
474 	GfParmSetNum(paramHdle, GFSCR_SECT_PROP, GFSCR_ATT_MAXREFRESH, (char*)NULL, curMaxFreq);
475 
476 	GfParmSetStr(paramHdle, GFSCR_SECT_PROP, GFSCR_ATT_VINIT, VInit[curVInit]);
477 
478 	if (curMode == 0) {
479 		GfParmSetStr(paramHdle, GFSCR_SECT_PROP, GFSCR_ATT_FSCR, "yes");
480 	} else {
481 		GfParmSetStr(paramHdle, GFSCR_SECT_PROP, GFSCR_ATT_FSCR, "no");
482 	}
483 	GfParmWriteFile(NULL, paramHdle, "Screen");
484 	GfParmReleaseHandle(paramHdle);
485 }
486 
487 
488 void
GfScrReinit(void *)489 GfScrReinit(void * /* dummy */)
490 {
491     int retcode = 0;
492 	static const int CMDSIZE = 1024;
493 	char cmd[CMDSIZE];
494 
495 	stopMenuMusic();
496 
497 #ifndef WIN32
498     const char *arg[8];
499     int		curArg;
500 #endif
501 
502     saveParams();
503 
504 #ifdef WIN32
505 	snprintf(cmd, CMDSIZE, "%swtorcs.exe", GetLibDir());
506     int i;
507 	for (i = 0; i < CMDSIZE && cmd[i] != NULL; i++) {
508 		if (cmd[i] == '/') {
509 			cmd[i] = '\\';
510 		}
511 	}
512 
513 	char cmdarg[CMDSIZE];
514 	snprintf(cmdarg, CMDSIZE, "\"%swtorcs.exe\"", GetLibDir());
515 	for (i = 0; i < CMDSIZE && cmdarg[i] != NULL; i++) {
516 		if (cmdarg[i] == '/') {
517 			cmdarg[i] = '\\';
518 		}
519 	}
520 
521 	retcode = execlp(cmd, cmdarg, (const char *)NULL);
522 #else
523 	GfScrShutdown();
524 
525 	snprintf (cmd, CMDSIZE, "%storcs-bin", GetLibDir ());
526 	memset (arg, 0, sizeof (arg));
527 	curArg = 0;
528 	if (GfuiMouseHW) {
529 		arg[curArg++] = "-m";
530 	}
531 
532 	if (strlen(GetLocalDir ())) {
533 		arg[curArg++] = "-l";
534 		arg[curArg++] = GetLocalDir();
535 	}
536 
537 	if (strlen(GetLibDir ())) {
538 		arg[curArg++] = "-L";
539 		arg[curArg++] = GetLibDir ();
540 	}
541 
542 	if (strlen(GetDataDir ())) {
543 		arg[curArg++] = "-D";
544 		arg[curArg++] = GetDataDir ();
545 	}
546 
547 	switch (curArg) {
548 		case 0:
549 			retcode = execlp (cmd, cmd, (const char *)NULL);
550 			break;
551 		case 1:
552 			retcode = execlp (cmd, cmd, arg[0], (const char *)NULL);
553 			break;
554 		case 2:
555 			retcode = execlp (cmd, cmd, arg[0], arg[1], (const char *)NULL);
556 			break;
557 		case 3:
558 			retcode = execlp (cmd, cmd, arg[0], arg[1], arg[2], (const char *)NULL);
559 			break;
560 		case 4:
561 			retcode = execlp (cmd, cmd, arg[0], arg[1], arg[2], arg[3], (const char *)NULL);
562 			break;
563 		case 5:
564 			retcode = execlp (cmd, cmd, arg[0], arg[1], arg[2], arg[3], arg[4], (const char *)NULL);
565 			break;
566 		case 6:
567 			retcode = execlp (cmd, cmd, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], (const char *)NULL);
568 			break;
569 		case 7:
570 			retcode = execlp (cmd, cmd, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], (const char *)NULL);
571 			break;
572 		case 8:
573 			retcode = execlp (cmd, cmd, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], (const char *)NULL);
574 			break;
575 	}
576 
577 
578 #endif
579     if (retcode) {
580 	perror("torcs");
581 	exit(1);
582     }
583 }
584 
585 static void
updateLabelText(void)586 updateLabelText(void)
587 {
588     GfuiLabelSetText (scrHandle, ResLabelId, Res[curRes]);
589     GfuiLabelSetText (scrHandle, DepthLabelId, Depthlist[curDepth]);
590     GfuiLabelSetText (scrHandle, ModeLabelId, Mode[curMode]);
591 #ifdef WIN32
592 	const int BUFSIZE = 1024;
593 	char buf[BUFSIZE];
594 
595 	snprintf(buf, BUFSIZE, "%d", curMaxFreq);
596     GfuiEditboxSetString(scrHandle, MaxFreqId, buf);
597 #endif
598 	GfuiLabelSetText (scrHandle, VInitLabelId, VInit[curVInit]);
599 }
600 
601 static void
ResPrevNext(void * vdelta)602 ResPrevNext(void *vdelta)
603 {
604     long delta = (long)vdelta;
605     curRes += (int)delta;
606     if (curRes < 0) {
607 	curRes = nbRes - 1;
608     } else {
609 	if (curRes >= nbRes) {
610 	    curRes = 0;
611 	}
612     }
613     updateLabelText();
614 }
615 
616 static void
DepthPrevNext(void * vdelta)617 DepthPrevNext(void *vdelta)
618 {
619     long delta = (long)vdelta;
620 
621     curDepth += (int)delta;
622     if (curDepth < 0) {
623 	curDepth = nbDepth - 1;
624     } else {
625 	if (curDepth >= nbDepth) {
626 	    curDepth = 0;
627 	}
628     }
629     updateLabelText();
630 }
631 
632 static void
ModePrevNext(void * vdelta)633 ModePrevNext(void *vdelta)
634 {
635     long delta = (long)vdelta;
636 
637     curMode += (int)delta;
638     if (curMode < 0) {
639 	curMode = nbMode - 1;
640     } else {
641 	if (curMode >= nbMode) {
642 	    curMode = 0;
643 	}
644     }
645     updateLabelText();
646 }
647 
648 
649 static void
VInitPrevNext(void * vdelta)650 VInitPrevNext(void *vdelta)
651 {
652 	long delta = (long)vdelta;
653 
654 	curVInit += (int)delta;
655 	if (curVInit < 0) {
656 		curVInit = nbVInit - 1;
657 	} else {
658 		if (curVInit >= nbVInit) {
659 			curVInit = 0;
660 		}
661 	}
662 	updateLabelText();
663 }
664 
665 
666 static void
initFromConf(void)667 initFromConf(void)
668 {
669 	int x, y, bpp;
670 	int i;
671 	const int BUFSIZE = 1024;
672 	char buf[BUFSIZE];
673 
674 	snprintf(buf, BUFSIZE, "%s%s", GetLocalDir(), GFSCR_CONF_FILE);
675 	void *paramHdle = GfParmReadFile(buf, GFPARM_RMODE_STD | GFPARM_RMODE_CREAT);
676 
677 	x = (int)GfParmGetNum(paramHdle, GFSCR_SECT_PROP, GFSCR_ATT_X, NULL, 640);
678 	y = (int)GfParmGetNum(paramHdle, GFSCR_SECT_PROP, GFSCR_ATT_Y, NULL, 480);
679 
680 	snprintf(buf, BUFSIZE, "%dx%d", x, y);
681 	for (i = 0; i < nbRes; i++) {
682 		if (!strcmp(buf, Res[i])) {
683 			curRes = i;
684 			break;
685 		}
686 	}
687 
688 	if (!strcmp("yes", GfParmGetStr(paramHdle, GFSCR_SECT_PROP, GFSCR_ATT_FSCR, "yes"))) {
689 		curMode = 0;
690 	} else {
691 		curMode = 1;
692 	}
693 
694 	curVInit = 0;
695 	const char *tmp = GfParmGetStr(paramHdle, GFSCR_SECT_PROP, GFSCR_ATT_VINIT, GFSCR_VAL_VINIT_COMPATIBLE);
696 	for (i = 0; i < nbVInit; i++) {
697 		if (strcmp(VInit[i], tmp) == 0) {
698 			curVInit = i;
699 			break;
700 		}
701 	}
702 
703 	bpp = (int)GfParmGetNum(paramHdle, GFSCR_SECT_PROP, GFSCR_ATT_BPP, NULL, 24);
704 	snprintf(buf, BUFSIZE, "%d", bpp);
705 	for (i = 0; i < nbDepth; i++) {
706 		if (!strcmp(buf, Depthlist[i])) {
707 			curDepth = i;
708 			break;
709 		}
710 	}
711 
712 	curMaxFreq = (int)GfParmGetNum(paramHdle, GFSCR_SECT_PROP, GFSCR_ATT_MAXREFRESH, NULL, curMaxFreq);
713 	GfParmReleaseHandle(paramHdle);
714 }
715 
716 #ifdef WIN32
717 static void
ChangeMaxFreq(void *)718 ChangeMaxFreq(void * /* dummy */)
719 {
720     char	*val;
721 	const int BUFSIZE = 1024;
722 	char buf[BUFSIZE];
723 
724     val = GfuiEditboxGetString(scrHandle, MaxFreqId);
725     curMaxFreq = (int)strtol(val, (char **)NULL, 0);
726     snprintf(buf, BUFSIZE, "%d", curMaxFreq);
727     GfuiEditboxSetString(scrHandle, MaxFreqId, buf);
728 }
729 #endif
730 
731 static void
onActivate(void *)732 onActivate(void * /* dummy */)
733 {
734     initFromConf();
735     updateLabelText();
736 }
737 
738 
739 /** Create and activate the video options menu screen.
740     @ingroup	screen
741     @param	precMenu	previous menu to return to
742 */
743 void *
GfScrMenuInit(void * precMenu)744 GfScrMenuInit(void *precMenu)
745 {
746     int		y, x1, x2;
747 
748 #ifndef WIN32
749 	const int yoffset1 = 30, yoffset2 = 60;
750 #else // WIN32
751 	const int yoffset1 = 30, yoffset2 = 40;
752 #endif // WIN32
753 
754     if (scrHandle) return scrHandle;
755 
756     scrHandle = GfuiScreenCreateEx((float*)NULL, NULL, onActivate, NULL, (tfuiCallback)NULL, 1);
757     GfuiTitleCreate(scrHandle, "Screen configuration", 0);
758     GfuiScreenAddBgImg(scrHandle, "data/img/splash-graphic.png");
759 
760     x1 = 200;
761     x2 = 440;
762     y = 400;
763     GfuiLabelCreate(scrHandle,
764 		    "Screen Resolution",
765 		    GFUI_FONT_LARGE,
766 		    320, y, GFUI_ALIGN_HC_VB,
767 		    0);
768 
769     y -= yoffset1; //30;
770     GfuiGrButtonCreate(scrHandle,
771 		       "data/img/arrow-left.png",
772 		       "data/img/arrow-left.png",
773 		       "data/img/arrow-left.png",
774 		       "data/img/arrow-left-pushed.png",
775 		       x1, y, GFUI_ALIGN_HC_VB, 0,
776 		       (void*)-1, ResPrevNext,
777 		       NULL, (tfuiCallback)NULL, (tfuiCallback)NULL);
778     GfuiAddSKey(scrHandle, GLUT_KEY_LEFT, "Previous Resolution", (void*)-1, ResPrevNext, NULL);
779 
780     ResLabelId = GfuiLabelCreate(scrHandle,
781 				 "",
782 				 GFUI_FONT_LARGE_C,
783 				 320, y, GFUI_ALIGN_HC_VB,
784 				 30);
785     GfuiLabelSetColor(scrHandle, ResLabelId, LabelColor);
786 
787     GfuiGrButtonCreate(scrHandle,
788 		       "data/img/arrow-right.png",
789 		       "data/img/arrow-right.png",
790 		       "data/img/arrow-right.png",
791 		       "data/img/arrow-right-pushed.png",
792 		       x2, y, GFUI_ALIGN_HC_VB, 0,
793 		       (void*)1, ResPrevNext,
794 		       NULL, (tfuiCallback)NULL, (tfuiCallback)NULL);
795     GfuiAddSKey(scrHandle, GLUT_KEY_RIGHT, "Next Resolution", (void*)1, ResPrevNext, NULL);
796 
797     y -= yoffset2; //60;
798     GfuiLabelCreate(scrHandle,
799 		    "Color Depth",
800 		    GFUI_FONT_LARGE,
801 		    320, y, GFUI_ALIGN_HC_VB,
802 		    0);
803     y -= yoffset1; //30;
804     GfuiGrButtonCreate(scrHandle,
805 		       "data/img/arrow-left.png",
806 		       "data/img/arrow-left.png",
807 		       "data/img/arrow-left.png",
808 		       "data/img/arrow-left-pushed.png",
809 		       x1, y, GFUI_ALIGN_HC_VB, 0,
810 		       (void*)-1, DepthPrevNext,
811 		       NULL, (tfuiCallback)NULL, (tfuiCallback)NULL);
812 
813     DepthLabelId = GfuiLabelCreate(scrHandle,
814 				   "",
815 				   GFUI_FONT_LARGE_C,
816 				   320, y, GFUI_ALIGN_HC_VB,
817 				   30);
818     GfuiLabelSetColor(scrHandle, DepthLabelId, LabelColor);
819 
820     GfuiGrButtonCreate(scrHandle,
821 		       "data/img/arrow-right.png",
822 		       "data/img/arrow-right.png",
823 		       "data/img/arrow-right.png",
824 		       "data/img/arrow-right-pushed.png",
825 		       x2, y, GFUI_ALIGN_HC_VB, 0,
826 		       (void*)1, DepthPrevNext,
827 		       NULL, (tfuiCallback)NULL, (tfuiCallback)NULL);
828 
829     y -= yoffset2; //60;
830     GfuiLabelCreate(scrHandle,
831 		    "Display Mode",
832 		    GFUI_FONT_LARGE,
833 		    320, y, GFUI_ALIGN_HC_VB,
834 		    0);
835 
836     y -= yoffset1; //30;
837     GfuiGrButtonCreate(scrHandle,
838 		       "data/img/arrow-left.png",
839 		       "data/img/arrow-left.png",
840 		       "data/img/arrow-left.png",
841 		       "data/img/arrow-left-pushed.png",
842 		       x1, y, GFUI_ALIGN_HC_VB, 0,
843 		       (void*)-1, ModePrevNext,
844 		       NULL, (tfuiCallback)NULL, (tfuiCallback)NULL);
845 
846     ModeLabelId = GfuiLabelCreate(scrHandle,
847 				  "",
848 				  GFUI_FONT_LARGE_C,
849 				  320, y, GFUI_ALIGN_HC_VB,
850 				  30);
851     GfuiLabelSetColor(scrHandle, ModeLabelId, LabelColor);
852 
853     GfuiGrButtonCreate(scrHandle,
854 		       "data/img/arrow-right.png",
855 		       "data/img/arrow-right.png",
856 		       "data/img/arrow-right.png",
857 		       "data/img/arrow-right-pushed.png",
858 		       x2, y, GFUI_ALIGN_HC_VB, 0,
859 		       (void*)1, ModePrevNext,
860 		       NULL, (tfuiCallback)NULL, (tfuiCallback)NULL);
861     GfuiAddKey(scrHandle, 'f', "Display Mode", (void*)1, ModePrevNext, NULL);
862 
863 #ifdef WIN32
864     y -= yoffset2; //60;
865     GfuiLabelCreate(scrHandle,
866 		    "Max Frequency",
867 		    GFUI_FONT_LARGE,
868 		    320, y, GFUI_ALIGN_HC_VB,
869 		    0);
870     y -= yoffset1; //30;
871     MaxFreqId = GfuiEditboxCreate(scrHandle, "", GFUI_FONT_MEDIUM_C,
872 				   275, y, 0, 8, NULL, (tfuiCallback)NULL, ChangeMaxFreq);
873 #endif
874 
875 	y -= yoffset2; //60;
876     GfuiLabelCreate(scrHandle,
877 		    "Video Mode Initialization",
878 		    GFUI_FONT_LARGE,
879 		    320, y, GFUI_ALIGN_HC_VB,
880 		    0);
881     y -= yoffset1; //30;
882     GfuiGrButtonCreate(scrHandle,
883 		       "data/img/arrow-left.png",
884 		       "data/img/arrow-left.png",
885 		       "data/img/arrow-left.png",
886 		       "data/img/arrow-left-pushed.png",
887 		       x1, y, GFUI_ALIGN_HC_VB, 0,
888 		       (void*)-1, VInitPrevNext,
889 		       NULL, (tfuiCallback)NULL, (tfuiCallback)NULL);
890 
891     VInitLabelId = GfuiLabelCreate(scrHandle,
892 				  "",
893 				  GFUI_FONT_LARGE_C,
894 				  320, y, GFUI_ALIGN_HC_VB,
895 				  30);
896     GfuiLabelSetColor(scrHandle, VInitLabelId, LabelColor);
897 
898     GfuiGrButtonCreate(scrHandle,
899 		       "data/img/arrow-right.png",
900 		       "data/img/arrow-right.png",
901 		       "data/img/arrow-right.png",
902 		       "data/img/arrow-right-pushed.png",
903 		       x2, y, GFUI_ALIGN_HC_VB, 0,
904 		       (void*)1, VInitPrevNext,
905 		       NULL, (tfuiCallback)NULL, (tfuiCallback)NULL);
906 
907 
908     GfuiAddKey(scrHandle, 13, "Apply Mode", NULL, GfScrReinit, NULL);
909     GfuiButtonCreate(scrHandle, "Apply", GFUI_FONT_LARGE, 210, 40, 150, GFUI_ALIGN_HC_VB, GFUI_MOUSE_UP,
910 		     NULL, GfScrReinit, NULL, (tfuiCallback)NULL, (tfuiCallback)NULL);
911 
912     GfuiAddKey(scrHandle, 27, "Cancel", precMenu, GfuiScreenActivate, NULL);
913     GfuiButtonCreate(scrHandle, "Back", GFUI_FONT_LARGE, 430, 40, 150, GFUI_ALIGN_HC_VB, GFUI_MOUSE_UP,
914 		     precMenu, GfuiScreenActivate, NULL, (tfuiCallback)NULL, (tfuiCallback)NULL);
915 
916     return scrHandle;
917 }
918 
919 
920 
GfuiGlutExtensionSupported(const char * str)921 int GfuiGlutExtensionSupported(const char *str)
922 {
923     return glutExtensionSupported(str);
924 }
925