replace APIENTRY with GLUTAPIENTRY to be consistant with glut.h
[mesa.git] / src / glut / glx / glut_dstr.c
1
2 /* Copyright (c) Mark J. Kilgard, 1997. */
3
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. */
7
8 #include <assert.h>
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include "glutint.h"
13
14 /* glxcaps matches the criteria macros listed in glutint.h, but
15 only list the first set (those that correspond to GLX visual
16 attributes). */
17 static int glxcap[NUM_GLXCAPS] =
18 {
19 GLX_RGBA,
20 GLX_BUFFER_SIZE,
21 GLX_DOUBLEBUFFER,
22 GLX_STEREO,
23 GLX_AUX_BUFFERS,
24 GLX_RED_SIZE,
25 GLX_GREEN_SIZE,
26 GLX_BLUE_SIZE,
27 GLX_ALPHA_SIZE,
28 GLX_DEPTH_SIZE,
29 GLX_STENCIL_SIZE,
30 GLX_ACCUM_RED_SIZE,
31 GLX_ACCUM_GREEN_SIZE,
32 GLX_ACCUM_BLUE_SIZE,
33 GLX_ACCUM_ALPHA_SIZE,
34 GLX_LEVEL,
35 };
36
37 #ifdef TEST
38
39 #if !defined(_WIN32)
40 char *__glutProgramName = "dstr";
41 Display *__glutDisplay;
42 int __glutScreen;
43 XVisualInfo *(*__glutDetermineVisualFromString) (char *string, Bool * treatAsSingle,
44 Criterion * requiredCriteria, int nRequired, int requiredMask, void **fbc) = NULL;
45 char *__glutDisplayString = NULL;
46 #endif
47 static int verbose = 0;
48
49 static char *compstr[] =
50 {
51 "none", "=", "!=", "<=", ">=", ">", "<", "~"
52 };
53 static char *capstr[] =
54 {
55 "rgba", "bufsize", "double", "stereo", "auxbufs", "red", "green", "blue", "alpha",
56 "depth", "stencil", "acred", "acgreen", "acblue", "acalpha", "level", "xvisual",
57 "transparent", "samples", "xstaticgray", "xgrayscale", "xstaticcolor", "xpseudocolor",
58 "xtruecolor", "xdirectcolor", "slow", "conformant", "num"
59 };
60
61 static void
62 printCriteria(Criterion * criteria, int ncriteria)
63 {
64 int i;
65 printf("Criteria: %d\n", ncriteria);
66 for (i = 0; i < ncriteria; i++) {
67 printf(" %s %s %d\n",
68 capstr[criteria[i].capability],
69 compstr[criteria[i].comparison],
70 criteria[i].value);
71 }
72 }
73
74 #endif /* TEST */
75
76 static int isMesaGLX = -1;
77
78 static int
79 determineMesaGLX(void)
80 {
81 #ifdef GLX_VERSION_1_1
82 const char *vendor, *version, *ch;
83
84 vendor = glXGetClientString(__glutDisplay, GLX_VENDOR);
85 if (!strcmp(vendor, "Brian Paul")) {
86 version = glXGetClientString(__glutDisplay, GLX_VERSION);
87 for (ch = version; *ch != ' ' && *ch != '\0'; ch++);
88 for (; *ch == ' ' && *ch != '\0'; ch++);
89
90 #define MESA_NAME "Mesa " /* Trailing space is intentional. */
91
92 if (!strncmp(MESA_NAME, ch, sizeof(MESA_NAME) - 1)) {
93 return 1;
94 }
95 }
96 #else
97 /* Recent versions for Mesa should support GLX 1.1 and
98 therefore glXGetClientString. If we get into this case,
99 we would be compiling against a true OpenGL not supporting
100 GLX 1.1, and the resulting compiled library won't work well
101 with Mesa then. */
102 #endif
103 return 0;
104 }
105
106 static XVisualInfo **
107 getMesaVisualList(int *n)
108 {
109 XVisualInfo **vlist, *vinfo;
110 int attribs[23];
111 int i, x, cnt;
112
113 vlist = (XVisualInfo **) malloc((32 + 16) * sizeof(XVisualInfo *));
114 if (!vlist)
115 __glutFatalError("out of memory.");
116
117 cnt = 0;
118 for (i = 0; i < 32; i++) {
119 x = 0;
120 attribs[x] = GLX_RGBA;
121 x++;
122 attribs[x] = GLX_RED_SIZE;
123 x++;
124 attribs[x] = 1;
125 x++;
126 attribs[x] = GLX_GREEN_SIZE;
127 x++;
128 attribs[x] = 1;
129 x++;
130 attribs[x] = GLX_BLUE_SIZE;
131 x++;
132 attribs[x] = 1;
133 x++;
134 if (i & 1) {
135 attribs[x] = GLX_DEPTH_SIZE;
136 x++;
137 attribs[x] = 1;
138 x++;
139 }
140 if (i & 2) {
141 attribs[x] = GLX_STENCIL_SIZE;
142 x++;
143 attribs[x] = 1;
144 x++;
145 }
146 if (i & 4) {
147 attribs[x] = GLX_ACCUM_RED_SIZE;
148 x++;
149 attribs[x] = 1;
150 x++;
151 attribs[x] = GLX_ACCUM_GREEN_SIZE;
152 x++;
153 attribs[x] = 1;
154 x++;
155 attribs[x] = GLX_ACCUM_BLUE_SIZE;
156 x++;
157 attribs[x] = 1;
158 x++;
159 }
160 if (i & 8) {
161 attribs[x] = GLX_ALPHA_SIZE;
162 x++;
163 attribs[x] = 1;
164 x++;
165 if (i & 4) {
166 attribs[x] = GLX_ACCUM_ALPHA_SIZE;
167 x++;
168 attribs[x] = 1;
169 x++;
170 }
171 }
172 if (i & 16) {
173 attribs[x] = GLX_DOUBLEBUFFER;
174 x++;
175 }
176 attribs[x] = None;
177 x++;
178 assert(x <= sizeof(attribs) / sizeof(attribs[0]));
179 vinfo = glXChooseVisual(__glutDisplay, __glutScreen, attribs);
180 if (vinfo) {
181 vlist[cnt] = vinfo;
182 cnt++;
183 }
184 }
185 for (i = 0; i < 16; i++) {
186 x = 0;
187 if (i & 1) {
188 attribs[x] = GLX_DEPTH_SIZE;
189 x++;
190 attribs[x] = 1;
191 x++;
192 }
193 if (i & 2) {
194 attribs[x] = GLX_STENCIL_SIZE;
195 x++;
196 attribs[x] = 1;
197 x++;
198 }
199 if (i & 4) {
200 attribs[x] = GLX_DOUBLEBUFFER;
201 x++;
202 }
203 if (i & 8) {
204 attribs[x] = GLX_LEVEL;
205 x++;
206 attribs[x] = 1;
207 x++;
208 #if defined(GLX_TRANSPARENT_TYPE_EXT) && defined(GLX_TRANSPARENT_INDEX_EXT)
209 attribs[x] = GLX_TRANSPARENT_TYPE_EXT;
210 x++;
211 attribs[x] = GLX_TRANSPARENT_INDEX_EXT;
212 x++;
213 #endif
214 }
215 attribs[x] = None;
216 x++;
217 assert(x <= sizeof(attribs) / sizeof(attribs[0]));
218 vinfo = glXChooseVisual(__glutDisplay, __glutScreen, attribs);
219 if (vinfo) {
220 vlist[cnt] = vinfo;
221 cnt++;
222 }
223 }
224
225 *n = cnt;
226 return vlist;
227 }
228
229 static FrameBufferMode *
230 loadVisuals(int *nitems_return)
231 {
232 XVisualInfo *vinfo, **vlist, template;
233 FrameBufferMode *fbmodes, *mode;
234 int n, i, j, rc, glcapable;
235 #if defined(GLX_VERSION_1_1) && defined(GLX_SGIS_multisample)
236 int multisample;
237 #endif
238 #if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_info)
239 int visual_info;
240 #endif
241 #if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_rating)
242 int visual_rating;
243 #endif
244 #if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_fbconfig)
245 int fbconfig;
246 #endif
247
248 isMesaGLX = determineMesaGLX();
249 if (isMesaGLX) {
250 vlist = getMesaVisualList(&n);
251 } else {
252 #if !defined(_WIN32)
253 template.screen = __glutScreen;
254 vinfo = XGetVisualInfo(__glutDisplay, VisualScreenMask, &template, &n);
255 #else
256 vinfo = XGetVisualInfo(__glutDisplay, 0, &template, &n);
257 #endif
258 if (vinfo == NULL) {
259 *nitems_return = 0;
260 return NULL;
261 }
262 assert(n > 0);
263
264 /* Make an array of XVisualInfo* pointers to help the Mesa
265 case because each glXChooseVisual call returns a
266 distinct XVisualInfo*, not a handy array like
267 XGetVisualInfo. (Mesa expects us to return the _exact_
268 pointer returned by glXChooseVisual so we could not just
269 copy the returned structure.) */
270 vlist = (XVisualInfo **) malloc(n * sizeof(XVisualInfo *));
271 if (!vlist)
272 __glutFatalError("out of memory.");
273 for (i = 0; i < n; i++) {
274 vlist[i] = &vinfo[i];
275 }
276 }
277
278 #if defined(GLX_VERSION_1_1) && defined(GLX_SGIS_multisample)
279 multisample = __glutIsSupportedByGLX("GLX_SGIS_multisample");
280 #endif
281 #if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_info)
282 visual_info = __glutIsSupportedByGLX("GLX_EXT_visual_info");
283 #endif
284 #if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_rating)
285 visual_rating = __glutIsSupportedByGLX("GLX_EXT_visual_rating");
286 #endif
287 #if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_fbconfig)
288 fbconfig = __glutIsSupportedByGLX("GLX_SGIX_fbconfig");
289 #endif
290
291 fbmodes = (FrameBufferMode *) malloc(n * sizeof(FrameBufferMode));
292 if (fbmodes == NULL) {
293 *nitems_return = -1;
294 return NULL;
295 }
296 for (i = 0; i < n; i++) {
297 mode = &fbmodes[i];
298 mode->vi = vlist[i];
299 #if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_fbconfig)
300 mode->fbc = NULL;
301 #endif
302 rc = glXGetConfig(__glutDisplay, vlist[i], GLX_USE_GL, &glcapable);
303 if (rc == 0 && glcapable) {
304 mode->valid = 1; /* Assume the best until proven
305 otherwise. */
306 for (j = 0; j < NUM_GLXCAPS; j++) {
307 rc = glXGetConfig(__glutDisplay, vlist[i], glxcap[j], &mode->cap[j]);
308 if (rc != 0) {
309 mode->valid = 0;
310 }
311 }
312 #if defined(_WIN32)
313 mode->cap[XVISUAL] = ChoosePixelFormat(XHDC, vlist[i]);
314 #else
315 mode->cap[XVISUAL] = (int) vlist[i]->visualid;
316 #endif
317 mode->cap[XSTATICGRAY] = 0;
318 mode->cap[XGRAYSCALE] = 0;
319 mode->cap[XSTATICCOLOR] = 0;
320 mode->cap[XPSEUDOCOLOR] = 0;
321 mode->cap[XTRUECOLOR] = 0;
322 mode->cap[XDIRECTCOLOR] = 0;
323 #if !defined(_WIN32)
324 #if defined(__cplusplus) || defined(c_plusplus)
325 switch (vlist[i]->c_class) {
326 #else
327 switch (vlist[i]->class) {
328 #endif
329 case StaticGray:
330 mode->cap[XSTATICGRAY] = 1;
331 break;
332 case GrayScale:
333 mode->cap[XGRAYSCALE] = 1;
334 break;
335 case StaticColor:
336 mode->cap[XSTATICCOLOR] = 1;
337 break;
338 case PseudoColor:
339 mode->cap[XPSEUDOCOLOR] = 1;
340 break;
341 case TrueColor:
342 mode->cap[XTRUECOLOR] = 1;
343 break;
344 case DirectColor:
345 mode->cap[XDIRECTCOLOR] = 1;
346 break;
347 }
348 #endif
349 #if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_rating)
350 if (visual_rating) {
351 int rating;
352
353 /* babcock@cs.montana.edu reported that DEC UNIX (OSF1) V4.0
354 564 for Alpha did not properly define GLX_VISUAL_CAVEAT_EXT
355 in <GL/glx.h> despite claiming to support
356 GLX_EXT_visual_rating. */
357 #ifndef GLX_VISUAL_CAVEAT_EXT
358 #define GLX_VISUAL_CAVEAT_EXT 0x20
359 #endif
360
361 rc = glXGetConfig(__glutDisplay,
362 vlist[i], GLX_VISUAL_CAVEAT_EXT, &rating);
363 if (rc != 0) {
364 mode->cap[SLOW] = 0;
365 mode->cap[CONFORMANT] = 1;
366 } else {
367 switch (rating) {
368 case GLX_SLOW_VISUAL_EXT:
369 mode->cap[SLOW] = 1;
370 mode->cap[CONFORMANT] = 1;
371 break;
372
373 /* IRIX 5.3 for the R10K Indigo2 may have shipped without this
374 properly defined in /usr/include/GL/glxtokens.h */
375 #ifndef GLX_NON_CONFORMANT_VISUAL_EXT
376 #define GLX_NON_CONFORMANT_VISUAL_EXT 0x800D
377 #endif
378
379 case GLX_NON_CONFORMANT_VISUAL_EXT:
380 mode->cap[SLOW] = 0;
381 mode->cap[CONFORMANT] = 0;
382 break;
383 case GLX_NONE_EXT:
384 default: /* XXX Hopefully this is a good default
385 assumption. */
386 mode->cap[SLOW] = 0;
387 mode->cap[CONFORMANT] = 1;
388 break;
389 }
390 }
391 } else {
392 mode->cap[TRANSPARENT] = 0;
393 }
394 #else
395 mode->cap[SLOW] = 0;
396 mode->cap[CONFORMANT] = 1;
397 #endif
398 #if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_info)
399 if (visual_info) {
400 int transparent;
401
402 /* babcock@cs.montana.edu reported that DEC UNIX (OSF1) V4.0
403 564 for Alpha did not properly define
404 GLX_TRANSPARENT_TYPE_EXT in <GL/glx.h> despite claiming to
405 support GLX_EXT_visual_info. */
406 #ifndef GLX_TRANSPARENT_TYPE_EXT
407 #define GLX_TRANSPARENT_TYPE_EXT 0x23
408 #endif
409
410 rc = glXGetConfig(__glutDisplay,
411 vlist[i], GLX_TRANSPARENT_TYPE_EXT, &transparent);
412 if (rc != 0) {
413 mode->cap[TRANSPARENT] = 0;
414 } else {
415 mode->cap[TRANSPARENT] = (transparent != GLX_NONE_EXT);
416 }
417 } else {
418 mode->cap[TRANSPARENT] = 0;
419 }
420 #else
421 mode->cap[TRANSPARENT] = 0;
422 #endif
423 #if defined(GLX_VERSION_1_1) && defined(GLX_SGIS_multisample)
424 if (multisample) {
425 rc = glXGetConfig(__glutDisplay,
426 vlist[i], GLX_SAMPLES_SGIS, &mode->cap[SAMPLES]);
427 if (rc != 0) {
428 mode->cap[SAMPLES] = 0;
429 }
430 } else {
431 mode->cap[SAMPLES] = 0;
432 }
433 #else
434 mode->cap[SAMPLES] = 0;
435 #endif
436 } else {
437 #if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_fbconfig)
438 if (fbconfig) {
439 GLXFBConfigSGIX fbc;
440 int fbconfigID, drawType, renderType;
441
442 fbc = __glut_glXGetFBConfigFromVisualSGIX(__glutDisplay, vlist[i]);
443 if (fbc) {
444 rc = __glut_glXGetFBConfigAttribSGIX(__glutDisplay, fbc,
445 GLX_FBCONFIG_ID_SGIX, &fbconfigID);
446 if ((rc == 0) && (fbconfigID != None)) {
447 rc = __glut_glXGetFBConfigAttribSGIX(__glutDisplay, fbc,
448 GLX_DRAWABLE_TYPE_SGIX, &drawType);
449 if ((rc == 0) && (drawType & GLX_WINDOW_BIT_SGIX)) {
450 rc = __glut_glXGetFBConfigAttribSGIX(__glutDisplay, fbc,
451 GLX_RENDER_TYPE_SGIX, &renderType);
452 if ((rc == 0) && (renderType & GLX_RGBA_BIT_SGIX)) {
453 mode->fbc = fbc;
454 mode->valid = 1; /* Assume the best until
455 proven otherwise. */
456
457 assert(glxcap[0] == GLX_RGBA);
458 mode->cap[0] = 1;
459
460 /* Start with "j = 1" to skip the GLX_RGBA attribute. */
461 for (j = 1; j < NUM_GLXCAPS; j++) {
462 rc = __glut_glXGetFBConfigAttribSGIX(__glutDisplay,
463 fbc, glxcap[j], &mode->cap[j]);
464 if (rc != 0) {
465 mode->valid = 0;
466 }
467 }
468
469 mode->cap[XVISUAL] = (int) vlist[i]->visualid;
470 mode->cap[XSTATICGRAY] = 0;
471 mode->cap[XGRAYSCALE] = 0;
472 mode->cap[XSTATICCOLOR] = 0;
473 mode->cap[XPSEUDOCOLOR] = 0;
474 mode->cap[XTRUECOLOR] = 0;
475 mode->cap[XDIRECTCOLOR] = 0;
476 #if defined(__cplusplus) || defined(c_plusplus)
477 switch (vlist[i]->c_class) {
478 #else
479 switch (vlist[i]->class) {
480 #endif
481 case StaticGray:
482 mode->cap[XSTATICGRAY] = 1;
483 break;
484 case GrayScale:
485 mode->cap[XGRAYSCALE] = 1;
486 break;
487 case StaticColor:
488 mode->cap[XSTATICCOLOR] = 1;
489 break;
490 case PseudoColor:
491 mode->cap[XPSEUDOCOLOR] = 1;
492 break;
493 case TrueColor:
494 mode->cap[XTRUECOLOR] = 1;
495 break;
496 case DirectColor:
497 mode->cap[XDIRECTCOLOR] = 1;
498 break;
499 }
500 #if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_rating)
501 if (visual_rating) {
502 int rating;
503
504 /* babcock@cs.montana.edu reported that DEC UNIX (OSF1) V4.0
505 564 for Alpha did not properly define GLX_VISUAL_CAVEAT_EXT
506 in <GL/glx.h> despite claiming to support
507 GLX_EXT_visual_rating. */
508 #ifndef GLX_VISUAL_CAVEAT_EXT
509 #define GLX_VISUAL_CAVEAT_EXT 0x20
510 #endif
511
512 rc = __glut_glXGetFBConfigAttribSGIX(__glutDisplay,
513 fbc, GLX_VISUAL_CAVEAT_EXT, &rating);
514 if (rc != 0) {
515 mode->cap[SLOW] = 0;
516 mode->cap[CONFORMANT] = 1;
517 } else {
518 switch (rating) {
519 case GLX_SLOW_VISUAL_EXT:
520 mode->cap[SLOW] = 1;
521 mode->cap[CONFORMANT] = 1;
522 break;
523
524 /* IRIX 5.3 for the R10K Indigo2 may have shipped without this
525 properly defined in /usr/include/GL/glxtokens.h */
526 #ifndef GLX_NON_CONFORMANT_VISUAL_EXT
527 #define GLX_NON_CONFORMANT_VISUAL_EXT 0x800D
528 #endif
529
530 case GLX_NON_CONFORMANT_VISUAL_EXT:
531 mode->cap[SLOW] = 0;
532 mode->cap[CONFORMANT] = 0;
533 break;
534 case GLX_NONE_EXT:
535 default: /* XXX Hopefully this is a good
536 default assumption. */
537 mode->cap[SLOW] = 0;
538 mode->cap[CONFORMANT] = 1;
539 break;
540 }
541 }
542 } else {
543 mode->cap[TRANSPARENT] = 0;
544 }
545 #else
546 mode->cap[SLOW] = 0;
547 mode->cap[CONFORMANT] = 1;
548 #endif
549 #if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_info)
550 if (visual_info) {
551 int transparent;
552
553 /* babcock@cs.montana.edu reported that DEC UNIX (OSF1) V4.0
554 564 for Alpha did not properly define
555 GLX_TRANSPARENT_TYPE_EXT in <GL/glx.h> despite claiming to
556 support GLX_EXT_visual_info. */
557 #ifndef GLX_TRANSPARENT_TYPE_EXT
558 #define GLX_TRANSPARENT_TYPE_EXT 0x23
559 #endif
560
561 rc = __glut_glXGetFBConfigAttribSGIX(__glutDisplay,
562 fbc, GLX_TRANSPARENT_TYPE_EXT, &transparent);
563 if (rc != 0) {
564 mode->cap[TRANSPARENT] = 0;
565 } else {
566 mode->cap[TRANSPARENT] = (transparent != GLX_NONE_EXT);
567 }
568 } else {
569 mode->cap[TRANSPARENT] = 0;
570 }
571 #else
572 mode->cap[TRANSPARENT] = 0;
573 #endif
574 #if defined(GLX_VERSION_1_1) && defined(GLX_SGIS_multisample)
575 if (multisample) {
576 rc = __glut_glXGetFBConfigAttribSGIX(__glutDisplay,
577 fbc, GLX_SAMPLES_SGIS, &mode->cap[SAMPLES]);
578 if (rc != 0) {
579 mode->cap[SAMPLES] = 0;
580 }
581 } else {
582 mode->cap[SAMPLES] = 0;
583 }
584 #else
585 mode->cap[SAMPLES] = 0;
586 #endif
587
588 } else {
589 /* Fbconfig is not RGBA; GLUT only uses RGBA
590 FBconfigs. */
591 /* XXX Code could be exteneded to handle color
592 index FBconfigs, but seems a color index
593 window-renderable FBconfig would also be
594 advertised as an X visual. */
595 mode->valid = 0;
596 }
597 } else {
598 /* Fbconfig does not support window rendering;
599 not a valid FBconfig for GLUT windows. */
600 mode->valid = 0;
601 }
602 } else {
603 /* FBconfig ID is None (zero); not a valid
604 FBconfig. */
605 mode->valid = 0;
606 }
607 } else {
608 /* FBconfig ID is None (zero); not a valid FBconfig. */
609 mode->valid = 0;
610 }
611 } else {
612 /* No SGIX_fbconfig GLX sever implementation support. */
613 mode->valid = 0;
614 }
615 #else
616 /* No SGIX_fbconfig GLX extension API support. */
617 mode->valid = 0;
618 #endif
619 }
620 }
621
622 free(vlist);
623 *nitems_return = n;
624 return fbmodes;
625 }
626
627 static XVisualInfo *
628 findMatch(FrameBufferMode * fbmodes, int nfbmodes,
629 Criterion * criteria, int ncriteria, void **fbc)
630 {
631 FrameBufferMode *found;
632 int *bestScore, *thisScore;
633 int i, j, numok, result = 0, worse, better;
634
635 found = NULL;
636 numok = 1; /* "num" capability is indexed from 1,
637 not 0. */
638
639 /* XXX alloca canidate. */
640 bestScore = (int *) malloc(ncriteria * sizeof(int));
641 if (!bestScore)
642 __glutFatalError("out of memory.");
643 for (j = 0; j < ncriteria; j++) {
644 /* Very negative number. */
645 bestScore[j] = -32768;
646 }
647
648 /* XXX alloca canidate. */
649 thisScore = (int *) malloc(ncriteria * sizeof(int));
650 if (!thisScore)
651 __glutFatalError("out of memory.");
652
653 for (i = 0; i < nfbmodes; i++) {
654 if (fbmodes[i].valid) {
655 #ifdef TEST
656 #if !defined(_WIN32)
657 if (verbose)
658 printf("Visual 0x%x\n", fbmodes[i].vi->visualid);
659 #endif
660 #endif
661
662 worse = 0;
663 better = 0;
664
665 for (j = 0; j < ncriteria; j++) {
666 int cap, cvalue, fbvalue;
667
668 cap = criteria[j].capability;
669 cvalue = criteria[j].value;
670 if (cap == NUM) {
671 fbvalue = numok;
672 } else {
673 fbvalue = fbmodes[i].cap[cap];
674 }
675 #ifdef TEST
676 if (verbose)
677 printf(" %s %s %d to %d\n",
678 capstr[cap], compstr[criteria[j].comparison], cvalue, fbvalue);
679 #endif
680 switch (criteria[j].comparison) {
681 case EQ:
682 result = cvalue == fbvalue;
683 thisScore[j] = 1;
684 break;
685 case NEQ:
686 result = cvalue != fbvalue;
687 thisScore[j] = 1;
688 break;
689 case LT:
690 result = fbvalue < cvalue;
691 thisScore[j] = fbvalue - cvalue;
692 break;
693 case GT:
694 result = fbvalue > cvalue;
695 thisScore[j] = fbvalue - cvalue;
696 break;
697 case LTE:
698 result = fbvalue <= cvalue;
699 thisScore[j] = fbvalue - cvalue;
700 break;
701 case GTE:
702 result = (fbvalue >= cvalue);
703 thisScore[j] = fbvalue - cvalue;
704 break;
705 case MIN:
706 result = fbvalue >= cvalue;
707 thisScore[j] = cvalue - fbvalue;
708 break;
709 }
710
711 #ifdef TEST
712 if (verbose)
713 printf(" result=%d score=%d bestScore=%d\n", result, thisScore[j], bestScore[j]);
714 #endif
715
716 if (result) {
717 if (better || thisScore[j] > bestScore[j]) {
718 better = 1;
719 } else if (thisScore[j] == bestScore[j]) {
720 /* Keep looking. */
721 } else {
722 goto nextFBM;
723 }
724 } else {
725 if (cap == NUM) {
726 worse = 1;
727 } else {
728 goto nextFBM;
729 }
730 }
731
732 }
733
734 if (better && !worse) {
735 found = &fbmodes[i];
736 for (j = 0; j < ncriteria; j++) {
737 bestScore[j] = thisScore[j];
738 }
739 }
740 numok++;
741
742 nextFBM:;
743
744 }
745 }
746 free(bestScore);
747 free(thisScore);
748 if (found) {
749 #if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_fbconfig)
750 *fbc = found->fbc;
751 #endif
752 return found->vi;
753 } else {
754 return NULL;
755 }
756 }
757
758 static int
759 parseCriteria(char *word, Criterion * criterion, int *mask,
760 Bool * allowDoubleAsSingle)
761 {
762 char *cstr, *vstr, *response;
763 int comparator, value = 0;
764 int rgb, rgba, acc, acca, count, i;
765
766 cstr = strpbrk(word, "=><!~");
767 if (cstr) {
768 switch (cstr[0]) {
769 case '=':
770 comparator = EQ;
771 vstr = &cstr[1];
772 break;
773 case '~':
774 comparator = MIN;
775 vstr = &cstr[1];
776 break;
777 case '>':
778 if (cstr[1] == '=') {
779 comparator = GTE;
780 vstr = &cstr[2];
781 } else {
782 comparator = GT;
783 vstr = &cstr[1];
784 }
785 break;
786 case '<':
787 if (cstr[1] == '=') {
788 comparator = LTE;
789 vstr = &cstr[2];
790 } else {
791 comparator = LT;
792 vstr = &cstr[1];
793 }
794 break;
795 case '!':
796 if (cstr[1] == '=') {
797 comparator = NEQ;
798 vstr = &cstr[2];
799 } else {
800 return -1;
801 }
802 break;
803 default:
804 return -1;
805 }
806 value = (int) strtol(vstr, &response, 0);
807 if (response == vstr) {
808 /* Not a valid number. */
809 return -1;
810 }
811 *cstr = '\0';
812 } else {
813 comparator = NONE;
814 }
815 switch (word[0]) {
816 case 'a':
817 if (!strcmp(word, "alpha")) {
818 criterion[0].capability = ALPHA_SIZE;
819 if (comparator == NONE) {
820 criterion[0].comparison = GTE;
821 criterion[0].value = 1;
822 } else {
823 criterion[0].comparison = comparator;
824 criterion[0].value = value;
825 }
826 *mask |= (1 << RGBA);
827 *mask |= (1 << ALPHA_SIZE);
828 *mask |= (1 << RGBA_MODE);
829 return 1;
830 }
831 acca = !strcmp(word, "acca");
832 acc = !strcmp(word, "acc");
833 if (acc || acca) {
834 criterion[0].capability = ACCUM_RED_SIZE;
835 criterion[1].capability = ACCUM_GREEN_SIZE;
836 criterion[2].capability = ACCUM_BLUE_SIZE;
837 criterion[3].capability = ACCUM_ALPHA_SIZE;
838 if (acca) {
839 count = 4;
840 } else {
841 count = 3;
842 criterion[3].comparison = MIN;
843 criterion[3].value = 0;
844 }
845 if (comparator == NONE) {
846 comparator = GTE;
847 value = 8;
848 }
849 for (i = 0; i < count; i++) {
850 criterion[i].comparison = comparator;
851 criterion[i].value = value;
852 }
853 *mask |= (1 << ACCUM_RED_SIZE);
854 return 4;
855 }
856 if (!strcmp(word, "auxbufs")) {
857 criterion[0].capability = AUX_BUFFERS;
858 if (comparator == NONE) {
859 criterion[0].comparison = MIN;
860 criterion[0].value = 1;
861 } else {
862 criterion[0].comparison = comparator;
863 criterion[0].value = value;
864 }
865 *mask |= (1 << AUX_BUFFERS);
866 return 1;
867 }
868 return -1;
869 case 'b':
870 if (!strcmp(word, "blue")) {
871 criterion[0].capability = BLUE_SIZE;
872 if (comparator == NONE) {
873 criterion[0].comparison = GTE;
874 criterion[0].value = 1;
875 } else {
876 criterion[0].comparison = comparator;
877 criterion[0].value = value;
878 }
879 *mask |= (1 << RGBA);
880 *mask |= (1 << RGBA_MODE);
881 return 1;
882 }
883 if (!strcmp(word, "buffer")) {
884 criterion[0].capability = BUFFER_SIZE;
885 if (comparator == NONE) {
886 criterion[0].comparison = GTE;
887 criterion[0].value = 1;
888 } else {
889 criterion[0].comparison = comparator;
890 criterion[0].value = value;
891 }
892 return 1;
893 }
894 return -1;
895 case 'c':
896 if (!strcmp(word, "conformant")) {
897 criterion[0].capability = CONFORMANT;
898 if (comparator == NONE) {
899 criterion[0].comparison = EQ;
900 criterion[0].value = 1;
901 } else {
902 criterion[0].comparison = comparator;
903 criterion[0].value = value;
904 }
905 *mask |= (1 << CONFORMANT);
906 return 1;
907 }
908 return -1;
909 case 'd':
910 if (!strcmp(word, "depth")) {
911 criterion[0].capability = DEPTH_SIZE;
912 if (comparator == NONE) {
913 criterion[0].comparison = GTE;
914 criterion[0].value = 12;
915 } else {
916 criterion[0].comparison = comparator;
917 criterion[0].value = value;
918 }
919 *mask |= (1 << DEPTH_SIZE);
920 return 1;
921 }
922 if (!strcmp(word, "double")) {
923 criterion[0].capability = DOUBLEBUFFER;
924 if (comparator == NONE) {
925 criterion[0].comparison = EQ;
926 criterion[0].value = 1;
927 } else {
928 criterion[0].comparison = comparator;
929 criterion[0].value = value;
930 }
931 *mask |= (1 << DOUBLEBUFFER);
932 return 1;
933 }
934 return -1;
935 case 'g':
936 if (!strcmp(word, "green")) {
937 criterion[0].capability = GREEN_SIZE;
938 if (comparator == NONE) {
939 criterion[0].comparison = GTE;
940 criterion[0].value = 1;
941 } else {
942 criterion[0].comparison = comparator;
943 criterion[0].value = value;
944 }
945 *mask |= (1 << RGBA);
946 *mask |= (1 << RGBA_MODE);
947 return 1;
948 }
949 return -1;
950 case 'i':
951 if (!strcmp(word, "index")) {
952 criterion[0].capability = RGBA;
953 criterion[0].comparison = EQ;
954 criterion[0].value = 0;
955 *mask |= (1 << RGBA);
956 *mask |= (1 << CI_MODE);
957 criterion[1].capability = BUFFER_SIZE;
958 if (comparator == NONE) {
959 criterion[1].comparison = GTE;
960 criterion[1].value = 1;
961 } else {
962 criterion[1].comparison = comparator;
963 criterion[1].value = value;
964 }
965 return 2;
966 }
967 return -1;
968 case 'l':
969 if (!strcmp(word, "luminance")) {
970 criterion[0].capability = RGBA;
971 criterion[0].comparison = EQ;
972 criterion[0].value = 1;
973
974 criterion[1].capability = RED_SIZE;
975 if (comparator == NONE) {
976 criterion[1].comparison = GTE;
977 criterion[1].value = 1;
978 } else {
979 criterion[1].comparison = comparator;
980 criterion[1].value = value;
981 }
982
983 criterion[2].capability = GREEN_SIZE;
984 criterion[2].comparison = EQ;
985 criterion[2].value = 0;
986
987 criterion[3].capability = BLUE_SIZE;
988 criterion[3].comparison = EQ;
989 criterion[3].value = 0;
990
991 *mask |= (1 << RGBA);
992 *mask |= (1 << RGBA_MODE);
993 *mask |= (1 << LUMINANCE_MODE);
994 return 4;
995 }
996 return -1;
997 case 'n':
998 if (!strcmp(word, "num")) {
999 criterion[0].capability = NUM;
1000 if (comparator == NONE) {
1001 return -1;
1002 } else {
1003 criterion[0].comparison = comparator;
1004 criterion[0].value = value;
1005 return 1;
1006 }
1007 }
1008 return -1;
1009 case 'r':
1010 if (!strcmp(word, "red")) {
1011 criterion[0].capability = RED_SIZE;
1012 if (comparator == NONE) {
1013 criterion[0].comparison = GTE;
1014 criterion[0].value = 1;
1015 } else {
1016 criterion[0].comparison = comparator;
1017 criterion[0].value = value;
1018 }
1019 *mask |= (1 << RGBA);
1020 *mask |= (1 << RGBA_MODE);
1021 return 1;
1022 }
1023 rgba = !strcmp(word, "rgba");
1024 rgb = !strcmp(word, "rgb");
1025 if (rgb || rgba) {
1026 criterion[0].capability = RGBA;
1027 criterion[0].comparison = EQ;
1028 criterion[0].value = 1;
1029
1030 criterion[1].capability = RED_SIZE;
1031 criterion[2].capability = GREEN_SIZE;
1032 criterion[3].capability = BLUE_SIZE;
1033 criterion[4].capability = ALPHA_SIZE;
1034 if (rgba) {
1035 count = 5;
1036 } else {
1037 count = 4;
1038 criterion[4].comparison = MIN;
1039 criterion[4].value = 0;
1040 }
1041 if (comparator == NONE) {
1042 comparator = GTE;
1043 value = 1;
1044 }
1045 for (i = 1; i < count; i++) {
1046 criterion[i].comparison = comparator;
1047 criterion[i].value = value;
1048 }
1049 *mask |= (1 << RGBA);
1050 *mask |= (1 << RGBA_MODE);
1051 return 5;
1052 }
1053 return -1;
1054 case 's':
1055 if (!strcmp(word, "stencil")) {
1056 criterion[0].capability = STENCIL_SIZE;
1057 if (comparator == NONE) {
1058 criterion[0].comparison = MIN;
1059 criterion[0].value = 1;
1060 } else {
1061 criterion[0].comparison = comparator;
1062 criterion[0].value = value;
1063 }
1064 *mask |= (1 << STENCIL_SIZE);
1065 return 1;
1066 }
1067 if (!strcmp(word, "single")) {
1068 criterion[0].capability = DOUBLEBUFFER;
1069 if (comparator == NONE) {
1070 criterion[0].comparison = EQ;
1071 criterion[0].value = 0;
1072 *allowDoubleAsSingle = True;
1073 *mask |= (1 << DOUBLEBUFFER);
1074 return 1;
1075 } else {
1076 return -1;
1077 }
1078 }
1079 if (!strcmp(word, "stereo")) {
1080 criterion[0].capability = STEREO;
1081 if (comparator == NONE) {
1082 criterion[0].comparison = EQ;
1083 criterion[0].value = 1;
1084 } else {
1085 criterion[0].comparison = comparator;
1086 criterion[0].value = value;
1087 }
1088 *mask |= (1 << STEREO);
1089 return 1;
1090 }
1091 if (!strcmp(word, "samples")) {
1092 criterion[0].capability = SAMPLES;
1093 if (comparator == NONE) {
1094 criterion[0].comparison = LTE;
1095 criterion[0].value = 4;
1096 } else {
1097 criterion[0].comparison = comparator;
1098 criterion[0].value = value;
1099 }
1100 *mask |= (1 << SAMPLES);
1101 return 1;
1102 }
1103 if (!strcmp(word, "slow")) {
1104 criterion[0].capability = SLOW;
1105 if (comparator == NONE) {
1106 /* Just "slow" means permit fast visuals, but accept
1107 slow ones in preference. Presumably the slow ones
1108 must be higher quality or something else desirable. */
1109 criterion[0].comparison = GTE;
1110 criterion[0].value = 0;
1111 } else {
1112 criterion[0].comparison = comparator;
1113 criterion[0].value = value;
1114 }
1115 *mask |= (1 << SLOW);
1116 return 1;
1117 }
1118 return -1;
1119 #if defined(_WIN32)
1120 case 'w':
1121 if (!strcmp(word, "win32pfd")) {
1122 criterion[0].capability = XVISUAL;
1123 if (comparator == NONE) {
1124 return -1;
1125 } else {
1126 criterion[0].comparison = comparator;
1127 criterion[0].value = value;
1128 return 1;
1129 }
1130 }
1131 return -1;
1132 #endif
1133 #if !defined(_WIN32)
1134 case 'x':
1135 if (!strcmp(word, "xvisual")) {
1136 if (comparator == NONE) {
1137 return -1;
1138 } else {
1139 criterion[0].capability = XVISUAL;
1140 criterion[0].comparison = comparator;
1141 criterion[0].value = value;
1142 /* Set everything in "mask" so that no default criteria
1143 get used. Assume the program really wants the
1144 xvisual specified. */
1145 *mask |= ~0;
1146 return 1;
1147 }
1148 }
1149 /* Be a little over-eager to fill in the comparison and
1150 value so we won't have to replicate the code after each
1151 string match. */
1152 if (comparator == NONE) {
1153 criterion[0].comparison = EQ;
1154 criterion[0].value = 1;
1155 } else {
1156 criterion[0].comparison = comparator;
1157 criterion[0].value = value;
1158 }
1159
1160 if (!strcmp(word, "xstaticgray")) {
1161 criterion[0].capability = XSTATICGRAY;
1162 *mask |= (1 << XSTATICGRAY); /* Indicates _any_ visual
1163 class selected. */
1164 return 1;
1165 }
1166 if (!strcmp(word, "xgrayscale")) {
1167 criterion[0].capability = XGRAYSCALE;
1168 *mask |= (1 << XSTATICGRAY); /* Indicates _any_ visual
1169 class selected. */
1170 return 1;
1171 }
1172 if (!strcmp(word, "xstaticcolor")) {
1173 criterion[0].capability = XSTATICCOLOR;
1174 *mask |= (1 << XSTATICGRAY); /* Indicates _any_ visual
1175 class selected. */
1176 return 1;
1177 }
1178 if (!strcmp(word, "xpseudocolor")) {
1179 criterion[0].capability = XPSEUDOCOLOR;
1180 *mask |= (1 << XSTATICGRAY); /* Indicates _any_ visual
1181 class selected. */
1182 return 1;
1183 }
1184 if (!strcmp(word, "xtruecolor")) {
1185 criterion[0].capability = XTRUECOLOR;
1186 *mask |= (1 << XSTATICGRAY); /* Indicates _any_ visual
1187 class selected. */
1188 return 1;
1189 }
1190 if (!strcmp(word, "xdirectcolor")) {
1191 criterion[0].capability = XDIRECTCOLOR;
1192 *mask |= (1 << XSTATICGRAY); /* Indicates _any_ visual
1193 class selected. */
1194 return 1;
1195 }
1196 return -1;
1197 #endif
1198 default:
1199 return -1;
1200 }
1201 }
1202
1203 static Criterion *
1204 parseModeString(char *mode, int *ncriteria, Bool * allowDoubleAsSingle,
1205 Criterion * requiredCriteria, int nRequired, int requiredMask)
1206 {
1207 Criterion *criteria = NULL;
1208 int n, mask, parsed, i;
1209 char *copy, *word;
1210
1211 *allowDoubleAsSingle = False;
1212 copy = __glutStrdup(mode);
1213 /* Attempt to estimate how many criteria entries should be
1214 needed. */
1215 n = 0;
1216 word = strtok(copy, " \t");
1217 while (word) {
1218 n++;
1219 word = strtok(NULL, " \t");
1220 }
1221 /* Overestimate by 4 times ("rgba" might add four criteria
1222 entries) plus add in possible defaults plus space for
1223 required criteria. */
1224 criteria = (Criterion *) malloc((4 * n + 30 + nRequired) * sizeof(Criterion));
1225 if (!criteria) {
1226 __glutFatalError("out of memory.");
1227 }
1228
1229 /* Re-copy the copy of the mode string. */
1230 strcpy(copy, mode);
1231
1232 /* First add the required criteria (these match at the
1233 highest priority). Typically these will be used to force a
1234 specific level (layer), transparency, and/or visual type. */
1235 mask = requiredMask;
1236 for (i = 0; i < nRequired; i++) {
1237 criteria[i] = requiredCriteria[i];
1238 }
1239 n = nRequired;
1240
1241 word = strtok(copy, " \t");
1242 while (word) {
1243 parsed = parseCriteria(word, &criteria[n], &mask, allowDoubleAsSingle);
1244 if (parsed >= 0) {
1245 n += parsed;
1246 } else {
1247 __glutWarning("Unrecognized display string word: %s (ignoring)\n", word);
1248 }
1249 word = strtok(NULL, " \t");
1250 }
1251
1252 #if defined(GLX_VERSION_1_1) && defined(GLX_SGIS_multisample)
1253 if (__glutIsSupportedByGLX("GLX_SGIS_multisample")) {
1254 if (!(mask & (1 << SAMPLES))) {
1255 criteria[n].capability = SAMPLES;
1256 criteria[n].comparison = EQ;
1257 criteria[n].value = 0;
1258 n++;
1259 } else {
1260 /* Multisample visuals are marked nonconformant. If
1261 multisampling was requeste and no conformant
1262 preference was set, assume that we will settle for a
1263 non-conformant visual to get multisampling. */
1264 if (!(mask & (1 << CONFORMANT))) {
1265 criteria[n].capability = CONFORMANT;
1266 criteria[n].comparison = MIN;
1267 criteria[n].value = 0;
1268 n++;
1269 mask |= (1 << CONFORMANT);
1270 }
1271 }
1272 }
1273 #endif
1274 #if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_info)
1275 if (__glutIsSupportedByGLX("GLX_EXT_visual_info")) {
1276 if (!(mask & (1 << TRANSPARENT))) {
1277 criteria[n].capability = TRANSPARENT;
1278 criteria[n].comparison = EQ;
1279 criteria[n].value = 0;
1280 n++;
1281 }
1282 }
1283 #endif
1284 #if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_rating)
1285 if (__glutIsSupportedByGLX("GLX_EXT_visual_rating")) {
1286 if (!(mask & (1 << SLOW))) {
1287 criteria[n].capability = SLOW;
1288 criteria[n].comparison = EQ;
1289 criteria[n].value = 0;
1290 n++;
1291 }
1292 if (!(mask & (1 << CONFORMANT))) {
1293 criteria[n].capability = CONFORMANT;
1294 criteria[n].comparison = EQ;
1295 criteria[n].value = 1;
1296 n++;
1297 }
1298 }
1299 #endif
1300 if (!(mask & (1 << ACCUM_RED_SIZE))) {
1301 criteria[n].capability = ACCUM_RED_SIZE;
1302 criteria[n].comparison = MIN;
1303 criteria[n].value = 0;
1304 criteria[n + 1].capability = ACCUM_GREEN_SIZE;
1305 criteria[n + 1].comparison = MIN;
1306 criteria[n + 1].value = 0;
1307 criteria[n + 2].capability = ACCUM_BLUE_SIZE;
1308 criteria[n + 2].comparison = MIN;
1309 criteria[n + 2].value = 0;
1310 criteria[n + 3].capability = ACCUM_ALPHA_SIZE;
1311 criteria[n + 3].comparison = MIN;
1312 criteria[n + 3].value = 0;
1313 n += 4;
1314 }
1315 if (!(mask & (1 << AUX_BUFFERS))) {
1316 criteria[n].capability = AUX_BUFFERS;
1317 criteria[n].comparison = MIN;
1318 criteria[n].value = 0;
1319 n++;
1320 }
1321 if (!(mask & (1 << RGBA))) {
1322 criteria[n].capability = RGBA;
1323 criteria[n].comparison = EQ;
1324 criteria[n].value = 1;
1325 criteria[n + 1].capability = RED_SIZE;
1326 criteria[n + 1].comparison = GTE;
1327 criteria[n + 1].value = 1;
1328 criteria[n + 2].capability = GREEN_SIZE;
1329 criteria[n + 2].comparison = GTE;
1330 criteria[n + 2].value = 1;
1331 criteria[n + 3].capability = BLUE_SIZE;
1332 criteria[n + 3].comparison = GTE;
1333 criteria[n + 3].value = 1;
1334 criteria[n + 4].capability = ALPHA_SIZE;
1335 criteria[n + 4].comparison = MIN;
1336 criteria[n + 4].value = 0;
1337 n += 5;
1338 mask |= (1 << RGBA_MODE);
1339 }
1340 #if !defined(_WIN32)
1341 if (!(mask & (1 << XSTATICGRAY))) {
1342 assert(isMesaGLX != -1);
1343 if ((mask & (1 << RGBA_MODE)) && !isMesaGLX) {
1344 /* Normally, request an RGBA mode visual be TrueColor,
1345 except in the case of Mesa where we trust Mesa (and
1346 other code in GLUT) to handle any type of RGBA visual
1347 reasonably. */
1348 if (mask & (1 << LUMINANCE_MODE)) {
1349 /* If RGBA luminance was requested, actually go for
1350 a StaticGray visual. */
1351 criteria[n].capability = XSTATICGRAY;
1352 } else {
1353 criteria[n].capability = XTRUECOLOR;
1354 }
1355 criteria[n].value = 1;
1356 criteria[n].comparison = EQ;
1357
1358 n++;
1359 }
1360 if (mask & (1 << CI_MODE)) {
1361 criteria[n].capability = XPSEUDOCOLOR;
1362 criteria[n].value = 1;
1363 criteria[n].comparison = EQ;
1364 n++;
1365 }
1366 }
1367 #endif
1368 if (!(mask & (1 << STEREO))) {
1369 criteria[n].capability = STEREO;
1370 criteria[n].comparison = EQ;
1371 criteria[n].value = 0;
1372 n++;
1373 }
1374 if (!(mask & (1 << DOUBLEBUFFER))) {
1375 criteria[n].capability = DOUBLEBUFFER;
1376 criteria[n].comparison = EQ;
1377 criteria[n].value = 0;
1378 *allowDoubleAsSingle = True;
1379 n++;
1380 }
1381 if (!(mask & (1 << DEPTH_SIZE))) {
1382 criteria[n].capability = DEPTH_SIZE;
1383 criteria[n].comparison = MIN;
1384 criteria[n].value = 0;
1385 n++;
1386 }
1387 if (!(mask & (1 << STENCIL_SIZE))) {
1388 criteria[n].capability = STENCIL_SIZE;
1389 criteria[n].comparison = MIN;
1390 criteria[n].value = 0;
1391 n++;
1392 }
1393 if (!(mask & (1 << LEVEL))) {
1394 criteria[n].capability = LEVEL;
1395 criteria[n].comparison = EQ;
1396 criteria[n].value = 0;
1397 n++;
1398 }
1399 if (n) {
1400 /* Since over-estimated the size needed; squeeze it down to
1401 reality. */
1402 criteria = (Criterion *) realloc(criteria, n * sizeof(Criterion));
1403 if (!criteria) {
1404 /* Should never happen since should be shrinking down! */
1405 __glutFatalError("out of memory.");
1406 }
1407 } else {
1408 /* For portability, avoid "realloc(ptr,0)" call. */
1409 free(criteria);
1410 criteria = NULL;
1411 }
1412
1413 free(copy);
1414 *ncriteria = n;
1415 return criteria;
1416 }
1417
1418 static FrameBufferMode *fbmodes = NULL;
1419 static int nfbmodes = 0;
1420
1421 static XVisualInfo *
1422 getVisualInfoFromString(char *string, Bool * treatAsSingle,
1423 Criterion * requiredCriteria, int nRequired, int requiredMask, void **fbc)
1424 {
1425 Criterion *criteria;
1426 XVisualInfo *visinfo;
1427 Bool allowDoubleAsSingle;
1428 int ncriteria, i;
1429
1430 if (!fbmodes) {
1431 fbmodes = loadVisuals(&nfbmodes);
1432 }
1433 criteria = parseModeString(string, &ncriteria,
1434 &allowDoubleAsSingle, requiredCriteria, nRequired, requiredMask);
1435 if (criteria == NULL) {
1436 __glutWarning("failed to parse mode string");
1437 return NULL;
1438 }
1439 #ifdef TEST
1440 printCriteria(criteria, ncriteria);
1441 #endif
1442 visinfo = findMatch(fbmodes, nfbmodes, criteria, ncriteria, fbc);
1443 if (visinfo) {
1444 *treatAsSingle = 0;
1445 } else {
1446 if (allowDoubleAsSingle) {
1447 /* Rewrite criteria so that we now look for a double
1448 buffered visual which will then get treated as a
1449 single buffered visual. */
1450 for (i = 0; i < ncriteria; i++) {
1451 if (criteria[i].capability == DOUBLEBUFFER
1452 && criteria[i].comparison == EQ
1453 && criteria[i].value == 0) {
1454 criteria[i].value = 1;
1455 }
1456 }
1457 visinfo = findMatch(fbmodes, nfbmodes, criteria, ncriteria, fbc);
1458 if (visinfo) {
1459 *treatAsSingle = 1;
1460 }
1461 }
1462 }
1463 free(criteria);
1464
1465 if (visinfo) {
1466 #if defined(_WIN32)
1467 /* We could have a valid pixel format for drawing to a
1468 bitmap. However, we don't want to draw into a bitmap, we
1469 need one that can be used with a window, so make sure
1470 that this is true. */
1471 if (!(visinfo->dwFlags & PFD_DRAW_TO_WINDOW))
1472 return NULL;
1473 #endif
1474 return visinfo;
1475 } else {
1476 return NULL;
1477 }
1478 }
1479
1480 /* CENTRY */
1481 void GLUTAPIENTRY
1482 glutInitDisplayString(const char *string)
1483 {
1484 #ifdef _WIN32
1485 XHDC = GetDC(GetDesktopWindow());
1486 #endif
1487
1488 __glutDetermineVisualFromString = getVisualInfoFromString;
1489 if (__glutDisplayString) {
1490 free(__glutDisplayString);
1491 }
1492 if (string) {
1493 __glutDisplayString = __glutStrdup(string);
1494 if (!__glutDisplayString)
1495 __glutFatalError("out of memory.");
1496 } else {
1497 __glutDisplayString = NULL;
1498 }
1499 }
1500 /* ENDCENTRY */
1501
1502 #ifdef TEST
1503
1504 Criterion requiredWindowCriteria[] =
1505 {
1506 {LEVEL, EQ, 0},
1507 {TRANSPARENT, EQ, 0}
1508 };
1509 int numRequiredWindowCriteria = sizeof(requiredWindowCriteria) / sizeof(Criterion);
1510 int requiredWindowCriteriaMask = (1 << LEVEL) | (1 << TRANSPARENT);
1511
1512 Criterion requiredOverlayCriteria[] =
1513 {
1514 {LEVEL, EQ, 1},
1515 {TRANSPARENT, EQ, 1},
1516 {XPSEUDOCOLOR, EQ, 1},
1517 {RGBA, EQ, 0},
1518 {BUFFER_SIZE, GTE, 1}
1519 };
1520 int numRequiredOverlayCriteria = sizeof(requiredOverlayCriteria) / sizeof(Criterion);
1521 int requiredOverlayCriteriaMask =
1522 (1 << LEVEL) | (1 << TRANSPARENT) | (1 << XSTATICGRAY) | (1 << RGBA) | (1 << CI_MODE);
1523
1524 int
1525 main(int argc, char **argv)
1526 {
1527 Display *dpy;
1528 XVisualInfo *vinfo;
1529 Bool treatAsSingle;
1530 char *str, buffer[1024];
1531 int tty = isatty(fileno(stdin));
1532 int overlay = 0, showconfig = 0;
1533 #if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_fbconfig)
1534 GLXFBConfigSGIX fbc;
1535 #else
1536 void *fbc;
1537 #endif
1538
1539 #if !defined(_WIN32)
1540 dpy = XOpenDisplay(NULL);
1541 if (dpy == NULL) {
1542 printf("Could not connect to X server\n");
1543 exit(1);
1544 }
1545 __glutDisplay = dpy;
1546 __glutScreen = DefaultScreen(__glutDisplay);
1547 #endif
1548 while (!feof(stdin)) {
1549 if (tty)
1550 printf("dstr> ");
1551 str = fgets(buffer, 1023, stdin);
1552 if (str) {
1553 printf("\n");
1554 if (!strcmp("v", str)) {
1555 verbose = 1 - verbose;
1556 printf("verbose = %d\n\n", verbose);
1557 } else if (!strcmp("s", str)) {
1558 showconfig = 1 - showconfig;
1559 printf("showconfig = %d\n\n", showconfig);
1560 } else if (!strcmp("o", str)) {
1561 overlay = 1 - overlay;
1562 printf("overlay = %d\n\n", overlay);
1563 } else {
1564 if (overlay) {
1565 vinfo = getVisualInfoFromString(str, &treatAsSingle,
1566 requiredOverlayCriteria, numRequiredOverlayCriteria, requiredOverlayCriteriaMask, (void**) &fbc);
1567 } else {
1568 vinfo = getVisualInfoFromString(str, &treatAsSingle,
1569 requiredWindowCriteria, numRequiredWindowCriteria, requiredWindowCriteriaMask, (void**) &fbc);
1570 }
1571 if (vinfo) {
1572 printf("\n");
1573 if (!tty)
1574 printf("Display string: %s", str);
1575 #ifdef _WIN32
1576 printf("Visual = 0x%x\n", 0);
1577 #else
1578 printf("Visual = 0x%x%s\n", vinfo->visualid, fbc ? " (needs FBC)" : "");
1579 #endif
1580 if (treatAsSingle) {
1581 printf("Treat as SINGLE.\n");
1582 }
1583 if (showconfig) {
1584 int glxCapable, bufferSize, level, renderType, doubleBuffer,
1585 stereo, auxBuffers, redSize, greenSize, blueSize,
1586 alphaSize, depthSize, stencilSize, acRedSize, acGreenSize,
1587 acBlueSize, acAlphaSize;
1588
1589 glXGetConfig(dpy, vinfo, GLX_BUFFER_SIZE, &bufferSize);
1590 glXGetConfig(dpy, vinfo, GLX_LEVEL, &level);
1591 glXGetConfig(dpy, vinfo, GLX_RGBA, &renderType);
1592 glXGetConfig(dpy, vinfo, GLX_DOUBLEBUFFER, &doubleBuffer);
1593 glXGetConfig(dpy, vinfo, GLX_STEREO, &stereo);
1594 glXGetConfig(dpy, vinfo, GLX_AUX_BUFFERS, &auxBuffers);
1595 glXGetConfig(dpy, vinfo, GLX_RED_SIZE, &redSize);
1596 glXGetConfig(dpy, vinfo, GLX_GREEN_SIZE, &greenSize);
1597 glXGetConfig(dpy, vinfo, GLX_BLUE_SIZE, &blueSize);
1598 glXGetConfig(dpy, vinfo, GLX_ALPHA_SIZE, &alphaSize);
1599 glXGetConfig(dpy, vinfo, GLX_DEPTH_SIZE, &depthSize);
1600 glXGetConfig(dpy, vinfo, GLX_STENCIL_SIZE, &stencilSize);
1601 glXGetConfig(dpy, vinfo, GLX_ACCUM_RED_SIZE, &acRedSize);
1602 glXGetConfig(dpy, vinfo, GLX_ACCUM_GREEN_SIZE, &acGreenSize);
1603 glXGetConfig(dpy, vinfo, GLX_ACCUM_BLUE_SIZE, &acBlueSize);
1604 glXGetConfig(dpy, vinfo, GLX_ACCUM_ALPHA_SIZE, &acAlphaSize);
1605 printf("RGBA = (%d, %d, %d, %d)\n", redSize, greenSize, blueSize, alphaSize);
1606 printf("acc = (%d, %d, %d, %d)\n", acRedSize, acGreenSize, acBlueSize, acAlphaSize);
1607 printf("db = %d\n", doubleBuffer);
1608 printf("str = %d\n", stereo);
1609 printf("aux = %d\n", auxBuffers);
1610 printf("lvl = %d\n", level);
1611 printf("buf = %d\n", bufferSize);
1612 printf("rgba = %d\n", renderType);
1613 printf("z = %d\n", depthSize);
1614 printf("s = %d\n", stencilSize);
1615 }
1616 } else {
1617 printf("\n");
1618 printf("No match.\n");
1619 }
1620 printf("\n");
1621 }
1622 }
1623 }
1624 printf("\n");
1625 return 0;
1626 }
1627 #endif