From d23dab7be99c781e4c0c1ed52e2b78ddf8e0a9f1 Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Tue, 16 Feb 2021 13:51:23 +0200 Subject: [PATCH] wayland: Fix handling of synthetic touch cancel events In case the compositor wants to cancel a touch sequence, we need to ignore subsequent touch motion and touch up events until a new sequence is initiated by the user. Previously, it was implicitly handled by clearing the mapping table between the touch slots and touch ids generated by kwayland-server. --- autotests/integration/touch_input_test.cpp | 2 -- src/input.cpp | 4 +-- src/touch_input.cpp | 29 ++++++++++++---------- src/touch_input.h | 6 ++--- 4 files changed, 20 insertions(+), 21 deletions(-) diff --git a/autotests/integration/touch_input_test.cpp b/autotests/integration/touch_input_test.cpp index 50969489fd..d7abec3696 100644 --- a/autotests/integration/touch_input_test.cpp +++ b/autotests/integration/touch_input_test.cpp @@ -275,8 +275,6 @@ void TouchInputTest::testTouchPointCount() kwinApp()->platform()->touchUp(1, timestamp++); QCOMPARE(kwinApp()->platform()->touchPointCount(), 2); - kwinApp()->platform()->cancelTouchSequence(); - QCOMPARE(kwinApp()->platform()->touchPointCount(), 1); kwinApp()->platform()->cancelTouchSequence(); QCOMPARE(kwinApp()->platform()->touchPointCount(), 0); } diff --git a/src/input.cpp b/src/input.cpp index 6f838d1d39..fdbad49aa6 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -2303,7 +2303,7 @@ void InputRedirection::setupLibInput() connect(conn, &LibInput::Connection::touchDown, m_touch, &TouchInputRedirection::processDown); connect(conn, &LibInput::Connection::touchUp, m_touch, &TouchInputRedirection::processUp); connect(conn, &LibInput::Connection::touchMotion, m_touch, &TouchInputRedirection::processMotion); - connect(conn, &LibInput::Connection::touchCanceled, m_touch, &TouchInputRedirection::processCancel); + connect(conn, &LibInput::Connection::touchCanceled, m_touch, &TouchInputRedirection::cancel); connect(conn, &LibInput::Connection::touchFrame, m_touch, &TouchInputRedirection::frame); auto handleSwitchEvent = [this] (SwitchEvent::State state, quint32 time, quint64 timeMicroseconds, LibInput::Device *device) { SwitchEvent event(state, time, timeMicroseconds, device); @@ -2496,7 +2496,7 @@ void InputRedirection::processTouchMotion(qint32 id, const QPointF &pos, quint32 void InputRedirection::cancelTouchSequence() { - m_touch->processCancel(); + m_touch->cancel(); } void InputRedirection::cancelTouch() diff --git a/src/touch_input.cpp b/src/touch_input.cpp index 715d052931..fa8744f20f 100644 --- a/src/touch_input.cpp +++ b/src/touch_input.cpp @@ -66,7 +66,7 @@ bool TouchInputRedirection::focusUpdatesBlocked() if (waylandServer()->seat()->isDragTouch()) { return true; } - if (m_touches > 1) { + if (m_activeTouchPoints.count() > 1) { // first touch defines focus return true; } @@ -75,9 +75,8 @@ bool TouchInputRedirection::focusUpdatesBlocked() bool TouchInputRedirection::positionValid() const { - Q_ASSERT(m_touches >= 0); // we can only determine a position with at least one touch point - return m_touches; + return !m_activeTouchPoints.isEmpty(); } void TouchInputRedirection::focusUpdate(Toplevel *focusOld, Toplevel *focusNow) @@ -144,8 +143,8 @@ void TouchInputRedirection::processDown(qint32 id, const QPointF &pos, quint32 t } m_lastPosition = pos; m_windowUpdatedInCycle = false; - m_touches++; - if (m_touches == 1) { + m_activeTouchPoints.insert(id); + if (m_activeTouchPoints.count() == 1) { update(); } input()->processSpies(std::bind(&InputEventSpy::touchDown, std::placeholders::_1, id, pos, time)); @@ -159,12 +158,14 @@ void TouchInputRedirection::processUp(qint32 id, quint32 time, LibInput::Device if (!inited()) { return; } + if (!m_activeTouchPoints.remove(id)) { + return; + } m_windowUpdatedInCycle = false; input()->processSpies(std::bind(&InputEventSpy::touchUp, std::placeholders::_1, id, time)); input()->processFilters(std::bind(&InputEventFilter::touchUp, std::placeholders::_1, id, time)); m_windowUpdatedInCycle = false; - m_touches--; - if (m_touches == 0) { + if (m_activeTouchPoints.count() == 0) { update(); } } @@ -175,6 +176,9 @@ void TouchInputRedirection::processMotion(qint32 id, const QPointF &pos, quint32 if (!inited()) { return; } + if (!m_activeTouchPoints.contains(id)) { + return; + } m_lastPosition = pos; m_windowUpdatedInCycle = false; input()->processSpies(std::bind(&InputEventSpy::touchMotion, std::placeholders::_1, id, pos, time)); @@ -182,17 +186,16 @@ void TouchInputRedirection::processMotion(qint32 id, const QPointF &pos, quint32 m_windowUpdatedInCycle = false; } -void TouchInputRedirection::processCancel() -{ - m_touches--; - cancel(); -} - void TouchInputRedirection::cancel() { if (!inited()) { return; } + // If the touch sequence is artificially cancelled by the compositor, touch motion and touch + // up events will be silently ignored and won't be passed down through the event filter chain. + // If the touch sequence is cancelled because we received a TOUCH_CANCEL event from libinput, + // the compositor will not receive any TOUCH_MOTION or TOUCH_UP events for that slot. + m_activeTouchPoints.clear(); waylandServer()->seat()->cancelTouchSequence(); } diff --git a/src/touch_input.h b/src/touch_input.h index 0dcb4f08cb..b2f3801616 100644 --- a/src/touch_input.h +++ b/src/touch_input.h @@ -46,7 +46,6 @@ public: void processDown(qint32 id, const QPointF &pos, quint32 time, LibInput::Device *device = nullptr); void processUp(qint32 id, quint32 time, LibInput::Device *device = nullptr); void processMotion(qint32 id, const QPointF &pos, quint32 time, LibInput::Device *device = nullptr); - void processCancel(); void cancel(); void frame(); @@ -68,7 +67,7 @@ public: } int touchPointCount() const { - return m_touches; + return m_activeTouchPoints.count(); } private: @@ -77,14 +76,13 @@ private: void focusUpdate(Toplevel *focusOld, Toplevel *focusNow) override; + QSet m_activeTouchPoints; bool m_inited = false; qint32 m_decorationId = -1; qint32 m_internalId = -1; QMetaObject::Connection m_focusGeometryConnection; bool m_windowUpdatedInCycle = false; QPointF m_lastPosition; - - int m_touches = 0; }; }