Adds a helper function for MapToOutput which determines which
output the device is currently mapped to, and moves to the next
available output. Repeatedly calling this function will result
in the device being mapped to every available output (including
the desktop as a whole) in turn.

Signed-off-by: Jason Gerecke <[email protected]>
---
Changes from v3:

 * Corresponds to patch v3 4/7
 * Updated commit message
 * Changed from if/else-if to switch statement
 * Exit loop as soon as matrix is determined invalid

 man/xsetwacom.man |    8 ++-
 tools/xsetwacom.c |  137 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 142 insertions(+), 3 deletions(-)

diff --git a/man/xsetwacom.man b/man/xsetwacom.man
index 9375e5b..10832ad 100644
--- a/man/xsetwacom.man
+++ b/man/xsetwacom.man
@@ -123,9 +123,11 @@ Default: 0
 Map the tablet's input area to the given output (e.g. "VGA1"), or the entire
 desktop if no output is provided. Output names may either be the name of
 a head available through the XRandR extension, or an X11 geometry string of
-the from WIDTHxHEIGHT+X+Y. Users of the NVIDIA binary driver should use the
-output names "HEAD-0" and "HEAD-1" until the driver supports XRandr 1.2 or
-later.
+the form WIDTHxHEIGHT+X+Y. To switch to the next available output, the "next"
+keyword is also supported. This will cycle between the individual monitors
+connected to the system, and then the entire desktop. Users of the NVIDIA
+binary driver should use the output names "HEAD-0" and "HEAD-1" until the
+driver supports XRandR 1.2 or later.
 
 The output mapping configuration is a onetime setting and does not track output
 reconfigurations; the command needs to be re-run whenever the output
diff --git a/tools/xsetwacom.c b/tools/xsetwacom.c
index dea6e99..c9c090c 100644
--- a/tools/xsetwacom.c
+++ b/tools/xsetwacom.c
@@ -1955,6 +1955,75 @@ static Bool need_xinerama(Display *dpy)
        return False;
 }
 
