X-Git-Url: https://diplodocus.org/git/xorg-xinput/blobdiff_plain/8563e64fa4eeaf7b56374fd6695f026d98f1696d..fb9cb61708c2cbe832824575daef27ea1c51ab38:/src/transform.c?ds=inline diff --git a/src/transform.c b/src/transform.c index c1a065f..d85b071 100644 --- a/src/transform.c +++ b/src/transform.c @@ -106,11 +106,31 @@ apply_matrix(Display *dpy, int deviceid, Matrix *m) return EXIT_SUCCESS; } +static void +matrix_s4(Matrix *m, float x02, float x12, float d1, float d2, int main_diag) +{ + matrix_set(m, 0, 2, x02); + matrix_set(m, 1, 2, x12); + + if (main_diag) { + matrix_set(m, 0, 0, d1); + matrix_set(m, 1, 1, d2); + } else { + matrix_set(m, 0, 0, 0); + matrix_set(m, 1, 1, 0); + matrix_set(m, 0, 1, d1); + matrix_set(m, 1, 0, d2); + } +} + +#define RR_Reflect_All (RR_Reflect_X|RR_Reflect_Y) + static void set_transformation_matrix(Display *dpy, Matrix *m, int offset_x, int offset_y, - int screen_width, int screen_height) + int screen_width, int screen_height, + int rotation) { - /* offset */ + /* total display size */ int width = DisplayWidth(dpy, DefaultScreen(dpy)); int height = DisplayHeight(dpy, DefaultScreen(dpy)); @@ -124,50 +144,111 @@ set_transformation_matrix(Display *dpy, Matrix *m, int offset_x, int offset_y, matrix_set_unity(m); - matrix_set(m, 0, 2, x); - matrix_set(m, 1, 2, y); - - matrix_set(m, 0, 0, w); - matrix_set(m, 1, 1, h); + /* + * There are 16 cases: + * Rotation X Reflection + * Rotation: 0 | 90 | 180 | 270 + * Reflection: None | X | Y | XY + * + * They are spelled out instead of doing matrix multiplication to avoid + * any floating point errors. + */ + switch (rotation) { + case RR_Rotate_0: + case RR_Rotate_180 | RR_Reflect_All: + matrix_s4(m, x, y, w, h, 1); + break; + case RR_Reflect_X|RR_Rotate_0: + case RR_Reflect_Y|RR_Rotate_180: + matrix_s4(m, x + w, y, -w, h, 1); + break; + case RR_Reflect_Y|RR_Rotate_0: + case RR_Reflect_X|RR_Rotate_180: + matrix_s4(m, x, y + h, w, -h, 1); + break; + case RR_Rotate_90: + case RR_Rotate_270 | RR_Reflect_All: /* left limited - correct in working zone. */ + matrix_s4(m, x + w, y, -w, h, 0); + break; + case RR_Rotate_270: + case RR_Rotate_90 | RR_Reflect_All: /* left limited - correct in working zone. */ + matrix_s4(m, x, y + h, w, -h, 0); + break; + case RR_Rotate_90 | RR_Reflect_X: /* left limited - correct in working zone. */ + case RR_Rotate_270 | RR_Reflect_Y: /* left limited - correct in working zone. */ + matrix_s4(m, x, y, w, h, 0); + break; + case RR_Rotate_90 | RR_Reflect_Y: /* right limited - correct in working zone. */ + case RR_Rotate_270 | RR_Reflect_X: /* right limited - correct in working zone. */ + matrix_s4(m, x + w, y + h, -w, -h, 0); + break; + case RR_Rotate_180: + case RR_Reflect_All|RR_Rotate_0: + matrix_s4(m, x + w, y + h, -w, -h, 1); + break; + } #if DEBUG matrix_print(m); #endif } -static int -map_crtc_xrandr(Display *dpy, int deviceid, const char *output_name) +/* Caller must free return value */ +static XRROutputInfo* +find_output_xrandr(Display *dpy, const char *output_name) { - int i, found = 0; - int rc = EXIT_FAILURE; XRRScreenResources *res; - XRROutputInfo *output_info; - XRRCrtcInfo *crtc_info; + XRROutputInfo *output_info = NULL; + int i; + int found = 0; res = XRRGetScreenResources(dpy, DefaultRootWindow(dpy)); for (i = 0; i < res->noutput && !found; i++) { output_info = XRRGetOutputInfo(dpy, res, res->outputs[i]); - if (!output_info->crtc || output_info->connection != RR_Connected) - continue; - crtc_info = XRRGetCrtcInfo (dpy, res, output_info->crtc); - if (strcmp(output_info->name, output_name) == 0) + if (output_info->crtc && output_info->connection == RR_Connected && + strcmp(output_info->name, output_name) == 0) { found = 1; break; } + + XRRFreeOutputInfo(output_info); } + XRRFreeScreenResources(res); + + if (!found) + output_info = NULL; + + return output_info; +} + +static int +map_output_xrandr(Display *dpy, int deviceid, const char *output_name) +{ + int rc = EXIT_FAILURE; + XRRScreenResources *res; + XRROutputInfo *output_info; + + res = XRRGetScreenResources(dpy, DefaultRootWindow(dpy)); + output_info = find_output_xrandr(dpy, output_name); + /* crtc holds our screen info, need to compare to actual screen size */ - if (found) + if (output_info) { + XRRCrtcInfo *crtc_info; Matrix m; matrix_set_unity(&m); + crtc_info = XRRGetCrtcInfo (dpy, res, output_info->crtc); set_transformation_matrix(dpy, &m, crtc_info->x, crtc_info->y, - crtc_info->width, crtc_info->height); + crtc_info->width, crtc_info->height, + crtc_info->rotation); rc = apply_matrix(dpy, deviceid, &m); + XRRFreeCrtcInfo(crtc_info); + XRRFreeOutputInfo(output_info); } else printf("Unable to find output '%s'. " "Output may not be connected.\n", output_name); @@ -178,7 +259,7 @@ map_crtc_xrandr(Display *dpy, int deviceid, const char *output_name) } static int -map_crtc_xinerama(Display *dpy, int deviceid, const char *output_name) +map_output_xinerama(Display *dpy, int deviceid, const char *output_name) { const char *prefix = "HEAD-"; XineramaScreenInfo *screens = NULL; @@ -220,7 +301,8 @@ map_crtc_xinerama(Display *dpy, int deviceid, const char *output_name) matrix_set_unity(&m); set_transformation_matrix(dpy, &m, screens[head].x_org, screens[head].y_org, - screens[head].width, screens[head].height); + screens[head].width, screens[head].height, + RR_Rotate_0); rc = apply_matrix(dpy, deviceid, &m); out: @@ -229,12 +311,11 @@ out: } int -map_to_crtc(Display *dpy, int argc, char *argv[], char *name, char *desc) +map_to_output(Display *dpy, int argc, char *argv[], char *name, char *desc) { - int opcode, event, error; - int maj, min; - char *crtc_name; + char *output_name; XIDeviceInfo *info; + XRROutputInfo *output_info; if (argc < 2) { @@ -245,19 +326,24 @@ map_to_crtc(Display *dpy, int argc, char *argv[], char *name, char *desc) info = xi2_find_device_info(dpy, argv[0]); if (!info) { - fprintf(stderr, "unable to find device %s\n", argv[0]); + fprintf(stderr, "unable to find device '%s'\n", argv[0]); return EXIT_FAILURE; } - crtc_name = argv[1]; - - /* Check for RandR 1.2. Server bug causes the NVIDIA driver to - * report with RandR 1.3 support but it doesn't expose RandR CRTCs. - * Force Xinerama if NV-CONTROL is present */ - if (XQueryExtension(dpy, "NV-CONTROL", &opcode, &event, &error) || - !XQueryExtension(dpy, "RANDR", &opcode, &event, &error) || - !XRRQueryVersion(dpy, &maj, &min) || (maj * 1000 + min) < 1002) - return map_crtc_xinerama(dpy, info->deviceid, crtc_name); - else - return map_crtc_xrandr(dpy, info->deviceid, crtc_name); + output_name = argv[1]; + output_info = find_output_xrandr(dpy, output_name); + if (!output_info) + { + /* Output doesn't exist. Is this a (partial) non-RandR setup? */ + output_info = find_output_xrandr(dpy, "default"); + if (output_info) + { + XRRFreeOutputInfo(output_info); + if (strncmp("HEAD-", output_name, strlen("HEAD-")) == 0) + return map_output_xinerama(dpy, info->deviceid, output_name); + } + } else + XRRFreeOutputInfo(output_info); + + return map_output_xrandr(dpy, info->deviceid, output_name); }