Adds an optional "KeepShape" paramater to the MapToOutput command.
If provided, the Area property is updated to match the aspect ratio
of the new output. If not provided, the Area property is reset to
the full tablet dimensions.

This commit causes the MapToOutput command to break existing scripts
that rely on the Area property for device calibration. It is not
expected that this will result in actual problems since calibration
utilities do not currently handle multi-head setups properly anyway.

Signed-off-by: Jason Gerecke <killert...@gmail.com>
---
 man/xsetwacom.man |   21 +++++----
 tools/xsetwacom.c |  125 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 134 insertions(+), 12 deletions(-)

diff --git a/man/xsetwacom.man b/man/xsetwacom.man
index dc0995f..43da602 100644
--- a/man/xsetwacom.man
+++ b/man/xsetwacom.man
@@ -119,15 +119,18 @@ the device will ignore events from other tools. A serial 
of 0 means the
 device is unbound and will react to any tool of the matching type.
 Default: 0
 .TP
-\fBMapToOutput\fR [output]
-Map the tablet's input area to a given output (e.g. "VGA1"). Output names may
-either be the name of a head available through the XRandR extension, or an
-X11 geometry string of 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. The mapping may be reset to the entire desktop at any time with the
-output name "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.
+\fBMapToOutput\fR [output] [KeepShape]
+Map the tablet's input area to a given output (e.g. "VGA1"). If the "KeepShape"
+argument is passed in, the the active area of the tablet will be restricted
+to match the aspect ratio of the output; if unspecified, the entire tablet
+area will be usable.
+
+Outputs may be specified by their XRandR name (users of the NVIDIA binary
+should use the names "HEAD-0" and "HEAD-1" until the driver supports XRandR
+1.2 or later). To map the tablet to an arbitrary portion of the desktop, you
+may provide an X11 geometry string of the form WIDTHxHEIGHT+X+Y. To map to
+the entire desktop, use "desktop". To cycle through all attached displays and
+the desktop, use "next".
 
 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 acc57c7..8480b0c 100644
--- a/tools/xsetwacom.c
+++ b/tools/xsetwacom.c
@@ -434,7 +434,7 @@ static param_t parameters[] =
                .name = "MapToOutput",
                .desc = "Map the device to the given output. ",
                .set_func = set_output,
