applied David's patch for parsing display's server:screen string
[mesa.git] / progs / xdemos / glxinfo.c
1 /* $Id: glxinfo.c,v 1.13 2001/04/02 22:45:07 brianp Exp $ */
2
3 /*
4 * Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
20 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24
25 /*
26 * This program is a work-alike of the IRIX glxinfo program.
27 * Command line options:
28 * -t print wide table
29 * -v print verbose information
30 * -display DisplayName specify the X display to interogate
31 * -b only print ID of "best" visual on screen 0
32 *
33 * Brian Paul 26 January 2000
34 */
35
36 #define DO_GLU /* may want to remove this for easier XFree86 building? */
37
38 #include <X11/Xlib.h>
39 #include <X11/Xutil.h>
40 #include <GL/gl.h>
41 #ifdef DO_GLU
42 #include <GL/glu.h>
43 #endif
44 #include <GL/glx.h>
45 #include <stdio.h>
46 #include <string.h>
47 #include <stdlib.h>
48
49
50 #ifndef GLX_NONE_EXT
51 #define GLX_NONE_EXT 0x8000
52 #endif
53
54
55 typedef enum
56 {
57 Normal,
58 Wide,
59 Verbose
60 } InfoMode;
61
62
63 struct visual_attribs
64 {
65 /* X visual attribs */
66 int id;
67 int klass;
68 int depth;
69 int redMask, greenMask, blueMask;
70 int colormapSize;
71 int bitsPerRGB;
72
73 /* GL visual attribs */
74 int supportsGL;
75 int transparent;
76 int bufferSize;
77 int level;
78 int rgba;
79 int doubleBuffer;
80 int stereo;
81 int auxBuffers;
82 int redSize, greenSize, blueSize, alphaSize;
83 int depthSize;
84 int stencilSize;
85 int accumRedSize, accumGreenSize, accumBlueSize, accumAlphaSize;
86 int numSamples, numMultisample;
87 int visualCaveat;
88 };
89
90
91 /*
92 * Print a list of extensions, with word-wrapping.
93 */
94 static void
95 print_extension_list(const char *ext)
96 {
97 const char *indentString = " ";
98 const int indent = 4;
99 const int max = 79;
100 int width, i, j;
101
102 if (!ext || !ext[0])
103 return;
104
105 width = indent;
106 printf(indentString);
107 i = j = 0;
108 while (1) {
109 if (ext[j] == ' ' || ext[j] == 0) {
110 /* found end of an extension name */
111 const int len = j - i;
112 if (width + len > max) {
113 /* start a new line */
114 printf("\n");
115 width = indent;
116 printf(indentString);
117 }
118 /* print the extension name between ext[i] and ext[j] */
119 while (i < j) {
120 printf("%c", ext[i]);
121 i++;
122 }
123 /* either we're all done, or we'll continue with next extension */
124 width += len + 1;
125 if (ext[j] == 0) {
126 break;
127 }
128 else {
129 i++;
130 j++;
131 if (ext[j] == 0)
132 break;
133 printf(", ");
134 width += 2;
135 }
136 }
137 j++;
138 }
139 printf("\n");
140 }
141
142
143 static void
144 print_display_info(Display *dpy)
145 {
146 printf("name of display: %s\n", DisplayString(dpy));
147 }
148
149
150 static void
151 print_screen_info(Display *dpy, int scrnum)
152 {
153 Window win;
154 int attribSingle[] = {
155 GLX_RGBA,
156 GLX_RED_SIZE, 1,
157 GLX_GREEN_SIZE, 1,
158 GLX_BLUE_SIZE, 1,
159 None };
160 int attribDouble[] = {
161 GLX_RGBA,
162 GLX_RED_SIZE, 1,
163 GLX_GREEN_SIZE, 1,
164 GLX_BLUE_SIZE, 1,
165 GLX_DOUBLEBUFFER,
166 None };
167
168 XSetWindowAttributes attr;
169 unsigned long mask;
170 Window root;
171 GLXContext ctx;
172 XVisualInfo *visinfo;
173 int width = 100, height = 100;
174
175 root = RootWindow(dpy, scrnum);
176
177 visinfo = glXChooseVisual(dpy, scrnum, attribSingle);
178 if (!visinfo) {
179 visinfo = glXChooseVisual(dpy, scrnum, attribDouble);
180 if (!visinfo) {
181 fprintf(stderr, "Error: couldn't find RGB GLX visual\n");
182 return;
183 }
184 }
185
186 attr.background_pixel = 0;
187 attr.border_pixel = 0;
188 attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone);
189 attr.event_mask = StructureNotifyMask | ExposureMask;
190 mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
191 win = XCreateWindow(dpy, root, 0, 0, width, height,
192 0, visinfo->depth, InputOutput,
193 visinfo->visual, mask, &attr);
194
195 ctx = glXCreateContext( dpy, visinfo, NULL, True );
196 if (!ctx) {
197 fprintf(stderr, "Error: glXCreateContext failed\n");
198 XDestroyWindow(dpy, win);
199 return;
200 }
201
202 if (glXMakeCurrent(dpy, win, ctx)) {
203 const char *serverVendor = glXQueryServerString(dpy, scrnum, GLX_VENDOR);
204 const char *serverVersion = glXQueryServerString(dpy, scrnum, GLX_VERSION);
205 const char *serverExtensions = glXQueryServerString(dpy, scrnum, GLX_EXTENSIONS);
206 const char *clientVendor = glXGetClientString(dpy, GLX_VENDOR);
207 const char *clientVersion = glXGetClientString(dpy, GLX_VERSION);
208 const char *clientExtensions = glXGetClientString(dpy, GLX_EXTENSIONS);
209 const char *glxExtensions = glXQueryExtensionsString(dpy, scrnum);
210 const char *glVendor = (const char *) glGetString(GL_VENDOR);
211 const char *glRenderer = (const char *) glGetString(GL_RENDERER);
212 const char *glVersion = (const char *) glGetString(GL_VERSION);
213 const char *glExtensions = (const char *) glGetString(GL_EXTENSIONS);
214 char *displayName = NULL;
215 char *colon = NULL, *period = NULL;
216 #ifdef DO_GLU
217 const char *gluVersion = (const char *) gluGetString(GLU_VERSION);
218 const char *gluExtensions = (const char *) gluGetString(GLU_EXTENSIONS);
219 #endif
220 /* Strip the screen number from the display name, if present. */
221 if (!(displayName = malloc(strlen(DisplayString(dpy)) + 1))) {
222 fprintf(stderr, "Error: malloc() failed\n");
223 exit(1);
224 }
225 strcpy(displayName, DisplayString(dpy));
226 colon = strrchr(displayName, ':');
227 if (colon) {
228 period = strchr(colon, '.');
229 if (period)
230 *period = '\0';
231 }
232 printf("display: %s screen: %d\n", displayName, scrnum);
233 free(displayName);
234 printf("direct rendering: %s\n", glXIsDirect(dpy, ctx) ? "Yes" : "No");
235 printf("server glx vendor string: %s\n", serverVendor);
236 printf("server glx version string: %s\n", serverVersion);
237 printf("server glx extensions:\n");
238 print_extension_list(serverExtensions);
239 printf("client glx vendor string: %s\n", clientVendor);
240 printf("client glx version string: %s\n", clientVersion);
241 printf("client glx extensions:\n");
242 print_extension_list(clientExtensions);
243 printf("GLX extensions:\n");
244 print_extension_list(glxExtensions);
245 printf("OpenGL vendor string: %s\n", glVendor);
246 printf("OpenGL renderer string: %s\n", glRenderer);
247 printf("OpenGL version string: %s\n", glVersion);
248 printf("OpenGL extensions:\n");
249 print_extension_list(glExtensions);
250 #ifdef DO_GLU
251 printf("glu version: %s\n", gluVersion);
252 printf("glu extensions:\n");
253 print_extension_list(gluExtensions);
254 #endif
255 }
256 else {
257 fprintf(stderr, "Error: glXMakeCurrent failed\n");
258 }
259
260 glXDestroyContext(dpy, ctx);
261 XDestroyWindow(dpy, win);
262 }
263
264
265 static const char *
266 visual_class_name(int cls)
267 {
268 switch (cls) {
269 case StaticColor:
270 return "StaticColor";
271 case PseudoColor:
272 return "PseudoColor";
273 case StaticGray:
274 return "StaticGray";
275 case GrayScale:
276 return "GrayScale";
277 case TrueColor:
278 return "TrueColor";
279 case DirectColor:
280 return "DirectColor";
281 default:
282 return "";
283 }
284 }
285
286
287 static const char *
288 visual_class_abbrev(int cls)
289 {
290 switch (cls) {
291 case StaticColor:
292 return "sc";
293 case PseudoColor:
294 return "pc";
295 case StaticGray:
296 return "sg";
297 case GrayScale:
298 return "gs";
299 case TrueColor:
300 return "tc";
301 case DirectColor:
302 return "dc";
303 default:
304 return "";
305 }
306 }
307
308
309 static void
310 get_visual_attribs(Display *dpy, XVisualInfo *vInfo,
311 struct visual_attribs *attribs)
312 {
313 const char *ext = glXQueryExtensionsString(dpy, vInfo->screen);
314
315 memset(attribs, 0, sizeof(struct visual_attribs));
316
317 attribs->id = vInfo->visualid;
318 #if defined(__cplusplus) || defined(c_plusplus)
319 attribs->klass = vInfo->c_class;
320 #else
321 attribs->klass = vInfo->class;
322 #endif
323 attribs->depth = vInfo->depth;
324 attribs->redMask = vInfo->red_mask;
325 attribs->greenMask = vInfo->green_mask;
326 attribs->blueMask = vInfo->blue_mask;
327 attribs->colormapSize = vInfo->colormap_size;
328 attribs->bitsPerRGB = vInfo->bits_per_rgb;
329
330 if (glXGetConfig(dpy, vInfo, GLX_USE_GL, &attribs->supportsGL) != 0)
331 return;
332 glXGetConfig(dpy, vInfo, GLX_BUFFER_SIZE, &attribs->bufferSize);
333 glXGetConfig(dpy, vInfo, GLX_LEVEL, &attribs->level);
334 glXGetConfig(dpy, vInfo, GLX_RGBA, &attribs->rgba);
335 glXGetConfig(dpy, vInfo, GLX_DOUBLEBUFFER, &attribs->doubleBuffer);
336 glXGetConfig(dpy, vInfo, GLX_STEREO, &attribs->stereo);
337 glXGetConfig(dpy, vInfo, GLX_AUX_BUFFERS, &attribs->auxBuffers);
338 glXGetConfig(dpy, vInfo, GLX_RED_SIZE, &attribs->redSize);
339 glXGetConfig(dpy, vInfo, GLX_GREEN_SIZE, &attribs->greenSize);
340 glXGetConfig(dpy, vInfo, GLX_BLUE_SIZE, &attribs->blueSize);
341 glXGetConfig(dpy, vInfo, GLX_ALPHA_SIZE, &attribs->alphaSize);
342 glXGetConfig(dpy, vInfo, GLX_DEPTH_SIZE, &attribs->depthSize);
343 glXGetConfig(dpy, vInfo, GLX_STENCIL_SIZE, &attribs->stencilSize);
344 glXGetConfig(dpy, vInfo, GLX_ACCUM_RED_SIZE, &attribs->accumRedSize);
345 glXGetConfig(dpy, vInfo, GLX_ACCUM_GREEN_SIZE, &attribs->accumGreenSize);
346 glXGetConfig(dpy, vInfo, GLX_ACCUM_BLUE_SIZE, &attribs->accumBlueSize);
347 glXGetConfig(dpy, vInfo, GLX_ACCUM_ALPHA_SIZE, &attribs->accumAlphaSize);
348
349 /* transparent pixel value not implemented yet */
350 attribs->transparent = 0;
351
352 /* multisample tests not implemented yet */
353 attribs->numSamples = 0;
354 attribs->numMultisample = 0;
355
356 #if defined(GLX_EXT_visual_rating)
357 if (ext && strstr(ext, "GLX_EXT_visual_rating")) {
358 glXGetConfig(dpy, vInfo, GLX_VISUAL_CAVEAT_EXT, &attribs->visualCaveat);
359 }
360 else {
361 attribs->visualCaveat = GLX_NONE_EXT;
362 }
363 #else
364 attribs->visualCaveat = 0;
365 #endif
366 }
367
368
369 static void
370 print_visual_attribs_verbose(const struct visual_attribs *attribs)
371 {
372 printf("Visual ID: %x depth=%d class=%s\n",
373 attribs->id, attribs->depth, visual_class_name(attribs->klass));
374 printf(" bufferSize=%d level=%d renderType=%s doubleBuffer=%d stereo=%d\n",
375 attribs->bufferSize, attribs->level, attribs->rgba ? "rgba" : "ci",
376 attribs->doubleBuffer, attribs->stereo);
377 printf(" rgba: redSize=%d greenSize=%d blueSize=%d alphaSize=%d\n",
378 attribs->redSize, attribs->greenSize,
379 attribs->blueSize, attribs->alphaSize);
380 printf(" auxBuffers=%d depthSize=%d stencilSize=%d\n",
381 attribs->auxBuffers, attribs->depthSize, attribs->stencilSize);
382 printf(" accum: redSize=%d greenSize=%d blueSize=%d alphaSize=%d\n",
383 attribs->accumRedSize, attribs->accumGreenSize,
384 attribs->accumBlueSize, attribs->accumAlphaSize);
385 printf(" multiSample=%d multiSampleBuffers=%d\n",
386 attribs->numSamples, attribs->numMultisample);
387 #ifdef GLX_EXT_visual_rating
388 if (attribs->visualCaveat == GLX_NONE_EXT || attribs->visualCaveat == 0)
389 printf(" visualCaveat=None\n");
390 else if (attribs->visualCaveat == GLX_SLOW_VISUAL_EXT)
391 printf(" visualCaveat=Slow\n");
392 else if (attribs->visualCaveat == GLX_NON_CONFORMANT_VISUAL_EXT)
393 printf(" visualCaveat=Nonconformant\n");
394 #endif
395 printf(" %s\n", attribs->transparent ? "Transparent." : "Opaque.");
396 }
397
398
399 static void
400 print_visual_attribs_short_header(void)
401 {
402 printf(" visual x bf lv rg d st colorbuffer ax dp st accumbuffer ms cav\n");
403 printf(" id dep cl sp sz l ci b ro r g b a bf th cl r g b a ns b eat\n");
404 printf("----------------------------------------------------------------------\n");
405 }
406
407
408 static void
409 print_visual_attribs_short(const struct visual_attribs *attribs)
410 {
411 char *caveat;
412 #ifdef GLX_EXT_visual_rating
413 if (attribs->visualCaveat == GLX_NONE_EXT || attribs->visualCaveat == 0)
414 caveat = "None";
415 else if (attribs->visualCaveat == GLX_SLOW_VISUAL_EXT)
416 caveat = "Slow";
417 else if (attribs->visualCaveat == GLX_NON_CONFORMANT_VISUAL_EXT)
418 caveat = "Ncon";
419 #else
420 caveat = "None";
421 #endif
422
423 printf("0x%2x %2d %2s %2d %2d %2d %1s %2s %2s %2d %2d %2d %2d %2d %2d %2d",
424 attribs->id,
425 attribs->depth,
426 visual_class_abbrev(attribs->klass),
427 attribs->transparent,
428 attribs->bufferSize,
429 attribs->level,
430 attribs->rgba ? "r" : "c",
431 attribs->doubleBuffer ? "y" : ".",
432 attribs->stereo ? "y" : ".",
433 attribs->redSize, attribs->greenSize,
434 attribs->blueSize, attribs->alphaSize,
435 attribs->auxBuffers,
436 attribs->depthSize,
437 attribs->stencilSize
438 );
439
440 printf(" %2d %2d %2d %2d %2d %1d %s\n",
441 attribs->accumRedSize, attribs->accumGreenSize,
442 attribs->accumBlueSize, attribs->accumAlphaSize,
443 attribs->numSamples, attribs->numMultisample,
444 caveat
445 );
446 }
447
448
449 static void
450 print_visual_attribs_long_header(void)
451 {
452 printf("Vis Vis Visual Trans buff lev render DB ste r g b a aux dep ste accum buffers MS MS\n");
453 printf(" ID Depth Type parent size el type reo sz sz sz sz buf th ncl r g b a num bufs\n");
454 printf("----------------------------------------------------------------------------------------------------\n");
455 }
456
457
458 static void
459 print_visual_attribs_long(const struct visual_attribs *attribs)
460 {
461 printf("0x%2x %2d %-11s %2d %2d %2d %4s %3d %3d %3d %3d %3d %3d",
462 attribs->id,
463 attribs->depth,
464 visual_class_name(attribs->klass),
465 attribs->transparent,
466 attribs->bufferSize,
467 attribs->level,
468 attribs->rgba ? "rgba" : "ci ",
469 attribs->doubleBuffer,
470 attribs->stereo,
471 attribs->redSize, attribs->greenSize,
472 attribs->blueSize, attribs->alphaSize
473 );
474
475 printf(" %3d %4d %2d %3d %3d %3d %3d %2d %2d\n",
476 attribs->auxBuffers,
477 attribs->depthSize,
478 attribs->stencilSize,
479 attribs->accumRedSize, attribs->accumGreenSize,
480 attribs->accumBlueSize, attribs->accumAlphaSize,
481 attribs->numSamples, attribs->numMultisample
482 );
483 }
484
485
486 static void
487 print_visual_info(Display *dpy, int scrnum, InfoMode mode)
488 {
489 XVisualInfo template;
490 XVisualInfo *visuals;
491 int numVisuals;
492 long mask;
493 int i;
494
495 /* get list of all visuals on this screen */
496 template.screen = scrnum;
497 mask = VisualScreenMask;
498 visuals = XGetVisualInfo(dpy, mask, &template, &numVisuals);
499
500 if (mode == Verbose) {
501 for (i = 0; i < numVisuals; i++) {
502 struct visual_attribs attribs;
503 get_visual_attribs(dpy, &visuals[i], &attribs);
504 print_visual_attribs_verbose(&attribs);
505 }
506 }
507 else if (mode == Normal) {
508 print_visual_attribs_short_header();
509 for (i = 0; i < numVisuals; i++) {
510 struct visual_attribs attribs;
511 get_visual_attribs(dpy, &visuals[i], &attribs);
512 print_visual_attribs_short(&attribs);
513 }
514 }
515 else if (mode == Wide) {
516 print_visual_attribs_long_header();
517 for (i = 0; i < numVisuals; i++) {
518 struct visual_attribs attribs;
519 get_visual_attribs(dpy, &visuals[i], &attribs);
520 print_visual_attribs_long(&attribs);
521 }
522 }
523
524 XFree(visuals);
525 }
526
527
528 /*
529 * Stand-alone Mesa doesn't really implement the GLX protocol so it
530 * doesn't really know the GLX attributes associated with an X visual.
531 * The first time a visual is presented to Mesa's pseudo-GLX it
532 * attaches ancilliary buffers to it (like depth and stencil).
533 * But that usually only works if glXChooseVisual is used.
534 * This function calls glXChooseVisual() to sort of "prime the pump"
535 * for Mesa's GLX so that the visuals that get reported actually
536 * reflect what applications will see.
537 * This has no effect when using true GLX.
538 */
539 static void
540 mesa_hack(Display *dpy, int scrnum)
541 {
542 static int attribs[] = {
543 GLX_RGBA,
544 GLX_RED_SIZE, 1,
545 GLX_GREEN_SIZE, 1,
546 GLX_BLUE_SIZE, 1,
547 GLX_DEPTH_SIZE, 1,
548 GLX_STENCIL_SIZE, 1,
549 GLX_ACCUM_RED_SIZE, 1,
550 GLX_ACCUM_GREEN_SIZE, 1,
551 GLX_ACCUM_BLUE_SIZE, 1,
552 GLX_ACCUM_ALPHA_SIZE, 1,
553 GLX_DOUBLEBUFFER,
554 None
555 };
556 XVisualInfo *visinfo;
557
558 visinfo = glXChooseVisual(dpy, scrnum, attribs);
559 if (visinfo)
560 XFree(visinfo);
561 }
562
563
564 /*
565 * Examine all visuals to find the so-called best one.
566 * We prefer deepest RGBA buffer with depth, stencil and accum
567 * that has no caveats.
568 */
569 static int
570 find_best_visual(Display *dpy, int scrnum)
571 {
572 XVisualInfo template;
573 XVisualInfo *visuals;
574 int numVisuals;
575 long mask;
576 int i;
577 struct visual_attribs bestVis;
578
579 /* get list of all visuals on this screen */
580 template.screen = scrnum;
581 mask = VisualScreenMask;
582 visuals = XGetVisualInfo(dpy, mask, &template, &numVisuals);
583
584 /* init bestVis with first visual info */
585 get_visual_attribs(dpy, &visuals[0], &bestVis);
586
587 /* try to find a "better" visual */
588 for (i = 1; i < numVisuals; i++) {
589 struct visual_attribs vis;
590
591 get_visual_attribs(dpy, &visuals[i], &vis);
592
593 /* always skip visuals with caveats */
594 if (vis.visualCaveat != GLX_NONE_EXT)
595 continue;
596
597 /* see if this vis is better than bestVis */
598 if ((!bestVis.supportsGL && vis.supportsGL) ||
599 (bestVis.visualCaveat != GLX_NONE_EXT) ||
600 (!bestVis.rgba && vis.rgba) ||
601 (!bestVis.doubleBuffer && vis.doubleBuffer) ||
602 (bestVis.redSize < vis.redSize) ||
603 (bestVis.greenSize < vis.greenSize) ||
604 (bestVis.blueSize < vis.blueSize) ||
605 (bestVis.alphaSize < vis.alphaSize) ||
606 (bestVis.depthSize < vis.depthSize) ||
607 (bestVis.stencilSize < vis.stencilSize) ||
608 (bestVis.accumRedSize < vis.accumRedSize)) {
609 /* found a better visual */
610 bestVis = vis;
611 }
612 }
613
614 XFree(visuals);
615
616 return bestVis.id;
617 }
618
619
620 int
621 main(int argc, char *argv[])
622 {
623 char *displayName = NULL;
624 Display *dpy;
625 int numScreens, scrnum;
626 InfoMode mode = Normal;
627 GLboolean findBest = GL_FALSE;
628 int i;
629
630 for (i = 1; i < argc; i++) {
631 if (strcmp(argv[i], "-display") == 0 && i + 1 < argc) {
632 displayName = argv[i + 1];
633 i++;
634 }
635 else if (strcmp(argv[i], "-t") == 0) {
636 mode = Wide;
637 }
638 else if (strcmp(argv[i], "-v") == 0) {
639 mode = Verbose;
640 }
641 else if (strcmp(argv[i], "-b") == 0) {
642 findBest = GL_TRUE;
643 }
644 }
645
646 dpy = XOpenDisplay(displayName);
647 if (!dpy) {
648 fprintf(stderr, "Error: unable to open display %s\n", displayName);
649 return -1;
650 }
651
652 if (findBest) {
653 int b;
654 mesa_hack(dpy, 0);
655 b = find_best_visual(dpy, 0);
656 printf("%d\n", b);
657 }
658 else {
659 numScreens = ScreenCount(dpy);
660 print_display_info(dpy);
661 for (scrnum = 0; scrnum < numScreens; scrnum++) {
662 mesa_hack(dpy, scrnum);
663 print_screen_info(dpy, scrnum);
664 printf("\n");
665 print_visual_info(dpy, scrnum, mode);
666 if (scrnum + 1 < numScreens)
667 printf("\n\n");
668 }
669 }
670
671 XCloseDisplay(dpy);
672
673 return 0;
674 }