-\r
-/* Copyright (c) Mark J. Kilgard, 1998. */\r
-\r
-/* This program is freely distributable without licensing fees\r
- and is provided without guarantee or warrantee expressed or\r
- implied. This program is -not- in the public domain. */\r
-\r
-\r
-#include <assert.h>\r
-#include <stdio.h>\r
-#include <stdlib.h>\r
-#include <string.h>\r
-\r
-#include "glutint.h"\r
-\r
-#if !defined(_WIN32) && !defined(__OS2__)\r
-#include <X11/Xlib.h>\r
-#include <X11/Xatom.h>\r
-\r
-/* SGI optimization introduced in IRIX 6.3 to avoid X server\r
- round trips for interning common X atoms. */\r
-#if defined(_SGI_EXTRA_PREDEFINES) && !defined(NO_FAST_ATOMS)\r
-#include <X11/SGIFastAtom.h>\r
-#else\r
-#define XSGIFastInternAtom(dpy,string,fast_name,how) XInternAtom(dpy,string,how)\r
-#endif\r
-#endif /* not _WIN32 */\r
-\r
-int __glutDisplaySettingsChanged = 0;\r
-static DisplayMode *dmodes, *currentDm = NULL;\r
-static int ndmodes = -1;\r
-GLUTwindow *__glutGameModeWindow = NULL;\r
-\r
-#ifdef TEST\r
-static char *compstr[] =\r
-{\r
- "none", "=", "!=", "<=", ">=", ">", "<", "~"\r
-};\r
-static char *capstr[] =\r
-{\r
- "width", "height", "bpp", "hertz", "num"\r
-};\r
-#endif\r
-\r
-#if defined(__OS2__)\r
-void\r
-#else\r
-void __cdecl\r
-#endif\r
-__glutCloseDownGameMode(void)\r
-{\r
- if (__glutDisplaySettingsChanged) {\r
-#ifdef _WIN32\r
- /* Assumes that display settings have been changed, that\r
- is __glutDisplaySettingsChanged is true. */\r
- ChangeDisplaySettings(NULL, 0);\r
-#endif\r
- __glutDisplaySettingsChanged = 0;\r
- }\r
- __glutGameModeWindow = NULL;\r
-}\r
-\r
-void GLUTAPIENTRY\r
-glutLeaveGameMode(void)\r
-{\r
- if (__glutGameModeWindow == NULL) {\r
- __glutWarning("not in game mode so cannot leave game mode");\r
- return;\r
- }\r
- __glutDestroyWindow(__glutGameModeWindow,\r
- __glutGameModeWindow);\r
- XFlush(__glutDisplay);\r
- __glutGameModeWindow = NULL;\r
-}\r
-\r
-#ifdef _WIN32\r
-\r
-/* Same values as from MSDN's SetDisp.c example. */\r
-#define MIN_WIDTH 400\r
-#define MIN_FREQUENCY 60\r
-\r
-static void\r
-initGameModeSupport(void)\r
-{\r
- DEVMODE dm;\r
- DWORD mode;\r
- int i;\r
-\r
- if (ndmodes >= 0) {\r
- /* ndmodes is initially -1 to indicate no\r
- dmodes allocated yet. */\r
- return;\r
- }\r
-\r
- /* Determine how many display modes there are. */\r
- ndmodes = 0;\r
- mode = 0;\r
- while (EnumDisplaySettings(NULL, mode, &dm)) {\r
- if (dm.dmPelsWidth >= MIN_WIDTH &&\r
- (dm.dmDisplayFrequency == 0 ||\r
- dm.dmDisplayFrequency >= MIN_FREQUENCY)) {\r
- ndmodes++;\r
- }\r
- mode++;\r
- }\r
-\r
- /* Allocate memory for a list of all the display modes. */\r
- dmodes = (DisplayMode*)\r
- malloc(ndmodes * sizeof(DisplayMode));\r
-\r
- /* Now that we know how many display modes to expect,\r
- enumerate them again and save the information in\r
- the list we allocated above. */\r
- i = 0;\r
- mode = 0;\r
- while (EnumDisplaySettings(NULL, mode, &dm)) {\r
- /* Try to reject any display settings that seem unplausible. */\r
- if (dm.dmPelsWidth >= MIN_WIDTH &&\r
- (dm.dmDisplayFrequency == 0 ||\r
- dm.dmDisplayFrequency >= MIN_FREQUENCY)) {\r
- dmodes[i].devmode = dm;\r
- dmodes[i].valid = 1; /* XXX Not used for now. */\r
- dmodes[i].cap[DM_WIDTH] = dm.dmPelsWidth;\r
- dmodes[i].cap[DM_HEIGHT] = dm.dmPelsHeight;\r
- dmodes[i].cap[DM_PIXEL_DEPTH] = dm.dmBitsPerPel;\r
- if (dm.dmDisplayFrequency == 0) {\r
- /* Guess a reasonable guess. */\r
- /* Lame Windows 95 version of EnumDisplaySettings. */\r
- dmodes[i].cap[DM_HERTZ] = 60;\r
- } else {\r
- dmodes[i].cap[DM_HERTZ] = dm.dmDisplayFrequency;\r
- }\r
- i++;\r
- }\r
- mode++;\r
- }\r
-\r
- assert(i == ndmodes);\r
-}\r
-\r
-#else\r
-\r
-/* X Windows version of initGameModeSupport. */\r
-static void\r
-initGameModeSupport(void)\r
-{\r
- if (ndmodes >= 0) {\r
- /* ndmodes is initially -1 to indicate no\r
- dmodes allocated yet. */\r
- return;\r
- }\r
-\r
- /* Determine how many display modes there are. */\r
- ndmodes = 0;\r
-}\r
-\r
-#endif\r
-\r
-/* This routine is based on similiar code in glut_dstr.c */\r
-static DisplayMode *\r
-findMatch(DisplayMode * dmodes, int ndmodes,\r
- Criterion * criteria, int ncriteria)\r
-{\r
- DisplayMode *found;\r
- int *bestScore, *thisScore;\r
- int i, j, numok, result = 0, worse, better;\r
-\r
- found = NULL;\r
- numok = 1; /* "num" capability is indexed from 1,\r
- not 0. */\r
-\r
- /* XXX alloca canidate. */\r
- bestScore = (int *) malloc(ncriteria * sizeof(int));\r
- if (!bestScore) {\r
- __glutFatalError("out of memory.");\r
- }\r
- for (j = 0; j < ncriteria; j++) {\r
- /* Very negative number. */\r
- bestScore[j] = -32768;\r
- }\r
-\r
- /* XXX alloca canidate. */\r
- thisScore = (int *) malloc(ncriteria * sizeof(int));\r
- if (!thisScore) {\r
- __glutFatalError("out of memory.");\r
- }\r
-\r
- for (i = 0; i < ndmodes; i++) {\r
- if (dmodes[i].valid) {\r
- worse = 0;\r
- better = 0;\r
-\r
- for (j = 0; j < ncriteria; j++) {\r
- int cap, cvalue, dvalue;\r
-\r
- cap = criteria[j].capability;\r
- cvalue = criteria[j].value;\r
- if (cap == NUM) {\r
- dvalue = numok;\r
- } else {\r
- dvalue = dmodes[i].cap[cap];\r
- }\r
-#ifdef TEST\r
- if (verbose)\r
- printf(" %s %s %d to %d\n",\r
- capstr[cap], compstr[criteria[j].comparison], cvalue, dvalue);\r
-#endif\r
- switch (criteria[j].comparison) {\r
- case EQ:\r
- result = cvalue == dvalue;\r
- thisScore[j] = 1;\r
- break;\r
- case NEQ:\r
- result = cvalue != dvalue;\r
- thisScore[j] = 1;\r
- break;\r
- case LT:\r
- result = dvalue < cvalue;\r
- thisScore[j] = dvalue - cvalue;\r
- break;\r
- case GT:\r
- result = dvalue > cvalue;\r
- thisScore[j] = dvalue - cvalue;\r
- break;\r
- case LTE:\r
- result = dvalue <= cvalue;\r
- thisScore[j] = dvalue - cvalue;\r
- break;\r
- case GTE:\r
- result = (dvalue >= cvalue);\r
- thisScore[j] = dvalue - cvalue;\r
- break;\r
- case MIN:\r
- result = dvalue >= cvalue;\r
- thisScore[j] = cvalue - dvalue;\r
- break;\r
- }\r
-\r
-#ifdef TEST\r
- if (verbose)\r
- printf(" result=%d score=%d bestScore=%d\n", result, thisScore[j], bestScore[j]);\r
-#endif\r
-\r
- if (result) {\r
- if (better || thisScore[j] > bestScore[j]) {\r
- better = 1;\r
- } else if (thisScore[j] == bestScore[j]) {\r
- /* Keep looking. */\r
- } else {\r
- goto nextDM;\r
- }\r
- } else {\r
- if (cap == NUM) {\r
- worse = 1;\r
- } else {\r
- goto nextDM;\r
- }\r
- }\r
-\r
- }\r
-\r
- if (better && !worse) {\r
- found = &dmodes[i];\r
- for (j = 0; j < ncriteria; j++) {\r
- bestScore[j] = thisScore[j];\r
- }\r
- }\r
- numok++;\r
-\r
- nextDM:;\r
-\r
- }\r
- }\r
- free(bestScore);\r
- free(thisScore);\r
- return found;\r
-}\r
-\r
-/**\r
- * Parses strings in the form of:\r
- * 800x600\r
- * 800x600:16\r
- * 800x600@60\r
- * 800x600:16@60\r
- * @60\r
- * :16\r
- * :16@60\r
- * NOTE that @ before : is not parsed.\r
- */\r
-static int\r
-specialCaseParse(char *word, Criterion * criterion, int mask)\r
-{\r
- char *xstr, *response;\r
- int got;\r
- int width, height, bpp, hertz;\r
-\r
- switch(word[0]) {\r
- case '0':\r
- case '1':\r
- case '2':\r
- case '3':\r
- case '4':\r
- case '5':\r
- case '6':\r
- case '7':\r
- case '8':\r
- case '9':\r
- /* The WWWxHHH case. */\r
- if (mask & (1 << DM_WIDTH)) {\r
- return -1;\r
- }\r
- xstr = strpbrk(&word[1], "x");\r
- if (xstr) {\r
- width = (int) strtol(word, &response, 0);\r
- if (response == word || response[0] != 'x') {\r
- /* Not a valid number OR needs to be followed by 'x'. */\r
- return -1;\r
- }\r
- height = (int) strtol(&xstr[1], &response, 0);\r
- if (response == &xstr[1]) {\r
- /* Not a valid number. */\r
- return -1;\r
- }\r
- criterion[0].capability = DM_WIDTH;\r
- criterion[0].comparison = EQ;\r
- criterion[0].value = width;\r
- criterion[1].capability = DM_HEIGHT;\r
- criterion[1].comparison = EQ;\r
- criterion[1].value = height;\r
- got = specialCaseParse(response,\r
- &criterion[2], 1 << DM_WIDTH);\r
- if (got >= 0) {\r
- return got + 2;\r
- } else {\r
- return -1;\r
- }\r
- }\r
- return -1;\r
- case ':':\r
- /* The :BPP case. */\r
- if (mask & (1 << DM_PIXEL_DEPTH)) {\r
- return -1;\r
- }\r
- bpp = (int) strtol(&word[1], &response, 0);\r
- if (response == &word[1]) {\r
- /* Not a valid number. */\r
- return -1;\r
- }\r
- criterion[0].capability = DM_PIXEL_DEPTH;\r
- criterion[0].comparison = EQ;\r
- criterion[0].value = bpp;\r
- got = specialCaseParse(response,\r
- &criterion[1], (1 << DM_WIDTH) | (1 << DM_PIXEL_DEPTH));\r
- if (got >= 0) {\r
- return got + 1;\r
- } else {\r
- return -1;\r
- }\r
- case '@':\r
- /* The @HZ case. */\r
- if (mask & (1 << DM_HERTZ)) {\r
- return -1;\r
- }\r
- hertz = (int) strtol(&word[1], &response, 0);\r
- if (response == &word[1]) {\r
- /* Not a valid number. */\r
- return -1;\r
- }\r
- criterion[0].capability = DM_HERTZ;\r
- criterion[0].comparison = EQ;\r
- criterion[0].value = hertz;\r
- got = specialCaseParse(response,\r
- &criterion[1], ~DM_HERTZ);\r
- if (got >= 0) {\r
- return got + 1;\r
- } else {\r
- return -1;\r
- }\r
- case '\0':\r
- return 0;\r
- }\r
- return -1;\r
-}\r
-\r
-/* This routine is based on similiar code in glut_dstr.c */\r
-static int\r
-parseCriteria(char *word, Criterion * criterion)\r
-{\r
- char *cstr, *vstr, *response;\r
- int comparator, value = 0;\r
-\r
- cstr = strpbrk(word, "=><!~");\r
- if (cstr) {\r
- switch (cstr[0]) {\r
- case '=':\r
- comparator = EQ;\r
- vstr = &cstr[1];\r
- break;\r
- case '~':\r
- comparator = MIN;\r
- vstr = &cstr[1];\r
- break;\r
- case '>':\r
- if (cstr[1] == '=') {\r
- comparator = GTE;\r
- vstr = &cstr[2];\r
- } else {\r
- comparator = GT;\r
- vstr = &cstr[1];\r
- }\r
- break;\r
- case '<':\r
- if (cstr[1] == '=') {\r
- comparator = LTE;\r
- vstr = &cstr[2];\r
- } else {\r
- comparator = LT;\r
- vstr = &cstr[1];\r
- }\r
- break;\r
- case '!':\r
- if (cstr[1] == '=') {\r
- comparator = NEQ;\r
- vstr = &cstr[2];\r
- } else {\r
- return -1;\r
- }\r
- break;\r
- default:\r
- return -1;\r
- }\r
- value = (int) strtol(vstr, &response, 0);\r
- if (response == vstr) {\r
- /* Not a valid number. */\r
- return -1;\r
- }\r
- *cstr = '\0';\r
- } else {\r
- comparator = NONE;\r
- }\r
- switch (word[0]) {\r
- case 'b':\r
- if (!strcmp(word, "bpp")) {\r
- criterion[0].capability = DM_PIXEL_DEPTH;\r
- if (comparator == NONE) {\r
- return -1;\r
- } else {\r
- criterion[0].comparison = comparator;\r
- criterion[0].value = value;\r
- return 1;\r
- }\r
- }\r
- return -1;\r
- case 'h':\r
- if (!strcmp(word, "height")) {\r
- criterion[0].capability = DM_HEIGHT;\r
- if (comparator == NONE) {\r
- return -1;\r
- } else {\r
- criterion[0].comparison = comparator;\r
- criterion[0].value = value;\r
- return 1;\r
- }\r
- }\r
- if (!strcmp(word, "hertz")) {\r
- criterion[0].capability = DM_HERTZ;\r
- if (comparator == NONE) {\r
- return -1;\r
- } else {\r
- criterion[0].comparison = comparator;\r
- criterion[0].value = value;\r
- return 1;\r
- }\r
- }\r
- return -1;\r
- case 'n':\r
- if (!strcmp(word, "num")) {\r
- criterion[0].capability = DM_NUM;\r
- if (comparator == NONE) {\r
- return -1;\r
- } else {\r
- criterion[0].comparison = comparator;\r
- criterion[0].value = value;\r
- return 1;\r
- }\r
- }\r
- return -1;\r
- case 'w':\r
- if (!strcmp(word, "width")) {\r
- criterion[0].capability = DM_WIDTH;\r
- if (comparator == NONE) {\r
- return -1;\r
- } else {\r
- criterion[0].comparison = comparator;\r
- criterion[0].value = value;\r
- return 1;\r
- }\r
- }\r
- return -1;\r
- }\r
- if (comparator == NONE) {\r
- return specialCaseParse(word, criterion, 0);\r
- }\r
- return -1;\r
-}\r
-\r
-/* This routine is based on similiar code in glut_dstr.c */\r
-static Criterion *\r
-parseDisplayString(const char *display, int *ncriteria)\r
-{\r
- Criterion *criteria = NULL;\r
- int n, parsed;\r
- char *copy, *word;\r
-\r
- copy = __glutStrdup(display);\r
- /* Attempt to estimate how many criteria entries should be\r
- needed. */\r
- n = 0;\r
- word = strtok(copy, " \t");\r
- while (word) {\r
- n++;\r
- word = strtok(NULL, " \t");\r
- }\r
- /* Allocate number of words of criteria. A word\r
- could contain as many as four criteria in the\r
- worst case. Example: 800x600:16@60 */\r
- criteria = (Criterion *) malloc(4 * n * sizeof(Criterion));\r
- if (!criteria) {\r
- __glutFatalError("out of memory.");\r
- }\r
-\r
- /* Re-copy the copy of the display string. */\r
- strcpy(copy, display);\r
-\r
- n = 0;\r
- word = strtok(copy, " \t");\r
- while (word) {\r
- parsed = parseCriteria(word, &criteria[n]);\r
- if (parsed >= 0) {\r
- n += parsed;\r
- } else {\r
- __glutWarning("Unrecognized game mode string word: %s (ignoring)\n", word);\r
- }\r
- word = strtok(NULL, " \t");\r
- }\r
-\r
- free(copy);\r
- *ncriteria = n;\r
- return criteria;\r
-}\r
-\r
-void GLUTAPIENTRY\r
-glutGameModeString(const char *string)\r
-{\r
- Criterion *criteria;\r
- int ncriteria;\r
-\r
- initGameModeSupport();\r
- criteria = parseDisplayString(string, &ncriteria);\r
- currentDm = findMatch(dmodes, ndmodes, criteria, ncriteria);\r
- free(criteria);\r
-}\r
-\r
-int GLUTAPIENTRY\r
-glutEnterGameMode(void)\r
-{\r
- GLUTwindow *window;\r
- int width, height;\r
- Window win;\r
-\r
- if (__glutMappedMenu) {\r
- __glutFatalUsage("entering game mode not allowed while menus in use");\r
- }\r
- if (__glutGameModeWindow) {\r
- /* Already in game mode, so blow away game mode\r
- window so apps can change resolutions. */\r
- window = __glutGameModeWindow;\r
- /* Setting the game mode window to NULL tricks\r
- the window destroy code into not undoing the\r
- screen display change since we plan on immediately\r
- doing another mode change. */\r
- __glutGameModeWindow = NULL;\r
- __glutDestroyWindow(window, window);\r
- }\r
-\r
- /* Assume default screen size until we find out if we\r
- can actually change the display settings. */\r
- width = __glutScreenWidth;\r
- height = __glutScreenHeight;\r
-\r
- if (currentDm) {\r
-#ifdef _WIN32\r
- LONG status;\r
- static int registered = 0;\r
-\r
- status = ChangeDisplaySettings(¤tDm->devmode,\r
- CDS_FULLSCREEN);\r
- if (status == DISP_CHANGE_SUCCESSFUL) {\r
- __glutDisplaySettingsChanged = 1;\r
- width = currentDm->cap[DM_WIDTH];\r
- height = currentDm->cap[DM_HEIGHT];\r
- if (!registered) {\r
- atexit(__glutCloseDownGameMode);\r
- registered = 1;\r
- }\r
- } else {\r
- /* Switch back to default resolution. */\r
- ChangeDisplaySettings(NULL, 0);\r
- }\r
-#endif\r
- }\r
-\r
- window = __glutCreateWindow(NULL, 0, 0,\r
- width, height, /* game mode */ 1);\r
- win = window->win;\r
-\r
-#if !defined(_WIN32) && !defined(__OS2__)\r
- if (__glutMotifHints == None) {\r
- __glutMotifHints = XSGIFastInternAtom(__glutDisplay, "_MOTIF_WM_HINTS",\r
- SGI_XA__MOTIF_WM_HINTS, 0);\r
- if (__glutMotifHints == None) {\r
- __glutWarning("Could not intern X atom for _MOTIF_WM_HINTS.");\r
- }\r
- }\r
-\r
- /* Game mode window is a toplevel window. */\r
- XSetWMProtocols(__glutDisplay, win, &__glutWMDeleteWindow, 1);\r
-#endif\r
-\r
- /* Schedule the fullscreen property to be added and to\r
- make sure the window is configured right. Win32\r
- doesn't need this. */\r
- window->desiredX = 0;\r
- window->desiredY = 0;\r
- window->desiredWidth = width;\r
- window->desiredHeight = height;\r
- window->desiredConfMask |= CWX | CWY | CWWidth | CWHeight;\r
-#ifdef _WIN32\r
- /* Win32 does not want to use GLUT_FULL_SCREEN_WORK\r
- for game mode because we need to be maximizing\r
- the window in game mode, not just sizing it to\r
- take up the full screen. The Win32-ness of game\r
- mode happens when you pass 1 in the gameMode parameter\r
- to __glutCreateWindow above. A gameMode of creates\r
- a WS_POPUP window, not a standard WS_OVERLAPPEDWINDOW\r
- window. WS_POPUP ensures the taskbar is hidden. */\r
- __glutPutOnWorkList(window,\r
- GLUT_CONFIGURE_WORK);\r
-#else\r
- __glutPutOnWorkList(window,\r
- GLUT_CONFIGURE_WORK | GLUT_FULL_SCREEN_WORK);\r
-#endif\r
-\r
- __glutGameModeWindow = window;\r
- return window->num + 1;\r
-}\r
-\r
-int GLUTAPIENTRY\r
-glutGameModeGet(GLenum mode)\r
-{\r
- switch (mode) {\r
- case GLUT_GAME_MODE_ACTIVE:\r
- return __glutGameModeWindow != NULL;\r
- case GLUT_GAME_MODE_POSSIBLE:\r
- return currentDm != NULL;\r
- case GLUT_GAME_MODE_WIDTH:\r
- return currentDm ? currentDm->cap[DM_WIDTH] : -1;\r
- case GLUT_GAME_MODE_HEIGHT:\r
- return currentDm ? currentDm->cap[DM_HEIGHT] : -1;\r
- case GLUT_GAME_MODE_PIXEL_DEPTH:\r
- return currentDm ? currentDm->cap[DM_PIXEL_DEPTH] : -1;\r
- case GLUT_GAME_MODE_REFRESH_RATE:\r
- return currentDm ? currentDm->cap[DM_HERTZ] : -1;\r
- case GLUT_GAME_MODE_DISPLAY_CHANGED:\r
- return __glutDisplaySettingsChanged;\r
- default:\r
- return -1;\r
- }\r
-}\r
-\1a
\ No newline at end of file
+
+/* Copyright (c) Mark J. Kilgard, 1998. */
+
+/* This program is freely distributable without licensing fees
+ and is provided without guarantee or warrantee expressed or
+ implied. This program is -not- in the public domain. */
+
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "glutint.h"
+
+#if !defined(_WIN32) && !defined(__OS2__)
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+
+/* SGI optimization introduced in IRIX 6.3 to avoid X server
+ round trips for interning common X atoms. */
+#if defined(_SGI_EXTRA_PREDEFINES) && !defined(NO_FAST_ATOMS)
+#include <X11/SGIFastAtom.h>
+#else
+#define XSGIFastInternAtom(dpy,string,fast_name,how) XInternAtom(dpy,string,how)
+#endif
+#endif /* not _WIN32 */
+
+int __glutDisplaySettingsChanged = 0;
+static DisplayMode *dmodes, *currentDm = NULL;
+static int ndmodes = -1;
+GLUTwindow *__glutGameModeWindow = NULL;
+
+#ifdef TEST
+static char *compstr[] =
+{
+ "none", "=", "!=", "<=", ">=", ">", "<", "~"
+};
+static char *capstr[] =
+{
+ "width", "height", "bpp", "hertz", "num"
+};
+#endif
+
+#if defined(__OS2__)
+void
+#else
+void __cdecl
+#endif
+__glutCloseDownGameMode(void)
+{
+ if (__glutDisplaySettingsChanged) {
+#ifdef _WIN32
+ /* Assumes that display settings have been changed, that
+ is __glutDisplaySettingsChanged is true. */
+ ChangeDisplaySettings(NULL, 0);
+#endif
+ __glutDisplaySettingsChanged = 0;
+ }
+ __glutGameModeWindow = NULL;
+}
+
+void GLUTAPIENTRY
+glutLeaveGameMode(void)
+{
+ if (__glutGameModeWindow == NULL) {
+ __glutWarning("not in game mode so cannot leave game mode");
+ return;
+ }
+ __glutDestroyWindow(__glutGameModeWindow,
+ __glutGameModeWindow);
+ XFlush(__glutDisplay);
+ __glutGameModeWindow = NULL;
+}
+
+#ifdef _WIN32
+
+/* Same values as from MSDN's SetDisp.c example. */
+#define MIN_WIDTH 400
+#define MIN_FREQUENCY 60
+
+static void
+initGameModeSupport(void)
+{
+ DEVMODE dm;
+ DWORD mode;
+ int i;
+
+ if (ndmodes >= 0) {
+ /* ndmodes is initially -1 to indicate no
+ dmodes allocated yet. */
+ return;
+ }
+
+ /* Determine how many display modes there are. */
+ ndmodes = 0;
+ mode = 0;
+ while (EnumDisplaySettings(NULL, mode, &dm)) {
+ if (dm.dmPelsWidth >= MIN_WIDTH &&
+ (dm.dmDisplayFrequency == 0 ||
+ dm.dmDisplayFrequency >= MIN_FREQUENCY)) {
+ ndmodes++;
+ }
+ mode++;
+ }
+
+ /* Allocate memory for a list of all the display modes. */
+ dmodes = (DisplayMode*)
+ malloc(ndmodes * sizeof(DisplayMode));
+
+ /* Now that we know how many display modes to expect,
+ enumerate them again and save the information in
+ the list we allocated above. */
+ i = 0;
+ mode = 0;
+ while (EnumDisplaySettings(NULL, mode, &dm)) {
+ /* Try to reject any display settings that seem unplausible. */
+ if (dm.dmPelsWidth >= MIN_WIDTH &&
+ (dm.dmDisplayFrequency == 0 ||
+ dm.dmDisplayFrequency >= MIN_FREQUENCY)) {
+ dmodes[i].devmode = dm;
+ dmodes[i].valid = 1; /* XXX Not used for now. */
+ dmodes[i].cap[DM_WIDTH] = dm.dmPelsWidth;
+ dmodes[i].cap[DM_HEIGHT] = dm.dmPelsHeight;
+ dmodes[i].cap[DM_PIXEL_DEPTH] = dm.dmBitsPerPel;
+ if (dm.dmDisplayFrequency == 0) {
+ /* Guess a reasonable guess. */
+ /* Lame Windows 95 version of EnumDisplaySettings. */
+ dmodes[i].cap[DM_HERTZ] = 60;
+ } else {
+ dmodes[i].cap[DM_HERTZ] = dm.dmDisplayFrequency;
+ }
+ i++;
+ }
+ mode++;
+ }
+
+ assert(i == ndmodes);
+}
+
+#else
+
+/* X Windows version of initGameModeSupport. */
+static void
+initGameModeSupport(void)
+{
+ if (ndmodes >= 0) {
+ /* ndmodes is initially -1 to indicate no
+ dmodes allocated yet. */
+ return;
+ }
+
+ /* Determine how many display modes there are. */
+ ndmodes = 0;
+}
+
+#endif
+
+/* This routine is based on similiar code in glut_dstr.c */
+static DisplayMode *
+findMatch(DisplayMode * dmodes, int ndmodes,
+ Criterion * criteria, int ncriteria)
+{
+ DisplayMode *found;
+ int *bestScore, *thisScore;
+ int i, j, numok, result = 0, worse, better;
+
+ found = NULL;
+ numok = 1; /* "num" capability is indexed from 1,
+ not 0. */
+
+ /* XXX alloca canidate. */
+ bestScore = (int *) malloc(ncriteria * sizeof(int));
+ if (!bestScore) {
+ __glutFatalError("out of memory.");
+ }
+ for (j = 0; j < ncriteria; j++) {
+ /* Very negative number. */
+ bestScore[j] = -32768;
+ }
+
+ /* XXX alloca canidate. */
+ thisScore = (int *) malloc(ncriteria * sizeof(int));
+ if (!thisScore) {
+ __glutFatalError("out of memory.");
+ }
+
+ for (i = 0; i < ndmodes; i++) {
+ if (dmodes[i].valid) {
+ worse = 0;
+ better = 0;
+
+ for (j = 0; j < ncriteria; j++) {
+ int cap, cvalue, dvalue;
+
+ cap = criteria[j].capability;
+ cvalue = criteria[j].value;
+ if (cap == NUM) {
+ dvalue = numok;
+ } else {
+ dvalue = dmodes[i].cap[cap];
+ }
+#ifdef TEST
+ if (verbose)
+ printf(" %s %s %d to %d\n",
+ capstr[cap], compstr[criteria[j].comparison], cvalue, dvalue);
+#endif
+ switch (criteria[j].comparison) {
+ case EQ:
+ result = cvalue == dvalue;
+ thisScore[j] = 1;
+ break;
+ case NEQ:
+ result = cvalue != dvalue;
+ thisScore[j] = 1;
+ break;
+ case LT:
+ result = dvalue < cvalue;
+ thisScore[j] = dvalue - cvalue;
+ break;
+ case GT:
+ result = dvalue > cvalue;
+ thisScore[j] = dvalue - cvalue;
+ break;
+ case LTE:
+ result = dvalue <= cvalue;
+ thisScore[j] = dvalue - cvalue;
+ break;
+ case GTE:
+ result = (dvalue >= cvalue);
+ thisScore[j] = dvalue - cvalue;
+ break;
+ case MIN:
+ result = dvalue >= cvalue;
+ thisScore[j] = cvalue - dvalue;
+ break;
+ }
+
+#ifdef TEST
+ if (verbose)
+ printf(" result=%d score=%d bestScore=%d\n", result, thisScore[j], bestScore[j]);
+#endif
+
+ if (result) {
+ if (better || thisScore[j] > bestScore[j]) {
+ better = 1;
+ } else if (thisScore[j] == bestScore[j]) {
+ /* Keep looking. */
+ } else {
+ goto nextDM;
+ }
+ } else {
+ if (cap == NUM) {
+ worse = 1;
+ } else {
+ goto nextDM;
+ }
+ }
+
+ }
+
+ if (better && !worse) {
+ found = &dmodes[i];
+ for (j = 0; j < ncriteria; j++) {
+ bestScore[j] = thisScore[j];
+ }
+ }
+ numok++;
+
+ nextDM:;
+
+ }
+ }
+ free(bestScore);
+ free(thisScore);
+ return found;
+}
+
+/**
+ * Parses strings in the form of:
+ * 800x600
+ * 800x600:16
+ * 800x600@60
+ * 800x600:16@60
+ * @60
+ * :16
+ * :16@60
+ * NOTE that @ before : is not parsed.
+ */
+static int
+specialCaseParse(char *word, Criterion * criterion, int mask)
+{
+ char *xstr, *response;
+ int got;
+ int width, height, bpp, hertz;
+
+ switch(word[0]) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ /* The WWWxHHH case. */
+ if (mask & (1 << DM_WIDTH)) {
+ return -1;
+ }
+ xstr = strpbrk(&word[1], "x");
+ if (xstr) {
+ width = (int) strtol(word, &response, 0);
+ if (response == word || response[0] != 'x') {
+ /* Not a valid number OR needs to be followed by 'x'. */
+ return -1;
+ }
+ height = (int) strtol(&xstr[1], &response, 0);
+ if (response == &xstr[1]) {
+ /* Not a valid number. */
+ return -1;
+ }
+ criterion[0].capability = DM_WIDTH;
+ criterion[0].comparison = EQ;
+ criterion[0].value = width;
+ criterion[1].capability = DM_HEIGHT;
+ criterion[1].comparison = EQ;
+ criterion[1].value = height;
+ got = specialCaseParse(response,
+ &criterion[2], 1 << DM_WIDTH);
+ if (got >= 0) {
+ return got + 2;
+ } else {
+ return -1;
+ }
+ }
+ return -1;
+ case ':':
+ /* The :BPP case. */
+ if (mask & (1 << DM_PIXEL_DEPTH)) {
+ return -1;
+ }
+ bpp = (int) strtol(&word[1], &response, 0);
+ if (response == &word[1]) {
+ /* Not a valid number. */
+ return -1;
+ }
+ criterion[0].capability = DM_PIXEL_DEPTH;
+ criterion[0].comparison = EQ;
+ criterion[0].value = bpp;
+ got = specialCaseParse(response,
+ &criterion[1], (1 << DM_WIDTH) | (1 << DM_PIXEL_DEPTH));
+ if (got >= 0) {
+ return got + 1;
+ } else {
+ return -1;
+ }
+ case '@':
+ /* The @HZ case. */
+ if (mask & (1 << DM_HERTZ)) {
+ return -1;
+ }
+ hertz = (int) strtol(&word[1], &response, 0);
+ if (response == &word[1]) {
+ /* Not a valid number. */
+ return -1;
+ }
+ criterion[0].capability = DM_HERTZ;
+ criterion[0].comparison = EQ;
+ criterion[0].value = hertz;
+ got = specialCaseParse(response,
+ &criterion[1], ~DM_HERTZ);
+ if (got >= 0) {
+ return got + 1;
+ } else {
+ return -1;
+ }
+ case '\0':
+ return 0;
+ }
+ return -1;
+}
+
+/* This routine is based on similiar code in glut_dstr.c */
+static int
+parseCriteria(char *word, Criterion * criterion)
+{
+ char *cstr, *vstr, *response;
+ int comparator, value = 0;
+
+ cstr = strpbrk(word, "=><!~");
+ if (cstr) {
+ switch (cstr[0]) {
+ case '=':
+ comparator = EQ;
+ vstr = &cstr[1];
+ break;
+ case '~':
+ comparator = MIN;
+ vstr = &cstr[1];
+ break;
+ case '>':
+ if (cstr[1] == '=') {
+ comparator = GTE;
+ vstr = &cstr[2];
+ } else {
+ comparator = GT;
+ vstr = &cstr[1];
+ }
+ break;
+ case '<':
+ if (cstr[1] == '=') {
+ comparator = LTE;
+ vstr = &cstr[2];
+ } else {
+ comparator = LT;
+ vstr = &cstr[1];
+ }
+ break;
+ case '!':
+ if (cstr[1] == '=') {
+ comparator = NEQ;
+ vstr = &cstr[2];
+ } else {
+ return -1;
+ }
+ break;
+ default:
+ return -1;
+ }
+ value = (int) strtol(vstr, &response, 0);
+ if (response == vstr) {
+ /* Not a valid number. */
+ return -1;
+ }
+ *cstr = '\0';
+ } else {
+ comparator = NONE;
+ }
+ switch (word[0]) {
+ case 'b':
+ if (!strcmp(word, "bpp")) {
+ criterion[0].capability = DM_PIXEL_DEPTH;
+ if (comparator == NONE) {
+ return -1;
+ } else {
+ criterion[0].comparison = comparator;
+ criterion[0].value = value;
+ return 1;
+ }
+ }
+ return -1;
+ case 'h':
+ if (!strcmp(word, "height")) {
+ criterion[0].capability = DM_HEIGHT;
+ if (comparator == NONE) {
+ return -1;
+ } else {
+ criterion[0].comparison = comparator;
+ criterion[0].value = value;
+ return 1;
+ }
+ }
+ if (!strcmp(word, "hertz")) {
+ criterion[0].capability = DM_HERTZ;
+ if (comparator == NONE) {
+ return -1;
+ } else {
+ criterion[0].comparison = comparator;
+ criterion[0].value = value;
+ return 1;
+ }
+ }
+ return -1;
+ case 'n':
+ if (!strcmp(word, "num")) {
+ criterion[0].capability = DM_NUM;
+ if (comparator == NONE) {
+ return -1;
+ } else {
+ criterion[0].comparison = comparator;
+ criterion[0].value = value;
+ return 1;
+ }
+ }
+ return -1;
+ case 'w':
+ if (!strcmp(word, "width")) {
+ criterion[0].capability = DM_WIDTH;
+ if (comparator == NONE) {
+ return -1;
+ } else {
+ criterion[0].comparison = comparator;
+ criterion[0].value = value;
+ return 1;
+ }
+ }
+ return -1;
+ }
+ if (comparator == NONE) {
+ return specialCaseParse(word, criterion, 0);
+ }
+ return -1;
+}
+
+/* This routine is based on similiar code in glut_dstr.c */
+static Criterion *
+parseDisplayString(const char *display, int *ncriteria)
+{
+ Criterion *criteria = NULL;
+ int n, parsed;
+ char *copy, *word;
+
+ copy = __glutStrdup(display);
+ /* Attempt to estimate how many criteria entries should be
+ needed. */
+ n = 0;
+ word = strtok(copy, " \t");
+ while (word) {
+ n++;
+ word = strtok(NULL, " \t");
+ }
+ /* Allocate number of words of criteria. A word
+ could contain as many as four criteria in the
+ worst case. Example: 800x600:16@60 */
+ criteria = (Criterion *) malloc(4 * n * sizeof(Criterion));
+ if (!criteria) {
+ __glutFatalError("out of memory.");
+ }
+
+ /* Re-copy the copy of the display string. */
+ strcpy(copy, display);
+
+ n = 0;
+ word = strtok(copy, " \t");
+ while (word) {
+ parsed = parseCriteria(word, &criteria[n]);
+ if (parsed >= 0) {
+ n += parsed;
+ } else {
+ __glutWarning("Unrecognized game mode string word: %s (ignoring)\n", word);
+ }
+ word = strtok(NULL, " \t");
+ }
+
+ free(copy);
+ *ncriteria = n;
+ return criteria;
+}
+
+void GLUTAPIENTRY
+glutGameModeString(const char *string)
+{
+ Criterion *criteria;
+ int ncriteria;
+
+ initGameModeSupport();
+ criteria = parseDisplayString(string, &ncriteria);
+ currentDm = findMatch(dmodes, ndmodes, criteria, ncriteria);
+ free(criteria);
+}
+
+int GLUTAPIENTRY
+glutEnterGameMode(void)
+{
+ GLUTwindow *window;
+ int width, height;
+ Window win;
+
+ if (__glutMappedMenu) {
+ __glutFatalUsage("entering game mode not allowed while menus in use");
+ }
+ if (__glutGameModeWindow) {
+ /* Already in game mode, so blow away game mode
+ window so apps can change resolutions. */
+ window = __glutGameModeWindow;
+ /* Setting the game mode window to NULL tricks
+ the window destroy code into not undoing the
+ screen display change since we plan on immediately
+ doing another mode change. */
+ __glutGameModeWindow = NULL;
+ __glutDestroyWindow(window, window);
+ }
+
+ /* Assume default screen size until we find out if we
+ can actually change the display settings. */
+ width = __glutScreenWidth;
+ height = __glutScreenHeight;
+
+ if (currentDm) {
+#ifdef _WIN32
+ LONG status;
+ static int registered = 0;
+
+ status = ChangeDisplaySettings(¤tDm->devmode,
+ CDS_FULLSCREEN);
+ if (status == DISP_CHANGE_SUCCESSFUL) {
+ __glutDisplaySettingsChanged = 1;
+ width = currentDm->cap[DM_WIDTH];
+ height = currentDm->cap[DM_HEIGHT];
+ if (!registered) {
+ atexit(__glutCloseDownGameMode);
+ registered = 1;
+ }
+ } else {
+ /* Switch back to default resolution. */
+ ChangeDisplaySettings(NULL, 0);
+ }
+#endif
+ }
+
+ window = __glutCreateWindow(NULL, 0, 0,
+ width, height, /* game mode */ 1);
+ win = window->win;
+
+#if !defined(_WIN32) && !defined(__OS2__)
+ if (__glutMotifHints == None) {
+ __glutMotifHints = XSGIFastInternAtom(__glutDisplay, "_MOTIF_WM_HINTS",
+ SGI_XA__MOTIF_WM_HINTS, 0);
+ if (__glutMotifHints == None) {
+ __glutWarning("Could not intern X atom for _MOTIF_WM_HINTS.");
+ }
+ }
+
+ /* Game mode window is a toplevel window. */
+ XSetWMProtocols(__glutDisplay, win, &__glutWMDeleteWindow, 1);
+#endif
+
+ /* Schedule the fullscreen property to be added and to
+ make sure the window is configured right. Win32
+ doesn't need this. */
+ window->desiredX = 0;
+ window->desiredY = 0;
+ window->desiredWidth = width;
+ window->desiredHeight = height;
+ window->desiredConfMask |= CWX | CWY | CWWidth | CWHeight;
+#ifdef _WIN32
+ /* Win32 does not want to use GLUT_FULL_SCREEN_WORK
+ for game mode because we need to be maximizing
+ the window in game mode, not just sizing it to
+ take up the full screen. The Win32-ness of game
+ mode happens when you pass 1 in the gameMode parameter
+ to __glutCreateWindow above. A gameMode of creates
+ a WS_POPUP window, not a standard WS_OVERLAPPEDWINDOW
+ window. WS_POPUP ensures the taskbar is hidden. */
+ __glutPutOnWorkList(window,
+ GLUT_CONFIGURE_WORK);
+#else
+ __glutPutOnWorkList(window,
+ GLUT_CONFIGURE_WORK | GLUT_FULL_SCREEN_WORK);
+#endif
+
+ __glutGameModeWindow = window;
+ return window->num + 1;
+}
+
+int GLUTAPIENTRY
+glutGameModeGet(GLenum mode)
+{
+ switch (mode) {
+ case GLUT_GAME_MODE_ACTIVE:
+ return __glutGameModeWindow != NULL;
+ case GLUT_GAME_MODE_POSSIBLE:
+ return currentDm != NULL;
+ case GLUT_GAME_MODE_WIDTH:
+ return currentDm ? currentDm->cap[DM_WIDTH] : -1;
+ case GLUT_GAME_MODE_HEIGHT:
+ return currentDm ? currentDm->cap[DM_HEIGHT] : -1;
+ case GLUT_GAME_MODE_PIXEL_DEPTH:
+ return currentDm ? currentDm->cap[DM_PIXEL_DEPTH] : -1;
+ case GLUT_GAME_MODE_REFRESH_RATE:
+ return currentDm ? currentDm->cap[DM_HERTZ] : -1;
+ case GLUT_GAME_MODE_DISPLAY_CHANGED:
+ return __glutDisplaySettingsChanged;
+ default:
+ return -1;
+ }
+}