File indexing completed on 2024-04-28 05:36:16
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 0007 #include "powerdevilpowermanagement.h" 0008 #include "powerdevil_debug.h" 0009 0010 #include <QDBusConnection> 0011 #include <QDBusConnectionInterface> 0012 #include <QDBusServiceWatcher> 0013 0014 namespace PowerDevil 0015 { 0016 static const QString s_fdoPowerService = QStringLiteral("org.freedesktop.PowerManagement"); 0017 static const QString s_fdoPowerPath = QStringLiteral("/org/freedesktop/PowerManagement"); 0018 0019 class PowerManagementInstance : public PowerManagement 0020 { 0021 Q_OBJECT 0022 public: 0023 explicit PowerManagementInstance() 0024 : PowerManagement() 0025 { 0026 } 0027 }; 0028 Q_GLOBAL_STATIC(PowerManagementInstance, s_instance) 0029 0030 class PowerManagement::Private 0031 { 0032 public: 0033 Private(PowerManagement *q); 0034 void update(); 0035 void setCanSuspend(bool set); 0036 void setCanHibernate(bool set); 0037 void setCanHybridSuspend(bool set); 0038 void setCanSuspendThenHibernate(bool set); 0039 0040 bool serviceRegistered; 0041 bool canSuspend; 0042 bool canSuspendThenHibernate; 0043 bool canHibernate; 0044 bool canHybridSuspend; 0045 QScopedPointer<QDBusServiceWatcher> fdoPowerServiceWatcher; 0046 0047 private: 0048 void updateProperty(const QString &dbusName, void (Private::*setter)(bool)); 0049 PowerManagement *const q; 0050 }; 0051 0052 PowerManagement::Private::Private(PowerManagement *qq) 0053 : serviceRegistered(false) 0054 , canSuspend(false) 0055 , canSuspendThenHibernate(false) 0056 , canHibernate(false) 0057 , canHybridSuspend(false) 0058 , fdoPowerServiceWatcher(new QDBusServiceWatcher(s_fdoPowerService, 0059 QDBusConnection::sessionBus(), 0060 QDBusServiceWatcher::WatchForUnregistration | QDBusServiceWatcher::WatchForRegistration)) 0061 , q(qq) 0062 { 0063 } 0064 0065 void PowerManagement::Private::update() 0066 { 0067 serviceRegistered = true; 0068 updateProperty(QStringLiteral("CanSuspend"), &Private::setCanSuspend); 0069 updateProperty(QStringLiteral("CanSuspendThenHibernate"), &Private::setCanSuspendThenHibernate); 0070 updateProperty(QStringLiteral("CanHibernate"), &Private::setCanHibernate); 0071 updateProperty(QStringLiteral("CanHybridSuspend"), &Private::setCanHybridSuspend); 0072 } 0073 0074 void PowerManagement::Private::updateProperty(const QString &dbusName, void (Private::*setter)(bool)) 0075 { 0076 QDBusMessage message = QDBusMessage::createMethodCall(s_fdoPowerService, s_fdoPowerPath, s_fdoPowerService, dbusName); 0077 QDBusReply<bool> reply = QDBusConnection::sessionBus().call(message); 0078 if (!reply.isValid()) { 0079 return; 0080 } 0081 0082 ((this)->*setter)(reply.value()); 0083 } 0084 0085 void PowerManagement::Private::setCanHibernate(bool set) 0086 { 0087 if (canHibernate == set) { 0088 return; 0089 } 0090 canHibernate = set; 0091 Q_EMIT q->canHibernateChanged(); 0092 } 0093 0094 void PowerManagement::Private::setCanSuspend(bool set) 0095 { 0096 if (canSuspend == set) { 0097 return; 0098 } 0099 canSuspend = set; 0100 Q_EMIT q->canSuspendChanged(); 0101 } 0102 0103 void PowerManagement::Private::setCanSuspendThenHibernate(bool set) 0104 { 0105 if (canSuspendThenHibernate == set) { 0106 return; 0107 } 0108 canSuspendThenHibernate = set; 0109 Q_EMIT q->canSuspendThenHibernateChanged(); 0110 } 0111 0112 void PowerManagement::Private::setCanHybridSuspend(bool set) 0113 { 0114 if (canHybridSuspend == set) { 0115 return; 0116 } 0117 canHybridSuspend = set; 0118 Q_EMIT q->canHybridSuspendChanged(); 0119 } 0120 0121 PowerManagement *PowerManagement::instance() 0122 { 0123 return s_instance; 0124 } 0125 0126 PowerManagement::PowerManagement() 0127 : QObject() 0128 , d(new Private(this)) 0129 { 0130 connect(d->fdoPowerServiceWatcher.data(), &QDBusServiceWatcher::serviceRegistered, this, [this] { 0131 d->update(); 0132 }); 0133 connect(d->fdoPowerServiceWatcher.data(), &QDBusServiceWatcher::serviceUnregistered, this, [this] { 0134 d->serviceRegistered = false; 0135 d->setCanSuspend(false); 0136 d->setCanHibernate(false); 0137 d->setCanHybridSuspend(false); 0138 d->setCanSuspendThenHibernate(false); 0139 }); 0140 0141 // check whether the service is registered 0142 QDBusMessage message = QDBusMessage::createMethodCall(QStringLiteral("org.freedesktop.DBus"), 0143 QStringLiteral("/"), 0144 QStringLiteral("org.freedesktop.DBus"), 0145 QStringLiteral("ListNames")); 0146 QDBusReply<QStringList> reply = QDBusConnection::sessionBus().call(message); 0147 if (!reply.isValid()) { 0148 return; 0149 } 0150 if (reply.value().contains(s_fdoPowerService)) { 0151 d->update(); 0152 } 0153 } 0154 0155 PowerManagement::~PowerManagement() 0156 { 0157 } 0158 0159 void PowerManagement::suspend() 0160 { 0161 if (!d->serviceRegistered) { 0162 return; 0163 } 0164 if (!d->canSuspend) { 0165 return; 0166 } 0167 QDBusMessage message = QDBusMessage::createMethodCall(s_fdoPowerService, s_fdoPowerPath, s_fdoPowerService, QStringLiteral("Suspend")); 0168 QDBusConnection::sessionBus().asyncCall(message); 0169 } 0170 0171 void PowerManagement::hibernate() 0172 { 0173 if (!d->serviceRegistered) { 0174 return; 0175 } 0176 if (!d->canHibernate) { 0177 return; 0178 } 0179 QDBusMessage message = QDBusMessage::createMethodCall(s_fdoPowerService, s_fdoPowerPath, s_fdoPowerService, QStringLiteral("Hibernate")); 0180 QDBusConnection::sessionBus().asyncCall(message); 0181 } 0182 0183 void PowerManagement::hybridSuspend() 0184 { 0185 // FIXME: Whether there is a support of this mode? 0186 } 0187 0188 void PowerManagement::suspendThenHibernate() 0189 { 0190 if (!d->serviceRegistered) { 0191 return; 0192 } 0193 if (!d->canSuspendThenHibernate) { 0194 return; 0195 } 0196 QDBusMessage message = QDBusMessage::createMethodCall(s_fdoPowerService, s_fdoPowerPath, s_fdoPowerService, QStringLiteral("SuspendThenHibernate")); 0197 QDBusConnection::sessionBus().asyncCall(message); 0198 } 0199 0200 bool PowerManagement::isVirtualMachine() 0201 { 0202 if (!QDBusConnection::systemBus().interface()->isServiceRegistered(QStringLiteral("org.freedesktop.systemd1"))) { 0203 // can't check, fall back to assuming false 0204 return false; 0205 } 0206 QDBusMessage message = QDBusMessage::createMethodCall(QStringLiteral("org.freedesktop.systemd1"), 0207 QStringLiteral("/org/freedesktop/systemd1"), 0208 QStringLiteral("org.freedesktop.DBus.Properties"), 0209 QStringLiteral("Get")); 0210 message.setArguments({QStringLiteral("org.freedesktop.systemd1.Manager"), QStringLiteral("Virtualization")}); 0211 QDBusReply<QDBusVariant> reply = QDBusConnection::systemBus().call(message); 0212 if (!reply.isValid() || reply.value().variant().isNull() || reply.value().variant().toString().isNull()) { 0213 qCWarning(POWERDEVIL) << "Failed to get property Virtualization from systemd1 DBus service:" << reply.error().message(); 0214 return false; 0215 } 0216 // on bare-metal hardware this is the empty string, otherwise an identifier such as "kvm", "vmware", etc. 0217 return !reply.value().variant().toString().isEmpty(); 0218 } 0219 0220 bool PowerManagement::canSuspend() const 0221 { 0222 return d->canSuspend; 0223 } 0224 0225 bool PowerManagement::canHibernate() const 0226 { 0227 return d->canHibernate; 0228 } 0229 0230 bool PowerManagement::canHybridSuspend() const 0231 { 0232 return d->canHybridSuspend; 0233 } 0234 0235 bool PowerManagement::canSuspendThenHibernate() const 0236 { 0237 return d->canSuspendThenHibernate; 0238 } 0239 0240 } // namespace PowerDevil 0241 0242 #include "powerdevilpowermanagement.moc" 0243 0244 #include "moc_powerdevilpowermanagement.cpp"