kdeconnect-kde/declarativeplugin/pointerlockerwayland.cpp

215 lines
5.4 KiB
C++
Raw Permalink Normal View History

/*
SPDX-FileCopyrightText: 2018 Roman Gilg <subdiff@gmail.com>
SPDX-FileCopyrightText: 2021 Aleix Pol Gonzalez <aleixpol@kde.org>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#include "pointerlockerwayland.h"
#include <QDebug>
#include "qwayland-pointer-constraints-unstable-v1.h"
#include "qwayland-relative-pointer-unstable-v1.h"
#include <QtWaylandClient/qwaylandclientextension.h>
#include <qpa/qplatformnativeinterface.h>
#include <QGuiApplication>
class PointerConstraints : public QWaylandClientExtensionTemplate<PointerConstraints>, public QtWayland::zwp_pointer_constraints_v1
{
public:
PointerConstraints()
: QWaylandClientExtensionTemplate<PointerConstraints>(1)
{
}
};
class LockedPointer : public QObject, public QtWayland::zwp_locked_pointer_v1
{
Q_OBJECT
public:
LockedPointer(struct ::zwp_locked_pointer_v1 *object, QObject *parent)
: QObject(parent)
, zwp_locked_pointer_v1(object)
{
}
Q_SIGNAL void locked();
Q_SIGNAL void unlocked();
private:
void zwp_locked_pointer_v1_locked() override
{
Q_EMIT locked();
}
void zwp_locked_pointer_v1_unlocked() override
{
Q_EMIT unlocked();
}
};
class RelativePointerManagerV1 : public QWaylandClientExtensionTemplate<RelativePointerManagerV1>, public QtWayland::zwp_relative_pointer_manager_v1
{
public:
explicit RelativePointerManagerV1()
: QWaylandClientExtensionTemplate<RelativePointerManagerV1>(1)
{
}
~RelativePointerManagerV1()
{
destroy();
}
};
class RelativePointerV1 : public QtWayland::zwp_relative_pointer_v1
{
public:
explicit RelativePointerV1(PointerLockerWayland *locker, struct ::zwp_relative_pointer_v1 *p)
: QtWayland::zwp_relative_pointer_v1(p)
, locker(locker)
{
}
~RelativePointerV1()
{
destroy();
}
void zwp_relative_pointer_v1_relative_motion(uint32_t /*utime_hi*/,
uint32_t /*utime_lo*/,
wl_fixed_t dx,
wl_fixed_t dy,
wl_fixed_t /*dx_unaccel*/,
wl_fixed_t /*dy_unaccel*/) override
{
locker->pointerMoved({wl_fixed_to_double(dx), wl_fixed_to_double(dy)});
}
private:
PointerLockerWayland *const locker;
};
PointerLockerWayland::PointerLockerWayland(QObject *parent)
: AbstractPointerLocker(parent)
{
m_relativePointerMgr = std::make_unique<RelativePointerManagerV1>();
m_pointerConstraints = new PointerConstraints;
}
PointerLockerWayland::~PointerLockerWayland()
{
delete m_pointerConstraints;
}
bool PointerLockerWayland::isLockEffective() const
{
return m_lockedPointer;
}
wl_pointer *PointerLockerWayland::getPointer()
{
QPlatformNativeInterface *native = qGuiApp->platformNativeInterface();
if (!native) {
return nullptr;
}
window()->create();
return reinterpret_cast<wl_pointer *>(native->nativeResourceForIntegration(QByteArrayLiteral("wl_pointer")));
}
void PointerLockerWayland::enforceLock()
{
if (!m_isLocked) {
return;
}
auto pointer = getPointer();
if (!m_relativePointer) {
m_relativePointer.reset(new RelativePointerV1(this, m_relativePointerMgr->get_relative_pointer(pointer)));
}
wl_surface *wlSurface = [](QWindow *window) -> wl_surface * {
if (!window) {
return nullptr;
}
QPlatformNativeInterface *native = qGuiApp->platformNativeInterface();
if (!native) {
return nullptr;
}
window->create();
return reinterpret_cast<wl_surface *>(native->nativeResourceForWindow(QByteArrayLiteral("surface"), window));
}(m_window);
m_lockedPointer =
new LockedPointer(m_pointerConstraints->lock_pointer(wlSurface, pointer, nullptr, PointerConstraints::lifetime::lifetime_persistent), this);
if (!m_lockedPointer) {
qDebug() << "ERROR when receiving locked pointer!";
return;
}
connect(m_lockedPointer, &LockedPointer::locked, this, [this] {
Q_EMIT lockEffectiveChanged(true);
});
connect(m_lockedPointer, &LockedPointer::unlocked, this, [this] {
Q_EMIT lockEffectiveChanged(false);
});
}
void PointerLockerWayland::setLocked(bool lock)
{
if (m_isLocked == lock) {
return;
}
if (!isSupported()) {
qWarning() << "Locking before having our interfaces announced";
return;
}
m_isLocked = lock;
if (lock) {
enforceLock();
} else {
cleanupLock();
}
Q_EMIT lockedChanged(lock);
}
void PointerLockerWayland::cleanupLock()
{
if (!m_lockedPointer) {
return;
}
m_lockedPointer->destroy();
m_lockedPointer->deleteLater();
m_lockedPointer = nullptr;
Q_EMIT lockEffectiveChanged(false);
}
void PointerLockerWayland::setWindow(QWindow *window)
{
if (m_window == window) {
return;
}
cleanupLock();
if (m_window) {
disconnect(m_window, &QWindow::visibleChanged, this, &PointerLockerWayland::enforceLock);
}
AbstractPointerLocker::setWindow(window);
connect(m_window, &QWindow::visibleChanged, this, &PointerLockerWayland::enforceLock);
if (m_isLocked) {
enforceLock();
}
}
#include "pointerlockerwayland.moc"