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

Pali Rohár pali.rohar at gmail.com
Wed Apr 12 16:29:19 UTC 2017


Current usage of DisplayWidthMM() and DisplayHeightMM() does not make sense
for multi-monitor configuration. In most cases DPI is set to 96 as there is
no sane value.

Instead when XRANDR 1.2 extension is supported, report dimensions and
resolution information per XRANDR monitor output. It should provide
correct DPI value.

Lot of users complains about incorrect DPI reported by xdpyinfo, see bug:
https://bugs.freedesktop.org/show_bug.cgi?id=23705

Signed-off-by: Pali Rohár <pali.rohar at gmail.com>
---
Without this patch `xdpyinfo | grep -A 4 ^screen` reports:

screen #0:
  dimensions:    1600x900 pixels (423x238 millimeters)
  resolution:    96x96 dots per inch
  depths (7):    24, 1, 4, 8, 15, 16, 32
  root window id:    0xf8

Where DPI and also monitor dimensions in millimeters is incorrect.
After applying this patch `xdpyinfo | grep -A 4 ^screen` reports:

screen #0:
  output: eDP1
    dimensions:    1600x900 pixels (310x170 millimeters)
    resolution:    131x134 dots per inch
  depths (7):    24, 1, 4, 8, 15, 16, 32

And both DPI and monitor dimensions (for eDP1) are correct.
---
 Makefile.am  |    2 ++
 configure.ac |   12 ++++++++
 xdpyinfo.c   |   86 ++++++++++++++++++++++++++++++++++++++++++++++------------
 3 files changed, 82 insertions(+), 18 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/xdpyinfo.c b/xdpyinfo.c
index 152e32c..7a75fdc 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>
@@ -455,27 +462,70 @@ print_screen_info(Display *dpy, int scr)
     double xres, yres;
     int ndepths = 0, *depths = NULL;
     unsigned int width, height;
-
-    /*
-     * there are 2.54 centimeters to an inch; so there are 25.4 millimeters.
-     *
-     *     dpi = N pixels / (M millimeters / (25.4 millimeters / 1 inch))
-     *         = N pixels / (M inch / 25.4)
-     *         = 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)));
+#ifdef XRANDR
+    int event_base, error_base;
+    int major, minor;
+    XRRScreenResources *res = NULL;
+    XRROutputInfo *output;
+    XRRCrtcInfo *crtc;
+#endif
 
     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)) &&
+        (res = XRRGetScreenResources (dpy, RootWindow (dpy, scr))))
+    {
+        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;
+            }
+
+            printf ("  output: %s\n", output->name);
+            printf ("    dimensions:    %ux%u pixels (%lux%lu millimeters)\n",
+                    crtc->width, crtc->height, output->mm_width, output->mm_height);
+
+            xres = ((((double) crtc->width) * 25.4) / ((double) output->mm_width));
+            yres = ((((double) crtc->height) * 25.4) / ((double) output->mm_height));
+            printf ("    resolution:    %dx%d dots per inch\n",
+                    (int) (xres + 0.5), (int) (yres + 0.5));
+
+            XRRFreeCrtcInfo (crtc);
+            XRRFreeOutputInfo (output);
+        }
+        XRRFreeScreenResources (res);
+    }
+    else
+#endif
+    {
+        printf ("  dimensions:    %dx%d pixels (%dx%d millimeters)\n",
+                DisplayWidth (dpy, scr),  DisplayHeight (dpy, scr),
+                DisplayWidthMM(dpy, scr), DisplayHeightMM (dpy, scr));
+
+        /*
+         * there are 2.54 centimeters to an inch; so there are 25.4 millimeters.
+         *
+         *     dpi = N pixels / (M millimeters / (25.4 millimeters / 1 inch))
+         *         = N pixels / (M inch / 25.4)
+         *         = 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 ("  resolution:    %dx%d dots per inch\n",
+                (int) (xres + 0.5), (int) (yres + 0.5));
+    }
+
     depths = XListDepths (dpy, scr, &ndepths);
     if (!depths) ndepths = 0;
     printf ("  depths (%d):    ", ndepths);
-- 
1.7.9.5



More information about the xorg-devel mailing list