From 178c5d0595581acc40bfeab48b4008d9e9426f37 Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Sat, 13 Feb 2021 00:29:45 +0200 Subject: [PATCH] Rewrite wl_pointer implementation with new approach With this design, a single PointerInterface manages multiple wl_pointer objects. This makes the API tidier and allows implementing things such as keyboard grabs more easier. In addition to that, the PointerInterface doesn't inject its own frame events anymore. It's up to the compositor to decide when it has to be sent. However, the PointerInterface may still send a frame event if the pointer focus changes. Besides re-writing the pointer interface, this change, unfortunately, also affects the implementation of pointer-gestures and relative-pointer protocols because previously they were coupled to individual instances of PointerInterface. --- .../autotests/client/test_datadevice.cpp | 4 + .../autotests/client/test_drag_drop.cpp | 22 +- .../client/test_pointer_constraints.cpp | 3 + .../autotests/client/test_wayland_seat.cpp | 235 ++++--- src/wayland/autotests/server/test_seat.cpp | 11 +- src/wayland/pointer_interface.cpp | 574 ++++++++---------- src/wayland/pointer_interface.h | 98 +-- src/wayland/pointer_interface_p.h | 64 +- src/wayland/pointergestures_v1_interface.cpp | 216 +++++-- src/wayland/pointergestures_v1_interface_p.h | 32 +- src/wayland/relativepointer_v1_interface.cpp | 52 +- src/wayland/relativepointer_v1_interface_p.h | 13 +- src/wayland/seat_interface.cpp | 369 +++++------ src/wayland/seat_interface.h | 30 +- src/wayland/seat_interface_p.h | 7 +- src/wayland/tests/renderingservertest.cpp | 8 +- 16 files changed, 854 insertions(+), 884 deletions(-) diff --git a/src/wayland/autotests/client/test_datadevice.cpp b/src/wayland/autotests/client/test_datadevice.cpp index 30d052bb40..6b8af7d211 100644 --- a/src/wayland/autotests/client/test_datadevice.cpp +++ b/src/wayland/autotests/client/test_datadevice.cpp @@ -254,12 +254,14 @@ void TestDataDevice::testDrag() if (!hasGrab) { // in case we don't have grab, still generate a pointer serial to make it more interesting m_seatInterface->pointerButtonPressed(Qt::LeftButton); + m_seatInterface->pointerFrame(); } if (hasPointerFocus) { m_seatInterface->setFocusedPointerSurface(surfaceInterface); } if (hasGrab) { m_seatInterface->pointerButtonPressed(Qt::LeftButton); + m_seatInterface->pointerFrame(); } // TODO: This test would be better, if it could also test that a client trying to guess @@ -333,12 +335,14 @@ void TestDataDevice::testDragInternally() if (!hasGrab) { // in case we don't have grab, still generate a pointer serial to make it more interesting m_seatInterface->pointerButtonPressed(Qt::LeftButton); + m_seatInterface->pointerFrame(); } if (hasPointerFocus) { m_seatInterface->setFocusedPointerSurface(surfaceInterface); } if (hasGrab) { m_seatInterface->pointerButtonPressed(Qt::LeftButton); + m_seatInterface->pointerFrame(); } // TODO: This test would be better, if it could also test that a client trying to guess diff --git a/src/wayland/autotests/client/test_drag_drop.cpp b/src/wayland/autotests/client/test_drag_drop.cpp index 9ee65176eb..b5fc72f9e5 100644 --- a/src/wayland/autotests/client/test_drag_drop.cpp +++ b/src/wayland/autotests/client/test_drag_drop.cpp @@ -209,6 +209,7 @@ void TestDragAndDrop::testPointerDragAndDrop() m_seatInterface->setFocusedPointerSurface(serverSurface); m_seatInterface->setTimestamp(2); m_seatInterface->pointerButtonPressed(1); + m_seatInterface->pointerFrame(); QVERIFY(buttonPressSpy.wait()); QCOMPARE(buttonPressSpy.first().at(1).value(), quint32(2)); @@ -256,6 +257,7 @@ void TestDragAndDrop::testPointerDragAndDrop() // simulate motion m_seatInterface->setTimestamp(3); m_seatInterface->setPointerPos(QPointF(3, 3)); + m_seatInterface->pointerFrame(); QVERIFY(dragMotionSpy.wait()); QCOMPARE(dragMotionSpy.count(), 1); QCOMPARE(dragMotionSpy.first().first().toPointF(), QPointF(3, 3)); @@ -268,6 +270,7 @@ void TestDragAndDrop::testPointerDragAndDrop() QVERIFY(droppedSpy.isValid()); m_seatInterface->setTimestamp(4); m_seatInterface->pointerButtonReleased(1); + m_seatInterface->pointerFrame(); QVERIFY(sourceDropSpy.isEmpty()); QVERIFY(droppedSpy.wait()); QCOMPARE(sourceDropSpy.count(), 1); @@ -405,6 +408,7 @@ void TestDragAndDrop::testDragAndDropWithCancelByDestroyDataSource() m_seatInterface->setFocusedPointerSurface(serverSurface); m_seatInterface->setTimestamp(2); m_seatInterface->pointerButtonPressed(1); + m_seatInterface->pointerFrame(); QVERIFY(buttonPressSpy.wait()); QCOMPARE(buttonPressSpy.first().at(1).value(), quint32(2)); @@ -452,6 +456,7 @@ void TestDragAndDrop::testDragAndDropWithCancelByDestroyDataSource() // simulate motion m_seatInterface->setTimestamp(3); m_seatInterface->setPointerPos(QPointF(3, 3)); + m_seatInterface->pointerFrame(); QVERIFY(dragMotionSpy.wait()); QCOMPARE(dragMotionSpy.count(), 1); QCOMPARE(dragMotionSpy.first().first().toPointF(), QPointF(3, 3)); @@ -472,6 +477,7 @@ void TestDragAndDrop::testDragAndDropWithCancelByDestroyDataSource() QVERIFY(droppedSpy.isValid()); m_seatInterface->setTimestamp(4); m_seatInterface->pointerButtonReleased(1); + m_seatInterface->pointerFrame(); QVERIFY(!droppedSpy.wait(500)); // verify that we did not get any further input events @@ -511,7 +517,8 @@ void TestDragAndDrop::testPointerEventsIgnored() m_seatInterface->setTimestamp(timestamp++); m_seatInterface->setPointerPos(QPointF(10, 10)); m_seatInterface->setTimestamp(timestamp++); - m_seatInterface->pointerAxis(Qt::Vertical, 5); + m_seatInterface->pointerAxis(Qt::Vertical, 5, 1, PointerAxisSource::Wheel); + m_seatInterface->pointerFrame(); // verify that we have those QVERIFY(axisSpy.wait()); QCOMPARE(axisSpy.count(), 1); @@ -523,6 +530,7 @@ void TestDragAndDrop::testPointerEventsIgnored() // let's start the drag m_seatInterface->setTimestamp(timestamp++); m_seatInterface->pointerButtonPressed(1); + m_seatInterface->pointerFrame(); QVERIFY(buttonSpy.wait()); QCOMPARE(buttonSpy.count(), 1); m_dataDevice->startDrag(buttonSpy.first().first().value(), m_dataSource, s.data()); @@ -531,24 +539,32 @@ void TestDragAndDrop::testPointerEventsIgnored() // now simulate all the possible pointer interactions m_seatInterface->setTimestamp(timestamp++); m_seatInterface->pointerButtonPressed(2); + m_seatInterface->pointerFrame(); m_seatInterface->setTimestamp(timestamp++); m_seatInterface->pointerButtonReleased(2); + m_seatInterface->pointerFrame(); m_seatInterface->setTimestamp(timestamp++); - m_seatInterface->pointerAxis(Qt::Vertical, 5); + m_seatInterface->pointerAxis(Qt::Vertical, 5, 1, PointerAxisSource::Wheel); + m_seatInterface->pointerFrame(); m_seatInterface->setTimestamp(timestamp++); - m_seatInterface->pointerAxis(Qt::Horizontal, 5); + m_seatInterface->pointerAxis(Qt::Vertical, 5, 1, PointerAxisSource::Wheel); + m_seatInterface->pointerFrame(); m_seatInterface->setTimestamp(timestamp++); m_seatInterface->setFocusedPointerSurface(nullptr); + m_seatInterface->pointerFrame(); m_seatInterface->setTimestamp(timestamp++); m_seatInterface->setFocusedPointerSurface(serverSurface); + m_seatInterface->pointerFrame(); m_seatInterface->setTimestamp(timestamp++); m_seatInterface->setPointerPos(QPointF(50, 50)); + m_seatInterface->pointerFrame(); // last but not least, simulate the drop QSignalSpy cancelledSpy(m_dataSource, &DataSource::cancelled); QVERIFY(cancelledSpy.isValid()); m_seatInterface->setTimestamp(timestamp++); m_seatInterface->pointerButtonReleased(1); + m_seatInterface->pointerFrame(); QVERIFY(cancelledSpy.wait()); // all the changes should have been ignored diff --git a/src/wayland/autotests/client/test_pointer_constraints.cpp b/src/wayland/autotests/client/test_pointer_constraints.cpp index e27a80e2d3..9422cd0824 100644 --- a/src/wayland/autotests/client/test_pointer_constraints.cpp +++ b/src/wayland/autotests/client/test_pointer_constraints.cpp @@ -225,11 +225,13 @@ void TestPointerConstraints::testLockPointer() QSignalSpy pointerMotionSpy(m_pointer, &Pointer::motion); QVERIFY(pointerMotionSpy.isValid()); m_seatInterface->setPointerPos(QPoint(0, 1)); + m_seatInterface->pointerFrame(); QVERIFY(pointerMotionSpy.wait()); serverLockedPointer->setLocked(true); QCOMPARE(serverLockedPointer->isLocked(), true); m_seatInterface->setPointerPos(QPoint(1, 1)); + m_seatInterface->pointerFrame(); QCOMPARE(lockedChangedSpy.count(), 1); QCOMPARE(pointerMotionSpy.count(), 1); QVERIFY(lockedSpy.isEmpty()); @@ -257,6 +259,7 @@ void TestPointerConstraints::testLockPointer() // now motion should work again m_seatInterface->setPointerPos(QPoint(0, 1)); + m_seatInterface->pointerFrame(); QVERIFY(pointerMotionSpy.wait()); QCOMPARE(pointerMotionSpy.count(), 2); diff --git a/src/wayland/autotests/client/test_wayland_seat.cpp b/src/wayland/autotests/client/test_wayland_seat.cpp index cf8208e629..ddc69799da 100644 --- a/src/wayland/autotests/client/test_wayland_seat.cpp +++ b/src/wayland/autotests/client/test_wayland_seat.cpp @@ -345,16 +345,16 @@ void TestWaylandSeat::testPointer() SurfaceInterface *serverSurface = surfaceCreatedSpy.first().first().value(); QVERIFY(serverSurface); - QSignalSpy focusedPointerChangedSpy(m_seatInterface, &SeatInterface::focusedPointerChanged); - QVERIFY(focusedPointerChangedSpy.isValid()); + QImage image(QSize(100, 100), QImage::Format_ARGB32_Premultiplied); + image.fill(Qt::black); + s->attachBuffer(m_shm->createBuffer(image)); + s->damage(image.rect()); + s->commit(Surface::CommitFlag::None); + QSignalSpy committedSpy(serverSurface, &KWaylandServer::SurfaceInterface::committed); + QVERIFY(committedSpy.wait()); m_seatInterface->setPointerPos(QPoint(20, 18)); m_seatInterface->setFocusedPointerSurface(serverSurface, QPoint(10, 15)); - QCOMPARE(focusedPointerChangedSpy.count(), 1); - QVERIFY(!focusedPointerChangedSpy.first().first().value()); - // no pointer yet - QVERIFY(m_seatInterface->focusedPointerSurface()); - QVERIFY(!m_seatInterface->focusedPointer()); Pointer *p = m_seat->createPointer(m_seat); QSignalSpy frameSpy(p, &Pointer::frame); @@ -363,20 +363,10 @@ void TestWaylandSeat::testPointer() QVERIFY(p->isValid()); QScopedPointer relativePointer(m_relativePointerManager->createRelativePointer(p)); QVERIFY(relativePointer->isValid()); - QSignalSpy pointerCreatedSpy(m_seatInterface, &KWaylandServer::SeatInterface::pointerCreated); - QVERIFY(pointerCreatedSpy.isValid()); - // once the pointer is created it should be set as the focused pointer - QVERIFY(pointerCreatedSpy.wait()); - QVERIFY(m_seatInterface->focusedPointer()); - QCOMPARE(pointerCreatedSpy.first().first().value(), m_seatInterface->focusedPointer()); - QCOMPARE(focusedPointerChangedSpy.count(), 2); - QCOMPARE(focusedPointerChangedSpy.last().first().value(), m_seatInterface->focusedPointer()); QVERIFY(frameSpy.wait()); QCOMPARE(frameSpy.count(), 1); m_seatInterface->setFocusedPointerSurface(nullptr); - QCOMPARE(focusedPointerChangedSpy.count(), 3); - QVERIFY(!focusedPointerChangedSpy.last().first().value()); serverSurface->client()->flush(); QVERIFY(frameSpy.wait()); QCOMPARE(frameSpy.count(), 2); @@ -407,16 +397,13 @@ void TestWaylandSeat::testPointer() QCOMPARE(enteredSpy.first().first().value(), m_display->serial()); QCOMPARE(enteredSpy.first().last().toPoint(), QPoint(10, 3)); QCOMPARE(frameSpy.count(), 3); - PointerInterface *serverPointer = m_seatInterface->focusedPointer(); - QVERIFY(serverPointer); QCOMPARE(p->enteredSurface(), s); QCOMPARE(cp.enteredSurface(), s); - QCOMPARE(focusedPointerChangedSpy.count(), 4); - QCOMPARE(focusedPointerChangedSpy.last().first().value(), serverPointer); // test motion m_seatInterface->setTimestamp(1); m_seatInterface->setPointerPos(QPoint(10, 16)); + m_seatInterface->pointerFrame(); QVERIFY(motionSpy.wait()); QCOMPARE(frameSpy.count(), 4); QCOMPARE(motionSpy.first().first().toPoint(), QPoint(0, 1)); @@ -424,6 +411,7 @@ void TestWaylandSeat::testPointer() // test relative motion m_seatInterface->relativePointerMotion(QSizeF(1, 2), QSizeF(3, 4), quint64(-1)); + m_seatInterface->pointerFrame(); QVERIFY(relativeMotionSpy.wait()); QCOMPARE(relativeMotionSpy.count(), 1); QCOMPARE(frameSpy.count(), 5); @@ -433,11 +421,13 @@ void TestWaylandSeat::testPointer() // test axis m_seatInterface->setTimestamp(2); - m_seatInterface->pointerAxis(Qt::Horizontal, 10); + m_seatInterface->pointerAxis(Qt::Horizontal, 10, 1, PointerAxisSource::Wheel); + m_seatInterface->pointerFrame(); QVERIFY(axisSpy.wait()); QCOMPARE(frameSpy.count(), 6); m_seatInterface->setTimestamp(3); - m_seatInterface->pointerAxis(Qt::Vertical, 20); + m_seatInterface->pointerAxis(Qt::Vertical, 20, 2, PointerAxisSource::Wheel); + m_seatInterface->pointerFrame(); QVERIFY(axisSpy.wait()); QCOMPARE(frameSpy.count(), 7); QCOMPARE(axisSpy.first().at(0).value(), quint32(2)); @@ -451,21 +441,25 @@ void TestWaylandSeat::testPointer() // test button m_seatInterface->setTimestamp(4); m_seatInterface->pointerButtonPressed(1); + m_seatInterface->pointerFrame(); QVERIFY(buttonSpy.wait()); QCOMPARE(frameSpy.count(), 8); QCOMPARE(buttonSpy.at(0).at(0).value(), m_display->serial()); m_seatInterface->setTimestamp(5); m_seatInterface->pointerButtonPressed(2); + m_seatInterface->pointerFrame(); QVERIFY(buttonSpy.wait()); QCOMPARE(frameSpy.count(), 9); QCOMPARE(buttonSpy.at(1).at(0).value(), m_display->serial()); m_seatInterface->setTimestamp(6); m_seatInterface->pointerButtonReleased(2); + m_seatInterface->pointerFrame(); QVERIFY(buttonSpy.wait()); QCOMPARE(frameSpy.count(), 10); QCOMPARE(buttonSpy.at(2).at(0).value(), m_display->serial()); m_seatInterface->setTimestamp(7); m_seatInterface->pointerButtonReleased(1); + m_seatInterface->pointerFrame(); QVERIFY(buttonSpy.wait()); QCOMPARE(frameSpy.count(), 11); QCOMPARE(buttonSpy.count(), 4); @@ -498,7 +492,6 @@ void TestWaylandSeat::testPointer() // leave the surface m_seatInterface->setFocusedPointerSurface(nullptr); - QCOMPARE(focusedPointerChangedSpy.count(), 5); QVERIFY(leftSpy.wait()); QCOMPARE(frameSpy.count(), 12); QCOMPARE(leftSpy.first().first().value(), m_display->serial()); @@ -511,7 +504,6 @@ void TestWaylandSeat::testPointer() // enter it again m_seatInterface->setFocusedPointerSurface(serverSurface, QPoint(0, 0)); - QCOMPARE(focusedPointerChangedSpy.count(), 6); QVERIFY(enteredSpy.wait()); QCOMPARE(frameSpy.count(), 13); QCOMPARE(p->enteredSurface(), s); @@ -524,62 +516,6 @@ void TestWaylandSeat::testPointer() QCOMPARE(relativeMotionSpy.last().at(0).toSizeF(), QSizeF(4, 5)); QCOMPARE(relativeMotionSpy.last().at(1).toSizeF(), QSizeF(6, 7)); QCOMPARE(relativeMotionSpy.last().at(2).value(), quint64(1)); - - // destroy the focused pointer - QSignalSpy unboundSpy(serverPointer, &Resource::unbound); - QVERIFY(unboundSpy.isValid()); - QSignalSpy destroyedSpy(serverPointer, &Resource::destroyed); - QVERIFY(destroyedSpy.isValid()); - delete p; - QVERIFY(unboundSpy.wait()); - QCOMPARE(unboundSpy.count(), 1); - QCOMPARE(destroyedSpy.count(), 0); - // now test that calling into the methods in Seat does not crash - QCOMPARE(m_seatInterface->focusedPointer(), serverPointer); - QCOMPARE(m_seatInterface->focusedPointerSurface(), serverSurface); - m_seatInterface->setTimestamp(8); - m_seatInterface->setPointerPos(QPoint(10, 15)); - m_seatInterface->setTimestamp(9); - m_seatInterface->pointerButtonPressed(1); - m_seatInterface->setTimestamp(10); - m_seatInterface->pointerButtonReleased(1); - m_seatInterface->setTimestamp(11); - m_seatInterface->pointerAxis(Qt::Horizontal, 10); - m_seatInterface->setTimestamp(12); - m_seatInterface->pointerAxis(Qt::Vertical, 20); - m_seatInterface->setFocusedPointerSurface(nullptr); - QCOMPARE(focusedPointerChangedSpy.count(), 7); - m_seatInterface->setFocusedPointerSurface(serverSurface); - QCOMPARE(focusedPointerChangedSpy.count(), 8); - QCOMPARE(m_seatInterface->focusedPointerSurface(), serverSurface); - QVERIFY(!m_seatInterface->focusedPointer()); - - // and now destroy - QVERIFY(destroyedSpy.wait()); - QCOMPARE(unboundSpy.count(), 1); - QCOMPARE(destroyedSpy.count(), 1); - QCOMPARE(m_seatInterface->focusedPointerSurface(), serverSurface); - QVERIFY(!m_seatInterface->focusedPointer()); - - // create a pointer again - p = m_seat->createPointer(m_seat); - QVERIFY(focusedPointerChangedSpy.wait()); - QCOMPARE(focusedPointerChangedSpy.count(), 9); - QCOMPARE(m_seatInterface->focusedPointerSurface(), serverSurface); - serverPointer = m_seatInterface->focusedPointer(); - QVERIFY(serverPointer); - - QSignalSpy entered2Spy(p, &Pointer::entered); - QVERIFY(entered2Spy.wait()); - QCOMPARE(p->enteredSurface(), s); - QSignalSpy leftSpy2(p, &Pointer::left); - QVERIFY(leftSpy2.isValid()); - delete s; - QVERIFY(!p->enteredSurface()); - QVERIFY(leftSpy2.wait()); - QCOMPARE(focusedPointerChangedSpy.count(), 10); - QVERIFY(!m_seatInterface->focusedPointerSurface()); - QVERIFY(!m_seatInterface->focusedPointer()); } void TestWaylandSeat::testPointerTransformation_data() @@ -618,23 +554,26 @@ void TestWaylandSeat::testPointerTransformation() SurfaceInterface *serverSurface = surfaceCreatedSpy.first().first().value(); QVERIFY(serverSurface); + QImage image(QSize(100, 100), QImage::Format_ARGB32_Premultiplied); + image.fill(Qt::black); + s->attachBuffer(m_shm->createBuffer(image)); + s->damage(image.rect()); + s->commit(Surface::CommitFlag::None); + QSignalSpy committedSpy(serverSurface, &KWaylandServer::SurfaceInterface::committed); + QVERIFY(committedSpy.wait()); + m_seatInterface->setPointerPos(QPoint(20, 18)); QFETCH(QMatrix4x4, enterTransformation); m_seatInterface->setFocusedPointerSurface(serverSurface, enterTransformation); QCOMPARE(m_seatInterface->focusedPointerSurfaceTransformation(), enterTransformation); // no pointer yet QVERIFY(m_seatInterface->focusedPointerSurface()); - QVERIFY(!m_seatInterface->focusedPointer()); Pointer *p = m_seat->createPointer(m_seat); - const Pointer &cp = *p; QVERIFY(p->isValid()); - QSignalSpy pointerCreatedSpy(m_seatInterface, &SeatInterface::pointerCreated); - QVERIFY(pointerCreatedSpy.isValid()); - // once the pointer is created it should be set as the focused pointer - QVERIFY(pointerCreatedSpy.wait()); - QVERIFY(m_seatInterface->focusedPointer()); - QCOMPARE(pointerCreatedSpy.first().first().value(), m_seatInterface->focusedPointer()); + QSignalSpy frameSpy(p, &Pointer::frame); + QVERIFY(frameSpy.wait()); + const Pointer &cp = *p; m_seatInterface->setFocusedPointerSurface(nullptr); serverSurface->client()->flush(); @@ -656,14 +595,13 @@ void TestWaylandSeat::testPointerTransformation() QVERIFY(enteredSpy.wait()); QCOMPARE(enteredSpy.first().first().value(), m_display->serial()); QTEST(enteredSpy.first().last().toPointF(), "expectedEnterPoint"); - PointerInterface *serverPointer = m_seatInterface->focusedPointer(); - QVERIFY(serverPointer); QCOMPARE(p->enteredSurface(), s); QCOMPARE(cp.enteredSurface(), s); // test motion m_seatInterface->setTimestamp(1); m_seatInterface->setPointerPos(QPoint(10, 16)); + m_seatInterface->pointerFrame(); QVERIFY(motionSpy.wait()); QTEST(motionSpy.first().first().toPointF(), "expectedMovePoint"); QCOMPARE(motionSpy.first().last().value(), quint32(1)); @@ -730,11 +668,19 @@ void TestWaylandSeat::testPointerButton() QSignalSpy surfaceCreatedSpy(m_compositorInterface, &KWaylandServer::CompositorInterface::surfaceCreated); QVERIFY(surfaceCreatedSpy.isValid()); - m_compositor->createSurface(m_compositor); + KWayland::Client::Surface *s = m_compositor->createSurface(m_compositor); QVERIFY(surfaceCreatedSpy.wait()); SurfaceInterface *serverSurface = surfaceCreatedSpy.first().first().value(); QVERIFY(serverSurface); + QImage image(QSize(100, 100), QImage::Format_ARGB32_Premultiplied); + image.fill(Qt::black); + s->attachBuffer(m_shm->createBuffer(image)); + s->damage(image.rect()); + s->commit(Surface::CommitFlag::None); + QSignalSpy committedSpy(serverSurface, &KWaylandServer::SurfaceInterface::committed); + QVERIFY(committedSpy.wait()); + QScopedPointer p(m_seat->createPointer()); QVERIFY(p->isValid()); QSignalSpy buttonChangedSpy(p.data(), &KWayland::Client::Pointer::buttonStateChanged); @@ -745,13 +691,10 @@ void TestWaylandSeat::testPointerButton() m_seatInterface->setPointerPos(QPoint(20, 18)); m_seatInterface->setFocusedPointerSurface(serverSurface, QPoint(10, 15)); QVERIFY(m_seatInterface->focusedPointerSurface()); - QVERIFY(m_seatInterface->focusedPointer()); QCoreApplication::processEvents(); m_seatInterface->setFocusedPointerSurface(serverSurface, QPoint(10, 15)); - PointerInterface *serverPointer = m_seatInterface->focusedPointer(); - QVERIFY(serverPointer); QFETCH(Qt::MouseButton, qtButton); QFETCH(quint32, waylandButton); quint32 msec = QDateTime::currentMSecsSinceEpoch(); @@ -759,6 +702,7 @@ void TestWaylandSeat::testPointerButton() QCOMPARE(m_seatInterface->isPointerButtonPressed(qtButton), false); m_seatInterface->setTimestamp(msec); m_seatInterface->pointerButtonPressed(qtButton); + m_seatInterface->pointerFrame(); QCOMPARE(m_seatInterface->isPointerButtonPressed(waylandButton), true); QCOMPARE(m_seatInterface->isPointerButtonPressed(qtButton), true); QVERIFY(buttonChangedSpy.wait()); @@ -771,6 +715,7 @@ void TestWaylandSeat::testPointerButton() msec = QDateTime::currentMSecsSinceEpoch(); m_seatInterface->setTimestamp(QDateTime::currentMSecsSinceEpoch()); m_seatInterface->pointerButtonReleased(qtButton); + m_seatInterface->pointerFrame(); QCOMPARE(m_seatInterface->isPointerButtonPressed(waylandButton), false); QCOMPARE(m_seatInterface->isPointerButtonPressed(qtButton), false); QVERIFY(buttonChangedSpy.wait()); @@ -847,6 +792,7 @@ void TestWaylandSeat::testPointerSubSurfaceTree() // a motion on grandchild2 m_seatInterface->setTimestamp(timestamp++); m_seatInterface->setPointerPos(QPointF(25, 60)); + m_seatInterface->pointerFrame(); QVERIFY(motionSpy.wait()); QCOMPARE(enteredSpy.count(), 1); QCOMPARE(leftSpy.count(), 0); @@ -855,10 +801,11 @@ void TestWaylandSeat::testPointerSubSurfaceTree() // motion which changes to childSurface m_seatInterface->setTimestamp(timestamp++); m_seatInterface->setPointerPos(QPointF(25, 80)); + m_seatInterface->pointerFrame(); QVERIFY(enteredSpy.wait()); QCOMPARE(enteredSpy.count(), 2); QCOMPARE(leftSpy.count(), 1); - QCOMPARE(motionSpy.count(), 1); + QCOMPARE(motionSpy.count(), 2); QCOMPARE(enteredSpy.last().last().toPointF(), QPointF(25, 80)); QCOMPARE(pointer->enteredSurface(), childSurface.data()); // a leave for the whole surface @@ -867,7 +814,7 @@ void TestWaylandSeat::testPointerSubSurfaceTree() QVERIFY(leftSpy.wait()); QCOMPARE(enteredSpy.count(), 2); QCOMPARE(leftSpy.count(), 2); - QCOMPARE(motionSpy.count(), 1); + QCOMPARE(motionSpy.count(), 2); // a new enter on the main surface m_seatInterface->setTimestamp(timestamp++); m_seatInterface->setPointerPos(QPointF(75, 50)); @@ -875,7 +822,7 @@ void TestWaylandSeat::testPointerSubSurfaceTree() QVERIFY(enteredSpy.wait()); QCOMPARE(enteredSpy.count(), 3); QCOMPARE(leftSpy.count(), 2); - QCOMPARE(motionSpy.count(), 1); + QCOMPARE(motionSpy.count(), 2); QCOMPARE(enteredSpy.last().last().toPointF(), QPointF(75, 50)); QCOMPARE(pointer->enteredSurface(), parentSurface.data()); } @@ -923,9 +870,18 @@ void TestWaylandSeat::testPointerSwipeGesture() QVERIFY(surfaceCreatedSpy.wait()); auto serverSurface = surfaceCreatedSpy.first().first().value(); QVERIFY(serverSurface); + + QImage image(QSize(100, 100), QImage::Format_ARGB32_Premultiplied); + image.fill(Qt::black); + surface->attachBuffer(m_shm->createBuffer(image)); + surface->damage(image.rect()); + surface->commit(Surface::CommitFlag::None); + QSignalSpy committedSpy(serverSurface, &KWaylandServer::SurfaceInterface::committed); + QVERIFY(committedSpy.wait()); + m_seatInterface->setFocusedPointerSurface(serverSurface); QCOMPARE(m_seatInterface->focusedPointerSurface(), serverSurface); - QVERIFY(m_seatInterface->focusedPointer()); + QVERIFY(m_seatInterface->pointer()); // send in the start quint32 timestamp = 1; @@ -1039,9 +995,18 @@ void TestWaylandSeat::testPointerPinchGesture() QVERIFY(surfaceCreatedSpy.wait()); auto serverSurface = surfaceCreatedSpy.first().first().value(); QVERIFY(serverSurface); + + QImage image(QSize(100, 100), QImage::Format_ARGB32_Premultiplied); + image.fill(Qt::black); + surface->attachBuffer(m_shm->createBuffer(image)); + surface->damage(image.rect()); + surface->commit(Surface::CommitFlag::None); + QSignalSpy committedSpy(serverSurface, &KWaylandServer::SurfaceInterface::committed); + QVERIFY(committedSpy.wait()); + m_seatInterface->setFocusedPointerSurface(serverSurface); QCOMPARE(m_seatInterface->focusedPointerSurface(), serverSurface); - QVERIFY(m_seatInterface->focusedPointer()); + QVERIFY(m_seatInterface->pointer()); // send in the start quint32 timestamp = 1; @@ -1136,9 +1101,17 @@ void TestWaylandSeat::testPointerAxis() QVERIFY(surfaceCreatedSpy.wait()); auto serverSurface = surfaceCreatedSpy.first().first().value(); QVERIFY(serverSurface); + + QImage image(QSize(100, 100), QImage::Format_ARGB32_Premultiplied); + image.fill(Qt::black); + surface->attachBuffer(m_shm->createBuffer(image)); + surface->damage(image.rect()); + surface->commit(Surface::CommitFlag::None); + QSignalSpy committedSpy(serverSurface, &KWaylandServer::SurfaceInterface::committed); + QVERIFY(committedSpy.wait()); + m_seatInterface->setFocusedPointerSurface(serverSurface); QCOMPARE(m_seatInterface->focusedPointerSurface(), serverSurface); - QVERIFY(m_seatInterface->focusedPointer()); QSignalSpy frameSpy(pointer.data(), &Pointer::frame); QVERIFY(frameSpy.isValid()); QVERIFY(frameSpy.wait()); @@ -1156,7 +1129,8 @@ void TestWaylandSeat::testPointerAxis() quint32 timestamp = 1; m_seatInterface->setTimestamp(timestamp++); - m_seatInterface->pointerAxisV5(Qt::Vertical, 10, 1, PointerAxisSource::Wheel); + m_seatInterface->pointerAxis(Qt::Vertical, 10, 1, PointerAxisSource::Wheel); + m_seatInterface->pointerFrame(); QVERIFY(frameSpy.wait()); QCOMPARE(frameSpy.count(), 2); QCOMPARE(axisSourceSpy.count(), 1); @@ -1172,7 +1146,8 @@ void TestWaylandSeat::testPointerAxis() // let's scroll using fingers m_seatInterface->setTimestamp(timestamp++); - m_seatInterface->pointerAxisV5(Qt::Horizontal, 42, 0, PointerAxisSource::Finger); + m_seatInterface->pointerAxis(Qt::Horizontal, 42, 0, PointerAxisSource::Finger); + m_seatInterface->pointerFrame(); QVERIFY(frameSpy.wait()); QCOMPARE(frameSpy.count(), 3); QCOMPARE(axisSourceSpy.count(), 2); @@ -1186,7 +1161,8 @@ void TestWaylandSeat::testPointerAxis() // lift the fingers off the device m_seatInterface->setTimestamp(timestamp++); - m_seatInterface->pointerAxisV5(Qt::Horizontal, 0, 0, PointerAxisSource::Finger); + m_seatInterface->pointerAxis(Qt::Horizontal, 0, 0, PointerAxisSource::Finger); + m_seatInterface->pointerFrame(); QVERIFY(frameSpy.wait()); QCOMPARE(frameSpy.count(), 4); QCOMPARE(axisSourceSpy.count(), 3); @@ -1199,7 +1175,8 @@ void TestWaylandSeat::testPointerAxis() // if the device is unknown, no axis_source event should be sent m_seatInterface->setTimestamp(timestamp++); - m_seatInterface->pointerAxisV5(Qt::Horizontal, 42, 1, PointerAxisSource::Unknown); + m_seatInterface->pointerAxis(Qt::Horizontal, 42, 1, PointerAxisSource::Unknown); + m_seatInterface->pointerFrame(); QVERIFY(frameSpy.wait()); QCOMPARE(frameSpy.count(), 5); QCOMPARE(axisSourceSpy.count(), 3); @@ -1291,8 +1268,10 @@ void TestWaylandSeat::testKeyboardSubSurfaceTreeFromPointer() // let's click m_seatInterface->setTimestamp(timestamp++); m_seatInterface->pointerButtonPressed(Qt::LeftButton); + m_seatInterface->pointerFrame(); m_seatInterface->setTimestamp(timestamp++); m_seatInterface->pointerButtonReleased(Qt::LeftButton); + m_seatInterface->pointerFrame(); QVERIFY(enterSpy.wait()); QCOMPARE(enterSpy.count(), 2); QCOMPARE(leftSpy.count(), 1); @@ -1301,8 +1280,10 @@ void TestWaylandSeat::testKeyboardSubSurfaceTreeFromPointer() // click on same surface should not trigger another enter m_seatInterface->setTimestamp(timestamp++); m_seatInterface->pointerButtonPressed(Qt::LeftButton); + m_seatInterface->pointerFrame(); m_seatInterface->setTimestamp(timestamp++); m_seatInterface->pointerButtonReleased(Qt::LeftButton); + m_seatInterface->pointerFrame(); QVERIFY(!enterSpy.wait(200)); QCOMPARE(enterSpy.count(), 2); QCOMPARE(leftSpy.count(), 1); @@ -1310,6 +1291,7 @@ void TestWaylandSeat::testKeyboardSubSurfaceTreeFromPointer() // unfocus keyboard m_seatInterface->setFocusedKeyboardSurface(nullptr); + m_seatInterface->pointerFrame(); QVERIFY(leftSpy.wait()); QCOMPARE(enterSpy.count(), 2); QCOMPARE(leftSpy.count(), 2); @@ -1327,11 +1309,19 @@ void TestWaylandSeat::testCursor() QSignalSpy surfaceCreatedSpy(m_compositorInterface, &KWaylandServer::CompositorInterface::surfaceCreated); QVERIFY(surfaceCreatedSpy.isValid()); - m_compositor->createSurface(m_compositor); + KWayland::Client::Surface *surface = m_compositor->createSurface(m_compositor); QVERIFY(surfaceCreatedSpy.wait()); SurfaceInterface *serverSurface = surfaceCreatedSpy.first().first().value(); QVERIFY(serverSurface); + QImage image(QSize(100, 100), QImage::Format_ARGB32_Premultiplied); + image.fill(Qt::black); + surface->attachBuffer(m_shm->createBuffer(image)); + surface->damage(image.rect()); + surface->commit(Surface::CommitFlag::None); + QSignalSpy committedSpy(serverSurface, &KWaylandServer::SurfaceInterface::committed); + QVERIFY(committedSpy.wait()); + QScopedPointer p(m_seat->createPointer()); QVERIFY(p->isValid()); wl_display_flush(m_connection->display()); @@ -1346,21 +1336,20 @@ void TestWaylandSeat::testCursor() QVERIFY(enteredSpy.wait()); QCOMPARE(enteredSpy.first().first().value(), serial); QVERIFY(m_seatInterface->focusedPointerSurface()); - QVERIFY(m_seatInterface->focusedPointer()); - QVERIFY(!m_seatInterface->focusedPointer()->cursor()); + QVERIFY(!m_seatInterface->pointer()->cursor()); - QSignalSpy cursorChangedSpy(m_seatInterface->focusedPointer(), &KWaylandServer::PointerInterface::cursorChanged); + QSignalSpy cursorChangedSpy(m_seatInterface->pointer(), &KWaylandServer::PointerInterface::cursorChanged); QVERIFY(cursorChangedSpy.isValid()); // just remove the pointer p->setCursor(nullptr); QVERIFY(cursorChangedSpy.wait()); QCOMPARE(cursorChangedSpy.count(), 1); - auto cursor = m_seatInterface->focusedPointer()->cursor(); + auto cursor = m_seatInterface->pointer()->cursor(); QVERIFY(cursor); QVERIFY(!cursor->surface()); QCOMPARE(cursor->hotspot(), QPoint()); QCOMPARE(cursor->enteredSerial(), serial); - QCOMPARE(cursor->pointer(), m_seatInterface->focusedPointer()); + QCOMPARE(cursor->pointer(), m_seatInterface->pointer()); QSignalSpy hotspotChangedSpy(cursor, &KWaylandServer::Cursor::hotspotChanged); QVERIFY(hotspotChangedSpy.isValid()); @@ -1443,17 +1432,25 @@ void TestWaylandSeat::testCursorDamage() // create surface QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated); QVERIFY(surfaceCreatedSpy.isValid()); - m_compositor->createSurface(m_compositor); + KWayland::Client::Surface *surface = m_compositor->createSurface(m_compositor); QVERIFY(surfaceCreatedSpy.wait()); SurfaceInterface *serverSurface = surfaceCreatedSpy.first().first().value(); QVERIFY(serverSurface); + QImage image(QSize(100, 100), QImage::Format_ARGB32_Premultiplied); + image.fill(Qt::black); + surface->attachBuffer(m_shm->createBuffer(image)); + surface->damage(image.rect()); + surface->commit(Surface::CommitFlag::None); + QSignalSpy committedSpy(serverSurface, &KWaylandServer::SurfaceInterface::committed); + QVERIFY(committedSpy.wait()); + // send enter to the surface m_seatInterface->setFocusedPointerSurface(serverSurface); QVERIFY(enteredSpy.wait()); // create a signal spy for the cursor changed signal - auto pointer = m_seatInterface->focusedPointer(); + auto pointer = m_seatInterface->pointer(); QSignalSpy cursorChangedSpy(pointer, &PointerInterface::cursorChanged); QVERIFY(cursorChangedSpy.isValid()); @@ -2167,14 +2164,11 @@ void TestWaylandSeat::testDisconnect() using namespace KWaylandServer; QSignalSpy keyboardCreatedSpy(m_seatInterface, &SeatInterface::keyboardCreated); QVERIFY(keyboardCreatedSpy.isValid()); - QSignalSpy pointerCreatedSpy(m_seatInterface, &SeatInterface::pointerCreated); - QVERIFY(pointerCreatedSpy.isValid()); QSignalSpy touchCreatedSpy(m_seatInterface, &SeatInterface::touchCreated); QVERIFY(touchCreatedSpy.isValid()); // create the things we need m_seatInterface->setHasKeyboard(true); - m_seatInterface->setHasPointer(true); m_seatInterface->setHasTouch(true); QSignalSpy touchSpy(m_seat, &Seat::hasTouchChanged); QVERIFY(touchSpy.isValid()); @@ -2186,12 +2180,6 @@ void TestWaylandSeat::testDisconnect() auto serverKeyboard = keyboardCreatedSpy.first().first().value(); QVERIFY(serverKeyboard); - QScopedPointer pointer(m_seat->createPointer()); - QVERIFY(!pointer.isNull()); - QVERIFY(pointerCreatedSpy.wait()); - auto serverPointer = pointerCreatedSpy.first().first().value(); - QVERIFY(serverPointer); - QScopedPointer touch(m_seat->createTouch()); QVERIFY(!touch.isNull()); QVERIFY(touchCreatedSpy.wait()); @@ -2201,8 +2189,6 @@ void TestWaylandSeat::testDisconnect() // setup destroys QSignalSpy keyboardDestroyedSpy(serverKeyboard, &QObject::destroyed); QVERIFY(keyboardDestroyedSpy.isValid()); - QSignalSpy pointerDestroyedSpy(serverPointer, &QObject::destroyed); - QVERIFY(pointerDestroyedSpy.isValid()); QSignalSpy touchDestroyedSpy(serverTouch, &QObject::destroyed); QVERIFY(touchDestroyedSpy.isValid()); @@ -2212,7 +2198,6 @@ void TestWaylandSeat::testDisconnect() } keyboard->destroy(); - pointer->destroy(); touch->destroy(); m_relativePointerManager->destroy(); m_pointerGestures->destroy(); diff --git a/src/wayland/autotests/server/test_seat.cpp b/src/wayland/autotests/server/test_seat.cpp index 1734444255..3dbd863a10 100644 --- a/src/wayland/autotests/server/test_seat.cpp +++ b/src/wayland/autotests/server/test_seat.cpp @@ -102,8 +102,7 @@ void TestWaylandServerSeat::testPointerButton() display.addSocketName(s_socketName); display.start(); SeatInterface *seat = new SeatInterface(&display); - PointerInterface *pointer = seat->focusedPointer(); - QVERIFY(!pointer); + seat->setHasPointer(true); // no button pressed yet, should be released and no serial QVERIFY(!seat->isPointerButtonPressed(0)); @@ -113,6 +112,7 @@ void TestWaylandServerSeat::testPointerButton() // mark the button as pressed seat->pointerButtonPressed(0); + seat->pointerFrame(); QVERIFY(seat->isPointerButtonPressed(0)); QCOMPARE(seat->pointerButtonSerial(0), display.serial()); @@ -122,6 +122,7 @@ void TestWaylandServerSeat::testPointerButton() // release it again seat->pointerButtonReleased(0); + seat->pointerFrame(); QVERIFY(!seat->isPointerButtonPressed(0)); QCOMPARE(seat->pointerButtonSerial(0), display.serial()); } @@ -132,22 +133,24 @@ void TestWaylandServerSeat::testPointerPos() display.addSocketName(s_socketName); display.start(); SeatInterface *seat = new SeatInterface(&display); + seat->setHasPointer(true); QSignalSpy seatPosSpy(seat, SIGNAL(pointerPosChanged(QPointF))); QVERIFY(seatPosSpy.isValid()); - PointerInterface *pointer = seat->focusedPointer(); - QVERIFY(!pointer); QCOMPARE(seat->pointerPos(), QPointF()); seat->setPointerPos(QPointF(10, 15)); + seat->pointerFrame(); QCOMPARE(seat->pointerPos(), QPointF(10, 15)); QCOMPARE(seatPosSpy.count(), 1); QCOMPARE(seatPosSpy.first().first().toPointF(), QPointF(10, 15)); seat->setPointerPos(QPointF(10, 15)); + seat->pointerFrame(); QCOMPARE(seatPosSpy.count(), 1); seat->setPointerPos(QPointF(5, 7)); + seat->pointerFrame(); QCOMPARE(seat->pointerPos(), QPointF(5, 7)); QCOMPARE(seatPosSpy.count(), 2); QCOMPARE(seatPosSpy.first().first().toPointF(), QPointF(10, 15)); diff --git a/src/wayland/pointer_interface.cpp b/src/wayland/pointer_interface.cpp index 4fcb8d9598..d2f57c45d3 100644 --- a/src/wayland/pointer_interface.cpp +++ b/src/wayland/pointer_interface.cpp @@ -1,411 +1,315 @@ /* SPDX-FileCopyrightText: 2014 Martin Gräßlin + SPDX-FileCopyrightText: 2020 Adrien Faveraux + SPDX-FileCopyrightText: 2021 Vlad Zahorodnii SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ + #include "pointer_interface.h" +#include "clientconnection.h" +#include "display.h" +#include "logging.h" #include "pointer_interface_p.h" -#include "pointerconstraints_v1_interface.h" #include "pointergestures_v1_interface_p.h" -#include "resource_p.h" #include "relativepointer_v1_interface_p.h" #include "seat_interface.h" -#include "display.h" -#include "subcompositor_interface.h" #include "surface_interface.h" -#include "datadevice_interface.h" -// Wayland -#include +#include "surfacerole_p.h" +#include "utils.h" namespace KWaylandServer { -class Cursor::Private +class CursorPrivate { public: - Private(Cursor *q, PointerInterface *pointer); + CursorPrivate(Cursor *q, PointerInterface *pointer); + + Cursor *q; PointerInterface *pointer; quint32 enteredSerial = 0; QPoint hotspot; QPointer surface; - void update(const QPointer &surface, quint32 serial, const QPoint &hotspot); - -private: - Cursor *q; + void update(SurfaceInterface *surface, quint32 serial, const QPoint &hotspot); }; -PointerInterface::Private::Private(SeatInterface *parent, wl_resource *parentResource, PointerInterface *q) - : Resource::Private(q, parent, parentResource, &wl_pointer_interface, &s_interface) - , seat(parent) +PointerInterfacePrivate *PointerInterfacePrivate::get(PointerInterface *pointer) +{ + return pointer->d.data(); +} + +PointerInterfacePrivate::PointerInterfacePrivate(PointerInterface *q, SeatInterface *seat) + : q(q) + , seat(seat) + , relativePointersV1(new RelativePointerV1Interface(q)) + , swipeGesturesV1(new PointerSwipeGestureV1Interface(q)) + , pinchGesturesV1(new PointerPinchGestureV1Interface(q)) { } -void PointerInterface::Private::setCursor(quint32 serial, SurfaceInterface *surface, const QPoint &hotspot) +PointerInterfacePrivate::~PointerInterfacePrivate() { - if (!cursor) { - Q_Q(PointerInterface); +} + +QList PointerInterfacePrivate::pointersForClient(ClientConnection *client) const +{ + return resourceMap().values(client->client()); +} + +void PointerInterfacePrivate::pointer_set_cursor(Resource *resource, uint32_t serial, + ::wl_resource *surface_resource, + int32_t hotspot_x, int32_t hotspot_y) +{ + SurfaceInterface *surface = nullptr; + + if (!focusedSurface) { + return; + } + if (focusedSurface->client()->client() != resource->client()) { + qCDebug(KWAYLAND_SERVER, "Denied set_cursor request from unfocused client"); + return; + } + + if (surface_resource) { + surface = SurfaceInterface::get(surface_resource); + if (!surface) { + wl_resource_post_error(resource->handle, WL_DISPLAY_ERROR_INVALID_OBJECT, + "invalid surface"); + return; + } + + const SurfaceRole *surfaceRole = SurfaceRole::get(surface); + if (surfaceRole) { + wl_resource_post_error(resource->handle, error_role, + "the wl_surface already has a role assigned %s", + surfaceRole->name().constData()); + return; + } + } + + if (!cursor) { // TODO: Assign the cursor surface role. cursor = new Cursor(q); - cursor->d->update(QPointer(surface), serial, hotspot); + cursor->d->update(surface, serial, QPoint(hotspot_x, hotspot_y)); QObject::connect(cursor, &Cursor::changed, q, &PointerInterface::cursorChanged); emit q->cursorChanged(); } else { - cursor->d->update(QPointer(surface), serial, hotspot); + cursor->d->update(surface, serial, QPoint(hotspot_x, hotspot_y)); } } -void PointerInterface::Private::sendLeave(SurfaceInterface *surface, quint32 serial) +void PointerInterfacePrivate::pointer_release(Resource *resource) { - if (!surface) { - return; - } - if (resource && surface->resource()) { - wl_pointer_send_leave(resource, serial, surface->resource()); - } + wl_resource_destroy(resource->handle); } -void PointerInterface::Private::registerRelativePointerV1(RelativePointerV1Interface *relativePointer) +void PointerInterfacePrivate::pointer_bind_resource(Resource *resource) { - Q_ASSERT(!relativePointersV1.contains(relativePointer)); - relativePointersV1.append(relativePointer); -} + const ClientConnection *focusedClient = focusedSurface ? focusedSurface->client() : nullptr; -void PointerInterface::Private::unregisterRelativePointerV1(RelativePointerV1Interface *relativePointer) -{ - Q_ASSERT(relativePointersV1.contains(relativePointer)); - relativePointersV1.removeOne(relativePointer); -} - -void PointerInterface::Private::registerSwipeGestureV1(PointerSwipeGestureV1Interface *gesture) -{ - Q_ASSERT(!swipeGesturesV1.contains(gesture)); - swipeGesturesV1.append(gesture); -} - -void PointerInterface::Private::unregisterSwipeGestureV1(PointerSwipeGestureV1Interface *gesture) -{ - Q_ASSERT(swipeGesturesV1.contains(gesture)); - swipeGesturesV1.removeOne(gesture); -} - -void PointerInterface::Private::registerPinchGestureV1(PointerPinchGestureV1Interface *gesture) -{ - Q_ASSERT(!pinchGesturesV1.contains(gesture)); - pinchGesturesV1.append(gesture); -} - -void PointerInterface::Private::unregisterPinchGestureV1(PointerPinchGestureV1Interface *gesture) -{ - Q_ASSERT(pinchGesturesV1.contains(gesture)); - pinchGesturesV1.removeOne(gesture); -} - -namespace { -static QPointF surfacePosition(SurfaceInterface *surface) { - if (surface && surface->subSurface()) { - return surface->subSurface()->position() + surfacePosition(surface->subSurface()->parentSurface()); - } - return QPointF(); -} -} - -void PointerInterface::Private::sendEnter(SurfaceInterface *surface, const QPointF &parentSurfacePosition, quint32 serial) -{ - if (!surface || !surface->resource()) { - return; - } - const QPointF adjustedPos = parentSurfacePosition - surfacePosition(surface); - wl_pointer_send_enter(resource, serial, - surface->resource(), - wl_fixed_from_double(adjustedPos.x()), wl_fixed_from_double(adjustedPos.y())); -} - -void PointerInterface::Private::startSwipeGesture(quint32 serial, quint32 fingerCount) -{ - if (!focusedSurface) { - return; - } - for (PointerSwipeGestureV1Interface *gesture : qAsConst(swipeGesturesV1)) { - gesture->send_begin(serial, seat->timestamp(), focusedSurface->resource(), fingerCount); - } -} - -void PointerInterface::Private::updateSwipeGesture(const QSizeF &delta) -{ - for (PointerSwipeGestureV1Interface *gesture : qAsConst(swipeGesturesV1)) { - gesture->send_update(seat->timestamp(), - wl_fixed_from_double(delta.width()), - wl_fixed_from_double(delta.height())); - } -} - -void PointerInterface::Private::endSwipeGesture(quint32 serial) -{ - for (PointerSwipeGestureV1Interface *gesture : qAsConst(swipeGesturesV1)) { - gesture->send_end(serial, seat->timestamp(), false); - } -} - -void PointerInterface::Private::cancelSwipeGesture(quint32 serial) -{ - for (PointerSwipeGestureV1Interface *gesture : qAsConst(swipeGesturesV1)) { - gesture->send_end(serial, seat->timestamp(), true); - } -} - -void PointerInterface::Private::startPinchGesture(quint32 serial, quint32 fingerCount) -{ - if (!focusedSurface) { - return; - } - for (PointerPinchGestureV1Interface *gesture : qAsConst(pinchGesturesV1)) { - gesture->send_begin(serial, seat->timestamp(), focusedSurface->resource(), fingerCount); - } -} - -void PointerInterface::Private::updatePinchGesture(const QSizeF &delta, qreal scale, qreal rotation) -{ - for (PointerPinchGestureV1Interface *gesture : qAsConst(pinchGesturesV1)) { - gesture->send_update(seat->timestamp(), - wl_fixed_from_double(delta.width()), - wl_fixed_from_double(delta.height()), - wl_fixed_from_double(scale), - wl_fixed_from_double(rotation)); - } -} - -void PointerInterface::Private::endPinchGesture(quint32 serial) -{ - for (PointerPinchGestureV1Interface *gesture : qAsConst(pinchGesturesV1)) { - gesture->send_end(serial, seat->timestamp(), false); - } -} - -void PointerInterface::Private::cancelPinchGesture(quint32 serial) -{ - for (PointerPinchGestureV1Interface *gesture : qAsConst(pinchGesturesV1)) { - gesture->send_end(serial, seat->timestamp(), true); - } -} - -void PointerInterface::Private::sendFrame() -{ - if (!resource || wl_resource_get_version(resource) < WL_POINTER_FRAME_SINCE_VERSION) { - return; - } - wl_pointer_send_frame(resource); -} - -#ifndef K_DOXYGEN -const struct wl_pointer_interface PointerInterface::Private::s_interface = { - setCursorCallback, - resourceDestroyedCallback -}; -#endif - -PointerInterface::PointerInterface(SeatInterface *parent, wl_resource *parentResource) - : Resource(new Private(parent, parentResource, this)) -{ - // TODO: handle touch - connect(parent, &SeatInterface::pointerPosChanged, this, [this] { - Q_D(); - if (!d->focusedSurface || !d->resource) { - return; + if (focusedClient && focusedClient->client() == resource->client()) { + const quint32 serial = seat->display()->nextSerial(); + send_enter(resource->handle, serial, focusedSurface->resource(), + wl_fixed_from_double(lastPosition.x()), wl_fixed_from_double(lastPosition.y())); + if (resource->version() >= WL_POINTER_FRAME_SINCE_VERSION) { + send_frame(resource->handle); } - if (d->seat->isDragPointer()) { - const auto *originSurface = d->seat->dragSource()->origin(); - const bool proxyRemoteFocused = originSurface->dataProxy() && originSurface == d->focusedSurface; - if (!proxyRemoteFocused) { - // handled by DataDevice - return; - } + } +} + +void PointerInterfacePrivate::sendLeave(quint32 serial) +{ + const QList pointerResources = pointersForClient(focusedSurface->client()); + for (Resource *resource : pointerResources) { + send_leave(resource->handle, serial, focusedSurface->resource()); + } +} + +void PointerInterfacePrivate::sendEnter(const QPointF &position, quint32 serial) +{ + const QList pointerResources = pointersForClient(focusedSurface->client()); + for (Resource *resource : pointerResources) { + send_enter(resource->handle, serial, focusedSurface->resource(), + wl_fixed_from_double(position.x()), wl_fixed_from_double(position.y())); + } +} + +void PointerInterfacePrivate::sendFrame() +{ + const QList pointerResources = pointersForClient(focusedSurface->client()); + for (Resource *resource : pointerResources) { + if (resource->version() >= WL_POINTER_FRAME_SINCE_VERSION) { + send_frame(resource->handle); } - if (d->focusedSurface->lockedPointer() && d->focusedSurface->lockedPointer()->isLocked()) { - return; - } - const QPointF pos = d->seat->focusedPointerSurfaceTransformation().map(d->seat->pointerPos()); - auto targetSurface = d->focusedSurface->inputSurfaceAt(pos); - if (!targetSurface) { - targetSurface = d->focusedSurface; - } - if (targetSurface != d->focusedChildSurface.data()) { - const quint32 serial = d->seat->display()->nextSerial(); - d->sendLeave(d->focusedChildSurface.data(), serial); - d->focusedChildSurface = QPointer(targetSurface); - d->sendEnter(targetSurface, pos, serial); - d->sendFrame(); - d->client->flush(); - } else { - const QPointF adjustedPos = pos - surfacePosition(d->focusedChildSurface); - wl_pointer_send_motion(d->resource, d->seat->timestamp(), - wl_fixed_from_double(adjustedPos.x()), wl_fixed_from_double(adjustedPos.y())); + } +} + +PointerInterface::PointerInterface(SeatInterface *seat) + : d(new PointerInterfacePrivate(this, seat)) +{ +} + +PointerInterface::~PointerInterface() +{ +} + +SurfaceInterface *PointerInterface::focusedSurface() const +{ + return d->focusedSurface; +} + +void PointerInterface::setFocusedSurface(SurfaceInterface *surface, const QPointF &position, quint32 serial) +{ + if (d->focusedSurface == surface) { + return; + } + + if (d->focusedSurface) { + d->sendLeave(serial); + if (!surface || d->focusedSurface->client() != surface->client()) { d->sendFrame(); } - }); -} - -PointerInterface::~PointerInterface() = default; - -void PointerInterface::setFocusedSurface(SurfaceInterface *surface, quint32 serial) -{ - Q_D(); - d->sendLeave(d->focusedChildSurface.data(), serial); - disconnect(d->destroyConnection); - if (!surface) { - d->focusedSurface = nullptr; - d->focusedChildSurface.clear(); - return; + disconnect(d->destroyConnection); } + d->focusedSurface = surface; - d->destroyConnection = connect(d->focusedSurface, &SurfaceInterface::aboutToBeDestroyed, this, - [this] { - Q_D(); - d->sendLeave(d->focusedChildSurface.data(), d->global->display()->nextSerial()); + + if (d->focusedSurface) { + d->destroyConnection = connect(d->focusedSurface, &SurfaceInterface::aboutToBeDestroyed, this, [this]() { + d->sendLeave(d->seat->display()->nextSerial()); d->sendFrame(); d->focusedSurface = nullptr; - d->focusedChildSurface.clear(); + emit focusedSurfaceChanged(); + }); + d->sendEnter(position, serial); + d->sendFrame(); + d->lastPosition = position; + } + + emit focusedSurfaceChanged(); +} + +void PointerInterface::sendPressed(quint32 button, quint32 serial) +{ + if (!d->focusedSurface) { + return; + } + + const auto pointerResources = d->pointersForClient(d->focusedSurface->client()); + for (PointerInterfacePrivate::Resource *resource : pointerResources) { + d->send_button(resource->handle, serial, d->seat->timestamp(), button, + PointerInterfacePrivate::button_state_pressed); + } +} + +void PointerInterface::sendReleased(quint32 button, quint32 serial) +{ + if (!d->focusedSurface) { + return; + } + + const auto pointerResources = d->pointersForClient(d->focusedSurface->client()); + for (PointerInterfacePrivate::Resource *resource : pointerResources) { + d->send_button(resource->handle, serial, d->seat->timestamp(), button, + PointerInterfacePrivate::button_state_released); + } +} + +void PointerInterface::sendAxis(Qt::Orientation orientation, qreal delta, qint32 discreteDelta, PointerAxisSource source) +{ + if (!d->focusedSurface) { + return; + } + + const auto pointerResources = d->pointersForClient(d->focusedSurface->client()); + for (PointerInterfacePrivate::Resource *resource : pointerResources) { + const quint32 version = resource->version(); + + const auto wlOrientation = (orientation == Qt::Vertical) + ? PointerInterfacePrivate::axis_vertical_scroll + : PointerInterfacePrivate::axis_horizontal_scroll; + + if (source != PointerAxisSource::Unknown && version >= WL_POINTER_AXIS_SOURCE_SINCE_VERSION) { + PointerInterfacePrivate::axis_source wlSource; + switch (source) { + case PointerAxisSource::Wheel: + wlSource = PointerInterfacePrivate::axis_source_wheel; + break; + case PointerAxisSource::Finger: + wlSource = PointerInterfacePrivate::axis_source_finger; + break; + case PointerAxisSource::Continuous: + wlSource = PointerInterfacePrivate::axis_source_continuous; + break; + case PointerAxisSource::WheelTilt: + wlSource = PointerInterfacePrivate::axis_source_wheel_tilt; + break; + default: + Q_UNREACHABLE(); + break; + } + d->send_axis_source(resource->handle, wlSource); } - ); - const QPointF pos = d->seat->focusedPointerSurfaceTransformation().map(d->seat->pointerPos()); - d->focusedChildSurface = QPointer(d->focusedSurface->inputSurfaceAt(pos)); - if (!d->focusedChildSurface) { - d->focusedChildSurface = QPointer(d->focusedSurface); - } - d->sendEnter(d->focusedChildSurface.data(), pos, serial); - d->client->flush(); -} - -void PointerInterface::buttonPressed(quint32 button, quint32 serial) -{ - Q_D(); - Q_ASSERT(d->focusedSurface); - if (!d->resource) { - return; - } - wl_pointer_send_button(d->resource, serial, d->seat->timestamp(), button, WL_POINTER_BUTTON_STATE_PRESSED); - d->sendFrame(); -} - -void PointerInterface::buttonReleased(quint32 button, quint32 serial) -{ - Q_D(); - Q_ASSERT(d->focusedSurface); - if (!d->resource) { - return; - } - wl_pointer_send_button(d->resource, serial, d->seat->timestamp(), button, WL_POINTER_BUTTON_STATE_RELEASED); - d->sendFrame(); -} - -void PointerInterface::axis(Qt::Orientation orientation, qreal delta, qint32 discreteDelta, PointerAxisSource source) -{ - Q_D(); - Q_ASSERT(d->focusedSurface); - if (!d->resource) { - return; - } - - const quint32 version = wl_resource_get_version(d->resource); - - const auto wlOrientation = (orientation == Qt::Vertical) - ? WL_POINTER_AXIS_VERTICAL_SCROLL - : WL_POINTER_AXIS_HORIZONTAL_SCROLL; - - if (source != PointerAxisSource::Unknown && version >= WL_POINTER_AXIS_SOURCE_SINCE_VERSION) { - wl_pointer_axis_source wlSource; - switch (source) { - case PointerAxisSource::Wheel: - wlSource = WL_POINTER_AXIS_SOURCE_WHEEL; - break; - case PointerAxisSource::Finger: - wlSource = WL_POINTER_AXIS_SOURCE_FINGER; - break; - case PointerAxisSource::Continuous: - wlSource = WL_POINTER_AXIS_SOURCE_CONTINUOUS; - break; - case PointerAxisSource::WheelTilt: - wlSource = WL_POINTER_AXIS_SOURCE_WHEEL_TILT; - break; - default: - Q_UNREACHABLE(); - break; + if (delta != 0.0) { + if (discreteDelta && version >= WL_POINTER_AXIS_DISCRETE_SINCE_VERSION) { + d->send_axis_discrete(resource->handle, wlOrientation, discreteDelta); + } + d->send_axis(resource->handle, d->seat->timestamp(), wlOrientation, wl_fixed_from_double(delta)); + } else if (version >= WL_POINTER_AXIS_STOP_SINCE_VERSION) { + d->send_axis_stop(resource->handle, d->seat->timestamp(), wlOrientation); } - wl_pointer_send_axis_source(d->resource, wlSource); } - - if (delta != 0.0) { - if (discreteDelta && version >= WL_POINTER_AXIS_DISCRETE_SINCE_VERSION) { - wl_pointer_send_axis_discrete(d->resource, wlOrientation, discreteDelta); - } - wl_pointer_send_axis(d->resource, d->seat->timestamp(), wlOrientation, wl_fixed_from_double(delta)); - } else if (version >= WL_POINTER_AXIS_STOP_SINCE_VERSION) { - wl_pointer_send_axis_stop(d->resource, d->seat->timestamp(), wlOrientation); - } - - d->sendFrame(); } -void PointerInterface::axis(Qt::Orientation orientation, quint32 delta) +void PointerInterface::sendMotion(const QPointF &position) { - Q_D(); - Q_ASSERT(d->focusedSurface); - if (!d->resource) { + d->lastPosition = position; + + if (!d->focusedSurface) { return; } - wl_pointer_send_axis(d->resource, d->seat->timestamp(), - (orientation == Qt::Vertical) ? WL_POINTER_AXIS_VERTICAL_SCROLL : WL_POINTER_AXIS_HORIZONTAL_SCROLL, - wl_fixed_from_int(delta)); - d->sendFrame(); + + const auto pointerResources = d->pointersForClient(d->focusedSurface->client()); + for (PointerInterfacePrivate::Resource *resource : pointerResources) { + d->send_motion(resource->handle, d->seat->timestamp(), + wl_fixed_from_double(position.x()), wl_fixed_from_double(position.y())); + } } -void PointerInterface::Private::setCursorCallback(wl_client *client, wl_resource *resource, uint32_t serial, - wl_resource *surface, int32_t hotspot_x, int32_t hotspot_y) +void PointerInterface::sendFrame() { - auto p = cast(resource); - Q_ASSERT(p->client->client() == client); - p->setCursor(serial, SurfaceInterface::get(surface), QPoint(hotspot_x, hotspot_y)); + if (d->focusedSurface) { + d->sendFrame(); + } } Cursor *PointerInterface::cursor() const { - Q_D(); return d->cursor; } -void PointerInterface::relativeMotion(const QSizeF &delta, const QSizeF &deltaNonAccelerated, quint64 microseconds) +SeatInterface *PointerInterface::seat() const { - Q_D(); - if (d->relativePointersV1.isEmpty()) { - return; - } - for (RelativePointerV1Interface *relativePointer : qAsConst(d->relativePointersV1)) { - relativePointer->send_relative_motion(microseconds >> 32, microseconds & 0xffffffff, - wl_fixed_from_double(delta.width()), - wl_fixed_from_double(delta.height()), - wl_fixed_from_double(deltaNonAccelerated.width()), - wl_fixed_from_double(deltaNonAccelerated.height())); - } - d->sendFrame(); -} - -PointerInterface::Private *PointerInterface::d_func() const -{ - return reinterpret_cast(d.data()); + return d->seat; } PointerInterface *PointerInterface::get(wl_resource *native) { - return Private::get(native); + if (PointerInterfacePrivate *pointerPrivate = resource_cast(native)) { + return pointerPrivate->q; + } + return nullptr; } -Cursor::Private::Private(Cursor *q, PointerInterface *pointer) - : pointer(pointer) - , q(q) +CursorPrivate::CursorPrivate(Cursor *q, PointerInterface *pointer) + : q(q) + , pointer(pointer) { } -void Cursor::Private::update(const QPointer< SurfaceInterface > &s, quint32 serial, const QPoint &p) +void CursorPrivate::update(SurfaceInterface *s, quint32 serial, const QPoint &p) { bool emitChanged = false; if (enteredSerial != serial) { @@ -436,11 +340,13 @@ void Cursor::Private::update(const QPointer< SurfaceInterface > &s, quint32 seri Cursor::Cursor(PointerInterface *parent) : QObject(parent) - , d(new Private(this, parent)) + , d(new CursorPrivate(this, parent)) { } -Cursor::~Cursor() = default; +Cursor::~Cursor() +{ +} quint32 Cursor::enteredSerial() const { @@ -457,7 +363,7 @@ PointerInterface *Cursor::pointer() const return d->pointer; } -QPointer< SurfaceInterface > Cursor::surface() const +SurfaceInterface *Cursor::surface() const { return d->surface; } diff --git a/src/wayland/pointer_interface.h b/src/wayland/pointer_interface.h index b6a3092a3f..f81a449aad 100644 --- a/src/wayland/pointer_interface.h +++ b/src/wayland/pointer_interface.h @@ -1,5 +1,7 @@ /* SPDX-FileCopyrightText: 2014 Martin Gräßlin + SPDX-FileCopyrightText: 2020 Adrien Faveraux + SPDX-FileCopyrightText: 2021 Vlad Zahorodnii SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ @@ -8,93 +10,106 @@ #include -#include "resource.h" +#include + +struct wl_resource; namespace KWaylandServer { +class CursorPrivate; class Cursor; +class PointerInterfacePrivate; class SeatInterface; class SurfaceInterface; enum class PointerAxisSource; /** - * @brief Resource for the wl_pointer interface. - * - * @see SeatInterface - **/ -class KWAYLANDSERVER_EXPORT PointerInterface : public Resource + * The PointerInterface class represents one or more input devices such as mice, which control + * the pointer location. It corresponds to the Wayland interface @c wl_pointer. + */ +class KWAYLANDSERVER_EXPORT PointerInterface : public QObject { Q_OBJECT + public: - virtual ~PointerInterface(); + ~PointerInterface() override; /** - * @returns the focused SurfaceInterface on this pointer resource, if any. - **/ + * Returns the focused pointer surface. Note that the returned value may be different + * from SurfaceInterface::focusedSurfacePointerSurface() because this function returns + * the effective focused surface. + */ SurfaceInterface *focusedSurface() const; - /** - * The Cursor set on this PointerInterface. Might be @c null. - * @since 5.3 - **/ + * 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; + /** + * Returns the seat to which this pointer belongs to. + */ + SeatInterface *seat() const; + /** * @returns The PointerInterface for the @p native resource. - * @since 5.28 - **/ + */ static PointerInterface *get(wl_resource *native); + void sendPressed(quint32 button, quint32 serial); + void sendReleased(quint32 button, quint32 serial); + void sendAxis(Qt::Orientation orientation, qreal delta, qint32 discreteDelta, PointerAxisSource source); + void sendMotion(const QPointF &position); + void sendFrame(); + Q_SIGNALS: /** - * Signal emitted whenever the Cursor changes. - **/ + * This signal is emitted whenever the cursor surface changes. As long as there is no + * any focused surface, the cursor cannot be changed. + */ void cursorChanged(); + /** + * This signal is emitted whenever the focused pointer surface changes. + */ + void focusedSurfaceChanged(); private: - void setFocusedSurface(SurfaceInterface *surface, quint32 serial); - void buttonPressed(quint32 button, quint32 serial); - void buttonReleased(quint32 button, quint32 serial); - void axis(Qt::Orientation orientation, qreal delta, qint32 discreteDelta, PointerAxisSource source); - void axis(Qt::Orientation orientation, quint32 delta); - void relativeMotion(const QSizeF &delta, const QSizeF &deltaNonAccelerated, quint64 microseconds); + explicit PointerInterface(SeatInterface *seat); + QScopedPointer d; + friend class SeatInterface; - friend class RelativePointerV1Interface; - friend class PointerPinchGestureV1Interface; - friend class PointerSwipeGestureV1Interface; - explicit PointerInterface(SeatInterface *parent, wl_resource *parentResource); - class Private; - Private *d_func() const; + friend class PointerInterfacePrivate; }; /** * @brief Class encapsulating a Cursor image. - * - * @since 5.3 - **/ + */ class KWAYLANDSERVER_EXPORT Cursor : public QObject { Q_OBJECT + public: virtual ~Cursor(); /** * The hotspot of the cursor image in surface-relative coordinates. - **/ + */ QPoint hotspot() const; /** * The entered serial when the Cursor got set. - **/ + */ quint32 enteredSerial() const; /** * The PointerInterface this Cursor belongs to. - **/ + */ PointerInterface *pointer() const; /** * The SurfaceInterface for the image content of the Cursor. - **/ - QPointer surface() const; + */ + SurfaceInterface *surface() const; Q_SIGNALS: void hotspotChanged(); @@ -103,14 +118,11 @@ Q_SIGNALS: void changed(); private: - friend class PointerInterface; - Cursor(PointerInterface *parent); - class Private; - const QScopedPointer d; + QScopedPointer d; + friend class PointerInterfacePrivate; + explicit Cursor(PointerInterface *parent); }; } -Q_DECLARE_METATYPE(KWaylandServer::PointerInterface*) - #endif diff --git a/src/wayland/pointer_interface_p.h b/src/wayland/pointer_interface_p.h index 911b8c0f50..f731363508 100644 --- a/src/wayland/pointer_interface_p.h +++ b/src/wayland/pointer_interface_p.h @@ -1,68 +1,58 @@ /* SPDX-FileCopyrightText: 2016 Martin Gräßlin + SPDX-FileCopyrightText: 2020 Adrien Faveraux + SPDX-FileCopyrightText: 2021 Vlad Zahorodnii SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL */ #ifndef WAYLAND_SERVER_POINTER_INTERFACE_P_H #define WAYLAND_SERVER_POINTER_INTERFACE_P_H #include "pointer_interface.h" -#include "resource_p.h" +#include #include #include +#include "qwayland-server-wayland.h" + namespace KWaylandServer { + +class ClientConnection; class PointerPinchGestureV1Interface; class PointerSwipeGestureV1Interface; class RelativePointerV1Interface; -class PointerInterface::Private : public Resource::Private +class PointerInterfacePrivate : public QtWaylandServer::wl_pointer { public: - Private(SeatInterface *parent, wl_resource *parentResource, PointerInterface *q); + static PointerInterfacePrivate *get(PointerInterface *pointer); + PointerInterfacePrivate(PointerInterface *q, SeatInterface *seat); + ~PointerInterfacePrivate() override; + + QList pointersForClient(ClientConnection *client) const; + + PointerInterface *q; SeatInterface *seat; SurfaceInterface *focusedSurface = nullptr; - QPointer focusedChildSurface; QMetaObject::Connection destroyConnection; Cursor *cursor = nullptr; - QVector relativePointersV1; - QVector swipeGesturesV1; - QVector pinchGesturesV1; + QScopedPointer relativePointersV1; + QScopedPointer swipeGesturesV1; + QScopedPointer pinchGesturesV1; + QPointF lastPosition; - void sendLeave(SurfaceInterface *surface, quint32 serial); - void sendEnter(SurfaceInterface *surface, const QPointF &parentSurfacePosition, quint32 serial); + void sendLeave(quint32 serial); + void sendEnter(const QPointF &parentSurfacePosition, quint32 serial); void sendFrame(); - void registerRelativePointerV1(RelativePointerV1Interface *relativePointer); - void registerSwipeGestureV1(PointerSwipeGestureV1Interface *gesture); - void registerPinchGestureV1(PointerPinchGestureV1Interface *gesture); - - void unregisterRelativePointerV1(RelativePointerV1Interface *relativePointer); - void unregisterSwipeGestureV1(PointerSwipeGestureV1Interface *gesture); - void unregisterPinchGestureV1(PointerPinchGestureV1Interface *gesture); - - void startSwipeGesture(quint32 serial, quint32 fingerCount); - void updateSwipeGesture(const QSizeF &delta); - void endSwipeGesture(quint32 serial); - void cancelSwipeGesture(quint32 serial); - - void startPinchGesture(quint32 serial, quint32 fingerCount); - void updatePinchGesture(const QSizeF &delta, qreal scale, qreal rotation); - void endPinchGesture(quint32 serial); - void cancelPinchGesture(quint32 serial); - -private: - PointerInterface *q_func() { - return reinterpret_cast(q); - } - void setCursor(quint32 serial, SurfaceInterface *surface, const QPoint &hotspot); - // interface - static void setCursorCallback(wl_client *client, wl_resource *resource, uint32_t serial, - wl_resource *surface, int32_t hotspot_x, int32_t hotspot_y); - - static const struct wl_pointer_interface s_interface; +protected: + void pointer_set_cursor(Resource *resource, uint32_t serial, + ::wl_resource *surface_resource, + int32_t hotspot_x, int32_t hotspot_y) override; + void pointer_release(Resource *resource) override; + void pointer_bind_resource(Resource *resource) override; }; } diff --git a/src/wayland/pointergestures_v1_interface.cpp b/src/wayland/pointergestures_v1_interface.cpp index 17f1f23cd3..19b5f2a874 100644 --- a/src/wayland/pointergestures_v1_interface.cpp +++ b/src/wayland/pointergestures_v1_interface.cpp @@ -6,14 +6,17 @@ */ #include "pointergestures_v1_interface.h" +#include "clientconnection.h" #include "display.h" #include "pointer_interface_p.h" #include "pointergestures_v1_interface_p.h" +#include "seat_interface.h" +#include "surface_interface.h" namespace KWaylandServer { -static const int s_version = 1; +static const int s_version = 2; PointerGesturesV1InterfacePrivate::PointerGesturesV1InterfacePrivate(Display *display) : QtWaylandServer::zwp_pointer_gestures_v1(*display, s_version) @@ -29,14 +32,8 @@ void PointerGesturesV1InterfacePrivate::zwp_pointer_gestures_v1_get_swipe_gestur return; } - wl_resource *swipeResource = wl_resource_create(resource->client(), &zwp_pointer_gesture_swipe_v1_interface, - resource->version(), id); - if (!swipeResource) { - wl_resource_post_no_memory(resource->handle); - return; - } - - new PointerSwipeGestureV1Interface(pointer, swipeResource); + PointerSwipeGestureV1Interface *swipeGesture = PointerSwipeGestureV1Interface::get(pointer); + swipeGesture->add(resource->client(), id, resource->version()); } void PointerGesturesV1InterfacePrivate::zwp_pointer_gestures_v1_get_pinch_gesture(Resource *resource, uint32_t id, struct ::wl_resource *pointer_resource) @@ -48,14 +45,8 @@ void PointerGesturesV1InterfacePrivate::zwp_pointer_gestures_v1_get_pinch_gestur return; } - wl_resource *pinchResource = wl_resource_create(resource->client(), &zwp_pointer_gesture_pinch_v1_interface, - resource->version(), id); - if (!pinchResource) { - wl_resource_post_no_memory(resource->handle); - return; - } - - new PointerPinchGestureV1Interface(pointer, pinchResource); + PointerPinchGestureV1Interface *pinchGesture = PointerPinchGestureV1Interface::get(pointer); + pinchGesture->add(resource->client(), id, resource->version()); } void PointerGesturesV1InterfacePrivate::zwp_pointer_gestures_v1_release(Resource *resource) @@ -73,25 +64,18 @@ PointerGesturesV1Interface::~PointerGesturesV1Interface() { } -PointerSwipeGestureV1Interface::PointerSwipeGestureV1Interface(PointerInterface *pointer, - ::wl_resource *resource) - : QtWaylandServer::zwp_pointer_gesture_swipe_v1(resource) - , pointer(pointer) +PointerSwipeGestureV1Interface::PointerSwipeGestureV1Interface(PointerInterface *pointer) + : pointer(pointer) { - pointer->d_func()->registerSwipeGestureV1(this); } -PointerSwipeGestureV1Interface::~PointerSwipeGestureV1Interface() +PointerSwipeGestureV1Interface *PointerSwipeGestureV1Interface::get(PointerInterface *pointer) { if (pointer) { - pointer->d_func()->unregisterSwipeGestureV1(this); + PointerInterfacePrivate *pointerPrivate = PointerInterfacePrivate::get(pointer); + return pointerPrivate->swipeGesturesV1.data(); } -} - -void PointerSwipeGestureV1Interface::zwp_pointer_gesture_swipe_v1_destroy_resource(Resource *resource) -{ - Q_UNUSED(resource) - delete this; + return nullptr; } void PointerSwipeGestureV1Interface::zwp_pointer_gesture_swipe_v1_destroy(Resource *resource) @@ -99,25 +83,94 @@ void PointerSwipeGestureV1Interface::zwp_pointer_gesture_swipe_v1_destroy(Resour wl_resource_destroy(resource->handle); } -PointerPinchGestureV1Interface::PointerPinchGestureV1Interface(PointerInterface *pointer, - ::wl_resource *resource) - : QtWaylandServer::zwp_pointer_gesture_pinch_v1(resource) - , pointer(pointer) +void PointerSwipeGestureV1Interface::sendBegin(quint32 serial, quint32 fingerCount) { - pointer->d_func()->registerPinchGestureV1(this); -} + if (focusedClient) { + return; + } + if (!pointer->focusedSurface()) { + return; + } -PointerPinchGestureV1Interface::~PointerPinchGestureV1Interface() -{ - if (pointer) { - pointer->d_func()->unregisterPinchGestureV1(this); + const SurfaceInterface *focusedSurface = pointer->focusedSurface(); + focusedClient = focusedSurface->client(); + SeatInterface *seat = pointer->seat(); + + const QList swipeResources = resourceMap().values(focusedClient->client()); + for (Resource *swipeResource : swipeResources) { + if (swipeResource->client() == focusedClient->client()) { + send_begin(swipeResource->handle, serial, seat->timestamp(), focusedSurface->resource(), fingerCount); + } } } -void PointerPinchGestureV1Interface::zwp_pointer_gesture_pinch_v1_destroy_resource(Resource *resource) +void PointerSwipeGestureV1Interface::sendUpdate(const QSizeF &delta) { - Q_UNUSED(resource) - delete this; + if (!focusedClient) { + return; + } + + SeatInterface *seat = pointer->seat(); + + const QList swipeResources = resourceMap().values(focusedClient->client()); + for (Resource *swipeResource : swipeResources) { + if (swipeResource->client() == focusedClient->client()) { + send_update(swipeResource->handle, seat->timestamp(), + wl_fixed_from_double(delta.width()), wl_fixed_from_double(delta.height())); + } + } +} + +void PointerSwipeGestureV1Interface::sendEnd(quint32 serial) +{ + if (!focusedClient) { + return; + } + + SeatInterface *seat = pointer->seat(); + + const QList swipeResources = resourceMap().values(focusedClient->client()); + for (Resource *swipeResource : swipeResources) { + if (swipeResource->client() == focusedClient->client()) { + send_end(swipeResource->handle, serial, seat->timestamp(), false); + } + } + + // The gesture session has been just finished, reset the cached focused client. + focusedClient = nullptr; +} + +void PointerSwipeGestureV1Interface::sendCancel(quint32 serial) +{ + if (!focusedClient) { + return; + } + + SeatInterface *seat = pointer->seat(); + + const QList swipeResources = resourceMap().values(focusedClient->client()); + for (Resource *swipeResource : swipeResources) { + if (swipeResource->client() == focusedClient->client()) { + send_end(swipeResource->handle, serial, seat->timestamp(), true); + } + } + + // The gesture session has been just finished, reset the cached focused client. + focusedClient = nullptr; +} + +PointerPinchGestureV1Interface::PointerPinchGestureV1Interface(PointerInterface *pointer) + : pointer(pointer) +{ +} + +PointerPinchGestureV1Interface *PointerPinchGestureV1Interface::get(PointerInterface *pointer) +{ + if (pointer) { + PointerInterfacePrivate *pointerPrivate = PointerInterfacePrivate::get(pointer); + return pointerPrivate->pinchGesturesV1.data(); + } + return nullptr; } void PointerPinchGestureV1Interface::zwp_pointer_gesture_pinch_v1_destroy(Resource *resource) @@ -125,4 +178,81 @@ void PointerPinchGestureV1Interface::zwp_pointer_gesture_pinch_v1_destroy(Resour wl_resource_destroy(resource->handle); } +void PointerPinchGestureV1Interface::sendBegin(quint32 serial, quint32 fingerCount) +{ + if (focusedClient) { + return; // gesture is already active + } + if (!pointer->focusedSurface()) { + return; + } + + const SurfaceInterface *focusedSurface = pointer->focusedSurface(); + focusedClient = focusedSurface->client(); + SeatInterface *seat = pointer->seat(); + + const QList pinchResources = resourceMap().values(*focusedClient); + for (Resource *pinchResource : pinchResources) { + if (pinchResource->client() == focusedClient->client()) { + send_begin(pinchResource->handle, serial, seat->timestamp(), focusedSurface->resource(), fingerCount); + } + } +} + +void PointerPinchGestureV1Interface::sendUpdate(const QSizeF &delta, qreal scale, qreal rotation) +{ + if (!focusedClient) { + return; + } + + SeatInterface *seat = pointer->seat(); + + const QList pinchResources = resourceMap().values(*focusedClient); + for (Resource *pinchResource : pinchResources) { + if (pinchResource->client() == focusedClient->client()) { + send_update(pinchResource->handle, seat->timestamp(), + wl_fixed_from_double(delta.width()), wl_fixed_from_double(delta.height()), + wl_fixed_from_double(scale), wl_fixed_from_double(rotation)); + } + } +} + +void PointerPinchGestureV1Interface::sendEnd(quint32 serial) +{ + if (!focusedClient) { + return; + } + + SeatInterface *seat = pointer->seat(); + + const QList pinchResources = resourceMap().values(*focusedClient); + for (Resource *pinchResource : pinchResources) { + if (pinchResource->client() == focusedClient->client()) { + send_end(pinchResource->handle, serial, seat->timestamp(), false); + } + } + + // The gesture session has been just finished, reset the cached focused client. + focusedClient = nullptr; +} + +void PointerPinchGestureV1Interface::sendCancel(quint32 serial) +{ + if (!focusedClient) { + return; + } + + SeatInterface *seat = pointer->seat(); + + const QList pinchResources = resourceMap().values(*focusedClient); + for (Resource *pinchResource : pinchResources) { + if (pinchResource->client() == focusedClient->client()) { + send_end(pinchResource->handle, serial, seat->timestamp(), true); + } + } + + // The gesture session has been just finished, reset the cached focused client. + focusedClient = nullptr; +} + } // namespace KWaylandServer diff --git a/src/wayland/pointergestures_v1_interface_p.h b/src/wayland/pointergestures_v1_interface_p.h index 37ed456627..9bde74a771 100644 --- a/src/wayland/pointergestures_v1_interface_p.h +++ b/src/wayland/pointergestures_v1_interface_p.h @@ -14,8 +14,10 @@ namespace KWaylandServer { +class ClientConnection; class Display; class PointerInterface; +class SurfaceInterface; class PointerGesturesV1InterfacePrivate : public QtWaylandServer::zwp_pointer_gestures_v1 { @@ -33,27 +35,41 @@ protected: class PointerSwipeGestureV1Interface : public QtWaylandServer::zwp_pointer_gesture_swipe_v1 { public: - PointerSwipeGestureV1Interface(PointerInterface *pointer, ::wl_resource *resource); - ~PointerSwipeGestureV1Interface() override; + explicit PointerSwipeGestureV1Interface(PointerInterface *pointer); - QPointer pointer; + static PointerSwipeGestureV1Interface *get(PointerInterface *pointer); + + void sendBegin(quint32 serial, quint32 fingerCount); + void sendUpdate(const QSizeF &delta); + void sendEnd(quint32 serial); + void sendCancel(quint32 serial); protected: - void zwp_pointer_gesture_swipe_v1_destroy_resource(Resource *resource) override; void zwp_pointer_gesture_swipe_v1_destroy(Resource *resource) override; + +private: + PointerInterface *pointer; + QPointer focusedClient; }; class PointerPinchGestureV1Interface : public QtWaylandServer::zwp_pointer_gesture_pinch_v1 { public: - PointerPinchGestureV1Interface(PointerInterface *pointer, ::wl_resource *resource); - ~PointerPinchGestureV1Interface() override; + explicit PointerPinchGestureV1Interface(PointerInterface *pointer); - QPointer pointer; + static PointerPinchGestureV1Interface *get(PointerInterface *pointer); + + void sendBegin(quint32 serial, quint32 fingerCount); + void sendUpdate(const QSizeF &delta, qreal scale, qreal rotation); + void sendEnd(quint32 serial); + void sendCancel(quint32 serial); protected: - void zwp_pointer_gesture_pinch_v1_destroy_resource(Resource *resource) override; void zwp_pointer_gesture_pinch_v1_destroy(Resource *resource) override; + +private: + PointerInterface *pointer; + QPointer focusedClient; }; } // namespace KWaylandServer diff --git a/src/wayland/relativepointer_v1_interface.cpp b/src/wayland/relativepointer_v1_interface.cpp index 3973477f9e..a9cba272c3 100644 --- a/src/wayland/relativepointer_v1_interface.cpp +++ b/src/wayland/relativepointer_v1_interface.cpp @@ -6,9 +6,12 @@ */ #include "relativepointer_v1_interface.h" +#include "clientconnection.h" #include "display.h" #include "pointer_interface_p.h" #include "relativepointer_v1_interface_p.h" +#include "seat_interface.h" +#include "surface_interface.h" namespace KWaylandServer { @@ -34,15 +37,8 @@ void RelativePointerManagerV1InterfacePrivate::zwp_relative_pointer_manager_v1_g return; } - wl_resource *relativePointerResource = wl_resource_create(resource->client(), - &zwp_relative_pointer_v1_interface, - resource->version(), id); - if (!relativePointerResource) { - wl_resource_post_no_memory(resource->handle); - return; - } - - new RelativePointerV1Interface(pointer, relativePointerResource); + RelativePointerV1Interface *relativePointer = RelativePointerV1Interface::get(pointer); + relativePointer->add(resource->client(), id, resource->version()); } RelativePointerManagerV1Interface::RelativePointerManagerV1Interface(Display *display, QObject *parent) @@ -55,24 +51,18 @@ RelativePointerManagerV1Interface::~RelativePointerManagerV1Interface() { } -RelativePointerV1Interface::RelativePointerV1Interface(PointerInterface *pointer, ::wl_resource *resource) - : QtWaylandServer::zwp_relative_pointer_v1(resource) - , pointer(pointer) +RelativePointerV1Interface::RelativePointerV1Interface(PointerInterface *pointer) + : pointer(pointer) { - pointer->d_func()->registerRelativePointerV1(this); } -RelativePointerV1Interface::~RelativePointerV1Interface() +RelativePointerV1Interface *RelativePointerV1Interface::get(PointerInterface *pointer) { if (pointer) { - pointer->d_func()->unregisterRelativePointerV1(this); + PointerInterfacePrivate *pointerPrivate = PointerInterfacePrivate::get(pointer); + return pointerPrivate->relativePointersV1.data(); } -} - -void RelativePointerV1Interface::zwp_relative_pointer_v1_destroy_resource(Resource *resource) -{ - Q_UNUSED(resource) - delete this; + return nullptr; } void RelativePointerV1Interface::zwp_relative_pointer_v1_destroy(Resource *resource) @@ -80,4 +70,24 @@ void RelativePointerV1Interface::zwp_relative_pointer_v1_destroy(Resource *resou wl_resource_destroy(resource->handle); } +void RelativePointerV1Interface::sendRelativeMotion(const QSizeF &delta, const QSizeF &deltaNonAccelerated, quint64 microseconds) +{ + if (!pointer->focusedSurface()) { + return; + } + + ClientConnection *focusedClient = pointer->focusedSurface()->client(); + const QList pointerResources = resourceMap().values(focusedClient->client()); + for (Resource *pointerResource : pointerResources) { + if (pointerResource->client() == focusedClient->client()) { + send_relative_motion(pointerResource->handle, microseconds >> 32, microseconds & 0xffffffff, + wl_fixed_from_double(delta.width()), + wl_fixed_from_double(delta.height()), + wl_fixed_from_double(deltaNonAccelerated.width()), + wl_fixed_from_double(deltaNonAccelerated.height())); + + } + } +} + } // namespace KWaylandServer diff --git a/src/wayland/relativepointer_v1_interface_p.h b/src/wayland/relativepointer_v1_interface_p.h index e39e0197e5..73e70850eb 100644 --- a/src/wayland/relativepointer_v1_interface_p.h +++ b/src/wayland/relativepointer_v1_interface_p.h @@ -9,11 +9,10 @@ #include "qwayland-server-relative-pointer-unstable-v1.h" -#include - namespace KWaylandServer { +class ClientConnection; class Display; class PointerInterface; @@ -31,14 +30,16 @@ protected: class RelativePointerV1Interface : public QtWaylandServer::zwp_relative_pointer_v1 { public: - RelativePointerV1Interface(PointerInterface *pointer, ::wl_resource *resource); - ~RelativePointerV1Interface() override; + explicit RelativePointerV1Interface(PointerInterface *pointer); - QPointer pointer; + static RelativePointerV1Interface *get(PointerInterface *pointer); + void sendRelativeMotion(const QSizeF &delta, const QSizeF &deltaNonAccelerated, quint64 microseconds); protected: - void zwp_relative_pointer_v1_destroy_resource(Resource *resource) override; void zwp_relative_pointer_v1_destroy(Resource *resource) override; + +private: + PointerInterface *pointer; }; } // namespace KWaylandServer diff --git a/src/wayland/seat_interface.cpp b/src/wayland/seat_interface.cpp index 94e6444c74..dd18056123 100644 --- a/src/wayland/seat_interface.cpp +++ b/src/wayland/seat_interface.cpp @@ -17,10 +17,13 @@ #include "keyboard_interface.h" #include "keyboard_interface_p.h" #include "logging.h" +#include "pointerconstraints_v1_interface.h" +#include "pointergestures_v1_interface_p.h" #include "pointer_interface.h" #include "pointer_interface_p.h" #include "primaryselectiondevice_v1_interface.h" #include "primaryselectionsource_v1_interface.h" +#include "relativepointer_v1_interface_p.h" #include "surface_interface.h" #include "textinput_v2_interface_p.h" #include "textinput_v3_interface_p.h" @@ -233,11 +236,6 @@ bool forEachInterface(SurfaceInterface *surface, const QVector &interfaces, } -QVector SeatInterface::Private::pointersForSurface(SurfaceInterface *surface) const -{ - return interfacesForSurface(surface, pointers); -} - QVector SeatInterface::Private::touchsForSurface(SurfaceInterface *surface) const { return interfacesForSurface(surface, touchs); @@ -282,7 +280,6 @@ void SeatInterface::Private::registerDataDevice(DataDeviceInterface *dataDevice) auto *dragSurface = dataDevice->origin(); if (q->hasImplicitPointerGrab(dragSerial)) { drag.mode = Drag::Mode::Pointer; - drag.sourcePointer = interfaceForSurface(dragSurface, pointers); drag.transformation = globalPointer.focus.transformation; } else if (q->hasImplicitTouchGrab(dragSerial)) { drag.mode = Drag::Mode::Touch; @@ -302,7 +299,6 @@ void SeatInterface::Private::registerDataDevice(DataDeviceInterface *dataDevice) drag.transformation = globalPointer.focus.transformation; } drag.source = dataDevice; - drag.sourcePointer = interfaceForSurface(originSurface, pointers); drag.destroyConnection = QObject::connect(dataDevice, &DataDeviceInterface::aboutToBeDestroyed, q, [this] { cancelDrag(display->nextSerial()); @@ -479,10 +475,15 @@ void SeatInterface::setHasKeyboard(bool has) void SeatInterface::setHasPointer(bool has) { Q_D(); - if (d->pointer == has) { + if (d->pointer.isNull() != has) { return; } - d->pointer = has; + if (has) { + d->pointer.reset(new PointerInterface(this)); + } else { + d->pointer.reset(); + } + emit hasPointerChanged(d->pointer); } @@ -513,37 +514,10 @@ void SeatInterface::Private::getPointerCallback(wl_client *client, wl_resource * void SeatInterface::Private::getPointer(wl_client *client, wl_resource *resource, uint32_t id) { - // TODO: only create if seat has pointer? - PointerInterface *pointer = new PointerInterface(q, resource); - auto clientConnection = display->getConnection(client); - pointer->create(clientConnection, qMin(wl_resource_get_version(resource), s_pointerVersion), id); - if (!pointer->resource()) { - wl_resource_post_no_memory(resource); - delete pointer; - return; + if (pointer) { + PointerInterfacePrivate *pointerPrivate = PointerInterfacePrivate::get(pointer.data()); + pointerPrivate->add(client, id, wl_resource_get_version(resource)); } - pointers << pointer; - if (globalPointer.focus.surface && globalPointer.focus.surface->client() == clientConnection) { - // this is a pointer for the currently focused pointer surface - globalPointer.focus.pointers << pointer; - pointer->setFocusedSurface(globalPointer.focus.surface, globalPointer.focus.serial); - pointer->d_func()->sendFrame(); - if (globalPointer.focus.pointers.count() == 1) { - // got a new pointer - emit q->focusedPointerChanged(pointer); - } - } - QObject::connect(pointer, &QObject::destroyed, q, - [pointer,this] { - pointers.removeAt(pointers.indexOf(pointer)); - if (globalPointer.focus.pointers.removeOne(pointer)) { - if (globalPointer.focus.pointers.isEmpty()) { - emit q->focusedPointerChanged(nullptr); - } - } - } - ); - emit q->pointerCreated(pointer); } void SeatInterface::Private::getKeyboardCallback(wl_client *client, wl_resource *resource, uint32_t id) @@ -642,6 +616,37 @@ void SeatInterface::setPointerPos(const QPointF &pos) } d->globalPointer.pos = pos; emit pointerPosChanged(pos); + + SurfaceInterface *focusedSurface = focusedPointerSurface(); + if (!focusedSurface) { + return; + } + if (isDragPointer()) { + const auto *originSurface = dragSource()->origin(); + const bool proxyRemoteFocused = originSurface->dataProxy() && originSurface == focusedSurface; + if (!proxyRemoteFocused) { + // handled by DataDevice + return; + } + } + if (focusedSurface->lockedPointer() && focusedSurface->lockedPointer()->isLocked()) { + return; + } + + QPointF localPosition = focusedPointerSurfaceTransformation().map(pos); + SurfaceInterface *effectiveFocusedSurface = focusedSurface->inputSurfaceAt(localPosition); + if (!effectiveFocusedSurface) { + effectiveFocusedSurface = focusedSurface; + } + if (focusedSurface != effectiveFocusedSurface) { + localPosition = focusedSurface->mapToChild(effectiveFocusedSurface, localPosition); + } + + if (d->pointer->focusedSurface() != effectiveFocusedSurface) { + d->pointer->setFocusedSurface(effectiveFocusedSurface, localPosition, display()->nextSerial()); + } + + d->pointer->sendMotion(localPosition); } quint32 SeatInterface::timestamp() const @@ -683,6 +688,7 @@ void SeatInterface::setDragTarget(SurfaceInterface *surface, const QPointF &glob if (d->drag.mode == Private::Drag::Mode::Pointer) { setPointerPos(globalPosition); + pointerFrame(); } else if (d->drag.mode == Private::Drag::Mode::Touch && d->globalTouch.focus.firstTouchPos != globalPosition) { touchMove(d->globalTouch.ids.first(), globalPosition); @@ -734,58 +740,37 @@ void SeatInterface::setFocusedPointerSurface(SurfaceInterface *surface, const QM // ignore return; } + const quint32 serial = d->display->nextSerial(); - QSet framePointers; - for (auto it = d->globalPointer.focus.pointers.constBegin(), end = d->globalPointer.focus.pointers.constEnd(); it != end; ++it) { - (*it)->setFocusedSurface(nullptr, serial); - framePointers << *it; - } + if (d->globalPointer.focus.surface) { disconnect(d->globalPointer.focus.destroyConnection); } d->globalPointer.focus = Private::Pointer::Focus(); d->globalPointer.focus.surface = surface; - auto p = d->pointersForSurface(surface); - d->globalPointer.focus.pointers = p; if (d->globalPointer.focus.surface) { - d->globalPointer.focus.destroyConnection = connect(surface, &QObject::destroyed, this, - [this] { - Q_D(); - d->globalPointer.focus = Private::Pointer::Focus(); - emit focusedPointerChanged(nullptr); - } - ); - d->globalPointer.focus.offset = QPointF(); - d->globalPointer.focus.transformation = transformation; + d->globalPointer.focus.destroyConnection = connect(surface, &QObject::destroyed, this, [this] { + Q_D(); + d->globalPointer.focus = Private::Pointer::Focus(); + }); d->globalPointer.focus.serial = serial; + d->globalPointer.focus.transformation = transformation; + d->globalPointer.focus.offset = QPointF(); } - if (p.isEmpty()) { - emit focusedPointerChanged(nullptr); - for (auto p : qAsConst(framePointers)) - { - p->d_func()->sendFrame(); - } - return; - } - // TODO: signal with all pointers - emit focusedPointerChanged(p.first()); - for (auto it = p.constBegin(), end = p.constEnd(); it != end; ++it) { - (*it)->setFocusedSurface(surface, serial); - framePointers << *it; - } - for (auto p : qAsConst(framePointers)) - { - p->d_func()->sendFrame(); - } -} -PointerInterface *SeatInterface::focusedPointer() const -{ - Q_D(); - if (d->globalPointer.focus.pointers.isEmpty()) { - return nullptr; + 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); } - return d->globalPointer.focus.pointers.first(); } void SeatInterface::setFocusedPointerSurfacePosition(const QPointF &surfacePosition) @@ -818,6 +803,12 @@ QMatrix4x4 SeatInterface::focusedPointerSurfaceTransformation() const return d->globalPointer.focus.transformation; } +PointerInterface *SeatInterface::pointer() const +{ + Q_D(); + return d->pointer.data(); +} + namespace { static quint32 qtToWaylandButton(Qt::MouseButton button) { @@ -863,32 +854,15 @@ bool SeatInterface::isPointerButtonPressed(quint32 button) const return it.value() == Private::Pointer::State::Pressed ? true : false; } -void SeatInterface::pointerAxisV5(Qt::Orientation orientation, qreal delta, qint32 discreteDelta, PointerAxisSource source) +void SeatInterface::pointerAxis(Qt::Orientation orientation, qreal delta, qint32 discreteDelta, PointerAxisSource source) { Q_D(); + Q_ASSERT(d->pointer); if (d->drag.mode == Private::Drag::Mode::Pointer) { // ignore return; } - if (d->globalPointer.focus.surface) { - for (auto it = d->globalPointer.focus.pointers.constBegin(), end = d->globalPointer.focus.pointers.constEnd(); it != end; ++it) { - (*it)->axis(orientation, delta, discreteDelta, source); - } - } -} - -void SeatInterface::pointerAxis(Qt::Orientation orientation, quint32 delta) -{ - Q_D(); - if (d->drag.mode == Private::Drag::Mode::Pointer) { - // ignore - return; - } - if (d->globalPointer.focus.surface) { - for (auto it = d->globalPointer.focus.pointers.constBegin(), end = d->globalPointer.focus.pointers.constEnd(); it != end; ++it) { - (*it)->axis(orientation, delta); - } - } + d->pointer->sendAxis(orientation, delta, discreteDelta, source); } void SeatInterface::pointerButtonPressed(Qt::MouseButton button) @@ -903,6 +877,7 @@ void SeatInterface::pointerButtonPressed(Qt::MouseButton button) void SeatInterface::pointerButtonPressed(quint32 button) { Q_D(); + Q_ASSERT(d->pointer); const quint32 serial = d->display->nextSerial(); d->updatePointerButtonSerial(button, serial); d->updatePointerButtonState(button, Private::Pointer::State::Pressed); @@ -910,16 +885,11 @@ void SeatInterface::pointerButtonPressed(quint32 button) // ignore return; } - if (auto *focusSurface = d->globalPointer.focus.surface) { - for (auto it = d->globalPointer.focus.pointers.constBegin(), end = d->globalPointer.focus.pointers.constEnd(); it != end; ++it) { - (*it)->buttonPressed(button, serial); - } - if (focusSurface == d->globalKeyboard.focus.surface) { - // update the focused child surface - auto p = focusedPointer(); - if (p && d->keyboard) { - d->keyboard->d->focusChildSurface(p->d_func()->focusedChildSurface, serial); - } + d->pointer->sendPressed(button, serial); + + if (focusedPointerSurface() == focusedKeyboardSurface()) { + if (d->keyboard) { + d->keyboard->setFocusedSurface(d->pointer->focusedSurface(), serial); } } } @@ -936,6 +906,7 @@ void SeatInterface::pointerButtonReleased(Qt::MouseButton button) void SeatInterface::pointerButtonReleased(quint32 button) { Q_D(); + Q_ASSERT(d->pointer); const quint32 serial = d->display->nextSerial(); const quint32 currentButtonSerial = pointerButtonSerial(button); d->updatePointerButtonSerial(button, serial); @@ -948,11 +919,14 @@ void SeatInterface::pointerButtonReleased(quint32 button) d->endDrag(serial); return; } - if (d->globalPointer.focus.surface) { - for (auto it = d->globalPointer.focus.pointers.constBegin(), end = d->globalPointer.focus.pointers.constEnd(); it != end; ++it) { - (*it)->buttonReleased(button, serial); - } - } + d->pointer->sendReleased(button, serial); +} + +void SeatInterface::pointerFrame() +{ + Q_D(); + Q_ASSERT(d->pointer); + d->pointer->sendFrame(); } quint32 SeatInterface::pointerButtonSerial(Qt::MouseButton button) const @@ -973,133 +947,100 @@ quint32 SeatInterface::pointerButtonSerial(quint32 button) const void SeatInterface::relativePointerMotion(const QSizeF &delta, const QSizeF &deltaNonAccelerated, quint64 microseconds) { Q_D(); - if (d->globalPointer.focus.surface) { - for (auto it = d->globalPointer.focus.pointers.constBegin(), end = d->globalPointer.focus.pointers.constEnd(); it != end; ++it) { - (*it)->relativeMotion(delta, deltaNonAccelerated, microseconds); - } + Q_ASSERT(d->pointer); + + auto relativePointer = RelativePointerV1Interface::get(pointer()); + if (relativePointer) { + relativePointer->sendRelativeMotion(delta, deltaNonAccelerated, microseconds); } } void SeatInterface::startPointerSwipeGesture(quint32 fingerCount) { Q_D(); - if (!d->globalPointer.gestureSurface.isNull()) { - return; + Q_ASSERT(d->pointer); + + auto swipeGesture = PointerSwipeGestureV1Interface::get(pointer()); + if (swipeGesture) { + swipeGesture->sendBegin(d->display->nextSerial(), fingerCount); } - d->globalPointer.gestureSurface = QPointer(d->globalPointer.focus.surface); - if (d->globalPointer.gestureSurface.isNull()) { - return; - } - const quint32 serial = d->display->nextSerial(); - forEachInterface(d->globalPointer.gestureSurface.data(), d->pointers, - [serial, fingerCount] (PointerInterface *p) { - p->d_func()->startSwipeGesture(serial, fingerCount); - } - ); } void SeatInterface::updatePointerSwipeGesture(const QSizeF &delta) { Q_D(); - if (d->globalPointer.gestureSurface.isNull()) { - return; + Q_ASSERT(d->pointer); + + auto swipeGesture = PointerSwipeGestureV1Interface::get(pointer()); + if (swipeGesture) { + swipeGesture->sendUpdate(delta); } - forEachInterface(d->globalPointer.gestureSurface.data(), d->pointers, - [delta] (PointerInterface *p) { - p->d_func()->updateSwipeGesture(delta); - } - ); } void SeatInterface::endPointerSwipeGesture() { Q_D(); - if (d->globalPointer.gestureSurface.isNull()) { - return; + Q_ASSERT(d->pointer); + + auto swipeGesture = PointerSwipeGestureV1Interface::get(pointer()); + if (swipeGesture) { + swipeGesture->sendEnd(d->display->nextSerial()); } - const quint32 serial = d->display->nextSerial(); - forEachInterface(d->globalPointer.gestureSurface.data(), d->pointers, - [serial] (PointerInterface *p) { - p->d_func()->endSwipeGesture(serial); - } - ); - d->globalPointer.gestureSurface.clear(); } void SeatInterface::cancelPointerSwipeGesture() { Q_D(); - if (d->globalPointer.gestureSurface.isNull()) { - return; + Q_ASSERT(d->pointer); + + auto swipeGesture = PointerSwipeGestureV1Interface::get(pointer()); + if (swipeGesture) { + swipeGesture->sendCancel(d->display->nextSerial()); } - const quint32 serial = d->display->nextSerial(); - forEachInterface(d->globalPointer.gestureSurface.data(), d->pointers, - [serial] (PointerInterface *p) { - p->d_func()->cancelSwipeGesture(serial); - } - ); - d->globalPointer.gestureSurface.clear(); } void SeatInterface::startPointerPinchGesture(quint32 fingerCount) { Q_D(); - if (!d->globalPointer.gestureSurface.isNull()) { - return; + Q_ASSERT(d->pointer); + + auto pinchGesture = PointerPinchGestureV1Interface::get(pointer()); + if (pinchGesture) { + pinchGesture->sendBegin(d->display->nextSerial(), fingerCount); } - d->globalPointer.gestureSurface = QPointer(d->globalPointer.focus.surface); - if (d->globalPointer.gestureSurface.isNull()) { - return; - } - const quint32 serial = d->display->nextSerial(); - forEachInterface(d->globalPointer.gestureSurface.data(), d->pointers, - [serial, fingerCount] (PointerInterface *p) { - p->d_func()->startPinchGesture(serial, fingerCount); - } - ); } void SeatInterface::updatePointerPinchGesture(const QSizeF &delta, qreal scale, qreal rotation) { Q_D(); - if (d->globalPointer.gestureSurface.isNull()) { - return; + Q_ASSERT(d->pointer); + + auto pinchGesture = PointerPinchGestureV1Interface::get(pointer()); + if (pinchGesture) { + pinchGesture->sendUpdate(delta, scale, rotation); } - forEachInterface(d->globalPointer.gestureSurface.data(), d->pointers, - [delta, scale, rotation] (PointerInterface *p) { - p->d_func()->updatePinchGesture(delta, scale, rotation); - } - ); } void SeatInterface::endPointerPinchGesture() { Q_D(); - if (d->globalPointer.gestureSurface.isNull()) { - return; + Q_ASSERT(d->pointer); + + auto pinchGesture = PointerPinchGestureV1Interface::get(pointer()); + if (pinchGesture) { + pinchGesture->sendEnd(d->display->nextSerial()); } - const quint32 serial = d->display->nextSerial(); - forEachInterface(d->globalPointer.gestureSurface.data(), d->pointers, - [serial] (PointerInterface *p) { - p->d_func()->endPinchGesture(serial); - } - ); - d->globalPointer.gestureSurface.clear(); } void SeatInterface::cancelPointerPinchGesture() { Q_D(); - if (d->globalPointer.gestureSurface.isNull()) { - return; + Q_ASSERT(d->pointer); + + auto pinchGesture = PointerPinchGestureV1Interface::get(pointer()); + if (pinchGesture) { + pinchGesture->sendCancel(d->display->nextSerial()); } - const quint32 serial = d->display->nextSerial(); - forEachInterface(d->globalPointer.gestureSurface.data(), d->pointers, - [serial] (PointerInterface *p) { - p->d_func()->cancelPinchGesture(serial); - } - ); - d->globalPointer.gestureSurface.clear(); } SurfaceInterface *SeatInterface::focusedKeyboardSurface() const @@ -1267,18 +1208,9 @@ void SeatInterface::touchDown(qint32 id, const QPointF &globalPosition) if (id == 0 && d->globalTouch.focus.touchs.isEmpty()) { // If the client did not bind the touch interface fall back // to at least emulating touch through pointer events. - forEachInterface(focusedTouchSurface(), d->pointers, - [this, pos, serial] (PointerInterface *p) { - wl_pointer_send_enter(p->resource(), serial, - focusedTouchSurface()->resource(), - wl_fixed_from_double(pos.x()), wl_fixed_from_double(pos.y())); - wl_pointer_send_motion(p->resource(), timestamp(), - wl_fixed_from_double(pos.x()), wl_fixed_from_double(pos.y())); - - wl_pointer_send_button(p->resource(), serial, timestamp(), BTN_LEFT, WL_POINTER_BUTTON_STATE_PRESSED); - p->d_func()->sendFrame(); - } - ); + d->pointer->setFocusedSurface(focusedTouchSurface(), pos, serial); + d->pointer->sendMotion(pos); + d->pointer->sendFrame(); } #endif @@ -1300,13 +1232,8 @@ void SeatInterface::touchMove(qint32 id, const QPointF &globalPosition) if (id == 0 && d->globalTouch.focus.touchs.isEmpty()) { // Client did not bind touch, fall back to emulating with pointer events. - forEachInterface(focusedTouchSurface(), d->pointers, - [this, pos] (PointerInterface *p) { - wl_pointer_send_motion(p->resource(), timestamp(), - wl_fixed_from_double(pos.x()), wl_fixed_from_double(pos.y())); - p->d_func()->sendFrame(); - } - ); + d->pointer->sendMotion(pos); + d->pointer->sendFrame(); } emit touchMoved(id, d->globalTouch.ids[id], globalPosition); } @@ -1329,12 +1256,8 @@ void SeatInterface::touchUp(qint32 id) if (id == 0 && d->globalTouch.focus.touchs.isEmpty()) { // Client did not bind touch, fall back to emulating with pointer events. const quint32 serial = display()->nextSerial(); - forEachInterface(focusedTouchSurface(), d->pointers, - [this, serial] (PointerInterface *p) { - wl_pointer_send_button(p->resource(), serial, timestamp(), BTN_LEFT, WL_POINTER_BUTTON_STATE_RELEASED); - p->d_func()->sendFrame(); - } - ); + d->pointer->sendReleased(BTN_LEFT, serial); + d->pointer->sendFrame(); } #endif @@ -1401,16 +1324,6 @@ SurfaceInterface *SeatInterface::dragSurface() const return d->drag.surface; } -PointerInterface *SeatInterface::dragPointer() const -{ - Q_D(); - if (d->drag.mode != Private::Drag::Mode::Pointer) { - return nullptr; - } - - return d->drag.sourcePointer; -} - DataDeviceInterface *SeatInterface::dragSource() const { Q_D(); diff --git a/src/wayland/seat_interface.h b/src/wayland/seat_interface.h index bbb323290c..7801919323 100644 --- a/src/wayland/seat_interface.h +++ b/src/wayland/seat_interface.h @@ -90,10 +90,13 @@ enum class PointerAxisSource { * seat->setFocusedPointerSurface(surface, QPointF(100, 200)); // surface at it's global position * seat->setTimestamp(100); * seat->setPointerPos(QPointF(350, 210)); // global pos, local pos in surface: 250,10 + * seat->pointerFrame(); * seat->setTimestamp(110); * seat->pointerButtonPressed(Qt::LeftButton); + * seat->pointerFrame(); * seat->setTimestamp(120); * seat->pointerButtonReleased(Qt::LeftButton); + * seat->pointerFrame(); * @endcode * * @see KeyboardInterface @@ -190,12 +193,6 @@ public: * @see dragSurfaceChanged **/ SurfaceInterface *dragSurface() const; - /** - * @returns The PointerInterface which triggered the drag operation - * @since 5.6 - * @see isDragPointer - **/ - PointerInterface *dragPointer() const; /** * @returns The DataDeviceInterface which started the drag and drop operation. * @see isDrag @@ -291,11 +288,7 @@ public: * @see setFocusedPointerSurface **/ SurfaceInterface *focusedPointerSurface() const; - /** - * @returns The PointerInterface belonging to the focused pointer surface, if any. - * @see setFocusedPointerSurface - **/ - PointerInterface *focusedPointer() const; + PointerInterface *pointer() const; /** * Updates the global position of the currently focused pointer surface. * @@ -348,6 +341,7 @@ public: * @overload **/ void pointerButtonPressed(Qt::MouseButton button); + void pointerFrame(); /** * Marks the @p button as released. * @@ -384,13 +378,8 @@ public: * @param discreteDelta The number of discrete steps, e.g. mouse wheel clicks. * @param source Describes how the axis event was physically generated. * @since 5.59 - * @todo Drop V5 suffix with KF6. **/ - void pointerAxisV5(Qt::Orientation orientation, qreal delta, qint32 discreteDelta, PointerAxisSource source); - /** - * @see pointerAxisV5 - **/ - void pointerAxis(Qt::Orientation orientation, quint32 delta); + void pointerAxis(Qt::Orientation orientation, qreal delta, qint32 discreteDelta, PointerAxisSource source); /** * @returns true if there is a pressed button with the given @p serial * @since 5.6 @@ -664,16 +653,9 @@ Q_SIGNALS: void touchMoved(qint32 id, quint32 serial, const QPointF &globalPosition); void timestampChanged(quint32); - void pointerCreated(KWaylandServer::PointerInterface*); void keyboardCreated(KWaylandServer::KeyboardInterface*); void touchCreated(KWaylandServer::TouchInterface*); - /** - * Emitted whenever the focused pointer changes - * @since 5.6 - **/ - void focusedPointerChanged(KWaylandServer::PointerInterface*); - /** * Emitted whenever the selection changes * @since 5.56 diff --git a/src/wayland/seat_interface_p.h b/src/wayland/seat_interface_p.h index 4882984b70..d1ec9e637e 100644 --- a/src/wayland/seat_interface_p.h +++ b/src/wayland/seat_interface_p.h @@ -34,7 +34,6 @@ public: void bind(wl_client *client, uint32_t version, uint32_t id) override; void sendCapabilities(wl_resource *r); void sendName(wl_resource *r); - QVector pointersForSurface(SurfaceInterface *surface) const; QVector touchsForSurface(SurfaceInterface *surface) const; QVector dataDevicesForSurface(SurfaceInterface *surface) const; void registerPrimarySelectionDevice(PrimarySelectionDeviceV1Interface *primarySelectionDevice); @@ -45,12 +44,11 @@ public: quint32 nextSerial() const; QString name; - bool pointer = false; bool touch = false; QList resources; quint32 timestamp = 0; - QVector pointers; QScopedPointer keyboard; + QScopedPointer pointer; QVector touchs; QVector dataDevices; QVector primarySelectionDevices; @@ -78,14 +76,12 @@ public: QPointF pos; struct Focus { SurfaceInterface *surface = nullptr; - QVector pointers; QMetaObject::Connection destroyConnection; QPointF offset = QPointF(); QMatrix4x4 transformation; quint32 serial = 0; }; Focus focus; - QPointer gestureSurface; }; Pointer globalPointer; void updatePointerButtonSerial(quint32 button, quint32 serial); @@ -128,7 +124,6 @@ public: DataDeviceInterface *source = nullptr; QPointer target; SurfaceInterface *surface = nullptr; - PointerInterface *sourcePointer = nullptr; TouchInterface *sourceTouch = nullptr; QMatrix4x4 transformation; QMetaObject::Connection destroyConnection; diff --git a/src/wayland/tests/renderingservertest.cpp b/src/wayland/tests/renderingservertest.cpp index f4687e97b2..7bbe421aab 100644 --- a/src/wayland/tests/renderingservertest.cpp +++ b/src/wayland/tests/renderingservertest.cpp @@ -191,6 +191,7 @@ void CompositorWindow::mouseMoveEvent(QMouseEvent *event) } m_seat->setTimestamp(event->timestamp()); m_seat->setPointerPos(event->localPos().toPoint()); + m_seat->pointerFrame(); } void CompositorWindow::mousePressEvent(QMouseEvent *event) @@ -203,6 +204,7 @@ void CompositorWindow::mousePressEvent(QMouseEvent *event) } m_seat->setTimestamp(event->timestamp()); m_seat->pointerButtonPressed(event->button()); + m_seat->pointerFrame(); } void CompositorWindow::mouseReleaseEvent(QMouseEvent *event) @@ -210,6 +212,7 @@ void CompositorWindow::mouseReleaseEvent(QMouseEvent *event) QWidget::mouseReleaseEvent(event); m_seat->setTimestamp(event->timestamp()); m_seat->pointerButtonReleased(event->button()); + m_seat->pointerFrame(); } void CompositorWindow::wheelEvent(QWheelEvent *event) @@ -218,11 +221,12 @@ void CompositorWindow::wheelEvent(QWheelEvent *event) m_seat->setTimestamp(event->timestamp()); const QPoint &angle = event->angleDelta() / (8 * 15); if (angle.x() != 0) { - m_seat->pointerAxis(Qt::Horizontal, angle.x()); + m_seat->pointerAxis(Qt::Horizontal, angle.x(), 1, KWaylandServer::PointerAxisSource::Wheel); } if (angle.y() != 0) { - m_seat->pointerAxis(Qt::Vertical, angle.y()); + m_seat->pointerAxis(Qt::Vertical, angle.y(), 1, KWaylandServer::PointerAxisSource::Wheel); } + m_seat->pointerFrame(); } int main(int argc, char **argv)