File indexing completed on 2024-04-28 16:55:15
0001 /******************************************************************** 0002 Copyright 2016 Martin Gräßlin <mgraesslin@kde.org> 0003 0004 This library is free software; you can redistribute it and/or 0005 modify it under the terms of the GNU Lesser General Public 0006 License as published by the Free Software Foundation; either 0007 version 2.1 of the License, or (at your option) version 3, or any 0008 later version accepted by the membership of KDE e.V. (or its 0009 successor approved by the membership of KDE e.V.), which shall 0010 act as a proxy defined in Section 6 of version 3 of the license. 0011 0012 This library is distributed in the hope that it will be useful, 0013 but WITHOUT ANY WARRANTY; without even the implied warranty of 0014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0015 Lesser General Public License for more details. 0016 0017 You should have received a copy of the GNU Lesser General Public 0018 License along with this library. If not, see <http://www.gnu.org/licenses/>. 0019 *********************************************************************/ 0020 0021 #include "powerdevilpowermanagement.h" 0022 #include "powerdevil_debug.h" 0023 0024 #include <QDBusConnection> 0025 #include <QDBusConnectionInterface> 0026 #include <QDBusServiceWatcher> 0027 0028 namespace PowerDevil { 0029 0030 static const QString s_fdoPowerService = QStringLiteral("org.freedesktop.PowerManagement"); 0031 static const QString s_fdoPowerPath = QStringLiteral("/org/freedesktop/PowerManagement"); 0032 0033 class PowerManagementInstance : public PowerManagement 0034 { 0035 Q_OBJECT 0036 public: 0037 explicit PowerManagementInstance() : PowerManagement() {} 0038 }; 0039 Q_GLOBAL_STATIC(PowerManagementInstance, s_instance) 0040 0041 class PowerManagement::Private 0042 { 0043 public: 0044 Private(PowerManagement *q); 0045 void update(); 0046 void setCanSuspend(bool set); 0047 void setCanHibernate(bool set); 0048 void setCanHybridSuspend(bool set); 0049 void setCanSuspendThenHibernate(bool set); 0050 0051 bool serviceRegistered; 0052 bool canSuspend; 0053 bool canSuspendThenHibernate; 0054 bool canHibernate; 0055 bool canHybridSuspend; 0056 QScopedPointer<QDBusServiceWatcher> fdoPowerServiceWatcher; 0057 0058 private: 0059 void updateProperty(const QString &dbusName, void (Private::*setter)(bool)); 0060 PowerManagement *const q; 0061 }; 0062 0063 PowerManagement::Private::Private(PowerManagement *qq) 0064 : serviceRegistered(false) 0065 , canSuspend(false) 0066 , canSuspendThenHibernate(false) 0067 , canHibernate(false) 0068 , canHybridSuspend(false) 0069 , fdoPowerServiceWatcher(new QDBusServiceWatcher(s_fdoPowerService, QDBusConnection::sessionBus(), QDBusServiceWatcher::WatchForUnregistration | QDBusServiceWatcher::WatchForRegistration)) 0070 , q(qq) 0071 { 0072 } 0073 0074 void PowerManagement::Private::update() 0075 { 0076 serviceRegistered = true; 0077 updateProperty(QStringLiteral("CanSuspend"), &Private::setCanSuspend); 0078 updateProperty(QStringLiteral("CanSuspendThenHibernate"), &Private::setCanSuspendThenHibernate); 0079 updateProperty(QStringLiteral("CanHibernate"), &Private::setCanHibernate); 0080 updateProperty(QStringLiteral("CanHybridSuspend"), &Private::setCanHybridSuspend); 0081 } 0082 0083 void PowerManagement::Private::updateProperty(const QString &dbusName, void (Private::*setter)(bool)) 0084 { 0085 QDBusMessage message = QDBusMessage::createMethodCall(s_fdoPowerService, 0086 s_fdoPowerPath, 0087 s_fdoPowerService, 0088 dbusName); 0089 QDBusReply<bool> reply = QDBusConnection::sessionBus().call(message); 0090 if (!reply.isValid()) { 0091 return; 0092 } 0093 0094 ((this)->*setter)(reply.value()); 0095 } 0096 0097 void PowerManagement::Private::setCanHibernate(bool set) 0098 { 0099 if (canHibernate == set) { 0100 return; 0101 } 0102 canHibernate = set; 0103 Q_EMIT q->canHibernateChanged(); 0104 } 0105 0106 void PowerManagement::Private::setCanSuspend(bool set) 0107 { 0108 if (canSuspend == set) { 0109 return; 0110 } 0111 canSuspend = set; 0112 Q_EMIT q->canSuspendChanged(); 0113 } 0114 0115 void PowerManagement::Private::setCanSuspendThenHibernate(bool set) 0116 { 0117 if (canSuspendThenHibernate == set) { 0118 return; 0119 } 0120 canSuspendThenHibernate = set; 0121 Q_EMIT q->canSuspendThenHibernateChanged(); 0122 } 0123 0124 void PowerManagement::Private::setCanHybridSuspend(bool set) 0125 { 0126 if (canHybridSuspend == set) { 0127 return; 0128 } 0129 canHybridSuspend = set; 0130 Q_EMIT q->canHybridSuspendChanged(); 0131 } 0132 0133 PowerManagement *PowerManagement::instance() 0134 { 0135 return s_instance; 0136 } 0137 0138 PowerManagement::PowerManagement() 0139 : QObject() 0140 , d(new Private(this)) 0141 { 0142 connect(d->fdoPowerServiceWatcher.data(), &QDBusServiceWatcher::serviceRegistered, this, [this] { d->update(); }); 0143 connect(d->fdoPowerServiceWatcher.data(), &QDBusServiceWatcher::serviceUnregistered, this, 0144 [this] { 0145 d->serviceRegistered = false; 0146 d->setCanSuspend(false); 0147 d->setCanHibernate(false); 0148 d->setCanHybridSuspend(false); 0149 d->setCanSuspendThenHibernate(false); 0150 } 0151 ); 0152 0153 // check whether the service is registered 0154 QDBusMessage message = QDBusMessage::createMethodCall(QStringLiteral("org.freedesktop.DBus"), 0155 QStringLiteral("/"), 0156 QStringLiteral("org.freedesktop.DBus"), 0157 QStringLiteral("ListNames")); 0158 QDBusReply<QStringList> reply = QDBusConnection::sessionBus().call(message); 0159 if (!reply.isValid()) { 0160 return; 0161 } 0162 if (reply.value().contains(s_fdoPowerService)) { 0163 d->update(); 0164 } 0165 } 0166 0167 PowerManagement::~PowerManagement() 0168 { 0169 } 0170 0171 void PowerManagement::suspend() 0172 { 0173 if (!d->serviceRegistered) { 0174 return; 0175 } 0176 if (!d->canSuspend) { 0177 return; 0178 } 0179 QDBusMessage message = QDBusMessage::createMethodCall(s_fdoPowerService, 0180 s_fdoPowerPath, 0181 s_fdoPowerService, 0182 QStringLiteral("Suspend")); 0183 QDBusConnection::sessionBus().asyncCall(message); 0184 } 0185 0186 void PowerManagement::hibernate() 0187 { 0188 if (!d->serviceRegistered) { 0189 return; 0190 } 0191 if (!d->canHibernate) { 0192 return; 0193 } 0194 QDBusMessage message = QDBusMessage::createMethodCall(s_fdoPowerService, 0195 s_fdoPowerPath, 0196 s_fdoPowerService, 0197 QStringLiteral("Hibernate")); 0198 QDBusConnection::sessionBus().asyncCall(message); 0199 } 0200 0201 void PowerManagement::hybridSuspend() 0202 { 0203 // FIXME: Whether there is a support of this mode? 0204 } 0205 0206 void PowerManagement::suspendThenHibernate() 0207 { 0208 if (!d->serviceRegistered) { 0209 return; 0210 } 0211 if (!d->canSuspendThenHibernate) { 0212 return; 0213 } 0214 QDBusMessage message = QDBusMessage::createMethodCall(s_fdoPowerService, 0215 s_fdoPowerPath, 0216 s_fdoPowerService, 0217 QStringLiteral("SuspendThenHibernate")); 0218 QDBusConnection::sessionBus().asyncCall(message); 0219 } 0220 0221 bool PowerManagement::isVirtualMachine() 0222 { 0223 if (!QDBusConnection::systemBus().interface()->isServiceRegistered(QStringLiteral("org.freedesktop.systemd1"))) { 0224 // can't check, fall back to assuming false 0225 return false; 0226 } 0227 QDBusMessage message = QDBusMessage::createMethodCall(QStringLiteral("org.freedesktop.systemd1"), 0228 QStringLiteral("/org/freedesktop/systemd1"), 0229 QStringLiteral("org.freedesktop.DBus.Properties"), 0230 QStringLiteral("Get")); 0231 message.setArguments({QStringLiteral("org.freedesktop.systemd1.Manager"), QStringLiteral("Virtualization")}); 0232 QDBusReply<QDBusVariant> reply = QDBusConnection::systemBus().call(message); 0233 if (!reply.isValid() || reply.value().variant().isNull() || reply.value().variant().toString().isNull()) { 0234 qCWarning(POWERDEVIL) << "Failed to get property Virtualization from systemd1 DBus service:" << reply.error().message(); 0235 return false; 0236 } 0237 /* on bare-metal hardware this is the empty string, otherwise an identifier such as "kvm", "vmware", etc. */ 0238 return !reply.value().variant().toString().isEmpty(); 0239 } 0240 0241 bool PowerManagement::canSuspend() const 0242 { 0243 return d->canSuspend; 0244 } 0245 0246 bool PowerManagement::canHibernate() const 0247 { 0248 return d->canHibernate; 0249 } 0250 0251 bool PowerManagement::canHybridSuspend() const 0252 { 0253 return d->canHybridSuspend; 0254 } 0255 0256 bool PowerManagement::canSuspendThenHibernate() const 0257 { 0258 return d->canSuspendThenHibernate; 0259 } 0260 0261 } // namespace PowerDevil 0262 0263 #include "powerdevilpowermanagement.moc"