At the moment, this helper is only capable of understanding the
keyword "next". This will cause it to move to the next available
output, with the order determined by the underlying list of heads.

Its hoped this can be expanded to support other keywords, most
notably "left" and "right", which would choose the correct head
based on its relative position in space.
---
 man/xsetwacom.man |    3 +-
 tools/xsetwacom.c |  198 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 194 insertions(+), 7 deletions(-)

diff --git a/man/xsetwacom.man b/man/xsetwacom.man
index 68599b8..fbdfc16 100644
--- a/man/xsetwacom.man
+++ b/man/xsetwacom.man
@@ -123,7 +123,8 @@ 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 defined area of the
-desktop with the form WIDTHxHEIGHT@X,Y. Users of the NVIDIA binary driver
+desktop with the form WIDTHxHEIGHT@X,Y. To switch to the next available output,
+the "next" keyword is also supported. Users of the NVIDIA binary driver
 should use the output names "HEAD-0" and "HEAD-1" until proper XRandR support
 is included.
 
diff --git a/tools/xsetwacom.c b/tools/xsetwacom.c
index 32a1d83..66e2697 100644
--- a/tools/xsetwacom.c
+++ b/tools/xsetwacom.c
@@ -2150,12 +2150,168 @@ out:
 }
 
 /**
- * Adjust the transformation matrix based on a user-defined area.
- * This function will attempt to map the given pointer to the area defined
- * in the first command-line argument (which should be formatted as
- * 'WIDTHxHEIGHT@X,Y'). If this function succeeds in modifying the
- * transformation matrix, it returns 'true'.
+ * Given the dimensions and origin of one of the outputs, this
+ * function finds the corresponding output in the list of Xinerama
+ * heads and then returns the information for the next output.
+ *
+ * If the function fails (e.g. is unable to locate the output
+ * matching the arguments), it returns False.
  */
