File indexing completed on 2025-01-19 04:23:50
0001 /* 0002 SPDX-FileCopyrightText: 2019 (c) Matthieu Gallien <matthieu_gallien@yahoo.fr> 0003 0004 SPDX-License-Identifier: LGPL-3.0-or-later 0005 */ 0006 0007 #include "powermanagementinterface.h" 0008 0009 #include <KLocalizedString> 0010 0011 #if defined Q_OS_LINUX && !defined Q_OS_ANDROID 0012 #define Qt5DBus_FOUND true 0013 #else 0014 #define Qt5DBus_FOUND false 0015 #endif 0016 0017 #if Qt5DBus_FOUND 0018 #include <QDBusConnection> 0019 #include <QDBusMessage> 0020 #include <QDBusPendingCall> 0021 #include <QDBusPendingCallWatcher> 0022 #include <QDBusPendingReply> 0023 #include <QDBusUnixFileDescriptor> 0024 #endif 0025 0026 #if defined Q_OS_WIN 0027 #include <windows.h> 0028 #include <winbase.h> 0029 #endif 0030 0031 #include <QString> 0032 #include <QDebug> 0033 #include <QGuiApplication> 0034 0035 class PowerManagementInterfacePrivate 0036 { 0037 public: 0038 0039 bool mPreventSleep = false; 0040 0041 bool mInhibitedSleep = false; 0042 0043 uint mInhibitSleepCookie = 0; 0044 0045 }; 0046 0047 PowerManagementInterface::PowerManagementInterface(QObject *parent) : QObject(parent), d(std::make_unique<PowerManagementInterfacePrivate>()) 0048 { 0049 #if Qt5DBus_FOUND 0050 auto sessionBus = QDBusConnection::sessionBus(); 0051 0052 sessionBus.connect(QStringLiteral("org.freedesktop.PowerManagement.Inhibit"), 0053 QStringLiteral("/org/freedesktop/PowerManagement/Inhibit"), 0054 QStringLiteral("org.freedesktop.PowerManagement.Inhibit"), 0055 QStringLiteral("HasInhibitChanged"), this, SLOT(hostSleepInhibitChanged())); 0056 #endif 0057 } 0058 0059 PowerManagementInterface::~PowerManagementInterface() = default; 0060 0061 bool PowerManagementInterface::preventSleep() const 0062 { 0063 return d->mPreventSleep; 0064 } 0065 0066 bool PowerManagementInterface::sleepInhibited() const 0067 { 0068 return d->mInhibitedSleep; 0069 } 0070 0071 void PowerManagementInterface::setPreventSleep(bool value) 0072 { 0073 if (d->mPreventSleep == value) { 0074 return; 0075 } 0076 0077 if (value) { 0078 inhibitSleepPlasmaWorkspace(); 0079 inhibitSleepGnomeWorkspace(); 0080 d->mPreventSleep = true; 0081 } else { 0082 uninhibitSleepPlasmaWorkspace(); 0083 uninhibitSleepGnomeWorkspace(); 0084 d->mPreventSleep = false; 0085 } 0086 0087 Q_EMIT preventSleepChanged(); 0088 } 0089 0090 void PowerManagementInterface::retryInhibitingSleep() 0091 { 0092 if (d->mPreventSleep && !d->mInhibitedSleep) { 0093 inhibitSleepPlasmaWorkspace(); 0094 inhibitSleepGnomeWorkspace(); 0095 } 0096 } 0097 0098 void PowerManagementInterface::hostSleepInhibitChanged() 0099 { 0100 } 0101 0102 void PowerManagementInterface::inhibitDBusCallFinishedPlasmaWorkspace(QDBusPendingCallWatcher *aWatcher) 0103 { 0104 #if Qt5DBus_FOUND 0105 QDBusPendingReply<uint> reply = *aWatcher; 0106 if (reply.isError()) { 0107 } else { 0108 d->mInhibitSleepCookie = reply.argumentAt<0>(); 0109 d->mInhibitedSleep = true; 0110 0111 Q_EMIT sleepInhibitedChanged(); 0112 } 0113 aWatcher->deleteLater(); 0114 #endif 0115 } 0116 0117 void PowerManagementInterface::uninhibitDBusCallFinishedPlasmaWorkspace(QDBusPendingCallWatcher *aWatcher) 0118 { 0119 #if Qt5DBus_FOUND 0120 QDBusPendingReply<> reply = *aWatcher; 0121 if (reply.isError()) { 0122 qDebug() << "PowerManagementInterface::uninhibitDBusCallFinished" << reply.error(); 0123 } else { 0124 d->mInhibitedSleep = false; 0125 0126 Q_EMIT sleepInhibitedChanged(); 0127 } 0128 aWatcher->deleteLater(); 0129 #endif 0130 } 0131 0132 void PowerManagementInterface::inhibitDBusCallFinishedGnomeWorkspace(QDBusPendingCallWatcher *aWatcher) 0133 { 0134 #if Qt5DBus_FOUND 0135 QDBusPendingReply<uint> reply = *aWatcher; 0136 if (reply.isError()) { 0137 qDebug() << "PowerManagementInterface::inhibitDBusCallFinishedGnomeWorkspace" << reply.error(); 0138 } else { 0139 d->mInhibitSleepCookie = reply.argumentAt<0>(); 0140 d->mInhibitedSleep = true; 0141 0142 Q_EMIT sleepInhibitedChanged(); 0143 } 0144 aWatcher->deleteLater(); 0145 #endif 0146 } 0147 0148 void PowerManagementInterface::uninhibitDBusCallFinishedGnomeWorkspace(QDBusPendingCallWatcher *aWatcher) 0149 { 0150 #if Qt5DBus_FOUND 0151 QDBusPendingReply<> reply = *aWatcher; 0152 if (reply.isError()) { 0153 qDebug() << "PowerManagementInterface::uninhibitDBusCallFinished" << reply.error(); 0154 } else { 0155 d->mInhibitedSleep = false; 0156 0157 Q_EMIT sleepInhibitedChanged(); 0158 } 0159 aWatcher->deleteLater(); 0160 #endif 0161 } 0162 0163 void PowerManagementInterface::inhibitSleepPlasmaWorkspace() 0164 { 0165 #if Qt5DBus_FOUND 0166 auto sessionBus = QDBusConnection::sessionBus(); 0167 0168 auto inhibitCall = QDBusMessage::createMethodCall(QStringLiteral("org.freedesktop.PowerManagement.Inhibit"), 0169 QStringLiteral("/org/freedesktop/PowerManagement/Inhibit"), 0170 QStringLiteral("org.freedesktop.PowerManagement.Inhibit"), 0171 QStringLiteral("Inhibit")); 0172 0173 inhibitCall.setArguments({{QGuiApplication::desktopFileName()}, {i18nc("explanation for sleep inhibit during play of music", "Playing music")}}); 0174 0175 auto asyncReply = sessionBus.asyncCall(inhibitCall); 0176 0177 auto replyWatcher = new QDBusPendingCallWatcher(asyncReply, this); 0178 0179 QObject::connect(replyWatcher, &QDBusPendingCallWatcher::finished, 0180 this, &PowerManagementInterface::inhibitDBusCallFinishedPlasmaWorkspace); 0181 #endif 0182 } 0183 0184 void PowerManagementInterface::uninhibitSleepPlasmaWorkspace() 0185 { 0186 #if Qt5DBus_FOUND 0187 auto sessionBus = QDBusConnection::sessionBus(); 0188 0189 auto uninhibitCall = QDBusMessage::createMethodCall(QStringLiteral("org.freedesktop.PowerManagement.Inhibit"), 0190 QStringLiteral("/org/freedesktop/PowerManagement/Inhibit"), 0191 QStringLiteral("org.freedesktop.PowerManagement.Inhibit"), 0192 QStringLiteral("UnInhibit")); 0193 0194 uninhibitCall.setArguments({{d->mInhibitSleepCookie}}); 0195 0196 auto asyncReply = sessionBus.asyncCall(uninhibitCall); 0197 0198 auto replyWatcher = new QDBusPendingCallWatcher(asyncReply, this); 0199 0200 QObject::connect(replyWatcher, &QDBusPendingCallWatcher::finished, 0201 this, &PowerManagementInterface::uninhibitDBusCallFinishedPlasmaWorkspace); 0202 #endif 0203 } 0204 0205 void PowerManagementInterface::inhibitSleepGnomeWorkspace() 0206 { 0207 #if Qt5DBus_FOUND 0208 auto sessionBus = QDBusConnection::sessionBus(); 0209 0210 auto inhibitCall = QDBusMessage::createMethodCall(QStringLiteral("org.gnome.SessionManager"), 0211 QStringLiteral("/org/gnome/SessionManager"), 0212 QStringLiteral("org.gnome.SessionManager"), 0213 QStringLiteral("Inhibit")); 0214 0215 // See: https://gitlab.gnome.org/GNOME/gnome-session/-/blob/master/gnome-session/org.gnome.SessionManager.xml 0216 // The last argument are flag settings to specify what should be inhibited: 0217 // 1 = Inhibit logging out 0218 // 2 = Inhibit user switching 0219 // 4 = Inhibit suspending the session or computer 0220 // 8 = Inhibit the session being marked as idle 0221 // 16 = Inhibit auto-mounting removable media for the session 0222 inhibitCall.setArguments({{QCoreApplication::applicationName()}, {uint(0)}, 0223 {i18nc("explanation for sleep inhibit during play of music", "Playing music")}, {uint(12)}}); 0224 0225 auto asyncReply = sessionBus.asyncCall(inhibitCall); 0226 0227 auto replyWatcher = new QDBusPendingCallWatcher(asyncReply, this); 0228 0229 QObject::connect(replyWatcher, &QDBusPendingCallWatcher::finished, 0230 this, &PowerManagementInterface::inhibitDBusCallFinishedGnomeWorkspace); 0231 #endif 0232 } 0233 0234 void PowerManagementInterface::uninhibitSleepGnomeWorkspace() 0235 { 0236 #if Qt5DBus_FOUND 0237 auto sessionBus = QDBusConnection::sessionBus(); 0238 0239 auto uninhibitCall = QDBusMessage::createMethodCall(QStringLiteral("org.gnome.SessionManager"), 0240 QStringLiteral("/org/gnome/SessionManager"), 0241 QStringLiteral("org.gnome.SessionManager"), 0242 QStringLiteral("UnInhibit")); 0243 0244 uninhibitCall.setArguments({{d->mInhibitSleepCookie}}); 0245 0246 auto asyncReply = sessionBus.asyncCall(uninhibitCall); 0247 0248 auto replyWatcher = new QDBusPendingCallWatcher(asyncReply, this); 0249 0250 QObject::connect(replyWatcher, &QDBusPendingCallWatcher::finished, 0251 this, &PowerManagementInterface::uninhibitDBusCallFinishedGnomeWorkspace); 0252 #endif 0253 } 0254 0255 void PowerManagementInterface::inhibitSleepWindowsWorkspace() 0256 { 0257 #if defined Q_OS_WIN 0258 SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED); 0259 #endif 0260 } 0261 0262 void PowerManagementInterface::uninhibitSleepWindowsWorkspace() 0263 { 0264 #if defined Q_OS_WIN 0265 SetThreadExecutionState(ES_CONTINUOUS); 0266 #endif 0267 } 0268 0269 0270 #include "moc_powermanagementinterface.cpp"