diff --git a/autotests/CMakeLists.txt b/autotests/CMakeLists.txt index bffe6c3841..5e70e73a98 100644 --- a/autotests/CMakeLists.txt +++ b/autotests/CMakeLists.txt @@ -281,6 +281,7 @@ set( testScreenEdges_SRCS mock_screens.cpp mock_workspace.cpp ../atoms.cpp + ../gestures.cpp ../screens.cpp ../screenedge.cpp ../virtualdesktops.cpp diff --git a/autotests/test_gestures.cpp b/autotests/test_gestures.cpp index da32e72ab2..a2600d7164 100644 --- a/autotests/test_gestures.cpp +++ b/autotests/test_gestures.cpp @@ -34,6 +34,18 @@ private Q_SLOTS: void testSwipeMaxFinger(); void testDirection_data(); void testDirection(); + void testMinimumX_data(); + void testMinimumX(); + void testMinimumY_data(); + void testMinimumY(); + void testMaximumX_data(); + void testMaximumX(); + void testMaximumY_data(); + void testMaximumY(); + void testStartGeometry(); + void testSetMinimumDelta(); + void testMinimumDeltaReached_data(); + void testMinimumDeltaReached(); void testUnregisterSwipeCancels(); void testDeleteSwipeCancels(); void testSwipeCancel_data(); @@ -45,6 +57,8 @@ private Q_SLOTS: void testSwipeMinFingerStart(); void testSwipeMaxFingerStart_data(); void testSwipeMaxFingerStart(); + void testSwipeGeometryStart_data(); + void testSwipeGeometryStart(); void testSwipeDiagonalCancels_data(); void testSwipeDiagonalCancels(); }; @@ -119,6 +133,178 @@ void GestureTest::testDirection() QCOMPARE(gesture.direction(), SwipeGesture::Direction::Down); } +void GestureTest::testMinimumX_data() +{ + QTest::addColumn("min"); + + QTest::newRow("0") << 0; + QTest::newRow("-1") << -1; + QTest::newRow("1") << 1; +} + +void GestureTest::testMinimumX() +{ + SwipeGesture gesture; + QCOMPARE(gesture.minimumX(), 0); + QCOMPARE(gesture.minimumXIsRelevant(), false); + QFETCH(int, min); + gesture.setMinimumX(min); + QCOMPARE(gesture.minimumX(), min); + QCOMPARE(gesture.minimumXIsRelevant(), true); +} + +void GestureTest::testMinimumY_data() +{ + QTest::addColumn("min"); + + QTest::newRow("0") << 0; + QTest::newRow("-1") << -1; + QTest::newRow("1") << 1; +} + +void GestureTest::testMinimumY() +{ + SwipeGesture gesture; + QCOMPARE(gesture.minimumY(), 0); + QCOMPARE(gesture.minimumYIsRelevant(), false); + QFETCH(int, min); + gesture.setMinimumY(min); + QCOMPARE(gesture.minimumY(), min); + QCOMPARE(gesture.minimumYIsRelevant(), true); +} + +void GestureTest::testMaximumX_data() +{ + QTest::addColumn("max"); + + QTest::newRow("0") << 0; + QTest::newRow("-1") << -1; + QTest::newRow("1") << 1; +} + +void GestureTest::testMaximumX() +{ + SwipeGesture gesture; + QCOMPARE(gesture.maximumX(), 0); + QCOMPARE(gesture.maximumXIsRelevant(), false); + QFETCH(int, max); + gesture.setMaximumX(max); + QCOMPARE(gesture.maximumX(), max); + QCOMPARE(gesture.maximumXIsRelevant(), true); +} + +void GestureTest::testMaximumY_data() +{ + QTest::addColumn("max"); + + QTest::newRow("0") << 0; + QTest::newRow("-1") << -1; + QTest::newRow("1") << 1; +} + +void GestureTest::testMaximumY() +{ + SwipeGesture gesture; + QCOMPARE(gesture.maximumY(), 0); + QCOMPARE(gesture.maximumYIsRelevant(), false); + QFETCH(int, max); + gesture.setMaximumY(max); + QCOMPARE(gesture.maximumY(), max); + QCOMPARE(gesture.maximumYIsRelevant(), true); +} + +void GestureTest::testStartGeometry() +{ + SwipeGesture gesture; + gesture.setStartGeometry(QRect(1, 2, 20, 30)); + QCOMPARE(gesture.minimumXIsRelevant(), true); + QCOMPARE(gesture.minimumYIsRelevant(), true); + QCOMPARE(gesture.maximumXIsRelevant(), true); + QCOMPARE(gesture.maximumYIsRelevant(), true); + QCOMPARE(gesture.minimumX(), 1); + QCOMPARE(gesture.minimumY(), 2); + QCOMPARE(gesture.maximumX(), 21); + QCOMPARE(gesture.maximumY(), 32); +} + +void GestureTest::testSetMinimumDelta() +{ + SwipeGesture gesture; + QCOMPARE(gesture.isMinimumDeltaRelevant(), false); + QCOMPARE(gesture.minimumDelta(), QSizeF()); + QCOMPARE(gesture.minimumDeltaReached(QSizeF()), true); + gesture.setMinimumDelta(QSizeF(2, 3)); + QCOMPARE(gesture.isMinimumDeltaRelevant(), true); + QCOMPARE(gesture.minimumDelta(), QSizeF(2, 3)); + QCOMPARE(gesture.minimumDeltaReached(QSizeF()), false); + QCOMPARE(gesture.minimumDeltaReached(QSizeF(2, 3)), true); +} + +void GestureTest::testMinimumDeltaReached_data() +{ + QTest::addColumn("direction"); + QTest::addColumn("minimumDelta"); + QTest::addColumn("delta"); + QTest::addColumn("reached"); + QTest::addColumn("progress"); + + QTest::newRow("Up (more)") << KWin::SwipeGesture::Direction::Up << QSizeF(0, -30) << QSizeF(0, -40) << true << 1.0; + QTest::newRow("Up (exact)") << KWin::SwipeGesture::Direction::Up << QSizeF(0, -30) << QSizeF(0, -30) << true << 1.0; + QTest::newRow("Up (less)") << KWin::SwipeGesture::Direction::Up << QSizeF(0, -30) << QSizeF(0, -29) << false << 29.0/30.0; + QTest::newRow("Left (more)") << KWin::SwipeGesture::Direction::Left << QSizeF(-30, -30) << QSizeF(-40, 20) << true << 1.0; + QTest::newRow("Left (exact)") << KWin::SwipeGesture::Direction::Left << QSizeF(-30, -40) << QSizeF(-30, 0) << true << 1.0; + QTest::newRow("Left (less)") << KWin::SwipeGesture::Direction::Left << QSizeF(-30, -30) << QSizeF(-29, 0) << false << 29.0/30.0; + QTest::newRow("Right (more)") << KWin::SwipeGesture::Direction::Right << QSizeF(30, -30) << QSizeF(40, 20) << true << 1.0; + QTest::newRow("Right (exact)") << KWin::SwipeGesture::Direction::Right << QSizeF(30, -40) << QSizeF(30, 0) << true << 1.0; + QTest::newRow("Right (less)") << KWin::SwipeGesture::Direction::Right << QSizeF(30, -30) << QSizeF(29, 0) << false << 29.0/30.0; + QTest::newRow("Down (more)") << KWin::SwipeGesture::Direction::Down << QSizeF(0, 30) << QSizeF(0, 40) << true << 1.0; + QTest::newRow("Down (exact)") << KWin::SwipeGesture::Direction::Down << QSizeF(0, 30) << QSizeF(0, 30) << true << 1.0; + QTest::newRow("Down (less)") << KWin::SwipeGesture::Direction::Down << QSizeF(0, 30) << QSizeF(0, 29) << false << 29.0/30.0; +} + +void GestureTest::testMinimumDeltaReached() +{ + SwipeGesture gesture; + QFETCH(SwipeGesture::Direction, direction); + gesture.setDirection(direction); + QFETCH(QSizeF, minimumDelta); + gesture.setMinimumDelta(minimumDelta); + QFETCH(QSizeF, delta); + QFETCH(bool, reached); + QCOMPARE(gesture.minimumDeltaReached(delta), reached); + + GestureRecognizer recognizer; + recognizer.registerGesture(&gesture); + + QSignalSpy startedSpy(&gesture, &SwipeGesture::started); + QVERIFY(startedSpy.isValid()); + QSignalSpy triggeredSpy(&gesture, &SwipeGesture::triggered); + QVERIFY(triggeredSpy.isValid()); + QSignalSpy cancelledSpy(&gesture, &SwipeGesture::cancelled); + QVERIFY(cancelledSpy.isValid()); + QSignalSpy progressSpy(&gesture, &SwipeGesture::progress); + QVERIFY(progressSpy.isValid()); + + recognizer.startSwipeGesture(1); + QCOMPARE(startedSpy.count(), 1); + QCOMPARE(triggeredSpy.count(), 0); + QCOMPARE(cancelledSpy.count(), 0); + QCOMPARE(progressSpy.count(), 0); + + recognizer.updateSwipeGesture(delta); + QCOMPARE(startedSpy.count(), 1); + QCOMPARE(triggeredSpy.count(), 0); + QCOMPARE(cancelledSpy.count(), 0); + QCOMPARE(progressSpy.count(), 1); + QTEST(progressSpy.first().first().value(), "progress"); + + recognizer.endSwipeGesture(); + QCOMPARE(startedSpy.count(), 1); + QCOMPARE(progressSpy.count(), 1); + QCOMPARE(triggeredSpy.isEmpty(), !reached); + QCOMPARE(cancelledSpy.isEmpty(), reached); +} + void GestureTest::testUnregisterSwipeCancels() { GestureRecognizer recognizer; @@ -219,12 +405,21 @@ void GestureTest::testSwipeUpdateCancel() QSignalSpy leftTriggeredSpy(&leftGesture, &SwipeGesture::triggered); QVERIFY(leftTriggeredSpy.isValid()); + QSignalSpy upProgressSpy(&upGesture, &SwipeGesture::progress); + QVERIFY(upProgressSpy.isValid()); + QSignalSpy downProgressSpy(&downGesture, &SwipeGesture::progress); + QVERIFY(downProgressSpy.isValid()); + QSignalSpy leftProgressSpy(&leftGesture, &SwipeGesture::progress); + QVERIFY(leftProgressSpy.isValid()); + QSignalSpy rightProgressSpy(&rightGesture, &SwipeGesture::progress); + QVERIFY(rightProgressSpy.isValid()); + recognizer.registerGesture(&upGesture); recognizer.registerGesture(&downGesture); recognizer.registerGesture(&rightGesture); recognizer.registerGesture(&leftGesture); - recognizer.startSwipeGesture(4); + QCOMPARE(recognizer.startSwipeGesture(4), 4); // first a down gesture recognizer.updateSwipeGesture(QSizeF(1, 20)); @@ -251,6 +446,11 @@ void GestureTest::testSwipeUpdateCancel() QCOMPARE(downTriggeredSpy.count(), 0); QCOMPARE(leftTriggeredSpy.count(), 0); QCOMPARE(rightTriggeredSpy.count(), 0); + + QCOMPARE(upProgressSpy.count(), 0); + QCOMPARE(downProgressSpy.count(), 0); + QCOMPARE(leftProgressSpy.count(), 0); + QCOMPARE(rightProgressSpy.count(), 0); } void GestureTest::testSwipeUpdateTrigger_data() @@ -343,6 +543,39 @@ void GestureTest::testSwipeMaxFingerStart() QTEST(!startedSpy.isEmpty(), "started"); } +void GestureTest::testSwipeGeometryStart_data() +{ + QTest::addColumn("geometry"); + QTest::addColumn("startPos"); + QTest::addColumn("started"); + + QTest::newRow("top left") << QRect(0, 0, 10, 20) << QPointF(0, 0) << true; + QTest::newRow("top right") << QRect(0, 0, 10, 20) << QPointF(10, 0) << true; + QTest::newRow("bottom left") << QRect(0, 0, 10, 20) << QPointF(0, 20) << true; + QTest::newRow("bottom right") << QRect(0, 0, 10, 20) << QPointF(10, 20) << true; + QTest::newRow("x too small") << QRect(10, 20, 30, 40) << QPointF(9, 25) << false; + QTest::newRow("y too small") << QRect(10, 20, 30, 40) << QPointF(25, 19) << false; + QTest::newRow("x too large") << QRect(10, 20, 30, 40) << QPointF(41, 25) << false; + QTest::newRow("y too large") << QRect(10, 20, 30, 40) << QPointF(25, 61) << false; + QTest::newRow("inside") << QRect(10, 20, 30, 40) << QPointF(25, 25) << true; +} + +void GestureTest::testSwipeGeometryStart() +{ + GestureRecognizer recognizer; + SwipeGesture gesture; + QFETCH(QRect, geometry); + gesture.setStartGeometry(geometry); + + QSignalSpy startedSpy(&gesture, &SwipeGesture::started); + QVERIFY(startedSpy.isValid()); + + recognizer.registerGesture(&gesture); + QFETCH(QPointF, startPos); + recognizer.startSwipeGesture(startPos); + QTEST(!startedSpy.isEmpty(), "started"); +} + void GestureTest::testSwipeDiagonalCancels_data() { QTest::addColumn("direction"); diff --git a/gestures.cpp b/gestures.cpp index 08ebd8fdc4..511732d384 100644 --- a/gestures.cpp +++ b/gestures.cpp @@ -19,7 +19,7 @@ along with this program. If not, see . *********************************************************************/ #include "gestures.h" -#include +#include #include namespace KWin @@ -39,6 +39,36 @@ SwipeGesture::SwipeGesture(QObject *parent) SwipeGesture::~SwipeGesture() = default; +void SwipeGesture::setStartGeometry(const QRect &geometry) +{ + setMinimumX(geometry.x()); + setMinimumY(geometry.y()); + setMaximumX(geometry.x() + geometry.width()); + setMaximumY(geometry.y() + geometry.height()); +} + +qreal SwipeGesture::minimumDeltaReachedProgress(const QSizeF &delta) const +{ + if (!m_minimumDeltaRelevant || m_minimumDelta.isNull()) { + return 1.0; + } + switch (m_direction) { + case Direction::Up: + case Direction::Down: + return std::min(std::abs(delta.height()) / std::abs(m_minimumDelta.height()), 1.0); + case Direction::Left: + case Direction::Right: + return std::min(std::abs(delta.width()) / std::abs(m_minimumDelta.width()), 1.0); + default: + Q_UNREACHABLE(); + } +} + +bool SwipeGesture::minimumDeltaReached(const QSizeF &delta) const +{ + return minimumDeltaReachedProgress(delta) >= 1.0; +} + GestureRecognizer::GestureRecognizer(QObject *parent) : QObject(parent) { @@ -67,8 +97,9 @@ void GestureRecognizer::unregisterGesture(KWin::Gesture* gesture) } } -void GestureRecognizer::startSwipeGesture(uint fingerCount) +int GestureRecognizer::startSwipeGesture(uint fingerCount, const QPointF &startPos, StartPositionBehavior startPosBehavior) { + int count = 0; // TODO: verify that no gesture is running for (Gesture *gesture : qAsConst(m_gestures)) { SwipeGesture *swipeGesture = qobject_cast(gesture); @@ -85,10 +116,34 @@ void GestureRecognizer::startSwipeGesture(uint fingerCount) continue; } } + if (startPosBehavior == StartPositionBehavior::Relevant) { + if (swipeGesture->minimumXIsRelevant()) { + if (swipeGesture->minimumX() > startPos.x()) { + continue; + } + } + if (swipeGesture->maximumXIsRelevant()) { + if (swipeGesture->maximumX() < startPos.x()) { + continue; + } + } + if (swipeGesture->minimumYIsRelevant()) { + if (swipeGesture->minimumY() > startPos.y()) { + continue; + } + } + if (swipeGesture->maximumYIsRelevant()) { + if (swipeGesture->maximumY() < startPos.y()) { + continue; + } + } + } // direction doesn't matter yet m_activeSwipeGestures << swipeGesture; + count++; emit swipeGesture->started(); } + return count; } void GestureRecognizer::updateSwipeGesture(const QSizeF &delta) @@ -108,9 +163,13 @@ void GestureRecognizer::updateSwipeGesture(const QSizeF &delta) // vertical direction = delta.height() < 0 ? SwipeGesture::Direction::Up : SwipeGesture::Direction::Down; } + const QSizeF combinedDelta = std::accumulate(m_swipeUpdates.constBegin(), m_swipeUpdates.constEnd(), QSizeF(0, 0)); for (auto it = m_activeSwipeGestures.begin(); it != m_activeSwipeGestures.end();) { auto g = qobject_cast(*it); if (g->direction() == direction) { + if (g->isMinimumDeltaRelevant()) { + emit g->progress(g->minimumDeltaReachedProgress(combinedDelta)); + } it++; } else { emit g->cancelled(); @@ -135,8 +194,13 @@ void GestureRecognizer::cancelSwipeGesture() void GestureRecognizer::endSwipeGesture() { + const QSizeF delta = std::accumulate(m_swipeUpdates.constBegin(), m_swipeUpdates.constEnd(), QSizeF(0, 0)); for (auto g : qAsConst(m_activeSwipeGestures)) { - emit g->triggered(); + if (static_cast(g)->minimumDeltaReached(delta)) { + emit g->triggered(); + } else { + emit g->cancelled(); + } } m_activeSwipeGestures.clear(); m_swipeUpdates.clear(); diff --git a/gestures.h b/gestures.h index 802b515102..3abbc9d1db 100644 --- a/gestures.h +++ b/gestures.h @@ -21,6 +21,8 @@ along with this program. If not, see . #define KWIN_GESTURES_H #include +#include +#include #include #include @@ -95,12 +97,86 @@ public: m_direction = direction; } + void setMinimumX(int x) { + m_minimumX = x; + m_minimumXRelevant = true; + } + int minimumX() const { + return m_minimumX; + } + bool minimumXIsRelevant() const { + return m_minimumXRelevant; + } + void setMinimumY(int y) { + m_minimumY = y; + m_minimumYRelevant = true; + } + int minimumY() const { + return m_minimumY; + } + bool minimumYIsRelevant() const { + return m_minimumYRelevant; + } + + void setMaximumX(int x) { + m_maximumX = x; + m_maximumXRelevant = true; + } + int maximumX() const { + return m_maximumX; + } + bool maximumXIsRelevant() const { + return m_maximumXRelevant; + } + void setMaximumY(int y) { + m_maximumY = y; + m_maximumYRelevant = true; + } + int maximumY() const { + return m_maximumY; + } + bool maximumYIsRelevant() const { + return m_maximumYRelevant; + } + void setStartGeometry(const QRect &geometry); + + QSizeF minimumDelta() const { + return m_minimumDelta; + } + void setMinimumDelta(const QSizeF &delta) { + m_minimumDelta = delta; + m_minimumDeltaRelevant = true; + } + bool isMinimumDeltaRelevant() const { + return m_minimumDeltaRelevant; + } + + qreal minimumDeltaReachedProgress(const QSizeF &delta) const; + bool minimumDeltaReached(const QSizeF &delta) const; + +Q_SIGNALS: + /** + * The progress of the gesture if a @link{minimumDelta} is set. + * The progress is reported in [0.0,1.0] + **/ + void progress(qreal); + private: bool m_minimumFingerCountRelevant = false; uint m_minimumFingerCount = 0; bool m_maximumFingerCountRelevant = false; uint m_maximumFingerCount = 0; Direction m_direction = Direction::Down; + bool m_minimumXRelevant = false; + int m_minimumX = 0; + bool m_minimumYRelevant = false; + int m_minimumY = 0; + bool m_maximumXRelevant = false; + int m_maximumX = 0; + bool m_maximumYRelevant = false; + int m_maximumY = 0; + bool m_minimumDeltaRelevant = false; + QSizeF m_minimumDelta; }; class GestureRecognizer : public QObject @@ -113,13 +189,23 @@ public: void registerGesture(Gesture *gesture); void unregisterGesture(Gesture *gesture); - void startSwipeGesture(uint fingerCount); + int startSwipeGesture(uint fingerCount) { + return startSwipeGesture(fingerCount, QPointF(), StartPositionBehavior::Irrelevant); + } + int startSwipeGesture(const QPointF &startPos) { + return startSwipeGesture(1, startPos, StartPositionBehavior::Relevant); + } void updateSwipeGesture(const QSizeF &delta); void cancelSwipeGesture(); void endSwipeGesture(); private: void cancelActiveSwipeGestures(); + enum class StartPositionBehavior { + Relevant, + Irrelevant + }; + int startSwipeGesture(uint fingerCount, const QPointF &startPos, StartPositionBehavior startPosBehavior); QVector m_gestures; QVector m_activeSwipeGestures; QMap m_destroyConnections; diff --git a/input.cpp b/input.cpp index 59b422e0ad..49e08b3c23 100644 --- a/input.cpp +++ b/input.cpp @@ -25,6 +25,7 @@ along with this program. If not, see . #include "touch_input.h" #include "client.h" #include "effects.h" +#include "gestures.h" #include "globalshortcuts.h" #include "logind.h" #include "main.h" @@ -1047,6 +1048,46 @@ public: // always forward return false; } + bool touchDown(quint32 id, const QPointF &pos, quint32 time) override { + Q_UNUSED(time) + // TODO: better check whether a touch sequence is in progess + if (m_touchInProgress || waylandServer()->seat()->isTouchSequence()) { + // cancel existing touch + ScreenEdges::self()->gestureRecognizer()->cancelSwipeGesture(); + m_touchInProgress = false; + m_id = 0; + return false; + } + if (ScreenEdges::self()->gestureRecognizer()->startSwipeGesture(pos) > 0) { + m_touchInProgress = true; + m_id = id; + m_lastPos = pos; + return true; + } + return false; + } + bool touchMotion(quint32 id, const QPointF &pos, quint32 time) override { + Q_UNUSED(time) + if (m_touchInProgress && m_id == id) { + ScreenEdges::self()->gestureRecognizer()->updateSwipeGesture(QSizeF(pos.x() - m_lastPos.x(), pos.y() - m_lastPos.y())); + m_lastPos = pos; + return true; + } + return false; + } + bool touchUp(quint32 id, quint32 time) override { + Q_UNUSED(time) + if (m_touchInProgress && m_id == id) { + ScreenEdges::self()->gestureRecognizer()->endSwipeGesture(); + m_touchInProgress = false; + return true; + } + return false; + } +private: + bool m_touchInProgress = false; + quint32 m_id = 0; + QPointF m_lastPos; }; /** diff --git a/plugins/platforms/x11/standalone/edge.cpp b/plugins/platforms/x11/standalone/edge.cpp index bf03cc02ed..544e78d67e 100644 --- a/plugins/platforms/x11/standalone/edge.cpp +++ b/plugins/platforms/x11/standalone/edge.cpp @@ -44,14 +44,14 @@ WindowBasedEdge::~WindowBasedEdge() { } -void WindowBasedEdge::activate() +void WindowBasedEdge::doActivate() { createWindow(); createApproachWindow(); doUpdateBlocking(); } -void WindowBasedEdge::deactivate() +void WindowBasedEdge::doDeactivate() { m_window.reset(); m_approachWindow.reset(); diff --git a/plugins/platforms/x11/standalone/edge.h b/plugins/platforms/x11/standalone/edge.h index 44dc3dffae..980c8b3ae8 100644 --- a/plugins/platforms/x11/standalone/edge.h +++ b/plugins/platforms/x11/standalone/edge.h @@ -50,8 +50,8 @@ public: protected: virtual void doGeometryUpdate(); - virtual void activate(); - virtual void deactivate(); + virtual void doActivate() override; + virtual void doDeactivate() override; virtual void doStartApproaching(); virtual void doStopApproaching(); virtual void doUpdateBlocking(); diff --git a/screenedge.cpp b/screenedge.cpp index f28d1f401d..9eecbe6034 100644 --- a/screenedge.cpp +++ b/screenedge.cpp @@ -31,6 +31,7 @@ along with this program. If not, see . // KWin #include "atoms.h" +#include "gestures.h" #include #include "cursor.h" #include "main.h" @@ -72,7 +73,33 @@ Edge::Edge(ScreenEdges *parent) , m_blocked(false) , m_pushBackBlocked(false) , m_client(nullptr) + , m_gesture(new SwipeGesture(this)) { + m_gesture->setMinimumFingerCount(1); + m_gesture->setMaximumFingerCount(1); + connect(m_gesture, &Gesture::triggered, this, + [this] { + stopApproaching(); + if (m_client) { + m_client->showOnScreenEdge(); + unreserve(); + return; + } + handleAction(); + handleByCallback(); + }, Qt::QueuedConnection + ); + connect(m_gesture, &SwipeGesture::started, this, &Edge::startApproaching); + connect(m_gesture, &SwipeGesture::cancelled, this, &Edge::stopApproaching); + connect(m_gesture, &SwipeGesture::progress, this, + [this] (qreal progress) { + int factor = progress * 256.0f; + if (m_lastApproachingFactor != factor) { + m_lastApproachingFactor = factor; + emit approaching(border(), m_lastApproachingFactor/256.0f, m_approachGeometry); + } + } + ); } Edge::~Edge() @@ -436,13 +463,31 @@ void Edge::doUpdateBlocking() void Edge::doGeometryUpdate() { + if (isScreenEdge()) { + m_gesture->setStartGeometry(m_geometry); + m_gesture->setMinimumDelta(screens()->size(screens()->number(m_geometry.center())) * 0.2); + } } void Edge::activate() +{ + if (isScreenEdge() && !m_edges->isDesktopSwitching()) { + m_edges->gestureRecognizer()->registerGesture(m_gesture); + } + doActivate(); +} + +void Edge::doActivate() { } void Edge::deactivate() +{ + m_edges->gestureRecognizer()->unregisterGesture(m_gesture); + doDeactivate(); +} + +void Edge::doDeactivate() { } @@ -531,6 +576,27 @@ quint32 Edge::approachWindow() const return 0; } +void Edge::setBorder(ElectricBorder border) +{ + m_border = border; + switch (m_border) { + case ElectricTop: + m_gesture->setDirection(SwipeGesture::Direction::Down); + break; + case ElectricRight: + m_gesture->setDirection(SwipeGesture::Direction::Left); + break; + case ElectricBottom: + m_gesture->setDirection(SwipeGesture::Direction::Up); + break; + case ElectricLeft: + m_gesture->setDirection(SwipeGesture::Direction::Right); + break; + default: + break; + } +} + /********************************************************** * ScreenEdges *********************************************************/ @@ -551,6 +617,7 @@ ScreenEdges::ScreenEdges(QObject *parent) , m_actionBottom(ElectricActionNone) , m_actionBottomLeft(ElectricActionNone) , m_actionLeft(ElectricActionNone) + , m_gestureRecognizer(new GestureRecognizer(this)) { QWidget w; m_cornerOffset = (w.physicalDpiX() + w.physicalDpiY() + 5) / 6; diff --git a/screenedge.h b/screenedge.h index 0c76b06169..a65183b79b 100644 --- a/screenedge.h +++ b/screenedge.h @@ -44,7 +44,9 @@ class QMouseEvent; namespace KWin { class AbstractClient; +class GestureRecognizer; class ScreenEdges; +class SwipeGesture; class KWIN_EXPORT Edge : public QObject { @@ -103,12 +105,14 @@ protected: const ScreenEdges *edges() const; bool isBlocked() const; virtual void doGeometryUpdate(); - virtual void activate(); - virtual void deactivate(); + virtual void doActivate(); + virtual void doDeactivate(); virtual void doStartApproaching(); virtual void doStopApproaching(); virtual void doUpdateBlocking(); private: + void activate(); + void deactivate(); bool canActivate(const QPoint &cursorPos, const QDateTime &triggerTime); void handle(const QPoint &cursorPos); bool handleAction(); @@ -130,6 +134,7 @@ private: bool m_blocked; bool m_pushBackBlocked; AbstractClient *m_client; + SwipeGesture *m_gesture; }; /** @@ -304,6 +309,10 @@ public: ElectricBorderAction actionBottomLeft() const; ElectricBorderAction actionLeft() const; + GestureRecognizer *gestureRecognizer() const { + return m_gestureRecognizer; + } + public Q_SLOTS: void reconfigure(); /** @@ -358,6 +367,7 @@ private: ElectricBorderAction m_actionBottomLeft; ElectricBorderAction m_actionLeft; int m_cornerOffset; + GestureRecognizer *m_gestureRecognizer; KWIN_SINGLETON(ScreenEdges) }; @@ -412,11 +422,6 @@ inline void Edge::setAction(ElectricBorderAction action) m_action = action; } -inline void Edge::setBorder(ElectricBorder border) -{ - m_border = border; -} - inline ScreenEdges *Edge::edges() { return m_edges;