File indexing completed on 2025-03-16 10:01:12
0001 /* 0002 SPDX-FileCopyrightText: 2021 David Edmundson <davidedmundson@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0005 */ 0006 #include "poller.h" 0007 0008 #include <QDebug> 0009 #include <QGuiApplication> 0010 #include <QLoggingCategory> 0011 #include <QWaylandClientExtensionTemplate> 0012 #include <QtWaylandClient/QtWaylandClientVersion> 0013 0014 #include <qpa/qplatformnativeinterface.h> 0015 0016 #include "qwayland-ext-idle-notify-v1.h" 0017 #include "qwayland-idle.h" 0018 0019 Q_DECLARE_LOGGING_CATEGORY(POLLER) 0020 Q_LOGGING_CATEGORY(POLLER, "kf5idletime_wayland") 0021 0022 /* 0023 * Porting notes: 0024 * org_kde_kwin_idle refers to an early specific idle timeout protocol 0025 * the version ext_idle refers to an upstream stable protocol 0026 * 0027 * Pragmattically they're both the same, but we have to have two implementations for a while 0028 * 0029 * When a suitable amount of time passes (Plasma 5.24 being EOL) drop IdleTimeoutKwin and drop IdleManagerKwin as well as merge the abstract IdleTimeout class into the real implementation 0030 */ 0031 0032 class IdleTimeout : public QObject 0033 { 0034 Q_OBJECT 0035 public: 0036 IdleTimeout() = default; 0037 Q_SIGNALS: 0038 void idle(); 0039 void resumeFromIdle(); 0040 }; 0041 0042 class IdleTimeoutKwin : public IdleTimeout, public QtWayland::org_kde_kwin_idle_timeout 0043 { 0044 Q_OBJECT 0045 public: 0046 IdleTimeoutKwin(struct ::org_kde_kwin_idle_timeout *object) 0047 : IdleTimeout() 0048 , QtWayland::org_kde_kwin_idle_timeout(object) 0049 {} 0050 0051 ~IdleTimeoutKwin() 0052 { 0053 if (qGuiApp) { 0054 release(); 0055 } 0056 } 0057 0058 protected: 0059 void org_kde_kwin_idle_timeout_idle() override { 0060 Q_EMIT idle(); 0061 } 0062 void org_kde_kwin_idle_timeout_resumed() override { 0063 Q_EMIT resumeFromIdle(); 0064 } 0065 }; 0066 0067 class IdleTimeoutExt : public IdleTimeout, public QtWayland::ext_idle_notification_v1 0068 { 0069 Q_OBJECT 0070 public: 0071 IdleTimeoutExt(struct ::ext_idle_notification_v1 *object) 0072 : IdleTimeout() 0073 , QtWayland::ext_idle_notification_v1(object) 0074 { 0075 } 0076 0077 ~IdleTimeoutExt() 0078 { 0079 if (qGuiApp) { 0080 destroy(); 0081 } 0082 } 0083 0084 protected: 0085 void ext_idle_notification_v1_idled() override 0086 { 0087 Q_EMIT idle(); 0088 } 0089 void ext_idle_notification_v1_resumed() override 0090 { 0091 Q_EMIT resumeFromIdle(); 0092 } 0093 }; 0094 0095 class IdleManagerKwin : public QWaylandClientExtensionTemplate<IdleManagerKwin>, public QtWayland::org_kde_kwin_idle 0096 { 0097 public: 0098 IdleManagerKwin() 0099 : QWaylandClientExtensionTemplate<IdleManagerKwin>(1) 0100 { 0101 #if QTWAYLANDCLIENT_VERSION >= QT_VERSION_CHECK(6, 2, 0) 0102 initialize(); 0103 #else 0104 // QWaylandClientExtensionTemplate invokes this with a QueuedConnection but we want shortcuts 0105 // to be inhibited immediately. 0106 QMetaObject::invokeMethod(this, "addRegistryListener"); 0107 #endif 0108 } 0109 }; 0110 0111 class IdleManagerExt : public QWaylandClientExtensionTemplate<IdleManagerExt>, public QtWayland::ext_idle_notifier_v1 0112 { 0113 public: 0114 IdleManagerExt() 0115 : QWaylandClientExtensionTemplate<IdleManagerExt>(1) 0116 { 0117 #if QTWAYLANDCLIENT_VERSION >= QT_VERSION_CHECK(6, 2, 0) 0118 initialize(); 0119 #else 0120 // QWaylandClientExtensionTemplate invokes this with a QueuedConnection but we want shortcuts 0121 // to be inhibited immediately. 0122 QMetaObject::invokeMethod(this, "addRegistryListener"); 0123 #endif 0124 } 0125 ~IdleManagerExt() 0126 { 0127 if (qGuiApp && isActive()) { 0128 destroy(); 0129 } 0130 } 0131 }; 0132 0133 Poller::Poller(QObject *parent) 0134 : AbstractSystemPoller(parent) 0135 , m_idleManagerKwin(new IdleManagerKwin) 0136 , m_idleManagerExt(new IdleManagerExt) 0137 { 0138 } 0139 0140 Poller::~Poller() = default; 0141 0142 bool Poller::isAvailable() 0143 { 0144 return m_idleManagerKwin->isActive() || m_idleManagerExt->isActive(); 0145 } 0146 0147 void Poller::addTimeout(int nextTimeout) 0148 { 0149 if (m_timeouts.contains(nextTimeout)) { 0150 return; 0151 } 0152 0153 auto timeout = createTimeout(nextTimeout); 0154 if (!timeout) { 0155 return; 0156 } 0157 0158 connect(timeout, &IdleTimeout::idle, this, [this, nextTimeout] { 0159 Q_EMIT timeoutReached(nextTimeout); 0160 }); 0161 connect(timeout, &IdleTimeout::resumeFromIdle, this, &Poller::resumingFromIdle); 0162 m_timeouts.insert(nextTimeout, QSharedPointer<IdleTimeout>(timeout)); 0163 } 0164 0165 void Poller::removeTimeout(int nextTimeout) 0166 { 0167 m_timeouts.remove(nextTimeout); 0168 } 0169 0170 QList<int> Poller::timeouts() const 0171 { 0172 return QList<int>(); 0173 } 0174 0175 void Poller::catchIdleEvent() 0176 { 0177 if (m_catchResumeTimeout) { 0178 // already setup 0179 return; 0180 } 0181 if (!isAvailable()) { 0182 return; 0183 } 0184 0185 m_catchResumeTimeout.reset(createTimeout(0)); 0186 if (!m_catchResumeTimeout) { 0187 return; 0188 } 0189 connect(m_catchResumeTimeout.get(), &IdleTimeout::resumeFromIdle, this, [this] { 0190 stopCatchingIdleEvents(); 0191 Q_EMIT resumingFromIdle(); 0192 }); 0193 } 0194 0195 void Poller::stopCatchingIdleEvents() 0196 { 0197 m_catchResumeTimeout.reset(); 0198 } 0199 0200 int Poller::forcePollRequest() 0201 { 0202 qCWarning(POLLER) << "This plugin does not support polling idle time"; 0203 return 0; 0204 } 0205 0206 void Poller::simulateUserActivity() 0207 { 0208 } 0209 0210 IdleTimeout* Poller::createTimeout(int timeout) 0211 { 0212 QPlatformNativeInterface *nativeInterface = qGuiApp->platformNativeInterface(); 0213 if (!nativeInterface) { 0214 return nullptr; 0215 } 0216 auto seat = static_cast<wl_seat *>(nativeInterface->nativeResourceForIntegration("wl_seat")); 0217 if (!seat) { 0218 return nullptr; 0219 } 0220 0221 if (m_idleManagerExt->isActive()) { 0222 return new IdleTimeoutExt(m_idleManagerExt->get_idle_notification(timeout, seat)); 0223 } 0224 if (m_idleManagerKwin->isActive()) { 0225 return new IdleTimeoutKwin(m_idleManagerKwin->get_idle_timeout(seat, timeout)); 0226 } 0227 return nullptr; 0228 } 0229 0230 #include "moc_poller.cpp" 0231 #include "poller.moc"