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>
22 /* SGI optimization introduced in IRIX 6.3 to avoid X server
23 round trips for interning common X atoms. */
24 #if defined(_SGI_EXTRA_PREDEFINES) && !defined(NO_FAST_ATOMS)
25 #include <X11/SGIFastAtom.h>
27 #define XSGIFastInternAtom(dpy,string,fast_name,how) XInternAtom(dpy,string,how)
29 #endif /* not _WIN32 */
31 int __glutDisplaySettingsChanged
= 0;
32 static DisplayMode
*dmodes
, *currentDm
= NULL
;
33 static int ndmodes
= -1;
34 GLUTwindow
*__glutGameModeWindow
= NULL
;
37 static char *compstr
[] =
39 "none", "=", "!=", "<=", ">=", ">", "<", "~"
41 static char *capstr
[] =
43 "width", "height", "bpp", "hertz", "num"
48 __glutCloseDownGameMode(void)
50 if (__glutDisplaySettingsChanged
) {
52 /* Assumes that display settings have been changed, that
53 is __glutDisplaySettingsChanged is true. */
54 ChangeDisplaySettings(NULL
, 0);
56 __glutDisplaySettingsChanged
= 0;
58 __glutGameModeWindow
= NULL
;
62 glutLeaveGameMode(void)
64 if (__glutGameModeWindow
== NULL
) {
65 __glutWarning("not in game mode so cannot leave game mode");
68 __glutDestroyWindow(__glutGameModeWindow
,
69 __glutGameModeWindow
);
70 XFlush(__glutDisplay
);
71 __glutGameModeWindow
= NULL
;
76 /* Same values as from MSDN's SetDisp.c example. */
78 #define MIN_FREQUENCY 60
81 initGameModeSupport(void)
88 /* ndmodes is initially -1 to indicate no
89 dmodes allocated yet. */
93 /* Determine how many display modes there are. */
96 while (EnumDisplaySettings(NULL
, mode
, &dm
)) {
97 if (dm
.dmPelsWidth
>= MIN_WIDTH
&&
98 (dm
.dmDisplayFrequency
== 0 ||
99 dm
.dmDisplayFrequency
>= MIN_FREQUENCY
)) {
105 /* Allocate memory for a list of all the display modes. */
106 dmodes
= (DisplayMode
*)
107 malloc(ndmodes
* sizeof(DisplayMode
));
109 /* Now that we know how many display modes to expect,
110 enumerate them again and save the information in
111 the list we allocated above. */
114 while (EnumDisplaySettings(NULL
, mode
, &dm
)) {
115 /* Try to reject any display settings that seem unplausible. */
116 if (dm
.dmPelsWidth
>= MIN_WIDTH
&&
117 (dm
.dmDisplayFrequency
== 0 ||
118 dm
.dmDisplayFrequency
>= MIN_FREQUENCY
)) {
119 dmodes
[i
].devmode
= dm
;
120 dmodes
[i
].valid
= 1; /* XXX Not used for now. */
121 dmodes
[i
].cap
[DM_WIDTH
] = dm
.dmPelsWidth
;
122 dmodes
[i
].cap
[DM_HEIGHT
] = dm
.dmPelsHeight
;
123 dmodes
[i
].cap
[DM_PIXEL_DEPTH
] = dm
.dmBitsPerPel
;
124 if (dm
.dmDisplayFrequency
== 0) {
125 /* Guess a reasonable guess. */
126 /* Lame Windows 95 version of EnumDisplaySettings. */
127 dmodes
[i
].cap
[DM_HERTZ
] = 60;
129 dmodes
[i
].cap
[DM_HERTZ
] = dm
.dmDisplayFrequency
;
136 assert(i
== ndmodes
);
141 /* X Windows version of initGameModeSupport. */
143 initGameModeSupport(void)
146 /* ndmodes is initially -1 to indicate no
147 dmodes allocated yet. */
151 /* Determine how many display modes there are. */
157 /* This routine is based on similiar code in glut_dstr.c */
159 findMatch(DisplayMode
* dmodes
, int ndmodes
,
160 Criterion
* criteria
, int ncriteria
)
163 int *bestScore
, *thisScore
;
164 int i
, j
, numok
, result
= 0, worse
, better
;
167 numok
= 1; /* "num" capability is indexed from 1,
170 /* XXX alloca canidate. */
171 bestScore
= (int *) malloc(ncriteria
* sizeof(int));
173 __glutFatalError("out of memory.");
175 for (j
= 0; j
< ncriteria
; j
++) {
176 /* Very negative number. */
177 bestScore
[j
] = -32768;
180 /* XXX alloca canidate. */
181 thisScore
= (int *) malloc(ncriteria
* sizeof(int));
183 __glutFatalError("out of memory.");
186 for (i
= 0; i
< ndmodes
; i
++) {
187 if (dmodes
[i
].valid
) {
191 for (j
= 0; j
< ncriteria
; j
++) {
192 int cap
, cvalue
, dvalue
;
194 cap
= criteria
[j
].capability
;
195 cvalue
= criteria
[j
].value
;
199 dvalue
= dmodes
[i
].cap
[cap
];
203 printf(" %s %s %d to %d\n",
204 capstr
[cap
], compstr
[criteria
[j
].comparison
], cvalue
, dvalue
);
206 switch (criteria
[j
].comparison
) {
208 result
= cvalue
== dvalue
;
212 result
= cvalue
!= dvalue
;
216 result
= dvalue
< cvalue
;
217 thisScore
[j
] = dvalue
- cvalue
;
220 result
= dvalue
> cvalue
;
221 thisScore
[j
] = dvalue
- cvalue
;
224 result
= dvalue
<= cvalue
;
225 thisScore
[j
] = dvalue
- cvalue
;
228 result
= (dvalue
>= cvalue
);
229 thisScore
[j
] = dvalue
- cvalue
;
232 result
= dvalue
>= cvalue
;
233 thisScore
[j
] = cvalue
- dvalue
;
239 printf(" result=%d score=%d bestScore=%d\n", result
, thisScore
[j
], bestScore
[j
]);
243 if (better
|| thisScore
[j
] > bestScore
[j
]) {
245 } else if (thisScore
[j
] == bestScore
[j
]) {
260 if (better
&& !worse
) {
262 for (j
= 0; j
< ncriteria
; j
++) {
263 bestScore
[j
] = thisScore
[j
];
278 * Parses strings in the form of:
286 * NOTE that @ before : is not parsed.
289 specialCaseParse(char *word
, Criterion
* criterion
, int mask
)
291 char *xstr
, *response
;
293 int width
, height
, bpp
, hertz
;
306 /* The WWWxHHH case. */
307 if (mask
& (1 << DM_WIDTH
)) {
310 xstr
= strpbrk(&word
[1], "x");
312 width
= (int) strtol(word
, &response
, 0);
313 if (response
== word
|| response
[0] != 'x') {
314 /* Not a valid number OR needs to be followed by 'x'. */
317 height
= (int) strtol(&xstr
[1], &response
, 0);
318 if (response
== &xstr
[1]) {
319 /* Not a valid number. */
322 criterion
[0].capability
= DM_WIDTH
;
323 criterion
[0].comparison
= EQ
;
324 criterion
[0].value
= width
;
325 criterion
[1].capability
= DM_HEIGHT
;
326 criterion
[1].comparison
= EQ
;
327 criterion
[1].value
= height
;
328 got
= specialCaseParse(response
,
329 &criterion
[2], 1 << DM_WIDTH
);
339 if (mask
& (1 << DM_PIXEL_DEPTH
)) {
342 bpp
= (int) strtol(&word
[1], &response
, 0);
343 if (response
== &word
[1]) {
344 /* Not a valid number. */
347 criterion
[0].capability
= DM_PIXEL_DEPTH
;
348 criterion
[0].comparison
= EQ
;
349 criterion
[0].value
= bpp
;
350 got
= specialCaseParse(response
,
351 &criterion
[1], 1 << DM_WIDTH
| 1 << DM_PIXEL_DEPTH
);
359 if (mask
& (1 << DM_HERTZ
)) {
362 hertz
= (int) strtol(&word
[1], &response
, 0);
363 if (response
== &word
[1]) {
364 /* Not a valid number. */
367 criterion
[0].capability
= DM_HERTZ
;
368 criterion
[0].comparison
= EQ
;
369 criterion
[0].value
= hertz
;
370 got
= specialCaseParse(response
,
371 &criterion
[1], ~DM_HERTZ
);
383 /* This routine is based on similiar code in glut_dstr.c */
385 parseCriteria(char *word
, Criterion
* criterion
)
387 char *cstr
, *vstr
, *response
;
388 int comparator
, value
= 0;
390 cstr
= strpbrk(word
, "=><!~");
402 if (cstr
[1] == '=') {
411 if (cstr
[1] == '=') {
420 if (cstr
[1] == '=') {
430 value
= (int) strtol(vstr
, &response
, 0);
431 if (response
== vstr
) {
432 /* Not a valid number. */
441 if (!strcmp(word
, "bpp")) {
442 criterion
[0].capability
= DM_PIXEL_DEPTH
;
443 if (comparator
== NONE
) {
446 criterion
[0].comparison
= comparator
;
447 criterion
[0].value
= value
;
453 if (!strcmp(word
, "height")) {
454 criterion
[0].capability
= DM_HEIGHT
;
455 if (comparator
== NONE
) {
458 criterion
[0].comparison
= comparator
;
459 criterion
[0].value
= value
;
463 if (!strcmp(word
, "hertz")) {
464 criterion
[0].capability
= DM_HERTZ
;
465 if (comparator
== NONE
) {
468 criterion
[0].comparison
= comparator
;
469 criterion
[0].value
= value
;
475 if (!strcmp(word
, "num")) {
476 criterion
[0].capability
= DM_NUM
;
477 if (comparator
== NONE
) {
480 criterion
[0].comparison
= comparator
;
481 criterion
[0].value
= value
;
487 if (!strcmp(word
, "width")) {
488 criterion
[0].capability
= DM_WIDTH
;
489 if (comparator
== NONE
) {
492 criterion
[0].comparison
= comparator
;
493 criterion
[0].value
= value
;
499 if (comparator
== NONE
) {
500 return specialCaseParse(word
, criterion
, 0);
505 /* This routine is based on similiar code in glut_dstr.c */
507 parseDisplayString(const char *display
, int *ncriteria
)
509 Criterion
*criteria
= NULL
;
513 copy
= __glutStrdup(display
);
514 /* Attempt to estimate how many criteria entries should be
517 word
= strtok(copy
, " \t");
520 word
= strtok(NULL
, " \t");
522 /* Allocate number of words of criteria. A word
523 could contain as many as four criteria in the
524 worst case. Example: 800x600:16@60 */
525 criteria
= (Criterion
*) malloc(4 * n
* sizeof(Criterion
));
527 __glutFatalError("out of memory.");
530 /* Re-copy the copy of the display string. */
531 strcpy(copy
, display
);
534 word
= strtok(copy
, " \t");
536 parsed
= parseCriteria(word
, &criteria
[n
]);
540 __glutWarning("Unrecognized game mode string word: %s (ignoring)\n", word
);
542 word
= strtok(NULL
, " \t");
551 glutGameModeString(const char *string
)
556 initGameModeSupport();
557 criteria
= parseDisplayString(string
, &ncriteria
);
558 currentDm
= findMatch(dmodes
, ndmodes
, criteria
, ncriteria
);
563 glutEnterGameMode(void)
569 if (__glutMappedMenu
) {
570 __glutFatalUsage("entering game mode not allowed while menus in use");
572 if (__glutGameModeWindow
) {
573 /* Already in game mode, so blow away game mode
574 window so apps can change resolutions. */
575 window
= __glutGameModeWindow
;
576 /* Setting the game mode window to NULL tricks
577 the window destroy code into not undoing the
578 screen display change since we plan on immediately
579 doing another mode change. */
580 __glutGameModeWindow
= NULL
;
581 __glutDestroyWindow(window
, window
);
584 /* Assume default screen size until we find out if we
585 can actually change the display settings. */
586 width
= __glutScreenWidth
;
587 height
= __glutScreenHeight
;
592 static int registered
= 0;
594 status
= ChangeDisplaySettings(¤tDm
->devmode
,
596 if (status
== DISP_CHANGE_SUCCESSFUL
) {
597 __glutDisplaySettingsChanged
= 1;
598 width
= currentDm
->cap
[DM_WIDTH
];
599 height
= currentDm
->cap
[DM_HEIGHT
];
601 atexit(__glutCloseDownGameMode
);
605 /* Switch back to default resolution. */
606 ChangeDisplaySettings(NULL
, 0);
611 window
= __glutCreateWindow(NULL
, 0, 0,
612 width
, height
, /* game mode */ 1);
616 if (__glutMotifHints
== None
) {
617 __glutMotifHints
= XSGIFastInternAtom(__glutDisplay
, "_MOTIF_WM_HINTS",
618 SGI_XA__MOTIF_WM_HINTS
, 0);
619 if (__glutMotifHints
== None
) {
620 __glutWarning("Could not intern X atom for _MOTIF_WM_HINTS.");
624 /* Game mode window is a toplevel window. */
625 XSetWMProtocols(__glutDisplay
, win
, &__glutWMDeleteWindow
, 1);
628 /* Schedule the fullscreen property to be added and to
629 make sure the window is configured right. Win32
630 doesn't need this. */
631 window
->desiredX
= 0;
632 window
->desiredY
= 0;
633 window
->desiredWidth
= width
;
634 window
->desiredHeight
= height
;
635 window
->desiredConfMask
|= CWX
| CWY
| CWWidth
| CWHeight
;
637 /* Win32 does not want to use GLUT_FULL_SCREEN_WORK
638 for game mode because we need to be maximizing
639 the window in game mode, not just sizing it to
640 take up the full screen. The Win32-ness of game
641 mode happens when you pass 1 in the gameMode parameter
642 to __glutCreateWindow above. A gameMode of creates
643 a WS_POPUP window, not a standard WS_OVERLAPPEDWINDOW
644 window. WS_POPUP ensures the taskbar is hidden. */
645 __glutPutOnWorkList(window
,
646 GLUT_CONFIGURE_WORK
);
648 __glutPutOnWorkList(window
,
649 GLUT_CONFIGURE_WORK
| GLUT_FULL_SCREEN_WORK
);
652 __glutGameModeWindow
= window
;
653 return window
->num
+ 1;
657 glutGameModeGet(GLenum mode
)
660 case GLUT_GAME_MODE_ACTIVE
:
661 return __glutGameModeWindow
!= NULL
;
662 case GLUT_GAME_MODE_POSSIBLE
:
663 return currentDm
!= NULL
;
664 case GLUT_GAME_MODE_WIDTH
:
665 return currentDm
? currentDm
->cap
[DM_WIDTH
] : -1;
666 case GLUT_GAME_MODE_HEIGHT
:
667 return currentDm
? currentDm
->cap
[DM_HEIGHT
] : -1;
668 case GLUT_GAME_MODE_PIXEL_DEPTH
:
669 return currentDm
? currentDm
->cap
[DM_PIXEL_DEPTH
] : -1;
670 case GLUT_GAME_MODE_REFRESH_RATE
:
671 return currentDm
? currentDm
->cap
[DM_HERTZ
] : -1;
672 case GLUT_GAME_MODE_DISPLAY_CHANGED
:
673 return __glutDisplaySettingsChanged
;