The NVIDIA binary driver doesn't support RandR 1.2 but it does support
Xinerama. Test for RandR and then fall back to Xinerama if we need to.

User commands:
    xsetwacom set "device name" MapToOutput HEAD-0
    xsetwacom set "device name" MapToOutput HEAD-1

Signed-off-by: Peter Hutterer <peter.hutte...@who-t.net>
---
Changes to v1:
- rename set_output_twinview to set_output_xinerama
- test for RandR first, fall back to Xinerama if it fails. Only test for
  NVidia for tracing/debugging purposes
- use convert_value_from_user for arg parsing

 configure.ac      |    2 +-
 man/xsetwacom.man |    3 +-
 tools/xsetwacom.c |   91 ++++++++++++++++++++++++++++++++++++++++++----------
 3 files changed, 76 insertions(+), 20 deletions(-)

diff --git a/configure.ac b/configure.ac
index 408e75f..c151e54 100644
--- a/configure.ac
+++ b/configure.ac
@@ -53,7 +53,7 @@ AC_CHECK_LIB([m], [rint])
 PKG_CHECK_MODULES(XORG, [xorg-server >= 1.7.0] xproto xext kbproto inputproto 
randrproto)
 
 # Obtain compiler/linker options for the xsetwacom tool
-PKG_CHECK_MODULES(X11, x11 xi xrandr)
+PKG_CHECK_MODULES(X11, x11 xi xrandr xinerama)
 
 # Obtain compiler/linker options for libudev used by ISDV4 code
 PKG_CHECK_MODULES(UDEV, libudev)
diff --git a/man/xsetwacom.man b/man/xsetwacom.man
index 3a5fa40..564e1d0 100644
--- a/man/xsetwacom.man
+++ b/man/xsetwacom.man
@@ -126,7 +126,8 @@ outputs may be obtained with the xrandr tool. The output 
mapping
 configuration is a onetime setting and does not track output
 reconfigurations; the command needs to be re-run whenever the output
 configuration changes. When used with tablet rotation, the tablet must be
-rotated before it is mapped to the new screen.
+rotated before it is mapped to the new screen. When running the NVIDIA
+binary driver, the output names are "HEAD-0" and "HEAD-1".
 This parameter is write-only and cannot be queried.
 .TP
 \fBMode\fR Absolute|Relative
diff --git a/tools/xsetwacom.c b/tools/xsetwacom.c
index c0cf707..9f75e83 100644
--- a/tools/xsetwacom.c
+++ b/tools/xsetwacom.c
@@ -37,6 +37,7 @@
 #include <X11/Xatom.h>
 #include <X11/extensions/XInput.h>
 #include <X11/extensions/Xrandr.h>
+#include <X11/extensions/Xinerama.h>
 #include <X11/XKBlib.h>
 
 #define TRACE(...) \
@@ -57,6 +58,7 @@ enum prop_flags {
        PROP_FLAG_READONLY = 2,
        PROP_FLAG_WRITEONLY = 4,
        PROP_FLAG_INVERTED = 8, /* only valid with PROP_FLAG_BOOLEAN */
+       PROP_FLAG_OUTPUT = 16,
 };
 
 
@@ -416,7 +418,7 @@ static param_t parameters[] =
                .desc = "Map the device to the given output. ",
                .set_func = set_output,
                .arg_count = 1,
