Merge branch 'master' into gallium-0.2
[mesa.git] / src / glut / os2 / glut_gamemode.cpp
index 50185d7b9d48f36ab14b1bab533d26f4d0ff1589..1756e8a4b56cf30c065743f2b586961f1993e581 100644 (file)
-\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(&currentDm->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(&currentDm->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;
+  }
+}