-               .arg_count = 1,
+               .arg_count = 2,
                .prop_flags = PROP_FLAG_WRITEONLY | PROP_FLAG_OUTPUT,
        },
        {
@@ -2137,6 +2137,108 @@ Bool get_mapped_area(Display *dpy, XDevice *dev, int 
*width, int *height, int *x
        return matrix_is_valid;
 }
 
+static Bool shrink(float aspect_ratio, long *width, long *height)
+{
+       if (!isfinite(aspect_ratio))
+               return False;
+       else if (aspect_ratio == 0)
+               return True;
+
+       if ((float)*width / (float)*height > aspect_ratio)
+               *width = *height * aspect_ratio;
+       else
+               *height = *width / aspect_ratio;
+
+       return True;
+}
+
+static Bool rectangle_to_aspect(float aspect_ratio, int rotate, long *x1, long 
*y1,
+                          long *x2, long *y2)
+{
+       long width  = *x2 - *x1;
+       long height = *y2 - *y1;
+
+       if (rotate == ROTATE_CW || rotate == ROTATE_CCW)
+               aspect_ratio = 1/aspect_ratio;
+
+       shrink(aspect_ratio, &width, &height);
+
+       switch (rotate)
+       {
+               case ROTATE_NONE:
+                       *x2 = *x1 + width;
+                       *y2 = *y1 + height;
+                       break;
+
+               case ROTATE_CW:
+                       *x1 = *x2 - width;
+                       *y2 = *y1 + height;
+                       break;
+
+               case ROTATE_HALF:
+                       *x1 = *x2 - width;
+                       *y1 = *y2 - height;
+                       break;
+
+               case ROTATE_CCW:
+                       *x2 = *x1 + width;
+                       *y1 = *y2 - height;
+                       break;
+
+               default:
+                       return False;
+       }
+
+       return True;
+}
+
+/**
+ * Updates device's area property so that it's aspect ratio matches
+ * that of the currently defied output area (if 'do_match' is true),
+ * or to allow use of the entire area (if 'do_match' is false).
+ *
+ * If this function succeeds in modifying the aspect ratio, it returns
+ * 'true'.
+ */
+static Bool _update_aspect(Display *dpy, XDevice *dev, Bool do_match)
+{
+       param_t* area_param = find_parameter("Area");
+       param_t* rotate_param = find_parameter("Rotate");
+       int w, h, x_org, y_org;
+       float aspect;
+       long area[4] = {-1, -1, -1, -1};
+
+       if (!get_mapped_area(dpy, dev, &w, &h, &x_org, &y_org))
+       {
+               fprintf(stderr, "Unable to get the output area.\n");
+               return False;
+       }
+       aspect = (float)w/(float)h;
+
+       _set(dpy, dev, area_param->prop_name, area_param->prop_offset, &area,
+            area_param->prop_format, XA_INTEGER, area_param->arg_count);
+
+       if (do_match)
+       {
+               long *rotptr  = _get(dpy, dev, rotate_param->prop_name, 
rotate_param->prop_offset,
+                                    rotate_param->prop_format, XA_INTEGER, 
rotate_param->arg_count);
+               long *areaptr = _get(dpy, dev, area_param->prop_name, 
area_param->prop_offset,
+                                    area_param->prop_format, XA_INTEGER, 
area_param->arg_count);
+
+               if(rectangle_to_aspect(aspect, rotptr[0], &areaptr[0], 
&areaptr[1], &areaptr[2], &areaptr[3]))
+               {
+                       _set(dpy, dev, area_param->prop_name, 
area_param->prop_offset, areaptr,
+                            area_param->prop_format, XA_INTEGER, 
area_param->arg_count);
+               }
+
+               return False;
+       }
+       else
+       {
+               return True;
+       }
+}
+
 /**
  * Modifies the server's transformation matrix property for the given
  * device. It takes as input a 9-element array of floats interpreted
@@ -2417,10 +2519,21 @@ static void set_output(Display *dpy, XDevice *dev, 
param_t *param, int argc, cha
        unsigned int width, height;
        int flags = XParseGeometry(argv[0], &x, &y, &width, &height);
        Bool success = False;
+       Bool do_match;
 
-       if (argc != param->arg_count)
+       if (argc == 0)
        {
-               fprintf(stderr, "'%s' requires exactly %d value(s).\n", 
param->name,
+               fprintf(stderr, "'%s' requires at least one argument.\n", 
param->name);
+               return;
+       }
+       else if (argc == param->arg_count && strcasecmp(argv[1], "KeepShape") 
!= 0)
+       {
+               fprintf(stderr, "'%s' could not understand the provided 
argument '%s'.\n",
+                       param->name, argv[1]);
+       }
+       else if (argc > param->arg_count)
+       {
+               fprintf(stderr, "'%s' accepts no more than %d value(s).\n", 
param->name,
                        param->arg_count);
                return;
        }
@@ -2437,6 +2550,12 @@ static void set_output(Display *dpy, XDevice *dev, 
param_t *param, int argc, cha
                success = set_output_xinerama(dpy, dev, head_no);
        else
                fprintf(stderr, "Unable to find an output '%s'.\n", argv[0]);
+
+       if (!success)
+               return;
+
+       do_match = argc > 1 && strcasecmp(argv[1], "KeepShape") == 0;
+       _update_aspect(dpy, dev, do_match);
 }
 
 
-- 
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
Linuxwacom-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linuxwacom-devel

Reply via email to