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. */
9 #include <GL/vms_x_fix.h>
21 #include <X11/Xatom.h>
23 /* SGI optimization introduced in IRIX 6.3 to avoid X server
24 round trips for interning common X atoms. */
25 #if defined(_SGI_EXTRA_PREDEFINES) && !defined(NO_FAST_ATOMS)
26 #include <X11/SGIFastAtom.h>
28 #define XSGIFastInternAtom(dpy,string,fast_name,how) XInternAtom(dpy,string,how)
30 #endif /* not _WIN32 */
32 int __glutDisplaySettingsChanged
= 0;
33 static DisplayMode
*dmodes
, *currentDm
= NULL
;
34 static int ndmodes
= -1;
35 GLUTwindow
*__glutGameModeWindow
= NULL
;
38 static char *compstr
[] =
40 "none", "=", "!=", "<=", ">=", ">", "<", "~"
42 static char *capstr
[] =
44 "width", "height", "bpp", "hertz", "num"
49 __glutCloseDownGameMode(void)
51 if (__glutDisplaySettingsChanged
) {
53 /* Assumes that display settings have been changed, that
54 is __glutDisplaySettingsChanged is true. */
55 ChangeDisplaySettings(NULL
, 0);
57 __glutDisplaySettingsChanged
= 0;
59 __glutGameModeWindow
= NULL
;
63 glutLeaveGameMode(void)
65 if (__glutGameModeWindow
== NULL
) {
66 __glutWarning("not in game mode so cannot leave game mode");
69 __glutDestroyWindow(__glutGameModeWindow
,
70 __glutGameModeWindow
);
71 XFlush(__glutDisplay
);
72 __glutGameModeWindow
= NULL
;
77 /* Same values as from MSDN's SetDisp.c example. */
79 #define MIN_FREQUENCY 60
82 initGameModeSupport(void)
89 /* ndmodes is initially -1 to indicate no
90 dmodes allocated yet. */
94 /* Determine how many display modes there are. */
97 while (EnumDisplaySettings(NULL
, mode
, &dm
)) {
98 if (dm
.dmPelsWidth
>= MIN_WIDTH
&&
99 (dm
.dmDisplayFrequency
== 0 ||
100 dm
.dmDisplayFrequency
>= MIN_FREQUENCY
)) {
106 /* Allocate memory for a list of all the display modes. */
107 dmodes
= (DisplayMode
*)
108 malloc(ndmodes
* sizeof(DisplayMode
));
110 /* Now that we know how many display modes to expect,
111 enumerate them again and save the information in
112 the list we allocated above. */
115 while (EnumDisplaySettings(NULL
, mode
, &dm
)) {
116 /* Try to reject any display settings that seem unplausible. */
117 if (dm
.dmPelsWidth
>= MIN_WIDTH
&&
118 (dm
.dmDisplayFrequency
== 0 ||
119 dm
.dmDisplayFrequency
>= MIN_FREQUENCY
)) {
120 dmodes
[i
].devmode
= dm
;
121 dmodes
[i
].valid
= 1; /* XXX Not used for now. */
122 dmodes
[i
].cap
[DM_WIDTH
] = dm
.dmPelsWidth
;
123 dmodes
[i
].cap
[DM_HEIGHT
] = dm
.dmPelsHeight
;
124 dmodes
[i
].cap
[DM_PIXEL_DEPTH
] = dm
.dmBitsPerPel
;
125 if (dm
.dmDisplayFrequency
== 0) {
126 /* Guess a reasonable guess. */
127 /* Lame Windows 95 version of EnumDisplaySettings. */
128 dmodes
[i
].cap
[DM_HERTZ
] = 60;
130 dmodes
[i
].cap
[DM_HERTZ
] = dm
.dmDisplayFrequency
;
137 assert(i
== ndmodes
);
142 /* X Windows version of initGameModeSupport. */
144 initGameModeSupport(void)
147 /* ndmodes is initially -1 to indicate no
148 dmodes allocated yet. */
152 /* Determine how many display modes there are. */
158 /* This routine is based on similiar code in glut_dstr.c */
160 findMatch(DisplayMode
* dmodes
, int ndmodes
,
161 Criterion
* criteria
, int ncriteria
)
164 int *bestScore
, *thisScore
;
165 int i
, j
, numok
, result
= 0, worse
, better
;
168 numok
= 1; /* "num" capability is indexed from 1,
171 /* XXX alloca canidate. */
172 bestScore
= (int *) malloc(ncriteria
* sizeof(int));
174 __glutFatalError("out of memory.");
176 for (j
= 0; j
< ncriteria
; j
++) {
177 /* Very negative number. */
178 bestScore
[j
] = -32768;
181 /* XXX alloca canidate. */
182 thisScore
= (int *) malloc(ncriteria
* sizeof(int));
184 __glutFatalError("out of memory.");
187 for (i
= 0; i
< ndmodes
; i
++) {
188 if (dmodes
[i
].valid
) {
192 for (j
= 0; j
< ncriteria
; j
++) {
193 int cap
, cvalue
, dvalue
;
195 cap
= criteria
[j
].capability
;
196 cvalue
= criteria
[j
].value
;
200 dvalue
= dmodes
[i
].cap
[cap
];
204 printf(" %s %s %d to %d\n",
205 capstr
[cap
], compstr
[criteria
[j
].comparison
], cvalue
, dvalue
);
207 switch (criteria
[j
].comparison
) {
209 result
= cvalue
== dvalue
;
213 result
= cvalue
!= dvalue
;
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
] = dvalue
- cvalue
;
233 result
= dvalue
>= cvalue
;
234 thisScore
[j
] = cvalue
- dvalue
;
240 printf(" result=%d score=%d bestScore=%d\n", result
, thisScore
[j
], bestScore
[j
]);
244 if (better
|| thisScore
[j
] > bestScore
[j
]) {
246 } else if (thisScore
[j
] == bestScore
[j
]) {
261 if (better
&& !worse
) {
263 for (j
= 0; j
< ncriteria
; j
++) {
264 bestScore
[j
] = thisScore
[j
];
279 * Parses strings in the form of:
287 * NOTE that @ before : is not parsed.
290 specialCaseParse(char *word
, Criterion
* criterion
, int mask
)
292 char *xstr
, *response
;
294 int width
, height
, bpp
, hertz
;
307 /* The WWWxHHH case. */
308 if (mask
& (1 << DM_WIDTH
)) {
311 xstr
= strpbrk(&word
[1], "x");
313 width
= (int) strtol(word
, &response
, 0);
314 if (response
== word
|| response
[0] != 'x') {
315 /* Not a valid number OR needs to be followed by 'x'. */
318 height
= (int) strtol(&xstr
[1], &response
, 0);
319 if (response
== &xstr
[1]) {
320 /* Not a valid number. */
323 criterion
[0].capability
= DM_WIDTH
;
324 criterion
[0].comparison
= EQ
;
325 criterion
[0].value
= width
;
326 criterion
[1].capability
= DM_HEIGHT
;
327 criterion
[1].comparison
= EQ
;
328 criterion
[1].value
= height
;
329 got
= specialCaseParse(response
,
330 &criterion
[2], 1 << DM_WIDTH
);
340 if (mask
& (1 << DM_PIXEL_DEPTH
)) {
343 bpp
= (int) strtol(&word
[1], &response
, 0);
344 if (response
== &word
[1]) {
345 /* Not a valid number. */
348 criterion
[0].capability
= DM_PIXEL_DEPTH
;
349 criterion
[0].comparison
= EQ
;
350 criterion
[0].value
= bpp
;
351 got
= specialCaseParse(response
,
352 &criterion
[1], 1 << DM_WIDTH
| 1 << DM_PIXEL_DEPTH
);
360 if (mask
& (1 << DM_HERTZ
)) {
363 hertz
= (int) strtol(&word
[1], &response
, 0);
364 if (response
== &word
[1]) {
365 /* Not a valid number. */
368 criterion
[0].capability
= DM_HERTZ
;
369 criterion
[0].comparison
= EQ
;
370 criterion
[0].value
= hertz
;
371 got
= specialCaseParse(response
,
372 &criterion
[1], ~DM_HERTZ
);
384 /* This routine is based on similiar code in glut_dstr.c */
386 parseCriteria(char *word
, Criterion
* criterion
)
388 char *cstr
, *vstr
, *response
;
389 int comparator
, value
= 0;
391 cstr
= strpbrk(word
, "=><!~");
403 if (cstr
[1] == '=') {
412 if (cstr
[1] == '=') {
421 if (cstr
[1] == '=') {
431 value
= (int) strtol(vstr
, &response
, 0);
432 if (response
== vstr
) {
433 /* Not a valid number. */
442 if (!strcmp(word
, "bpp")) {
443 criterion
[0].capability
= DM_PIXEL_DEPTH
;
444 if (comparator
== NONE
) {
447 criterion
[0].comparison
= comparator
;
448 criterion
[0].value
= value
;
454 if (!strcmp(word
, "height")) {
455 criterion
[0].capability
= DM_HEIGHT
;
456 if (comparator
== NONE
) {
459 criterion
[0].comparison
= comparator
;
460 criterion
[0].value
= value
;
464 if (!strcmp(word
, "hertz")) {
465 criterion
[0].capability
= DM_HERTZ
;
466 if (comparator
== NONE
) {
469 criterion
[0].comparison
= comparator
;
470 criterion
[0].value
= value
;
476 if (!strcmp(word
, "num")) {
477 criterion
[0].capability
= DM_NUM
;
478 if (comparator
== NONE
) {
481 criterion
[0].comparison
= comparator
;
482 criterion
[0].value
= value
;
488 if (!strcmp(word
, "width")) {
489 criterion
[0].capability
= DM_WIDTH
;
490 if (comparator
== NONE
) {
493 criterion
[0].comparison
= comparator
;
494 criterion
[0].value
= value
;
500 if (comparator
== NONE
) {
501 return specialCaseParse(word
, criterion
, 0);
506 /* This routine is based on similiar code in glut_dstr.c */
508 parseDisplayString(const char *display
, int *ncriteria
)
510 Criterion
*criteria
= NULL
;
514 copy
= __glutStrdup(display
);
515 /* Attempt to estimate how many criteria entries should be
518 word
= strtok(copy
, " \t");
521 word
= strtok(NULL
, " \t");
523 /* Allocate number of words of criteria. A word
524 could contain as many as four criteria in the
525 worst case. Example: 800x600:16@60 */
526 criteria
= (Criterion
*) malloc(4 * n
* sizeof(Criterion
));
528 __glutFatalError("out of memory.");
531 /* Re-copy the copy of the display string. */
532 strcpy(copy
, display
);
535 word
= strtok(copy
, " \t");
537 parsed
= parseCriteria(word
, &criteria
[n
]);
541 __glutWarning("Unrecognized game mode string word: %s (ignoring)\n", word
);
543 word
= strtok(NULL
, " \t");
552 glutGameModeString(const char *string
)
557 initGameModeSupport();
558 criteria
= parseDisplayString(string
, &ncriteria
);
559 currentDm
= findMatch(dmodes
, ndmodes
, criteria
, ncriteria
);
564 glutEnterGameMode(void)
570 if (__glutMappedMenu
) {
571 __glutFatalUsage("entering game mode not allowed while menus in use");
573 if (__glutGameModeWindow
) {
574 /* Already in game mode, so blow away game mode
575 window so apps can change resolutions. */
576 window
= __glutGameModeWindow
;
577 /* Setting the game mode window to NULL tricks
578 the window destroy code into not undoing the
579 screen display change since we plan on immediately
580 doing another mode change. */
581 __glutGameModeWindow
= NULL
;
582 __glutDestroyWindow(window
, window
);
585 /* Assume default screen size until we find out if we
586 can actually change the display settings. */
587 width
= __glutScreenWidth
;
588 height
= __glutScreenHeight
;
593 static int registered
= 0;
595 status
= ChangeDisplaySettings(¤tDm
->devmode
,
597 if (status
== DISP_CHANGE_SUCCESSFUL
) {
598 __glutDisplaySettingsChanged
= 1;
599 width
= currentDm
->cap
[DM_WIDTH
];
600 height
= currentDm
->cap
[DM_HEIGHT
];
602 atexit(__glutCloseDownGameMode
);
606 /* Switch back to default resolution. */
607 ChangeDisplaySettings(NULL
, 0);
612 window
= __glutCreateWindow(NULL
, 0, 0,
613 width
, height
, /* game mode */ 1);
617 if (__glutMotifHints
== None
) {
618 __glutMotifHints
= XSGIFastInternAtom(__glutDisplay
, "_MOTIF_WM_HINTS",
619 SGI_XA__MOTIF_WM_HINTS
, 0);
620 if (__glutMotifHints
== None
) {
621 __glutWarning("Could not intern X atom for _MOTIF_WM_HINTS.");
625 /* Game mode window is a toplevel window. */
626 XSetWMProtocols(__glutDisplay
, win
, &__glutWMDeleteWindow
, 1);
629 /* Schedule the fullscreen property to be added and to
630 make sure the window is configured right. Win32
631 doesn't need this. */
632 window
->desiredX
= 0;
633 window
->desiredY
= 0;
634 window
->desiredWidth
= width
;
635 window
->desiredHeight
= height
;
636 window
->desiredConfMask
|= CWX
| CWY
| CWWidth
| CWHeight
;
638 /* Win32 does not want to use GLUT_FULL_SCREEN_WORK
639 for game mode because we need to be maximizing
640 the window in game mode, not just sizing it to
641 take up the full screen. The Win32-ness of game
642 mode happens when you pass 1 in the gameMode parameter
643 to __glutCreateWindow above. A gameMode of creates
644 a WS_POPUP window, not a standard WS_OVERLAPPEDWINDOW
645 window. WS_POPUP ensures the taskbar is hidden. */
646 __glutPutOnWorkList(window
,
647 GLUT_CONFIGURE_WORK
);
649 __glutPutOnWorkList(window
,
650 GLUT_CONFIGURE_WORK
| GLUT_FULL_SCREEN_WORK
);
653 __glutGameModeWindow
= window
;
654 return window
->num
+ 1;
658 glutGameModeGet(GLenum mode
)
661 case GLUT_GAME_MODE_ACTIVE
:
662 return __glutGameModeWindow
!= NULL
;
663 case GLUT_GAME_MODE_POSSIBLE
:
664 return currentDm
!= NULL
;
665 case GLUT_GAME_MODE_WIDTH
:
666 return currentDm
? currentDm
->cap
[DM_WIDTH
] : -1;
667 case GLUT_GAME_MODE_HEIGHT
:
668 return currentDm
? currentDm
->cap
[DM_HEIGHT
] : -1;
669 case GLUT_GAME_MODE_PIXEL_DEPTH
:
670 return currentDm
? currentDm
->cap
[DM_PIXEL_DEPTH
] : -1;
671 case GLUT_GAME_MODE_REFRESH_RATE
:
672 return currentDm
? currentDm
->cap
[DM_HERTZ
] : -1;
673 case GLUT_GAME_MODE_DISPLAY_CHANGED
:
674 return __glutDisplaySettingsChanged
;