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"