1 /***************************************************************************
2 * Copyright (c) 2013 Abdurrahman AVCI <abdurrahmanavci@gmail.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 ***************************************************************************/
19 
20 #include "PowerManager.h"
21 
22 #include "Configuration.h"
23 #include "DaemonApp.h"
24 #include "Messages.h"
25 
26 #include <QDBusConnectionInterface>
27 #include <QDBusInterface>
28 #include <QDBusReply>
29 #include <QProcess>
30 
31 namespace SDDM {
32     /************************************************/
33     /* POWER MANAGER BACKEND                        */
34     /************************************************/
35     class PowerManagerBackend {
36     public:
PowerManagerBackend()37         PowerManagerBackend() {
38         }
39 
~PowerManagerBackend()40         virtual ~PowerManagerBackend() {
41         }
42 
43         virtual Capabilities capabilities() const = 0;
44 
45         virtual void powerOff() const = 0;
46         virtual void reboot() const = 0;
47         virtual void suspend() const = 0;
48         virtual void hibernate() const = 0;
49         virtual void hybridSleep() const = 0;
50     };
51 
52     /**********************************************/
53     /* UPOWER BACKEND                             */
54     /**********************************************/
55 
56 const QString UPOWER_PATH = QStringLiteral("/org/freedesktop/UPower");
57 const QString UPOWER_SERVICE = QStringLiteral("org.freedesktop.UPower");
58 const QString UPOWER_OBJECT = QStringLiteral("org.freedesktop.UPower");
59 
60     class UPowerBackend : public PowerManagerBackend {
61     public:
UPowerBackend(const QString & service,const QString & path,const QString & interface)62         UPowerBackend(const QString & service, const QString & path, const QString & interface) {
63             m_interface = new QDBusInterface(service, path, interface, QDBusConnection::systemBus());
64         }
65 
~UPowerBackend()66         ~UPowerBackend() {
67             delete m_interface;
68         }
69 
capabilities() const70         Capabilities capabilities() const {
71             Capabilities caps = Capability::PowerOff | Capability::Reboot;
72 
73             QDBusReply<bool> reply;
74 
75             // suspend
76             reply = m_interface->call(QStringLiteral("SuspendAllowed"));
77             if (reply.isValid() && reply.value())
78                 caps |= Capability::Suspend;
79 
80             // hibernate
81             reply = m_interface->call(QStringLiteral("HibernateAllowed"));
82             if (reply.isValid() && reply.value())
83                 caps |= Capability::Hibernate;
84 
85             // return capabilities
86             return caps;
87         }
88 
powerOff() const89         void powerOff() const {
90             QProcess::execute(mainConfig.HaltCommand.get());
91         }
92 
reboot() const93         void reboot() const {
94             QProcess::execute(mainConfig.RebootCommand.get());
95         }
96 
suspend() const97         void suspend() const {
98             m_interface->call(QStringLiteral("Suspend"));
99         }
100 
hibernate() const101         void hibernate() const {
102             m_interface->call(QStringLiteral("Hibernate"));
103         }
104 
hybridSleep() const105         void hybridSleep() const {
106         }
107 
108     private:
109         QDBusInterface *m_interface { nullptr };
110     };
111 
112     /**********************************************/
113     /* LOGIN1 && ConsoleKit2 BACKEND              */
114     /**********************************************/
115 
116 const QString LOGIN1_SERVICE = QStringLiteral("org.freedesktop.login1");
117 const QString LOGIN1_PATH = QStringLiteral("/org/freedesktop/login1");
118 const QString LOGIN1_OBJECT = QStringLiteral("org.freedesktop.login1.Manager");
119 
120 const QString CK2_SERVICE = QStringLiteral("org.freedesktop.ConsoleKit");
121 const QString CK2_PATH = QStringLiteral("/org/freedesktop/ConsoleKit/Manager");
122 const QString CK2_OBJECT = QStringLiteral("org.freedesktop.ConsoleKit.Manager");
123 
124     class SeatManagerBackend : public PowerManagerBackend {
125     public:
SeatManagerBackend(const QString & service,const QString & path,const QString & interface)126         SeatManagerBackend(const QString & service, const QString & path, const QString & interface) {
127             m_interface = new QDBusInterface(service, path, interface, QDBusConnection::systemBus());
128         }
129 
~SeatManagerBackend()130         ~SeatManagerBackend() {
131             delete m_interface;
132         }
133 
capabilities() const134         Capabilities capabilities() const {
135             Capabilities caps = Capability::None;
136 
137             QDBusReply<QString> reply;
138 
139             // power off
140             reply = m_interface->call(QStringLiteral("CanPowerOff"));
141             if (reply.isValid() && (reply.value() == QLatin1String("yes")))
142                 caps |= Capability::PowerOff;
143 
144             // reboot
145             reply = m_interface->call(QStringLiteral("CanReboot"));
146             if (reply.isValid() && (reply.value() == QLatin1String("yes")))
147                 caps |= Capability::Reboot;
148 
149             // suspend
150             reply = m_interface->call(QStringLiteral("CanSuspend"));
151             if (reply.isValid() && (reply.value() == QLatin1String("yes")))
152                 caps |= Capability::Suspend;
153 
154             // hibernate
155             reply = m_interface->call(QStringLiteral("CanHibernate"));
156             if (reply.isValid() && (reply.value() == QLatin1String("yes")))
157                 caps |= Capability::Hibernate;
158 
159             // hybrid sleep
160             reply = m_interface->call(QStringLiteral("CanHybridSleep"));
161             if (reply.isValid() && (reply.value() == QLatin1String("yes")))
162                 caps |= Capability::HybridSleep;
163 
164             // return capabilities
165             return caps;
166         }
167 
powerOff() const168         void powerOff() const {
169             m_interface->call(QStringLiteral("PowerOff"), true);
170         }
171 
reboot() const172         void reboot() const {
173             if (!daemonApp->testing())
174                 m_interface->call(QStringLiteral("Reboot"), true);
175         }
176 
suspend() const177         void suspend() const {
178             m_interface->call(QStringLiteral("Suspend"), true);
179         }
180 
hibernate() const181         void hibernate() const {
182             m_interface->call(QStringLiteral("Hibernate"), true);
183         }
184 
hybridSleep() const185         void hybridSleep() const {
186             m_interface->call(QStringLiteral("HybridSleep"), true);
187         }
188 
189     private:
190         QDBusInterface *m_interface { nullptr };
191     };
192 
193     /**********************************************/
194     /* POWER MANAGER                              */
195     /**********************************************/
PowerManager(QObject * parent)196     PowerManager::PowerManager(QObject *parent) : QObject(parent) {
197         QDBusConnectionInterface *interface = QDBusConnection::systemBus().interface();
198 
199         // check if login1 interface exists
200         if (interface->isServiceRegistered(LOGIN1_SERVICE))
201             m_backends << new SeatManagerBackend(LOGIN1_SERVICE, LOGIN1_PATH, LOGIN1_OBJECT);
202 
203         // check if ConsoleKit2 interface exists
204         if (interface->isServiceRegistered(CK2_SERVICE))
205             m_backends << new SeatManagerBackend(CK2_SERVICE, CK2_PATH, CK2_OBJECT);
206 
207         // check if upower interface exists
208         if (interface->isServiceRegistered(UPOWER_SERVICE))
209             m_backends << new UPowerBackend(UPOWER_SERVICE, UPOWER_PATH, UPOWER_OBJECT);
210     }
211 
~PowerManager()212     PowerManager::~PowerManager() {
213         while (!m_backends.empty())
214             delete m_backends.takeFirst();
215     }
216 
capabilities() const217     Capabilities PowerManager::capabilities() const {
218         Capabilities caps = Capability::None;
219 
220         for (PowerManagerBackend *backend: m_backends)
221             caps |= backend->capabilities();
222 
223         return caps;
224     }
225 
powerOff() const226     void PowerManager::powerOff() const {
227         if (daemonApp->testing())
228             return;
229 
230         for (PowerManagerBackend *backend: m_backends) {
231             if (backend->capabilities() & Capability::PowerOff) {
232                 backend->powerOff();
233                 break;
234             }
235         }
236     }
237 
reboot() const238     void PowerManager::reboot() const {
239         if (daemonApp->testing())
240             return;
241 
242         for (PowerManagerBackend *backend: m_backends) {
243             if (backend->capabilities() & Capability::Reboot) {
244                 backend->reboot();
245                 break;
246             }
247         }
248     }
249 
suspend() const250     void PowerManager::suspend() const {
251         if (daemonApp->testing())
252             return;
253 
254         for (PowerManagerBackend *backend: m_backends) {
255             if (backend->capabilities() & Capability::Suspend) {
256                 backend->suspend();
257                 break;
258             }
259         }
260     }
261 
hibernate() const262     void PowerManager::hibernate() const {
263         if (daemonApp->testing())
264             return;
265 
266         for (PowerManagerBackend *backend: m_backends) {
267             if (backend->capabilities() & Capability::Hibernate) {
268                 backend->hibernate();
269                 break;
270             }
271         }
272     }
273 
hybridSleep() const274     void PowerManager::hybridSleep() const {
275         if (daemonApp->testing())
276             return;
277 
278         for (PowerManagerBackend *backend: m_backends) {
279             if (backend->capabilities() & Capability::HybridSleep) {
280                 backend->hybridSleep();
281                 break;
282             }
283         }
284     }
285 }
286