File indexing completed on 2024-04-21 14:56:11

0001 /*
0002     Copyright 2006-2007 Kevin Ottens <ervin@kde.org>
0003     Copyright 2013 Lukas Tinkl <ltinkl@redhat.com>
0004 
0005     This library is free software; you can redistribute it and/or
0006     modify it under the terms of the GNU Lesser General Public
0007     License as published by the Free Software Foundation; either
0008     version 2.1 of the License, or (at your option) version 3, or any
0009     later version accepted by the membership of KDE e.V. (or its
0010     successor approved by the membership of KDE e.V.), which shall
0011     act as a proxy defined in Section 6 of version 3 of the license.
0012 
0013     This library is distributed in the hope that it will be useful,
0014     but WITHOUT ANY WARRANTY; without even the implied warranty of
0015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0016     Lesser General Public License for more details.
0017 
0018     You should have received a copy of the GNU Lesser General Public
0019     License along with this library. If not, see <http://www.gnu.org/licenses/>.
0020 */
0021 
0022 #include "powermanagement.h"
0023 #include "powermanagement_p.h"
0024 
0025 #include <QCoreApplication>
0026 
0027 Q_GLOBAL_STATIC(Solid::PowerManagementPrivate, globalPowerManager)
0028 
0029 Solid::PowerManagementPrivate::PowerManagementPrivate()
0030     : managerIface("org.freedesktop.PowerManagement",
0031                    "/org/freedesktop/PowerManagement",
0032                    QDBusConnection::sessionBus()),
0033     policyAgentIface("org.kde.Solid.PowerManagement.PolicyAgent",
0034                      "/org/kde/Solid/PowerManagement/PolicyAgent",
0035                      QDBusConnection::sessionBus()),
0036     inhibitIface("org.freedesktop.PowerManagement.Inhibit",
0037                  "/org/freedesktop/PowerManagement/Inhibit",
0038                  QDBusConnection::sessionBus()),
0039     serviceWatcher("org.kde.Solid.PowerManagement",
0040                    QDBusConnection::sessionBus(),
0041                    QDBusServiceWatcher::WatchForRegistration | QDBusServiceWatcher::WatchForUnregistration),
0042     powerSaveStatus(false)
0043 {
0044     serviceWatcher.addWatchedService(QLatin1String("org.freedesktop.PowerManagement"));
0045 
0046     connect(&managerIface, SIGNAL(CanSuspendChanged(bool)),
0047             this, SLOT(slotCanSuspendChanged(bool)));
0048     connect(&managerIface, SIGNAL(CanHibernateChanged(bool)),
0049             this, SLOT(slotCanHibernateChanged(bool)));
0050     connect(&managerIface, SIGNAL(CanHybridSuspendChanged(bool)),
0051             this, SLOT(slotCanHybridSuspendChanged(bool)));
0052     connect(&managerIface, SIGNAL(PowerSaveStatusChanged(bool)),
0053             this, SLOT(slotPowerSaveStatusChanged(bool)));
0054     connect(&serviceWatcher, SIGNAL(serviceRegistered(QString)),
0055             this, SLOT(slotServiceRegistered(QString)));
0056     connect(&serviceWatcher, SIGNAL(serviceUnregistered(QString)),
0057             this, SLOT(slotServiceUnregistered(QString)));
0058 
0059     // If the service is registered, trigger the connection immediately
0060     if (QDBusConnection::sessionBus().interface()->isServiceRegistered("org.kde.Solid.PowerManagement")) {
0061         slotServiceRegistered("org.kde.Solid.PowerManagement");
0062     }
0063     if (QDBusConnection::sessionBus().interface()->isServiceRegistered(QLatin1String("org.freedesktop.PowerManagement"))) {
0064         slotServiceRegistered(QLatin1String("org.freedesktop.PowerManagement"));
0065     }
0066 }
0067 
0068 Solid::PowerManagementPrivate::~PowerManagementPrivate()
0069 {
0070 }
0071 
0072 Solid::PowerManagement::Notifier::Notifier()
0073 {
0074 }
0075 
0076 bool Solid::PowerManagement::appShouldConserveResources()
0077 {
0078     return globalPowerManager->managerIface.GetPowerSaveStatus();
0079 }
0080 
0081 QSet<Solid::PowerManagement::SleepState> Solid::PowerManagement::supportedSleepStates()
0082 {
0083     return globalPowerManager->supportedSleepStates;
0084 }
0085 
0086 void Solid::PowerManagement::requestSleep(SleepState state, QObject *receiver, const char *member)
0087 {
0088     Q_UNUSED(receiver)
0089     Q_UNUSED(member)
0090 
0091     if (!globalPowerManager->supportedSleepStates.contains(state)) {
0092         return;
0093     }
0094 
0095     switch (state) {
0096     case StandbyState:
0097     case SuspendState:
0098         globalPowerManager->managerIface.Suspend();
0099         break;
0100     case HibernateState:
0101         globalPowerManager->managerIface.Hibernate();
0102         break;
0103     }
0104 }
0105 
0106 int Solid::PowerManagement::beginSuppressingSleep(const QString &reason)
0107 {
0108     QDBusReply<uint> reply;
0109     if (globalPowerManager->policyAgentIface.isValid()) {
0110         reply = globalPowerManager->policyAgentIface.AddInhibition(
0111                     (uint)PowerManagementPrivate::InterruptSession,
0112                     QCoreApplication::applicationName(), reason);
0113     } else {
0114         // Fallback to the fd.o Inhibit interface
0115         reply = globalPowerManager->inhibitIface.Inhibit(QCoreApplication::applicationName(), reason);
0116     }
0117 
0118     if (reply.isValid()) {
0119         return reply;
0120     } else {
0121         return -1;
0122     }
0123 }
0124 
0125 bool Solid::PowerManagement::stopSuppressingSleep(int cookie)
0126 {
0127     if (globalPowerManager->policyAgentIface.isValid()) {
0128         return globalPowerManager->policyAgentIface.ReleaseInhibition(cookie).isValid();
0129     } else {
0130         // Fallback to the fd.o Inhibit interface
0131         return globalPowerManager->inhibitIface.UnInhibit(cookie).isValid();
0132     }
0133 }
0134 
0135 int Solid::PowerManagement::beginSuppressingScreenPowerManagement(const QString &reason)
0136 {
0137     if (globalPowerManager->policyAgentIface.isValid()) {
0138         QDBusReply<uint> reply = globalPowerManager->policyAgentIface.AddInhibition(
0139                                      (uint)PowerManagementPrivate::ChangeScreenSettings,
0140                                      QCoreApplication::applicationName(), reason);
0141 
0142         if (reply.isValid()) {
0143             QDBusMessage message = QDBusMessage::createMethodCall("org.freedesktop.ScreenSaver", "/ScreenSaver",
0144                                    "org.freedesktop.ScreenSaver", "Inhibit");
0145             message << QCoreApplication::applicationName();
0146             message << reason;
0147 
0148             QDBusPendingReply<uint> ssReply = QDBusConnection::sessionBus().asyncCall(message);
0149             ssReply.waitForFinished();
0150             if (ssReply.isValid()) {
0151                 globalPowerManager->screensaverCookiesForPowerDevilCookies.insert(reply, ssReply.value());
0152             }
0153 
0154             return reply;
0155         } else {
0156             return -1;
0157         }
0158     } else {
0159         // No way to fallback on something, hence return failure
0160         return -1;
0161     }
0162 }
0163 
0164 bool Solid::PowerManagement::stopSuppressingScreenPowerManagement(int cookie)
0165 {
0166     if (globalPowerManager->policyAgentIface.isValid()) {
0167         bool result = globalPowerManager->policyAgentIface.ReleaseInhibition(cookie).isValid();
0168 
0169         if (globalPowerManager->screensaverCookiesForPowerDevilCookies.contains(cookie)) {
0170             QDBusMessage message = QDBusMessage::createMethodCall("org.freedesktop.ScreenSaver", "/ScreenSaver",
0171                                    "org.freedesktop.ScreenSaver", "UnInhibit");
0172             message << globalPowerManager->screensaverCookiesForPowerDevilCookies.take(cookie);
0173             QDBusConnection::sessionBus().asyncCall(message);
0174         }
0175 
0176         return result;
0177     } else {
0178         // No way to fallback on something, hence return failure
0179         return false;
0180     }
0181 }
0182 
0183 Solid::PowerManagement::Notifier *Solid::PowerManagement::notifier()
0184 {
0185     return globalPowerManager;
0186 }
0187 
0188 void Solid::PowerManagementPrivate::slotCanSuspendChanged(bool newState)
0189 {
0190     if (supportedSleepStates.contains(Solid::PowerManagement::SuspendState) == newState) {
0191         return;
0192     }
0193 
0194     if (newState) {
0195         supportedSleepStates += Solid::PowerManagement::SuspendState;
0196     } else {
0197         supportedSleepStates -= Solid::PowerManagement::SuspendState;
0198     }
0199 }
0200 
0201 void Solid::PowerManagementPrivate::slotCanHibernateChanged(bool newState)
0202 {
0203     if (supportedSleepStates.contains(Solid::PowerManagement::HibernateState) == newState) {
0204         return;
0205     }
0206 
0207     if (newState) {
0208         supportedSleepStates += Solid::PowerManagement::HibernateState;
0209     } else {
0210         supportedSleepStates -= Solid::PowerManagement::HibernateState;
0211     }
0212 }
0213 
0214 void Solid::PowerManagementPrivate::slotCanHybridSuspendChanged(bool newState)
0215 {
0216     if (supportedSleepStates.contains(Solid::PowerManagement::HybridSuspendState) == newState) {
0217         return;
0218     }
0219 
0220     if (newState) {
0221         supportedSleepStates += Solid::PowerManagement::HybridSuspendState;
0222     } else {
0223         supportedSleepStates -= Solid::PowerManagement::HybridSuspendState;
0224     }
0225 }
0226 
0227 void Solid::PowerManagementPrivate::slotPowerSaveStatusChanged(bool newState)
0228 {
0229     if (powerSaveStatus == newState) {
0230         return;
0231     }
0232 
0233     powerSaveStatus = newState;
0234     emit appShouldConserveResourcesChanged(powerSaveStatus);
0235 }
0236 
0237 void Solid::PowerManagementPrivate::slotServiceRegistered(const QString &serviceName)
0238 {
0239     if (serviceName == QLatin1String("org.freedesktop.PowerManagement")) {
0240         // Load all the properties
0241         QDBusPendingReply<bool> suspendReply = managerIface.CanSuspend();
0242         suspendReply.waitForFinished();
0243         slotCanSuspendChanged(suspendReply.isValid() ? suspendReply.value() : false);
0244 
0245         QDBusPendingReply<bool> hibernateReply = managerIface.CanHibernate();
0246         hibernateReply.waitForFinished();
0247         slotCanHibernateChanged(hibernateReply.isValid() ? hibernateReply.value() : false);
0248 
0249         QDBusPendingReply<bool> hybridSuspendReply = managerIface.CanHybridSuspend();
0250         hybridSuspendReply.waitForFinished();
0251         slotCanHybridSuspendChanged(hybridSuspendReply.isValid() ? hybridSuspendReply.value() : false);
0252 
0253         QDBusPendingReply<bool> saveStatusReply = managerIface.GetPowerSaveStatus();
0254         saveStatusReply.waitForFinished();
0255         slotPowerSaveStatusChanged(saveStatusReply.isValid() ? saveStatusReply.value() : false);
0256     } else {
0257         // Is the resume signal available?
0258         QDBusMessage call = QDBusMessage::createMethodCall("org.kde.Solid.PowerManagement",
0259                             "/org/kde/Solid/PowerManagement",
0260                             "org.kde.Solid.PowerManagement",
0261                             "backendCapabilities");
0262         QDBusPendingReply< uint > reply = QDBusConnection::sessionBus().asyncCall(call);
0263         reply.waitForFinished();
0264 
0265         if (reply.isValid() && reply.value() > 0) {
0266             // Connect the signal
0267             QDBusConnection::sessionBus().connect(QLatin1String("org.kde.Solid.PowerManagement"),
0268                                                   QLatin1String("/org/kde/Solid/PowerManagement/Actions/SuspendSession"),
0269                                                   QLatin1String("org.kde.Solid.PowerManagement.Actions.SuspendSession"),
0270                                                   QLatin1String("resumingFromSuspend"),
0271                                                   this,
0272                                                   SIGNAL(resumingFromSuspend()));
0273         }
0274     }
0275 }
0276 
0277 void Solid::PowerManagementPrivate::slotServiceUnregistered(const QString &serviceName)
0278 {
0279     if (serviceName == QLatin1String("org.freedesktop.PowerManagement")) {
0280         // Reset the values
0281         slotCanSuspendChanged(false);
0282         slotCanHibernateChanged(false);
0283         slotCanHybridSuspendChanged(false);
0284         slotPowerSaveStatusChanged(false);
0285     } else {
0286         // Disconnect the signal
0287         QDBusConnection::sessionBus().disconnect(QLatin1String("org.kde.Solid.PowerManagement"),
0288                 QLatin1String("/org/kde/Solid/PowerManagement"),
0289                 QLatin1String("org.kde.Solid.PowerManagement"),
0290                 QLatin1String("resumingFromSuspend"),
0291                 this,
0292                 SIGNAL(resumingFromSuspend()));
0293     }
0294 }
0295 
0296 #include "moc_powermanagement.cpp"
0297 #include "moc_powermanagement_p.cpp"