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