diff --git a/src/wayland/CMakeLists.txt b/src/wayland/CMakeLists.txt
index bfb268b484..c444510b29 100644
--- a/src/wayland/CMakeLists.txt
+++ b/src/wayland/CMakeLists.txt
@@ -23,6 +23,8 @@ set(SERVER_LIB_SRCS
plasmawindowmanagement_interface.cpp
qtsurfaceextension_interface.cpp
region_interface.cpp
+ relativepointer_interface.cpp
+ relativepointer_interface_v1.cpp
resource.cpp
seat_interface.cpp
slide_interface.cpp
@@ -95,6 +97,11 @@ ecm_add_wayland_server_protocol(SERVER_LIB_SRCS
BASENAME contrast
)
+ecm_add_wayland_server_protocol(SERVER_LIB_SRCS
+ PROTOCOL ${KWAYLAND_SOURCE_DIR}/src/client/protocols/relative-pointer-unstable-v1.xml
+ BASENAME relativepointer-unstable-v1
+)
+
ecm_add_wayland_server_protocol(SERVER_LIB_SRCS
PROTOCOL ${KWAYLAND_SOURCE_DIR}/src/client/protocols/slide.xml
BASENAME slide
@@ -180,6 +187,7 @@ install(FILES
plasmawindowmanagement_interface.h
qtsurfaceextension_interface.h
region_interface.h
+ relativepointer_interface.h
resource.h
seat_interface.h
server_decoration_interface.h
diff --git a/src/wayland/autotests/client/test_wayland_registry.cpp b/src/wayland/autotests/client/test_wayland_registry.cpp
index 32acff300e..263c22317f 100644
--- a/src/wayland/autotests/client/test_wayland_registry.cpp
+++ b/src/wayland/autotests/client/test_wayland_registry.cpp
@@ -27,6 +27,7 @@ License along with this library. If not, see .
#include "../../src/client/registry.h"
#include "../../src/client/output.h"
#include "../../src/client/seat.h"
+#include "../../src/client/relativepointer.h"
#include "../../src/client/server_decoration.h"
#include "../../src/client/shell.h"
#include "../../src/client/subcompositor.h"
@@ -47,6 +48,7 @@ License along with this library. If not, see .
#include "../../src/server/outputdevice_interface.h"
#include "../../src/server/textinput_interface.h"
#include "../../src/server/xdgshell_interface.h"
+#include "../../src/server/relativepointer_interface.h"
// Wayland
#include
#include
@@ -54,6 +56,7 @@ License along with this library. If not, see .
#include
#include
#include
+#include
class TestWaylandRegistry : public QObject
{
@@ -80,6 +83,7 @@ private Q_SLOTS:
void testBindTextInputManagerUnstableV0();
void testBindTextInputManagerUnstableV2();
void testBindXdgShellUnstableV5();
+ void testBindRelativePointerManagerUnstableV1();
void testGlobalSync();
void testGlobalSyncThreaded();
void testRemoval();
@@ -101,6 +105,7 @@ private:
KWayland::Server::TextInputManagerInterface *m_textInputManagerV0;
KWayland::Server::TextInputManagerInterface *m_textInputManagerV2;
KWayland::Server::XdgShellInterface *m_xdgShellUnstableV5;
+ KWayland::Server::RelativePointerManagerInterface *m_relativePointerV1;
};
static const QString s_socketName = QStringLiteral("kwin-test-wayland-registry-0");
@@ -120,6 +125,7 @@ TestWaylandRegistry::TestWaylandRegistry(QObject *parent)
, m_textInputManagerV0(nullptr)
, m_textInputManagerV2(nullptr)
, m_xdgShellUnstableV5(nullptr)
+ , m_relativePointerV1(nullptr)
{
}
@@ -161,6 +167,9 @@ void TestWaylandRegistry::init()
m_xdgShellUnstableV5 = m_display->createXdgShell(KWayland::Server::XdgShellInterfaceVersion::UnstableV5);
m_xdgShellUnstableV5->create();
QCOMPARE(m_xdgShellUnstableV5->interfaceVersion(), KWayland::Server::XdgShellInterfaceVersion::UnstableV5);
+ m_relativePointerV1 = m_display->createRelativePointerManager(KWayland::Server::RelativePointerInterfaceVersion::UnstableV1);
+ m_relativePointerV1->create();
+ QCOMPARE(m_relativePointerV1->interfaceVersion(), KWayland::Server::RelativePointerInterfaceVersion::UnstableV1);
}
void TestWaylandRegistry::cleanup()
@@ -303,6 +312,11 @@ void TestWaylandRegistry::testBindXdgShellUnstableV5()
TEST_BIND(KWayland::Client::Registry::Interface::XdgShellUnstableV5, SIGNAL(xdgShellUnstableV5Announced(quint32,quint32)), bindXdgShellUnstableV5, xdg_shell_destroy)
}
+void TestWaylandRegistry::testBindRelativePointerManagerUnstableV1()
+{
+ TEST_BIND(KWayland::Client::Registry::Interface::RelativePointerManagerUnstableV1, SIGNAL(relativePointerManagerUnstableV1Announced(quint32,quint32)), bindRelativePointerManagerUnstableV1, zwp_relative_pointer_manager_v1_destroy)
+}
+
#undef TEST_BIND
void TestWaylandRegistry::testRemoval()
diff --git a/src/wayland/autotests/client/test_wayland_seat.cpp b/src/wayland/autotests/client/test_wayland_seat.cpp
index b414e667ca..390631e06c 100644
--- a/src/wayland/autotests/client/test_wayland_seat.cpp
+++ b/src/wayland/autotests/client/test_wayland_seat.cpp
@@ -30,6 +30,7 @@ License along with this library. If not, see .
#include "../../src/client/pointer.h"
#include "../../src/client/surface.h"
#include "../../src/client/registry.h"
+#include "../../src/client/relativepointer.h"
#include "../../src/client/seat.h"
#include "../../src/client/shm_pool.h"
#include "../../src/client/subcompositor.h"
@@ -41,6 +42,7 @@ License along with this library. If not, see .
#include "../../src/server/display.h"
#include "../../src/server/keyboard_interface.h"
#include "../../src/server/pointer_interface.h"
+#include "../../src/server/relativepointer_interface.h"
#include "../../src/server/seat_interface.h"
#include "../../src/server/subcompositor_interface.h"
#include "../../src/server/surface_interface.h"
@@ -87,11 +89,13 @@ private:
KWayland::Server::CompositorInterface *m_compositorInterface;
KWayland::Server::SeatInterface *m_seatInterface;
KWayland::Server::SubCompositorInterface *m_subCompositorInterface;
+ KWayland::Server::RelativePointerManagerInterface *m_relativePointerManagerInterface;
KWayland::Client::ConnectionThread *m_connection;
KWayland::Client::Compositor *m_compositor;
KWayland::Client::Seat *m_seat;
KWayland::Client::ShmPool *m_shm;
KWayland::Client::SubCompositor * m_subCompositor;
+ KWayland::Client::RelativePointerManager *m_relativePointerManager;
KWayland::Client::EventQueue *m_queue;
QThread *m_thread;
};
@@ -104,11 +108,13 @@ TestWaylandSeat::TestWaylandSeat(QObject *parent)
, m_compositorInterface(nullptr)
, m_seatInterface(nullptr)
, m_subCompositorInterface(nullptr)
+ , m_relativePointerManagerInterface(nullptr)
, m_connection(nullptr)
, m_compositor(nullptr)
, m_seat(nullptr)
, m_shm(nullptr)
, m_subCompositor(nullptr)
+ , m_relativePointerManager(nullptr)
, m_queue(nullptr)
, m_thread(nullptr)
{
@@ -134,6 +140,11 @@ void TestWaylandSeat::init()
m_subCompositorInterface->create();
QVERIFY(m_subCompositorInterface->isValid());
+ m_relativePointerManagerInterface = m_display->createRelativePointerManager(RelativePointerInterfaceVersion::UnstableV1, m_display);
+ QVERIFY(m_relativePointerManagerInterface);
+ m_relativePointerManagerInterface->create();
+ QVERIFY(m_relativePointerManagerInterface->isValid());
+
// setup connection
m_connection = new KWayland::Client::ConnectionThread;
QSignalSpy connectedSpy(m_connection, SIGNAL(connected()));
@@ -182,10 +193,19 @@ void TestWaylandSeat::init()
registry.interface(KWayland::Client::Registry::Interface::SubCompositor).version,
this);
QVERIFY(m_subCompositor->isValid());
+
+ m_relativePointerManager = registry.createRelativePointerManager(registry.interface(KWayland::Client::Registry::Interface::RelativePointerManagerUnstableV1).name,
+ registry.interface(KWayland::Client::Registry::Interface::RelativePointerManagerUnstableV1).version,
+ this);
+ QVERIFY(m_relativePointerManager->isValid());
}
void TestWaylandSeat::cleanup()
{
+ if (m_relativePointerManager) {
+ delete m_relativePointerManager;
+ m_relativePointerManager = nullptr;
+ }
if (m_subCompositor) {
delete m_subCompositor;
m_subCompositor = nullptr;
@@ -226,6 +246,9 @@ void TestWaylandSeat::cleanup()
delete m_subCompositorInterface;
m_subCompositorInterface = nullptr;
+ delete m_relativePointerManagerInterface;
+ m_relativePointerManagerInterface = nullptr;
+
delete m_display;
m_display = nullptr;
}
@@ -342,6 +365,8 @@ void TestWaylandSeat::testPointer()
Pointer *p = m_seat->createPointer(m_seat);
const Pointer &cp = *p;
QVERIFY(p->isValid());
+ QScopedPointer relativePointer(m_relativePointerManager->createRelativePointer(p));
+ QVERIFY(relativePointer->isValid());
QSignalSpy pointerCreatedSpy(m_seatInterface, SIGNAL(pointerCreated(KWayland::Server::PointerInterface*)));
QVERIFY(pointerCreatedSpy.isValid());
// once the pointer is created it should be set as the focused pointer
@@ -372,6 +397,9 @@ void TestWaylandSeat::testPointer()
QSignalSpy buttonSpy(p, SIGNAL(buttonStateChanged(quint32,quint32,quint32,KWayland::Client::Pointer::ButtonState)));
QVERIFY(buttonSpy.isValid());
+ QSignalSpy relativeMotionSpy(relativePointer.data(), &RelativePointer::relativeMotion);
+ QVERIFY(relativeMotionSpy.isValid());
+
QVERIFY(!p->enteredSurface());
QVERIFY(!cp.enteredSurface());
m_seatInterface->setFocusedPointerSurface(serverSurface, QPoint(10, 15));
@@ -393,6 +421,14 @@ void TestWaylandSeat::testPointer()
QCOMPARE(motionSpy.first().first().toPoint(), QPoint(0, 1));
QCOMPARE(motionSpy.first().last().value(), quint32(1));
+ // test relative motion
+ m_seatInterface->relativePointerMotion(QSizeF(1, 2), QSizeF(3, 4), quint64(-1));
+ QVERIFY(relativeMotionSpy.wait());
+ QCOMPARE(relativeMotionSpy.count(), 1);
+ QCOMPARE(relativeMotionSpy.first().at(0).toSizeF(), QSizeF(1, 2));
+ QCOMPARE(relativeMotionSpy.first().at(1).toSizeF(), QSizeF(3, 4));
+ QCOMPARE(relativeMotionSpy.first().at(2).value(), quint64(-1));
+
// test axis
m_seatInterface->setTimestamp(2);
m_seatInterface->pointerAxis(Qt::Horizontal, 10);
@@ -460,6 +496,10 @@ void TestWaylandSeat::testPointer()
QVERIFY(!p->enteredSurface());
QVERIFY(!cp.enteredSurface());
+ // now a relative motion should not be sent to the relative pointer
+ m_seatInterface->relativePointerMotion(QSizeF(1, 2), QSizeF(3, 4), quint64(-1));
+ QVERIFY(!relativeMotionSpy.wait());
+
// enter it again
m_seatInterface->setFocusedPointerSurface(serverSurface, QPoint(0, 0));
QCOMPARE(focusedPointerChangedSpy.count(), 6);
@@ -467,6 +507,14 @@ void TestWaylandSeat::testPointer()
QCOMPARE(p->enteredSurface(), s);
QCOMPARE(cp.enteredSurface(), s);
+ // send another relative motion event
+ m_seatInterface->relativePointerMotion(QSizeF(4, 5), QSizeF(6, 7), quint64(1));
+ QVERIFY(relativeMotionSpy.wait());
+ QCOMPARE(relativeMotionSpy.count(), 2);
+ 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());
@@ -1368,6 +1416,7 @@ void TestWaylandSeat::testDestroy()
connect(m_connection, &ConnectionThread::connectionDied, m_seat, &Seat::destroy);
connect(m_connection, &ConnectionThread::connectionDied, m_shm, &ShmPool::destroy);
connect(m_connection, &ConnectionThread::connectionDied, m_subCompositor, &SubCompositor::destroy);
+ connect(m_connection, &ConnectionThread::connectionDied, m_relativePointerManager, &RelativePointerManager::destroy);
connect(m_connection, &ConnectionThread::connectionDied, m_queue, &EventQueue::destroy);
QVERIFY(m_seat->isValid());
@@ -1378,6 +1427,7 @@ void TestWaylandSeat::testDestroy()
m_compositorInterface = nullptr;
m_seatInterface = nullptr;
m_subCompositorInterface = nullptr;
+ m_relativePointerManagerInterface = nullptr;
QVERIFY(connectionDiedSpy.wait());
// now the seat should be destroyed;
diff --git a/src/wayland/display.cpp b/src/wayland/display.cpp
index 3a6dc17e7f..5848b933fe 100644
--- a/src/wayland/display.cpp
+++ b/src/wayland/display.cpp
@@ -35,6 +35,7 @@ License along with this library. If not, see .
#include "shadow_interface.h"
#include "blur_interface.h"
#include "contrast_interface.h"
+#include "relativepointer_interface_p.h"
#include "server_decoration_interface.h"
#include "slide_interface.h"
#include "shell_interface.h"
@@ -369,6 +370,18 @@ XdgShellInterface *Display::createXdgShell(const XdgShellInterfaceVersion &versi
return x;
}
+RelativePointerManagerInterface *Display::createRelativePointerManager(const RelativePointerInterfaceVersion &version, QObject *parent)
+{
+ RelativePointerManagerInterface *r = nullptr;
+ switch (version) {
+ case RelativePointerInterfaceVersion::UnstableV1:
+ r = new RelativePointerManagerUnstableV1Interface(this, parent);
+ break;
+ }
+ connect(this, &Display::aboutToTerminate, r, [r] { delete r; });
+ return r;
+}
+
void Display::createShm()
{
Q_ASSERT(d->display);
diff --git a/src/wayland/display.h b/src/wayland/display.h
index e56aa19794..48ee6c7940 100644
--- a/src/wayland/display.h
+++ b/src/wayland/display.h
@@ -74,6 +74,8 @@ class TextInputManagerInterface;
class XdgShellV5Interface;
enum class XdgShellInterfaceVersion;
class XdgShellInterface;
+enum class RelativePointerInterfaceVersion;
+class RelativePointerManagerInterface;
/**
* @brief Class holding the Wayland server display loop.
@@ -189,6 +191,14 @@ public:
**/
XdgShellInterface *createXdgShell(const XdgShellInterfaceVersion &version, QObject *parent = nullptr);
+ /**
+ * Creates the RelativePointerManagerInterface in interface @p version
+ *
+ * @returns The created manager object
+ * @since 5.28
+ **/
+ RelativePointerManagerInterface *createRelativePointerManager(const RelativePointerInterfaceVersion &version, QObject *parent = nullptr);
+
/**
* Gets the ClientConnection for the given @p client.
* If there is no ClientConnection yet for the given @p client, it will be created.
diff --git a/src/wayland/pointer_interface.cpp b/src/wayland/pointer_interface.cpp
index 8a7472b26b..1e5c6621da 100644
--- a/src/wayland/pointer_interface.cpp
+++ b/src/wayland/pointer_interface.cpp
@@ -20,6 +20,7 @@ License along with this library. If not, see .
#include "pointer_interface.h"
#include "pointer_interface_p.h"
#include "resource_p.h"
+#include "relativepointer_interface_p.h"
#include "seat_interface.h"
#include "display.h"
#include "subcompositor_interface.h"
@@ -77,6 +78,16 @@ void PointerInterface::Private::sendLeave(SurfaceInterface *surface, quint32 ser
}
}
+void PointerInterface::Private::registerRelativePointer(RelativePointerInterface *relativePointer)
+{
+ relativePointers << relativePointer;
+ QObject::connect(relativePointer, &QObject::destroyed, q,
+ [this, relativePointer] {
+ relativePointers.removeOne(relativePointer);
+ }
+ );
+}
+
namespace {
static QPointF surfacePosition(SurfaceInterface *surface) {
if (surface && surface->subSurface()) {
@@ -211,11 +222,28 @@ Cursor *PointerInterface::cursor() const
return d->cursor;
}
+void PointerInterface::relativeMotion(const QSizeF &delta, const QSizeF &deltaNonAccelerated, quint64 microseconds)
+{
+ Q_D();
+ if (d->relativePointers.isEmpty()) {
+ return;
+ }
+ for (auto it = d->relativePointers.constBegin(), end = d->relativePointers.constEnd(); it != end; it++) {
+ (*it)->relativeMotion(delta, deltaNonAccelerated, microseconds);
+ }
+ client()->flush();
+}
+
PointerInterface::Private *PointerInterface::d_func() const
{
return reinterpret_cast(d.data());
}
+PointerInterface *PointerInterface::get(wl_resource *native)
+{
+ return Private::get(native);
+}
+
Cursor::Private::Private(Cursor *q, PointerInterface *pointer)
: pointer(pointer)
, q(q)
diff --git a/src/wayland/pointer_interface.h b/src/wayland/pointer_interface.h
index eb18a0101b..37a98037b0 100644
--- a/src/wayland/pointer_interface.h
+++ b/src/wayland/pointer_interface.h
@@ -30,6 +30,7 @@ namespace Server
{
class Cursor;
+class RelativePointerManagerUnstableV1Interface;
class SeatInterface;
class SurfaceInterface;
@@ -55,6 +56,12 @@ public:
**/
Cursor *cursor() const;
+ /**
+ * @returns The PointerInterface for the @p native resource.
+ * @since 5.28
+ **/
+ static PointerInterface *get(wl_resource *native);
+
Q_SIGNALS:
/**
* Signal emitted whenever the Cursor changes.
@@ -66,7 +73,9 @@ private:
void buttonPressed(quint32 button, quint32 serial);
void buttonReleased(quint32 button, quint32 serial);
void axis(Qt::Orientation orientation, quint32 delta);
+ void relativeMotion(const QSizeF &delta, const QSizeF &deltaNonAccelerated, quint64 microseconds);
friend class SeatInterface;
+ friend class RelativePointerManagerUnstableV1Interface;
explicit PointerInterface(SeatInterface *parent, wl_resource *parentResource);
class Private;
Private *d_func() const;
diff --git a/src/wayland/pointer_interface_p.h b/src/wayland/pointer_interface_p.h
index bbfd7828be..2c29ef1b47 100644
--- a/src/wayland/pointer_interface_p.h
+++ b/src/wayland/pointer_interface_p.h
@@ -28,6 +28,7 @@ namespace KWayland
{
namespace Server
{
+class RelativePointerInterface;
class PointerInterface::Private : public Resource::Private
{
@@ -39,10 +40,13 @@ public:
QPointer focusedChildSurface;
QMetaObject::Connection destroyConnection;
Cursor *cursor = nullptr;
+ QVector relativePointers;
void sendLeave(SurfaceInterface *surface, quint32 serial);
void sendEnter(SurfaceInterface *surface, const QPointF &parentSurfacePosition, quint32 serial);
+ void registerRelativePointer(RelativePointerInterface *relativePointer);
+
private:
PointerInterface *q_func() {
return reinterpret_cast(q);
diff --git a/src/wayland/seat_interface.cpp b/src/wayland/seat_interface.cpp
index 976877ae93..0076d065a7 100644
--- a/src/wayland/seat_interface.cpp
+++ b/src/wayland/seat_interface.cpp
@@ -846,6 +846,14 @@ quint32 SeatInterface::pointerButtonSerial(quint32 button) const
return it.value();
}
+void SeatInterface::relativePointerMotion(const QSizeF &delta, const QSizeF &deltaNonAccelerated, quint64 microseconds)
+{
+ Q_D();
+ if (d->globalPointer.focus.pointer && d->globalPointer.focus.surface) {
+ d->globalPointer.focus.pointer->relativeMotion(delta, deltaNonAccelerated, microseconds);
+ }
+}
+
void SeatInterface::keyPressed(quint32 key)
{
Q_D();
diff --git a/src/wayland/seat_interface.h b/src/wayland/seat_interface.h
index b5808f4d69..d51678ac6a 100644
--- a/src/wayland/seat_interface.h
+++ b/src/wayland/seat_interface.h
@@ -367,6 +367,42 @@ public:
* @since 5.6
**/
bool hasImplicitPointerGrab(quint32 serial) const;
+
+ /**
+ * A relative motion is in the same dimension as regular motion events,
+ * except they do not represent an absolute position. For example,
+ * moving a pointer from (x, y) to (x', y') would have the equivalent
+ * relative motion (x' - x, y' - y). If a pointer motion caused the
+ * absolute pointer position to be clipped by for example the edge of the
+ * monitor, the relative motion is unaffected by the clipping and will
+ * represent the unclipped motion.
+ *
+ * This method also contains non-accelerated motion deltas (@p deltaNonAccelerated).
+ * The non-accelerated delta is, when applicable, the regular pointer motion
+ * delta as it was before having applied motion acceleration and other
+ * transformations such as normalization.
+ *
+ * Note that the non-accelerated delta does not represent 'raw' events as
+ * they were read from some device. Pointer motion acceleration is device-
+ * and configuration-specific and non-accelerated deltas and accelerated
+ * deltas may have the same value on some devices.
+ *
+ * Relative motions are not coupled to wl_pointer.motion events (see @link{setPointerPos},
+ * and can be sent in combination with such events, but also independently. There may
+ * also be scenarios where wl_pointer.motion is sent, but there is no
+ * relative motion. The order of an absolute and relative motion event
+ * originating from the same physical motion is not guaranteed.
+ *
+ * Sending relative pointer events only makes sense if the RelativePointerManagerInterface
+ * is created on the Display.
+ *
+ * @param delta Motion vector
+ * @param deltaNonAccelerated non-accelerated motion vector
+ * @param microseconds timestamp with microseconds granularity
+ * @see setPointerPos
+ * @since 5.28
+ **/
+ void relativePointerMotion(const QSizeF &delta, const QSizeF &deltaNonAccelerated, quint64 microseconds);
///@}
/**
diff --git a/src/wayland/server/relativepointer_interface.cpp b/src/wayland/server/relativepointer_interface.cpp
new file mode 100644
index 0000000000..69af3ad99e
--- /dev/null
+++ b/src/wayland/server/relativepointer_interface.cpp
@@ -0,0 +1,84 @@
+/****************************************************************************
+Copyright 2016 Martin Gräßlin
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) version 3, or any
+later version accepted by the membership of KDE e.V. (or its
+successor approved by the membership of KDE e.V.), which shall
+act as a proxy defined in Section 6 of version 3 of the license.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library. If not, see .
+****************************************************************************/
+#include "relativepointer_interface_p.h"
+
+namespace KWayland
+{
+namespace Server
+{
+
+RelativePointerManagerInterface::Private::Private(RelativePointerInterfaceVersion interfaceVersion, RelativePointerManagerInterface *q, Display *d, const wl_interface *interface, quint32 version)
+ : Global::Private(d, interface, version)
+ , interfaceVersion(interfaceVersion)
+ , q(q)
+{
+}
+
+RelativePointerManagerInterface::RelativePointerManagerInterface(Private *d, QObject *parent)
+ : Global(d, parent)
+{
+}
+
+RelativePointerManagerInterface::~RelativePointerManagerInterface() = default;
+
+RelativePointerInterfaceVersion RelativePointerManagerInterface::interfaceVersion() const
+{
+ Q_D();
+ return d->interfaceVersion;
+}
+
+RelativePointerManagerInterface::Private *RelativePointerManagerInterface::d_func() const
+{
+ return reinterpret_cast(d.data());
+}
+
+RelativePointerInterface::Private::Private(RelativePointerInterface *q, Global *c, wl_resource *parentResource, const wl_interface *interface, const void *implementation)
+ : Resource::Private(q, c, parentResource, interface, implementation)
+{
+}
+
+RelativePointerInterface::Private::~Private()
+{
+ if (resource) {
+ wl_resource_destroy(resource);
+ resource = nullptr;
+ }
+}
+
+RelativePointerInterface::RelativePointerInterface(Private *p, QObject *parent)
+ : Resource(p, parent)
+{
+}
+
+RelativePointerInterface::~RelativePointerInterface() = default;
+
+void RelativePointerInterface::relativeMotion(const QSizeF &delta, const QSizeF &deltaNonAccelerated, quint64 microseconds)
+{
+ Q_D();
+ d->relativeMotion(delta, deltaNonAccelerated, microseconds);
+}
+
+RelativePointerInterface::Private *RelativePointerInterface::d_func() const
+{
+ return reinterpret_cast(d.data());
+}
+
+}
+}
diff --git a/src/wayland/server/relativepointer_interface.h b/src/wayland/server/relativepointer_interface.h
new file mode 100644
index 0000000000..aa8507c814
--- /dev/null
+++ b/src/wayland/server/relativepointer_interface.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+Copyright 2016 Martin Gräßlin
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) version 3, or any
+later version accepted by the membership of KDE e.V. (or its
+successor approved by the membership of KDE e.V.), which shall
+act as a proxy defined in Section 6 of version 3 of the license.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library. If not, see .
+****************************************************************************/
+#ifndef KWAYLAND_SERVER_RELATIVE_POINTER_H
+#define KWAYLAND_SERVER_RELATIVE_POINTER_H
+
+#include "global.h"
+
+#include
+
+namespace KWayland
+{
+namespace Server
+{
+
+class Display;
+
+enum class RelativePointerInterfaceVersion {
+ /**
+ * zwp_relative_pointer_manager_v1 and zwp_relative_pointer_v1
+ **/
+ UnstableV1
+};
+
+/**
+ * Manager object to create relative pointer interfaces.
+ *
+ * Once created the interaction happens through the SeatInterface class
+ * which automatically delegates relative motion events to the created relative pointer
+ * interfaces.
+ *
+ * @see SeatInterface::relativePointerMotion
+ * @since 5.28
+ **/
+class KWAYLANDSERVER_EXPORT RelativePointerManagerInterface : public Global
+{
+ Q_OBJECT
+public:
+ virtual ~RelativePointerManagerInterface();
+
+ /**
+ * @returns The interface version used by this RelativePointerManagerInterface
+ **/
+ RelativePointerInterfaceVersion interfaceVersion() const;
+
+protected:
+ class Private;
+ explicit RelativePointerManagerInterface(Private *d, QObject *parent = nullptr);
+
+private:
+ Private *d_func() const;
+};
+
+}
+}
+
+#endif
diff --git a/src/wayland/server/relativepointer_interface_p.h b/src/wayland/server/relativepointer_interface_p.h
new file mode 100644
index 0000000000..a7220a070f
--- /dev/null
+++ b/src/wayland/server/relativepointer_interface_p.h
@@ -0,0 +1,100 @@
+/****************************************************************************
+Copyright 2016 Martin Gräßlin
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) version 3, or any
+later version accepted by the membership of KDE e.V. (or its
+successor approved by the membership of KDE e.V.), which shall
+act as a proxy defined in Section 6 of version 3 of the license.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library. If not, see .
+****************************************************************************/
+#ifndef KWAYLAND_SERVER_RELATIVEPOINTER_INTERFACE_P_H
+#define KWAYLAND_SERVER_RELATIVEPOINTER_INTERFACE_P_H
+#include "relativepointer_interface.h"
+#include "resource_p.h"
+#include "global_p.h"
+
+
+namespace KWayland
+{
+namespace Server
+{
+
+class RelativePointerManagerInterface::Private : public Global::Private
+{
+public:
+ RelativePointerInterfaceVersion interfaceVersion;
+
+protected:
+ Private(RelativePointerInterfaceVersion interfaceVersion, RelativePointerManagerInterface *q, Display *d, const wl_interface *interface, quint32 version);
+ RelativePointerManagerInterface *q;
+};
+
+class RelativePointerManagerUnstableV1Interface : public RelativePointerManagerInterface
+{
+ Q_OBJECT
+public:
+ explicit RelativePointerManagerUnstableV1Interface(Display *display, QObject *parent = nullptr);
+ virtual ~RelativePointerManagerUnstableV1Interface();
+
+private:
+ class Private;
+};
+
+class RelativePointerInterface : public Resource
+{
+ Q_OBJECT
+public:
+ virtual ~RelativePointerInterface();
+ void relativeMotion(const QSizeF &delta, const QSizeF &deltaNonAccelerated, quint64 microseconds);
+
+protected:
+ class Private;
+ explicit RelativePointerInterface(Private *p, QObject *parent = nullptr);
+
+private:
+ Private *d_func() const;
+};
+
+class RelativePointerInterface::Private : public Resource::Private
+{
+public:
+ ~Private();
+ virtual void relativeMotion(const QSizeF &delta, const QSizeF &deltaNonAccelerated, quint64 microseconds) = 0;
+
+protected:
+ Private(RelativePointerInterface *q, Global *c, wl_resource *parentResource, const wl_interface *interface, const void *implementation);
+
+private:
+ RelativePointerInterface *q_func() {
+ return reinterpret_cast(q);
+ }
+};
+
+class RelativePointerUnstableV1Interface : public RelativePointerInterface
+{
+ Q_OBJECT
+public:
+ virtual ~RelativePointerUnstableV1Interface();
+
+private:
+ explicit RelativePointerUnstableV1Interface(RelativePointerManagerUnstableV1Interface *parent, wl_resource *parentResource);
+ friend class RelativePointerManagerUnstableV1Interface;
+
+ class Private;
+ Private *d_func() const;
+};
+
+}
+}
+
+#endif
diff --git a/src/wayland/server/relativepointer_interface_v1.cpp b/src/wayland/server/relativepointer_interface_v1.cpp
new file mode 100644
index 0000000000..0358aa24f0
--- /dev/null
+++ b/src/wayland/server/relativepointer_interface_v1.cpp
@@ -0,0 +1,160 @@
+/****************************************************************************
+Copyright 2016 Martin Gräßlin
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) version 3, or any
+later version accepted by the membership of KDE e.V. (or its
+successor approved by the membership of KDE e.V.), which shall
+act as a proxy defined in Section 6 of version 3 of the license.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library. If not, see .
+****************************************************************************/
+#include "relativepointer_interface_p.h"
+#include "display.h"
+#include "pointer_interface_p.h"
+#include
+#include
+
+namespace KWayland
+{
+namespace Server
+{
+
+class RelativePointerManagerUnstableV1Interface::Private : public RelativePointerManagerInterface::Private
+{
+public:
+ Private(RelativePointerManagerUnstableV1Interface *q, Display *d);
+
+private:
+ void bind(wl_client *client, uint32_t version, uint32_t id) override;
+
+ static void unbind(wl_resource *resource);
+ static Private *cast(wl_resource *r) {
+ return reinterpret_cast(wl_resource_get_user_data(r));
+ }
+
+ static void destroyCallback(wl_client *client, wl_resource *resource);
+ static void getRelativePointerCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource * pointer);
+
+ RelativePointerManagerUnstableV1Interface *q;
+
+ static const struct zwp_relative_pointer_manager_v1_interface s_interface;
+ static const quint32 s_version;
+};
+
+const quint32 RelativePointerManagerUnstableV1Interface::Private::s_version = 1;
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+const struct zwp_relative_pointer_manager_v1_interface RelativePointerManagerUnstableV1Interface::Private::s_interface = {
+ destroyCallback,
+ getRelativePointerCallback
+};
+#endif
+
+void RelativePointerManagerUnstableV1Interface::Private::destroyCallback(wl_client *client, wl_resource *resource)
+{
+ Q_UNUSED(client)
+ wl_resource_destroy(resource);
+}
+
+void RelativePointerManagerUnstableV1Interface::Private::getRelativePointerCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource *pointer)
+{
+ PointerInterface *p = PointerInterface::get(pointer);
+ if (!p) {
+ // TODO: raise error?
+ return;
+ }
+ auto m = cast(resource);
+ auto *r = new RelativePointerUnstableV1Interface(m->q, resource);
+ r->d->create(m->display->getConnection(client), version, id);
+ p->d_func()->registerRelativePointer(r);
+}
+
+RelativePointerManagerUnstableV1Interface::Private::Private(RelativePointerManagerUnstableV1Interface *q, Display *d)
+ : RelativePointerManagerInterface::Private(RelativePointerInterfaceVersion::UnstableV1, q, d, &zwp_relative_pointer_manager_v1_interface, s_version)
+ , q(q)
+{
+}
+
+void RelativePointerManagerUnstableV1Interface::Private::bind(wl_client *client, uint32_t version, uint32_t id)
+{
+ auto c = display->getConnection(client);
+ wl_resource *resource = c->createResource(&zwp_relative_pointer_manager_v1_interface, qMin(version, s_version), id);
+ if (!resource) {
+ wl_client_post_no_memory(client);
+ return;
+ }
+ wl_resource_set_implementation(resource, &s_interface, this, unbind);
+ // TODO: should we track?
+}
+
+void RelativePointerManagerUnstableV1Interface::Private::unbind(wl_resource *resource)
+{
+ Q_UNUSED(resource)
+ // TODO: implement?
+}
+
+RelativePointerManagerUnstableV1Interface::RelativePointerManagerUnstableV1Interface(Display *display, QObject *parent)
+ : RelativePointerManagerInterface(new Private(this, display), parent)
+{
+}
+
+RelativePointerManagerUnstableV1Interface::~RelativePointerManagerUnstableV1Interface() = default;
+
+class RelativePointerUnstableV1Interface::Private : public RelativePointerInterface::Private
+{
+public:
+ Private(RelativePointerUnstableV1Interface *q, RelativePointerManagerUnstableV1Interface *c, wl_resource *parentResource);
+ ~Private();
+ void relativeMotion(const QSizeF &delta, const QSizeF &deltaNonAccelerated, quint64 microseconds) override;
+
+private:
+ RelativePointerUnstableV1Interface *q_func() {
+ return reinterpret_cast(q);
+ }
+
+ static const struct zwp_relative_pointer_v1_interface s_interface;
+};
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+const struct zwp_relative_pointer_v1_interface RelativePointerUnstableV1Interface::Private::s_interface = {
+ resourceDestroyedCallback
+};
+#endif
+
+RelativePointerUnstableV1Interface::Private::Private(RelativePointerUnstableV1Interface *q, RelativePointerManagerUnstableV1Interface *c, wl_resource *parentResource)
+ : RelativePointerInterface::Private(q, c, parentResource, &zwp_relative_pointer_v1_interface, &s_interface)
+{
+}
+
+RelativePointerUnstableV1Interface::Private::~Private() = default;
+
+void RelativePointerUnstableV1Interface::Private::relativeMotion(const QSizeF &delta, const QSizeF &deltaNonAccelerated, quint64 microseconds)
+{
+ if (!resource) {
+ return;
+ }
+ zwp_relative_pointer_v1_send_relative_motion(resource, (microseconds >> 32), microseconds,
+ wl_fixed_from_double(delta.width()),
+ wl_fixed_from_double(delta.height()),
+ wl_fixed_from_double(deltaNonAccelerated.width()),
+ wl_fixed_from_double(deltaNonAccelerated.height()));
+}
+
+RelativePointerUnstableV1Interface::RelativePointerUnstableV1Interface(RelativePointerManagerUnstableV1Interface *parent, wl_resource *parentResource)
+ : RelativePointerInterface(new Private(this, parent, parentResource))
+{
+}
+
+RelativePointerUnstableV1Interface::~RelativePointerUnstableV1Interface() = default;
+
+}
+}
diff --git a/src/wayland/tools/mapping.txt b/src/wayland/tools/mapping.txt
index 3706952bff..dc71b142e6 100644
--- a/src/wayland/tools/mapping.txt
+++ b/src/wayland/tools/mapping.txt
@@ -47,3 +47,5 @@ zwp_text_input_manager_v2;TextInputManagerUnstableV2
xdg_shell;XdgShellV5
xdg_surface;XdgSurfaceV5
xdg_popup;XdgPopupV5
+zwp_relative_pointer_manager_v1;RelativePointerManagerUnstableV1
+zwp_relative_pointer_v1;RelativePointerUnstableV1