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
