Plasma-workspace

sessionmanagementbackend.cpp
1/*
2 SPDX-FileCopyrightText: 2019 David Edmundson <davidedmundson@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#include "sessionmanagementbackend.h"
8
9#include <QDebug>
10#include <QMutex>
11#include <QMutexLocker>
12
13#include <QDBusConnection>
14#include <QDBusConnectionInterface>
15#include <QDBusPendingCallWatcher>
16
17#include <KConfigGroup>
18#include <iostream>
19
20#include "login1_manager_interface.h"
21
22static SessionBackend *s_backend = nullptr;
23
24SessionBackend *SessionBackend::self()
25{
26 static QMutex mutex;
27 QMutexLocker lock(&mutex);
28
29 if (s_backend) {
30 return s_backend;
31 }
32
33 if (qEnvironmentVariableIntValue("PLASMA_SESSION_GUI_TEST")) {
34 s_backend = new TestSessionBackend();
35 } else if (LogindSessionBackend::exists()) {
36 s_backend = new LogindSessionBackend();
37 } else {
38 s_backend = new DummySessionBackend();
39 }
40
41 return s_backend;
42}
43
44SessionBackend::SessionBackend()
45 : m_kserverConfig(KConfigWatcher::create(KSharedConfig::openConfig(QStringLiteral("ksmserverrc"))))
46{
47}
48
49bool SessionBackend::confirmLogout() const
50{
51 return m_kserverConfig->config()->group(QStringLiteral("General")).readEntry("confirmLogout", true);
52}
53
54bool SessionBackend::canSwitchUser() const
55{
56 return false;
57}
58
59DummySessionBackend::DummySessionBackend()
60{
61 qCritical() << "Could not load a session backend. Session management operations such as shutdown will not be operational. This is a setup issue.";
62}
63
64TestSessionBackend::TestSessionBackend()
65{
66 qWarning() << "This backend is intended for gui autotesting only, it will not be operational";
67}
68
69void TestSessionBackend::shutdown()
70{
71 std::cout << "shutdown" << std::endl;
72}
73
74void TestSessionBackend::reboot()
75{
76 std::cout << "reboot" << std::endl;
77}
78
79void TestSessionBackend::suspend()
80{
81 std::cout << "suspend" << std::endl;
82}
83
84void TestSessionBackend::hybridSuspend()
85{
86 std::cout << "hybridSuspend" << std::endl;
87}
88
89void TestSessionBackend::hibernate()
90{
91 std::cout << "hibernate" << std::endl;
92}
93
94void TestSessionBackend::suspendThenHibernate()
95{
96 std::cout << "suspendThenHibernate" << std::endl;
97}
98
99/*********************************************************************************/
100
101LogindSessionBackend::LogindSessionBackend()
102{
103 m_login1 = new OrgFreedesktopLogin1ManagerInterface(QStringLiteral("org.freedesktop.login1"),
104 QStringLiteral("/org/freedesktop/login1"),
106 this);
107
108 auto propLoaded = [this](QDBusPendingCallWatcher *watcher, bool *argToUpdate) {
109 watcher->deleteLater();
110 m_pendingJobs--;
111 QDBusPendingReply<QString> reply = *watcher;
112 if (reply.isError()) {
113 *argToUpdate = false;
114 } else {
115 // both "yes" and "challenge" will show up in the UI
116 const QString value = reply.value();
117 *argToUpdate = false;
118 if (value == QLatin1String("yes") || value == QLatin1String("challenge")) {
119 *argToUpdate = true;
120 }
121 }
122
123 if (m_pendingJobs == 0) {
125 Q_EMIT stateChanged();
126 Q_EMIT canShutdownChanged();
127 Q_EMIT canRebootChanged();
128 Q_EMIT canSuspendChanged();
129 Q_EMIT canHibernateChanged();
130 Q_EMIT canSuspendThenHibernateChanged();
131 }
132 };
133
134 m_pendingJobs = 5;
135 {
136 auto watcher = new QDBusPendingCallWatcher(m_login1->CanPowerOff(), this);
137 connect(watcher, &QDBusPendingCallWatcher::finished, this, std::bind(propLoaded, std::placeholders::_1, &m_canShutdown));
138 }
139 {
140 auto watcher = new QDBusPendingCallWatcher(m_login1->CanReboot(), this);
141 connect(watcher, &QDBusPendingCallWatcher::finished, this, std::bind(propLoaded, std::placeholders::_1, &m_canReboot));
142 }
143 {
144 auto watcher = new QDBusPendingCallWatcher(m_login1->CanSuspend(), this);
145 connect(watcher, &QDBusPendingCallWatcher::finished, this, std::bind(propLoaded, std::placeholders::_1, &m_canSuspend));
146 }
147 {
148 auto watcher = new QDBusPendingCallWatcher(m_login1->CanHybridSleep(), this);
149 connect(watcher, &QDBusPendingCallWatcher::finished, this, std::bind(propLoaded, std::placeholders::_1, &m_canHybridSuspend));
150 }
151 {
152 auto watcher = new QDBusPendingCallWatcher(m_login1->CanHibernate(), this);
153 connect(watcher, &QDBusPendingCallWatcher::finished, this, std::bind(propLoaded, std::placeholders::_1, &m_canHibernate));
154 }
155 {
156 auto watcher = new QDBusPendingCallWatcher(m_login1->CanSuspendThenHibernate(), this);
157 connect(watcher, &QDBusPendingCallWatcher::finished, this, std::bind(propLoaded, std::placeholders::_1, &m_canSuspendThenHibernate));
158 }
159
160 connect(m_login1, &OrgFreedesktopLogin1ManagerInterface::PrepareForSleep, this, [this](bool sleeping) {
161 if (sleeping) {
162 Q_EMIT aboutToSuspend();
163 } else {
164 Q_EMIT resumingFromSuspend();
165 }
166 });
167}
168
169SessionManagement::State LogindSessionBackend::state() const
170{
171 return m_state;
172}
173
174void LogindSessionBackend::shutdown()
175{
176 // logind will confirm credentials with the caller, if the app quits after sending this
177 // this may fail
178 m_login1->PowerOff(true).waitForFinished();
179}
180
181void LogindSessionBackend::reboot()
182{
183 m_login1->Reboot(true).waitForFinished();
184}
185
186void LogindSessionBackend::suspend()
187{
188 // these need to be synchronous as well - ksmserver-logout-greeter specifically calls these
189 // and will quit immediately after
190 m_login1->Suspend(true).waitForFinished();
191}
192
193void LogindSessionBackend::hybridSuspend()
194{
195 m_login1->HybridSleep(true).waitForFinished();
196}
197
198void LogindSessionBackend::hibernate()
199{
200 m_login1->Hibernate(true).waitForFinished();
201}
202
203void LogindSessionBackend::suspendThenHibernate()
204{
205 m_login1->SuspendThenHibernate(true).waitForFinished();
206}
207
208bool LogindSessionBackend::canShutdown() const
209{
210 return m_canShutdown;
211}
212
213bool LogindSessionBackend::canReboot() const
214{
215 return m_canReboot;
216}
217
218bool LogindSessionBackend::canSuspend() const
219{
220 return m_canSuspend;
221}
222
223bool LogindSessionBackend::canHybridSuspend() const
224{
225 return m_canHybridSuspend;
226}
227
228bool LogindSessionBackend::canHibernate() const
229{
230 return m_canHibernate;
231}
232
233bool LogindSessionBackend::canSuspendThenHibernate() const
234{
235 return m_canSuspendThenHibernate;
236}
237
238bool LogindSessionBackend::canSwitchUser() const
239{
240 return true;
241}
Performs direct system actions that could kill the session.
QAction * create(StandardAction id, const Receiver *recvr, Func slot, QObject *parent, std::optional< Qt::ConnectionType > connectionType=std::nullopt)
QDBusConnection systemBus()
void finished(QDBusPendingCallWatcher *self)
bool isError() const const
typename Select< 0 >::Type value() const const
Q_EMITQ_EMIT
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
void deleteLater()
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:14:59 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.