File indexing completed on 2025-01-05 04:29:51

0001 /**
0002  * SPDX-FileCopyrightText: 2019 Matthieu Gallien <matthieu_gallien@yahoo.fr>
0003  * SPDX-FileCopyrightText: 2021-2023 Bart De Vries <bart@mogwai.be>
0004  *
0005  * SPDX-License-Identifier: LGPL-3.0-or-later
0006  */
0007 
0008 #include "powermanagementinterface.h"
0009 #include "powermanagementinterfacelogging.h"
0010 
0011 #include <KLocalizedString>
0012 
0013 #if !defined Q_OS_ANDROID && !defined Q_OS_WIN
0014 #include <QDBusConnection>
0015 #include <QDBusPendingCallWatcher>
0016 #include <QDBusPendingReply>
0017 #endif
0018 
0019 #if defined Q_OS_WIN
0020 #include <windows.h>
0021 #endif
0022 
0023 #include <QCoreApplication>
0024 #include <QDebug>
0025 #include <QString>
0026 
0027 #if !defined Q_OS_ANDROID && !defined Q_OS_WIN
0028 #include "gnomesessioninterface.h"
0029 #include "inhibitinterface.h"
0030 #endif
0031 
0032 class PowerManagementInterfacePrivate
0033 {
0034 public:
0035     bool mPreventSleep = false;
0036 
0037     bool mInhibitedSleep = false;
0038 
0039     uint mInhibitSleepCookie = 0;
0040 
0041     uint mGnomeSleepCookie = 0;
0042 
0043 #if !defined Q_OS_ANDROID && !defined Q_OS_WIN
0044     OrgFreedesktopPowerManagementInhibitInterface *mInhibitInterface;
0045     OrgGnomeSessionManagerInterface *mGnomeInterface;
0046 #endif
0047 };
0048 
0049 PowerManagementInterface::PowerManagementInterface(QObject *parent)
0050     : QObject(parent)
0051     , d(std::make_unique<PowerManagementInterfacePrivate>())
0052 {
0053 #if !defined Q_OS_ANDROID && !defined Q_OS_WIN
0054     d->mInhibitInterface = new OrgFreedesktopPowerManagementInhibitInterface(QStringLiteral("org.freedesktop.PowerManagement.Inhibit"),
0055                                                                              QStringLiteral("/org/freedesktop/PowerManagement/Inhibit"),
0056                                                                              QDBusConnection::sessionBus(),
0057                                                                              this);
0058 
0059     d->mGnomeInterface = new OrgGnomeSessionManagerInterface(QStringLiteral("org.gnome.SessionManager"),
0060                                                              QStringLiteral("/org/gnome/SessionManager"),
0061                                                              QDBusConnection::sessionBus(),
0062                                                              this);
0063 #endif
0064 }
0065 
0066 PowerManagementInterface::~PowerManagementInterface()
0067 {
0068 #if !defined Q_OS_ANDROID && !defined Q_OS_WIN
0069     delete d->mInhibitInterface;
0070     delete d->mGnomeInterface;
0071 #endif
0072 }
0073 
0074 bool PowerManagementInterface::preventSleep() const
0075 {
0076     return d->mPreventSleep;
0077 }
0078 
0079 bool PowerManagementInterface::sleepInhibited() const
0080 {
0081     return d->mInhibitedSleep;
0082 }
0083 
0084 void PowerManagementInterface::setPreventSleep(bool value)
0085 {
0086     if (d->mPreventSleep == value) {
0087         return;
0088     }
0089 
0090     if (value) {
0091         inhibitSleepPlasmaWorkspace();
0092         inhibitSleepGnomeWorkspace();
0093         d->mPreventSleep = true;
0094     } else {
0095         uninhibitSleepPlasmaWorkspace();
0096         uninhibitSleepGnomeWorkspace();
0097         d->mPreventSleep = false;
0098     }
0099 
0100     Q_EMIT preventSleepChanged();
0101 }
0102 
0103 void PowerManagementInterface::retryInhibitingSleep()
0104 {
0105     if (d->mPreventSleep && !d->mInhibitedSleep) {
0106         inhibitSleepPlasmaWorkspace();
0107         inhibitSleepGnomeWorkspace();
0108     }
0109 }
0110 
0111 void PowerManagementInterface::hostSleepInhibitChanged()
0112 {
0113 }
0114 
0115 void PowerManagementInterface::inhibitDBusCallFinishedPlasmaWorkspace(QDBusPendingCallWatcher *aWatcher)
0116 {
0117 #if !defined Q_OS_ANDROID && !defined Q_OS_WIN
0118     QDBusPendingReply<uint> reply = *aWatcher;
0119     if (reply.isError()) {
0120     } else {
0121         d->mInhibitSleepCookie = reply.argumentAt<0>();
0122         d->mInhibitedSleep = true;
0123 
0124         Q_EMIT sleepInhibitedChanged();
0125     }
0126     aWatcher->deleteLater();
0127 #else
0128     Q_UNUSED(aWatcher)
0129 #endif
0130 }
0131 
0132 void PowerManagementInterface::uninhibitDBusCallFinishedPlasmaWorkspace(QDBusPendingCallWatcher *aWatcher)
0133 {
0134 #if !defined Q_OS_ANDROID && !defined Q_OS_WIN
0135     QDBusPendingReply<> reply = *aWatcher;
0136     if (reply.isError()) {
0137         qCDebug(KMediaSessionPowerManagementInterface) << "PowerManagementInterface::uninhibitDBusCallFinished" << reply.error();
0138     } else {
0139         d->mInhibitedSleep = false;
0140 
0141         Q_EMIT sleepInhibitedChanged();
0142     }
0143     aWatcher->deleteLater();
0144 #else
0145     Q_UNUSED(aWatcher)
0146 #endif
0147 }
0148 
0149 void PowerManagementInterface::inhibitDBusCallFinishedGnomeWorkspace(QDBusPendingCallWatcher *aWatcher)
0150 {
0151 #if !defined Q_OS_ANDROID && !defined Q_OS_WIN
0152     QDBusPendingReply<uint> reply = *aWatcher;
0153     if (reply.isError()) {
0154         qCDebug(KMediaSessionPowerManagementInterface) << "PowerManagementInterface::inhibitDBusCallFinishedGnomeWorkspace" << reply.error();
0155     } else {
0156         d->mGnomeSleepCookie = reply.argumentAt<0>();
0157         d->mInhibitedSleep = true;
0158 
0159         Q_EMIT sleepInhibitedChanged();
0160     }
0161     aWatcher->deleteLater();
0162 #else
0163     Q_UNUSED(aWatcher)
0164 #endif
0165 }
0166 
0167 void PowerManagementInterface::uninhibitDBusCallFinishedGnomeWorkspace(QDBusPendingCallWatcher *aWatcher)
0168 {
0169 #if !defined Q_OS_ANDROID && !defined Q_OS_WIN
0170     QDBusPendingReply<> reply = *aWatcher;
0171     if (reply.isError()) {
0172         qCDebug(KMediaSessionPowerManagementInterface) << "PowerManagementInterface::uninhibitDBusCallFinished" << reply.error();
0173     } else {
0174         d->mInhibitedSleep = false;
0175 
0176         Q_EMIT sleepInhibitedChanged();
0177     }
0178     aWatcher->deleteLater();
0179 #else
0180     Q_UNUSED(aWatcher)
0181 #endif
0182 }
0183 
0184 void PowerManagementInterface::inhibitSleepPlasmaWorkspace()
0185 {
0186 #if !defined Q_OS_ANDROID && !defined Q_OS_WIN
0187     auto asyncReply =
0188         d->mInhibitInterface->Inhibit(QCoreApplication::applicationName(), i18nc("Explanation for sleep inhibit during media playback", "Playing Media"));
0189 
0190     auto replyWatcher = new QDBusPendingCallWatcher(asyncReply, this);
0191 
0192     QObject::connect(replyWatcher, &QDBusPendingCallWatcher::finished, this, &PowerManagementInterface::inhibitDBusCallFinishedPlasmaWorkspace);
0193 #endif
0194 }
0195 
0196 void PowerManagementInterface::uninhibitSleepPlasmaWorkspace()
0197 {
0198 #if !defined Q_OS_ANDROID && !defined Q_OS_WIN
0199     auto asyncReply = d->mInhibitInterface->UnInhibit(d->mInhibitSleepCookie);
0200 
0201     auto replyWatcher = new QDBusPendingCallWatcher(asyncReply, this);
0202 
0203     QObject::connect(replyWatcher, &QDBusPendingCallWatcher::finished, this, &PowerManagementInterface::uninhibitDBusCallFinishedPlasmaWorkspace);
0204 #endif
0205 }
0206 
0207 void PowerManagementInterface::inhibitSleepGnomeWorkspace()
0208 {
0209 #if !defined Q_OS_ANDROID && !defined Q_OS_WIN
0210     // flags are: 4 = "Inhibit suspending the session or computer"
0211     //            8 = "Inhibit the session being marked as idle"
0212     auto asyncReply = d->mGnomeInterface->Inhibit(QCoreApplication::applicationName(),
0213                                                   uint(0),
0214                                                   i18nc("Explanation for sleep inhibit during media playback", "Playing Media"),
0215                                                   uint(12));
0216 
0217     auto replyWatcher = new QDBusPendingCallWatcher(asyncReply, this);
0218 
0219     QObject::connect(replyWatcher, &QDBusPendingCallWatcher::finished, this, &PowerManagementInterface::inhibitDBusCallFinishedGnomeWorkspace);
0220 #endif
0221 }
0222 
0223 void PowerManagementInterface::uninhibitSleepGnomeWorkspace()
0224 {
0225 #if !defined Q_OS_ANDROID && !defined Q_OS_WIN
0226     auto asyncReply = d->mGnomeInterface->Uninhibit(d->mGnomeSleepCookie);
0227 
0228     auto replyWatcher = new QDBusPendingCallWatcher(asyncReply, this);
0229 
0230     QObject::connect(replyWatcher, &QDBusPendingCallWatcher::finished, this, &PowerManagementInterface::uninhibitDBusCallFinishedGnomeWorkspace);
0231 #endif
0232 }
0233 
0234 void PowerManagementInterface::inhibitSleepWindowsWorkspace()
0235 {
0236 #if defined Q_OS_WIN
0237     SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED);
0238 #endif
0239 }
0240 
0241 void PowerManagementInterface::uninhibitSleepWindowsWorkspace()
0242 {
0243 #if defined Q_OS_WIN
0244     SetThreadExecutionState(ES_CONTINUOUS);
0245 #endif
0246 }