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
144static char *ProgramName;
145static Bool queryExtensions = False;
146
147#if defined(XF86MISC) || defined(XFreeXDGA)
148static int
149silent_errors(_X_UNUSED Display *dpy, _X_UNUSED XErrorEvent *ev)
150{
151    return 0;
152}
153
154static int (*old_handler)(Display *, XErrorEvent *) = NULL;
155#endif
156
157static int print_event_mask(char *buf, int lastcol, int indent, long mask);
158
159static int StrCmp(const void *a, const  void *b)
160{
161    return strcmp(*(const char * const *)a, *(const char * const *)b);
162}
163
164static void
165print_extension_info(Display *dpy)
166{
167    int n = 0;
168    char **extlist = XListExtensions (dpy, &n);
169
170    printf ("number of extensions:    %d\n", n);
171
172    if (extlist) {
173	qsort(extlist, (size_t)n, sizeof(char *), StrCmp);
174
175	if (!queryExtensions) {
176	    for (int i = 0; i < n; i++) {
177		printf ("    %s\n", extlist[i]);
178	    }
179	} else {
180	    xcb_connection_t *xcb_conn = XGetXCBConnection (dpy);
181	    xcb_query_extension_cookie_t *qe_cookies;
182
183	    qe_cookies = calloc((size_t)n, sizeof(xcb_query_extension_cookie_t));
184	    if (!qe_cookies) {
185		perror ("calloc failed to allocate memory for extensions");
186		return;
187	    }
188
189	    /*
190	     * Generate all extension queries at once, so they can be
191	     * sent to the xserver in a single batch
192	     */
193	    for (int i = 0; i < n; i++) {
194		qe_cookies[i] = xcb_query_extension (xcb_conn,
195						     (uint16_t)strlen(extlist[i]),
196						     extlist[i]);
197	    }
198
199	    /*
200	     * Start processing replies as they come in.
201	     * The first call will flush the queue to the server, then
202	     * each one will wait, if needed, for its reply.
203	     */
204	    for (int i = 0; i < n; i++) {
205		xcb_query_extension_reply_t *rep
206		    = xcb_query_extension_reply(xcb_conn, qe_cookies[i], NULL);
207
208		printf ("    %s  (opcode: %d", extlist[i], rep->major_opcode);
209		if (rep->first_event)
210		    printf (", base event: %d", rep->first_event);
211		if (rep->first_error)
212		    printf (", base error: %d", rep->first_error);
213		printf (")\n");
214
215		free (rep);
216	    }
217	    free (qe_cookies);
218	}
219	/* do not free, Xlib can depend on contents being unaltered */
220	/* XFreeExtensionList (extlist); */
221    }
222}
223
224static void
225print_display_info(Display *dpy)
226{
227    char dummybuf[40];
228    const char *cp;
229    int minkeycode, maxkeycode;
230    int n;
231    long req_size;
232    XPixmapFormatValues *pmf;
233    Window focuswin;
234    int focusrevert;
235
236    printf ("name of display:    %s\n", DisplayString (dpy));
237    printf ("version number:    %d.%d\n",
238	    ProtocolVersion (dpy), ProtocolRevision (dpy));
239    printf ("vendor string:    %s\n", ServerVendor (dpy));
240    printf ("vendor release number:    %d\n", VendorRelease (dpy));
241
242    if (strstr(ServerVendor (dpy), "X.Org")) {
243	int vendrel = VendorRelease(dpy);
244
245	printf("X.Org version: ");
246        if (vendrel >= 12100000) {
247            vendrel -= 10000000; /* Y2.1K compliant */
248            printf("%d.%d",
249	       (vendrel /   100000) % 100,
250	       (vendrel /     1000) % 100);
251        } else {
252            printf("%d.%d.%d", vendrel / 10000000,
253                   (vendrel /   100000) % 100,
254                   (vendrel /     1000) % 100);
255        }
256        if (vendrel % 1000)
257            printf(".%d", vendrel % 1000);
258        printf("\n");
259    }
260    else if (strstr(ServerVendor (dpy), "XFree86")) {
261	int vendrel = VendorRelease(dpy);
262
263	printf("XFree86 version: ");
264	if (vendrel < 336) {
265	    /*
266	     * vendrel was set incorrectly for 3.3.4 and 3.3.5, so handle
267	     * those cases here.
268	     */
269	    printf("%d.%d.%d", vendrel / 100,
270			      (vendrel / 10) % 10,
271			       vendrel       % 10);
272	} else if (vendrel < 3900) {
273	    /* 3.3.x versions, other than the exceptions handled above */
274	    printf("%d.%d", vendrel / 1000,
275			   (vendrel /  100) % 10);
276	    if (((vendrel / 10) % 10) || (vendrel % 10)) {
277		printf(".%d", (vendrel / 10) % 10);
278		if (vendrel % 10) {
279		    printf(".%d", vendrel % 10);
280		}
281	    }
282	} else if (vendrel < 40000000) {
283	    /* 4.0.x versions */
284	    printf("%d.%d", vendrel / 1000,
285			   (vendrel /   10) % 10);
286	    if (vendrel % 10) {
287		printf(".%d", vendrel % 10);
288	    }
289	} else {
290	    /* post-4.0.x */
291	    printf("%d.%d.%d", vendrel / 10000000,
292			      (vendrel /   100000) % 100,
293			      (vendrel /     1000) % 100);
294	    if (vendrel % 1000) {
295		printf(".%d", vendrel % 1000);
296	    }
297	}
298	printf("\n");
299    }
300
301    if (strstr(ServerVendor (dpy), "DMX")) {
302	int vendrel = VendorRelease(dpy);
303        int major, minor, year, month, day;
304
305        major    = vendrel / 100000000;
306        vendrel -= major   * 100000000;
307        minor    = vendrel /   1000000;
308        vendrel -= minor   *   1000000;
309        year     = vendrel /     10000;
310        vendrel -= year    *     10000;
311        month    = vendrel /       100;
312        vendrel -= month   *       100;
313        day      = vendrel;
314
315                                /* Add other epoch tests here */
316        if (major > 0 && minor > 0) year += 2000;
317
318                                /* Do some sanity tests in case there is
319                                 * another server with the same vendor
320                                 * string.  That server could easily use
321                                 * values < 100000000, which would have
322                                 * the effect of keeping our major
323                                 * number 0. */
324        if (major > 0 && major <= 20
325            && minor >= 0 && minor <= 99
326            && year >= 2000
327            && month >= 1 && month <= 12
328            && day >= 1 && day <= 31)
329            printf("DMX version: %d.%d.%04d%02d%02d\n",
330                   major, minor, year, month, day);
331    }
332
333    req_size = XExtendedMaxRequestSize (dpy);
334    if (!req_size) req_size = XMaxRequestSize (dpy);
335    printf ("maximum request size:  %ld bytes\n", req_size * 4);
336    printf ("motion buffer size:  %ld\n", XDisplayMotionBufferSize (dpy));
337
338    switch (BitmapBitOrder (dpy)) {
339      case LSBFirst:    cp = "LSBFirst"; break;
340      case MSBFirst:    cp = "MSBFirst"; break;
341      default:
342	snprintf (dummybuf, sizeof(dummybuf),
343                  "unknown order %d", BitmapBitOrder (dpy));
344	cp = dummybuf;
345	break;
346    }
347    printf ("bitmap unit, bit order, padding:    %d, %s, %d\n",
348	    BitmapUnit (dpy), cp, BitmapPad (dpy));
349
350    switch (ImageByteOrder (dpy)) {
351      case LSBFirst:    cp = "LSBFirst"; break;
352      case MSBFirst:    cp = "MSBFirst"; break;
353      default:
354	snprintf (dummybuf, sizeof(dummybuf),
355                  "unknown order %d", ImageByteOrder (dpy));
356	cp = dummybuf;
357	break;
358    }
359    printf ("image byte order:    %s\n", cp);
360
361    pmf = XListPixmapFormats (dpy, &n);
362    printf ("number of supported pixmap formats:    %d\n", n);
363    if (pmf) {
364	printf ("supported pixmap formats:\n");
365	for (int i = 0; i < n; i++) {
366	    printf ("    depth %d, bits_per_pixel %d, scanline_pad %d\n",
367		    pmf[i].depth, pmf[i].bits_per_pixel, pmf[i].scanline_pad);
368	}
369	XFree ((char *) pmf);
370    }
371
372
373    /*
374     * when we get interfaces to the PixmapFormat stuff, insert code here
375     */
376
377    XDisplayKeycodes (dpy, &minkeycode, &maxkeycode);
378    printf ("keycode range:    minimum %d, maximum %d\n",
379	    minkeycode, maxkeycode);
380
381    XGetInputFocus (dpy, &focuswin, &focusrevert);
382    printf ("focus:  ");
383    switch (focuswin) {
384      case PointerRoot:
385	printf ("PointerRoot\n");
386	break;
387      case None:
388	printf ("None\n");
389	break;
390      default:
391	printf("window 0x%lx, revert to ", focuswin);
392	switch (focusrevert) {
393	  case RevertToParent:
394	    printf ("Parent\n");
395	    break;
396	  case RevertToNone:
397	    printf ("None\n");
398	    break;
399	  case RevertToPointerRoot:
400	    printf ("PointerRoot\n");
401	    break;
402	  default:			/* should not happen */
403	    printf ("%d\n", focusrevert);
404	    break;
405	}
406	break;
407    }
408
409    print_extension_info (dpy);
410
411    printf ("default screen number:    %d\n", DefaultScreen (dpy));
412    printf ("number of screens:    %d\n", ScreenCount (dpy));
413}
414
415static void
416print_visual_info(XVisualInfo *vip)
417{
418    char errorbuf[40];			/* for sprintfing into */
419    const char *class = NULL;		/* for printing */
420
421    switch (vip->class) {
422      case StaticGray:    class = "StaticGray"; break;
423      case GrayScale:    class = "GrayScale"; break;
424      case StaticColor:    class = "StaticColor"; break;
425      case PseudoColor:    class = "PseudoColor"; break;
426      case TrueColor:    class = "TrueColor"; break;
427      case DirectColor:    class = "DirectColor"; break;
428      default:
429	snprintf (errorbuf, sizeof(errorbuf), "unknown class %d", vip->class);
430	class = errorbuf;
431	break;
432    }
433
434    printf ("  visual:\n");
435    printf ("    visual id:    0x%lx\n", vip->visualid);
436    printf ("    class:    %s\n", class);
437    printf ("    depth:    %d plane%s\n", vip->depth,
438	    vip->depth == 1 ? "" : "s");
439    if (vip->class == TrueColor || vip->class == DirectColor)
440	printf ("    available colormap entries:    %d per subfield\n",
441		vip->colormap_size);
442    else
443	printf ("    available colormap entries:    %d\n",
444		vip->colormap_size);
445    printf ("    red, green, blue masks:    0x%lx, 0x%lx, 0x%lx\n",
446	    vip->red_mask, vip->green_mask, vip->blue_mask);
447    printf ("    significant bits in color specification:    %d bits\n",
448	    vip->bits_per_rgb);
449}
450
451static void
452print_screen_info(Display *dpy, int scr)
453{
454    Screen *s = ScreenOfDisplay (dpy, scr);  /* opaque structure */
455    XVisualInfo viproto;		/* fill in for getting info */
456    XVisualInfo *vip;			/* returned info */
457    int nvi;				/* number of elements returned */
458    char eventbuf[80];			/* want 79 chars per line + nul */
459    static const char *yes = "YES", *no = "NO", *when = "WHEN MAPPED";
460    double xres, yres;
461    int ndepths = 0, *depths = NULL;
462    unsigned int width, height;
463
464    /*
465     * there are 2.54 centimeters to an inch; so there are 25.4 millimeters.
466     *
467     *     dpi = N pixels / (M millimeters / (25.4 millimeters / 1 inch))
468     *         = N pixels / (M inch / 25.4)
469     *         = N * 25.4 pixels / M inch
470     */
471
472    xres = ((((double) DisplayWidth(dpy,scr)) * 25.4) /
473	    ((double) DisplayWidthMM(dpy,scr)));
474    yres = ((((double) DisplayHeight(dpy,scr)) * 25.4) /
475	    ((double) DisplayHeightMM(dpy,scr)));
476
477    printf ("\n");
478    printf ("screen #%d:\n", scr);
479    printf ("  dimensions:    %dx%d pixels (%dx%d millimeters)\n",
480	    XDisplayWidth (dpy, scr),  XDisplayHeight (dpy, scr),
481	    XDisplayWidthMM(dpy, scr), XDisplayHeightMM (dpy, scr));
482    printf ("  resolution:    %dx%d dots per inch\n",
483	    (int) (xres + 0.5), (int) (yres + 0.5));
484    depths = XListDepths (dpy, scr, &ndepths);
485    if (!depths) ndepths = 0;
486    printf ("  depths (%d):    ", ndepths);
487    for (int i = 0; i < ndepths; i++) {
488	printf ("%d", depths[i]);
489	if (i < ndepths - 1) {
490	    putchar (',');
491	    putchar (' ');
492	}
493    }
494    putchar ('\n');
495    if (depths) XFree ((char *) depths);
496    printf ("  root window id:    0x%lx\n", RootWindow (dpy, scr));
497    printf ("  depth of root window:    %d plane%s\n",
498	    DisplayPlanes (dpy, scr),
499	    DisplayPlanes (dpy, scr) == 1 ? "" : "s");
500    printf ("  number of colormaps:    minimum %d, maximum %d\n",
501	    MinCmapsOfScreen(s), MaxCmapsOfScreen(s));
502    printf ("  default colormap:    0x%lx\n", DefaultColormap (dpy, scr));
503    printf ("  default number of colormap cells:    %d\n",
504	    DisplayCells (dpy, scr));
505    printf ("  preallocated pixels:    black %ld, white %ld\n",
506	    BlackPixel (dpy, scr), WhitePixel (dpy, scr));
507    printf ("  options:    backing-store %s, save-unders %s\n",
508	    (DoesBackingStore (s) == NotUseful) ? no :
509	    ((DoesBackingStore (s) == Always) ? yes : when),
510	    DoesSaveUnders (s) ? yes : no);
511    XQueryBestSize (dpy, CursorShape, RootWindow (dpy, scr), 65535, 65535,
512		    &width, &height);
513    if (width == 65535 && height == 65535)
514	printf ("  largest cursor:    unlimited\n");
515    else
516	printf ("  largest cursor:    %dx%d\n", width, height);
517    printf ("  current input event mask:    0x%lx\n", EventMaskOfScreen (s));
518    (void) print_event_mask (eventbuf, 79, 4, EventMaskOfScreen (s));
519
520    nvi = 0;
521    viproto.screen = scr;
522    vip = XGetVisualInfo (dpy, VisualScreenMask, &viproto, &nvi);
523    printf ("  number of visuals:    %d\n", nvi);
524    printf ("  default visual id:  0x%lx\n",
525	    XVisualIDFromVisual (DefaultVisual (dpy, scr)));
526    for (int i = 0; i < nvi; i++) {
527	print_visual_info (vip+i);
528    }
529    if (vip) XFree ((char *) vip);
530}
531
532/*
533 * The following routine prints out an event mask, wrapping events at nice
534 * boundaries.
535 */
536
537#define MASK_NAME_WIDTH 25
538
539static struct _event_table {
540    const char *name;
541    long value;
542} event_table[] = {
543    { "KeyPressMask             ", KeyPressMask },
544    { "KeyReleaseMask           ", KeyReleaseMask },
545    { "ButtonPressMask          ", ButtonPressMask },
546    { "ButtonReleaseMask        ", ButtonReleaseMask },
547    { "EnterWindowMask          ", EnterWindowMask },
548    { "LeaveWindowMask          ", LeaveWindowMask },
549    { "PointerMotionMask        ", PointerMotionMask },
550    { "PointerMotionHintMask    ", PointerMotionHintMask },
551    { "Button1MotionMask        ", Button1MotionMask },
552    { "Button2MotionMask        ", Button2MotionMask },
553    { "Button3MotionMask        ", Button3MotionMask },
554    { "Button4MotionMask        ", Button4MotionMask },
555    { "Button5MotionMask        ", Button5MotionMask },
556    { "ButtonMotionMask         ", ButtonMotionMask },
557    { "KeymapStateMask          ", KeymapStateMask },
558    { "ExposureMask             ", ExposureMask },
559    { "VisibilityChangeMask     ", VisibilityChangeMask },
560    { "StructureNotifyMask      ", StructureNotifyMask },
561    { "ResizeRedirectMask       ", ResizeRedirectMask },
562    { "SubstructureNotifyMask   ", SubstructureNotifyMask },
563    { "SubstructureRedirectMask ", SubstructureRedirectMask },
564    { "FocusChangeMask          ", FocusChangeMask },
565    { "PropertyChangeMask       ", PropertyChangeMask },
566    { "ColormapChangeMask       ", ColormapChangeMask },
567    { "OwnerGrabButtonMask      ", OwnerGrabButtonMask },
568    { NULL, 0 }};
569
570static int
571print_event_mask(char *buf,     /* string to write into */
572                 int lastcol,   /* strlen(buf)+1 */
573                 int indent,    /* amount by which to indent */
574                 long mask)     /* event mask */
575{
576    int len;
577    int bitsfound = 0;
578
579    buf[0] = buf[lastcol] = '\0';	/* just in case */
580
581#define INDENT() do { len = indent; memset(buf, ' ', indent); } while (0)
582
583    INDENT ();
584
585    for (struct _event_table *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#define MULTIBUF_FMT "    visual id, max buffers, depth:    0x%lx, %d, %d\n"
626    int majorrev, minorrev;
627
628    if (!XmbufGetVersion(dpy, &majorrev, &minorrev))
629	return 0;
630
631    print_standard_extension_info(dpy, extname, majorrev, minorrev);
632
633    for (int i = 0; i < ScreenCount (dpy); i++)
634    {
635        int nmono, nstereo;		/* count */
636        XmbufBufferInfo *mono_info = NULL, *stereo_info = NULL; /* arrays */
637        const int scr = 0;
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 (int 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 (int 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;
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 (int 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	   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;
785    XF86VidModeMonitor monitor;
786
787    if (!XF86VidModeQueryVersion(dpy, &majorrev, &minorrev))
788	return 0;
789    print_standard_extension_info(dpy, extname, majorrev, minorrev);
790
791    if (XF86VidModeGetMonitor(dpy, DefaultScreen(dpy), &monitor)) {
792	printf("  Monitor Information:\n");
793	printf("    Vendor: %s, Model: %s\n",
794	       monitor.vendor == NULL ? "" : monitor.vendor,
795	       monitor.model == NULL ? "" : monitor.model);
796	printf("    Num hsync: %d, Num vsync: %d\n",
797	       monitor.nhsync, monitor.nvsync);
798	for (int i = 0; i < monitor.nhsync; i++) {
799	    printf("    hsync range %d: %6.2f - %6.2f\n", i,
800		   monitor.hsync[i].lo, monitor.hsync[i].hi);
801	}
802	for (int i = 0; i < monitor.nvsync; i++) {
803	    printf("    vsync range %d: %6.2f - %6.2f\n", i,
804		   monitor.vsync[i].lo, monitor.vsync[i].hi);
805	}
806	XFree(monitor.vendor);
807	XFree(monitor.model);
808	XFree(monitor.hsync);
809	XFree(monitor.vsync);
810    } else {
811	printf("  Monitor Information not available\n");
812    }
813
814    if ((majorrev > 0) || (majorrev == 0 && minorrev > 5)) {
815      int modecount, dotclock;
816      XF86VidModeModeLine modeline;
817      XF86VidModeModeInfo **modelines;
818
819      if (XF86VidModeGetAllModeLines(dpy, DefaultScreen(dpy), &modecount,
820				     &modelines)) {
821	  printf("  Available Video Mode Settings:\n");
822	  printf("     Clock   Hdsp Hbeg Hend Httl   Vdsp Vbeg Vend Vttl  Flags\n");
823	  for (int i = 0; i < modecount; i++) {
824	      print_XF86VidMode_modeline
825		  (modelines[i]->dotclock, modelines[i]->hdisplay,
826		   modelines[i]->hsyncstart, modelines[i]->hsyncend,
827		   modelines[i]->htotal, modelines[i]->vdisplay,
828		   modelines[i]->vsyncstart, modelines[i]->vsyncend,
829		   modelines[i]->vtotal, modelines[i]->flags);
830	  }
831	  XFree(modelines);
832      } else {
833	  printf("  Available Video Mode Settings not available\n");
834      }
835
836      if (XF86VidModeGetModeLine(dpy, DefaultScreen(dpy),
837				 &dotclock, &modeline)) {
838	  printf("  Current Video Mode Setting:\n");
839	  print_XF86VidMode_modeline(dotclock,
840				     modeline.hdisplay, modeline.hsyncstart,
841				     modeline.hsyncend, modeline.htotal,
842				     modeline.vdisplay, modeline.vsyncstart,
843				     modeline.vsyncend, modeline.vtotal,
844				     modeline.flags);
845      } else {
846	  printf("  Current Video Mode Setting not available\n");
847      }
848    }
849
850    return 1;
851}
852#endif
853
854#ifdef XF86MISC
855
856static const char *kbdtable[] = {
857		     "Unknown", "84-key", "101-key", "Other", "Xqueue" };
858static const char *msetable[] = {
859		     "None", "Microsoft", "MouseSystems", "MMSeries",
860		     "Logitech", "BusMouse", "Mouseman", "PS/2", "MMHitTab",
861		     "GlidePoint", "IntelliMouse", "ThinkingMouse",
862		     "IMPS/2", "ThinkingMousePS/2", "MouseManPlusPS/2",
863		     "GlidePointPS/2", "NetMousePS/2", "NetScrollPS/2",
864		     "SysMouse", "Auto" };
865static const char *flgtable[] = {
866		     "None", "ClearDTR", "ClearRTS", "ClearDTR and ClearRTS" };
867
868static int
869print_XF86Misc_info(Display *dpy, const char *extname)
870{
871    int majorrev, minorrev;
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      XF86MiscKbdSettings kbdinfo;
881      XF86MiscMouseSettings mouseinfo;
882
883      if (!XF86MiscGetKbdSettings(dpy, &kbdinfo))
884	return 0;
885      printf("  Keyboard Settings-    Type: %s, Rate: %d, Delay: %d, ServerNumLock: %s\n",
886	kbdtable[kbdinfo.type], kbdinfo.rate, kbdinfo.delay,
887	(kbdinfo.servnumlock? "yes": "no"));
888
889      if (!XF86MiscGetMouseSettings(dpy, &mouseinfo))
890	return 0;
891      printf("  Mouse Settings-       Device: %s, Type: ",
892	strlen(mouseinfo.device) == 0 ? "None": mouseinfo.device);
893      XFree(mouseinfo.device);
894      if (mouseinfo.type == MTYPE_XQUEUE)
895	printf("Xqueue\n");
896      else if (mouseinfo.type == MTYPE_OSMOUSE)
897	printf("OSMouse\n");
898      else if (mouseinfo.type <= MTYPE_AUTOMOUSE)
899	printf("%s\n", msetable[mouseinfo.type+1]);
900      else
901	printf("Unknown\n");
902      printf("                        BaudRate: %d, SampleRate: %d, Resolution: %d\n",
903	mouseinfo.baudrate, mouseinfo.samplerate, mouseinfo.resolution);
904      printf("                        Emulate3Buttons: %s, Emulate3Timeout: %d ms\n",
905	mouseinfo.emulate3buttons? "yes": "no", mouseinfo.emulate3timeout);
906      printf("                        ChordMiddle: %s, Flags: %s\n",
907	mouseinfo.chordmiddle? "yes": "no",
908	flgtable[(mouseinfo.flags & MF_CLEAR_DTR? 1: 0)
909		+(mouseinfo.flags & MF_CLEAR_RTS? 1: 0)] );
910      printf("                        Buttons: %d\n", mouseinfo.buttons);
911    }
912
913    XSetErrorHandler(old_handler);
914
915    return 1;
916}
917#endif
918
919#ifdef MITSHM
920static int
921print_mitshm_info(Display *dpy, const char *extname)
922{
923    int majorrev, minorrev;
924    Bool sharedPixmaps;
925
926    if (!XShmQueryVersion(dpy, &majorrev, &minorrev, &sharedPixmaps))
927	return 0;
928    print_standard_extension_info(dpy, extname, majorrev, minorrev);
929    printf("  shared pixmaps: ");
930    if (sharedPixmaps)
931    {
932	int format = XShmPixmapFormat(dpy);
933	printf("yes, format: %d\n", format);
934    }
935    else
936    {
937	printf("no\n");
938    }
939    return 1;
940}
941#endif /* MITSHM */
942
943#ifdef XKB
944static int
945print_xkb_info(Display *dpy, const char *extname)
946{
947    int opcode, eventbase, errorbase, majorrev, minorrev;
948
949    if (!XkbQueryExtension(dpy, &opcode, &eventbase, &errorbase,
950			   &majorrev, &minorrev)) {
951        return 0;
952    }
953    printf("%s version %d.%d ", extname, majorrev, minorrev);
954
955    printf ("opcode: %d", opcode);
956    if (eventbase)
957	printf (", base event: %d", eventbase);
958    if (errorbase)
959	printf (", base error: %d", errorbase);
960    printf("\n");
961
962    return 1;
963}
964#endif
965
966static int
967print_dbe_info(Display *dpy, const char *extname)
968{
969    int majorrev, minorrev;
970    XdbeScreenVisualInfo *svi;
971    int numscreens = 0;
972
973    if (!XdbeQueryExtension(dpy, &majorrev, &minorrev))
974	return 0;
975
976    print_standard_extension_info(dpy, extname, majorrev, minorrev);
977    svi = XdbeGetVisualInfo(dpy, (Drawable *)NULL, &numscreens);
978    for (int iscrn = 0; iscrn < numscreens; iscrn++)
979    {
980	printf("  Double-buffered visuals on screen %d\n", iscrn);
981	for (int ivis = 0; ivis < svi[iscrn].count; ivis++)
982	{
983	    printf("    visual id 0x%lx  depth %d  perflevel %d\n",
984		   svi[iscrn].visinfo[ivis].visual,
985		   svi[iscrn].visinfo[ivis].depth,
986		   svi[iscrn].visinfo[ivis].perflevel);
987	}
988    }
989    XdbeFreeVisualInfo(svi);
990    return 1;
991}
992
993static int
994print_record_info(Display *dpy, const char *extname)
995{
996    int majorrev, minorrev;
997
998    if (!XRecordQueryVersion(dpy, &majorrev, &minorrev))
999	return 0;
1000    print_standard_extension_info(dpy, extname, majorrev, minorrev);
1001    return 1;
1002}
1003
1004#ifdef XINPUT
1005static int
1006print_xinput_info(Display *dpy, const char *extname)
1007{
1008  int           loop, num_extensions;
1009  char          **extensions;
1010  XExtensionVersion *ext;
1011
1012  ext = XGetExtensionVersion(dpy, extname);
1013
1014  if (!ext || (ext == (XExtensionVersion*) NoSuchExtension))
1015      return 0;
1016
1017  print_standard_extension_info(dpy, extname, ext->major_version,
1018				ext->minor_version);
1019  XFree(ext);
1020
1021  extensions = XListExtensions(dpy, &num_extensions);
1022  for (loop = 0; loop < num_extensions &&
1023         (strcmp(extensions[loop], extname) != 0); loop++);
1024  XFreeExtensionList(extensions);
1025  if (loop != num_extensions) {
1026      int           num_devices;
1027      XDeviceInfo   *devices;
1028
1029      printf("  Extended devices :\n");
1030      devices = XListInputDevices(dpy, &num_devices);
1031      for(loop=0; loop<num_devices; loop++) {
1032	  printf("	\"%s\"	[", devices[loop].name ? devices[loop].name : "<noname>");
1033	  switch(devices[loop].use) {
1034	  case IsXPointer:
1035	      printf("XPointer]\n");
1036	      break;
1037	  case IsXKeyboard:
1038	      printf("XKeyboard]\n");
1039	      break;
1040	  case IsXExtensionDevice:
1041	      printf("XExtensionDevice]\n");
1042	      break;
1043#ifdef IsXExtensionKeyboard
1044	  case IsXExtensionKeyboard:
1045	      printf("XExtensionKeyboard]\n");
1046	      break;
1047#endif
1048#ifdef IsXExtensionPointer
1049	  case IsXExtensionPointer:
1050	      printf("XExtensionPointer]\n");
1051	      break;
1052#endif
1053	  default:
1054	      printf("invalid value]\n");
1055	      break;
1056	  }
1057        }
1058      XFreeDeviceList(devices);
1059      return 1;
1060    }
1061  else
1062      return 0;
1063}
1064#endif
1065
1066#ifdef XRENDER
1067static int
1068print_xrender_info(Display *dpy, const char *extname)
1069{
1070  int		    loop, num_extensions;
1071  char		    **extensions;
1072  int		    major, minor;
1073
1074  if (!XRenderQueryVersion (dpy, &major, &minor))
1075    return 0;
1076
1077  print_standard_extension_info(dpy, extname, major, minor);
1078
1079  extensions = XListExtensions(dpy, &num_extensions);
1080  for (loop = 0; loop < num_extensions &&
1081         (strcmp(extensions[loop], extname) != 0); loop++);
1082  XFreeExtensionList(extensions);
1083  if (loop != num_extensions) {
1084    XRenderPictFormat *pictform;
1085
1086    printf ("  Render formats :\n");
1087    for (int count = 0; (pictform = XRenderFindFormat (dpy, 0, NULL, count));
1088         count++)
1089    {
1090      printf  ("  pict format:\n");
1091      printf  ("\tformat id:    0x%lx\n", pictform->id);
1092      printf  ("\ttype:         %s\n",
1093	     pictform->type == PictTypeIndexed ? "Indexed" : "Direct");
1094      printf  ("\tdepth:        %d\n", pictform->depth);
1095      if (pictform->type == PictTypeDirect) {
1096	printf("\talpha:        %2d mask 0x%x\n", pictform->direct.alpha, pictform->direct.alphaMask);
1097	printf("\tred:          %2d mask 0x%x\n", pictform->direct.red, pictform->direct.redMask);
1098	printf("\tgreen:        %2d mask 0x%x\n", pictform->direct.green, pictform->direct.greenMask);
1099	printf("\tblue:         %2d mask 0x%x\n", pictform->direct.blue, pictform->direct.blueMask);
1100      }
1101      else
1102	printf("\tcolormap      0x%lx\n", pictform->colormap);
1103    }
1104    printf ("  Screen formats :\n");
1105    for (int i = 0; i < ScreenCount (dpy); i++) {
1106      int	     nvi;		/* number of elements returned */
1107      XVisualInfo    viproto;		/* fill in for getting info */
1108      XVisualInfo    *vip;		/* returned info */
1109      int 	     ndepths = 0, *depths = NULL;
1110#if RENDER_MAJOR > 0 || RENDER_MINOR >= 6
1111      XFilters	    *filters;
1112#endif
1113
1114      nvi = 0;
1115      viproto.screen = i;
1116      vip = XGetVisualInfo (dpy, VisualScreenMask, &viproto, &nvi);
1117      printf ("    Screen %d", i);
1118#if RENDER_MAJOR > 0 || RENDER_MINOR >= 6
1119      switch (XRenderQuerySubpixelOrder (dpy, i)) {
1120      case SubPixelUnknown: printf (" (sub-pixel order Unknown)"); break;
1121      case SubPixelHorizontalRGB: printf (" (sub-pixel order Horizontal RGB)"); break;
1122      case SubPixelHorizontalBGR: printf (" (sub-pixel order Horizontal BGR)"); break;
1123      case SubPixelVerticalRGB: printf (" (sub-pixel order Vertical RGB)"); break;
1124      case SubPixelVerticalBGR: printf (" (sub-pixel order Vertical BGR)"); break;
1125      case SubPixelNone: printf (" (sub-pixel order None)"); break;
1126      }
1127      printf ("\n");
1128      filters = XRenderQueryFilters (dpy, RootWindow (dpy, i));
1129      if (filters)
1130      {
1131	printf ("      filters: ");
1132	for (int f = 0; f < filters->nfilter; f++)
1133	{
1134	  printf ("%s", filters->filter[f]);
1135	  if (f < filters->nalias && filters->alias[f] != FilterAliasNone)
1136	    printf ("(%s)", filters->filter[filters->alias[f]]);
1137	  if (f < filters->nfilter - 1)
1138	    printf (", ");
1139	}
1140	XFree (filters);
1141      }
1142#endif
1143      printf ("\n");
1144      for (int j = 0; j < nvi; j++)
1145      {
1146	printf  ("      visual format:\n");
1147	printf  ("        visual id:      0x%lx\n", vip[j].visualid);
1148	pictform = XRenderFindVisualFormat (dpy, vip[j].visual);
1149	if (pictform)
1150	  printf("        pict format id: 0x%lx\n", pictform->id);
1151	else
1152	  printf("        pict format id: None\n");
1153      }
1154      if (vip) XFree ((char *) vip);
1155      depths = XListDepths (dpy, i, &ndepths);
1156      if (!depths) ndepths = 0;
1157      for (int j = 0; j < ndepths; j++)
1158      {
1159	XRenderPictFormat templ;
1160
1161	templ.depth = depths[j];
1162	printf  ("     depth formats:\n");
1163	printf  ("       depth           %d\n", depths[j]);
1164	for (int count = 0;
1165             (pictform = XRenderFindFormat (dpy, PictFormatDepth, &templ, count));
1166             count++) {
1167	  printf("       pict format id: 0x%lx\n", pictform->id);
1168        }
1169      }
1170      if (depths) XFree (depths);
1171    }
1172    return 1;
1173  }
1174  else
1175    return 0;
1176}
1177#endif /* XRENDER */
1178
1179#ifdef COMPOSITE
1180static int
1181print_composite_info(Display *dpy, const char *extname)
1182{
1183    int majorrev, minorrev, foo;
1184
1185    if (!XCompositeQueryExtension(dpy, &foo, &foo))
1186	return 0;
1187    if (!XCompositeQueryVersion(dpy, &majorrev, &minorrev))
1188	return 0;
1189    print_standard_extension_info(dpy, extname, majorrev, minorrev);
1190    return 1;
1191}
1192#endif
1193
1194#ifdef PANORAMIX
1195
1196static int
1197print_xinerama_info(Display *dpy, const char *extname)
1198{
1199  int              majorrev, minorrev;
1200
1201  if (!XineramaQueryVersion (dpy, &majorrev, &minorrev))
1202    return 0;
1203
1204  print_standard_extension_info(dpy, extname, majorrev, minorrev);
1205
1206  if (!XineramaIsActive(dpy)) {
1207    printf("  Xinerama is inactive.\n");
1208  } else {
1209    int count = 0;
1210    XineramaScreenInfo *xineramaScreens = XineramaQueryScreens(dpy, &count);
1211
1212    for (int i = 0; i < count; i++) {
1213      XineramaScreenInfo *xs = &xineramaScreens[i];
1214      printf("  head #%d: %dx%d @ %d,%d\n", xs->screen_number,
1215             xs->width, xs->height, xs->x_org, xs->y_org);
1216    }
1217
1218    XFree(xineramaScreens);
1219  }
1220
1221  return 1;
1222}
1223
1224#endif /* PANORAMIX */
1225
1226#ifdef DMX
1227static const char *core(DMXInputAttributes *iinfo)
1228{
1229    if (iinfo->isCore)         return "core";
1230    else if (iinfo->sendsCore) return "extension (sends core)";
1231    else                       return "extension";
1232}
1233
1234static int print_dmx_info(Display *dpy, const char *extname)
1235{
1236    int                  event_base, error_base;
1237    int                  major_version, minor_version, patch_version;
1238    int                  count;
1239
1240    if (!DMXQueryExtension(dpy, &event_base, &error_base)
1241        || !DMXQueryVersion(dpy, &major_version, &minor_version,
1242                            &patch_version)) return 0;
1243    print_standard_extension_info(dpy, extname, major_version, minor_version);
1244    printf("  Version stamp: %d\n", patch_version);
1245
1246    if (!DMXGetScreenCount(dpy, &count)) return 1;
1247    printf("  Screen count: %d\n", count);
1248    for (int i = 0; i < count; i++) {
1249        DMXScreenAttributes  sinfo;
1250
1251        if (DMXGetScreenAttributes(dpy, i, &sinfo)) {
1252            printf("    %2d %s %ux%u+%d+%d %d @%dx%d\n",
1253                   i, sinfo.displayName,
1254                   sinfo.screenWindowWidth, sinfo.screenWindowHeight,
1255                   sinfo.screenWindowXoffset, sinfo.screenWindowYoffset,
1256                   sinfo.logicalScreen,
1257                   sinfo.rootWindowXorigin, sinfo.rootWindowYorigin);
1258        }
1259    }
1260
1261    if (major_version != 1
1262        || minor_version < 1
1263        || !DMXGetInputCount(dpy, &count))
1264        return 1;
1265
1266    printf("  Input count = %d\n", count);
1267    for (int i = 0; i < count; i++) {
1268        DMXInputAttributes   iinfo;
1269#ifdef XINPUT
1270        Display *backend;
1271        char    *backendname = NULL;
1272#endif
1273        if (DMXGetInputAttributes(dpy, i, &iinfo)) {
1274            switch (iinfo.inputType) {
1275            case DMXLocalInputType:
1276                printf("    %2d local %s", i, core(&iinfo));
1277                break;
1278            case DMXConsoleInputType:
1279                printf("    %2d console %s %s", i, core(&iinfo),
1280                       iinfo.name);
1281                break;
1282            case DMXBackendInputType:
1283#ifdef XINPUT
1284                if (iinfo.physicalId >= 0) {
1285                    if ((backend = XOpenDisplay(iinfo.name))) {
1286                        XExtensionVersion *ext
1287                            = XGetExtensionVersion(backend, INAME);
1288                        if (ext
1289                            && ext != (XExtensionVersion *)NoSuchExtension) {
1290
1291                            int         dcount;
1292                            XDeviceInfo *devInfo = XListInputDevices(backend,
1293                                                                     &dcount);
1294                            if (devInfo) {
1295                                for (int d = 0; d < dcount; d++) {
1296                                    if ((unsigned)iinfo.physicalId
1297                                        == devInfo[d].id
1298                                        && devInfo[d].name) {
1299                                        backendname = strdup(devInfo[d].name);
1300                                        break;
1301                                    }
1302                                }
1303                                XFreeDeviceList(devInfo);
1304                            }
1305                        }
1306                        XCloseDisplay(backend);
1307                    }
1308                }
1309#endif
1310                printf("    %2d backend %s o%d/%s",i, core(&iinfo),
1311                       iinfo.physicalScreen, iinfo.name);
1312                if (iinfo.physicalId >= 0) printf("/id%d", iinfo.physicalId);
1313#ifdef XINPUT
1314                if (backendname) {
1315                    printf("=%s", backendname);
1316                    free(backendname);
1317                }
1318#endif
1319                break;
1320            }
1321        }
1322        printf("\n");
1323    }
1324    return 1;
1325}
1326
1327#endif /* DMX */
1328
1329/* utilities to manage the list of recognized extensions */
1330
1331
1332typedef int (*ExtensionPrintFunc)(
1333    Display *, const char *
1334);
1335
1336typedef struct {
1337    const char *extname;
1338    ExtensionPrintFunc printfunc;
1339    Bool printit;
1340} ExtensionPrintInfo;
1341
1342static ExtensionPrintInfo known_extensions[] =
1343{
1344#ifdef MITSHM
1345    {"MIT-SHM",	print_mitshm_info, False},
1346#endif /* MITSHM */
1347#ifdef XKB
1348    {XkbName, print_xkb_info, False},
1349#endif /* XKB */
1350#ifdef MULTIBUFFER
1351    {MULTIBUFFER_PROTOCOL_NAME,	print_multibuf_info, False},
1352#endif
1353    {"SHAPE", print_shape_info, False},
1354    {SYNC_NAME, print_sync_info, False},
1355#ifdef XFreeXDGA
1356    {XF86DGANAME, print_dga_info, False},
1357#endif /* XFreeXDGA */
1358#ifdef XF86VIDMODE
1359    {XF86VIDMODENAME, print_XF86VidMode_info, False},
1360#endif /* XF86VIDMODE */
1361#ifdef XF86MISC
1362    {XF86MISCNAME, print_XF86Misc_info, False},
1363#endif /* XF86MISC */
1364    {XTestExtensionName, print_xtest_info, False},
1365    {"DOUBLE-BUFFER", print_dbe_info, False},
1366    {"RECORD", print_record_info, False},
1367#ifdef XINPUT
1368    {INAME, print_xinput_info, False},
1369#endif
1370#ifdef XRENDER
1371    {RENDER_NAME, print_xrender_info, False},
1372#endif
1373#ifdef COMPOSITE
1374    {COMPOSITE_NAME, print_composite_info, False},
1375#endif
1376#ifdef PANORAMIX
1377    {"XINERAMA", print_xinerama_info, False},
1378#endif
1379#ifdef DMX
1380    {"DMX", print_dmx_info, False},
1381#endif
1382    /* add new extensions here */
1383};
1384
1385static const int num_known_extensions = sizeof known_extensions / sizeof known_extensions[0];
1386
1387static void
1388print_known_extensions(FILE *f)
1389{
1390    int i, col;
1391    for (i = 0, col = 6; i < num_known_extensions; i++)
1392    {
1393	int extlen = (int) strlen(known_extensions[i].extname) + 1;
1394
1395	if ((col + extlen) > 79)
1396	{
1397		col = 6;
1398		fprintf(f, "\n     ");
1399	}
1400	fprintf(f, "%s ", known_extensions[i].extname);
1401	col += extlen;
1402    }
1403}
1404
1405static void
1406mark_extension_for_printing(const char *extname)
1407{
1408    if (strcmp(extname, "all") == 0)
1409    {
1410	for (int i = 0; i < num_known_extensions; i++)
1411	    known_extensions[i].printit = True;
1412    }
1413    else
1414    {
1415	for (int i = 0; i < num_known_extensions; i++)
1416	{
1417	    if (strcmp(extname, known_extensions[i].extname) == 0)
1418	    {
1419		known_extensions[i].printit = True;
1420		return;
1421	    }
1422	}
1423	printf("%s extension not supported by %s\n", extname, ProgramName);
1424    }
1425}
1426
1427static void
1428print_marked_extensions(Display *dpy)
1429{
1430    for (int i = 0; i < num_known_extensions; i++)
1431    {
1432	if (known_extensions[i].printit)
1433	{
1434	    printf("\n");
1435	    if (! (*known_extensions[i].printfunc)(dpy,
1436					known_extensions[i].extname))
1437	    {
1438		printf("%s extension not supported by server\n",
1439		       known_extensions[i].extname);
1440	    }
1441	}
1442    }
1443}
1444
1445static void _X_NORETURN
1446usage(void)
1447{
1448    fprintf (stderr, "usage:  %s [options]\n%s", ProgramName,
1449             "-display displayname\tserver to query\n"
1450             "-version\t\tprint program version and exit\n"
1451             "-queryExtensions\tprint info returned by XQueryExtension\n"
1452             "-ext all\t\tprint detailed info for all supported extensions\n"
1453             "-ext extension-name\tprint detailed info for extension-name if one of:\n     ");
1454    print_known_extensions(stderr);
1455    fprintf (stderr, "\n");
1456    exit (1);
1457}
1458
1459int
1460main(int argc, char *argv[])
1461{
1462    Display *dpy;			/* X connection */
1463    char *displayname = NULL;		/* server to contact */
1464
1465    ProgramName = argv[0];
1466
1467    for (int i = 1; i < argc; i++) {
1468	char *arg = argv[i];
1469	size_t len = strlen(arg);
1470
1471	if (!strncmp("-display", arg, len)) {
1472	    if (++i >= argc) {
1473		fprintf (stderr, "%s: -display requires an argument\n",
1474			 ProgramName);
1475		usage ();
1476	    }
1477	    displayname = argv[i];
1478	} else if (!strncmp("-queryExtensions", arg, len)) {
1479	    queryExtensions = True;
1480	} else if (!strncmp("-ext", arg, len)) {
1481	    if (++i >= argc) {
1482		fprintf (stderr, "%s: -ext requires an argument\n",
1483			 ProgramName);
1484		usage ();
1485	    }
1486	    mark_extension_for_printing(argv[i]);
1487        } else if (!strncmp("-version", arg, len)) {
1488            printf("%s\n", PACKAGE_STRING);
1489            exit (0);
1490	} else {
1491	    fprintf (stderr, "%s: unrecognized argument '%s'\n",
1492		     ProgramName, arg);
1493	    usage ();
1494	}
1495    }
1496
1497    dpy = XOpenDisplay (displayname);
1498    if (!dpy) {
1499	fprintf (stderr, "%s:  unable to open display \"%s\".\n",
1500		 ProgramName, XDisplayName (displayname));
1501	exit (1);
1502    }
1503
1504    print_display_info (dpy);
1505    for (int i = 0; i < ScreenCount (dpy); i++) {
1506	print_screen_info (dpy, i);
1507    }
1508
1509    print_marked_extensions(dpy);
1510
1511    XCloseDisplay (dpy);
1512    exit (0);
1513}
1514