lxqtpower: Add suspend and hibernate to ConsoleKit2 provider
[lxde/liblxqt.git] / lxqtpower / lxqtpowerproviders.cpp
CommitLineData
b3678cfd
AS
1/* BEGIN_COMMON_COPYRIGHT_HEADER
2 * (c)LGPL2+
3 *
b9223fe7 4 * LXQt - a lightweight, Qt based, desktop toolset
b3678cfd
AS
5 * http://razor-qt.org
6 *
7 * Copyright: 2010-2011 Razor team
8 * Authors:
626f1f31 9 * Alexander Sokoloff <sokoloff.a@gmail.com>
c7351c0e 10 * Petr Vanek <petr@scribus.info>
b3678cfd
AS
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
8e6db58a 30#include "lxqtpowerproviders.h"
e6389bfc
HJYP
31#include <QDBusInterface>
32#include <QProcess>
33#include <QDebug>
0e4fbf35 34#include "lxqtnotification.h"
ce86ee51 35#include <signal.h> // for kill()
b3678cfd
AS
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
a5b5dc7a
AM
45#define SYSTEMD_SERVICE "org.freedesktop.login1"
46#define SYSTEMD_PATH "/org/freedesktop/login1"
47#define SYSTEMD_INTERFACE "org.freedesktop.login1.Manager"
48
db4aaddf 49#define LXQT_SERVICE "org.lxqt.session"
f05ba5af 50#define LXQT_PATH "/LXQtSession"
db4aaddf 51#define LXQT_INTERFACE "org.lxqt.session"
b3678cfd 52
ce86ee51
HJYP
53#define LXSESSION_SERVICE "org.lxde.SessionManager"
54#define LXSESSION_PATH "/org/lxde/SessionManager"
55#define LXSESSION_INTERFACE "org.lxde.SessionManager"
b3678cfd
AS
56
57#define PROPERTIES_INTERFACE "org.freedesktop.DBus.Properties"
58
f05ba5af 59using namespace LXQt;
b3678cfd
AS
60
61/************************************************
62 Helper func
63 ************************************************/
64void 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 ************************************************/
dabae7a2 76static bool dbusCall(const QString &service,
b3678cfd
AS
77 const QString &path,
78 const QString &interface,
79 const QDBusConnection &connection,
a9c02a1b 80 const QString & method,
8e6db58a 81 PowerProvider::DbusErrorCheck errorCheck = PowerProvider::CheckDBUS
b3678cfd
AS
82 )
83{
84 QDBusInterface dbus(service, path, interface, connection);
85 if (!dbus.isValid())
c7351c0e 86 {
87 qWarning() << "dbusCall: QDBusInterface is invalid" << service << path << interface << method;
8e6db58a 88 if (errorCheck == PowerProvider::CheckDBUS)
a9c02a1b 89 {
0e4fbf35 90 Notification::notify(
a9c02a1b 91 QObject::tr("Power Manager Error"),
1693d610 92 QObject::tr("QDBusInterface is invalid")+ "\n\n" + service + " " + path + " " + interface + " " + method,
db4aaddf 93 "lxqt-logo.png");
a9c02a1b 94 }
b3678cfd 95 return false;
c7351c0e 96 }
b3678cfd
AS
97
98 QDBusMessage msg = dbus.call(method);
99
100 if (!msg.errorName().isEmpty())
44311613 101 {
b3678cfd 102 printDBusMsg(msg);
8e6db58a 103 if (errorCheck == PowerProvider::CheckDBUS)
a9c02a1b 104 {
0e4fbf35 105 Notification::notify(
a9c02a1b 106 QObject::tr("Power Manager Error (D-BUS call)"),
1693d610 107 msg.errorName() + "\n\n" + msg.errorMessage(),
db4aaddf 108 "lxqt-logo.png");
a9c02a1b 109 }
44311613 110 }
b3678cfd 111
5ea86b7a
AS
112 // If the method no returns value, we believe that it was successful.
113 return msg.arguments().isEmpty() ||
6fd34ba5 114 msg.arguments().first().isNull() ||
5ea86b7a 115 msg.arguments().first().toBool();
b3678cfd
AS
116}
117
a5b5dc7a
AM
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 ************************************************/
dabae7a2 125static bool dbusCallSystemd(const QString &service,
a5b5dc7a
AM
126 const QString &path,
127 const QString &interface,
128 const QDBusConnection &connection,
129 const QString &method,
dabae7a2 130 bool needBoolArg,
8e6db58a 131 PowerProvider::DbusErrorCheck errorCheck = PowerProvider::CheckDBUS
a5b5dc7a
AM
132 )
133{
134 QDBusInterface dbus(service, path, interface, connection);
135 if (!dbus.isValid())
136 {
137 qWarning() << "dbusCall: QDBusInterface is invalid" << service << path << interface << method;
8e6db58a 138 if (errorCheck == PowerProvider::CheckDBUS)
a5b5dc7a 139 {
0e4fbf35 140 Notification::notify(
a5b5dc7a
AM
141 QObject::tr("Power Manager Error"),
142 QObject::tr("QDBusInterface is invalid")+ "\n\n" + service + " " + path + " " + interface + " " + method,
db4aaddf 143 "lxqt-logo.png");
a5b5dc7a
AM
144 }
145 return false;
146 }
147
dabae7a2 148 QDBusMessage msg = dbus.call(method, needBoolArg ? QVariant(true) : QVariant());
a5b5dc7a
AM
149
150 if (!msg.errorName().isEmpty())
151 {
152 printDBusMsg(msg);
8e6db58a 153 if (errorCheck == PowerProvider::CheckDBUS)
a5b5dc7a 154 {
0e4fbf35 155 Notification::notify(
a5b5dc7a
AM
156 QObject::tr("Power Manager Error (D-BUS call)"),
157 msg.errorName() + "\n\n" + msg.errorMessage(),
db4aaddf 158 "lxqt-logo.png");
a5b5dc7a
AM
159 }
160 }
161
162 // If the method no returns value, we believe that it was successful.
6fd34ba5 163 if (msg.arguments().isEmpty() || msg.arguments().first().isNull())
a5b5dc7a
AM
164 return true;
165
166 QString response = msg.arguments().first().toString();
167 qDebug() << "systemd:" << method << "=" << response;
168 return response == "yes" || response == "challenge";
169}
170
b3678cfd
AS
171
172/************************************************
173 Helper func
174 ************************************************/
175bool 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())
c7351c0e 184 {
185 qWarning() << "dbusGetProperty: QDBusInterface is invalid" << service << path << interface << property;
f05ba5af 186// Notification::notify(QObject::tr("LXQt Power Manager"),
db4aaddf 187// "lxqt-logo.png",
a9c02a1b 188// QObject::tr("Power Manager Error"),
1693d610 189// QObject::tr("QDBusInterface is invalid")+ "\n\n" + service +" " + path +" " + interface +" " + property);
44311613 190
b3678cfd 191 return false;
c7351c0e 192 }
b3678cfd
AS
193
194 QDBusMessage msg = dbus.call("Get", dbus.interface(), property);
195
196 if (!msg.errorName().isEmpty())
44311613 197 {
b3678cfd 198 printDBusMsg(msg);
f05ba5af 199// Notification::notify(QObject::tr("LXQt Power Manager"),
db4aaddf 200// "lxqt-logo.png",
a9c02a1b 201// QObject::tr("Power Manager Error (Get Property)"),
1693d610 202// msg.errorName() + "\n\n" + msg.errorMessage());
44311613 203 }
b3678cfd
AS
204
205 return !msg.arguments().isEmpty() &&
206 msg.arguments().first().value<QDBusVariant>().variant().toBool();
207}
208
209
210
211
212/************************************************
8e6db58a 213 PowerProvider
b3678cfd 214 ************************************************/
8e6db58a 215PowerProvider::PowerProvider(QObject *parent):
b3678cfd
AS
216 QObject(parent)
217{
218}
219
220
8e6db58a 221PowerProvider::~PowerProvider()
b3678cfd
AS
222{
223}
224
225
226
227/************************************************
228 UPowerProvider
229 ************************************************/
230UPowerProvider::UPowerProvider(QObject *parent):
8e6db58a 231 PowerProvider(parent)
b3678cfd
AS
232{
233}
234
235
236UPowerProvider::~UPowerProvider()
237{
238}
239
240
8e6db58a 241bool UPowerProvider::canAction(Power::Action action) const
b3678cfd
AS
242{
243 QString command;
244 QString property;
245 switch (action)
246 {
8e6db58a 247 case Power::PowerHibernate:
b3678cfd
AS
248 property = "CanHibernate";
249 command = "HibernateAllowed";
250 break;
251
8e6db58a 252 case Power::PowerSuspend:
b3678cfd
AS
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(),
731cfd19
PV
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.
8e6db58a 278 PowerProvider::DontCheckDBUS
b3678cfd
AS
279 );
280}
281
282
8e6db58a 283bool UPowerProvider::doAction(Power::Action action)
b3678cfd
AS
284{
285 QString command;
286
287 switch (action)
288 {
8e6db58a 289 case Power::PowerHibernate:
b3678cfd
AS
290 command = "Hibernate";
291 break;
292
8e6db58a 293 case Power::PowerSuspend:
b3678cfd
AS
294 command = "Suspend";
295 break;
296
297 default:
5ea86b7a 298 return false;
b3678cfd
AS
299 }
300
5ea86b7a
AS
301
302 return dbusCall(UPOWER_SERVICE,
b3678cfd
AS
303 UPOWER_PATH,
304 UPOWER_INTERFACE,
305 QDBusConnection::systemBus(),
306 command );
307}
308
309
310
311/************************************************
312 ConsoleKitProvider
313 ************************************************/
314ConsoleKitProvider::ConsoleKitProvider(QObject *parent):
8e6db58a 315 PowerProvider(parent)
b3678cfd
AS
316{
317}
318
319
320ConsoleKitProvider::~ConsoleKitProvider()
321{
322}
323
324
8e6db58a 325bool ConsoleKitProvider::canAction(Power::Action action) const
b3678cfd
AS
326{
327 QString command;
b3678cfd
AS
328 switch (action)
329 {
8e6db58a 330 case Power::PowerReboot:
6246a14a 331 command = "CanReboot";
b3678cfd
AS
332 break;
333
8e6db58a 334 case Power::PowerShutdown:
6246a14a
TM
335 command = "CanPowerOff";
336 break;
337
338 case Power::PowerHibernate:
339 command = "CanHibernate";
340 break;
341
342 case Power::PowerSuspend:
343 command = "CanSuspend";
b3678cfd
AS
344 break;
345
346 default:
347 return false;
348 }
349
6246a14a 350 return dbusCallSystemd(CONSOLEKIT_SERVICE,
4c73a6f3
CS
351 CONSOLEKIT_PATH,
352 CONSOLEKIT_INTERFACE,
353 QDBusConnection::systemBus(),
354 command,
6246a14a 355 false,
4c73a6f3
CS
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 );
b3678cfd
AS
361}
362
363
8e6db58a 364bool ConsoleKitProvider::doAction(Power::Action action)
b3678cfd
AS
365{
366 QString command;
b3678cfd
AS
367 switch (action)
368 {
8e6db58a 369 case Power::PowerReboot:
6246a14a 370 command = "Reboot";
b3678cfd
AS
371 break;
372
8e6db58a 373 case Power::PowerShutdown:
6246a14a
TM
374 command = "PowerOff";
375 break;
376
377 case Power::PowerHibernate:
378 command = "Hibernate";
379 break;
380
381 case Power::PowerSuspend:
382 command = "Suspend";
b3678cfd
AS
383 break;
384
385 default:
5ea86b7a 386 return false;
b3678cfd
AS
387 }
388
6246a14a
TM
389 return dbusCallSystemd(CONSOLEKIT_SERVICE,
390 CONSOLEKIT_PATH,
391 CONSOLEKIT_INTERFACE,
392 QDBusConnection::systemBus(),
393 command,
394 true
395 );
b3678cfd
AS
396}
397
a5b5dc7a
AM
398/************************************************
399 SystemdProvider
400
401 http://www.freedesktop.org/wiki/Software/systemd/logind
402 ************************************************/
403
404SystemdProvider::SystemdProvider(QObject *parent):
8e6db58a 405 PowerProvider(parent)
a5b5dc7a
AM
406{
407}
408
409
410SystemdProvider::~SystemdProvider()
411{
412}
413
414
8e6db58a 415bool SystemdProvider::canAction(Power::Action action) const
a5b5dc7a
AM
416{
417 QString command;
418
419 switch (action)
420 {
8e6db58a 421 case Power::PowerReboot:
a5b5dc7a
AM
422 command = "CanReboot";
423 break;
424
8e6db58a 425 case Power::PowerShutdown:
a5b5dc7a
AM
426 command = "CanPowerOff";
427 break;
428
8e6db58a 429 case Power::PowerSuspend:
a5b5dc7a
AM
430 command = "CanSuspend";
431 break;
432
8e6db58a 433 case Power::PowerHibernate:
a5b5dc7a
AM
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,
85965778 446 false,
a5b5dc7a
AM
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.
8e6db58a 450 PowerProvider::DontCheckDBUS
a5b5dc7a
AM
451 );
452}
453
454
8e6db58a 455bool SystemdProvider::doAction(Power::Action action)
a5b5dc7a
AM
456{
457 QString command;
458
459 switch (action)
460 {
8e6db58a 461 case Power::PowerReboot:
a5b5dc7a
AM
462 command = "Reboot";
463 break;
464
8e6db58a 465 case Power::PowerShutdown:
a5b5dc7a
AM
466 command = "PowerOff";
467 break;
468
8e6db58a 469 case Power::PowerSuspend:
a5b5dc7a
AM
470 command = "Suspend";
471 break;
472
8e6db58a 473 case Power::PowerHibernate:
a5b5dc7a
AM
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(),
dabae7a2 485 command,
85965778 486 true
a5b5dc7a
AM
487 );
488}
b3678cfd
AS
489
490
491/************************************************
f05ba5af 492 LXQtProvider
b3678cfd 493 ************************************************/
f05ba5af 494LXQtProvider::LXQtProvider(QObject *parent):
8e6db58a 495 PowerProvider(parent)
b3678cfd
AS
496{
497}
498
499
f05ba5af 500LXQtProvider::~LXQtProvider()
b3678cfd
AS
501{
502}
503
504
f05ba5af 505bool LXQtProvider::canAction(Power::Action action) const
b3678cfd 506{
c7351c0e 507 switch (action)
508 {
8e6db58a 509 case Power::PowerLogout:
c7351c0e 510 // there can be case when razo-session does not run
db4aaddf 511 return dbusCall(LXQT_SERVICE, LXQT_PATH, LXQT_SERVICE,
731cfd19 512 QDBusConnection::sessionBus(), "canLogout",
8e6db58a 513 PowerProvider::DontCheckDBUS);
c7351c0e 514 default:
515 return false;
516 }
b3678cfd
AS
517}
518
519
f05ba5af 520bool LXQtProvider::doAction(Power::Action action)
b3678cfd
AS
521{
522 QString command;
523
524 switch (action)
525 {
8e6db58a 526 case Power::PowerLogout:
b3678cfd
AS
527 command = "logout";
528 break;
529
530 default:
5ea86b7a 531 return false;
b3678cfd
AS
532 }
533
db4aaddf
HJYP
534 return dbusCall(LXQT_SERVICE,
535 LXQT_PATH,
536 LXQT_INTERFACE,
b3678cfd
AS
537 QDBusConnection::sessionBus(),
538 command
539 );
540}
541
ce86ee51
HJYP
542/************************************************
543 LxSessionProvider
544 ************************************************/
545LxSessionProvider::LxSessionProvider(QObject *parent):
546 PowerProvider(parent)
547{
548 pid = (Q_PID)qgetenv("_LXSESSION_PID").toLong();
549}
550
551
552LxSessionProvider::~LxSessionProvider()
553{
554}
555
556
557bool 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
569bool 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 }
85965778
JL
580
581 return true;
ce86ee51 582}
b3678cfd
AS
583
584
585/************************************************
586 HalProvider
587 ************************************************/
588HalProvider::HalProvider(QObject *parent):
8e6db58a 589 PowerProvider(parent)
b3678cfd
AS
590{
591}
592
593
594HalProvider::~HalProvider()
595{
596}
597
598
8e6db58a 599bool HalProvider::canAction(Power::Action action) const
b3678cfd
AS
600{
601 return false;
602}
603
604
8e6db58a 605bool HalProvider::doAction(Power::Action action)
b3678cfd 606{
5ea86b7a 607 return false;
b3678cfd 608}
497b5c91
AM
609
610
611/************************************************
612 CustomProvider
613 ************************************************/
614CustomProvider::CustomProvider(QObject *parent):
8e6db58a 615 PowerProvider(parent),
497b5c91
AM
616 mSettings("power")
617{
618}
619
620CustomProvider::~CustomProvider()
621{
622}
623
8e6db58a 624bool CustomProvider::canAction(Power::Action action) const
497b5c91
AM
625{
626 switch (action)
627 {
8e6db58a 628 case Power::PowerShutdown:
497b5c91
AM
629 return mSettings.contains("shutdownCommand");
630
8e6db58a 631 case Power::PowerReboot:
497b5c91
AM
632 return mSettings.contains("rebootCommand");
633
8e6db58a 634 case Power::PowerHibernate:
497b5c91
AM
635 return mSettings.contains("hibernateCommand");
636
8e6db58a 637 case Power::PowerSuspend:
497b5c91
AM
638 return mSettings.contains("suspendCommand");
639
8e6db58a 640 case Power::PowerLogout:
497b5c91
AM
641 return mSettings.contains("logoutCommand");
642
643 default:
644 return false;
645 }
646}
647
8e6db58a 648bool CustomProvider::doAction(Power::Action action)
497b5c91
AM
649{
650 QString command;
651
652 switch(action)
653 {
8e6db58a 654 case Power::PowerShutdown:
497b5c91
AM
655 command = mSettings.value("shutdownCommand").toString();
656 break;
657
8e6db58a 658 case Power::PowerReboot:
497b5c91
AM
659 command = mSettings.value("rebootCommand").toString();
660 break;
661
8e6db58a 662 case Power::PowerHibernate:
497b5c91
AM
663 command = mSettings.value("hibernateCommand").toString();
664 break;
665
8e6db58a 666 case Power::PowerSuspend:
497b5c91
AM
667 command = mSettings.value("suspendCommand").toString();
668 break;
669
8e6db58a 670 case Power::PowerLogout:
497b5c91
AM
671 command = mSettings.value("logoutCommand").toString();
672 break;
673
674 default:
675 return false;
676 }
677
678 return QProcess::startDetached(command);
679}