File indexing completed on 2024-04-28 16:54:32
0001 /* 0002 SPDX-FileCopyrightText: 2019 David Edmundson <davidedmundson@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "sessionmanagementbackend.h" 0008 0009 #include <QDebug> 0010 #include <QMutex> 0011 #include <QMutexLocker> 0012 0013 #include <QDBusConnection> 0014 #include <QDBusConnectionInterface> 0015 #include <QDBusPendingCallWatcher> 0016 0017 #include <KConfigGroup> 0018 0019 #include "kdisplaymanager.h" 0020 0021 #include "consolekit_manager_interface.h" 0022 #include "login1_manager_interface.h" 0023 #include "upower_interface.h" 0024 0025 static SessionBackend *s_backend = nullptr; 0026 0027 SessionBackend *SessionBackend::self() 0028 { 0029 static QMutex mutex; 0030 QMutexLocker lock(&mutex); 0031 0032 if (s_backend) { 0033 return s_backend; 0034 } 0035 0036 if (qEnvironmentVariableIntValue("PLASMA_SESSION_GUI_TEST")) { 0037 s_backend = new TestSessionBackend(); 0038 } else if (LogindSessionBackend::exists()) { 0039 s_backend = new LogindSessionBackend(); 0040 } else if (ConsoleKitSessionBackend::exists()) { 0041 s_backend = new ConsoleKitSessionBackend(); 0042 } else { 0043 s_backend = new DummySessionBackend(); 0044 } 0045 0046 return s_backend; 0047 } 0048 0049 SessionBackend::SessionBackend() 0050 : m_kserverConfig(KConfigWatcher::create(KSharedConfig::openConfig(QStringLiteral("ksmserverrc")))) 0051 { 0052 } 0053 0054 bool SessionBackend::confirmLogout() const 0055 { 0056 return m_kserverConfig->config()->group("General").readEntry("confirmLogout", true); 0057 } 0058 0059 bool SessionBackend::canSwitchUser() const 0060 { 0061 return KDisplayManager().isSwitchable(); 0062 } 0063 0064 DummySessionBackend::DummySessionBackend() 0065 { 0066 qCritical() << "Could not load a session backend. Session management operations such as shutdown will not be operational. This is a setup issue."; 0067 } 0068 0069 TestSessionBackend::TestSessionBackend() 0070 { 0071 qWarning() << "This backend is intended for gui autotesting only, it will not be operational"; 0072 } 0073 0074 void TestSessionBackend::shutdown() 0075 { 0076 qWarning() << "shutdown"; 0077 } 0078 0079 void TestSessionBackend::reboot() 0080 { 0081 qWarning() << "reboot"; 0082 } 0083 0084 void TestSessionBackend::suspend() 0085 { 0086 qWarning() << "suspend"; 0087 } 0088 0089 void TestSessionBackend::hybridSuspend() 0090 { 0091 qWarning() << "hybridSuspend"; 0092 } 0093 0094 void TestSessionBackend::hibernate() 0095 { 0096 qWarning() << "hibernate"; 0097 } 0098 0099 /*********************************************************************************/ 0100 0101 LogindSessionBackend::LogindSessionBackend() 0102 { 0103 m_login1 = new OrgFreedesktopLogin1ManagerInterface(QStringLiteral("org.freedesktop.login1"), 0104 QStringLiteral("/org/freedesktop/login1"), 0105 QDBusConnection::systemBus(), 0106 this); 0107 0108 auto propLoaded = [this](QDBusPendingCallWatcher *watcher, bool *argToUpdate) { 0109 watcher->deleteLater(); 0110 m_pendingJobs--; 0111 QDBusPendingReply<QString> reply = *watcher; 0112 if (reply.isError()) { 0113 *argToUpdate = false; 0114 } else { 0115 // both "yes" and "challenge" will show up in the UI 0116 const QString value = reply.value(); 0117 *argToUpdate = false; 0118 if (value == QLatin1String("yes") || value == QLatin1String("challenge")) { 0119 *argToUpdate = true; 0120 } 0121 } 0122 0123 if (m_pendingJobs == 0) { 0124 m_state = SessionManagement::State::Ready; 0125 Q_EMIT stateChanged(); 0126 Q_EMIT canShutdownChanged(); 0127 Q_EMIT canRebootChanged(); 0128 Q_EMIT canSuspendChanged(); 0129 Q_EMIT canHibernateChanged(); 0130 } 0131 }; 0132 0133 m_pendingJobs = 5; 0134 { 0135 auto watcher = new QDBusPendingCallWatcher(m_login1->CanPowerOff(), this); 0136 connect(watcher, &QDBusPendingCallWatcher::finished, this, std::bind(propLoaded, std::placeholders::_1, &m_canShutdown)); 0137 } 0138 { 0139 auto watcher = new QDBusPendingCallWatcher(m_login1->CanReboot(), this); 0140 connect(watcher, &QDBusPendingCallWatcher::finished, this, std::bind(propLoaded, std::placeholders::_1, &m_canReboot)); 0141 } 0142 { 0143 auto watcher = new QDBusPendingCallWatcher(m_login1->CanSuspend(), this); 0144 connect(watcher, &QDBusPendingCallWatcher::finished, this, std::bind(propLoaded, std::placeholders::_1, &m_canSuspend)); 0145 } 0146 { 0147 auto watcher = new QDBusPendingCallWatcher(m_login1->CanHybridSleep(), this); 0148 connect(watcher, &QDBusPendingCallWatcher::finished, this, std::bind(propLoaded, std::placeholders::_1, &m_canHybridSuspend)); 0149 } 0150 { 0151 auto watcher = new QDBusPendingCallWatcher(m_login1->CanHibernate(), this); 0152 connect(watcher, &QDBusPendingCallWatcher::finished, this, std::bind(propLoaded, std::placeholders::_1, &m_canHibernate)); 0153 } 0154 0155 connect(m_login1, &OrgFreedesktopLogin1ManagerInterface::PrepareForSleep, this, [this](bool sleeping) { 0156 if (sleeping) { 0157 Q_EMIT aboutToSuspend(); 0158 } else { 0159 Q_EMIT resumingFromSuspend(); 0160 } 0161 }); 0162 } 0163 0164 SessionManagement::State LogindSessionBackend::state() const 0165 { 0166 return m_state; 0167 } 0168 0169 void LogindSessionBackend::shutdown() 0170 { 0171 // logind will confirm credentials with the caller, if the app quits after sending this 0172 // this may fail 0173 m_login1->PowerOff(true).waitForFinished(); 0174 } 0175 0176 void LogindSessionBackend::reboot() 0177 { 0178 m_login1->Reboot(true).waitForFinished(); 0179 } 0180 0181 void LogindSessionBackend::suspend() 0182 { 0183 // these need to be synchronous as well - ksmserver-logout-greeter specifically calls these 0184 // and will quit immediately after 0185 m_login1->Suspend(true).waitForFinished(); 0186 } 0187 0188 void LogindSessionBackend::hybridSuspend() 0189 { 0190 m_login1->HybridSleep(true).waitForFinished(); 0191 } 0192 0193 void LogindSessionBackend::hibernate() 0194 { 0195 m_login1->Hibernate(true).waitForFinished(); 0196 } 0197 0198 bool LogindSessionBackend::canShutdown() const 0199 { 0200 return m_canShutdown; 0201 } 0202 0203 bool LogindSessionBackend::canReboot() const 0204 { 0205 return m_canReboot; 0206 } 0207 0208 bool LogindSessionBackend::canSuspend() const 0209 { 0210 return m_canSuspend; 0211 } 0212 0213 bool LogindSessionBackend::canHybridSuspend() const 0214 { 0215 return m_canHybridSuspend; 0216 } 0217 0218 bool LogindSessionBackend::canHibernate() const 0219 { 0220 return m_canHibernate; 0221 } 0222 0223 /*********************************************************************************/ 0224 0225 bool ConsoleKitSessionBackend::exists() 0226 { 0227 return QDBusConnection::systemBus().interface()->isServiceRegistered(QStringLiteral("org.freedesktop.login1")); 0228 } 0229 0230 ConsoleKitSessionBackend::ConsoleKitSessionBackend() 0231 { 0232 m_ck = new OrgFreedesktopConsoleKitManagerInterface(QStringLiteral("org.freedesktop.ConsoleKit"), 0233 QStringLiteral("/org/freedesktop/ConsoleKit/Manager"), 0234 QDBusConnection::systemBus(), 0235 this); 0236 m_upower = new OrgFreedesktopUPowerInterface(QStringLiteral("org.freedesktop.UPower"), 0237 QStringLiteral("/org/freedesktop/UPower"), 0238 QDBusConnection::systemBus(), 0239 this); 0240 0241 auto canStop = m_ck->CanStop(); 0242 canStop.waitForFinished(); 0243 m_canShutdown = canStop.value(); 0244 0245 auto canRestart = m_ck->CanRestart(); 0246 canRestart.waitForFinished(); 0247 m_canReboot = canRestart.value(); 0248 0249 m_canSuspend = m_upower->canSuspend(); 0250 m_canHibernate = m_upower->canHibernate(); 0251 0252 connect(m_upower, &OrgFreedesktopUPowerInterface::NotifySleep, this, &SessionBackend::aboutToSuspend); 0253 connect(m_upower, &OrgFreedesktopUPowerInterface::Resuming, this, &SessionBackend::resumingFromSuspend); 0254 0255 m_state = SessionManagement::State::Ready; 0256 } 0257 0258 SessionManagement::State ConsoleKitSessionBackend::state() const 0259 { 0260 return m_state; 0261 } 0262 0263 void ConsoleKitSessionBackend::shutdown() 0264 { 0265 m_ck->Stop(); 0266 } 0267 0268 void ConsoleKitSessionBackend::reboot() 0269 { 0270 m_ck->Restart(); 0271 } 0272 0273 void ConsoleKitSessionBackend::suspend() 0274 { 0275 m_upower->Suspend(); 0276 } 0277 0278 void ConsoleKitSessionBackend::hibernate() 0279 { 0280 m_upower->Hibernate(); 0281 } 0282 0283 bool ConsoleKitSessionBackend::canShutdown() const 0284 { 0285 return m_canShutdown; 0286 } 0287 0288 bool ConsoleKitSessionBackend::canReboot() const 0289 { 0290 return m_canReboot; 0291 } 0292 0293 bool ConsoleKitSessionBackend::canSuspend() const 0294 { 0295 return m_canSuspend; 0296 } 0297 0298 bool ConsoleKitSessionBackend::canHibernate() const 0299 { 0300 return m_canHibernate; 0301 }