lxqtpower: Add suspend and hibernate to ConsoleKit2 provider
[lxde/liblxqt.git] / lxqtpower / lxqtpowerproviders.cpp
1 /* BEGIN_COMMON_COPYRIGHT_HEADER
2 * (c)LGPL2+
3 *
4 * LXQt - a lightweight, Qt based, desktop toolset
5 * http://razor-qt.org
6 *
7 * Copyright: 2010-2011 Razor team
8 * Authors:
9 * Alexander Sokoloff <sokoloff.a@gmail.com>
10 * Petr Vanek <petr@scribus.info>
11 *
12 * This program or library is free software; you can redistribute it
13 * and/or modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
16 *
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
21
22 * You should have received a copy of the GNU Lesser General
23 * Public License along with this library; if not, write to the
24 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25 * Boston, MA 02110-1301 USA
26 *
27 * END_COMMON_COPYRIGHT_HEADER */
28
29
30 #include "lxqtpowerproviders.h"
31 #include <QDBusInterface>
32 #include <QProcess>
33 #include <QDebug>
34 #include "lxqtnotification.h"
35 #include <signal.h> // for kill()
36
37 #define UPOWER_SERVICE "org.freedesktop.UPower"
38 #define UPOWER_PATH "/org/freedesktop/UPower"
39 #define UPOWER_INTERFACE UPOWER_SERVICE
40
41 #define CONSOLEKIT_SERVICE "org.freedesktop.ConsoleKit"
42 #define CONSOLEKIT_PATH "/org/freedesktop/ConsoleKit/Manager"
43 #define CONSOLEKIT_INTERFACE "org.freedesktop.ConsoleKit.Manager"
44
45 #define SYSTEMD_SERVICE "org.freedesktop.login1"
46 #define SYSTEMD_PATH "/org/freedesktop/login1"
47 #define SYSTEMD_INTERFACE "org.freedesktop.login1.Manager"
48
49 #define LXQT_SERVICE "org.lxqt.session"
50 #define LXQT_PATH "/LXQtSession"
51 #define LXQT_INTERFACE "org.lxqt.session"
52
53 #define LXSESSION_SERVICE "org.lxde.SessionManager"
54 #define LXSESSION_PATH "/org/lxde/SessionManager"
55 #define LXSESSION_INTERFACE "org.lxde.SessionManager"
56
57 #define PROPERTIES_INTERFACE "org.freedesktop.DBus.Properties"
58
59 using namespace LXQt;
60
61 /************************************************
62 Helper func
63 ************************************************/
64 void printDBusMsg(const QDBusMessage &msg)
65 {
66 qWarning() << "** Dbus error **************************";
67 qWarning() << "Error name " << msg.errorName();
68 qWarning() << "Error msg " << msg.errorMessage();
69 qWarning() << "****************************************";
70 }
71
72
73 /************************************************
74 Helper func
75 ************************************************/
76 static bool dbusCall(const QString &service,
77 const QString &path,
78 const QString &interface,
79 const QDBusConnection &connection,
80 const QString & method,
81 PowerProvider::DbusErrorCheck errorCheck = PowerProvider::CheckDBUS
82 )
83 {
84 QDBusInterface dbus(service, path, interface, connection);
85 if (!dbus.isValid())
86 {
87 qWarning() << "dbusCall: QDBusInterface is invalid" << service << path << interface << method;
88 if (errorCheck == PowerProvider::CheckDBUS)
89 {
90 Notification::notify(
91 QObject::tr("Power Manager Error"),
92 QObject::tr("QDBusInterface is invalid")+ "\n\n" + service + " " + path + " " + interface + " " + method,
93 "lxqt-logo.png");
94 }
95 return false;
96 }
97
98 QDBusMessage msg = dbus.call(method);
99
100 if (!msg.errorName().isEmpty())
101 {
102 printDBusMsg(msg);
103 if (errorCheck == PowerProvider::CheckDBUS)
104 {
105 Notification::notify(
106 QObject::tr("Power Manager Error (D-BUS call)"),
107 msg.errorName() + "\n\n" + msg.errorMessage(),
108 "lxqt-logo.png");
109 }
110 }
111
112 // If the method no returns value, we believe that it was successful.
113 return msg.arguments().isEmpty() ||
114 msg.arguments().first().isNull() ||
115 msg.arguments().first().toBool();
116 }
117
118 /************************************************
119 Helper func
120
121 Just like dbusCall(), except that systemd
122 returns a string instead of a bool, and it takes
123 an "interactivity boolean" as an argument.
124 ************************************************/
125 static bool dbusCallSystemd(const QString &service,
126 const QString &path,
127 const QString &interface,
128 const QDBusConnection &connection,
129 const QString &method,
130 bool needBoolArg,
131 PowerProvider::DbusErrorCheck errorCheck = PowerProvider::CheckDBUS
132 )
133 {
134 QDBusInterface dbus(service, path, interface, connection);
135 if (!dbus.isValid())
136 {
137 qWarning() << "dbusCall: QDBusInterface is invalid" << service << path << interface << method;
138 if (errorCheck == PowerProvider::CheckDBUS)
139 {
140 Notification::notify(
141 QObject::tr("Power Manager Error"),
142 QObject::tr("QDBusInterface is invalid")+ "\n\n" + service + " " + path + " " + interface + " " + method,
143 "lxqt-logo.png");
144 }
145 return false;
146 }
147
148 QDBusMessage msg = dbus.call(method, needBoolArg ? QVariant(true) : QVariant());
149
150 if (!msg.errorName().isEmpty())
151 {
152 printDBusMsg(msg);
153 if (errorCheck == PowerProvider::CheckDBUS)
154 {
155 Notification::notify(
156 QObject::tr("Power Manager Error (D-BUS call)"),
157 msg.errorName() + "\n\n" + msg.errorMessage(),
158 "lxqt-logo.png");
159 }
160 }
161
162 // If the method no returns value, we believe that it was successful.
163 if (msg.arguments().isEmpty() || msg.arguments().first().isNull())
164 return true;
165
166 QString response = msg.arguments().first().toString();
167 qDebug() << "systemd:" << method << "=" << response;
168 return response == "yes" || response == "challenge";
169 }
170
171
172 /************************************************
173 Helper func
174 ************************************************/
175 bool dbusGetProperty(const QString &service,
176 const QString &path,
177 const QString &interface,
178 const QDBusConnection &connection,
179 const QString & property
180 )
181 {
182 QDBusInterface dbus(service, path, interface, connection);
183 if (!dbus.isValid())
184 {
185 qWarning() << "dbusGetProperty: QDBusInterface is invalid" << service << path << interface << property;
186 // Notification::notify(QObject::tr("LXQt Power Manager"),
187 // "lxqt-logo.png",
188 // QObject::tr("Power Manager Error"),
189 // QObject::tr("QDBusInterface is invalid")+ "\n\n" + service +" " + path +" " + interface +" " + property);
190
191 return false;
192 }
193
194 QDBusMessage msg = dbus.call("Get", dbus.interface(), property);
195
196 if (!msg.errorName().isEmpty())
197 {
198 printDBusMsg(msg);
199 // Notification::notify(QObject::tr("LXQt Power Manager"),
200 // "lxqt-logo.png",
201 // QObject::tr("Power Manager Error (Get Property)"),
202 // msg.errorName() + "\n\n" + msg.errorMessage());
203 }
204
205 return !msg.arguments().isEmpty() &&
206 msg.arguments().first().value<QDBusVariant>().variant().toBool();
207 }
208
209
210
211
212 /************************************************
213 PowerProvider
214 ************************************************/
215 PowerProvider::PowerProvider(QObject *parent):
216 QObject(parent)
217 {
218 }
219
220
221 PowerProvider::~PowerProvider()
222 {
223 }
224
225
226
227 /************************************************
228 UPowerProvider
229 ************************************************/
230 UPowerProvider::UPowerProvider(QObject *parent):
231 PowerProvider(parent)
232 {
233 }
234
235
236 UPowerProvider::~UPowerProvider()
237 {
238 }
239
240
241 bool UPowerProvider::canAction(Power::Action action) const
242 {
243 QString command;
244 QString property;
245 switch (action)
246 {
247 case Power::PowerHibernate:
248 property = "CanHibernate";
249 command = "HibernateAllowed";
250 break;
251
252 case Power::PowerSuspend:
253 property = "CanSuspend";
254 command = "SuspendAllowed";
255 break;
256
257 default:
258 return false;
259 }
260
261 return dbusGetProperty( // Whether the system is able to hibernate.
262 UPOWER_SERVICE,
263 UPOWER_PATH,
264 PROPERTIES_INTERFACE,
265 QDBusConnection::systemBus(),
266 property
267 )
268 &&
269 dbusCall( // Check if the caller has (or can get) the PolicyKit privilege to call command.
270 UPOWER_SERVICE,
271 UPOWER_PATH,
272 UPOWER_INTERFACE,
273 QDBusConnection::systemBus(),
274 command,
275 // canAction should be always silent because it can freeze
276 // g_main_context_iteration Qt event loop in QMessageBox
277 // on panel startup if there is no DBUS running.
278 PowerProvider::DontCheckDBUS
279 );
280 }
281
282
283 bool UPowerProvider::doAction(Power::Action action)
284 {
285 QString command;
286
287 switch (action)
288 {
289 case Power::PowerHibernate:
290 command = "Hibernate";
291 break;
292
293 case Power::PowerSuspend:
294 command = "Suspend";
295 break;
296
297 default:
298 return false;
299 }
300
301
302 return dbusCall(UPOWER_SERVICE,
303 UPOWER_PATH,
304 UPOWER_INTERFACE,
305 QDBusConnection::systemBus(),
306 command );
307 }
308
309
310
311 /************************************************
312 ConsoleKitProvider
313 ************************************************/
314 ConsoleKitProvider::ConsoleKitProvider(QObject *parent):
315 PowerProvider(parent)
316 {
317 }
318
319
320 ConsoleKitProvider::~ConsoleKitProvider()
321 {
322 }
323
324
325 bool ConsoleKitProvider::canAction(Power::Action action) const
326 {
327 QString command;
328 switch (action)
329 {
330 case Power::PowerReboot:
331 command = "CanReboot";
332 break;
333
334 case Power::PowerShutdown:
335 command = "CanPowerOff";
336 break;
337
338 case Power::PowerHibernate:
339 command = "CanHibernate";
340 break;
341
342 case Power::PowerSuspend:
343 command = "CanSuspend";
344 break;
345
346 default:
347 return false;
348 }
349
350 return dbusCallSystemd(CONSOLEKIT_SERVICE,
351 CONSOLEKIT_PATH,
352 CONSOLEKIT_INTERFACE,
353 QDBusConnection::systemBus(),
354 command,
355 false,
356 // canAction should be always silent because it can freeze
357 // g_main_context_iteration Qt event loop in QMessageBox
358 // on panel startup if there is no DBUS running.
359 PowerProvider::DontCheckDBUS
360 );
361 }
362
363
364 bool ConsoleKitProvider::doAction(Power::Action action)
365 {
366 QString command;
367 switch (action)
368 {
369 case Power::PowerReboot:
370 command = "Reboot";
371 break;
372
373 case Power::PowerShutdown:
374 command = "PowerOff";
375 break;
376
377 case Power::PowerHibernate:
378 command = "Hibernate";
379 break;
380
381 case Power::PowerSuspend:
382 command = "Suspend";
383 break;
384
385 default:
386 return false;
387 }
388
389 return dbusCallSystemd(CONSOLEKIT_SERVICE,
390 CONSOLEKIT_PATH,
391 CONSOLEKIT_INTERFACE,
392 QDBusConnection::systemBus(),
393 command,
394 true
395 );
396 }
397
398 /************************************************
399 SystemdProvider
400
401 http://www.freedesktop.org/wiki/Software/systemd/logind
402 ************************************************/
403
404 SystemdProvider::SystemdProvider(QObject *parent):
405 PowerProvider(parent)
406 {
407 }
408
409
410 SystemdProvider::~SystemdProvider()
411 {
412 }
413
414
415 bool SystemdProvider::canAction(Power::Action action) const
416 {
417 QString command;
418
419 switch (action)
420 {
421 case Power::PowerReboot:
422 command = "CanReboot";
423 break;
424
425 case Power::PowerShutdown:
426 command = "CanPowerOff";
427 break;
428
429 case Power::PowerSuspend:
430 command = "CanSuspend";
431 break;
432
433 case Power::PowerHibernate:
434 command = "CanHibernate";
435 break;
436
437 default:
438 return false;
439 }
440
441 return dbusCallSystemd(SYSTEMD_SERVICE,
442 SYSTEMD_PATH,
443 SYSTEMD_INTERFACE,
444 QDBusConnection::systemBus(),
445 command,
446 false,
447 // canAction should be always silent because it can freeze
448 // g_main_context_iteration Qt event loop in QMessageBox
449 // on panel startup if there is no DBUS running.
450 PowerProvider::DontCheckDBUS
451 );
452 }
453
454
455 bool SystemdProvider::doAction(Power::Action action)
456 {
457 QString command;
458
459 switch (action)
460 {
461 case Power::PowerReboot:
462 command = "Reboot";
463 break;
464
465 case Power::PowerShutdown:
466 command = "PowerOff";
467 break;
468
469 case Power::PowerSuspend:
470 command = "Suspend";
471 break;
472
473 case Power::PowerHibernate:
474 command = "Hibernate";
475 break;
476
477 default:
478 return false;
479 }
480
481 return dbusCallSystemd(SYSTEMD_SERVICE,
482 SYSTEMD_PATH,
483 SYSTEMD_INTERFACE,
484 QDBusConnection::systemBus(),
485 command,
486 true
487 );
488 }
489
490
491 /************************************************
492 LXQtProvider
493 ************************************************/
494 LXQtProvider::LXQtProvider(QObject *parent):
495 PowerProvider(parent)
496 {
497 }
498
499
500 LXQtProvider::~LXQtProvider()
501 {
502 }
503
504
505 bool LXQtProvider::canAction(Power::Action action) const
506 {
507 switch (action)
508 {
509 case Power::PowerLogout:
510 // there can be case when razo-session does not run
511 return dbusCall(LXQT_SERVICE, LXQT_PATH, LXQT_SERVICE,
512 QDBusConnection::sessionBus(), "canLogout",
513 PowerProvider::DontCheckDBUS);
514 default:
515 return false;
516 }
517 }
518
519
520 bool LXQtProvider::doAction(Power::Action action)
521 {
522 QString command;
523
524 switch (action)
525 {
526 case Power::PowerLogout:
527 command = "logout";
528 break;
529
530 default:
531 return false;
532 }
533
534 return dbusCall(LXQT_SERVICE,
535 LXQT_PATH,
536 LXQT_INTERFACE,
537 QDBusConnection::sessionBus(),
538 command
539 );
540 }
541
542 /************************************************
543 LxSessionProvider
544 ************************************************/
545 LxSessionProvider::LxSessionProvider(QObject *parent):
546 PowerProvider(parent)
547 {
548 pid = (Q_PID)qgetenv("_LXSESSION_PID").toLong();
549 }
550
551
552 LxSessionProvider::~LxSessionProvider()
553 {
554 }
555
556
557 bool LxSessionProvider::canAction(Power::Action action) const
558 {
559 switch (action)
560 {
561 case Power::PowerLogout:
562 return pid != 0;
563 default:
564 return false;
565 }
566 }
567
568
569 bool LxSessionProvider::doAction(Power::Action action)
570 {
571 switch (action)
572 {
573 case Power::PowerLogout:
574 if(pid)
575 ::kill(pid, SIGTERM);
576 break;
577 default:
578 return false;
579 }
580
581 return true;
582 }
583
584
585 /************************************************
586 HalProvider
587 ************************************************/
588 HalProvider::HalProvider(QObject *parent):
589 PowerProvider(parent)
590 {
591 }
592
593
594 HalProvider::~HalProvider()
595 {
596 }
597
598
599 bool HalProvider::canAction(Power::Action action) const
600 {
601 return false;
602 }
603
604
605 bool HalProvider::doAction(Power::Action action)
606 {
607 return false;
608 }
609
610
611 /************************************************
612 CustomProvider
613 ************************************************/
614 CustomProvider::CustomProvider(QObject *parent):
615 PowerProvider(parent),
616 mSettings("power")
617 {
618 }
619
620 CustomProvider::~CustomProvider()
621 {
622 }
623
624 bool CustomProvider::canAction(Power::Action action) const
625 {
626 switch (action)
627 {
628 case Power::PowerShutdown:
629 return mSettings.contains("shutdownCommand");
630
631 case Power::PowerReboot:
632 return mSettings.contains("rebootCommand");
633
634 case Power::PowerHibernate:
635 return mSettings.contains("hibernateCommand");
636
637 case Power::PowerSuspend:
638 return mSettings.contains("suspendCommand");
639
640 case Power::PowerLogout:
641 return mSettings.contains("logoutCommand");
642
643 default:
644 return false;
645 }
646 }
647
648 bool CustomProvider::doAction(Power::Action action)
649 {
650 QString command;
651
652 switch(action)
653 {
654 case Power::PowerShutdown:
655 command = mSettings.value("shutdownCommand").toString();
656 break;
657
658 case Power::PowerReboot:
659 command = mSettings.value("rebootCommand").toString();
660 break;
661
662 case Power::PowerHibernate:
663 command = mSettings.value("hibernateCommand").toString();
664 break;
665
666 case Power::PowerSuspend:
667 command = mSettings.value("suspendCommand").toString();
668 break;
669
670 case Power::PowerLogout:
671 command = mSettings.value("logoutCommand").toString();
672 break;
673
674 default:
675 return false;
676 }
677
678 return QProcess::startDetached(command);
679 }