Commit a96776ac authored by Martin Flöser's avatar Martin Flöser
Browse files

Implement support for the relative pointer protocol

Summary:
This change implements the zwp_relative_pointer_v1 protocol which allows
to send relative motion events.

The (unstable) protocol consists of a RelativePointerManager which
creates RelativePointers for a given Pointer. This interface currently
only has one event to report the relative motion. It carries the delta,
the non-accelerated-delta and a timestamp in microsends granularity.

On the server side the implementation is mostly internal. Once a
RelativePointerManagerInterface is created one can send relative motion
events through the SeatInterface. The SeatInterface takes care of
sending it to the responding RelativePointerInterface. The protocol does
not restrict the sending of "normal" and relative motion events. Thus it
can be combined in any way one wants. This allows to have a rather
simple implementation. A user of the SeatInterface can just start to
feed the relative motion events (if the information is available) to the
SeatInterface together with the pointer events.

On client side a new RelativePointerManager and RelativePointer class
are added. The RelativePointerManager creates the RelativePointer for a
given Pointer. The event sent to RelativePointer is transformed in a
normal signal.

Reviewers: #plasma

Subscribers: plasma-devel

Tags: #plasma_on_wayland

Differential Revision: https://phabricator.kde.org/D2978
parent 9f3d6c8f
......@@ -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
......
......@@ -27,6 +27,7 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
#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 <http://www.gnu.org/licenses/>.
#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 <wayland-client-protocol.h>
#include <wayland-dpms-client-protocol.h>
......@@ -54,6 +56,7 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
#include <wayland-text-input-v0-client-protocol.h>
#include <wayland-text-input-v2-client-protocol.h>
#include <wayland-xdg-shell-v5-client-protocol.h>
#include <wayland-relativepointer-unstable-v1-client-protocol.h>
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()
......
......@@ -30,6 +30,7 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
#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 <http://www.gnu.org/licenses/>.
#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> 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>(), 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>(), 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>(), 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;
......
......@@ -35,6 +35,7 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
#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);
......
......@@ -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.
......
......@@ -20,6 +20,7 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
#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<Private*>(d.data());
}
PointerInterface *PointerInterface::get(wl_resource *native)
{
return Private::get<PointerInterface>(native);
}
Cursor::Private::Private(Cursor *q, PointerInterface *pointer)
: pointer(pointer)
, q(q)
......
......@@ -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;
......
......@@ -28,6 +28,7 @@ namespace KWayland
{
namespace Server
{
class RelativePointerInterface;
class PointerInterface::Private : public Resource::Private
{
......@@ -39,10 +40,13 @@ public:
QPointer<SurfaceInterface> focusedChildSurface;
QMetaObject::Connection destroyConnection;
Cursor *cursor = nullptr;
QVector<RelativePointerInterface*> 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<PointerInterface *>(q);
......
......@@ -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();
......
......@@ -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);
///@}
/**
......
/****************************************************************************
Copyright 2016 Martin Gräßlin <mgraesslin@kde.org>
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 <http://www.gnu.org/licenses/>.
****************************************************************************/
#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<Private*>(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<Private*>(d.data());
}
}
}
/****************************************************************************
Copyright 2016 Martin Gräßlin <mgraesslin@kde.org>
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 <http://www.gnu.org/licenses/>.
****************************************************************************/
#ifndef KWAYLAND_SERVER_RELATIVE_POINTER_H
#define KWAYLAND_SERVER_RELATIVE_POINTER_H
#include "global.h"
#include <KWayland/Server/kwaylandserver_export.h>
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: