File indexing completed on 2024-05-12 07:49:33

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"