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));
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);
}
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;
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:
}
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)
{
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);
}