[PATCH app/xdpyinfo v4] Use XRANDR 1.2 extension for reporting dimensions and resolution per output

Pali Rohár pali.rohar at gmail.com
Mon May 7 21:34:22 UTC 2018


XServer with enabled XRANDR 1.2 extension does not provide correct
dimensions from DisplayWidthMM() and DisplayHeightMM() calls anymore.
Values are calculated from fixed DPI 96.

Therefore when XRANDR 1.2 extension is enabled, present and user requested
for it, instead use XRRGetScreenResources() and XRRGetOutputInfo() calls to
get correct dimensions and resolution information. Core dimensions from
DisplayWidthMM() and DisplayHeightMM() are still reported.

Otherwise when XRANDR 1.2 extension is enabled, present and user did not
request for it (which is default), show note that printed dimension does
not have to be correct and instruct user to run xdpyinfo with -ext RANDR.

Also update manual page and add information that xdpyinfo does not provide
correct information about DPI.

Signed-off-by: Pali Rohár <pali.rohar at gmail.com>
---
Changes since v3:
* Always show core x screen output

Changes since v2:
* Fixed dimensions calculation when rotation is active
* Show XRANDR output only when explicitly requested
* Update manpage

Changes since v1:
* Fixed detection of presence of XRANDR 1.2
* Fixed resolution calculation when dimensions are zero
---
 Makefile.am      |   2 +
 configure.ac     |  12 ++++++
 man/xdpyinfo.man |   7 +++
 xdpyinfo.c       | 129 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
 4 files changed, 140 insertions(+), 10 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index 2f21dda..496094e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -35,6 +35,7 @@ AM_CFLAGS = \
 	$(DPY_XCOMPOSITE_CFLAGS) \
 	$(DPY_XINERAMA_CFLAGS) \
 	$(DPY_DMX_CFLAGS) \
+	$(DPY_XRANDR_CFLAGS) \
 	$(DPY_XTST_CFLAGS)
 
 xdpyinfo_LDADD = \
@@ -49,6 +50,7 @@ xdpyinfo_LDADD = \
 	$(DPY_XCOMPOSITE_LIBS) \
 	$(DPY_XINERAMA_LIBS) \
 	$(DPY_DMX_LIBS) \
+	$(DPY_XRANDR_LIBS) \
 	$(DPY_XTST_LIBS)
 
 xdpyinfo_SOURCES =	\
diff --git a/configure.ac b/configure.ac
index 73dce26..4473faa 100644
--- a/configure.ac
+++ b/configure.ac
@@ -132,6 +132,18 @@ else
 	echo "without dmx"
 fi
 
