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.

Signed-off-by: Jason Gerecke <[email protected]>
---
 Changes from v2:
  * Corresponds to patch v2 6/9 (interim patches now gone)

  * 'get_next_output_area' and 'set_output_relative' joined into a
    singular 'set_output_next' since there's not likely to be any
    other type of relative movement offered in the near future

  * Introduce 'set_output_desktop' early (it'd show up in the next
    patch anyway, but is also useful here)

  * Numerous stylistic changes

 man/xsetwacom.man |    7 ++-
 tools/xsetwacom.c |  140 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 145 insertions(+), 2 deletions(-)

diff --git a/man/xsetwacom.man b/man/xsetwacom.man
index 84c91e9..edc97c4 100644
--- a/man/xsetwacom.man
+++ b/man/xsetwacom.man
@@ -123,8 +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 proper XRandR support is included.
+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 proper
+XRandR support is included.
 
 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 f887064..298da44 100644
--- a/tools/xsetwacom.c
+++ b/tools/xsetwacom.c
@@ -1958,6 +1958,76 @@ 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++)
+       {
+               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 (data[i] != 1)
+                               matrix_is_valid = False;
+               }
+               else if (data[i] != 0)
+                       matrix_is_valid = False;
+       }
+       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);
@@ -2132,6 +2202,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; 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 tmp_int[2];
@@ -2157,6 +2293,10 @@ static void set_output(Display *dpy, XDevice *dev, 
param_t *param, int argc, cha
        {
                set_output_area(dpy, dev, tmp_int[0], tmp_int[1], tmp_uint[0], 
tmp_uint[1]);
        }
+       else if (strcasecmp(argv[0], "next") == 0)
+       {
+               set_output_next(dpy, dev);
+       }
        else if (!need_xinerama(dpy))
        {
                set_output_xrandr(dpy, dev, argv[0]);
-- 
1.7.6


------------------------------------------------------------------------------
Using storage to extend the benefits of virtualization and iSCSI
Virtualization increases hardware utilization and delivers a new level of
agility. Learn what those decisions are and how to modernize your storage 
and backup environments for virtualization.
http://www.accelacomm.com/jaw/sfnl/114/51434361/
_______________________________________________
Linuxwacom-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/linuxwacom-devel

Reply via email to