+Bool get_next_output_area(Display *dpy, int *width, int *height, int *x_org, 
int *y_org)
+{
+       XineramaScreenInfo *screens;
+       int event, error, nscreens, head;
+       int theOne = -1;
+       int display_width = DisplayWidth(dpy, DefaultScreen(dpy));
+       int display_height = DisplayHeight(dpy, DefaultScreen(dpy));
+
+       if (!XineramaQueryExtension(dpy, &event, &error))
+       {
+               TRACE("Unable to get screen mapping. Xinerama extension not 
found\n");
+               return False;
+       }
+
+       screens = XineramaQueryScreens(dpy, &nscreens);
+
+       if (nscreens == 0)
+       {
+               TRACE("Xinerama failed to query screens.\n");
+               XFree(screens);
+               return False;
+       }
+
+       /* Compare the given dimensions to all the heads */
+       for (head=0; head<nscreens; head++)
+       {
+               if (screens[head].width == *width && screens[head].height == 
*height &&
+                   screens[head].x_org == *x_org && screens[head].y_org == 
*y_org)
+                       theOne = head;
+
+               TRACE("%s%d: %dx%d @ %d,%d\n",
+                       theOne == head ? "*" : " ", head,
+                       screens[head].width, screens[head].height,
+                       screens[head].x_org, screens[head].y_org);
+       }
+
+       /* Compare the given dimensions to the entire desktop */
+       if (display_width == *width && display_height == *height)
+               theOne = nscreens;
+       TRACE("%sS: %dx%d @ %d,%d\n",
+               theOne == nscreens? "*" : " ", display_width, display_height, 
0, 0);
+
+
+       /* Special case: check to see if we're mapped to the entire desktop */
+       if (theOne == nscreens)
+       {
+               *width  = screens[0].width;
+               *height = screens[0].height;
+               *x_org  = screens[0].x_org;
+               *y_org  = screens[0].y_org;
+       }
+       else if (++theOne == nscreens)
+       {
+               *width  = display_width;
+               *height = display_height;
+               *x_org  = 0;
+               *y_org  = 0;
+       }
+       else if (theOne >= 0)
+       {
+               *width  = screens[theOne].width;
+               *height = screens[theOne].height;
+               *x_org  = screens[theOne].x_org;
+               *y_org  = screens[theOne].y_org;
+       }
+
+       XFree(screens);
+       return True;
+}
+
+
+/**
+ * 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;
+       int isGoodMatrix = 1;
+       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)
+       {
+               TRACE("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))
+       {
+               TRACE("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; i++)
+       {
+               if (i == 0)
+                       *width = rint(display_width * data[i]);
+               else if (i == 2)
+                       *x_org = rint(display_width * data[i]);
+               else if (i == 4)
+                       *height = rint(display_height * data[i]);
+               else if (i == 5)
+                       *y_org = rint(display_height * data[i]);
+               else if (i == 8)
+               {
+                       if ((float)data[i] != 1)
+                       {
+                               isGoodMatrix = 0;
+                               TRACE("The matrix looks bad at position %d.\n", 
i);
+                       }
+               }
+               else
+               {
+                       if ((float)data[i] != 0)
+                       {
+                               isGoodMatrix = 0;
+                               TRACE("The matrix looks bad at position %d.\n", 
i);
+                       }
+               }
+       }
+
+       XFree(data);
+
+       return isGoodMatrix == 1;
+}
+
+/**
+* Adjust the transformation matrix based on a user-defined area.
+* This function will attempt to map the given pointer to the area defined
+* in the first command-line argument (which should be formatted as
+* 'WIDTHxHEIGHT@X,Y'). If this function succeeds in modifying the
+* transformation matrix, it returns 'true'.
+*/
 static Bool set_output_area(Display *dpy, XDevice *dev, param_t *param, int 
argc, char **argv)
 {
        int width, height, xorig, yorig;
@@ -2174,10 +2330,40 @@ static Bool set_output_area(Display *dpy, XDevice *dev, 
param_t *param, int argc
        return False;
 }
 
+/**
+ * Adjust the transformation matrix based on its current value and a
+ * desired relative direction the mapping should move. At the moment,
+ * this function only supports the command-line argument "next" (indicating
+ * the user's desire to switch to the next output in an arbitrary list).
+ * If this function succeeds in modifying the transformation matrix, it
+ * returns 'true'.
+ */
+static Bool set_output_relative(Display *dpy, XDevice *dev, param_t *param, 
int argc, char **argv)
+{
+       int w, h, x_org, y_org;
+
+       if (strcasecmp(argv[0], "next") == 0)
+       {
+               if (get_mapped_area(dpy, dev, &w, &h, &x_org, &y_org))
+                       if (get_next_output_area(dpy, &w, &h, &x_org, &y_org))
+                       {
+                               _set_matrix(dpy, dev, x_org, y_org, w, h);
+                               fprintf(stderr, "Remapping to output area 
obtained by relative position.\n");
+                               return True;
+                       }
+       }
+       else
+       {
+               TRACE("Unable to parse '%s' as a relative movement.\n", 
argv[0]);
+       }
+
+       return False;
+}
+
 static void set_output(Display *dpy, XDevice *dev, param_t *param, int argc, 
char **argv)
 {
        Bool (*fn[]) (Display * dpy, XDevice *dev, param_t *param, int argc, 
char **argv) =
-       { set_output_area, set_output_xinerama, set_output_xrandr };
+       { set_output_relative, set_output_area, set_output_xinerama, 
set_output_xrandr };
 
        if (argc == 0)
        {
-- 
1.7.6


------------------------------------------------------------------------------
Get a FREE DOWNLOAD! and learn more about uberSVN rich system, 
user administration capabilities and model configuration. Take 
the hassle out of deploying and managing Subversion and the 
tools developers use with it. http://p.sf.net/sfu/wandisco-d2d-2
_______________________________________________
Linuxwacom-devel mailing list
Linuxwacom-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linuxwacom-devel

Reply via email to