File indexing completed on 2024-04-14 05:21:18

0001 /*
0002 SPDX-FileCopyrightText: 2016 Martin Gräßlin <mgraesslin@kde.org>
0003 
0004 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005 */
0006 #include "powermanagement.h"
0007 
0008 #include <QDBusConnection>
0009 #include <QDBusConnectionInterface>
0010 #include <QDBusServiceWatcher>
0011 
0012 static const QString s_fdoPowerService = QStringLiteral("org.freedesktop.PowerManagement");
0013 static const QString s_fdoPowerPath = QStringLiteral("/org/freedesktop/PowerManagement");
0014 
0015 class PowerManagementInstance : public PowerManagement
0016 {
0017     Q_OBJECT
0018 public:
0019     explicit PowerManagementInstance()
0020         : PowerManagement()
0021     {
0022     }
0023 };
0024 Q_GLOBAL_STATIC(PowerManagementInstance, s_instance)
0025 
0026 class PowerManagement::Private
0027 {
0028 public:
0029     Private(PowerManagement *q);
0030     void update();
0031     void setCanSuspend(bool set);
0032     void setCanHibernate(bool set);
0033 
0034     bool serviceRegistered;
0035     bool canSuspend;
0036     bool canHibernate;
0037     QScopedPointer<QDBusServiceWatcher> fdoPowerServiceWatcher;
0038 
0039 private:
0040     void updateProperty(const QString &dbusName, void (Private::*setter)(bool));
0041     PowerManagement *q;
0042 };
0043 
0044 PowerManagement::Private::Private(PowerManagement *q)
0045     : serviceRegistered(false)
0046     , canSuspend(false)
0047     , canHibernate(false)
0048     , fdoPowerServiceWatcher(new QDBusServiceWatcher(s_fdoPowerService,
0049                                                      QDBusConnection::sessionBus(),
0050                                                      QDBusServiceWatcher::WatchForUnregistration | QDBusServiceWatcher::WatchForRegistration))
0051     , q(q)
0052 {
0053 }
0054 
0055 void PowerManagement::Private::update()
0056 {
0057     serviceRegistered = true;
0058     updateProperty(QStringLiteral("CanSuspend"), &Private::setCanSuspend);
0059     updateProperty(QStringLiteral("CanHibernate"), &Private::setCanHibernate);
0060 }
0061 
0062 void PowerManagement::Private::updateProperty(const QString &dbusName, void (Private::*setter)(bool))
0063 {
0064     QDBusMessage message = QDBusMessage::createMethodCall(s_fdoPowerService, s_fdoPowerPath, s_fdoPowerService, dbusName);
0065     QDBusPendingReply<bool> reply = QDBusConnection::sessionBus().asyncCall(message);
0066     QDBusPendingCallWatcher *callWatcher = new QDBusPendingCallWatcher(reply, q);
0067     QObject::connect(callWatcher, &QDBusPendingCallWatcher::finished, q, [this, setter](QDBusPendingCallWatcher *self) {
0068         QDBusPendingReply<bool> reply = *self;
0069         self->deleteLater();
0070         if (!reply.isValid()) {
0071             return;
0072         }
0073         ((this)->*setter)(reply.value());
0074     });
0075 }
0076 
0077 void PowerManagement::Private::setCanHibernate(bool set)
0078 {
0079     if (canHibernate == set) {
0080         return;
0081     }
0082     canHibernate = set;
0083     Q_EMIT q->canHibernateChanged();
0084 }
0085 
0086 void PowerManagement::Private::setCanSuspend(bool set)
0087 {
0088     if (canSuspend == set) {
0089         return;
0090     }
0091     canSuspend = set;
0092     Q_EMIT q->canSuspendChanged();
0093 }
0094 
0095 PowerManagement *PowerManagement::instance()
0096 {
0097     return s_instance;
0098 }
0099 
0100 PowerManagement::PowerManagement()
0101     : QObject()
0102     , d(new Private(this))
0103 {
0104     connect(d->fdoPowerServiceWatcher.data(), &QDBusServiceWatcher::serviceRegistered, this, [this] {
0105         d->update();
0106     });
0107     connect(d->fdoPowerServiceWatcher.data(), &QDBusServiceWatcher::serviceUnregistered, this, [this] {
0108         d->serviceRegistered = false;
0109         d->setCanSuspend(false);
0110         d->setCanHibernate(false);
0111     });
0112 
0113     // check whether the service is registered
0114     QDBusMessage message = QDBusMessage::createMethodCall(QStringLiteral("org.freedesktop.DBus"),
0115                                                           QStringLiteral("/"),
0116                                                           QStringLiteral("org.freedesktop.DBus"),
0117                                                           QStringLiteral("ListNames"));
0118     QDBusPendingReply<QStringList> async = QDBusConnection::sessionBus().asyncCall(message);
0119     QDBusPendingCallWatcher *callWatcher = new QDBusPendingCallWatcher(async, this);
0120     connect(callWatcher, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher *self) {
0121         QDBusPendingReply<QStringList> reply = *self;
0122         self->deleteLater();
0123         if (!reply.isValid()) {
0124             return;
0125         }
0126         if (reply.value().contains(s_fdoPowerService)) {
0127             d->update();
0128         }
0129     });
0130 }
0131 
0132 PowerManagement::~PowerManagement()
0133 {
0134 }
0135 
0136 void PowerManagement::suspend()
0137 {
0138     if (!d->serviceRegistered) {
0139         return;
0140     }
0141     if (!d->canSuspend) {
0142         return;
0143     }
0144     QDBusMessage message = QDBusMessage::createMethodCall(s_fdoPowerService, s_fdoPowerPath, s_fdoPowerService, QStringLiteral("Suspend"));
0145     QDBusConnection::sessionBus().asyncCall(message);
0146 }
0147 
0148 void PowerManagement::hibernate()
0149 {
0150     if (!d->serviceRegistered) {
0151         return;
0152     }
0153     if (!d->canHibernate) {
0154         return;
0155     }
0156     QDBusMessage message = QDBusMessage::createMethodCall(s_fdoPowerService, s_fdoPowerPath, s_fdoPowerService, QStringLiteral("Hibernate"));
0157     QDBusConnection::sessionBus().asyncCall(message);
0158 }
0159 
0160 bool PowerManagement::canSuspend() const
0161 {
0162     return d->canSuspend;
0163 }
0164 
0165 bool PowerManagement::canHibernate() const
0166 {
0167     return d->canHibernate;
0168 }
0169 
0170 #include "powermanagement.moc"
0171 
0172 #include "moc_powermanagement.cpp"