]> diplodocus.org Git - xorg-xinput/blobdiff - src/transform.c
autogen.sh: use exec instead of waiting for configure to finish
[xorg-xinput] / src / transform.c
index c1a065fa152ae762fe4a57ac285da1d62e70554a..d85b0715017d8b395160c375fc921f5e18581b71 100644 (file)
@@ -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);
 }