File indexing completed on 2023-12-10 04:54:44
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"