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. */
17 #include <X11/Xatom.h>
19 /* SGI optimization introduced in IRIX 6.3 to avoid X server
20 round trips for interning common X atoms. */
21 #if defined(_SGI_EXTRA_PREDEFINES) && !defined(NO_FAST_ATOMS)
22 #include <X11/SGIFastAtom.h>
24 #define XSGIFastInternAtom(dpy,string,fast_name,how) XInternAtom(dpy,string,how)
26 #endif /* not _WIN32 */
28 int __glutDisplaySettingsChanged
= 0;
29 static DisplayMode
*dmodes
, *currentDm
= NULL
;
30 static int ndmodes
= -1;
31 GLUTwindow
*__glutGameModeWindow
= NULL
;
34 static char *compstr
[] =
36 "none", "=", "!=", "<=", ">=", ">", "<", "~"
38 static char *capstr
[] =
40 "width", "height", "bpp", "hertz", "num"
45 __glutCloseDownGameMode(void)
47 if (__glutDisplaySettingsChanged
) {
49 /* Assumes that display settings have been changed, that
50 is __glutDisplaySettingsChanged is true. */
51 ChangeDisplaySettings(NULL
, 0);
53 __glutDisplaySettingsChanged
= 0;
55 __glutGameModeWindow
= NULL
;
59 glutLeaveGameMode(void)
61 if (__glutGameModeWindow
== NULL
) {
62 __glutWarning("not in game mode so cannot leave game mode");
65 __glutDestroyWindow(__glutGameModeWindow
,
66 __glutGameModeWindow
);
67 XFlush(__glutDisplay
);
68 __glutGameModeWindow
= NULL
;
73 /* Same values as from MSDN's SetDisp.c example. */
75 #define MIN_FREQUENCY 60
78 initGameModeSupport(void)
85 /* ndmodes is initially -1 to indicate no
86 dmodes allocated yet. */
90 /* Determine how many display modes there are. */
93 while (EnumDisplaySettings(NULL
, mode
, &dm
)) {
94 if (dm
.dmPelsWidth
>= MIN_WIDTH
&&
95 (dm
.dmDisplayFrequency
== 0 ||
96 dm
.dmDisplayFrequency
>= MIN_FREQUENCY
)) {
102 /* Allocate memory for a list of all the display modes. */
103 dmodes
= (DisplayMode
*)
104 malloc(ndmodes
* sizeof(DisplayMode
));
106 /* Now that we know how many display modes to expect,
107 enumerate them again and save the information in
108 the list we allocated above. */
111 while (EnumDisplaySettings(NULL
, mode
, &dm
)) {
112 /* Try to reject any display settings that seem unplausible. */
113 if (dm
.dmPelsWidth
>= MIN_WIDTH
&&
114 (dm
.dmDisplayFrequency
== 0 ||
115 dm
.dmDisplayFrequency
>= MIN_FREQUENCY
)) {
116 dmodes
[i
].devmode
= dm
;
117 dmodes
[i
].valid
= 1; /* XXX Not used for now. */
118 dmodes
[i
].cap
[DM_WIDTH
] = dm
.dmPelsWidth
;
119 dmodes
[i
].cap
[DM_HEIGHT
] = dm
.dmPelsHeight
;
120 dmodes
[i
].cap
[DM_PIXEL_DEPTH
] = dm
.dmBitsPerPel
;
121 if (dm
.dmDisplayFrequency
== 0) {
122 /* Guess a reasonable guess. */
123 /* Lame Windows 95 version of EnumDisplaySettings. */
124 dmodes
[i
].cap
[DM_HERTZ
] = 60;
126 dmodes
[i
].cap
[DM_HERTZ
] = dm
.dmDisplayFrequency
;
133 assert(i
== ndmodes
);
138 /* X Windows version of initGameModeSupport. */
140 initGameModeSupport(void)
143 /* ndmodes is initially -1 to indicate no
144 dmodes allocated yet. */
148 /* Determine how many display modes there are. */
154 /* This routine is based on similiar code in glut_dstr.c */
156 findMatch(DisplayMode
* dmodes
, int ndmodes
,
157 Criterion
* criteria
, int ncriteria
)
160 int *bestScore
, *thisScore
;
161 int i
, j
, numok
, result
, worse
, better
;
164 numok
= 1; /* "num" capability is indexed from 1,
167 /* XXX alloca canidate. */
168 bestScore
= (int *) malloc(ncriteria
* sizeof(int));
170 __glutFatalError("out of memory.");
172 for (j
= 0; j
< ncriteria
; j
++) {
173 /* Very negative number. */
174 bestScore
[j
] = -32768;
177 /* XXX alloca canidate. */
178 thisScore
= (int *) malloc(ncriteria
* sizeof(int));
180 __glutFatalError("out of memory.");
183 for (i
= 0; i
< ndmodes
; i
++) {
184 if (dmodes
[i
].valid
) {
188 for (j
= 0; j
< ncriteria
; j
++) {
189 int cap
, cvalue
, dvalue
;
191 cap
= criteria
[j
].capability
;
192 cvalue
= criteria
[j
].value
;
196 dvalue
= dmodes
[i
].cap
[cap
];
200 printf(" %s %s %d to %d\n",
201 capstr
[cap
], compstr
[criteria
[j
].comparison
], cvalue
, dvalue
);
203 switch (criteria
[j
].comparison
) {
205 result
= cvalue
== dvalue
;
209 result
= cvalue
!= dvalue
;
213 result
= dvalue
< cvalue
;
214 thisScore
[j
] = dvalue
- cvalue
;
217 result
= dvalue
> cvalue
;
218 thisScore
[j
] = dvalue
- cvalue
;
221 result
= dvalue
<= cvalue
;
222 thisScore
[j
] = dvalue
- cvalue
;
225 result
= (dvalue
>= cvalue
);
226 thisScore
[j
] = dvalue
- cvalue
;
229 result
= dvalue
>= cvalue
;
230 thisScore
[j
] = cvalue
- dvalue
;
236 printf(" result=%d score=%d bestScore=%d\n", result
, thisScore
[j
], bestScore
[j
]);
240 if (better
|| thisScore
[j
] > bestScore
[j
]) {
242 } else if (thisScore
[j
] == bestScore
[j
]) {
257 if (better
&& !worse
) {
259 for (j
= 0; j
< ncriteria
; j
++) {
260 bestScore
[j
] = thisScore
[j
];
275 * Parses strings in the form of:
283 * NOTE that @ before : is not parsed.
286 specialCaseParse(char *word
, Criterion
* criterion
, int mask
)
288 char *xstr
, *response
;
290 int width
, height
, bpp
, hertz
;
303 /* The WWWxHHH case. */
304 if (mask
& (1 << DM_WIDTH
)) {
307 xstr
= strpbrk(&word
[1], "x");
309 width
= (int) strtol(word
, &response
, 0);
310 if (response
== word
|| response
[0] != 'x') {
311 /* Not a valid number OR needs to be followed by 'x'. */
314 height
= (int) strtol(&xstr
[1], &response
, 0);
315 if (response
== &xstr
[1]) {
316 /* Not a valid number. */
319 criterion
[0].capability
= DM_WIDTH
;
320 criterion
[0].comparison
= EQ
;
321 criterion
[0].value
= width
;
322 criterion
[1].capability
= DM_HEIGHT
;
323 criterion
[1].comparison
= EQ
;
324 criterion
[1].value
= height
;
325 got
= specialCaseParse(response
,
326 &criterion
[2], 1 << DM_WIDTH
);
336 if (mask
& (1 << DM_PIXEL_DEPTH
)) {
339 bpp
= (int) strtol(&word
[1], &response
, 0);
340 if (response
== &word
[1]) {
341 /* Not a valid number. */
344 criterion
[0].capability
= DM_PIXEL_DEPTH
;
345 criterion
[0].comparison
= EQ
;
346 criterion
[0].value
= bpp
;
347 got
= specialCaseParse(response
,
348 &criterion
[1], 1 << DM_WIDTH
| 1 << DM_PIXEL_DEPTH
);
356 if (mask
& (1 << DM_HERTZ
)) {
359 hertz
= (int) strtol(&word
[1], &response
, 0);
360 if (response
== &word
[1]) {
361 /* Not a valid number. */
364 criterion
[0].capability
= DM_HERTZ
;
365 criterion
[0].comparison
= EQ
;
366 criterion
[0].value
= hertz
;
367 got
= specialCaseParse(response
,
368 &criterion
[1], ~DM_HERTZ
);
380 /* This routine is based on similiar code in glut_dstr.c */
382 parseCriteria(char *word
, Criterion
* criterion
)
384 char *cstr
, *vstr
, *response
;
385 int comparator
, value
;
387 cstr
= strpbrk(word
, "=><!~");
399 if (cstr
[1] == '=') {
408 if (cstr
[1] == '=') {
417 if (cstr
[1] == '=') {
427 value
= (int) strtol(vstr
, &response
, 0);
428 if (response
== vstr
) {
429 /* Not a valid number. */
438 if (!strcmp(word
, "bpp")) {
439 criterion
[0].capability
= DM_PIXEL_DEPTH
;
440 if (comparator
== NONE
) {
443 criterion
[0].comparison
= comparator
;
444 criterion
[0].value
= value
;
450 if (!strcmp(word
, "height")) {
451 criterion
[0].capability
= DM_HEIGHT
;
452 if (comparator
== NONE
) {
455 criterion
[0].comparison
= comparator
;
456 criterion
[0].value
= value
;
460 if (!strcmp(word
, "hertz")) {
461 criterion
[0].capability
= DM_HERTZ
;
462 if (comparator
== NONE
) {
465 criterion
[0].comparison
= comparator
;
466 criterion
[0].value
= value
;
472 if (!strcmp(word
, "num")) {
473 criterion
[0].capability
= DM_NUM
;
474 if (comparator
== NONE
) {
477 criterion
[0].comparison
= comparator
;
478 criterion
[0].value
= value
;
484 if (!strcmp(word
, "width")) {
485 criterion
[0].capability
= DM_WIDTH
;
486 if (comparator
== NONE
) {
489 criterion
[0].comparison
= comparator
;
490 criterion
[0].value
= value
;
496 if (comparator
== NONE
) {
497 return specialCaseParse(word
, criterion
, 0);
502 /* This routine is based on similiar code in glut_dstr.c */
504 parseDisplayString(const char *display
, int *ncriteria
)
506 Criterion
*criteria
= NULL
;
510 copy
= __glutStrdup(display
);
511 /* Attempt to estimate how many criteria entries should be
514 word
= strtok(copy
, " \t");
517 word
= strtok(NULL
, " \t");
519 /* Allocate number of words of criteria. A word
520 could contain as many as four criteria in the
521 worst case. Example: 800x600:16@60 */
522 criteria
= (Criterion
*) malloc(4 * n
* sizeof(Criterion
));
524 __glutFatalError("out of memory.");
527 /* Re-copy the copy of the display string. */
528 strcpy(copy
, display
);
531 word
= strtok(copy
, " \t");
533 parsed
= parseCriteria(word
, &criteria
[n
]);
537 __glutWarning("Unrecognized game mode string word: %s (ignoring)\n", word
);
539 word
= strtok(NULL
, " \t");
548 glutGameModeString(const char *string
)
553 initGameModeSupport();
554 criteria
= parseDisplayString(string
, &ncriteria
);
555 currentDm
= findMatch(dmodes
, ndmodes
, criteria
, ncriteria
);
560 glutEnterGameMode(void)
566 if (__glutMappedMenu
) {
567 __glutFatalUsage("entering game mode not allowed while menus in use");
569 if (__glutGameModeWindow
) {
570 /* Already in game mode, so blow away game mode
571 window so apps can change resolutions. */
572 window
= __glutGameModeWindow
;
573 /* Setting the game mode window to NULL tricks
574 the window destroy code into not undoing the
575 screen display change since we plan on immediately
576 doing another mode change. */
577 __glutGameModeWindow
= NULL
;
578 __glutDestroyWindow(window
, window
);
581 /* Assume default screen size until we find out if we
582 can actually change the display settings. */
583 width
= __glutScreenWidth
;
584 height
= __glutScreenHeight
;
589 static int registered
= 0;
591 status
= ChangeDisplaySettings(¤tDm
->devmode
,
593 if (status
== DISP_CHANGE_SUCCESSFUL
) {
594 __glutDisplaySettingsChanged
= 1;
595 width
= currentDm
->cap
[DM_WIDTH
];
596 height
= currentDm
->cap
[DM_HEIGHT
];
598 atexit(__glutCloseDownGameMode
);
602 /* Switch back to default resolution. */
603 ChangeDisplaySettings(NULL
, 0);
608 window
= __glutCreateWindow(NULL
, 0, 0,
609 width
, height
, /* game mode */ 1);
613 if (__glutMotifHints
== None
) {
614 __glutMotifHints
= XSGIFastInternAtom(__glutDisplay
, "_MOTIF_WM_HINTS",
615 SGI_XA__MOTIF_WM_HINTS
, 0);
616 if (__glutMotifHints
== None
) {
617 __glutWarning("Could not intern X atom for _MOTIF_WM_HINTS.");
621 /* Game mode window is a toplevel window. */
622 XSetWMProtocols(__glutDisplay
, win
, &__glutWMDeleteWindow
, 1);
625 /* Schedule the fullscreen property to be added and to
626 make sure the window is configured right. Win32
627 doesn't need this. */
628 window
->desiredX
= 0;
629 window
->desiredY
= 0;
630 window
->desiredWidth
= width
;
631 window
->desiredHeight
= height
;
632 window
->desiredConfMask
|= CWX
| CWY
| CWWidth
| CWHeight
;
634 /* Win32 does not want to use GLUT_FULL_SCREEN_WORK
635 for game mode because we need to be maximizing
636 the window in game mode, not just sizing it to
637 take up the full screen. The Win32-ness of game
638 mode happens when you pass 1 in the gameMode parameter
639 to __glutCreateWindow above. A gameMode of creates
640 a WS_POPUP window, not a standard WS_OVERLAPPEDWINDOW
641 window. WS_POPUP ensures the taskbar is hidden. */
642 __glutPutOnWorkList(window
,
643 GLUT_CONFIGURE_WORK
);
645 __glutPutOnWorkList(window
,
646 GLUT_CONFIGURE_WORK
| GLUT_FULL_SCREEN_WORK
);
649 __glutGameModeWindow
= window
;
650 return window
->num
+ 1;
654 glutGameModeGet(GLenum mode
)
657 case GLUT_GAME_MODE_ACTIVE
:
658 return __glutGameModeWindow
!= NULL
;
659 case GLUT_GAME_MODE_POSSIBLE
:
660 return currentDm
!= NULL
;
661 case GLUT_GAME_MODE_WIDTH
:
662 return currentDm
? currentDm
->cap
[DM_WIDTH
] : -1;
663 case GLUT_GAME_MODE_HEIGHT
:
664 return currentDm
? currentDm
->cap
[DM_HEIGHT
] : -1;
665 case GLUT_GAME_MODE_PIXEL_DEPTH
:
666 return currentDm
? currentDm
->cap
[DM_PIXEL_DEPTH
] : -1;
667 case GLUT_GAME_MODE_REFRESH_RATE
:
668 return currentDm
? currentDm
->cap
[DM_HERTZ
] : -1;
669 case GLUT_GAME_MODE_DISPLAY_CHANGED
:
670 return __glutDisplaySettingsChanged
;