Warning, file /plasma/libkscreen/src/libdpms/waylanddpmshelper.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
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 "kscreendpms_debug.h" 0007 #include "waylanddpmshelper_p.h" 0008 0009 #include "qwayland-dpms.h" 0010 #include <QDebug> 0011 #include <QGuiApplication> 0012 #include <QPointer> 0013 #include <QScreen> 0014 #include <QVector> 0015 #include <QWaylandClientExtensionTemplate> 0016 #include <qpa/qplatformnativeinterface.h> 0017 0018 class Dpms : public QObject, public QtWayland::org_kde_kwin_dpms 0019 { 0020 public: 0021 Dpms(struct ::org_kde_kwin_dpms *object, WaylandDpmsHelper *dpms, QScreen *parent) 0022 : QObject(parent) 0023 , org_kde_kwin_dpms(object) 0024 , m_screen(parent) 0025 , m_dpms(dpms) 0026 { 0027 } 0028 0029 ~Dpms() 0030 { 0031 release(); 0032 } 0033 0034 bool isSupported() const 0035 { 0036 return m_supported; 0037 } 0038 0039 void org_kde_kwin_dpms_supported(uint32_t supported) override 0040 { 0041 m_pendingSupported = supported; 0042 } 0043 0044 void org_kde_kwin_dpms_mode(uint32_t newMode) override 0045 { 0046 m_mode = mode(newMode); 0047 } 0048 0049 void org_kde_kwin_dpms_done() override 0050 { 0051 m_supported = m_pendingSupported; 0052 KScreen::Dpms::Mode mode; 0053 switch (m_mode) { 0054 case Dpms::mode_On: 0055 mode = KScreen::Dpms::On; 0056 break; 0057 case Dpms::mode_Standby: 0058 mode = KScreen::Dpms::Standby; 0059 break; 0060 case Dpms::mode_Suspend: 0061 mode = KScreen::Dpms::Suspend; 0062 break; 0063 case Dpms::mode_Off: 0064 mode = KScreen::Dpms::Off; 0065 break; 0066 } 0067 if (m_dpms) { 0068 Q_EMIT m_dpms->modeChanged(mode, m_screen); 0069 } 0070 } 0071 0072 QScreen *const m_screen; 0073 QPointer<WaylandDpmsHelper> m_dpms; 0074 bool m_supported = false; 0075 bool m_pendingSupported = false; 0076 mode m_mode; 0077 }; 0078 0079 class DpmsManager : public QWaylandClientExtensionTemplate<::DpmsManager>, public QtWayland::org_kde_kwin_dpms_manager 0080 { 0081 public: 0082 DpmsManager(WaylandDpmsHelper *dpms) 0083 : QWaylandClientExtensionTemplate<DpmsManager>(1) 0084 , m_dpms(dpms) 0085 { 0086 connect(this, &DpmsManager::activeChanged, this, [this] { 0087 const bool hasDpms = isActive(); 0088 if (hasDpms) { 0089 qCDebug(KSCREEN_DPMS) << "Compositor provides a DpmsManager"; 0090 } else { 0091 qCDebug(KSCREEN_DPMS) << "Compositor does not provide a DpmsManager"; 0092 m_dpms->setSupported(hasDpms); 0093 return; 0094 } 0095 0096 const auto screens = qGuiApp->screens(); 0097 for (QScreen *screen : screens) { 0098 addScreen(screen); 0099 } 0100 connect(qGuiApp, &QGuiApplication::screenAdded, this, &DpmsManager::addScreen); 0101 connect(qGuiApp, &QGuiApplication::screenRemoved, this, [this](QScreen *screen) { 0102 delete m_dpmsPerScreen.take(screen); 0103 }); 0104 m_dpms->setSupported(hasDpms); 0105 }); 0106 } 0107 ~DpmsManager() 0108 { 0109 qDeleteAll(m_dpmsPerScreen); 0110 } 0111 0112 Dpms *fetch(QScreen *screen) 0113 { 0114 return m_dpmsPerScreen.value(screen); 0115 } 0116 0117 private: 0118 void addScreen(QScreen *screen) 0119 { 0120 // We can't rely on checking the wl_output being null yet 0121 // https://codereview.qt-project.org/c/qt/qtwayland/+/464669 0122 const bool fake = screen->geometry().isEmpty() || screen->name().isEmpty(); 0123 if (fake) { 0124 return; 0125 } 0126 0127 QPlatformNativeInterface *native = qGuiApp->platformNativeInterface(); 0128 wl_output *output = reinterpret_cast<wl_output *>(native->nativeResourceForScreen(QByteArrayLiteral("output"), screen)); 0129 if (output) { 0130 m_dpmsPerScreen[screen] = new Dpms(get(output), m_dpms, screen); 0131 } 0132 } 0133 0134 WaylandDpmsHelper *const m_dpms; 0135 QHash<QScreen *, Dpms *> m_dpmsPerScreen; 0136 }; 0137 0138 WaylandDpmsHelper::WaylandDpmsHelper() 0139 : AbstractDpmsHelper() 0140 , m_dpmsManager(new DpmsManager(this)) 0141 { 0142 } 0143 0144 WaylandDpmsHelper::~WaylandDpmsHelper() 0145 { 0146 delete m_dpmsManager; 0147 } 0148 0149 void WaylandDpmsHelper::trigger(KScreen::Dpms::Mode mode, const QList<QScreen *> &screens) 0150 { 0151 Q_ASSERT(isSupported()); 0152 0153 if (screens.isEmpty()) { 0154 return; 0155 } 0156 0157 setHasPendingChanges(true); 0158 0159 auto level = Dpms::mode_On; 0160 switch (mode) { 0161 case KScreen::Dpms::Toggle: { 0162 for (QScreen *screen : screens) { 0163 auto dpms = m_dpmsManager->fetch(screen); 0164 if (!dpms || !dpms->isSupported()) { 0165 qCDebug(KSCREEN_DPMS) << "screen does not provide dpms" << screen; 0166 continue; 0167 } 0168 if (dpms->m_mode == Dpms::mode_On) { 0169 dpms->set(Dpms::mode_Off); 0170 } else { 0171 dpms->set(Dpms::mode_On); 0172 } 0173 } 0174 } 0175 return; 0176 case KScreen::Dpms::Off: 0177 level = Dpms::mode_Off; 0178 break; 0179 case KScreen::Dpms::Standby: 0180 level = Dpms::mode_Standby; 0181 break; 0182 case KScreen::Dpms::Suspend: 0183 level = Dpms::mode_Suspend; 0184 break; 0185 case KScreen::Dpms::On: 0186 level = Dpms::mode_On; 0187 break; 0188 } 0189 for (auto screen : screens) { 0190 auto dpms = m_dpmsManager->fetch(screen); 0191 if (dpms) { 0192 dpms->set(level); 0193 } 0194 } 0195 setHasPendingChanges(false); 0196 } 0197 0198 void WaylandDpmsHelper::blockUntilSupported() 0199 { 0200 QMetaObject::invokeMethod(m_dpmsManager, "addRegistryListener"); 0201 if (!m_dpmsManager->isActive()) { 0202 setSupported(false); 0203 } 0204 }