File indexing completed on 2024-05-05 16:09:10

0001 /*
0002     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0003     SPDX-FileCopyrightText: 2020 David Redondo <kde@david-redondo.de>
0004 */
0005 
0006 #include "waylandinhibition_p.h"
0007 
0008 #include <QDebug>
0009 #include <QGuiApplication>
0010 #include <QSharedPointer>
0011 #include <QtWaylandClient/QWaylandClientExtensionTemplate>
0012 #include <QtWaylandClient/QtWaylandClientVersion>
0013 #include <qpa/qplatformnativeinterface.h>
0014 
0015 #include "qwayland-keyboard-shortcuts-inhibit-unstable-v1.h"
0016 
0017 class ShortcutsInhibitor : public QtWayland::zwp_keyboard_shortcuts_inhibitor_v1
0018 {
0019 public:
0020     ShortcutsInhibitor(::zwp_keyboard_shortcuts_inhibitor_v1 *id)
0021         : QtWayland::zwp_keyboard_shortcuts_inhibitor_v1(id)
0022     {
0023     }
0024 
0025     ~ShortcutsInhibitor() override
0026     {
0027         destroy();
0028     }
0029 
0030     void zwp_keyboard_shortcuts_inhibitor_v1_active() override
0031     {
0032         m_active = true;
0033     }
0034 
0035     void zwp_keyboard_shortcuts_inhibitor_v1_inactive() override
0036     {
0037         m_active = false;
0038     }
0039 
0040     bool isActive() const
0041     {
0042         return m_active;
0043     }
0044 
0045 private:
0046     bool m_active = false;
0047 };
0048 
0049 class ShortcutsInhibitManager : public QWaylandClientExtensionTemplate<ShortcutsInhibitManager>, public QtWayland::zwp_keyboard_shortcuts_inhibit_manager_v1
0050 {
0051 public:
0052     ShortcutsInhibitManager()
0053         : QWaylandClientExtensionTemplate<ShortcutsInhibitManager>(1)
0054     {
0055 #if QTWAYLANDCLIENT_VERSION >= QT_VERSION_CHECK(6, 2, 0)
0056         initialize();
0057 #else
0058         // QWaylandClientExtensionTemplate invokes this with a QueuedConnection but we want shortcuts
0059         // to be inhibited immediately.
0060         QMetaObject::invokeMethod(this, "addRegistryListener");
0061 #endif
0062     }
0063     ~ShortcutsInhibitManager() override
0064     {
0065         if (isInitialized()) {
0066             destroy();
0067         }
0068     }
0069 
0070     void startInhibition(QWindow *window)
0071     {
0072         if (m_inhibitions.contains(window)) {
0073             return;
0074         }
0075         QPlatformNativeInterface *nativeInterface = qGuiApp->platformNativeInterface();
0076         if (!nativeInterface) {
0077             return;
0078         }
0079         auto seat = static_cast<wl_seat *>(nativeInterface->nativeResourceForIntegration("wl_seat"));
0080         auto surface = static_cast<wl_surface *>(nativeInterface->nativeResourceForWindow("surface", window));
0081         if (!seat || !surface) {
0082             return;
0083         }
0084         m_inhibitions[window].reset(new ShortcutsInhibitor(inhibit_shortcuts(surface, seat)));
0085     }
0086 
0087     bool isInhibited(QWindow *window) const
0088     {
0089         return m_inhibitions.contains(window);
0090     }
0091 
0092     void stopInhibition(QWindow *window)
0093     {
0094         m_inhibitions.remove(window);
0095     }
0096 
0097     QHash<QWindow *, QSharedPointer<ShortcutsInhibitor>> m_inhibitions;
0098 };
0099 
0100 static std::shared_ptr<ShortcutsInhibitManager> theManager()
0101 {
0102     static std::weak_ptr<ShortcutsInhibitManager> managerInstance;
0103     std::shared_ptr<ShortcutsInhibitManager> ret = managerInstance.lock();
0104     if (!ret) {
0105         ret = std::make_shared<ShortcutsInhibitManager>();
0106         managerInstance = ret;
0107     }
0108     return ret;
0109 }
0110 
0111 WaylandInhibition::WaylandInhibition(QWindow *window)
0112     : ShortcutInhibition()
0113     , m_window(window)
0114     , m_manager(theManager())
0115 {
0116 }
0117 
0118 WaylandInhibition::~WaylandInhibition() = default;
0119 
0120 bool WaylandInhibition::shortcutsAreInhibited() const
0121 {
0122     return m_manager->isInhibited(m_window);
0123 }
0124 
0125 void WaylandInhibition::enableInhibition()
0126 {
0127     m_manager->startInhibition(m_window);
0128 }
0129 
0130 void WaylandInhibition::disableInhibition()
0131 {
0132     m_manager->stopInhibition(m_window);
0133 }