Skip to content

Commit

Permalink
Fix #459: Apply screen rotation on touchscreen gestures
Browse files Browse the repository at this point in the history
  • Loading branch information
JoseExposito committed Apr 1, 2021
1 parent 44a4b03 commit 0bf049b
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 1 deletion.
12 changes: 11 additions & 1 deletion src/gesture-controller/gesture-controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@ void GestureController::onGestureBegin(std::unique_ptr<Gesture> gesture) {
tlg::debug << "\t\tDirection: " << gestureDirectionToStr(gesture->direction())
<< std::endl;

this->rotatedDirection = this->windowSystem.calculateRotation(
gesture->type(), gesture->performedOnDeviceType(), gesture->direction());
if (this->rotatedDirection != gesture->direction()) {
tlg::debug << "\t\tDirection after rotation: "
<< gestureDirectionToStr(this->rotatedDirection) << std::endl;
gesture->setDirection(this->rotatedDirection);
}

this->window = this->windowSystem.getWindowUnderCursor();
this->action = this->getActionForGesture(*gesture, *this->window);

Expand Down Expand Up @@ -71,18 +79,20 @@ void GestureController::onGestureUpdate(std::unique_ptr<Gesture> gesture) {
if (this->executeAction) {
tlg::debug << "Gesture update detected (" << gesture->percentage() << "%)"
<< std::endl;

gesture->setDirection(this->rotatedDirection);
this->action->onGestureUpdate(*gesture);
}
}

void GestureController::onGestureEnd(std::unique_ptr<Gesture> gesture) {
if (this->executeAction) {
tlg::debug << "Gesture end detected" << std::endl;
gesture->setDirection(this->rotatedDirection);
this->action->onGestureEnd(*gesture);
}

this->action.reset();
this->rotatedDirection = GestureDirection::UNKNOWN;
}

std::unique_ptr<Action> GestureController::getActionForGesture(
Expand Down
6 changes: 6 additions & 0 deletions src/gesture-controller/gesture-controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ class GestureController : public GestureControllerDelegate {
*/
bool executeAction = false;

/**
* If the screen is rotated, this values is set on gesture begin to match the
* screen rotation.
*/
GestureDirection rotatedDirection = GestureDirection::UNKNOWN;

/**
* @returns The action associated to a gesture or nullptr.
*/
Expand Down
8 changes: 8 additions & 0 deletions src/gesture/gesture.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,14 @@ class Gesture {
*/
uint64_t elapsedTime() const { return this->gestureElapsedTime; }

/**
* Set the gesture direction.
* @see GestureDirection
*/
void setDirection(GestureDirection direction) {
this->gestureDirection = direction;
}

protected:
GestureType gestureType = GestureType::NOT_SUPPORTED;
GestureDirection gestureDirection = GestureDirection::UNKNOWN;
Expand Down
16 changes: 16 additions & 0 deletions src/window-system/window-system.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@

#include "actions/action-direction.h"
#include "gesture/device-type.h"
#include "gesture/gesture-direction.h"
#include "gesture/gesture-type.h"
#include "utils/rectangle.h"
#include "window-system/cairo-surface.h"

Expand Down Expand Up @@ -169,6 +171,20 @@ class WindowSystem {
* @returns If natural scroll is enabled in the current window system.
*/
virtual bool isNaturalScrollEnabled(DeviceType deviceType) const = 0;

/**
* When a touchscreen is rotated, the gesture direction sent by the daemon
* doesn't apply the rotation because it doesn't know which backend is used
* and also because libinput only stores rotation information for trackpoints:
*
* "This is currently only available on trackpoints [...]"
* https://wayland.freedesktop.org/libinput/doc/latest/configuration.html#rotation
*
* @returns The direction after applying touchscreen rotation.
*/
virtual GestureDirection calculateRotation(
GestureType gestureType, DeviceType deviceType,
GestureDirection direction) const = 0;
};

#endif // WINDOW_SYSTEM_WINDOW_SYSTEM_H_
91 changes: 91 additions & 0 deletions src/window-system/x11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -774,6 +774,97 @@ bool X11::isNaturalScrollEnabled(DeviceType deviceType) const {
return enabled;
}

GestureDirection X11::calculateRotation(GestureType gestureType,
DeviceType deviceType,
GestureDirection direction) const {
if (gestureType != GestureType::SWIPE ||
deviceType != DeviceType::TOUCHSCREEN) {
return direction;
}

// Use Xrandr to get the screen rotation of the physical screen the mouse
// pointer is placed on
Window rootWindow = None;
Window childWindow = None;
int pointerX = 0;
int pointerY = 0;
int childX = 0;
int childY = 0;
unsigned int mask = 0;
XQueryPointer(this->display, XDefaultRootWindow(this->display), &rootWindow,
&childWindow, &pointerX, &pointerY, &childX, &childY, &mask);

// Get the physical screen size the mouse pointer is placed on
bool screenFound = false;
Rotation rotation = 0;
int currentCrtc = 0;
XRRScreenResources *resources =
XRRGetScreenResources(this->display, rootWindow);

while (!screenFound && currentCrtc < resources->ncrtc) {
XRRCrtcInfo *crtc =
// NOLINTNEXTLINE
XRRGetCrtcInfo(this->display, resources, resources->crtcs[currentCrtc]);

if (pointerX >= crtc->x && pointerX < (crtc->x + crtc->width) &&
pointerY >= crtc->y && pointerY < (crtc->y + crtc->height)) {
screenFound = true;
rotation = crtc->rotation;
}

XRRFreeCrtcInfo(crtc);
currentCrtc++;
}

XRRFreeScreenResources(resources);

if (!screenFound) {
return direction;
}

GestureDirection rotatedDirection = direction;
switch (rotation) {
case RR_Rotate_90:
if (direction == GestureDirection::UP) {
rotatedDirection = GestureDirection::RIGHT;
} else if (direction == GestureDirection::DOWN) {
rotatedDirection = GestureDirection::LEFT;
} else if (direction == GestureDirection::LEFT) {
rotatedDirection = GestureDirection::UP;
} else if (direction == GestureDirection::RIGHT) {
rotatedDirection = GestureDirection::DOWN;
}
break;
case RR_Rotate_180:
if (direction == GestureDirection::UP) {
rotatedDirection = GestureDirection::DOWN;
} else if (direction == GestureDirection::DOWN) {
rotatedDirection = GestureDirection::UP;
} else if (direction == GestureDirection::LEFT) {
rotatedDirection = GestureDirection::RIGHT;
} else if (direction == GestureDirection::RIGHT) {
rotatedDirection = GestureDirection::LEFT;
}
break;
case RR_Rotate_270:
if (direction == GestureDirection::UP) {
rotatedDirection = GestureDirection::LEFT;
} else if (direction == GestureDirection::DOWN) {
rotatedDirection = GestureDirection::RIGHT;
} else if (direction == GestureDirection::LEFT) {
rotatedDirection = GestureDirection::DOWN;
} else if (direction == GestureDirection::RIGHT) {
rotatedDirection = GestureDirection::UP;
}
break;
case RR_Rotate_0:
default:
break;
}

return rotatedDirection;
}

template <typename T>
std::vector<T> X11::getDeviceProperty(int deviceId, const std::string &atomName,
Atom atomType) const {
Expand Down
3 changes: 3 additions & 0 deletions src/window-system/x11.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ class X11 : public WindowSystem {
std::unique_ptr<CairoSurface> createCairoSurface() const override;

bool isNaturalScrollEnabled(DeviceType deviceType) const override;
GestureDirection calculateRotation(GestureType gestureType,
DeviceType deviceType,
GestureDirection direction) const override;

private:
/**
Expand Down

0 comments on commit 0bf049b

Please sign in to comment.