-               .prop_flags = PROP_FLAG_WRITEONLY
+               .prop_flags = PROP_FLAG_WRITEONLY | PROP_FLAG_OUTPUT,
        },
        {
                .name = "all",
@@ -1483,7 +1485,16 @@ static Bool convert_value_from_user(const param_t 
*param, const char *value, int
                if (param->prop_flags & PROP_FLAG_INVERTED)
                        *return_value = !(*return_value);
        }
-       else
+       else if (param->prop_flags & PROP_FLAG_OUTPUT)
+       {
+               const char *prefix = "HEAD-";
+               /* We currently support HEAD-X, where X is 0-9 */
+               if (strlen(value) != strlen(prefix) + 1 ||
+                   strncasecmp(value, prefix, strlen(prefix)) != 0)
+                       return False;
+
+               *return_value = value[strlen(prefix)] - '0';
+       } else
        {
                char *end;
                long conversion = strtol(value, &end, 10);
@@ -2000,7 +2011,6 @@ static void _set_matrix(Display *dpy, XDevice *dev,
 
 static void set_output_xrandr(Display *dpy, XDevice *dev, param_t *param, int 
argc, char **argv)
 {
-       int min, maj;
        int i, found = 0;
        char *output_name;
        XRRScreenResources *res;
@@ -2009,20 +2019,6 @@ static void set_output_xrandr(Display *dpy, XDevice 
*dev, param_t *param, int ar
 
        output_name = argv[0];
 
-       if (!XRRQueryExtension(dpy, &maj, &min)) /* using min/maj as dummy */
-       {
-               fprintf(stderr, "Server does not support RandR");
-               return;
-       }
-
-       if (!XRRQueryVersion(dpy, &maj, &min) ||
-           (maj * 1000 + min) < 1002)
-       {
-               fprintf(stderr, "Server does not support RandR 1.2");
-               return;
-       }
-
-
        res = XRRGetScreenResources(dpy, DefaultRootWindow(dpy));
 
        for (i = 0; i < res->noutput && !found; i++)
@@ -2058,8 +2054,58 @@ static void set_output_xrandr(Display *dpy, XDevice 
*dev, param_t *param, int ar
        XRRFreeScreenResources(res);
 }
 
+/**
+ * Adjust the transformation matrix based on the Xinerama settings. For
+ * TwinView This would better be done with libXNVCtrl but until they learn
+ * to package it properly, rely on Xinerama. Besides, libXNVCtrl isn't
+ * available on RHEL, so we'd have to do it through Xinerama there anyway.
+ */
+static void set_output_xinerama(Display *dpy, XDevice *dev, param_t *param, 
int argc, char **argv)
+{
+       int event, error;
+       XineramaScreenInfo *screens;
+       int nscreens;
+       int head;
+
+       if (!XineramaQueryExtension(dpy, &event, &error))
+       {
+               fprintf(stderr, "Unable to set screen mapping. Xinerama 
extension not found\n");
+               return;
+       }
+
+       if (!convert_value_from_user(param, argv[0], &head))
+       {
+               fprintf(stderr, "Please specify the output name as HEAD-X,"
+                               "where X is the screen number\n");
+               return;
+       }
+
+       screens = XineramaQueryScreens(dpy, &nscreens);
+
+       if (nscreens == 0)
+       {
+               fprintf(stderr, "Xinerama failed to query screens.\n");
+               goto out;
+       } else if (nscreens <= head)
+       {
+               fprintf(stderr, "Found %d screens, but you requested %s.\n",
+                               nscreens, argv[0]);
+               goto out;
+       }
+
+       _set_matrix(dpy, dev,
+                   screens[head].x_org, screens[head].y_org,
+                   screens[head].width, screens[head].height);
+
+out:
+       XFree(screens);
+}
+
 static void set_output(Display *dpy, XDevice *dev, param_t *param, int argc, 
char **argv)
 {
+       int opcode, event, error;
+       int maj, min;
+
        if (argc != param->arg_count)
        {
                fprintf(stderr, "'%s' requires exactly %d value(s).\n", 
param->name,
@@ -2067,7 +2113,16 @@ static void set_output(Display *dpy, XDevice *dev, 
param_t *param, int argc, cha
                return;
        }
 
-       set_output_xrandr(dpy, dev, param, argc, argv);
+       /* Check for RandR 1.2 */
+       if (!XQueryExtension(dpy, "RANDR", &opcode, &event, &error) ||
+           !XRRQueryVersion(dpy, &maj, &min) || (maj * 1000 + min) < 1002)
+       {
+               if (XQueryExtension(dpy, "NV-CONTROL", &opcode, &event, &error))
+                       TRACE("Nvidia binary driver detected.\n");
+               set_output_xinerama(dpy, dev, param, argc, argv);
+       } else {
+               set_output_xrandr(dpy, dev, param, argc, argv);
+       }
 }
 
 
-- 
1.7.5.4


------------------------------------------------------------------------------
Simplify data backup and recovery for your virtual environment with vRanger.
Installation's a snap, and flexible recovery options mean your data is safe,
secure and there when you need it. Data protection magic?
Nope - It's vRanger. Get your free trial download today.
http://p.sf.net/sfu/quest-sfdev2dev
_______________________________________________
Linuxwacom-devel mailing list
Linuxwacom-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linuxwacom-devel

Reply via email to