2 /* Copyright (c) Mark J. Kilgard, 1998. */
4 /* This program is freely distributable without licensing fees
5 and is provided without guarantee or warrantee expressed or
6 implied. This program is -not- in the public domain. */
16 #if !defined(_WIN32) && !defined(__OS2__)
18 #include <X11/Xatom.h>
20 /* SGI optimization introduced in IRIX 6.3 to avoid X server
21 round trips for interning common X atoms. */
22 #if defined(_SGI_EXTRA_PREDEFINES) && !defined(NO_FAST_ATOMS)
23 #include <X11/SGIFastAtom.h>
25 #define XSGIFastInternAtom(dpy,string,fast_name,how) XInternAtom(dpy,string,how)
27 #endif /* not _WIN32 */
29 int __glutDisplaySettingsChanged
= 0;
30 static DisplayMode
*dmodes
, *currentDm
= NULL
;
31 static int ndmodes
= -1;
32 GLUTwindow
*__glutGameModeWindow
= NULL
;
35 static char *compstr
[] =
37 "none", "=", "!=", "<=", ">=", ">", "<", "~"
39 static char *capstr
[] =
41 "width", "height", "bpp", "hertz", "num"
50 __glutCloseDownGameMode(void)
52 if (__glutDisplaySettingsChanged
) {
54 /* Assumes that display settings have been changed, that
55 is __glutDisplaySettingsChanged is true. */
56 ChangeDisplaySettings(NULL
, 0);
58 __glutDisplaySettingsChanged
= 0;
60 __glutGameModeWindow
= NULL
;
64 glutLeaveGameMode(void)
66 if (__glutGameModeWindow
== NULL
) {
67 __glutWarning("not in game mode so cannot leave game mode");
70 __glutDestroyWindow(__glutGameModeWindow
,
71 __glutGameModeWindow
);
72 XFlush(__glutDisplay
);
73 __glutGameModeWindow
= NULL
;
78 /* Same values as from MSDN's SetDisp.c example. */
80 #define MIN_FREQUENCY 60
83 initGameModeSupport(void)
90 /* ndmodes is initially -1 to indicate no
91 dmodes allocated yet. */
95 /* Determine how many display modes there are. */
98 while (EnumDisplaySettings(NULL
, mode
, &dm
)) {
99 if (dm
.dmPelsWidth
>= MIN_WIDTH
&&
100 (dm
.dmDisplayFrequency
== 0 ||
101 dm
.dmDisplayFrequency
>= MIN_FREQUENCY
)) {
107 /* Allocate memory for a list of all the display modes. */
108 dmodes
= (DisplayMode
*)
109 malloc(ndmodes
* sizeof(DisplayMode
));
111 /* Now that we know how many display modes to expect,
112 enumerate them again and save the information in
113 the list we allocated above. */
116 while (EnumDisplaySettings(NULL
, mode
, &dm
)) {
117 /* Try to reject any display settings that seem unplausible. */
118 if (dm
.dmPelsWidth
>= MIN_WIDTH
&&
119 (dm
.dmDisplayFrequency
== 0 ||
120 dm
.dmDisplayFrequency
>= MIN_FREQUENCY
)) {
121 dmodes
[i
].devmode
= dm
;
122 dmodes
[i
].valid
= 1; /* XXX Not used for now. */
123 dmodes
[i
].cap
[DM_WIDTH
] = dm
.dmPelsWidth
;
124 dmodes
[i
].cap
[DM_HEIGHT
] = dm
.dmPelsHeight
;
125 dmodes
[i
].cap
[DM_PIXEL_DEPTH
] = dm
.dmBitsPerPel
;
126 if (dm
.dmDisplayFrequency
== 0) {
127 /* Guess a reasonable guess. */
128 /* Lame Windows 95 version of EnumDisplaySettings. */
129 dmodes
[i
].cap
[DM_HERTZ
] = 60;
131 dmodes
[i
].cap
[DM_HERTZ
] = dm
.dmDisplayFrequency
;
138 assert(i
== ndmodes
);
143 /* X Windows version of initGameModeSupport. */
145 initGameModeSupport(void)
148 /* ndmodes is initially -1 to indicate no
149 dmodes allocated yet. */
153 /* Determine how many display modes there are. */
159 /* This routine is based on similiar code in glut_dstr.c */
161 findMatch(DisplayMode
* dmodes
, int ndmodes
,
162 Criterion
* criteria
, int ncriteria
)
165 int *bestScore
, *thisScore
;
166 int i
, j
, numok
, result
= 0, worse
, better
;
169 numok
= 1; /* "num" capability is indexed from 1,
172 /* XXX alloca canidate. */
173 bestScore
= (int *) malloc(ncriteria
* sizeof(int));
175 __glutFatalError("out of memory.");
177 for (j
= 0; j
< ncriteria
; j
++) {
178 /* Very negative number. */
179 bestScore
[j
] = -32768;
182 /* XXX alloca canidate. */
183 thisScore
= (int *) malloc(ncriteria
* sizeof(int));
185 __glutFatalError("out of memory.");
188 for (i
= 0; i
< ndmodes
; i
++) {
189 if (dmodes
[i
].valid
) {
193 for (j
= 0; j
< ncriteria
; j
++) {
194 int cap
, cvalue
, dvalue
;
196 cap
= criteria
[j
].capability
;
197 cvalue
= criteria
[j
].value
;
201 dvalue
= dmodes
[i
].cap
[cap
];
205 printf(" %s %s %d to %d\n",
206 capstr
[cap
], compstr
[criteria
[j
].comparison
], cvalue
, dvalue
);
208 switch (criteria
[j
].comparison
) {
210 result
= cvalue
== dvalue
;
214 result
= cvalue
!= dvalue
;
218 result
= dvalue
< cvalue
;
219 thisScore
[j
] = dvalue
- cvalue
;
222 result
= dvalue
> cvalue
;
223 thisScore
[j
] = dvalue
- cvalue
;
226 result
= dvalue
<= cvalue
;
227 thisScore
[j
] = dvalue
- cvalue
;
230 result
= (dvalue
>= cvalue
);
231 thisScore
[j
] = dvalue
- cvalue
;
234 result
= dvalue
>= cvalue
;
235 thisScore
[j
] = cvalue
- dvalue
;
241 printf(" result=%d score=%d bestScore=%d\n", result
, thisScore
[j
], bestScore
[j
]);
245 if (better
|| thisScore
[j
] > bestScore
[j
]) {
247 } else if (thisScore
[j
] == bestScore
[j
]) {
262 if (better
&& !worse
) {
264 for (j
= 0; j
< ncriteria
; j
++) {
265 bestScore
[j
] = thisScore
[j
];
280 * Parses strings in the form of:
288 * NOTE that @ before : is not parsed.
291 specialCaseParse(char *word
, Criterion
* criterion
, int mask
)
293 char *xstr
, *response
;
295 int width
, height
, bpp
, hertz
;
308 /* The WWWxHHH case. */
309 if (mask
& (1 << DM_WIDTH
)) {
312 xstr
= strpbrk(&word
[1], "x");
314 width
= (int) strtol(word
, &response
, 0);
315 if (response
== word
|| response
[0] != 'x') {
316 /* Not a valid number OR needs to be followed by 'x'. */
319 height
= (int) strtol(&xstr
[1], &response
, 0);
320 if (response
== &xstr
[1]) {
321 /* Not a valid number. */
324 criterion
[0].capability
= DM_WIDTH
;
325 criterion
[0].comparison
= EQ
;
326 criterion
[0].value
= width
;
327 criterion
[1].capability
= DM_HEIGHT
;
328 criterion
[1].comparison
= EQ
;
329 criterion
[1].value
= height
;
330 got
= specialCaseParse(response
,
331 &criterion
[2], 1 << DM_WIDTH
);
341 if (mask
& (1 << DM_PIXEL_DEPTH
)) {
344 bpp
= (int) strtol(&word
[1], &response
, 0);
345 if (response
== &word
[1]) {
346 /* Not a valid number. */
349 criterion
[0].capability
= DM_PIXEL_DEPTH
;
350 criterion
[0].comparison
= EQ
;
351 criterion
[0].value
= bpp
;
352 got
= specialCaseParse(response
,
353 &criterion
[1], (1 << DM_WIDTH
) | (1 << DM_PIXEL_DEPTH
));
361 if (mask
& (1 << DM_HERTZ
)) {
364 hertz
= (int) strtol(&word
[1], &response
, 0);
365 if (response
== &word
[1]) {
366 /* Not a valid number. */
369 criterion
[0].capability
= DM_HERTZ
;
370 criterion
[0].comparison
= EQ
;
371 criterion
[0].value
= hertz
;
372 got
= specialCaseParse(response
,
373 &criterion
[1], ~DM_HERTZ
);
385 /* This routine is based on similiar code in glut_dstr.c */
387 parseCriteria(char *word
, Criterion
* criterion
)
389 char *cstr
, *vstr
, *response
;
390 int comparator
, value
= 0;
392 cstr
= strpbrk(word
, "=><!~");
404 if (cstr
[1] == '=') {
413 if (cstr
[1] == '=') {
422 if (cstr
[1] == '=') {
432 value
= (int) strtol(vstr
, &response
, 0);
433 if (response
== vstr
) {
434 /* Not a valid number. */
443 if (!strcmp(word
, "bpp")) {
444 criterion
[0].capability
= DM_PIXEL_DEPTH
;
445 if (comparator
== NONE
) {
448 criterion
[0].comparison
= comparator
;
449 criterion
[0].value
= value
;
455 if (!strcmp(word
, "height")) {
456 criterion
[0].capability
= DM_HEIGHT
;
457 if (comparator
== NONE
) {
460 criterion
[0].comparison
= comparator
;
461 criterion
[0].value
= value
;
465 if (!strcmp(word
, "hertz")) {
466 criterion
[0].capability
= DM_HERTZ
;
467 if (comparator
== NONE
) {
470 criterion
[0].comparison
= comparator
;
471 criterion
[0].value
= value
;
477 if (!strcmp(word
, "num")) {
478 criterion
[0].capability
= DM_NUM
;
479 if (comparator
== NONE
) {
482 criterion
[0].comparison
= comparator
;
483 criterion
[0].value
= value
;
489 if (!strcmp(word
, "width")) {
490 criterion
[0].capability
= DM_WIDTH
;
491 if (comparator
== NONE
) {
494 criterion
[0].comparison
= comparator
;
495 criterion
[0].value
= value
;
501 if (comparator
== NONE
) {
502 return specialCaseParse(word
, criterion
, 0);
507 /* This routine is based on similiar code in glut_dstr.c */
509 parseDisplayString(const char *display
, int *ncriteria
)
511 Criterion
*criteria
= NULL
;
515 copy
= __glutStrdup(display
);
516 /* Attempt to estimate how many criteria entries should be
519 word
= strtok(copy
, " \t");
522 word
= strtok(NULL
, " \t");
524 /* Allocate number of words of criteria. A word
525 could contain as many as four criteria in the
526 worst case. Example: 800x600:16@60 */
527 criteria
= (Criterion
*) malloc(4 * n
* sizeof(Criterion
));
529 __glutFatalError("out of memory.");
532 /* Re-copy the copy of the display string. */
533 strcpy(copy
, display
);
536 word
= strtok(copy
, " \t");
538 parsed
= parseCriteria(word
, &criteria
[n
]);
542 __glutWarning("Unrecognized game mode string word: %s (ignoring)\n", word
);
544 word
= strtok(NULL
, " \t");
553 glutGameModeString(const char *string
)
558 initGameModeSupport();
559 criteria
= parseDisplayString(string
, &ncriteria
);
560 currentDm
= findMatch(dmodes
, ndmodes
, criteria
, ncriteria
);
565 glutEnterGameMode(void)
571 if (__glutMappedMenu
) {
572 __glutFatalUsage("entering game mode not allowed while menus in use");
574 if (__glutGameModeWindow
) {
575 /* Already in game mode, so blow away game mode
576 window so apps can change resolutions. */
577 window
= __glutGameModeWindow
;
578 /* Setting the game mode window to NULL tricks
579 the window destroy code into not undoing the
580 screen display change since we plan on immediately
581 doing another mode change. */
582 __glutGameModeWindow
= NULL
;
583 __glutDestroyWindow(window
, window
);
586 /* Assume default screen size until we find out if we
587 can actually change the display settings. */
588 width
= __glutScreenWidth
;
589 height
= __glutScreenHeight
;
594 static int registered
= 0;
596 status
= ChangeDisplaySettings(¤tDm
->devmode
,
598 if (status
== DISP_CHANGE_SUCCESSFUL
) {
599 __glutDisplaySettingsChanged
= 1;
600 width
= currentDm
->cap
[DM_WIDTH
];
601 height
= currentDm
->cap
[DM_HEIGHT
];
603 atexit(__glutCloseDownGameMode
);
607 /* Switch back to default resolution. */
608 ChangeDisplaySettings(NULL
, 0);
613 window
= __glutCreateWindow(NULL
, 0, 0,
614 width
, height
, /* game mode */ 1);
617 #if !defined(_WIN32) && !defined(__OS2__)
618 if (__glutMotifHints
== None
) {
619 __glutMotifHints
= XSGIFastInternAtom(__glutDisplay
, "_MOTIF_WM_HINTS",
620 SGI_XA__MOTIF_WM_HINTS
, 0);
621 if (__glutMotifHints
== None
) {
622 __glutWarning("Could not intern X atom for _MOTIF_WM_HINTS.");
626 /* Game mode window is a toplevel window. */
627 XSetWMProtocols(__glutDisplay
, win
, &__glutWMDeleteWindow
, 1);
630 /* Schedule the fullscreen property to be added and to
631 make sure the window is configured right. Win32
632 doesn't need this. */
633 window
->desiredX
= 0;
634 window
->desiredY
= 0;
635 window
->desiredWidth
= width
;
636 window
->desiredHeight
= height
;
637 window
->desiredConfMask
|= CWX
| CWY
| CWWidth
| CWHeight
;
639 /* Win32 does not want to use GLUT_FULL_SCREEN_WORK
640 for game mode because we need to be maximizing
641 the window in game mode, not just sizing it to
642 take up the full screen. The Win32-ness of game
643 mode happens when you pass 1 in the gameMode parameter
644 to __glutCreateWindow above. A gameMode of creates
645 a WS_POPUP window, not a standard WS_OVERLAPPEDWINDOW
646 window. WS_POPUP ensures the taskbar is hidden. */
647 __glutPutOnWorkList(window
,
648 GLUT_CONFIGURE_WORK
);
650 __glutPutOnWorkList(window
,
651 GLUT_CONFIGURE_WORK
| GLUT_FULL_SCREEN_WORK
);
654 __glutGameModeWindow
= window
;
655 return window
->num
+ 1;
659 glutGameModeGet(GLenum mode
)
662 case GLUT_GAME_MODE_ACTIVE
:
663 return __glutGameModeWindow
!= NULL
;
664 case GLUT_GAME_MODE_POSSIBLE
:
665 return currentDm
!= NULL
;
666 case GLUT_GAME_MODE_WIDTH
:
667 return currentDm
? currentDm
->cap
[DM_WIDTH
] : -1;
668 case GLUT_GAME_MODE_HEIGHT
:
669 return currentDm
? currentDm
->cap
[DM_HEIGHT
] : -1;
670 case GLUT_GAME_MODE_PIXEL_DEPTH
:
671 return currentDm
? currentDm
->cap
[DM_PIXEL_DEPTH
] : -1;
672 case GLUT_GAME_MODE_REFRESH_RATE
:
673 return currentDm
? currentDm
->cap
[DM_HERTZ
] : -1;
674 case GLUT_GAME_MODE_DISPLAY_CHANGED
:
675 return __glutDisplaySettingsChanged
;