From 8e304963ad372559a0ae068570886196ca25add8 Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Wed, 23 Feb 2022 21:03:51 +0200 Subject: [PATCH] Make pointer focus handling less error prone Currently, if the pointer surface has to change between two surfaces, the compositor must do the following seat->setFocusedPointerSurface(nullptr); seat->notifyPointerMotion(newPos); seat->setFocusedPointerSurface(focus); The pointer motion is needed so the enter event has correct position, setFocusedPointerSurface(nullptr) is needed to avoid sending a bad motion event before the leave event. This change makes the pointer focus api less error prone by splitting setFocusedPointerSurface() in two functions - notifyPointerEnter() and notifyPointerLeave(). notifyPointerEnter() takes new focus surface as well as the position where the pointer has entered the surface so the focus update can be atomic and without any corner cases. notifyPointerLeave() is used to clear pointer focus. --- .../autotests/client/test_datadevice.cpp | 4 +- .../autotests/client/test_drag_drop.cpp | 10 +-- .../client/test_pointer_constraints.cpp | 4 +- .../autotests/client/test_wayland_seat.cpp | 51 +++++++-------- src/wayland/pointer_interface.cpp | 37 +++++++---- src/wayland/pointer_interface.h | 7 +-- src/wayland/seat_interface.cpp | 62 ++++++++++++------- src/wayland/seat_interface.h | 13 ++-- src/wayland/tests/renderingservertest.cpp | 4 +- 9 files changed, 104 insertions(+), 88 deletions(-) diff --git a/src/wayland/autotests/client/test_datadevice.cpp b/src/wayland/autotests/client/test_datadevice.cpp index b388d5115c..a9dcf8c5c8 100644 --- a/src/wayland/autotests/client/test_datadevice.cpp +++ b/src/wayland/autotests/client/test_datadevice.cpp @@ -249,7 +249,7 @@ void TestDataDevice::testDrag() m_seatInterface->notifyPointerFrame(); } if (hasPointerFocus) { - m_seatInterface->setFocusedPointerSurface(surfaceInterface); + m_seatInterface->notifyPointerEnter(surfaceInterface, QPointF(0, 0)); } if (hasGrab) { m_seatInterface->notifyPointerButton(Qt::LeftButton, PointerButtonState::Pressed); @@ -330,7 +330,7 @@ void TestDataDevice::testDragInternally() m_seatInterface->notifyPointerFrame(); } if (hasPointerFocus) { - m_seatInterface->setFocusedPointerSurface(surfaceInterface); + m_seatInterface->notifyPointerEnter(surfaceInterface, QPointF(0, 0)); } if (hasGrab) { m_seatInterface->notifyPointerButton(Qt::LeftButton, PointerButtonState::Pressed); diff --git a/src/wayland/autotests/client/test_drag_drop.cpp b/src/wayland/autotests/client/test_drag_drop.cpp index dd31622903..fdb61b1475 100644 --- a/src/wayland/autotests/client/test_drag_drop.cpp +++ b/src/wayland/autotests/client/test_drag_drop.cpp @@ -206,8 +206,8 @@ void TestDragAndDrop::testPointerDragAndDrop() // now we need to pass pointer focus to the Surface and simulate a button press QSignalSpy buttonPressSpy(m_pointer, &Pointer::buttonStateChanged); QVERIFY(buttonPressSpy.isValid()); - m_seatInterface->setFocusedPointerSurface(serverSurface); m_seatInterface->setTimestamp(2); + m_seatInterface->notifyPointerEnter(serverSurface, QPointF(0, 0)); m_seatInterface->notifyPointerButton(1, PointerButtonState::Pressed); m_seatInterface->notifyPointerFrame(); QVERIFY(buttonPressSpy.wait()); @@ -404,8 +404,8 @@ void TestDragAndDrop::testDragAndDropWithCancelByDestroyDataSource() // now we need to pass pointer focus to the Surface and simulate a button press QSignalSpy buttonPressSpy(m_pointer, &Pointer::buttonStateChanged); QVERIFY(buttonPressSpy.isValid()); - m_seatInterface->setFocusedPointerSurface(serverSurface); m_seatInterface->setTimestamp(2); + m_seatInterface->notifyPointerEnter(serverSurface, QPointF(0, 0)); m_seatInterface->notifyPointerButton(1, PointerButtonState::Pressed); m_seatInterface->notifyPointerFrame(); QVERIFY(buttonPressSpy.wait()); @@ -495,7 +495,7 @@ void TestDragAndDrop::testPointerEventsIgnored() QVERIFY(serverSurface); // pass it pointer focus - m_seatInterface->setFocusedPointerSurface(serverSurface); + m_seatInterface->notifyPointerEnter(serverSurface, QPointF(0, 0)); // create signal spies for all the pointer events QSignalSpy pointerEnteredSpy(m_pointer, &Pointer::entered); @@ -549,10 +549,10 @@ void TestDragAndDrop::testPointerEventsIgnored() m_seatInterface->notifyPointerAxis(Qt::Vertical, 5, 1, PointerAxisSource::Wheel); m_seatInterface->notifyPointerFrame(); m_seatInterface->setTimestamp(timestamp++); - m_seatInterface->setFocusedPointerSurface(nullptr); + m_seatInterface->notifyPointerLeave(); m_seatInterface->notifyPointerFrame(); m_seatInterface->setTimestamp(timestamp++); - m_seatInterface->setFocusedPointerSurface(serverSurface); + m_seatInterface->notifyPointerEnter(serverSurface, m_seatInterface->pointerPos()); m_seatInterface->notifyPointerFrame(); m_seatInterface->setTimestamp(timestamp++); m_seatInterface->notifyPointerMotion(QPointF(50, 50)); diff --git a/src/wayland/autotests/client/test_pointer_constraints.cpp b/src/wayland/autotests/client/test_pointer_constraints.cpp index c8064f1174..1c2e016687 100644 --- a/src/wayland/autotests/client/test_pointer_constraints.cpp +++ b/src/wayland/autotests/client/test_pointer_constraints.cpp @@ -222,7 +222,7 @@ void TestPointerConstraints::testLockPointer() // let's lock the surface QSignalSpy lockedChangedSpy(serverLockedPointer, &LockedPointerV1Interface::lockedChanged); QVERIFY(lockedChangedSpy.isValid()); - m_seatInterface->setFocusedPointerSurface(serverSurface); + m_seatInterface->notifyPointerEnter(serverSurface, QPointF(0, 0)); QSignalSpy pointerMotionSpy(m_pointer, &Pointer::motion); QVERIFY(pointerMotionSpy.isValid()); m_seatInterface->notifyPointerMotion(QPoint(0, 1)); @@ -339,7 +339,7 @@ void TestPointerConstraints::testConfinePointer() // let's confine the surface QSignalSpy confinedChangedSpy(serverConfinedPointer, &ConfinedPointerV1Interface::confinedChanged); QVERIFY(confinedChangedSpy.isValid()); - m_seatInterface->setFocusedPointerSurface(serverSurface); + m_seatInterface->notifyPointerEnter(serverSurface, QPointF(0, 0)); serverConfinedPointer->setConfined(true); QCOMPARE(serverConfinedPointer->isConfined(), true); QCOMPARE(confinedChangedSpy.count(), 1); diff --git a/src/wayland/autotests/client/test_wayland_seat.cpp b/src/wayland/autotests/client/test_wayland_seat.cpp index 313bfe0ab1..0c531748c5 100644 --- a/src/wayland/autotests/client/test_wayland_seat.cpp +++ b/src/wayland/autotests/client/test_wayland_seat.cpp @@ -351,8 +351,7 @@ void TestWaylandSeat::testPointer() QSignalSpy committedSpy(serverSurface, &KWaylandServer::SurfaceInterface::committed); QVERIFY(committedSpy.wait()); - m_seatInterface->notifyPointerMotion(QPoint(20, 18)); - m_seatInterface->setFocusedPointerSurface(serverSurface, QPoint(10, 15)); + m_seatInterface->notifyPointerEnter(serverSurface, QPointF(20, 18), QPointF(10, 15)); Pointer *p = m_seat->createPointer(m_seat); QSignalSpy frameSpy(p, &Pointer::frame); @@ -364,7 +363,7 @@ void TestWaylandSeat::testPointer() QVERIFY(frameSpy.wait()); QCOMPARE(frameSpy.count(), 1); - m_seatInterface->setFocusedPointerSurface(nullptr); + m_seatInterface->notifyPointerLeave(); serverSurface->client()->flush(); QVERIFY(frameSpy.wait()); QCOMPARE(frameSpy.count(), 2); @@ -389,7 +388,7 @@ void TestWaylandSeat::testPointer() QVERIFY(!p->enteredSurface()); QVERIFY(!cp.enteredSurface()); - m_seatInterface->setFocusedPointerSurface(serverSurface, QPoint(10, 15)); + m_seatInterface->notifyPointerEnter(serverSurface, QPointF(20, 18), QPointF(10, 15)); QCOMPARE(m_seatInterface->focusedPointerSurface(), serverSurface); QVERIFY(enteredSpy.wait()); QCOMPARE(enteredSpy.first().first().value(), m_display->serial()); @@ -489,7 +488,7 @@ void TestWaylandSeat::testPointer() QCOMPARE(buttonSpy.at(3).at(3).value(), KWayland::Client::Pointer::ButtonState::Released); // leave the surface - m_seatInterface->setFocusedPointerSurface(nullptr); + m_seatInterface->notifyPointerLeave(); QVERIFY(leftSpy.wait()); QCOMPARE(frameSpy.count(), 12); QCOMPARE(leftSpy.first().first().value(), m_display->serial()); @@ -501,7 +500,7 @@ void TestWaylandSeat::testPointer() QVERIFY(!relativeMotionSpy.wait(500)); // enter it again - m_seatInterface->setFocusedPointerSurface(serverSurface, QPoint(0, 0)); + m_seatInterface->notifyPointerEnter(serverSurface, QPointF(10, 16), QPointF(0, 0)); QVERIFY(enteredSpy.wait()); QCOMPARE(frameSpy.count(), 13); QCOMPARE(p->enteredSurface(), s); @@ -560,9 +559,8 @@ void TestWaylandSeat::testPointerTransformation() QSignalSpy committedSpy(serverSurface, &KWaylandServer::SurfaceInterface::committed); QVERIFY(committedSpy.wait()); - m_seatInterface->notifyPointerMotion(QPoint(20, 18)); QFETCH(QMatrix4x4, enterTransformation); - m_seatInterface->setFocusedPointerSurface(serverSurface, enterTransformation); + m_seatInterface->notifyPointerEnter(serverSurface, QPointF(20, 18), enterTransformation); QCOMPARE(m_seatInterface->focusedPointerSurfaceTransformation(), enterTransformation); // no pointer yet QVERIFY(m_seatInterface->focusedPointerSurface()); @@ -573,7 +571,7 @@ void TestWaylandSeat::testPointerTransformation() QVERIFY(frameSpy.wait()); const Pointer &cp = *p; - m_seatInterface->setFocusedPointerSurface(nullptr); + m_seatInterface->notifyPointerLeave(); serverSurface->client()->flush(); QTest::qWait(100); @@ -588,7 +586,7 @@ void TestWaylandSeat::testPointerTransformation() QVERIFY(!p->enteredSurface()); QVERIFY(!cp.enteredSurface()); - m_seatInterface->setFocusedPointerSurface(serverSurface, enterTransformation); + m_seatInterface->notifyPointerEnter(serverSurface, QPointF(20, 18), enterTransformation); QCOMPARE(m_seatInterface->focusedPointerSurface(), serverSurface); QVERIFY(enteredSpy.wait()); QCOMPARE(enteredSpy.first().first().value(), m_display->serial()); @@ -605,14 +603,14 @@ void TestWaylandSeat::testPointerTransformation() QCOMPARE(motionSpy.first().last().value(), quint32(1)); // leave the surface - m_seatInterface->setFocusedPointerSurface(nullptr); + m_seatInterface->notifyPointerLeave(); QVERIFY(leftSpy.wait()); QCOMPARE(leftSpy.first().first().value(), m_display->serial()); QVERIFY(!p->enteredSurface()); QVERIFY(!cp.enteredSurface()); // enter it again - m_seatInterface->setFocusedPointerSurface(serverSurface); + m_seatInterface->notifyPointerEnter(serverSurface, QPointF(10, 16)); QVERIFY(enteredSpy.wait()); QCOMPARE(p->enteredSurface(), s); QCOMPARE(cp.enteredSurface(), s); @@ -689,13 +687,11 @@ void TestWaylandSeat::testPointerButton() wl_display_flush(m_connection->display()); QCoreApplication::processEvents(); - m_seatInterface->notifyPointerMotion(QPoint(20, 18)); - m_seatInterface->setFocusedPointerSurface(serverSurface, QPoint(10, 15)); + m_seatInterface->notifyPointerEnter(serverSurface, QPointF(20, 18), QPointF(10, 15)); QVERIFY(m_seatInterface->focusedPointerSurface()); QCoreApplication::processEvents(); - m_seatInterface->setFocusedPointerSurface(serverSurface, QPoint(10, 15)); QFETCH(Qt::MouseButton, qtButton); QFETCH(quint32, waylandButton); quint32 msec = QDateTime::currentMSecsSinceEpoch(); @@ -782,8 +778,7 @@ void TestWaylandSeat::testPointerSubSurfaceTree() // first to the grandChild2 in the overlapped area quint32 timestamp = 1; m_seatInterface->setTimestamp(timestamp++); - m_seatInterface->notifyPointerMotion(QPointF(25, 50)); - m_seatInterface->setFocusedPointerSurface(serverSurface); + m_seatInterface->notifyPointerEnter(serverSurface, QPointF(25, 50)); QVERIFY(enteredSpy.wait()); QCOMPARE(enteredSpy.count(), 1); QCOMPARE(leftSpy.count(), 0); @@ -811,15 +806,14 @@ void TestWaylandSeat::testPointerSubSurfaceTree() QCOMPARE(pointer->enteredSurface(), childSurface.data()); // a leave for the whole surface m_seatInterface->setTimestamp(timestamp++); - m_seatInterface->setFocusedPointerSurface(nullptr); + m_seatInterface->notifyPointerLeave(); QVERIFY(leftSpy.wait()); QCOMPARE(enteredSpy.count(), 2); QCOMPARE(leftSpy.count(), 2); QCOMPARE(motionSpy.count(), 2); // a new enter on the main surface m_seatInterface->setTimestamp(timestamp++); - m_seatInterface->notifyPointerMotion(QPointF(75, 50)); - m_seatInterface->setFocusedPointerSurface(serverSurface); + m_seatInterface->notifyPointerEnter(serverSurface, QPointF(75, 50)); QVERIFY(enteredSpy.wait()); QCOMPARE(enteredSpy.count(), 3); QCOMPARE(leftSpy.count(), 2); @@ -880,7 +874,7 @@ void TestWaylandSeat::testPointerSwipeGesture() QSignalSpy committedSpy(serverSurface, &KWaylandServer::SurfaceInterface::committed); QVERIFY(committedSpy.wait()); - m_seatInterface->setFocusedPointerSurface(serverSurface); + m_seatInterface->notifyPointerEnter(serverSurface, QPointF(0, 0)); QCOMPARE(m_seatInterface->focusedPointerSurface(), serverSurface); QVERIFY(m_seatInterface->pointer()); @@ -939,7 +933,7 @@ void TestWaylandSeat::testPointerSwipeGesture() QVERIFY(startSpy.wait()); // unsetting the focused pointer surface should not change anything - m_seatInterface->setFocusedPointerSurface(nullptr); + m_seatInterface->notifyPointerLeave(); m_seatInterface->setTimestamp(timestamp++); m_seatInterface->updatePointerSwipeGesture(QSizeF(6, 7)); QVERIFY(updateSpy.wait()); @@ -1005,7 +999,7 @@ void TestWaylandSeat::testPointerPinchGesture() QSignalSpy committedSpy(serverSurface, &KWaylandServer::SurfaceInterface::committed); QVERIFY(committedSpy.wait()); - m_seatInterface->setFocusedPointerSurface(serverSurface); + m_seatInterface->notifyPointerEnter(serverSurface, QPointF(0, 0)); QCOMPARE(m_seatInterface->focusedPointerSurface(), serverSurface); QVERIFY(m_seatInterface->pointer()); @@ -1068,7 +1062,7 @@ void TestWaylandSeat::testPointerPinchGesture() QVERIFY(startSpy.wait()); // unsetting the focused pointer surface should not change anything - m_seatInterface->setFocusedPointerSurface(nullptr); + m_seatInterface->notifyPointerLeave(); m_seatInterface->setTimestamp(timestamp++); m_seatInterface->updatePointerPinchGesture(QSizeF(6, 7), 2, -45); QVERIFY(updateSpy.wait()); @@ -1156,7 +1150,7 @@ void TestWaylandSeat::testPointerHoldGesture() QSignalSpy committedSpy(serverSurface, &KWaylandServer::SurfaceInterface::committed); QVERIFY(committedSpy.wait()); - m_seatInterface->setFocusedPointerSurface(serverSurface); + m_seatInterface->notifyPointerEnter(serverSurface, QPointF(0, 0)); QCOMPARE(m_seatInterface->focusedPointerSurface(), serverSurface); QVERIFY(m_seatInterface->pointer()); @@ -1237,7 +1231,7 @@ void TestWaylandSeat::testPointerAxis() QSignalSpy committedSpy(serverSurface, &KWaylandServer::SurfaceInterface::committed); QVERIFY(committedSpy.wait()); - m_seatInterface->setFocusedPointerSurface(serverSurface); + m_seatInterface->notifyPointerEnter(serverSurface, QPointF(0, 0)); QCOMPARE(m_seatInterface->focusedPointerSurface(), serverSurface); QSignalSpy frameSpy(pointer.data(), &Pointer::frame); QVERIFY(frameSpy.isValid()); @@ -1350,8 +1344,7 @@ void TestWaylandSeat::testCursor() QSignalSpy enteredSpy(p.data(), &KWayland::Client::Pointer::entered); QVERIFY(enteredSpy.isValid()); - m_seatInterface->notifyPointerMotion(QPoint(20, 18)); - m_seatInterface->setFocusedPointerSurface(serverSurface, QPoint(10, 15)); + m_seatInterface->notifyPointerEnter(serverSurface, QPointF(20, 18), QPointF(10, 15)); quint32 serial = m_seatInterface->display()->serial(); QVERIFY(enteredSpy.wait()); QCOMPARE(enteredSpy.first().first().value(), serial); @@ -1466,7 +1459,7 @@ void TestWaylandSeat::testCursorDamage() QVERIFY(committedSpy.wait()); // send enter to the surface - m_seatInterface->setFocusedPointerSurface(serverSurface); + m_seatInterface->notifyPointerEnter(serverSurface, QPointF(0, 0)); QVERIFY(enteredSpy.wait()); // create a signal spy for the cursor changed signal diff --git a/src/wayland/pointer_interface.cpp b/src/wayland/pointer_interface.cpp index b552ac4406..71d7831374 100644 --- a/src/wayland/pointer_interface.cpp +++ b/src/wayland/pointer_interface.cpp @@ -152,7 +152,7 @@ SurfaceInterface *PointerInterface::focusedSurface() const return d->focusedSurface; } -void PointerInterface::setFocusedSurface(SurfaceInterface *surface, const QPointF &position, quint32 serial) +void PointerInterface::sendEnter(SurfaceInterface *surface, const QPointF &position, quint32 serial) { if (d->focusedSurface == surface) { return; @@ -160,26 +160,39 @@ void PointerInterface::setFocusedSurface(SurfaceInterface *surface, const QPoint if (d->focusedSurface) { d->sendLeave(serial); - if (!surface || d->focusedSurface->client() != surface->client()) { + if (d->focusedSurface->client() != surface->client()) { d->sendFrame(); } disconnect(d->destroyConnection); } d->focusedSurface = surface; - - if (d->focusedSurface) { - d->destroyConnection = connect(d->focusedSurface, &SurfaceInterface::aboutToBeDestroyed, this, [this]() { - d->sendLeave(d->seat->display()->nextSerial()); - d->sendFrame(); - d->focusedSurface = nullptr; - Q_EMIT focusedSurfaceChanged(); - }); - d->sendEnter(position, serial); + d->destroyConnection = connect(d->focusedSurface, &SurfaceInterface::aboutToBeDestroyed, this, [this]() { + d->sendLeave(d->seat->display()->nextSerial()); d->sendFrame(); - d->lastPosition = position; + d->focusedSurface = nullptr; + Q_EMIT focusedSurfaceChanged(); + }); + + d->sendEnter(position, serial); + d->sendFrame(); + d->lastPosition = position; + + Q_EMIT focusedSurfaceChanged(); +} + +void PointerInterface::sendLeave(quint32 serial) +{ + if (!d->focusedSurface) { + return; } + d->sendLeave(serial); + d->sendFrame(); + + d->focusedSurface = nullptr; + disconnect(d->destroyConnection); + Q_EMIT focusedSurfaceChanged(); } diff --git a/src/wayland/pointer_interface.h b/src/wayland/pointer_interface.h index 1693206204..3397c78cf6 100644 --- a/src/wayland/pointer_interface.h +++ b/src/wayland/pointer_interface.h @@ -41,11 +41,6 @@ public: * the effective focused surface. */ SurfaceInterface *focusedSurface() const; - /** - * Sets the effective focused pointer surface to @a surface. The @a position indicates - * where the pointer has entered the surface. - */ - void setFocusedSurface(SurfaceInterface *surface, const QPointF &position, quint32 serial); Cursor *cursor() const; @@ -59,6 +54,8 @@ public: */ static PointerInterface *get(wl_resource *native); + void sendEnter(SurfaceInterface *surface, const QPointF &position, quint32 serial); + void sendLeave(quint32 serial); void sendButton(quint32 button, PointerButtonState state, quint32 serial); void sendAxis(Qt::Orientation orientation, qreal delta, qint32 discreteDelta, PointerAxisSource source); void sendMotion(const QPointF &position); diff --git a/src/wayland/seat_interface.cpp b/src/wayland/seat_interface.cpp index 2bdfa5543a..91fd81f73b 100644 --- a/src/wayland/seat_interface.cpp +++ b/src/wayland/seat_interface.cpp @@ -481,7 +481,7 @@ void SeatInterface::notifyPointerMotion(const QPointF &pos) } if (d->pointer->focusedSurface() != effectiveFocusedSurface) { - d->pointer->setFocusedSurface(effectiveFocusedSurface, localPosition, display()->nextSerial()); + d->pointer->sendEnter(effectiveFocusedSurface, localPosition, display()->nextSerial()); } d->pointer->sendMotion(localPosition); @@ -552,17 +552,17 @@ SurfaceInterface *SeatInterface::focusedPointerSurface() const return d->globalPointer.focus.surface; } -void SeatInterface::setFocusedPointerSurface(SurfaceInterface *surface, const QPointF &surfacePosition) +void SeatInterface::notifyPointerEnter(SurfaceInterface *surface, const QPointF &position, const QPointF &surfacePosition) { QMatrix4x4 m; m.translate(-surfacePosition.x(), -surfacePosition.y()); - setFocusedPointerSurface(surface, m); + notifyPointerEnter(surface, position, m); if (d->globalPointer.focus.surface) { d->globalPointer.focus.offset = surfacePosition; } } -void SeatInterface::setFocusedPointerSurface(SurfaceInterface *surface, const QMatrix4x4 &transformation) +void SeatInterface::notifyPointerEnter(SurfaceInterface *surface, const QPointF &position, const QMatrix4x4 &transformation) { if (!d->pointer) { return; @@ -579,28 +579,42 @@ void SeatInterface::setFocusedPointerSurface(SurfaceInterface *surface, const QM } d->globalPointer.focus = SeatInterfacePrivate::Pointer::Focus(); d->globalPointer.focus.surface = surface; - if (d->globalPointer.focus.surface) { - d->globalPointer.focus.destroyConnection = connect(surface, &QObject::destroyed, this, [this] { - d->globalPointer.focus = SeatInterfacePrivate::Pointer::Focus(); - }); - d->globalPointer.focus.serial = serial; - d->globalPointer.focus.transformation = transformation; - d->globalPointer.focus.offset = QPointF(); + d->globalPointer.focus.destroyConnection = connect(surface, &QObject::destroyed, this, [this] { + d->globalPointer.focus = SeatInterfacePrivate::Pointer::Focus(); + }); + d->globalPointer.focus.serial = serial; + d->globalPointer.focus.transformation = transformation; + d->globalPointer.focus.offset = QPointF(); + + d->globalPointer.pos = position; + QPointF localPosition = focusedPointerSurfaceTransformation().map(position); + SurfaceInterface *effectiveFocusedSurface = surface->inputSurfaceAt(localPosition); + if (!effectiveFocusedSurface) { + effectiveFocusedSurface = surface; + } + if (surface != effectiveFocusedSurface) { + localPosition = surface->mapToChild(effectiveFocusedSurface, localPosition); + } + d->pointer->sendEnter(effectiveFocusedSurface, localPosition, serial); +} + +void SeatInterface::notifyPointerLeave() +{ + if (!d->pointer) { + return; + } + if (d->drag.mode == SeatInterfacePrivate::Drag::Mode::Pointer) { + // ignore + return; } - if (surface) { - QPointF localPosition = focusedPointerSurfaceTransformation().map(pointerPos()); - SurfaceInterface *effectiveFocusedSurface = surface->inputSurfaceAt(localPosition); - if (!effectiveFocusedSurface) { - effectiveFocusedSurface = surface; - } - if (surface != effectiveFocusedSurface) { - localPosition = surface->mapToChild(effectiveFocusedSurface, localPosition); - } - d->pointer->setFocusedSurface(effectiveFocusedSurface, localPosition, serial); - } else { - d->pointer->setFocusedSurface(nullptr, QPointF(), serial); + if (d->globalPointer.focus.surface) { + disconnect(d->globalPointer.focus.destroyConnection); } + d->globalPointer.focus = SeatInterfacePrivate::Pointer::Focus(); + + const quint32 serial = d->display->nextSerial(); + d->pointer->sendLeave(serial); } void SeatInterface::setFocusedPointerSurfacePosition(const QPointF &surfacePosition) @@ -1066,7 +1080,7 @@ void SeatInterface::notifyTouchDown(qint32 id, const QPointF &globalPosition) if (touchPrivate->touchesForClient(focusedTouchSurface()->client()).isEmpty()) { // If the client did not bind the touch interface fall back // to at least emulating touch through pointer events. - d->pointer->setFocusedSurface(focusedTouchSurface(), pos, serial); + d->pointer->sendEnter(focusedTouchSurface(), pos, serial); d->pointer->sendMotion(pos); d->pointer->sendFrame(); } diff --git a/src/wayland/seat_interface.h b/src/wayland/seat_interface.h index 4aee61abe0..00d35e71ef 100644 --- a/src/wayland/seat_interface.h +++ b/src/wayland/seat_interface.h @@ -104,9 +104,8 @@ enum class KeyboardKeyState : quint32 { * * @code * // example for pointer - * seat->setFocusedPointerSurface(surface, QPointF(100, 200)); // surface at it's global position * seat->setTimestamp(100); - * seat->notifyPointerMotion(QPointF(350, 210)); // global pos, local pos in surface: 250,10 + * seat->notifyPointerEnter(surface, QPointF(350, 210), QPointF(100, 200)); // surface at it's global position * seat->notifyPointerFrame(); * seat->setTimestamp(110); * seat->notifyPointerButton(Qt::LeftButton, PointerButtonState::Pressed); @@ -274,7 +273,7 @@ public: * @see setFocusedPointerSurfaceTransformation * @see focusedPointerSurfaceTransformation */ - void setFocusedPointerSurface(SurfaceInterface *surface, const QPointF &surfacePosition = QPoint()); + void notifyPointerEnter(SurfaceInterface *surface, const QPointF &position, const QPointF &surfacePosition = QPointF()); /** * Sets the focused pointer @p surface. * All pointer events will be sent to the @p surface till a new focused pointer surface gets @@ -298,10 +297,12 @@ public: * @see setFocusedPointerSurfaceTransformation * @see focusedPointerSurfaceTransformation */ - void setFocusedPointerSurface(SurfaceInterface *surface, const QMatrix4x4 &transformation); + void notifyPointerEnter(SurfaceInterface *surface, const QPointF &position, const QMatrix4x4 &transformation); + void notifyPointerLeave(); /** * @returns The currently focused pointer surface, that is the surface receiving pointer events. - * @see setFocusedPointerSurface + * @see notifyPointerEnter + * @see notifyPointerLeave */ SurfaceInterface *focusedPointerSurface() const; PointerInterface *pointer() const; @@ -315,7 +316,6 @@ public: * * @param surfacePosition The new global position of the focused pointer surface * @see focusedPointerSurface - * @see setFocusedPointerSurface * @see focusedPointerSurfaceTransformation * @see setFocusedPointerSurfaceTransformation */ @@ -323,7 +323,6 @@ public: /** * @returns The position of the focused pointer surface in global coordinates. * @see setFocusedPointerSurfacePosition - * @see setFocusedPointerSurface * @see focusedPointerSurfaceTransformation */ QPointF focusedPointerSurfacePosition() const; diff --git a/src/wayland/tests/renderingservertest.cpp b/src/wayland/tests/renderingservertest.cpp index ffcde65f2f..f3a4bbae29 100644 --- a/src/wayland/tests/renderingservertest.cpp +++ b/src/wayland/tests/renderingservertest.cpp @@ -130,7 +130,7 @@ void CompositorWindow::updateFocus() if (it == m_stackingOrder.constEnd()) { return; } - m_seat->setFocusedPointerSurface((*it)->surface()); + m_seat->notifyPointerEnter((*it)->surface(), m_seat->pointerPos()); m_seat->setFocusedKeyboardSurface((*it)->surface()); } @@ -195,7 +195,7 @@ void CompositorWindow::mousePressEvent(QMouseEvent *event) QWidget::mousePressEvent(event); if (!m_seat->focusedPointerSurface()) { if (!m_stackingOrder.isEmpty()) { - m_seat->setFocusedPointerSurface(m_stackingOrder.last()->surface()); + m_seat->notifyPointerEnter(m_stackingOrder.last()->surface(), event->globalPos()); } } m_seat->setTimestamp(event->timestamp());