File indexing completed on 2024-04-14 04:51:42

0001 /*
0002     SPDX-FileCopyrightText: 2018 Roman Gilg <subdiff@gmail.com>
0003     SPDX-FileCopyrightText: 2021 Aleix Pol Gonzalez <aleixpol@kde.org>
0004 
0005     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0006 */
0007 
0008 #include "pointerlockerwayland.h"
0009 
0010 #include <QDebug>
0011 
0012 #include "qwayland-pointer-constraints-unstable-v1.h"
0013 #include "qwayland-relative-pointer-unstable-v1.h"
0014 #include <QtWaylandClient/qwaylandclientextension.h>
0015 #include <qpa/qplatformnativeinterface.h>
0016 
0017 #include <QGuiApplication>
0018 
0019 class PointerConstraints : public QWaylandClientExtensionTemplate<PointerConstraints>, public QtWayland::zwp_pointer_constraints_v1
0020 {
0021 public:
0022     PointerConstraints()
0023         : QWaylandClientExtensionTemplate<PointerConstraints>(1)
0024     {
0025     }
0026 };
0027 
0028 class LockedPointer : public QObject, public QtWayland::zwp_locked_pointer_v1
0029 {
0030     Q_OBJECT
0031 public:
0032     LockedPointer(struct ::zwp_locked_pointer_v1 *object, QObject *parent)
0033         : QObject(parent)
0034         , zwp_locked_pointer_v1(object)
0035     {
0036     }
0037 
0038     Q_SIGNAL void locked();
0039 
0040     Q_SIGNAL void unlocked();
0041 
0042 private:
0043     void zwp_locked_pointer_v1_locked() override
0044     {
0045         Q_EMIT locked();
0046     }
0047 
0048     void zwp_locked_pointer_v1_unlocked() override
0049     {
0050         Q_EMIT unlocked();
0051     }
0052 };
0053 
0054 class RelativePointerManagerV1 : public QWaylandClientExtensionTemplate<RelativePointerManagerV1>, public QtWayland::zwp_relative_pointer_manager_v1
0055 {
0056 public:
0057     explicit RelativePointerManagerV1()
0058         : QWaylandClientExtensionTemplate<RelativePointerManagerV1>(1)
0059     {
0060     }
0061 
0062     ~RelativePointerManagerV1()
0063     {
0064         destroy();
0065     }
0066 };
0067 
0068 class RelativePointerV1 : public QtWayland::zwp_relative_pointer_v1
0069 {
0070 public:
0071     explicit RelativePointerV1(PointerLockerWayland *locker, struct ::zwp_relative_pointer_v1 *p)
0072         : QtWayland::zwp_relative_pointer_v1(p)
0073         , locker(locker)
0074     {
0075     }
0076 
0077     ~RelativePointerV1()
0078     {
0079         destroy();
0080     }
0081 
0082     void zwp_relative_pointer_v1_relative_motion(uint32_t /*utime_hi*/,
0083                                                  uint32_t /*utime_lo*/,
0084                                                  wl_fixed_t dx,
0085                                                  wl_fixed_t dy,
0086                                                  wl_fixed_t /*dx_unaccel*/,
0087                                                  wl_fixed_t /*dy_unaccel*/) override
0088     {
0089         locker->pointerMoved({wl_fixed_to_double(dx), wl_fixed_to_double(dy)});
0090     }
0091 
0092 private:
0093     PointerLockerWayland *const locker;
0094 };
0095 
0096 PointerLockerWayland::PointerLockerWayland(QObject *parent)
0097     : AbstractPointerLocker(parent)
0098 {
0099     m_relativePointerMgr = std::make_unique<RelativePointerManagerV1>();
0100     m_pointerConstraints = new PointerConstraints;
0101 }
0102 
0103 PointerLockerWayland::~PointerLockerWayland()
0104 {
0105     delete m_pointerConstraints;
0106 }
0107 
0108 bool PointerLockerWayland::isLockEffective() const
0109 {
0110     return m_lockedPointer;
0111 }
0112 
0113 wl_pointer *PointerLockerWayland::getPointer()
0114 {
0115     QPlatformNativeInterface *native = qGuiApp->platformNativeInterface();
0116     if (!native) {
0117         return nullptr;
0118     }
0119 
0120     window()->create();
0121 
0122     return reinterpret_cast<wl_pointer *>(native->nativeResourceForIntegration(QByteArrayLiteral("wl_pointer")));
0123 }
0124 
0125 void PointerLockerWayland::enforceLock()
0126 {
0127     if (!m_isLocked) {
0128         return;
0129     }
0130 
0131     auto pointer = getPointer();
0132     if (!m_relativePointer) {
0133         m_relativePointer.reset(new RelativePointerV1(this, m_relativePointerMgr->get_relative_pointer(pointer)));
0134     }
0135 
0136     wl_surface *wlSurface = [](QWindow *window) -> wl_surface * {
0137         if (!window) {
0138             return nullptr;
0139         }
0140 
0141         QPlatformNativeInterface *native = qGuiApp->platformNativeInterface();
0142         if (!native) {
0143             return nullptr;
0144         }
0145         window->create();
0146         return reinterpret_cast<wl_surface *>(native->nativeResourceForWindow(QByteArrayLiteral("surface"), window));
0147     }(m_window);
0148 
0149     m_lockedPointer =
0150         new LockedPointer(m_pointerConstraints->lock_pointer(wlSurface, pointer, nullptr, PointerConstraints::lifetime::lifetime_persistent), this);
0151 
0152     if (!m_lockedPointer) {
0153         qDebug() << "ERROR when receiving locked pointer!";
0154         return;
0155     }
0156 
0157     connect(m_lockedPointer, &LockedPointer::locked, this, [this] {
0158         Q_EMIT lockEffectiveChanged(true);
0159     });
0160     connect(m_lockedPointer, &LockedPointer::unlocked, this, [this] {
0161         Q_EMIT lockEffectiveChanged(false);
0162     });
0163 }
0164 
0165 void PointerLockerWayland::setLocked(bool lock)
0166 {
0167     if (m_isLocked == lock) {
0168         return;
0169     }
0170 
0171     if (!isSupported()) {
0172         qWarning() << "Locking before having our interfaces announced";
0173         return;
0174     }
0175 
0176     m_isLocked = lock;
0177     if (lock) {
0178         enforceLock();
0179     } else {
0180         cleanupLock();
0181     }
0182     Q_EMIT lockedChanged(lock);
0183 }
0184 
0185 void PointerLockerWayland::cleanupLock()
0186 {
0187     if (!m_lockedPointer) {
0188         return;
0189     }
0190     m_lockedPointer->destroy();
0191     m_lockedPointer->deleteLater();
0192     m_lockedPointer = nullptr;
0193     Q_EMIT lockEffectiveChanged(false);
0194 }
0195 
0196 void PointerLockerWayland::setWindow(QWindow *window)
0197 {
0198     if (m_window == window) {
0199         return;
0200     }
0201     cleanupLock();
0202 
0203     if (m_window) {
0204         disconnect(m_window, &QWindow::visibleChanged, this, &PointerLockerWayland::enforceLock);
0205     }
0206     AbstractPointerLocker::setWindow(window);
0207     connect(m_window, &QWindow::visibleChanged, this, &PointerLockerWayland::enforceLock);
0208 
0209     if (m_isLocked) {
0210         enforceLock();
0211     }
0212 }
0213 
0214 #include "moc_pointerlockerwayland.cpp"
0215 #include "pointerlockerwayland.moc"