xdpyinfo.c revision b6f5cd12
1/*
2 * xdpyinfo - print information about X display connection
3 *
4 *
5Copyright 1988, 1998  The Open Group
6Copyright 2005 Hitachi, Ltd.
7
8Permission to use, copy, modify, distribute, and sell this software and its
9documentation for any purpose is hereby granted without fee, provided that
10the above copyright notice appear in all copies and that both that
11copyright notice and this permission notice appear in supporting
12documentation.
13
14The above copyright notice and this permission notice shall be included in
15all copies or substantial portions of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
20OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
24Except as contained in this notice, the name of The Open Group shall not be
25used in advertising or otherwise to promote the sale, use or other dealings
26in this Software without prior written authorization from The Open Group.
27 *
28 * Author:  Jim Fulton, MIT X Consortium
29 */
30
31#ifdef HAVE_CONFIG_H
32# include "config.h"
33# if HAVE_X11_EXTENSIONS_MULTIBUF_H
34#  define MULTIBUFFER
35# endif
36
37# if HAVE_X11_EXTENSIONS_XSHM_H
38#  define MITSHM
39# endif
40
41# if HAVE_X11_EXTENSIONS_XKB_H && HAVE_X11_XKBLIB_H
42#  define XKB
43# endif
44
45# if HAVE_X11_EXTENSIONS_XF86VMODE_H && \
46	(HAVE_X11_EXTENSIONS_XF86VMSTR_H || HAVE_X11_EXTENSIONS_XF86VMPROTO_H)
47#  define XF86VIDMODE
48# endif
49
50# if (HAVE_X11_EXTENSIONS_XXF86DGA_H && HAVE_X11_EXTENSIONS_XF86DGAPROTO_H) \
51  || (HAVE_X11_EXTENSIONS_XF86DGA_H && HAVE_X11_EXTENSIONS_XF86DGASTR_H)
52#  define XFreeXDGA
53# endif
54
55# if HAVE_X11_EXTENSIONS_XF86MISC_H && HAVE_X11_EXTENSIONS_XF86MSCSTR_H
56#  define XF86MISC
57# endif
58
59# if HAVE_X11_EXTENSIONS_XINPUT_H
60#  define XINPUT
61# endif
62
63# if HAVE_X11_EXTENSIONS_XRENDER_H
64#  define XRENDER
65# endif
66
67# if HAVE_X11_EXTENSIONS_XCOMPOSITE_H
68#  define COMPOSITE
69# endif
70
71# if HAVE_X11_EXTENSIONS_XINERAMA_H
72#  define PANORAMIX
73# endif
74
75# if HAVE_X11_EXTENSIONS_DMXEXT_H
76#  define DMX
77# endif
78
79#endif
80
81#ifdef WIN32
82#include <X11/Xwindows.h>
83#endif
84
85#include <X11/Xlib-xcb.h>
86#include <X11/Xlib.h>
87#include <X11/Xutil.h>
88#ifdef MULTIBUFFER
89#include <X11/extensions/multibuf.h>
90#endif
91#include <X11/extensions/XTest.h>
92#include <X11/extensions/sync.h>
93#include <X11/Xproto.h>
94#include <X11/extensions/Xdbe.h>
95#include <X11/extensions/record.h>
96#include <X11/extensions/shape.h>
97#ifdef MITSHM
98#include <X11/extensions/XShm.h>
99#endif
100#ifdef XKB
101#include <X11/extensions/XKB.h>
102#include <X11/XKBlib.h>
103#endif
104#ifdef XF86VIDMODE
105#include <X11/extensions/xf86vmode.h>
106# if HAVE_X11_EXTENSIONS_XF86VMPROTO_H /* xf86vidmodeproto 2.2.99.1 & later */
107#  include <X11/extensions/xf86vmproto.h>
108# else
109#  include <X11/extensions/xf86vmstr.h>
110# endif
111#endif
112#ifdef XFreeXDGA
113# if HAVE_X11_EXTENSIONS_XXF86DGA_H && HAVE_X11_EXTENSIONS_XF86DGAPROTO_H
114#  include <X11/extensions/Xxf86dga.h>
115#  include <X11/extensions/xf86dgaproto.h>
116# else
117#  include <X11/extensions/xf86dga.h>
118#  include <X11/extensions/xf86dgastr.h>
119# endif
120#endif
121#ifdef XF86MISC
122#include <X11/extensions/xf86misc.h>
123#include <X11/extensions/xf86mscstr.h>
124#endif
125#ifdef XINPUT
126#include <X11/extensions/XInput.h>
127#endif
128#ifdef XRENDER
129#include <X11/extensions/Xrender.h>
130#endif
131#ifdef COMPOSITE
132#include <X11/extensions/Xcomposite.h>
133#endif
134#ifdef PANORAMIX
135#include <X11/extensions/Xinerama.h>
136#endif
137#ifdef DMX
138#include <X11/extensions/dmxext.h>
139#endif
140#include <X11/Xos.h>
141#include <stdio.h>
142#include <stdlib.h>
143
144/* Turn a NULL pointer string into an empty string */
145#define NULLSTR(x) (((x)!=NULL)?(x):(""))
146
147static char *ProgramName;
148static Bool queryExtensions = False;
149
150static int
151silent_errors(Display *dpy, XErrorEvent *ev)
152{
153    return 0;
154}
155
156static int (*old_handler)(Display *, XErrorEvent *) = NULL;
157
158static int print_event_mask(char *buf, int lastcol, int indent, long mask);
159
160static int StrCmp(const void *a, const  void *b)
161{
162    return strcmp(*(char **)a, *(char **)b);
163}
164
165static void
166print_extension_info(Display *dpy)
167{
168    int n = 0;
169    char **extlist = XListExtensions (dpy, &n);
170
171    printf ("number of extensions:    %d\n", n);
172
173    if (extlist) {
174	int i;
175
176	qsort(extlist, n, sizeof(char *), StrCmp);
177
178	if (!queryExtensions) {
179	    for (i = 0; i < n; i++) {
180		printf ("    %s\n", extlist[i]);
181	    }
182	} else {
183	    xcb_connection_t *xcb_conn = XGetXCBConnection (dpy);
184	    xcb_query_extension_cookie_t *qe_cookies;
185
186	    qe_cookies = calloc(n, sizeof(xcb_query_extension_cookie_t));
187	    if (!qe_cookies) {
188		perror ("calloc failed to allocate memory for extensions");
189		return;
190	    }
191
192	    /*
193	     * Generate all extension queries at once, so they can be
194	     * sent to the xserver in a single batch
195	     */
196	    for (i = 0; i < n; i++) {
197		qe_cookies[i] = xcb_query_extension (xcb_conn,
198						     strlen(extlist[i]),
199						     extlist[i]);
200	    }
201
202	    /*
203	     * Start processing replies as they come in.
204	     * The first call will flush the queue to the server, then
205	     * each one will wait, if needed, for its reply.
206	     */
207	    for (i = 0; i < n; i++) {
208		xcb_query_extension_reply_t *rep
209		    = xcb_query_extension_reply(xcb_conn, qe_cookies[i], NULL);
210
211		printf ("    %s  (opcode: %d", extlist[i], rep->major_opcode);
212		if (rep->first_event)
213		    printf (", base event: %d", rep->first_event);
214		if (rep->first_error)
215		    printf (", base error: %d", rep->first_error);
216		printf (")\n");
217
218		free (rep);
219	    }
220	    free (qe_cookies);
221	}
222	/* do not free, Xlib can depend on contents being unaltered */
223	/* XFreeExtensionList (extlist); */
224    }
225}
226
227static void
228print_display_info(Display *dpy)
229{
230    char dummybuf[40];
231    const char *cp;
232    int minkeycode, maxkeycode;
233    int i, n;
234    long req_size;
235    XPixmapFormatValues *pmf;
236    Window focuswin;
237    int focusrevert;
238
239    printf ("name of display:    %s\n", DisplayString (dpy));
240    printf ("version number:    %d.%d\n",
241	    ProtocolVersion (dpy), ProtocolRevision (dpy));
242    printf ("vendor string:    %s\n", ServerVendor (dpy));
243    printf ("vendor release number:    %d\n", VendorRelease (dpy));
244
245    if (strstr(ServerVendor (dpy), "XFree86")) {
246	int vendrel = VendorRelease(dpy);
247
248	printf("XFree86 version: ");
249	if (vendrel < 336) {
250	    /*
251	     * vendrel was set incorrectly for 3.3.4 and 3.3.5, so handle
252	     * those cases here.
253	     */
254	    printf("%d.%d.%d", vendrel / 100,
255			      (vendrel / 10) % 10,
256			       vendrel       % 10);
257	} else if (vendrel < 3900) {
258	    /* 3.3.x versions, other than the exceptions handled above */
259	    printf("%d.%d", vendrel / 1000,
260			   (vendrel /  100) % 10);
261	    if (((vendrel / 10) % 10) || (vendrel % 10)) {
262		printf(".%d", (vendrel / 10) % 10);
263		if (vendrel % 10) {
264		    printf(".%d", vendrel % 10);
265		}
266	    }
267	} else if (vendrel < 40000000) {
268	    /* 4.0.x versions */
269	    printf("%d.%d", vendrel / 1000,
270			   (vendrel /   10) % 10);
271	    if (vendrel % 10) {
272		printf(".%d", vendrel % 10);
273	    }
274	} else {
275	    /* post-4.0.x */
276	    printf("%d.%d.%d", vendrel / 10000000,
277			      (vendrel /   100000) % 100,
278			      (vendrel /     1000) % 100);
279	    if (vendrel % 1000) {
280		printf(".%d", vendrel % 1000);
281	    }
282	}
283	printf("\n");
284    }
285
286    if (strstr(ServerVendor (dpy), "X.Org")) {
287	int vendrel = VendorRelease(dpy);
288
289	printf("X.Org version: ");
290	printf("%d.%d.%d", vendrel / 10000000,
291	       (vendrel /   100000) % 100,
292	       (vendrel /     1000) % 100);
293	if (vendrel % 1000)
294	    printf(".%d", vendrel % 1000);
295	printf("\n");
296    }
297
298    if (strstr(ServerVendor (dpy), "DMX")) {
299	int vendrel = VendorRelease(dpy);
300        int major, minor, year, month, day;
301
302        major    = vendrel / 100000000;
303        vendrel -= major   * 100000000;
304        minor    = vendrel /   1000000;
305        vendrel -= minor   *   1000000;
306        year     = vendrel /     10000;
307        vendrel -= year    *     10000;
308        month    = vendrel /       100;
309        vendrel -= month   *       100;
310        day      = vendrel;
311
312                                /* Add other epoch tests here */
313        if (major > 0 && minor > 0) year += 2000;
314
315                                /* Do some sanity tests in case there is
316                                 * another server with the same vendor
317                                 * string.  That server could easily use
318                                 * values < 100000000, which would have
319                                 * the effect of keeping our major
320                                 * number 0. */
321        if (major > 0 && major <= 20
322            && minor >= 0 && minor <= 99
323            && year >= 2000
324            && month >= 1 && month <= 12
325            && day >= 1 && day <= 31)
326            printf("DMX version: %d.%d.%04d%02d%02d\n",
327                   major, minor, year, month, day);
328    }
329
330    req_size = XExtendedMaxRequestSize (dpy);
331    if (!req_size) req_size = XMaxRequestSize (dpy);
332    printf ("maximum request size:  %ld bytes\n", req_size * 4);
333    printf ("motion buffer size:  %ld\n", XDisplayMotionBufferSize (dpy));
334
335    switch (BitmapBitOrder (dpy)) {
336      case LSBFirst:    cp = "LSBFirst"; break;
337      case MSBFirst:    cp = "MSBFirst"; break;
338      default:
339	snprintf (dummybuf, sizeof(dummybuf),
340                  "unknown order %d", BitmapBitOrder (dpy));
341	cp = dummybuf;
342	break;
343    }
344    printf ("bitmap unit, bit order, padding:    %d, %s, %d\n",
345	    BitmapUnit (dpy), cp, BitmapPad (dpy));
346
347    switch (ImageByteOrder (dpy)) {
348      case LSBFirst:    cp = "LSBFirst"; break;
349      case MSBFirst:    cp = "MSBFirst"; break;
350      default:
351	snprintf (dummybuf, sizeof(dummybuf),
352                  "unknown order %d", ImageByteOrder (dpy));
353	cp = dummybuf;
354	break;
355    }
356    printf ("image byte order:    %s\n", cp);
357
358    pmf = XListPixmapFormats (dpy, &n);
359    printf ("number of supported pixmap formats:    %d\n", n);
360    if (pmf) {
361	printf ("supported pixmap formats:\n");
362	for (i = 0; i < n; i++) {
363	    printf ("    depth %d, bits_per_pixel %d, scanline_pad %d\n",
364		    pmf[i].depth, pmf[i].bits_per_pixel, pmf[i].scanline_pad);
365	}
366	XFree ((char *) pmf);
367    }
368
369
370    /*
371     * when we get interfaces to the PixmapFormat stuff, insert code here
372     */
373
374    XDisplayKeycodes (dpy, &minkeycode, &maxkeycode);
375    printf ("keycode range:    minimum %d, maximum %d\n",
376	    minkeycode, maxkeycode);
377
378    XGetInputFocus (dpy, &focuswin, &focusrevert);
379    printf ("focus:  ");
380    switch (focuswin) {
381      case PointerRoot:
382	printf ("PointerRoot\n");
383	break;
384      case None:
385	printf ("None\n");
386	break;
387      default:
388	printf("window 0x%lx, revert to ", focuswin);
389	switch (focusrevert) {
390	  case RevertToParent:
391	    printf ("Parent\n");
392	    break;
393	  case RevertToNone:
394	    printf ("None\n");
395	    break;
396	  case RevertToPointerRoot:
397	    printf ("PointerRoot\n");
398	    break;
399	  default:			/* should not happen */
400	    printf ("%d\n", focusrevert);
401	    break;
402	}
403	break;
404    }
405
406    print_extension_info (dpy);
407
408    printf ("default screen number:    %d\n", DefaultScreen (dpy));
409    printf ("number of screens:    %d\n", ScreenCount (dpy));
410}
411
412static void
413print_visual_info(XVisualInfo *vip)
414{
415    char errorbuf[40];			/* for sprintfing into */
416    const char *class = NULL;		/* for printing */
417
418    switch (vip->class) {
419      case StaticGray:    class = "StaticGray"; break;
420      case GrayScale:    class = "GrayScale"; break;
421      case StaticColor:    class = "StaticColor"; break;
422      case PseudoColor:    class = "PseudoColor"; break;
423      case TrueColor:    class = "TrueColor"; break;
424      case DirectColor:    class = "DirectColor"; break;
425      default:
426	snprintf (errorbuf, sizeof(errorbuf), "unknown class %d", vip->class);
427	class = errorbuf;
428	break;
429    }
430
431    printf ("  visual:\n");
432    printf ("    visual id:    0x%lx\n", vip->visualid);
433    printf ("    class:    %s\n", class);
434    printf ("    depth:    %d plane%s\n", vip->depth,
435	    vip->depth == 1 ? "" : "s");
436    if (vip->class == TrueColor || vip->class == DirectColor)
437	printf ("    available colormap entries:    %d per subfield\n",
438		vip->colormap_size);
439    else
440	printf ("    available colormap entries:    %d\n",
441		vip->colormap_size);
442    printf ("    red, green, blue masks:    0x%lx, 0x%lx, 0x%lx\n",
443	    vip->red_mask, vip->green_mask, vip->blue_mask);
444    printf ("    significant bits in color specification:    %d bits\n",
445	    vip->bits_per_rgb);
446}
447
448static void
449print_screen_info(Display *dpy, int scr)
450{
451    Screen *s = ScreenOfDisplay (dpy, scr);  /* opaque structure */
452    XVisualInfo viproto;		/* fill in for getting info */
453    XVisualInfo *vip;			/* returned info */
454    int nvi;				/* number of elements returned */
455    int i;				/* temp variable: iterator */
456    char eventbuf[80];			/* want 79 chars per line + nul */
457    static const char *yes = "YES", *no = "NO", *when = "WHEN MAPPED";
458    double xres, yres;
459    int ndepths = 0, *depths = NULL;
460    unsigned int width, height;
461
462    /*
463     * there are 2.54 centimeters to an inch; so there are 25.4 millimeters.
464     *
465     *     dpi = N pixels / (M millimeters / (25.4 millimeters / 1 inch))
466     *         = N pixels / (M inch / 25.4)
467     *         = N * 25.4 pixels / M inch
468     */
469
470    xres = ((((double) DisplayWidth(dpy,scr)) * 25.4) /
471	    ((double) DisplayWidthMM(dpy,scr)));
472    yres = ((((double) DisplayHeight(dpy,scr)) * 25.4) /
473	    ((double) DisplayHeightMM(dpy,scr)));
474
475    printf ("\n");
476    printf ("screen #%d:\n", scr);
477    printf ("  dimensions:    %dx%d pixels (%dx%d millimeters)\n",
478	    XDisplayWidth (dpy, scr),  XDisplayHeight (dpy, scr),
479	    XDisplayWidthMM(dpy, scr), XDisplayHeightMM (dpy, scr));
480    printf ("  resolution:    %dx%d dots per inch\n",
481	    (int) (xres + 0.5), (int) (yres + 0.5));
482    depths = XListDepths (dpy, scr, &ndepths);
483    if (!depths) ndepths = 0;
484    printf ("  depths (%d):    ", ndepths);
485    for (i = 0; i < ndepths; i++) {
486	printf ("%d", depths[i]);
487	if (i < ndepths - 1) {
488	    putchar (',');
489	    putchar (' ');
490	}
491    }
492    putchar ('\n');
493    if (depths) XFree ((char *) depths);
494    printf ("  root window id:    0x%lx\n", RootWindow (dpy, scr));
495    printf ("  depth of root window:    %d plane%s\n",
496	    DisplayPlanes (dpy, scr),
497	    DisplayPlanes (dpy, scr) == 1 ? "" : "s");
498    printf ("  number of colormaps:    minimum %d, maximum %d\n",
499	    MinCmapsOfScreen(s), MaxCmapsOfScreen(s));
500    printf ("  default colormap:    0x%lx\n", DefaultColormap (dpy, scr));
501    printf ("  default number of colormap cells:    %d\n",
502	    DisplayCells (dpy, scr));
503    printf ("  preallocated pixels:    black %ld, white %ld\n",
504	    BlackPixel (dpy, scr), WhitePixel (dpy, scr));
505    printf ("  options:    backing-store %s, save-unders %s\n",
506	    (DoesBackingStore (s) == NotUseful) ? no :
507	    ((DoesBackingStore (s) == Always) ? yes : when),
508	    DoesSaveUnders (s) ? yes : no);
509    XQueryBestSize (dpy, CursorShape, RootWindow (dpy, scr), 65535, 65535,
510		    &width, &height);
511    if (width == 65535 && height == 65535)
512	printf ("  largest cursor:    unlimited\n");
513    else
514	printf ("  largest cursor:    %dx%d\n", width, height);
515    printf ("  current input event mask:    0x%lx\n", EventMaskOfScreen (s));
516    (void) print_event_mask (eventbuf, 79, 4, EventMaskOfScreen (s));
517
518    nvi = 0;
519    viproto.screen = scr;
520    vip = XGetVisualInfo (dpy, VisualScreenMask, &viproto, &nvi);
521    printf ("  number of visuals:    %d\n", nvi);
522    printf ("  default visual id:  0x%lx\n",
523	    XVisualIDFromVisual (DefaultVisual (dpy, scr)));
524    for (i = 0; i < nvi; i++) {
525	print_visual_info (vip+i);
526    }
527    if (vip) XFree ((char *) vip);
528}
529
530/*
531 * The following routine prints out an event mask, wrapping events at nice
532 * boundaries.
533 */
534
535#define MASK_NAME_WIDTH 25
536
537static struct _event_table {
538    const char *name;
539    long value;
540} event_table[] = {
541    { "KeyPressMask             ", KeyPressMask },
542    { "KeyReleaseMask           ", KeyReleaseMask },
543    { "ButtonPressMask          ", ButtonPressMask },
544    { "ButtonReleaseMask        ", ButtonReleaseMask },
545    { "EnterWindowMask          ", EnterWindowMask },
546    { "LeaveWindowMask          ", LeaveWindowMask },
547    { "PointerMotionMask        ", PointerMotionMask },
548    { "PointerMotionHintMask    ", PointerMotionHintMask },
549    { "Button1MotionMask        ", Button1MotionMask },
550    { "Button2MotionMask        ", Button2MotionMask },
551    { "Button3MotionMask        ", Button3MotionMask },
552    { "Button4MotionMask        ", Button4MotionMask },
553    { "Button5MotionMask        ", Button5MotionMask },
554    { "ButtonMotionMask         ", ButtonMotionMask },
555    { "KeymapStateMask          ", KeymapStateMask },
556    { "ExposureMask             ", ExposureMask },
557    { "VisibilityChangeMask     ", VisibilityChangeMask },
558    { "StructureNotifyMask      ", StructureNotifyMask },
559    { "ResizeRedirectMask       ", ResizeRedirectMask },
560    { "SubstructureNotifyMask   ", SubstructureNotifyMask },
561    { "SubstructureRedirectMask ", SubstructureRedirectMask },
562    { "FocusChangeMask          ", FocusChangeMask },
563    { "PropertyChangeMask       ", PropertyChangeMask },
564    { "ColormapChangeMask       ", ColormapChangeMask },
565    { "OwnerGrabButtonMask      ", OwnerGrabButtonMask },
566    { NULL, 0 }};
567
568static int
569print_event_mask(char *buf,     /* string to write into */
570                 int lastcol,   /* strlen(buf)+1 */
571                 int indent,    /* amount by which to indent */
572                 long mask)     /* event mask */
573{
574    struct _event_table *etp;
575    int len;
576    int bitsfound = 0;
577
578    buf[0] = buf[lastcol] = '\0';	/* just in case */
579
580#define INDENT() { register int i; len = indent; \
581		   for (i = 0; i < indent; i++) buf[i] = ' '; }
582
583    INDENT ();
584
585    for (etp = event_table; etp->name; etp++) {
586	if (mask & etp->value) {
587	    if (len + MASK_NAME_WIDTH > lastcol) {
588		puts (buf);
589		INDENT ();
590	    }
591	    strcpy (buf+len, etp->name);
592	    len += MASK_NAME_WIDTH;
593	    bitsfound++;
594	}
595    }
596
597    if (bitsfound) puts (buf);
598
599#undef INDENT
600
601    return (bitsfound);
602}
603
604static void
605print_standard_extension_info(Display *dpy, const char *extname,
606			      int majorrev, int minorrev)
607{
608    int opcode, event, error;
609
610    printf("%s version %d.%d ", extname, majorrev, minorrev);
611
612    XQueryExtension(dpy, extname, &opcode, &event, &error);
613    printf ("opcode: %d", opcode);
614    if (event)
615	printf (", base event: %d", event);
616    if (error)
617	printf (", base error: %d", error);
618    printf("\n");
619}
620
621#ifdef MULTIBUFFER
622static int
623print_multibuf_info(Display *dpy, const char *extname)
624{
625    int i, j;			/* temp variable: iterator */
626    int nmono, nstereo;		/* count */
627    XmbufBufferInfo *mono_info = NULL, *stereo_info = NULL; /* arrays */
628#define MULTIBUF_FMT "    visual id, max buffers, depth:    0x%lx, %d, %d\n"
629    int scr = 0;
630    int majorrev, minorrev;
631
632    if (!XmbufGetVersion(dpy, &majorrev, &minorrev))
633	return 0;
634
635    print_standard_extension_info(dpy, extname, majorrev, minorrev);
636
637    for (i = 0; i < ScreenCount (dpy); i++)
638    {
639	if (!XmbufGetScreenInfo (dpy, RootWindow(dpy, scr), &nmono, &mono_info,
640				 &nstereo, &stereo_info)) {
641	    fprintf (stderr,
642		     "%s:  unable to get multibuffer info for screen %d\n",
643		     ProgramName, scr);
644	} else {
645	    printf ("  screen %d number of mono multibuffer types:    %d\n", i, nmono);
646	    for (j = 0; j < nmono; j++) {
647		printf (MULTIBUF_FMT, mono_info[j].visualid,
648			mono_info[j].max_buffers, mono_info[j].depth);
649	    }
650	    printf ("  number of stereo multibuffer types:    %d\n", nstereo);
651	    for (j = 0; j < nstereo; j++) {
652		printf (MULTIBUF_FMT, stereo_info[j].visualid,
653			stereo_info[j].max_buffers, stereo_info[j].depth);
654	    }
655	    if (mono_info) XFree ((char *) mono_info);
656	    if (stereo_info) XFree ((char *) stereo_info);
657	}
658    }
659    return 1;
660} /* end print_multibuf_info */
661#endif
662
663static int
664print_xtest_info(Display *dpy, const char *extname)
665{
666    int majorrev, minorrev, foo;
667
668    if (!XTestQueryExtension(dpy, &foo, &foo, &majorrev, &minorrev))
669	return 0;
670    print_standard_extension_info(dpy, extname, majorrev, minorrev);
671    return 1;
672}
673
674static int
675print_sync_info(Display *dpy, const char *extname)
676{
677    int majorrev, minorrev;
678    XSyncSystemCounter *syscounters;
679    int ncounters, i;
680
681    if (!XSyncInitialize(dpy, &majorrev, &minorrev))
682	return 0;
683    print_standard_extension_info(dpy, extname, majorrev, minorrev);
684
685    syscounters = XSyncListSystemCounters(dpy, &ncounters);
686    printf("  system counters: %d\n", ncounters);
687    for (i = 0; i < ncounters; i++)
688    {
689	printf("    %s  id: 0x%08x  resolution_lo: %d  resolution_hi: %d\n",
690	       syscounters[i].name, (unsigned int)syscounters[i].counter,
691	       XSyncValueLow32(syscounters[i].resolution),
692	       XSyncValueHigh32(syscounters[i].resolution));
693    }
694    XSyncFreeSystemCounterList(syscounters);
695    return 1;
696}
697
698static int
699print_shape_info(Display *dpy, const char *extname)
700{
701    int majorrev, minorrev;
702
703    if (!XShapeQueryVersion(dpy, &majorrev, &minorrev))
704	return 0;
705    print_standard_extension_info(dpy, extname, majorrev, minorrev);
706    return 1;
707}
708
709#ifdef XFreeXDGA
710static int
711print_dga_info(Display *dpy, const char *extname)
712{
713    unsigned int offset;
714    int majorrev, minorrev, width, bank, ram, flags;
715
716    if (!XF86DGAQueryVersion(dpy, &majorrev, &minorrev))
717	return 0;
718    print_standard_extension_info(dpy, extname, majorrev, minorrev);
719
720    if (!XF86DGAQueryDirectVideo(dpy, DefaultScreen(dpy), &flags)
721	|| ! (flags & XF86DGADirectPresent) )
722    {
723	printf("  DGA not available on screen %d.\n", DefaultScreen(dpy));
724	return 1;
725    }
726
727    old_handler = XSetErrorHandler(silent_errors);
728
729    if (!XF86DGAGetVideoLL(dpy, DefaultScreen(dpy), &offset,
730			    &width, &bank, &ram))
731	return 0;
732    printf("  Base address = 0x%X, Width = %d, Bank size = %d,"
733	   " RAM size = %dk\n", offset, width, bank, ram);
734
735    XSetErrorHandler(old_handler);
736
737    return 1;
738}
739#endif
740
741#ifdef XF86VIDMODE
742#define V_PHSYNC        0x001
743#define V_NHSYNC        0x002
744#define V_PVSYNC        0x004
745#define V_NVSYNC        0x008
746#define V_INTERLACE     0x010
747#define V_DBLSCAN       0x020
748#define V_CSYNC         0x040
749#define V_PCSYNC        0x080
750#define V_NCSYNC        0x100
751
752static void
753print_XF86VidMode_modeline(
754    unsigned int        dotclock,
755    unsigned short      hdisplay,
756    unsigned short      hsyncstart,
757    unsigned short      hsyncend,
758    unsigned short      htotal,
759    unsigned short      vdisplay,
760    unsigned short      vsyncstart,
761    unsigned short      vsyncend,
762    unsigned short      vtotal,
763    unsigned int        flags)
764{
765    printf("    %6.2f   %4d %4d %4d %4d   %4d %4d %4d %4d ",
766	   (float)dotclock/1000.0,
767	   hdisplay, hsyncstart, hsyncend, htotal,
768	   vdisplay, vsyncstart, vsyncend, vtotal);
769    if (flags & V_PHSYNC)    printf(" +hsync");
770    if (flags & V_NHSYNC)    printf(" -hsync");
771    if (flags & V_PVSYNC)    printf(" +vsync");
772    if (flags & V_NVSYNC)    printf(" -vsync");
773    if (flags & V_INTERLACE) printf(" interlace");
774    if (flags & V_CSYNC)     printf(" composite");
775    if (flags & V_PCSYNC)    printf(" +csync");
776    if (flags & V_NCSYNC)    printf(" -csync");
777    if (flags & V_DBLSCAN)   printf(" doublescan");
778    printf("\n");
779}
780
781static int
782print_XF86VidMode_info(Display *dpy, const char *extname)
783{
784    int majorrev, minorrev, modecount, dotclock, i;
785    XF86VidModeMonitor monitor;
786    XF86VidModeModeLine modeline;
787    XF86VidModeModeInfo **modelines;
788
789    if (!XF86VidModeQueryVersion(dpy, &majorrev, &minorrev))
790	return 0;
791    print_standard_extension_info(dpy, extname, majorrev, minorrev);
792
793    if (XF86VidModeGetMonitor(dpy, DefaultScreen(dpy), &monitor)) {
794	printf("  Monitor Information:\n");
795	printf("    Vendor: %s, Model: %s\n",
796	       monitor.vendor == NULL ? "" : monitor.vendor,
797	       monitor.model == NULL ? "" : monitor.model);
798	printf("    Num hsync: %d, Num vsync: %d\n",
799	       monitor.nhsync, monitor.nvsync);
800	for (i = 0; i < monitor.nhsync; i++) {
801	    printf("    hsync range %d: %6.2f - %6.2f\n", i,
802		   monitor.hsync[i].lo, monitor.hsync[i].hi);
803	}
804	for (i = 0; i < monitor.nvsync; i++) {
805	    printf("    vsync range %d: %6.2f - %6.2f\n", i,
806		   monitor.vsync[i].lo, monitor.vsync[i].hi);
807	}
808	XFree(monitor.vendor);
809	XFree(monitor.model);
810	XFree(monitor.hsync);
811	XFree(monitor.vsync);
812    } else {
813	printf("  Monitor Information not available\n");
814    }
815
816    if ((majorrev > 0) || (majorrev == 0 && minorrev > 5)) {
817      if (XF86VidModeGetAllModeLines(dpy, DefaultScreen(dpy), &modecount,
818				     &modelines)) {
819	  printf("  Available Video Mode Settings:\n");
820	  printf("     Clock   Hdsp Hbeg Hend Httl   Vdsp Vbeg Vend Vttl  Flags\n");
821	  for (i = 0; i < modecount; i++) {
822	      print_XF86VidMode_modeline
823		  (modelines[i]->dotclock, modelines[i]->hdisplay,
824		   modelines[i]->hsyncstart, modelines[i]->hsyncend,
825		   modelines[i]->htotal, modelines[i]->vdisplay,
826		   modelines[i]->vsyncstart, modelines[i]->vsyncend,
827		   modelines[i]->vtotal, modelines[i]->flags);
828	  }
829	  XFree(modelines);
830      } else {
831	  printf("  Available Video Mode Settings not available\n");
832      }
833
834      if (XF86VidModeGetModeLine(dpy, DefaultScreen(dpy),
835				 &dotclock, &modeline)) {
836	  printf("  Current Video Mode Setting:\n");
837	  print_XF86VidMode_modeline(dotclock,
838				     modeline.hdisplay, modeline.hsyncstart,
839				     modeline.hsyncend, modeline.htotal,
840				     modeline.vdisplay, modeline.vsyncstart,
841				     modeline.vsyncend, modeline.vtotal,
842				     modeline.flags);
843      } else {
844	  printf("  Current Video Mode Setting not available\n");
845      }
846    }
847
848    return 1;
849}
850#endif
851
852#ifdef XF86MISC
853
854static const char *kbdtable[] = {
855		     "Unknown", "84-key", "101-key", "Other", "Xqueue" };
856static const char *msetable[] = {
857		     "None", "Microsoft", "MouseSystems", "MMSeries",
858		     "Logitech", "BusMouse", "Mouseman", "PS/2", "MMHitTab",
859		     "GlidePoint", "IntelliMouse", "ThinkingMouse",
860		     "IMPS/2", "ThinkingMousePS/2", "MouseManPlusPS/2",
861		     "GlidePointPS/2", "NetMousePS/2", "NetScrollPS/2",
862		     "SysMouse", "Auto" };
863static const char *flgtable[] = {
864		     "None", "ClearDTR", "ClearRTS", "ClearDTR and ClearRTS" };
865
866static int
867print_XF86Misc_info(Display *dpy, const char *extname)
868{
869    int majorrev, minorrev;
870    XF86MiscMouseSettings mouseinfo;
871    XF86MiscKbdSettings kbdinfo;
872
873    if (!XF86MiscQueryVersion(dpy, &majorrev, &minorrev))
874	return 0;
875    print_standard_extension_info(dpy, extname, majorrev, minorrev);
876
877    old_handler = XSetErrorHandler(silent_errors);
878
879    if ((majorrev > 0) || (majorrev == 0 && minorrev > 0)) {
880      if (!XF86MiscGetKbdSettings(dpy, &kbdinfo))
881	return 0;
882      printf("  Keyboard Settings-    Type: %s, Rate: %d, Delay: %d, ServerNumLock: %s\n",
883	kbdtable[kbdinfo.type], kbdinfo.rate, kbdinfo.delay,
884	(kbdinfo.servnumlock? "yes": "no"));
885
886      if (!XF86MiscGetMouseSettings(dpy, &mouseinfo))
887	return 0;
888      printf("  Mouse Settings-       Device: %s, Type: ",
889	strlen(mouseinfo.device) == 0 ? "None": mouseinfo.device);
890      XFree(mouseinfo.device);
891      if (mouseinfo.type == MTYPE_XQUEUE)
892	printf("Xqueue\n");
893      else if (mouseinfo.type == MTYPE_OSMOUSE)
894	printf("OSMouse\n");
895      else if (mouseinfo.type <= MTYPE_AUTOMOUSE)
896	printf("%s\n", msetable[mouseinfo.type+1]);
897      else
898	printf("Unknown\n");
899      printf("                        BaudRate: %d, SampleRate: %d, Resolution: %d\n",
900	mouseinfo.baudrate, mouseinfo.samplerate, mouseinfo.resolution);
901      printf("                        Emulate3Buttons: %s, Emulate3Timeout: %d ms\n",
902	mouseinfo.emulate3buttons? "yes": "no", mouseinfo.emulate3timeout);
903      printf("                        ChordMiddle: %s, Flags: %s\n",
904	mouseinfo.chordmiddle? "yes": "no",
905	flgtable[(mouseinfo.flags & MF_CLEAR_DTR? 1: 0)
906		+(mouseinfo.flags & MF_CLEAR_RTS? 1: 0)] );
907      printf("                        Buttons: %d\n", mouseinfo.buttons);
908    }
909
910    XSetErrorHandler(old_handler);
911
912    return 1;
913}
914#endif
915
916#ifdef MITSHM
917static int
918print_mitshm_info(Display *dpy, const char *extname)
919{
920    int majorrev, minorrev;
921    Bool sharedPixmaps;
922
923    if (!XShmQueryVersion(dpy, &majorrev, &minorrev, &sharedPixmaps))
924	return 0;
925    print_standard_extension_info(dpy, extname, majorrev, minorrev);
926    printf("  shared pixmaps: ");
927    if (sharedPixmaps)
928    {
929	int format = XShmPixmapFormat(dpy);
930	printf("yes, format: %d\n", format);
931    }
932    else
933    {
934	printf("no\n");
935    }
936    return 1;
937}
938#endif /* MITSHM */
939
940#ifdef XKB
941static int
942print_xkb_info(Display *dpy, const char *extname)
943{
944    int opcode, eventbase, errorbase, majorrev, minorrev;
945
946    if (!XkbQueryExtension(dpy, &opcode, &eventbase, &errorbase,
947			   &majorrev, &minorrev)) {
948        return 0;
949    }
950    printf("%s version %d.%d ", extname, majorrev, minorrev);
951
952    printf ("opcode: %d", opcode);
953    if (eventbase)
954	printf (", base event: %d", eventbase);
955    if (errorbase)
956	printf (", base error: %d", errorbase);
957    printf("\n");
958
959    return 1;
960}
961#endif
962
963static int
964print_dbe_info(Display *dpy, const char *extname)
965{
966    int majorrev, minorrev;
967    XdbeScreenVisualInfo *svi;
968    int numscreens = 0;
969    int iscrn, ivis;
970
971    if (!XdbeQueryExtension(dpy, &majorrev, &minorrev))
972	return 0;
973
974    print_standard_extension_info(dpy, extname, majorrev, minorrev);
975    svi = XdbeGetVisualInfo(dpy, (Drawable *)NULL, &numscreens);
976    for (iscrn = 0; iscrn < numscreens; iscrn++)
977    {
978	printf("  Double-buffered visuals on screen %d\n", iscrn);
979	for (ivis = 0; ivis < svi[iscrn].count; ivis++)
980	{
981	    printf("    visual id 0x%lx  depth %d  perflevel %d\n",
982		   svi[iscrn].visinfo[ivis].visual,
983		   svi[iscrn].visinfo[ivis].depth,
984		   svi[iscrn].visinfo[ivis].perflevel);
985	}
986    }
987    XdbeFreeVisualInfo(svi);
988    return 1;
989}
990
991static int
992print_record_info(Display *dpy, const char *extname)
993{
994    int majorrev, minorrev;
995
996    if (!XRecordQueryVersion(dpy, &majorrev, &minorrev))
997	return 0;
998    print_standard_extension_info(dpy, extname, majorrev, minorrev);
999    return 1;
1000}
1001
1002#ifdef XINPUT
1003static int
1004print_xinput_info(Display *dpy, const char *extname)
1005{
1006  int           loop, num_extensions, num_devices;
1007  char          **extensions;
1008  XDeviceInfo   *devices;
1009  XExtensionVersion *ext;
1010
1011  ext = XGetExtensionVersion(dpy, extname);
1012
1013  if (!ext || (ext == (XExtensionVersion*) NoSuchExtension))
1014      return 0;
1015
1016  print_standard_extension_info(dpy, extname, ext->major_version,
1017				ext->minor_version);
1018  XFree(ext);
1019
1020  extensions = XListExtensions(dpy, &num_extensions);
1021  for (loop = 0; loop < num_extensions &&
1022         (strcmp(extensions[loop], extname) != 0); loop++);
1023  XFreeExtensionList(extensions);
1024  if (loop != num_extensions) {
1025      printf("  Extended devices :\n");
1026      devices = XListInputDevices(dpy, &num_devices);
1027      for(loop=0; loop<num_devices; loop++) {
1028	  printf("	\"%s\"	[", devices[loop].name ? devices[loop].name : "<noname>");
1029	  switch(devices[loop].use) {
1030	  case IsXPointer:
1031	      printf("XPointer]\n");
1032	      break;
1033	  case IsXKeyboard:
1034	      printf("XKeyboard]\n");
1035	      break;
1036	  case IsXExtensionDevice:
1037	      printf("XExtensionDevice]\n");
1038	      break;
1039#ifdef IsXExtensionKeyboard
1040	  case IsXExtensionKeyboard:
1041	      printf("XExtensionKeyboard]\n");
1042	      break;
1043#endif
1044#ifdef IsXExtensionPointer
1045	  case IsXExtensionPointer:
1046	      printf("XExtensionPointer]\n");
1047	      break;
1048#endif
1049	  default:
1050	      printf("invalid value]\n");
1051	      break;
1052	  }
1053        }
1054      XFreeDeviceList(devices);
1055      return 1;
1056    }
1057  else
1058      return 0;
1059}
1060#endif
1061
1062#ifdef XRENDER
1063static int
1064print_xrender_info(Display *dpy, const char *extname)
1065{
1066  int		    loop, num_extensions;
1067  char		    **extensions;
1068  XRenderPictFormat *pictform;
1069  int		    count;
1070  int		    major, minor;
1071  int		    i, j;
1072  XVisualInfo	    viproto;		/* fill in for getting info */
1073  XVisualInfo	    *vip;		/* retured info */
1074  int		    nvi;		/* number of elements returned */
1075  int		    ndepths = 0, *depths = NULL;
1076#if RENDER_MAJOR > 0 || RENDER_MINOR >= 6
1077  XFilters	    *filters;
1078  int		    f;
1079#endif
1080
1081  if (!XRenderQueryVersion (dpy, &major, &minor))
1082    return 0;
1083
1084  print_standard_extension_info(dpy, extname, major, minor);
1085
1086  extensions = XListExtensions(dpy, &num_extensions);
1087  for (loop = 0; loop < num_extensions &&
1088         (strcmp(extensions[loop], extname) != 0); loop++);
1089  XFreeExtensionList(extensions);
1090  if (loop != num_extensions) {
1091    printf ("  Render formats :\n");
1092    for (count = 0; (pictform = XRenderFindFormat (dpy, 0, NULL, count)); count++)
1093    {
1094      printf  ("  pict format:\n");
1095      printf  ("\tformat id:    0x%lx\n", pictform->id);
1096      printf  ("\ttype:         %s\n",
1097	     pictform->type == PictTypeIndexed ? "Indexed" : "Direct");
1098      printf  ("\tdepth:        %d\n", pictform->depth);
1099      if (pictform->type == PictTypeDirect) {
1100	printf("\talpha:        %2d mask 0x%x\n", pictform->direct.alpha, pictform->direct.alphaMask);
1101	printf("\tred:          %2d mask 0x%x\n", pictform->direct.red, pictform->direct.redMask);
1102	printf("\tgreen:        %2d mask 0x%x\n", pictform->direct.green, pictform->direct.greenMask);
1103	printf("\tblue:         %2d mask 0x%x\n", pictform->direct.blue, pictform->direct.blueMask);
1104      }
1105      else
1106	printf("\tcolormap      0x%lx\n", pictform->colormap);
1107    }
1108    printf ("  Screen formats :\n");
1109    for (i = 0; i < ScreenCount (dpy); i++) {
1110      nvi = 0;
1111      viproto.screen = i;
1112      vip = XGetVisualInfo (dpy, VisualScreenMask, &viproto, &nvi);
1113      printf ("    Screen %d", i);
1114#if RENDER_MAJOR > 0 || RENDER_MINOR >= 6
1115      switch (XRenderQuerySubpixelOrder (dpy, i)) {
1116      case SubPixelUnknown: printf (" (sub-pixel order Unknown)"); break;
1117      case SubPixelHorizontalRGB: printf (" (sub-pixel order Horizontal RGB)"); break;
1118      case SubPixelHorizontalBGR: printf (" (sub-pixel order Horizontal BGR)"); break;
1119      case SubPixelVerticalRGB: printf (" (sub-pixel order Vertical RGB)"); break;
1120      case SubPixelVerticalBGR: printf (" (sub-pixel order Vertical BGR)"); break;
1121      case SubPixelNone: printf (" (sub-pixel order None)"); break;
1122      }
1123      printf ("\n");
1124      filters = XRenderQueryFilters (dpy, RootWindow (dpy, i));
1125      if (filters)
1126      {
1127	printf ("      filters: ");
1128	for (f = 0; f < filters->nfilter; f++)
1129	{
1130	  printf ("%s", filters->filter[f]);
1131	  if (f < filters->nalias && filters->alias[f] != FilterAliasNone)
1132	    printf ("(%s)", filters->filter[filters->alias[f]]);
1133	  if (f < filters->nfilter - 1)
1134	    printf (", ");
1135	}
1136	XFree (filters);
1137      }
1138#endif
1139      printf ("\n");
1140      for (j = 0; j < nvi; j++)
1141      {
1142	printf  ("      visual format:\n");
1143	printf  ("        visual id:      0x%lx\n", vip[j].visualid);
1144	pictform = XRenderFindVisualFormat (dpy, vip[j].visual);
1145	if (pictform)
1146	  printf("        pict format id: 0x%lx\n", pictform->id);
1147	else
1148	  printf("        pict format id: None\n");
1149      }
1150      if (vip) XFree ((char *) vip);
1151      depths = XListDepths (dpy, i, &ndepths);
1152      if (!depths) ndepths = 0;
1153      for (j = 0; j < ndepths; j++)
1154      {
1155	XRenderPictFormat templ;
1156
1157	templ.depth = depths[j];
1158	printf  ("     depth formats:\n");
1159	printf  ("       depth           %d\n", depths[j]);
1160	for (count = 0; (pictform = XRenderFindFormat (dpy, PictFormatDepth, &templ, count)); count++)
1161	  printf("       pict format id: 0x%lx\n", pictform->id);
1162      }
1163      if (depths) XFree (depths);
1164    }
1165    return 1;
1166  }
1167  else
1168    return 0;
1169}
1170#endif /* XRENDER */
1171
1172#ifdef COMPOSITE
1173static int
1174print_composite_info(Display *dpy, const char *extname)
1175{
1176    int majorrev, minorrev, foo;
1177
1178    if (!XCompositeQueryExtension(dpy, &foo, &foo))
1179	return 0;
1180    if (!XCompositeQueryVersion(dpy, &majorrev, &minorrev))
1181	return 0;
1182    print_standard_extension_info(dpy, extname, majorrev, minorrev);
1183    return 1;
1184}
1185#endif
1186
1187#ifdef PANORAMIX
1188
1189static int
1190print_xinerama_info(Display *dpy, const char *extname)
1191{
1192  int              majorrev, minorrev;
1193
1194  if (!XineramaQueryVersion (dpy, &majorrev, &minorrev))
1195    return 0;
1196
1197  print_standard_extension_info(dpy, extname, majorrev, minorrev);
1198
1199  if (!XineramaIsActive(dpy)) {
1200    printf("  Xinerama is inactive.\n");
1201  } else {
1202    int i, count = 0;
1203    XineramaScreenInfo *xineramaScreens = XineramaQueryScreens(dpy, &count);
1204
1205    for (i = 0; i < count; i++) {
1206      XineramaScreenInfo *xs = &xineramaScreens[i];
1207      printf("  head #%d: %dx%d @ %d,%d\n", xs->screen_number,
1208             xs->width, xs->height, xs->x_org, xs->y_org);
1209    }
1210
1211    XFree(xineramaScreens);
1212  }
1213
1214  return 1;
1215}
1216
1217#endif /* PANORAMIX */
1218
1219#ifdef DMX
1220static const char *core(DMXInputAttributes *iinfo)
1221{
1222    if (iinfo->isCore)         return "core";
1223    else if (iinfo->sendsCore) return "extension (sends core)";
1224    else                       return "extension";
1225}
1226
1227static int print_dmx_info(Display *dpy, const char *extname)
1228{
1229    int                  event_base, error_base;
1230    int                  major_version, minor_version, patch_version;
1231    DMXScreenAttributes  sinfo;
1232    DMXInputAttributes   iinfo;
1233    int                  count;
1234    int                  i;
1235
1236    if (!DMXQueryExtension(dpy, &event_base, &error_base)
1237        || !DMXQueryVersion(dpy, &major_version, &minor_version,
1238                            &patch_version)) return 0;
1239    print_standard_extension_info(dpy, extname, major_version, minor_version);
1240    printf("  Version stamp: %d\n", patch_version);
1241
1242    if (!DMXGetScreenCount(dpy, &count)) return 1;
1243    printf("  Screen count: %d\n", count);
1244    for (i = 0; i < count; i++) {
1245        if (DMXGetScreenAttributes(dpy, i, &sinfo)) {
1246            printf("    %2d %s %ux%u+%d+%d %d @%dx%d\n",
1247                   i, sinfo.displayName,
1248                   sinfo.screenWindowWidth, sinfo.screenWindowHeight,
1249                   sinfo.screenWindowXoffset, sinfo.screenWindowYoffset,
1250                   sinfo.logicalScreen,
1251                   sinfo.rootWindowXorigin, sinfo.rootWindowYorigin);
1252        }
1253    }
1254
1255    if (major_version != 1
1256        || minor_version < 1
1257        || !DMXGetInputCount(dpy, &count))
1258        return 1;
1259
1260    printf("  Input count = %d\n", count);
1261    for (i = 0; i < count; i++) {
1262#ifdef XINPUT
1263        Display *backend;
1264        char    *backendname = NULL;
1265#endif
1266        if (DMXGetInputAttributes(dpy, i, &iinfo)) {
1267            switch (iinfo.inputType) {
1268            case DMXLocalInputType:
1269                printf("    %2d local %s", i, core(&iinfo));
1270                break;
1271            case DMXConsoleInputType:
1272                printf("    %2d console %s %s", i, core(&iinfo),
1273                       iinfo.name);
1274                break;
1275            case DMXBackendInputType:
1276#ifdef XINPUT
1277                if (iinfo.physicalId >= 0) {
1278                    if ((backend = XOpenDisplay(iinfo.name))) {
1279                        XExtensionVersion *ext
1280                            = XGetExtensionVersion(backend, INAME);
1281                        if (ext
1282                            && ext != (XExtensionVersion *)NoSuchExtension) {
1283
1284                            int         dcount, d;
1285                            XDeviceInfo *devInfo = XListInputDevices(backend,
1286                                                                     &dcount);
1287                            if (devInfo) {
1288                                for (d = 0; d < dcount; d++) {
1289                                    if ((unsigned)iinfo.physicalId
1290                                        == devInfo[d].id
1291                                        && devInfo[d].name) {
1292                                        backendname = strdup(devInfo[d].name);
1293                                        break;
1294                                    }
1295                                }
1296                                XFreeDeviceList(devInfo);
1297                            }
1298                        }
1299                        XCloseDisplay(backend);
1300                    }
1301                }
1302#endif
1303                printf("    %2d backend %s o%d/%s",i, core(&iinfo),
1304                       iinfo.physicalScreen, iinfo.name);
1305                if (iinfo.physicalId >= 0) printf("/id%d", iinfo.physicalId);
1306#ifdef XINPUT
1307                if (backendname) {
1308                    printf("=%s", backendname);
1309                    free(backendname);
1310                }
1311#endif
1312                break;
1313            }
1314        }
1315        printf("\n");
1316    }
1317    return 1;
1318}
1319
1320#endif /* DMX */
1321
1322/* utilities to manage the list of recognized extensions */
1323
1324
1325typedef int (*ExtensionPrintFunc)(
1326    Display *, const char *
1327);
1328
1329typedef struct {
1330    const char *extname;
1331    ExtensionPrintFunc printfunc;
1332    Bool printit;
1333} ExtensionPrintInfo;
1334
1335static ExtensionPrintInfo known_extensions[] =
1336{
1337#ifdef MITSHM
1338    {"MIT-SHM",	print_mitshm_info, False},
1339#endif /* MITSHM */
1340#ifdef XKB
1341    {XkbName, print_xkb_info, False},
1342#endif /* XKB */
1343#ifdef MULTIBUFFER
1344    {MULTIBUFFER_PROTOCOL_NAME,	print_multibuf_info, False},
1345#endif
1346    {"SHAPE", print_shape_info, False},
1347    {SYNC_NAME, print_sync_info, False},
1348#ifdef XFreeXDGA
1349    {XF86DGANAME, print_dga_info, False},
1350#endif /* XFreeXDGA */
1351#ifdef XF86VIDMODE
1352    {XF86VIDMODENAME, print_XF86VidMode_info, False},
1353#endif /* XF86VIDMODE */
1354#ifdef XF86MISC
1355    {XF86MISCNAME, print_XF86Misc_info, False},
1356#endif /* XF86MISC */
1357    {XTestExtensionName, print_xtest_info, False},
1358    {"DOUBLE-BUFFER", print_dbe_info, False},
1359    {"RECORD", print_record_info, False},
1360#ifdef XINPUT
1361    {INAME, print_xinput_info, False},
1362#endif
1363#ifdef XRENDER
1364    {RENDER_NAME, print_xrender_info, False},
1365#endif
1366#ifdef COMPOSITE
1367    {COMPOSITE_NAME, print_composite_info, False},
1368#endif
1369#ifdef PANORAMIX
1370    {"XINERAMA", print_xinerama_info, False},
1371#endif
1372#ifdef DMX
1373    {"DMX", print_dmx_info, False},
1374#endif
1375    /* add new extensions here */
1376};
1377
1378static const int num_known_extensions = sizeof known_extensions / sizeof known_extensions[0];
1379
1380static void
1381print_known_extensions(FILE *f)
1382{
1383    int i, col;
1384    for (i = 0, col = 6; i < num_known_extensions; i++)
1385    {
1386	int extlen = strlen(known_extensions[i].extname) + 1;
1387
1388	if ((col + extlen) > 79)
1389	{
1390		col = 6;
1391		fprintf(f, "\n     ");
1392	}
1393	fprintf(f, "%s ", known_extensions[i].extname);
1394	col += extlen;
1395    }
1396}
1397
1398static void
1399mark_extension_for_printing(const char *extname)
1400{
1401    int i;
1402
1403    if (strcmp(extname, "all") == 0)
1404    {
1405	for (i = 0; i < num_known_extensions; i++)
1406	    known_extensions[i].printit = True;
1407    }
1408    else
1409    {
1410	for (i = 0; i < num_known_extensions; i++)
1411	{
1412	    if (strcmp(extname, known_extensions[i].extname) == 0)
1413	    {
1414		known_extensions[i].printit = True;
1415		return;
1416	    }
1417	}
1418	printf("%s extension not supported by %s\n", extname, ProgramName);
1419    }
1420}
1421
1422static void
1423print_marked_extensions(Display *dpy)
1424{
1425    int i;
1426    for (i = 0; i < num_known_extensions; i++)
1427    {
1428	if (known_extensions[i].printit)
1429	{
1430	    printf("\n");
1431	    if (! (*known_extensions[i].printfunc)(dpy,
1432					known_extensions[i].extname))
1433	    {
1434		printf("%s extension not supported by server\n",
1435		       known_extensions[i].extname);
1436	    }
1437	}
1438    }
1439}
1440
1441static void _X_NORETURN
1442usage(void)
1443{
1444    fprintf (stderr, "usage:  %s [options]\n%s", ProgramName,
1445             "-display displayname\tserver to query\n"
1446             "-version\t\tprint program version and exit\n"
1447             "-queryExtensions\tprint info returned by XQueryExtension\n"
1448             "-ext all\t\tprint detailed info for all supported extensions\n"
1449             "-ext extension-name\tprint detailed info for extension-name if one of:\n     ");
1450    print_known_extensions(stderr);
1451    fprintf (stderr, "\n");
1452    exit (1);
1453}
1454
1455int
1456main(int argc, char *argv[])
1457{
1458    Display *dpy;			/* X connection */
1459    char *displayname = NULL;		/* server to contact */
1460    int i;				/* temp variable:  iterator */
1461
1462    ProgramName = argv[0];
1463
1464    for (i = 1; i < argc; i++) {
1465	char *arg = argv[i];
1466	size_t len = strlen(arg);
1467
1468	if (!strncmp("-display", arg, len)) {
1469	    if (++i >= argc) usage ();
1470	    displayname = argv[i];
1471	} else if (!strncmp("-queryExtensions", arg, len)) {
1472	    queryExtensions = True;
1473	} else if (!strncmp("-ext", arg, len)) {
1474	    if (++i >= argc) usage ();
1475	    mark_extension_for_printing(argv[i]);
1476        } else if (!strncmp("-version", arg, len)) {
1477            printf("%s\n", PACKAGE_STRING);
1478            exit (0);
1479	} else
1480	    usage ();
1481    }
1482
1483    dpy = XOpenDisplay (displayname);
1484    if (!dpy) {
1485	fprintf (stderr, "%s:  unable to open display \"%s\".\n",
1486		 ProgramName, XDisplayName (displayname));
1487	exit (1);
1488    }
1489
1490    print_display_info (dpy);
1491    for (i = 0; i < ScreenCount (dpy); i++) {
1492	print_screen_info (dpy, i);
1493    }
1494
1495    print_marked_extensions(dpy);
1496
1497    XCloseDisplay (dpy);
1498    exit (0);
1499}
1500