+/**
+ * Uses the area of the desktop and the server's transformation
+ * matrix to calculate the dimensions and location of the area
+ * the given device is mapped to. If the matrix describes a
+ * non-rectangular transform (e.g. rotation or shear), this
+ * function returns False.
+ */
+Bool get_mapped_area(Display *dpy, XDevice *dev, int *width, int *height, int 
*x_org, int *y_org)
+{
+       Atom matrix_prop = XInternAtom(dpy, "Coordinate Transformation Matrix", 
True);
+       Atom type;
+       int format;
+       unsigned long nitems, bytes_after;
+       float *data;
+       Bool matrix_is_valid = True;
+       int i;
+
+       int display_width = DisplayWidth(dpy, DefaultScreen(dpy));
+       int display_height = DisplayHeight(dpy, DefaultScreen(dpy));
+       TRACE("Desktop width: %d, height: %d\n", display_width, display_height);
+
+       if (!matrix_prop)
+       {
+               fprintf(stderr, "Server does not support transformation\n");
+               return False;
+       }
+
+       XGetDeviceProperty(dpy, dev, matrix_prop, 0, 9, False,
+                          AnyPropertyType, &type, &format, &nitems,
+                          &bytes_after, (unsigned char**)&data);
+
+       if (format != 32 || type != XInternAtom(dpy, "FLOAT", True))
+       {
+               fprintf(stderr,"Property for '%s' has unexpected type - this is 
a bug.\n",
+                       "Coordinate Transformation Matrix");
+               XFree(data);
+               return False;
+       }
+
+       TRACE("Current transformation matrix:\n");
+       TRACE(" [ %f %f %f ]\n", data[0], data[1], data[2]);
+       TRACE(" [ %f %f %f ]\n", data[3], data[4], data[5]);
+       TRACE(" [ %f %f %f ]\n", data[6], data[7], data[8]);
+
+       for (i = 0; i < nitems && matrix_is_valid; i++)
+       {
+               switch (i) {
+                       case 0: *width  = rint(display_width  * data[i]); break;
+                       case 2: *x_org  = rint(display_width  * data[i]); break;
+                       case 4: *height = rint(display_height * data[i]); break;
+                       case 5: *y_org  = rint(display_height * data[i]); break;
+                       case 8:
+                               if (data[i] != 1)
+                                       matrix_is_valid = False;
+                               break;
+                       default:
+                               if (data[i] != 0)
+                                       matrix_is_valid = False;
+                               break;
+               }
+       }
+       XFree(data);
+
+       if (!matrix_is_valid)
+               fprintf(stderr, "Non-rectangular transformation matrix 
detected.\n");
+
+       return matrix_is_valid;
+}
+
 static void _set_matrix_prop(Display *dpy, XDevice *dev, const float 
fmatrix[9])
 {
        Atom matrix_prop = XInternAtom(dpy, "Coordinate Transformation Matrix", 
True);
@@ -2129,6 +2198,72 @@ out:
        XFree(screens);
 }
 
+/**
+ * Adjust the transformation matrix based on the desktop size.
+ * This function will attempt to map the given device to the entire
+ * desktop.
+ */
+static void set_output_desktop(Display *dpy, XDevice *dev)
+{
+       int display_width = DisplayWidth(dpy, DefaultScreen(dpy));
+       int display_height = DisplayHeight(dpy, DefaultScreen(dpy));
+
+       set_output_area(dpy, dev, 0, 0, display_width, display_height);
+}
+
+/**
+ * Adjust the transformation matrix based on its current value. This
+ * function will attempt to map the given device to the next output
+ * exposed in the list of Xinerama heads. If not mapped to a Xinerama
+ * head, it maps to the first head. If mapped to the last Xinerama
+ * head, it maps to the entire desktop.
+ */
+static void set_output_next(Display *dpy, XDevice *dev)
+{
+       XineramaScreenInfo *screens;
+       int event, error, nscreens, head;
+       int width, height, x_org, y_org;
+       Bool success = False;
+
+       if (!get_mapped_area(dpy, dev, &width, &height, &x_org, &y_org))
+               return;
+
+       if (!XineramaQueryExtension(dpy, &event, &error))
+       {
+               fprintf(stderr, "Unable to get screen mapping. Xinerama 
extension not found\n");
+               return;
+       }
+
+       screens = XineramaQueryScreens(dpy, &nscreens);
+
+       if (nscreens == 0)
+       {
+               fprintf(stderr, "Xinerama failed to query screens.\n");
+               goto out;
+       }
+
+       TRACE("Remapping to next available output.\n");
+       for (head = 0; head < nscreens && !success; head++)
+       {
+               if (screens[head].width == width && screens[head].height == 
height &&
+                   screens[head].x_org == x_org && screens[head].y_org  == 
y_org)
+               {
+                       success = True;
+
+                       if (head + 1 < nscreens)
+                               set_output_xinerama(dpy, dev, head+1);
+                       else
+                               set_output_desktop(dpy, dev);
+               }
+       }
+
+       if (!success)
+               set_output_xinerama(dpy, dev, 0);
+
+out:
+       XFree(screens);
+}
+
 static void set_output(Display *dpy, XDevice *dev, param_t *param, int argc, 
char **argv)
 {
        int head_no;
@@ -2153,6 +2288,8 @@ static void set_output(Display *dpy, XDevice *dev, 
param_t *param, int argc, cha
 
        if (MaskIsSet(flags, XValue|YValue|WidthValue|HeightValue))
                set_output_area(dpy, dev, x, y, width, height);
+       else if (strcasecmp(argv[0], "next") == 0)
+               set_output_next(dpy, dev);
        else if (!need_xinerama(dpy))
                set_output_xrandr(dpy, dev, argv[0]);
        else if  (convert_value_from_user(param, argv[0], &head_no))
-- 
1.7.6


------------------------------------------------------------------------------
All the data continuously generated in your IT infrastructure contains a
definitive record of customers, application performance, security
threats, fraudulent activity and more. Splunk takes this data and makes
sense of it. Business sense. IT sense. Common sense.
http://p.sf.net/sfu/splunk-d2dcopy1
_______________________________________________
Linuxwacom-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/linuxwacom-devel

Reply via email to