File indexing completed on 2024-05-12 05:33:54

0001 // SPDX-FileCopyrightText: 2015 by Martin Gräßlin <mgraesslin@kde.org>
0002 // SPDX-FileCopyrightText: 2022 Aleix Pol Gonzalez <aleixpol@kde.org>
0003 //
0004 // SPDX-License-Identifier: LGPL-2.1-or-later
0005 
0006 #include "waylanddpmshelper_p.h"
0007 
0008 #include <kscreendpms_debug.h>
0009 #include <qwayland-dpms.h>
0010 
0011 #include <QDebug>
0012 #include <QGuiApplication>
0013 #include <QList>
0014 #include <QPointer>
0015 #include <QScreen>
0016 #include <QWaylandClientExtensionTemplate>
0017 #include <qpa/qplatformscreen_p.h>
0018 
0019 class Dpms : public QObject, public QtWayland::org_kde_kwin_dpms
0020 {
0021 public:
0022     Dpms(struct ::org_kde_kwin_dpms *object, WaylandDpmsHelper *dpms, QScreen *parent)
0023         : QObject(parent)
0024         , org_kde_kwin_dpms(object)
0025         , m_screen(parent)
0026         , m_dpms(dpms)
0027     {
0028     }
0029 
0030     ~Dpms()
0031     {
0032         release();
0033     }
0034 
0035     bool isSupported() const
0036     {
0037         return m_supported;
0038     }
0039 
0040     void org_kde_kwin_dpms_supported(uint32_t supported) override
0041     {
0042         m_pendingSupported = supported;
0043     }
0044 
0045     void org_kde_kwin_dpms_mode(uint32_t newMode) override
0046     {
0047         m_mode = mode(newMode);
0048     }
0049 
0050     void org_kde_kwin_dpms_done() override
0051     {
0052         m_supported = m_pendingSupported;
0053         KScreen::Dpms::Mode mode;
0054         switch (m_mode) {
0055         case Dpms::mode_On:
0056             mode = KScreen::Dpms::On;
0057             break;
0058         case Dpms::mode_Standby:
0059             mode = KScreen::Dpms::Standby;
0060             break;
0061         case Dpms::mode_Suspend:
0062             mode = KScreen::Dpms::Suspend;
0063             break;
0064         case Dpms::mode_Off:
0065             mode = KScreen::Dpms::Off;
0066             break;
0067         }
0068         if (m_dpms) {
0069             Q_EMIT m_dpms->modeChanged(mode, m_screen);
0070         }
0071     }
0072 
0073     QScreen *const m_screen;
0074     QPointer<WaylandDpmsHelper> m_dpms;
0075     bool m_supported = false;
0076     bool m_pendingSupported = false;
0077     mode m_mode;
0078 };
0079 
0080 class DpmsManager : public QWaylandClientExtensionTemplate<::DpmsManager>, public QtWayland::org_kde_kwin_dpms_manager
0081 {
0082 public:
0083     DpmsManager(WaylandDpmsHelper *dpms)
0084         : QWaylandClientExtensionTemplate<DpmsManager>(1)
0085         , m_dpms(dpms)
0086     {
0087         connect(this, &DpmsManager::activeChanged, this, [this] {
0088             const bool hasDpms = isActive();
0089             if (hasDpms) {
0090                 qCDebug(KSCREEN_DPMS) << "Compositor provides a DpmsManager";
0091             } else {
0092                 qCDebug(KSCREEN_DPMS) << "Compositor does not provide a DpmsManager";
0093                 m_dpms->setSupported(hasDpms);
0094                 return;
0095             }
0096 
0097             const auto screens = qGuiApp->screens();
0098             for (QScreen *screen : screens) {
0099                 addScreen(screen);
0100             }
0101             connect(qGuiApp, &QGuiApplication::screenAdded, this, &DpmsManager::addScreen);
0102             connect(qGuiApp, &QGuiApplication::screenRemoved, this, [this](QScreen *screen) {
0103                 delete m_dpmsPerScreen.take(screen);
0104             });
0105             m_dpms->setSupported(hasDpms);
0106         });
0107         initialize();
0108     }
0109     ~DpmsManager()
0110     {
0111         qDeleteAll(m_dpmsPerScreen);
0112     }
0113 
0114     Dpms *fetch(QScreen *screen)
0115     {
0116         return m_dpmsPerScreen.value(screen);
0117     }
0118 
0119 private:
0120     void addScreen(QScreen *screen)
0121     {
0122 #if QT_VERSION < QT_VERSION_CHECK(6, 7, 0)
0123         auto waylandScreen = screen->nativeInterface<QNativeInterface::Private::QWaylandScreen>();
0124 #else
0125         auto waylandScreen = screen->nativeInterface<QNativeInterface::QWaylandScreen>();
0126 #endif
0127         if (waylandScreen && waylandScreen->output()) {
0128             m_dpmsPerScreen[screen] = new Dpms(get(waylandScreen->output()), m_dpms, screen);
0129         }
0130     }
0131 
0132     WaylandDpmsHelper *const m_dpms;
0133     QHash<QScreen *, Dpms *> m_dpmsPerScreen;
0134 };
0135 
0136 WaylandDpmsHelper::WaylandDpmsHelper()
0137     : AbstractDpmsHelper()
0138     , m_dpmsManager(new DpmsManager(this))
0139 {
0140 }
0141 
0142 WaylandDpmsHelper::~WaylandDpmsHelper()
0143 {
0144     delete m_dpmsManager;
0145 }
0146 
0147 void WaylandDpmsHelper::trigger(KScreen::Dpms::Mode mode, const QList<QScreen *> &screens)
0148 {
0149     Q_ASSERT(isSupported());
0150 
0151     if (screens.isEmpty()) {
0152         return;
0153     }
0154 
0155     setHasPendingChanges(true);
0156 
0157     auto level = Dpms::mode_On;
0158     switch (mode) {
0159     case KScreen::Dpms::Toggle: {
0160         for (QScreen *screen : screens) {
0161             auto dpms = m_dpmsManager->fetch(screen);
0162             if (!dpms || !dpms->isSupported()) {
0163                 qCDebug(KSCREEN_DPMS) << "screen does not provide dpms" << screen;
0164                 continue;
0165             }
0166             if (dpms->m_mode == Dpms::mode_On) {
0167                 dpms->set(Dpms::mode_Off);
0168             } else {
0169                 dpms->set(Dpms::mode_On);
0170             }
0171         }
0172     }
0173         return;
0174     case KScreen::Dpms::Off:
0175         level = Dpms::mode_Off;
0176         break;
0177     case KScreen::Dpms::Standby:
0178         level = Dpms::mode_Standby;
0179         break;
0180     case KScreen::Dpms::Suspend:
0181         level = Dpms::mode_Suspend;
0182         break;
0183     case KScreen::Dpms::On:
0184         level = Dpms::mode_On;
0185         break;
0186     }
0187     for (auto screen : screens) {
0188         auto dpms = m_dpmsManager->fetch(screen);
0189         if (dpms) {
0190             dpms->set(level);
0191         }
0192     }
0193     setHasPendingChanges(false);
0194 }
0195 
0196 #include "moc_waylanddpmshelper_p.cpp"