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