7a0b07831c926c04d398f518aa0280a666c47e39
[xscreensaver] / driver / xdpyinfo.c
1 /*
2  * $ TOG: xdpyinfo.c /main/35 1998/02/09 13:57:05 kaleb $
3  * 
4  * xdpyinfo - print information about X display connecton
5  *
6  * 
7 Copyright 1988, 1998  The Open Group
8
9 All Rights Reserved.
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in this Software without prior written authorization from The Open Group.
24  *
25  * Author:  Jim Fulton, MIT X Consortium
26  *
27  * GLX and Overlay support added by Jamie Zawinski <jwz@jwz.org>, 11-Nov-99
28  *
29  *      To compile:
30  *         cc -DHAVE_GLX xdpyinfo.c -o xdpyinfo -lGL -lX11 -lXext [-lXtst] -lm
31  *
32  *      Other defines to consider:
33  *         -DMITSHM -DHAVE_XDBE -DHAVE_XIE -DHAVE_XTEST -DHAVE_SYNC
34  *         -DHAVE_XRECORD
35  */
36
37 #include <X11/Xlib.h>
38 #include <X11/Xutil.h>
39 #include <X11/Xproto.h> /* for CARD32 */
40 #include <X11/extensions/multibuf.h>
41 #ifdef HAVE_XIE
42 #include <X11/extensions/XIElib.h>
43 #endif /* HAVE_XIE */
44 #ifdef HAVE_XTEST
45 #include <X11/extensions/XTest.h>
46 #endif /* HAVE_XTEST */
47 #ifdef HAVE_XSYNC
48 #include <X11/extensions/sync.h>
49 #endif /* HAVE_XSYNC */
50 #ifdef HAVE_XDBE
51 #include <X11/extensions/Xdbe.h>
52 #endif /* HAVE_XDBE */
53 #ifdef HAVE_XRECORD
54 #include <X11/extensions/record.h>
55 #endif /* HAVE_XRECORD */
56 #ifdef MITSHM
57 #include <X11/extensions/XShm.h>
58 #endif
59 #include <X11/Xos.h>
60 #include <stdio.h>
61
62 #ifdef HAVE_GLX
63 # include <GL/gl.h>
64 # include <GL/glx.h>
65 #endif /* HAVE_GLX */
66
67 #define HAVE_OVERLAY /* jwz: no compile-time deps, so do this all the time */
68
69 char *ProgramName;
70 Bool queryExtensions = False;
71
72 static int StrCmp(a, b)
73     char **a, **b;
74 {
75     return strcmp(*a, *b);
76 }
77
78
79 #ifdef HAVE_GLX  /* Added by jwz, 11-Nov-99 */
80
81 static void
82 print_glx_versions (dpy)
83     Display *dpy;
84 {
85   /* Note: with Mesa 3.0, this lies: it prints the info from the
86      client's GL library, rather than the info from the GLX server.
87
88      Note also that we can't protect these calls by only doing
89      them when the GLX extension is present, because with Mesa,
90      the server doesn't have that extension (but the GL library
91      works anyway.)
92    */
93       int scr = DefaultScreen (dpy);
94       const char *vend, *vers;
95       vend = glXQueryServerString (dpy, scr, GLX_VENDOR);
96       if (!vend) return;
97       vers = glXQueryServerString (dpy, scr, GLX_VERSION);
98       printf ("GLX vendor:    %s (%s)\n",
99               vend, (vers ? vers : "unknown version"));
100 }
101
102 static void
103 print_glx_visual_info (dpy, vip)
104     Display *dpy;
105     XVisualInfo *vip;
106 {
107   int status, value = False;
108
109   status = glXGetConfig (dpy, vip, GLX_USE_GL, &value);
110   if (status == GLX_NO_EXTENSION)
111     /* dpy does not support the GLX extension. */
112     return;
113
114   if (status == GLX_BAD_VISUAL || value == False)
115     {
116       printf ("    GLX supported:     no\n");
117       return;
118     }
119   else
120     {
121       printf ("    GLX supported:     yes\n");
122     }
123     
124   if (!glXGetConfig (dpy, vip, GLX_LEVEL, &value) &&
125       value != 0)
126     printf ("    GLX level:         %d\n", value);
127
128   if (!glXGetConfig (dpy, vip, GLX_RGBA, &value) && value)
129     {
130       int r=0, g=0, b=0, a=0;
131       glXGetConfig (dpy, vip, GLX_RED_SIZE,   &r);
132       glXGetConfig (dpy, vip, GLX_GREEN_SIZE, &g);
133       glXGetConfig (dpy, vip, GLX_BLUE_SIZE,  &b);
134       glXGetConfig (dpy, vip, GLX_ALPHA_SIZE, &a);
135       printf ("    GLX type:          RGBA (%2d, %2d, %2d, %2d)\n",
136               r, g, b, a);
137
138       r=0, g=0, b=0, a=0;
139       glXGetConfig (dpy, vip, GLX_ACCUM_RED_SIZE,   &r);
140       glXGetConfig (dpy, vip, GLX_ACCUM_GREEN_SIZE, &g);
141       glXGetConfig (dpy, vip, GLX_ACCUM_BLUE_SIZE,  &b);
142       glXGetConfig (dpy, vip, GLX_ACCUM_ALPHA_SIZE, &a);
143       printf ("    GLX accum:         RGBA (%2d, %2d, %2d, %2d)\n",
144               r, g, b, a);
145     }
146   else
147     {
148       value = 0;
149       glXGetConfig (dpy, vip, GLX_BUFFER_SIZE, &value);
150       printf ("    GLX type:          indexed (%d)\n", value);
151     }
152
153 # if 0  /* redundant */
154   if (!glXGetConfig (dpy, vip, GLX_X_VISUAL_TYPE_EXT, &value))
155       printf ("    GLX class:         %s\n",
156               (value == GLX_TRUE_COLOR_EXT ? "TrueColor" :
157                value == GLX_DIRECT_COLOR_EXT ? "DirectColor" :
158                value == GLX_PSEUDO_COLOR_EXT ? "PseudoColor" :
159                value == GLX_STATIC_COLOR_EXT ? "StaticColor" :
160                value == GLX_GRAY_SCALE_EXT ? "Grayscale" :
161                value == GLX_STATIC_GRAY_EXT ? "StaticGray" : "???"));
162 # endif
163
164 # ifdef GLX_VISUAL_CAVEAT_EXT
165   if (!glXGetConfig (dpy, vip, GLX_VISUAL_CAVEAT_EXT, &value) &&
166       value != GLX_NONE_EXT)
167     printf ("    GLX rating:        %s\n",
168             (value == GLX_NONE_EXT ? "none" :
169              value == GLX_SLOW_VISUAL_EXT ? "slow" :
170 #   ifdef GLX_NON_CONFORMANT_EXT
171              value == GLX_NON_CONFORMANT_EXT ? "non-conformant" :
172 #   endif
173              "???"));
174 # endif
175
176   if (!glXGetConfig (dpy, vip, GLX_DOUBLEBUFFER, &value))
177     printf ("    GLX double-buffer: %s\n", (value ? "yes" : "no"));
178
179   if (!glXGetConfig (dpy, vip, GLX_STEREO, &value) &&
180       value)
181     printf ("    GLX stereo:        %s\n", (value ? "yes" : "no"));
182
183   if (!glXGetConfig (dpy, vip, GLX_AUX_BUFFERS, &value) &&
184       value != 0)
185     printf ("    GLX aux buffers:   %d\n", value);
186
187   if (!glXGetConfig (dpy, vip, GLX_DEPTH_SIZE, &value))
188     printf ("    GLX depth size:    %d\n", value);
189
190   if (!glXGetConfig (dpy, vip, GLX_STENCIL_SIZE, &value) &&
191       value != 0)
192     printf ("    GLX stencil size:  %d\n", value);
193
194 # ifdef GLX_SAMPLE_BUFFERS_SGIS
195   if (!glXGetConfig (dpy, vip, GLX_SAMPLE_BUFFERS_SGIS, &value) &&
196       value != 0)
197     {
198       int bufs = value;
199       if (!glXGetConfig (dpy, vip, GLX_SAMPLES_SGIS, &value))
200         printf ("    GLX multisamplers: %d (%d)\n", bufs, value);
201     }
202 # endif
203
204   if (!glXGetConfig (dpy, vip, GLX_TRANSPARENT_TYPE_EXT, &value) &&
205       value != GLX_NONE_EXT)
206     {
207       if (value == GLX_NONE_EXT)
208         printf ("    GLX transparency:  none\n");
209       else if (value == GLX_TRANSPARENT_INDEX_EXT)
210         {
211           if (!glXGetConfig (dpy, vip, GLX_TRANSPARENT_INDEX_VALUE_EXT,&value))
212             printf ("    GLX transparency:  indexed (%d)\n", value);
213         }
214       else if (value == GLX_TRANSPARENT_RGB_EXT)
215         {
216           int r=0, g=0, b=0, a=0;
217           glXGetConfig (dpy, vip, GLX_TRANSPARENT_RED_VALUE_EXT,   &r);
218           glXGetConfig (dpy, vip, GLX_TRANSPARENT_GREEN_VALUE_EXT, &g);
219           glXGetConfig (dpy, vip, GLX_TRANSPARENT_BLUE_VALUE_EXT,  &b);
220           glXGetConfig (dpy, vip, GLX_TRANSPARENT_ALPHA_VALUE_EXT, &a);
221           printf ("    GLX transparency:  RGBA (%2d, %2d, %2d, %2d)\n",
222                   r, g, b, a);
223         }
224     }
225 }
226 #endif /* HAVE_GLX */
227
228
229 #ifdef HAVE_OVERLAY  /* Added by jwz, 11-Nov-99 */
230
231  /* If the server's root window contains a SERVER_OVERLAY_VISUALS property,
232     then that identifies the visuals which correspond to the video hardware's
233     overlay planes.  Windows created in these kinds of visuals may have
234     transparent pixels that let other layers shine through.
235
236     This might not be an X Consortium standard, but it turns out that
237     SGI, HP, DEC, and IBM all use this same mechanism.  So that's close
238     enough for me.
239
240     Documentation on the SERVER_OVERLAY_VISUALS property can be found at:
241     http://www.hp.com/xwindow/sharedInfo/Whitepapers/Visuals/server_overlay_visuals.html
242   */
243
244 struct overlay
245 {
246   CARD32 visual_id;
247   CARD32 transparency;  /* 0: none; 1: pixel; 2: mask */
248   CARD32 value;         /* the transparent pixel */
249   CARD32 layer;         /* -1: underlay; 0: normal; 1: popup; 2: overlay */
250 };
251
252 struct overlay_list
253 {
254   int count;
255   struct overlay *list;
256 };
257
258 static struct overlay_list *overlays = 0;
259
260 static void
261 find_overlay_info (dpy)
262   Display *dpy;
263 {
264   int screen;
265   Atom OVERLAY = XInternAtom (dpy, "SERVER_OVERLAY_VISUALS", False);
266
267   overlays = (struct overlay_list *) calloc (sizeof (struct overlay_list),
268                                              ScreenCount (dpy));
269
270   for (screen = 0; screen < ScreenCount (dpy); screen++)
271     {
272       Window window = RootWindow (dpy, screen);
273       Atom actual_type;
274       int actual_format;
275       unsigned long nitems, bytes_after;
276       struct overlay *data = 0;
277       int result = XGetWindowProperty (dpy, window, OVERLAY,
278                                        0, (65536 / sizeof (long)), False, 
279                                        OVERLAY, &actual_type, &actual_format,
280                                        &nitems, &bytes_after,
281                                        (unsigned char **) &data);
282       if (result == Success &&
283           actual_type == OVERLAY &&
284           actual_format == 32 &&
285           nitems > 0)
286         {
287           overlays[screen].count = (nitems /
288                                     (sizeof(struct overlay) / sizeof(CARD32)));
289           overlays[screen].list = data;
290         }
291       else if (data)
292         XFree((char *) data);
293     }
294 }
295
296 static void
297 print_overlay_visual_info (vip)
298     XVisualInfo *vip;
299 {
300   int i;
301   int vis = vip->visualid;
302   int scr = vip->screen;
303   if (!overlays) return;
304   for (i = 0; i < overlays[scr].count; i++)
305     if (vis == overlays[scr].list[i].visual_id)
306       {
307         struct overlay *ov = &overlays[scr].list[i];
308         printf ("    Overlay info:      layer %ld (%s), ",
309                 (long) ov->layer,
310                 (ov->layer == -1 ? "underlay" :
311                  ov->layer ==  0 ? "normal" :
312                  ov->layer ==  1 ? "popup" :
313                  ov->layer ==  2 ? "overlay" : "???"));
314         if (ov->transparency == 1)
315           printf ("transparent pixel %lu\n", (unsigned long) ov->value);
316         else if (ov->transparency == 2)
317           printf ("transparent mask 0x%x\n", (unsigned long) ov->value);
318         else
319           printf ("opaque\n");
320       }
321 }
322 #endif /* HAVE_OVERLAY */
323
324
325 void
326 print_extension_info (dpy)
327     Display *dpy;
328 {
329     int n = 0;
330     char **extlist = XListExtensions (dpy, &n);
331
332     printf ("number of extensions:    %d\n", n);
333
334     if (extlist) {
335         register int i;
336         int opcode, event, error;
337
338         qsort(extlist, n, sizeof(char *), StrCmp);
339         for (i = 0; i < n; i++) {
340             if (!queryExtensions) {
341                 printf ("    %s\n", extlist[i]);
342                 continue;
343             }
344             XQueryExtension(dpy, extlist[i], &opcode, &event, &error);
345             printf ("    %s  (opcode: %d", extlist[i], opcode);
346             if (event)
347                 printf (", base event: %d", event);
348             if (error)
349                 printf (", base error: %d", error);
350             printf(")\n");
351         }
352         /* do not free, Xlib can depend on contents being unaltered */
353         /* XFreeExtensionList (extlist); */
354     }
355 }
356
357 void
358 print_display_info (dpy)
359     Display *dpy;
360 {
361     char dummybuf[40];
362     char *cp;
363     int minkeycode, maxkeycode;
364     int i, n;
365     long req_size;
366     XPixmapFormatValues *pmf;
367     Window focuswin;
368     int focusrevert;
369
370     printf ("name of display:    %s\n", DisplayString (dpy));
371     printf ("version number:    %d.%d\n",
372             ProtocolVersion (dpy), ProtocolRevision (dpy));
373     printf ("vendor string:    %s\n", ServerVendor (dpy));
374     printf ("vendor release number:    %d\n", VendorRelease (dpy));
375
376 #ifdef HAVE_GLX
377     print_glx_versions (dpy);
378 #endif /* HAVE_GLX */
379
380     req_size = XExtendedMaxRequestSize (dpy);
381     if (!req_size) req_size = XMaxRequestSize (dpy);
382     printf ("maximum request size:  %ld bytes\n", req_size * 4);
383     printf ("motion buffer size:  %d\n", XDisplayMotionBufferSize (dpy));
384
385     switch (BitmapBitOrder (dpy)) {
386       case LSBFirst:    cp = "LSBFirst"; break;
387       case MSBFirst:    cp = "MSBFirst"; break;
388       default:    
389         sprintf (dummybuf, "unknown order %d", BitmapBitOrder (dpy));
390         cp = dummybuf;
391         break;
392     }
393     printf ("bitmap unit, bit order, padding:    %d, %s, %d\n",
394             BitmapUnit (dpy), cp, BitmapPad (dpy));
395
396     switch (ImageByteOrder (dpy)) {
397       case LSBFirst:    cp = "LSBFirst"; break;
398       case MSBFirst:    cp = "MSBFirst"; break;
399       default:    
400         sprintf (dummybuf, "unknown order %d", ImageByteOrder (dpy));
401         cp = dummybuf;
402         break;
403     }
404     printf ("image byte order:    %s\n", cp);
405
406     pmf = XListPixmapFormats (dpy, &n);
407     printf ("number of supported pixmap formats:    %d\n", n);
408     if (pmf) {
409         printf ("supported pixmap formats:\n");
410         for (i = 0; i < n; i++) {
411             printf ("    depth %d, bits_per_pixel %d, scanline_pad %d\n",
412                     pmf[i].depth, pmf[i].bits_per_pixel, pmf[i].scanline_pad);
413         }
414         XFree ((char *) pmf);
415     }
416
417
418     /*
419      * when we get interfaces to the PixmapFormat stuff, insert code here
420      */
421
422     XDisplayKeycodes (dpy, &minkeycode, &maxkeycode);
423     printf ("keycode range:    minimum %d, maximum %d\n",
424             minkeycode, maxkeycode);
425
426     XGetInputFocus (dpy, &focuswin, &focusrevert);
427     printf ("focus:  ");
428     switch (focuswin) {
429       case PointerRoot:
430         printf ("PointerRoot\n");
431         break;
432       case None:
433         printf ("None\n");
434         break;
435       default:
436         printf("window 0x%lx, revert to ", focuswin);
437         switch (focusrevert) {
438           case RevertToParent:
439             printf ("Parent\n");
440             break;
441           case RevertToNone:
442             printf ("None\n");
443             break;
444           case RevertToPointerRoot:
445             printf ("PointerRoot\n");
446             break;
447           default:                      /* should not happen */
448             printf ("%d\n", focusrevert);
449             break;
450         }
451         break;
452     }
453
454     print_extension_info (dpy);
455
456     printf ("default screen number:    %d\n", DefaultScreen (dpy));
457     printf ("number of screens:    %d\n", ScreenCount (dpy));
458 }
459
460 void
461 print_visual_info (vip)
462     XVisualInfo *vip;
463 {
464     char errorbuf[40];                  /* for sprintfing into */
465     char *class = NULL;                 /* for printing */
466
467     switch (vip->class) {
468       case StaticGray:    class = "StaticGray"; break;
469       case GrayScale:    class = "GrayScale"; break;
470       case StaticColor:    class = "StaticColor"; break;
471       case PseudoColor:    class = "PseudoColor"; break;
472       case TrueColor:    class = "TrueColor"; break;
473       case DirectColor:    class = "DirectColor"; break;
474       default:    
475         sprintf (errorbuf, "unknown class %d", vip->class);
476         class = errorbuf;
477         break;
478     }
479
480     printf ("  visual:\n");
481     printf ("    visual id:    0x%lx\n", vip->visualid);
482     printf ("    class:    %s\n", class);
483     printf ("    depth:    %d plane%s\n", vip->depth, 
484             vip->depth == 1 ? "" : "s");
485     if (vip->class == TrueColor || vip->class == DirectColor)
486         printf ("    available colormap entries:    %d per subfield\n",
487                 vip->colormap_size);
488     else
489         printf ("    available colormap entries:    %d\n",
490                 vip->colormap_size);
491     printf ("    red, green, blue masks:    0x%lx, 0x%lx, 0x%lx\n",
492             vip->red_mask, vip->green_mask, vip->blue_mask);
493     printf ("    significant bits in color specification:    %d bits\n",
494             vip->bits_per_rgb);
495 }
496
497 void
498 print_screen_info (dpy, scr)
499     Display *dpy;
500     int scr;
501 {
502     Screen *s = ScreenOfDisplay (dpy, scr);  /* opaque structure */
503     XVisualInfo viproto;                /* fill in for getting info */
504     XVisualInfo *vip;                   /* retured info */
505     int nvi;                            /* number of elements returned */
506     int i;                              /* temp variable: iterator */
507     char eventbuf[80];                  /* want 79 chars per line + nul */
508     static char *yes = "YES", *no = "NO", *when = "WHEN MAPPED";
509     double xres, yres;
510     int ndepths = 0, *depths = NULL;
511     unsigned int width, height;
512
513
514     /*
515      * there are 2.54 centimeters to an inch; so there are 25.4 millimeters.
516      *
517      *     dpi = N pixels / (M millimeters / (25.4 millimeters / 1 inch))
518      *         = N pixels / (M inch / 25.4)
519      *         = N * 25.4 pixels / M inch
520      */
521
522     xres = ((((double) DisplayWidth(dpy,scr)) * 25.4) / 
523             ((double) DisplayWidthMM(dpy,scr)));
524     yres = ((((double) DisplayHeight(dpy,scr)) * 25.4) / 
525             ((double) DisplayHeightMM(dpy,scr)));
526
527     printf ("\n");
528     printf ("screen #%d:\n", scr);
529     printf ("  dimensions:    %dx%d pixels (%dx%d millimeters)\n",
530             DisplayWidth (dpy, scr), DisplayHeight (dpy, scr),
531             DisplayWidthMM(dpy, scr), DisplayHeightMM (dpy, scr));
532     printf ("  resolution:    %dx%d dots per inch\n", 
533             (int) (xres + 0.5), (int) (yres + 0.5));
534     depths = XListDepths (dpy, scr, &ndepths);
535     if (!depths) ndepths = 0;
536     printf ("  depths (%d):    ", ndepths);
537     for (i = 0; i < ndepths; i++) {
538         printf ("%d", depths[i]);
539         if (i < ndepths - 1) { 
540             putchar (',');
541             putchar (' ');
542         }
543     }
544     putchar ('\n');
545     if (depths) XFree ((char *) depths);
546     printf ("  root window id:    0x%lx\n", RootWindow (dpy, scr));
547     printf ("  depth of root window:    %d plane%s\n",
548             DisplayPlanes (dpy, scr),
549             DisplayPlanes (dpy, scr) == 1 ? "" : "s");
550     printf ("  number of colormaps:    minimum %d, maximum %d\n",
551             MinCmapsOfScreen(s), MaxCmapsOfScreen(s));
552     printf ("  default colormap:    0x%lx\n", DefaultColormap (dpy, scr));
553     printf ("  default number of colormap cells:    %d\n",
554             DisplayCells (dpy, scr));
555     printf ("  preallocated pixels:    black %d, white %d\n",
556             BlackPixel (dpy, scr), WhitePixel (dpy, scr));
557     printf ("  options:    backing-store %s, save-unders %s\n",
558             (DoesBackingStore (s) == NotUseful) ? no :
559             ((DoesBackingStore (s) == Always) ? yes : when),
560             DoesSaveUnders (s) ? yes : no);
561     XQueryBestSize (dpy, CursorShape, RootWindow (dpy, scr), 65535, 65535,
562                     &width, &height);
563     if (width == 65535 && height == 65535)
564         printf ("  largest cursor:    unlimited\n");
565     else
566         printf ("  largest cursor:    %dx%d\n", width, height);
567     printf ("  current input event mask:    0x%lx\n", EventMaskOfScreen (s));
568     (void) print_event_mask (eventbuf, 79, 4, EventMaskOfScreen (s));
569                       
570
571     nvi = 0;
572     viproto.screen = scr;
573     vip = XGetVisualInfo (dpy, VisualScreenMask, &viproto, &nvi);
574     printf ("  number of visuals:    %d\n", nvi);
575     printf ("  default visual id:  0x%lx\n", 
576             XVisualIDFromVisual (DefaultVisual (dpy, scr)));
577     for (i = 0; i < nvi; i++) {
578         print_visual_info (vip+i);
579 #ifdef HAVE_OVERLAY
580         print_overlay_visual_info (vip+i);
581 #endif /* HAVE_OVERLAY */
582 #ifdef HAVE_GLX
583         print_glx_visual_info (dpy, vip+i);
584 #endif /* HAVE_GLX */
585     }
586     if (vip) XFree ((char *) vip);
587 }
588
589 /*
590  * The following routine prints out an event mask, wrapping events at nice
591  * boundaries.
592  */
593
594 #define MASK_NAME_WIDTH 25
595
596 static struct _event_table {
597     char *name;
598     long value;
599 } event_table[] = {
600     { "KeyPressMask             ", KeyPressMask },
601     { "KeyReleaseMask           ", KeyReleaseMask },
602     { "ButtonPressMask          ", ButtonPressMask },
603     { "ButtonReleaseMask        ", ButtonReleaseMask },
604     { "EnterWindowMask          ", EnterWindowMask },
605     { "LeaveWindowMask          ", LeaveWindowMask },
606     { "PointerMotionMask        ", PointerMotionMask },
607     { "PointerMotionHintMask    ", PointerMotionHintMask },
608     { "Button1MotionMask        ", Button1MotionMask },
609     { "Button2MotionMask        ", Button2MotionMask },
610     { "Button3MotionMask        ", Button3MotionMask },
611     { "Button4MotionMask        ", Button4MotionMask },
612     { "Button5MotionMask        ", Button5MotionMask },
613     { "ButtonMotionMask         ", ButtonMotionMask },
614     { "KeymapStateMask          ", KeymapStateMask },
615     { "ExposureMask             ", ExposureMask },
616     { "VisibilityChangeMask     ", VisibilityChangeMask },
617     { "StructureNotifyMask      ", StructureNotifyMask },
618     { "ResizeRedirectMask       ", ResizeRedirectMask },
619     { "SubstructureNotifyMask   ", SubstructureNotifyMask },
620     { "SubstructureRedirectMask ", SubstructureRedirectMask },
621     { "FocusChangeMask          ", FocusChangeMask },
622     { "PropertyChangeMask       ", PropertyChangeMask },
623     { "ColormapChangeMask       ", ColormapChangeMask },
624     { "OwnerGrabButtonMask      ", OwnerGrabButtonMask },
625     { NULL, 0 }};
626
627 int print_event_mask (buf, lastcol, indent, mask)
628     char *buf;                          /* string to write into */
629     int lastcol;                        /* strlen(buf)+1 */
630     int indent;                         /* amount by which to indent */
631     long mask;                          /* event mask */
632 {
633     struct _event_table *etp;
634     int len;
635     int bitsfound = 0;
636
637     buf[0] = buf[lastcol] = '\0';       /* just in case */
638
639 #define INDENT() { register int i; len = indent; \
640                    for (i = 0; i < indent; i++) buf[i] = ' '; }
641
642     INDENT ();
643
644     for (etp = event_table; etp->name; etp++) {
645         if (mask & etp->value) {
646             if (len + MASK_NAME_WIDTH > lastcol) {
647                 puts (buf);
648                 INDENT ();
649             }
650             strcpy (buf+len, etp->name);
651             len += MASK_NAME_WIDTH;
652             bitsfound++;
653         }
654     }
655
656     if (bitsfound) puts (buf);
657
658 #undef INDENT
659
660     return (bitsfound);
661 }
662
663 void
664 print_standard_extension_info(dpy, extname, majorrev, minorrev)
665     Display *dpy;
666     char *extname;
667     int majorrev, minorrev;
668 {
669     int opcode, event, error;
670
671     printf("%s version %d.%d ", extname, majorrev, minorrev);
672
673     XQueryExtension(dpy, extname, &opcode, &event, &error);
674     printf ("opcode: %d", opcode);
675     if (event)
676         printf (", base event: %d", event);
677     if (error)
678         printf (", base error: %d", error);
679     printf("\n");
680 }
681
682 int
683 print_multibuf_info(dpy, extname)
684     Display *dpy;
685     char *extname;
686 {
687     int i, j;                   /* temp variable: iterator */
688     int nmono, nstereo;         /* count */
689     XmbufBufferInfo *mono_info = NULL, *stereo_info = NULL; /* arrays */
690     static char *fmt = 
691         "    visual id, max buffers, depth:    0x%lx, %d, %d\n";
692     int scr = 0;
693     int majorrev, minorrev;
694
695     if (!XmbufGetVersion(dpy, &majorrev, &minorrev))
696         return 0;
697
698     print_standard_extension_info(dpy, extname, majorrev, minorrev);
699
700     for (i = 0; i < ScreenCount (dpy); i++)
701     {
702         if (!XmbufGetScreenInfo (dpy, RootWindow(dpy, scr), &nmono, &mono_info,
703                                  &nstereo, &stereo_info)) {
704             fprintf (stderr,
705                      "%s:  unable to get multibuffer info for screen %d\n",
706                      ProgramName, scr);
707         } else {
708             printf ("  screen %d number of mono multibuffer types:    %d\n", i, nmono);
709             for (j = 0; j < nmono; j++) {
710                 printf (fmt, mono_info[j].visualid, mono_info[j].max_buffers,
711                         mono_info[j].depth);
712             }
713             printf ("  number of stereo multibuffer types:    %d\n", nstereo);
714             for (j = 0; j < nstereo; j++) {
715                 printf (fmt, stereo_info[j].visualid,
716                         stereo_info[j].max_buffers, stereo_info[j].depth);
717             }
718             if (mono_info) XFree ((char *) mono_info);
719             if (stereo_info) XFree ((char *) stereo_info);
720         }
721     }
722     return 1;
723 } /* end print_multibuf_info */
724
725
726 /* XIE stuff */
727
728 #ifdef HAVE_XIE
729
730 char *subset_names[] = { NULL, "FULL", "DIS" };
731 char *align_names[] = { NULL, "Alignable", "Arbitrary" };
732 char *group_names[] = { /* 0  */ "Default",
733                             /* 2  */ "ColorAlloc",
734                             /* 4  */ "Constrain",
735                             /* 6  */ "ConvertFromRGB",
736                             /* 8  */ "ConvertToRGB",
737                             /* 10 */ "Convolve",
738                             /* 12 */ "Decode",
739                             /* 14 */ "Dither",
740                             /* 16 */ "Encode",
741                             /* 18 */ "Gamut",
742                             /* 20 */ "Geometry",
743                             /* 22 */ "Histogram",
744                             /* 24 */ "WhiteAdjust"
745                             };
746
747 int
748 print_xie_info(dpy, extname)
749     Display *dpy;
750     char *extname;
751 {
752     XieExtensionInfo *xieInfo;
753     int i;
754     int ntechs;
755     XieTechnique *techs;
756     XieTechniqueGroup prevGroup;
757
758     if (!XieInitialize(dpy, &xieInfo ))
759         return 0;
760
761     print_standard_extension_info(dpy, extname,
762         xieInfo->server_major_rev, xieInfo->server_minor_rev);
763
764     printf("  service class: %s\n", subset_names[xieInfo->service_class]);
765     printf("  alignment: %s\n", align_names[xieInfo->alignment]);
766     printf("  uncnst_mantissa: %d\n", xieInfo->uncnst_mantissa);
767     printf("  uncnst_min_exp: %d\n", xieInfo->uncnst_min_exp);
768     printf("  uncnst_max_exp: %d\n", xieInfo->uncnst_max_exp);
769     printf("  cnst_levels:"); 
770     for (i = 0; i < xieInfo->n_cnst_levels; i++)
771         printf(" %d", xieInfo->cnst_levels[i]);
772     printf("\n");
773
774     if (!XieQueryTechniques(dpy, xieValAll, &ntechs, &techs))
775         return 1;
776
777     prevGroup = -1;
778
779     for (i = 0; i < ntechs; i++)
780     {
781         if (techs[i].group != prevGroup)
782         {
783             printf("  technique group: %s\n", group_names[techs[i].group >> 1]);
784             prevGroup = techs[i].group;
785         }
786         printf("    %s\tspeed: %d  needs_param: %s  number: %d\n",
787                techs[i].name,
788                techs[i].speed, (techs[i].needs_param ? "True " : "False"),
789                techs[i].number);
790     }
791     return 1;
792 } /* end print_xie_info */
793
794 #endif /* HAVE_XIE */
795
796
797 #ifdef HAVE_XTEST
798 int
799 print_xtest_info(dpy, extname)
800     Display *dpy;
801     char *extname;
802 {
803     int majorrev, minorrev, foo;
804
805     if (!XTestQueryExtension(dpy, &foo, &foo, &majorrev, &minorrev))
806         return 0;
807     print_standard_extension_info(dpy, extname, majorrev, minorrev);
808     return 1;
809 }
810 #endif /* HAVE_XTEST */
811
812 #ifdef HAVE_XSYNC
813 int
814 print_sync_info(dpy, extname)
815     Display *dpy;
816     char *extname;
817 {
818     int majorrev, minorrev;
819     XSyncSystemCounter *syscounters;
820     int ncounters, i;
821
822     if (!XSyncInitialize(dpy, &majorrev, &minorrev))
823         return 0;
824     print_standard_extension_info(dpy, extname, majorrev, minorrev);
825
826     syscounters = XSyncListSystemCounters(dpy, &ncounters);
827     printf("  system counters: %d\n", ncounters);
828     for (i = 0; i < ncounters; i++)
829     {
830         printf("    %s  id: 0x%08x  resolution_lo: %d  resolution_hi: %d\n",
831                syscounters[i].name, syscounters[i].counter,
832                XSyncValueLow32(syscounters[i].resolution),
833                XSyncValueHigh32(syscounters[i].resolution));
834     }
835     XSyncFreeSystemCounterList(syscounters);
836     return 1;
837 }
838 #endif /* HAVE_XSYNC */
839
840 int
841 print_shape_info(dpy, extname)
842     Display *dpy;
843     char *extname;
844 {
845     int majorrev, minorrev;
846
847     if (!XShapeQueryVersion(dpy, &majorrev, &minorrev))
848         return 0;
849     print_standard_extension_info(dpy, extname, majorrev, minorrev);
850     return 1;
851 }
852
853 #ifdef MITSHM
854 int
855 print_mitshm_info(dpy, extname)
856     Display *dpy;
857     char *extname;
858 {
859     int majorrev, minorrev;
860     Bool sharedPixmaps;
861
862     if (!XShmQueryVersion(dpy, &majorrev, &minorrev, &sharedPixmaps))
863         return 0;
864     print_standard_extension_info(dpy, extname, majorrev, minorrev);
865     printf("  shared pixmaps: ");
866     if (sharedPixmaps)
867     {
868         int format = XShmPixmapFormat(dpy);
869         printf("yes, format: %d\n", format);
870     }
871     else
872     {
873         printf("no\n");
874     }
875     return 1;
876 }
877 #endif /* MITSHM */
878
879 #ifdef HAVE_XDBE
880 int
881 print_dbe_info(dpy, extname)
882     Display *dpy;
883     char *extname;
884 {
885     int majorrev, minorrev;
886     XdbeScreenVisualInfo *svi;
887     int numscreens = 0;
888     int iscrn, ivis;
889
890     if (!XdbeQueryExtension(dpy, &majorrev, &minorrev))
891         return 0;
892
893     print_standard_extension_info(dpy, extname, majorrev, minorrev);
894     svi = XdbeGetVisualInfo(dpy, (Drawable *)NULL, &numscreens);
895     for (iscrn = 0; iscrn < numscreens; iscrn++)
896     {
897         printf("  Double-buffered visuals on screen %d\n", iscrn);
898         for (ivis = 0; ivis < svi[iscrn].count; ivis++)
899         {
900             printf("    visual id 0x%lx  depth %d  perflevel %d\n",
901                    svi[iscrn].visinfo[ivis].visual,
902                    svi[iscrn].visinfo[ivis].depth,
903                    svi[iscrn].visinfo[ivis].perflevel);
904         }
905     }
906     XdbeFreeVisualInfo(svi);
907     return 1;
908 }
909 #endif /* HAVE_XDBE */
910
911 #ifdef HAVE_XRECORD
912 int
913 print_record_info(dpy, extname)
914     Display *dpy;
915     char *extname;
916 {
917     int majorrev, minorrev;
918
919     if (!XRecordQueryVersion(dpy, &majorrev, &minorrev))
920         return 0;
921     print_standard_extension_info(dpy, extname, majorrev, minorrev);
922     return 1;
923 }
924 #endif /* HAVE_XRECORD */
925
926 /* utilities to manage the list of recognized extensions */
927
928
929 typedef int (*ExtensionPrintFunc)(
930 #if NeedFunctionPrototypes
931     Display *, char *
932 #endif
933 );
934
935 typedef struct {
936     char *extname;
937     ExtensionPrintFunc printfunc;
938     Bool printit;
939 } ExtensionPrintInfo;
940
941 ExtensionPrintInfo known_extensions[] =
942 {
943 #ifdef MITSHM
944     {"MIT-SHM", print_mitshm_info, False},
945 #endif /* MITSHM */
946     {MULTIBUFFER_PROTOCOL_NAME, print_multibuf_info, False},
947     {"SHAPE", print_shape_info, False},
948 #ifdef HAVE_XSYNC
949     {SYNC_NAME, print_sync_info, False},
950 #endif /* HAVE_XSYNC */
951 #ifdef HAVE_XIE
952     {xieExtName, print_xie_info, False},
953 #endif /* HAVE_XIE */
954 #ifdef HAVE_XTEST
955     {XTestExtensionName, print_xtest_info, False},
956 #endif /* HAVE_XTEST */
957 #ifdef HAVE_XDBE
958     {"DOUBLE-BUFFER", print_dbe_info, False},
959 #endif /* HAVE_XDBE */
960 #ifdef HAVE_XRECORD
961     {"RECORD", print_record_info, False}    
962 #endif /* HAVE_XRECORD */
963     /* add new extensions here */
964     /* wish list: PEX XKB LBX */
965 };
966
967 int num_known_extensions = sizeof known_extensions / sizeof known_extensions[0];
968
969 void
970 print_known_extensions(f)
971     FILE *f;
972 {
973     int i;
974     for (i = 0; i < num_known_extensions; i++)
975     {
976         fprintf(f, "%s ", known_extensions[i].extname);
977     }
978 }
979
980 void
981 mark_extension_for_printing(extname)
982     char *extname;
983 {
984     int i;
985
986     if (strcmp(extname, "all") == 0)
987     {
988         for (i = 0; i < num_known_extensions; i++)
989             known_extensions[i].printit = True;
990     }
991     else
992     {
993         for (i = 0; i < num_known_extensions; i++)
994         {
995             if (strcmp(extname, known_extensions[i].extname) == 0)
996             {
997                 known_extensions[i].printit = True;
998                 return;
999             }
1000         }
1001         printf("%s extension not supported by %s\n", extname, ProgramName);
1002     }
1003 }
1004
1005 void
1006 print_marked_extensions(dpy)
1007     Display *dpy;
1008 {
1009     int i;
1010     for (i = 0; i < num_known_extensions; i++)
1011     {
1012         if (known_extensions[i].printit)
1013         {
1014             printf("\n");
1015             if (! (*known_extensions[i].printfunc)(dpy,
1016                                         known_extensions[i].extname))
1017             {
1018                 printf("%s extension not supported by server\n",
1019                        known_extensions[i].extname);
1020             }
1021         }
1022     }
1023 }
1024
1025 static void usage ()
1026 {
1027     fprintf (stderr, "usage:  %s [options]\n", ProgramName);
1028     fprintf (stderr, "-display displayname\tserver to query\n");
1029     fprintf (stderr, "-queryExtensions\tprint info returned by XQueryExtension\n");
1030     fprintf (stderr, "-ext all\t\tprint detailed info for all supported extensions\n");
1031     fprintf (stderr, "-ext extension-name\tprint detailed info for extension-name if one of:\n     ");
1032     print_known_extensions(stderr);
1033     fprintf (stderr, "\n");
1034     exit (1);
1035 }
1036
1037 int main (argc, argv)
1038     int argc;
1039     char *argv[];
1040 {
1041     Display *dpy;                       /* X connection */
1042     char *displayname = NULL;           /* server to contact */
1043     int i;                              /* temp variable:  iterator */
1044     Bool multibuf = False;
1045     int mbuf_event_base, mbuf_error_base;
1046
1047     ProgramName = argv[0];
1048
1049     for (i = 1; i < argc; i++) {
1050         char *arg = argv[i];
1051         int len = strlen(arg);
1052         
1053         if (!strncmp("-display", arg, len)) {
1054             if (++i >= argc) usage ();
1055             displayname = argv[i];
1056         } else if (!strncmp("-queryExtensions", arg, len)) {
1057             queryExtensions = True;
1058         } else if (!strncmp("-ext", arg, len)) {
1059             if (++i >= argc) usage ();
1060             mark_extension_for_printing(argv[i]);
1061         } else
1062             usage ();
1063     }
1064
1065     dpy = XOpenDisplay (displayname);
1066     if (!dpy) {
1067         fprintf (stderr, "%s:  unable to open display \"%s\".\n",
1068                  ProgramName, XDisplayName (displayname));
1069         exit (1);
1070     }
1071
1072 #ifdef HAVE_OVERLAY
1073         find_overlay_info (dpy);
1074 #endif /* HAVE_OVERLAY */
1075
1076     print_display_info (dpy);
1077     for (i = 0; i < ScreenCount (dpy); i++) {
1078         print_screen_info (dpy, i);
1079     }
1080
1081     print_marked_extensions(dpy);
1082
1083     XCloseDisplay (dpy);
1084     exit (0);
1085 }