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.
This commit is contained in:
Vlad Zahorodnii 2021-02-16 13:51:23 +02:00
parent 8f2520e00e
commit d23dab7be9
4 changed files with 20 additions and 21 deletions

View file

@ -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);
}

View file

@ -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()

View file

@ -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();
}

View file

@ -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<qint32> 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;
};
}