blob: 551e127fc7cbf0619e4c05d12b3f05a775777d07 [file] [log] [blame]
From 08b2f14bf234bad2443a6e3a8e237e31b97960e9 Mon Sep 17 00:00:00 2001
From: Andrew de los Reyes <adlr@chromium.org>
Date: Thu, 14 Mar 2013 17:36:23 -0700
Subject: [PATCH] x11-base/xorg-conf: Support screen rotation.
This patch uses properties set on the window from Chrome to see if a
display is internal/external, hi-resolution, and now rotated; it
scales the X cursor movement as appropriate.
---
dix/getevents.c | 157 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 157 insertions(+)
diff --git a/dix/getevents.c b/dix/getevents.c
index f1e7491..2a3acfa 100644
--- a/dix/getevents.c
+++ b/dix/getevents.c
@@ -33,6 +33,7 @@
#include <X11/X.h>
#include <X11/keysym.h>
+#include <X11/Xatom.h>
#include <X11/Xproto.h>
#include <math.h>
#include <limits.h>
@@ -50,6 +51,7 @@
#include "eventconvert.h"
#include "inpututils.h"
#include "mi.h"
+#include "propertyst.h"
#include "windowstr.h"
#include <X11/extensions/XKBproto.h>
@@ -60,6 +62,7 @@
#include "panoramiXsrv.h"
#endif
+#include <X11/extensions/randr.h>
#include <X11/extensions/XI.h>
#include <X11/extensions/XI2.h>
#include <X11/extensions/XIproto.h>
@@ -1262,6 +1265,158 @@ QueuePointerEvents(DeviceIntPtr device, int type,
queueEventList(device, InputEventList, nevents);
}
+/*
+ * Looks for magic properties for the window where the mouse cursor is, and
+ * uses them to return the scaleFactor of the display (e.g., 100 being normal,
+ * 200 being pixel doubled), whether or not it's internal, and the rotation.
+ * If a magic property is not found, the corresponding ouput value is not
+ * changed.
+ *
+ * Rotation values are:
+ * RR_Rotate_0: normal
+ * RR_Rotate_90: 90 deg clockwise
+ * RR_Rotate_180: 180 deg clockwise
+ * RR_Rotate_270: 270 deg clockwise
+ *
+ * Returns FALSE on error.
+ */
+static int
+getSpriteChromeProps(ScreenPtr pScreen, DeviceIntPtr dev,
+ int *scaleFactor, int *isInternal, int *rotation)
+{
+ PropertyPtr pProp;
+ SpriteInfoPtr spriteInfo;
+ SpritePtr sprite;
+ WindowPtr spriteWin;
+ int i;
+ const char kDisplayRotationPropName[] = "_CHROME_DISPLAY_ROTATION";
+ const char kDisplayScaleFactorPropName[] = "_CHROME_DISPLAY_SCALE_FACTOR";
+ const char kDisplayInternalPropName[] = "_CHROME_DISPLAY_INTERNAL";
+ Atom atomRotation = MakeAtom(kDisplayRotationPropName,
+ sizeof(kDisplayRotationPropName) - 1,
+ FALSE /* FALSE == do not malloc */);
+ Atom atomScaleFactor = MakeAtom(kDisplayScaleFactorPropName,
+ sizeof(kDisplayScaleFactorPropName) - 1,
+ FALSE /* FALSE == do not malloc */);
+ Atom atomDisplayInternal = MakeAtom(kDisplayInternalPropName,
+ sizeof(kDisplayInternalPropName) - 1,
+ FALSE /* FALSE == do not malloc */);
+
+ spriteInfo = dev->spriteInfo;
+ if (!spriteInfo)
+ return FALSE;
+ sprite = spriteInfo->sprite;
+ if (!sprite)
+ return FALSE;
+
+ if (sprite->spriteTraceGood <= 0)
+ return FALSE;
+
+ for (i = 0; i < sprite->spriteTraceGood; ++i) {
+ spriteWin = sprite->spriteTrace[i];
+ for (pProp = wUserProps(spriteWin); pProp; pProp = pProp->next) {
+ if ((pProp->format / 8) * pProp->size != 4)
+ continue;
+ if (pProp->propertyName == atomRotation && atomRotation != None) {
+ *rotation = *(int*)pProp->data;
+ } else if (pProp->propertyName == atomScaleFactor &&
+ atomScaleFactor != None) {
+ *scaleFactor = *(int*)pProp->data;
+ } else if (pProp->propertyName == atomDisplayInternal &&
+ atomDisplayInternal != None) {
+ *isInternal = *(int*)pProp->data;
+ }
+ }
+ }
+ return TRUE;
+}
+
+/*
+ * Looks for a magic property set on a device that indicates if it's an
+ * integrated touchpad. Returns TRUE if it's an integrated touchpad, FALSE if
+ * it's not or if there's an error.
+ */
+static int
+isIntegratedTouchpad(DeviceIntPtr dev)
+{
+ const char kIntegratedTouchpadPropName[] = "Integrated Touchpad";
+ XIPropertyPtr prop = NULL;
+ Atom property = MakeAtom(kIntegratedTouchpadPropName,
+ strlen(kIntegratedTouchpadPropName),
+ FALSE /* FALSE == do not malloc */);
+ if (property == None)
+ return FALSE;
+
+ for (prop = dev->properties.properties; prop; prop = prop->next)
+ if (prop->propertyName == property)
+ break;
+ if (prop == NULL)
+ return FALSE;
+
+ if ((prop->value.format / 8) * prop->value.size != 1)
+ return FALSE;
+
+ return (*(char*)prop->value.data == 1) ? TRUE : FALSE;
+}
+
+/*
+ * Scale the motion vector in mask valuators 0 & 1
+ *
+ * Specifically: scales all motion on High-DPI displays, add 20% more
+ * motion on non-integrated displays, and honors rotation settings.
+ */
+static void
+scaleAndRotateMotionPerRRCrtc(DeviceIntPtr dev, ValuatorMask *mask)
+{
+ ScreenPtr pScreen = miPointerGetScreen(dev);
+ double temp, dx, dy, scale;
+ int scaleFactor = 100;
+ int rotation = RR_Rotate_0;
+ int isInternal = FALSE;
+
+ if (!getSpriteChromeProps(pScreen, dev, &scaleFactor, &isInternal, &rotation))
+ return;
+
+ scale = (double)scaleFactor / 100.0;
+ if (!isInternal)
+ scale *= 1.2;
+
+ /* For the case of rotated integrated display and integrated touchpad,
+ * we do not honor the rotation. */
+ if (rotation != RR_Rotate_0 && isInternal && isIntegratedTouchpad(dev))
+ rotation = RR_Rotate_0;
+
+ if (scale != 1.0 || rotation != 0) {
+ dx = 0.0;
+ dy = 0.0;
+ valuator_mask_fetch_double(mask, 0, &dx);
+ valuator_mask_fetch_double(mask, 1, &dy);
+
+ switch (rotation) {
+ case RR_Rotate_90:
+ temp = dx;
+ dx = -dy;
+ dy = temp;
+ break;
+
+ case RR_Rotate_180:
+ dx = -dx;
+ dy = -dy;
+ break;
+
+ case RR_Rotate_270:
+ temp = dx;
+ dx = dy;
+ dy = -temp;
+ break;
+ }
+
+ valuator_mask_set_double(mask, 0, dx * scale);
+ valuator_mask_set_double(mask, 1, dy * scale);
+ }
+}
+
+
/**
* Helper function for GetPointerEvents, which only generates motion and
* raw motion events for the slave device: does not update the master device.
@@ -1368,6 +1523,8 @@ fill_pointer_events(InternalEvent *events, DeviceIntPtr pDev, int type,
if ((flags & POINTER_NORAW) == 0)
set_raw_valuators(raw, &mask, raw->valuators.data);
+ scaleAndRotateMotionPerRRCrtc(pDev, &mask);
+
moveRelative(pDev, &mask);
}