File indexing completed on 2025-02-09 04:22:49
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 <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 initialize(); 0102 } 0103 }; 0104 0105 class IdleManagerExt : public QWaylandClientExtensionTemplate<IdleManagerExt>, public QtWayland::ext_idle_notifier_v1 0106 { 0107 public: 0108 IdleManagerExt() 0109 : QWaylandClientExtensionTemplate<IdleManagerExt>(1) 0110 { 0111 initialize(); 0112 } 0113 ~IdleManagerExt() 0114 { 0115 if (qGuiApp && isActive()) { 0116 destroy(); 0117 } 0118 } 0119 }; 0120 0121 Poller::Poller(QObject *parent) 0122 : KAbstractIdleTimePoller(parent) 0123 , m_idleManagerKwin(new IdleManagerKwin) 0124 , m_idleManagerExt(new IdleManagerExt) 0125 { 0126 } 0127 0128 Poller::~Poller() = default; 0129 0130 bool Poller::isAvailable() 0131 { 0132 return m_idleManagerKwin->isActive() || m_idleManagerExt->isActive(); 0133 } 0134 0135 void Poller::addTimeout(int nextTimeout) 0136 { 0137 if (m_timeouts.contains(nextTimeout)) { 0138 return; 0139 } 0140 0141 auto timeout = createTimeout(nextTimeout); 0142 if (!timeout) { 0143 return; 0144 } 0145 0146 connect(timeout, &IdleTimeout::idle, this, [this, nextTimeout] { 0147 Q_EMIT timeoutReached(nextTimeout); 0148 }); 0149 connect(timeout, &IdleTimeout::resumeFromIdle, this, &Poller::resumingFromIdle); 0150 m_timeouts.insert(nextTimeout, QSharedPointer<IdleTimeout>(timeout)); 0151 } 0152 0153 void Poller::removeTimeout(int nextTimeout) 0154 { 0155 m_timeouts.remove(nextTimeout); 0156 } 0157 0158 QList<int> Poller::timeouts() const 0159 { 0160 return QList<int>(); 0161 } 0162 0163 void Poller::catchIdleEvent() 0164 { 0165 if (m_catchResumeTimeout) { 0166 // already setup 0167 return; 0168 } 0169 if (!isAvailable()) { 0170 return; 0171 } 0172 0173 m_catchResumeTimeout.reset(createTimeout(0)); 0174 if (!m_catchResumeTimeout) { 0175 return; 0176 } 0177 connect(m_catchResumeTimeout.get(), &IdleTimeout::resumeFromIdle, this, [this] { 0178 stopCatchingIdleEvents(); 0179 Q_EMIT resumingFromIdle(); 0180 }); 0181 } 0182 0183 void Poller::stopCatchingIdleEvents() 0184 { 0185 m_catchResumeTimeout.reset(); 0186 } 0187 0188 int Poller::forcePollRequest() 0189 { 0190 qCWarning(POLLER) << "This plugin does not support polling idle time"; 0191 return 0; 0192 } 0193 0194 void Poller::simulateUserActivity() 0195 { 0196 } 0197 0198 IdleTimeout* Poller::createTimeout(int timeout) 0199 { 0200 QPlatformNativeInterface *nativeInterface = qGuiApp->platformNativeInterface(); 0201 if (!nativeInterface) { 0202 return nullptr; 0203 } 0204 auto seat = static_cast<wl_seat *>(nativeInterface->nativeResourceForIntegration("wl_seat")); 0205 if (!seat) { 0206 return nullptr; 0207 } 0208 0209 if (m_idleManagerExt->isActive()) { 0210 return new IdleTimeoutExt(m_idleManagerExt->get_idle_notification(timeout, seat)); 0211 } 0212 if (m_idleManagerKwin->isActive()) { 0213 return new IdleTimeoutKwin(m_idleManagerKwin->get_idle_timeout(seat, timeout)); 0214 } 0215 return nullptr; 0216 } 0217 0218 #include "moc_poller.cpp" 0219 #include "poller.moc"