diff --git a/autotests/client/test_wayland_seat.cpp b/autotests/client/test_wayland_seat.cpp --- a/autotests/client/test_wayland_seat.cpp +++ b/autotests/client/test_wayland_seat.cpp @@ -392,6 +392,8 @@ QVERIFY(!m_seatInterface->focusedPointer()); Pointer *p = m_seat->createPointer(m_seat); + QSignalSpy frameSpy(p, &Pointer::frame); + QVERIFY(frameSpy.isValid()); const Pointer &cp = *p; QVERIFY(p->isValid()); QScopedPointer relativePointer(m_relativePointerManager->createRelativePointer(p)); @@ -404,12 +406,15 @@ 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(); - QTest::qWait(100); + QVERIFY(frameSpy.wait()); + QCOMPARE(frameSpy.count(), 2); QSignalSpy enteredSpy(p, SIGNAL(entered(quint32,QPointF))); QVERIFY(enteredSpy.isValid()); @@ -436,6 +441,7 @@ QVERIFY(enteredSpy.wait()); 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); @@ -447,6 +453,7 @@ m_seatInterface->setTimestamp(1); m_seatInterface->setPointerPos(QPoint(10, 16)); QVERIFY(motionSpy.wait()); + QCOMPARE(frameSpy.count(), 4); QCOMPARE(motionSpy.first().first().toPoint(), QPoint(0, 1)); QCOMPARE(motionSpy.first().last().value(), quint32(1)); @@ -462,9 +469,11 @@ m_seatInterface->setTimestamp(2); m_seatInterface->pointerAxis(Qt::Horizontal, 10); QVERIFY(axisSpy.wait()); + QCOMPARE(frameSpy.count(), 5); m_seatInterface->setTimestamp(3); m_seatInterface->pointerAxis(Qt::Vertical, 20); QVERIFY(axisSpy.wait()); + QCOMPARE(frameSpy.count(), 6); QCOMPARE(axisSpy.first().at(0).value(), quint32(2)); QCOMPARE(axisSpy.first().at(1).value(), Pointer::Axis::Horizontal); QCOMPARE(axisSpy.first().at(2).value(), qreal(10)); @@ -477,18 +486,22 @@ m_seatInterface->setTimestamp(4); m_seatInterface->pointerButtonPressed(1); QVERIFY(buttonSpy.wait()); + QCOMPARE(frameSpy.count(), 7); QCOMPARE(buttonSpy.at(0).at(0).value(), m_display->serial()); m_seatInterface->setTimestamp(5); m_seatInterface->pointerButtonPressed(2); QVERIFY(buttonSpy.wait()); + QCOMPARE(frameSpy.count(), 8); QCOMPARE(buttonSpy.at(1).at(0).value(), m_display->serial()); m_seatInterface->setTimestamp(6); m_seatInterface->pointerButtonReleased(2); QVERIFY(buttonSpy.wait()); + QCOMPARE(frameSpy.count(), 9); QCOMPARE(buttonSpy.at(2).at(0).value(), m_display->serial()); m_seatInterface->setTimestamp(7); m_seatInterface->pointerButtonReleased(1); QVERIFY(buttonSpy.wait()); + QCOMPARE(frameSpy.count(), 10); QCOMPARE(buttonSpy.count(), 4); // timestamp @@ -521,6 +534,7 @@ m_seatInterface->setFocusedPointerSurface(nullptr); QCOMPARE(focusedPointerChangedSpy.count(), 5); QVERIFY(leftSpy.wait()); + QCOMPARE(frameSpy.count(), 11); QCOMPARE(leftSpy.first().first().value(), m_display->serial()); QVERIFY(!p->enteredSurface()); QVERIFY(!cp.enteredSurface()); @@ -533,6 +547,7 @@ m_seatInterface->setFocusedPointerSurface(serverSurface, QPoint(0, 0)); QCOMPARE(focusedPointerChangedSpy.count(), 6); QVERIFY(enteredSpy.wait()); + QCOMPARE(frameSpy.count(), 12); QCOMPARE(p->enteredSurface(), s); QCOMPARE(cp.enteredSurface(), s); diff --git a/src/client/pointer.h b/src/client/pointer.h --- a/src/client/pointer.h +++ b/src/client/pointer.h @@ -170,6 +170,14 @@ **/ void axisChanged(quint32 time, KWayland::Client::Pointer::Axis axis, qreal delta); + /** + * Indicates the end of a set of events that logically belong together. + * A client is expected to accumulate the data in all events within the + * frame before proceeding. + * @since 5.45 + **/ + void frame(); + private: class Private; QScopedPointer d; diff --git a/src/client/pointer.cpp b/src/client/pointer.cpp --- a/src/client/pointer.cpp +++ b/src/client/pointer.cpp @@ -50,6 +50,10 @@ static void buttonCallback(void *data, wl_pointer *pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state); static void axisCallback(void *data, wl_pointer *pointer, uint32_t time, uint32_t axis, wl_fixed_t value); + static void frameCallback(void *data, wl_pointer *pointer); + static void axisSourceCallback(void *data, wl_pointer *pointer, uint32_t axis_source); + static void axisStopCallback(void *data, wl_pointer *pointer, uint32_t time, uint32_t axis); + static void axisDiscreteCallback(void *data, wl_pointer *pointer, uint32_t axis, int32_t discrete); Pointer *q; static const wl_pointer_listener s_listener; @@ -73,7 +77,11 @@ leaveCallback, motionCallback, buttonCallback, - axisCallback + axisCallback, + frameCallback, + axisSourceCallback, + axisStopCallback, + axisDiscreteCallback }; Pointer::Pointer(QObject *parent) @@ -166,6 +174,39 @@ emit p->q->axisChanged(time, toAxis(), wl_fixed_to_double(value)); } +void Pointer::Private::frameCallback(void *data, wl_pointer *pointer) +{ + auto p = reinterpret_cast(data); + Q_ASSERT(p->pointer == pointer); + emit p->q->frame(); +} + +void Pointer::Private::axisSourceCallback(void *data, wl_pointer *pointer, uint32_t axis_source) +{ + Q_UNUSED(data) + Q_UNUSED(pointer) + Q_UNUSED(axis_source) + // TODO: implement +} + +void Pointer::Private::axisStopCallback(void *data, wl_pointer *pointer, uint32_t time, uint32_t axis) +{ + Q_UNUSED(data) + Q_UNUSED(pointer) + Q_UNUSED(time) + Q_UNUSED(axis) + // TODO: implement +} + +void Pointer::Private::axisDiscreteCallback(void *data, wl_pointer *pointer, uint32_t axis, int32_t discrete) +{ + Q_UNUSED(data) + Q_UNUSED(pointer) + Q_UNUSED(axis) + Q_UNUSED(discrete) + // TODO: implement +} + void Pointer::setCursor(Surface *surface, const QPoint &hotspot) { Q_ASSERT(isValid()); diff --git a/src/client/registry.cpp b/src/client/registry.cpp --- a/src/client/registry.cpp +++ b/src/client/registry.cpp @@ -138,7 +138,7 @@ &Registry::shmRemoved }}, {Registry::Interface::Seat, { - 4, + 5, QByteArrayLiteral("wl_seat"), &wl_seat_interface, &Registry::seatAnnounced, diff --git a/src/server/pointer_interface.cpp b/src/server/pointer_interface.cpp --- a/src/server/pointer_interface.cpp +++ b/src/server/pointer_interface.cpp @@ -211,6 +211,14 @@ } } +void PointerInterface::Private::sendFrame() +{ + if (!resource || wl_resource_get_version(resource) < WL_POINTER_FRAME_SINCE_VERSION) { + return; + } + wl_pointer_send_frame(resource); +} + #ifndef DOXYGEN_SHOULD_SKIP_THIS const struct wl_pointer_interface PointerInterface::Private::s_interface = { setCursorCallback, @@ -242,11 +250,13 @@ 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())); + d->sendFrame(); } } }); @@ -269,6 +279,7 @@ [this] { Q_D(); d->sendLeave(d->focusedChildSurface.data(), d->global->display()->nextSerial()); + d->sendFrame(); d->focusedSurface = nullptr; d->focusedChildSurface.clear(); } @@ -291,6 +302,7 @@ 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) @@ -301,6 +313,7 @@ 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, quint32 delta) @@ -313,6 +326,7 @@ 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(); } void PointerInterface::Private::setCursorCallback(wl_client *client, wl_resource *resource, uint32_t serial, diff --git a/src/server/pointer_interface_p.h b/src/server/pointer_interface_p.h --- a/src/server/pointer_interface_p.h +++ b/src/server/pointer_interface_p.h @@ -49,6 +49,7 @@ void sendLeave(SurfaceInterface *surface, quint32 serial); void sendEnter(SurfaceInterface *surface, const QPointF &parentSurfacePosition, quint32 serial); + void sendFrame(); void registerRelativePointer(RelativePointerInterface *relativePointer); void registerSwipeGesture(PointerSwipeGestureInterface *gesture); diff --git a/src/server/seat_interface.cpp b/src/server/seat_interface.cpp --- a/src/server/seat_interface.cpp +++ b/src/server/seat_interface.cpp @@ -46,10 +46,10 @@ namespace Server { -const quint32 SeatInterface::Private::s_version = 4; -const qint32 SeatInterface::Private::s_pointerVersion = 3; -const qint32 SeatInterface::Private::s_touchVersion = 3; -const qint32 SeatInterface::Private::s_keyboardVersion = 4; +const quint32 SeatInterface::Private::s_version = 5; +const qint32 SeatInterface::Private::s_pointerVersion = 5; +const qint32 SeatInterface::Private::s_touchVersion = 5; +const qint32 SeatInterface::Private::s_keyboardVersion = 5; SeatInterface::Private::Private(SeatInterface *q, Display *display) : Global::Private(display, &wl_seat_interface, s_version) @@ -61,7 +61,8 @@ const struct wl_seat_interface SeatInterface::Private::s_interface = { getPointerCallback, getKeyboardCallback, - getTouchCallback + getTouchCallback, + releaseCallback }; #endif @@ -114,6 +115,12 @@ cast(r)->resources.removeAll(r); } +void SeatInterface::Private::releaseCallback(wl_client *client, wl_resource *resource) +{ + Q_UNUSED(client) + wl_resource_destroy(resource); +} + void SeatInterface::Private::updatePointerButtonSerial(quint32 button, quint32 serial) { auto it = globalPointer.buttonSerials.find(button); @@ -473,6 +480,7 @@ // 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); @@ -687,8 +695,10 @@ 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); @@ -711,12 +721,21 @@ } 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(); } } @@ -1322,6 +1341,7 @@ 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(); } ); if (!result) { diff --git a/src/server/seat_interface_p.h b/src/server/seat_interface_p.h --- a/src/server/seat_interface_p.h +++ b/src/server/seat_interface_p.h @@ -186,6 +186,7 @@ static void getPointerCallback(wl_client *client, wl_resource *resource, uint32_t id); static void getKeyboardCallback(wl_client *client, wl_resource *resource, uint32_t id); static void getTouchCallback(wl_client *client, wl_resource *resource, uint32_t id); + static void releaseCallback(wl_client *client, wl_resource *resource); static const struct wl_seat_interface s_interface; static const quint32 s_version; static const qint32 s_pointerVersion;