On Tue, Sep 27, 2011 at 06:03:57PM -0700, Jason Gerecke wrote:
> 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.

imo the better argument here is that if you're doing calibration, you're
implicitly getting the KeepShape through the calibration 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.

looking at this without any sentimental attachment to the name "KeepShape",
a better name would be "MatchAspectRatio" or somesuch. KeepShape doesn't
really specify which shape to keep, my tablet will look the same after all
;)

also, we need to state that the tablet's input area starts at the tablet's
0/0 (after accommmodating rotation), the input area matched is not centered
or so.


> +
> +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;
> +}

I'd really like to see some basic tests for this to ensure this keeps working 
if we ever change it.

> +
> +/**
> + * 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);

given that you only pass in one boolean to _update_aspect, you could pass the
same boolean into set_output_foo() and do the calculation there, right after
you've parsed the respective output geometries.
Saves you from having to re-fetch the property.

Cheers,
  Peter

------------------------------------------------------------------------------
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