+AC_ARG_WITH(xrandr, AS_HELP_STRING([--without-xrandr],[Disable xrandr 1.2 support.]),
+		[USE_XRANDR="$withval"], [USE_XRANDR="yes"])
+if test "x$USE_XRANDR" != "xno" ; then
+	PKG_CHECK_MODULES(DPY_XRANDR, xrandr >= 1.2,
+		[SAVE_CPPFLAGS="$CPPFLAGS"
+		CPPFLAGS="$CPPFLAGS $DPY_XRANDR_CFLAGS $DPY_X11_CFLAGS"
+		AC_CHECK_HEADERS([X11/extensions/Xrandr.h],,,[#include <X11/Xlib.h>])
+		CPPFLAGS="$SAVE_CPPFLAGS"],[echo "not found"])
+else
+	echo "without xrandr 1.2"
+fi
+
 PKG_CHECK_MODULES(DPY_XTST, xtst,
 	[SAVE_CPPFLAGS="$CPPFLAGS"
 	CPPFLAGS="$CPPFLAGS $DPY_XTST_CFLAGS $DPY_X11_CFLAGS"
diff --git a/man/xdpyinfo.man b/man/xdpyinfo.man
index c3d5c6d..5df44ea 100644
--- a/man/xdpyinfo.man
+++ b/man/xdpyinfo.man
@@ -51,6 +51,13 @@ Detailed information about a particular extension is displayed with the
 \fBall\fP, information about all extensions supported by both \fIxdpyinfo\fP
 and the server is displayed.
 .PP
+Do not use this utility for determining dimensions of monitor when XRANDR 1.2+
+extension is enabled for X screen, because it does not provide them. For
+determining physical dimensions or DPI of particular monitor use either
+.IR xrandr (__appmansuffix__)
+utility or call xdpyinfo with parameter \fB\-ext RANDR\fP (supported since
+xdpyinfo version 1.3.3).
+.PP
 If \fB-version\fP is specified, xdpyinfo prints its version and exits, without
 contacting the X server.
 .SH ENVIRONMENT
diff --git a/xdpyinfo.c b/xdpyinfo.c
index 152e32c..8d24b40 100644
--- a/xdpyinfo.c
+++ b/xdpyinfo.c
@@ -76,6 +76,10 @@ in this Software without prior written authorization from The Open Group.
 #  define DMX
 # endif
 
+# if HAVE_X11_EXTENSIONS_XRANDR_H
+#  define XRANDR
+# endif
+
 #endif
 
 #ifdef WIN32
@@ -137,6 +141,9 @@ in this Software without prior written authorization from The Open Group.
 #ifdef DMX
 #include <X11/extensions/dmxext.h>
 #endif
+#ifdef XRANDR
+#include <X11/extensions/Xrandr.h>
+#endif
 #include <X11/Xos.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -442,6 +449,10 @@ print_visual_info(XVisualInfo *vip)
 	    vip->bits_per_rgb);
 }
 
+#ifdef XRANDR
+static Bool print_xrandr = False;
+#endif
+
 static void
 print_screen_info(Display *dpy, int scr)
 {
@@ -455,6 +466,14 @@ print_screen_info(Display *dpy, int scr)
     double xres, yres;
     int ndepths = 0, *depths = NULL;
     unsigned int width, height;
+    Bool has_xrandr = False;
+#ifdef XRANDR
+    int event_base, error_base;
+    int major, minor;
+    XRRScreenResources *res;
+    XRROutputInfo *output;
+    XRRCrtcInfo *crtc;
+#endif
 
     /*
      * there are 2.54 centimeters to an inch; so there are 25.4 millimeters.
@@ -464,18 +483,93 @@ print_screen_info(Display *dpy, int scr)
      *         = N * 25.4 pixels / M inch
      */
 
-    xres = ((((double) DisplayWidth(dpy,scr)) * 25.4) /
-	    ((double) DisplayWidthMM(dpy,scr)));
-    yres = ((((double) DisplayHeight(dpy,scr)) * 25.4) /
-	    ((double) DisplayHeightMM(dpy,scr)));
-
     printf ("\n");
     printf ("screen #%d:\n", scr);
-    printf ("  dimensions:    %dx%d pixels (%dx%d millimeters)\n",
-	    XDisplayWidth (dpy, scr),  XDisplayHeight (dpy, scr),
-	    XDisplayWidthMM(dpy, scr), XDisplayHeightMM (dpy, scr));
-    printf ("  resolution:    %dx%d dots per inch\n",
-	    (int) (xres + 0.5), (int) (yres + 0.5));
+
+#ifdef XRANDR
+    if (XRRQueryExtension (dpy, &event_base, &error_base) &&
+        XRRQueryVersion (dpy, &major, &minor) &&
+        (major > 1 || (major == 1 && minor >= 2)))
+        has_xrandr = True;
+#endif
+
+#ifdef XRANDR
+    if (has_xrandr && print_xrandr)
+    {
+        res = XRRGetScreenResources (dpy, RootWindow (dpy, scr));
+        if (res) {
+            for (i = 0; i < res->noutput; ++i) {
+                output = XRRGetOutputInfo (dpy, res, res->outputs[i]);
+                if (!output || !output->crtc || output->connection != RR_Connected)
+                    continue;
+
+                crtc = XRRGetCrtcInfo (dpy, res, output->crtc);
+                if (!crtc) {
+                    XRRFreeOutputInfo (output);
+                    continue;
+                }
+
+                /* width and height is reported according to rotation, but mm_width and mm_height not */
+                if (crtc->rotation == RR_Rotate_0 || crtc->rotation == RR_Rotate_180) {
+                    width = crtc->width;
+                    height = crtc->height;
+                } else {
+                    width = crtc->height;
+                    height = crtc->width;
+                }
+
+                printf ("  output: %s\n", output->name);
+                printf ("    dimensions:    %ux%u pixels (%lux%lu millimeters)\n",
+                        width, height, output->mm_width, output->mm_height);
+
+                if (output->mm_width && output->mm_height) {
+                    xres = ((((double) width) * 25.4) / ((double) output->mm_width));
+                    yres = ((((double) height) * 25.4) / ((double) output->mm_height));
+                } else {
+                    xres = 0;
+                    yres = 0;
+                }
+                printf ("    resolution:    %dx%d dots per inch\n",
+                        (int) (xres + 0.5), (int) (yres + 0.5));
+
+                XRRFreeCrtcInfo (crtc);
+                XRRFreeOutputInfo (output);
+            }
+            XRRFreeScreenResources (res);
+        }
+
+        printf ("  screen output: (union of all configured monitors)\n");
+        printf ("    dimensions:    %dx%d pixels (%dx%d millimeters)\n",
+                DisplayWidth (dpy, scr),  DisplayHeight (dpy, scr),
+                DisplayWidthMM(dpy, scr), DisplayHeightMM (dpy, scr));
+
+        xres = ((((double) DisplayWidth(dpy,scr)) * 25.4) /
+                ((double) DisplayWidthMM(dpy,scr)));
+        yres = ((((double) DisplayHeight(dpy,scr)) * 25.4) /
+                ((double) DisplayHeightMM(dpy,scr)));
+        printf ("    resolution:    %dx%d dots per inch\n",
+                (int) (xres + 0.5), (int) (yres + 0.5));
+    }
+    else
+#endif
+    {
+        printf ("  dimensions:    %dx%d pixels (%dx%d millimeters)\n",
+                DisplayWidth (dpy, scr),  DisplayHeight (dpy, scr),
+                DisplayWidthMM(dpy, scr), DisplayHeightMM (dpy, scr));
+
+        xres = ((((double) DisplayWidth(dpy,scr)) * 25.4) /
+                ((double) DisplayWidthMM(dpy,scr)));
+        yres = ((((double) DisplayHeight(dpy,scr)) * 25.4) /
+                ((double) DisplayHeightMM(dpy,scr)));
+        printf ("  resolution:    %dx%d dots per inch\n",
+                (int) (xres + 0.5), (int) (yres + 0.5));
+
+        if (has_xrandr)
+            printf ("    NOTE: above information is obsoleted and may be incorrect\n"
+                    "          instead run `%s -ext RANDR' for correct output\n\n",
+                    ProgramName);
+    }
+
     depths = XListDepths (dpy, scr, &ndepths);
     if (!depths) ndepths = 0;
     printf ("  depths (%d):    ", ndepths);
@@ -1316,6 +1410,10 @@ static int print_dmx_info(Display *dpy, const char *extname)
 
 #endif /* DMX */
 
+#ifdef XRANDR
+static int print_none_info(Display *dpy, const char *extname) { return 1; }
+#endif
+
 /* utilities to manage the list of recognized extensions */
 
 
@@ -1369,6 +1467,9 @@ static ExtensionPrintInfo known_extensions[] =
 #ifdef DMX
     {"DMX", print_dmx_info, False},
 #endif
+#ifdef XRANDR
+    {RANDR_NAME, print_none_info, False},
+#endif
     /* add new extensions here */
 };
 
@@ -1397,8 +1498,16 @@ mark_extension_for_printing(const char *extname)
 {
     int i;
 
+#ifdef XRANDR
+    if (strcmp(extname, RANDR_NAME) == 0)
+	print_xrandr = True;
+#endif
+
     if (strcmp(extname, "all") == 0)
     {
+#ifdef XRANDR
+	print_xrandr = True;
+#endif
 	for (i = 0; i < num_known_extensions; i++)
 	    known_extensions[i].printit = True;
     }
-- 
2.11.0



More information about the xorg-devel mailing list