Home | History | Annotate | Line # | Download | only in dist
      1 /*
      2  * xdpyinfo - print information about X display connection
      3  *
      4  *
      5 Copyright 1988, 1998  The Open Group
      6 Copyright 2005 Hitachi, Ltd.
      7 
      8 Permission to use, copy, modify, distribute, and sell this software and its
      9 documentation for any purpose is hereby granted without fee, provided that
     10 the above copyright notice appear in all copies and that both that
     11 copyright notice and this permission notice appear in supporting
     12 documentation.
     13 
     14 The above copyright notice and this permission notice shall be included in
     15 all copies or substantial portions of the Software.
     16 
     17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
     20 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
     21 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     22 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     23 
     24 Except as contained in this notice, the name of The Open Group shall not be
     25 used in advertising or otherwise to promote the sale, use or other dealings
     26 in 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 static char *ProgramName;
    145 static Bool queryExtensions = False;
    146 
    147 #if defined(XF86MISC) || defined(XFreeXDGA)
    148 static int
    149 silent_errors(_X_UNUSED Display *dpy, _X_UNUSED XErrorEvent *ev)
    150 {
    151     return 0;
    152 }
    153 
    154 static int (*old_handler)(Display *, XErrorEvent *) = NULL;
    155 #endif
    156 
    157 static int print_event_mask(char *buf, int lastcol, int indent, long mask);
    158 
    159 static int StrCmp(const void *a, const  void *b)
    160 {
    161     return strcmp(*(const char * const *)a, *(const char * const *)b);
    162 }
    163 
    164 static void
    165 print_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 
    224 static void
    225 print_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 
    415 static void
    416 print_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 
    451 static void
    452 print_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 
    539 static 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 
    570 static int
    571 print_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 
    604 static void
    605 print_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
    622 static int
    623 print_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 
    663 static int
    664 print_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 
    674 static int
    675 print_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 
    698 static int
    699 print_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
    710 static int
    711 print_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 
    752 static void
    753 print_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 
    781 static int
    782 print_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 
    856 static const char *kbdtable[] = {
    857 		     "Unknown", "84-key", "101-key", "Other", "Xqueue" };
    858 static 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" };
    865 static const char *flgtable[] = {
    866 		     "None", "ClearDTR", "ClearRTS", "ClearDTR and ClearRTS" };
    867 
    868 static int
    869 print_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
    920 static int
    921 print_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
    944 static int
    945 print_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 
    966 static int
    967 print_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 
    993 static int
    994 print_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
   1005 static int
   1006 print_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
   1067 static int
   1068 print_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
   1180 static int
   1181 print_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 
   1196 static int
   1197 print_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
   1227 static 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 
   1234 static 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 
   1332 typedef int (*ExtensionPrintFunc)(
   1333     Display *, const char *
   1334 );
   1335 
   1336 typedef struct {
   1337     const char *extname;
   1338     ExtensionPrintFunc printfunc;
   1339     Bool printit;
   1340 } ExtensionPrintInfo;
   1341 
   1342 static 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 
   1385 static const int num_known_extensions = sizeof known_extensions / sizeof known_extensions[0];
   1386 
   1387 static void
   1388 print_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 
   1405 static void
   1406 mark_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 
   1427 static void
   1428 print_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 
   1445 static void _X_NORETURN
   1446 usage(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 
   1459 int
   1460 main(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