File indexing completed on 2024-04-28 05:35:36
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 #include <iostream> 0019 0020 #include "login1_manager_interface.h" 0021 0022 static SessionBackend *s_backend = nullptr; 0023 0024 SessionBackend *SessionBackend::self() 0025 { 0026 static QMutex mutex; 0027 QMutexLocker lock(&mutex); 0028 0029 if (s_backend) { 0030 return s_backend; 0031 } 0032 0033 if (qEnvironmentVariableIntValue("PLASMA_SESSION_GUI_TEST")) { 0034 s_backend = new TestSessionBackend(); 0035 } else if (LogindSessionBackend::exists()) { 0036 s_backend = new LogindSessionBackend(); 0037 } else { 0038 s_backend = new DummySessionBackend(); 0039 } 0040 0041 return s_backend; 0042 } 0043 0044 SessionBackend::SessionBackend() 0045 : m_kserverConfig(KConfigWatcher::create(KSharedConfig::openConfig(QStringLiteral("ksmserverrc")))) 0046 { 0047 } 0048 0049 bool SessionBackend::confirmLogout() const 0050 { 0051 return m_kserverConfig->config()->group(QStringLiteral("General")).readEntry("confirmLogout", true); 0052 } 0053 0054 bool SessionBackend::canSwitchUser() const 0055 { 0056 return false; 0057 } 0058 0059 DummySessionBackend::DummySessionBackend() 0060 { 0061 qCritical() << "Could not load a session backend. Session management operations such as shutdown will not be operational. This is a setup issue."; 0062 } 0063 0064 TestSessionBackend::TestSessionBackend() 0065 { 0066 qWarning() << "This backend is intended for gui autotesting only, it will not be operational"; 0067 } 0068 0069 void TestSessionBackend::shutdown() 0070 { 0071 std::cout << "shutdown" << std::endl; 0072 } 0073 0074 void TestSessionBackend::reboot() 0075 { 0076 std::cout << "reboot" << std::endl; 0077 } 0078 0079 void TestSessionBackend::suspend() 0080 { 0081 std::cout << "suspend" << std::endl; 0082 } 0083 0084 void TestSessionBackend::hybridSuspend() 0085 { 0086 std::cout << "hybridSuspend" << std::endl; 0087 } 0088 0089 void TestSessionBackend::hibernate() 0090 { 0091 std::cout << "hibernate" << std::endl; 0092 } 0093 0094 void TestSessionBackend::suspendThenHibernate() 0095 { 0096 std::cout << "suspendThenHibernate" << std::endl; 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 Q_EMIT canSuspendThenHibernateChanged(); 0131 } 0132 }; 0133 0134 m_pendingJobs = 5; 0135 { 0136 auto watcher = new QDBusPendingCallWatcher(m_login1->CanPowerOff(), this); 0137 connect(watcher, &QDBusPendingCallWatcher::finished, this, std::bind(propLoaded, std::placeholders::_1, &m_canShutdown)); 0138 } 0139 { 0140 auto watcher = new QDBusPendingCallWatcher(m_login1->CanReboot(), this); 0141 connect(watcher, &QDBusPendingCallWatcher::finished, this, std::bind(propLoaded, std::placeholders::_1, &m_canReboot)); 0142 } 0143 { 0144 auto watcher = new QDBusPendingCallWatcher(m_login1->CanSuspend(), this); 0145 connect(watcher, &QDBusPendingCallWatcher::finished, this, std::bind(propLoaded, std::placeholders::_1, &m_canSuspend)); 0146 } 0147 { 0148 auto watcher = new QDBusPendingCallWatcher(m_login1->CanHybridSleep(), this); 0149 connect(watcher, &QDBusPendingCallWatcher::finished, this, std::bind(propLoaded, std::placeholders::_1, &m_canHybridSuspend)); 0150 } 0151 { 0152 auto watcher = new QDBusPendingCallWatcher(m_login1->CanHibernate(), this); 0153 connect(watcher, &QDBusPendingCallWatcher::finished, this, std::bind(propLoaded, std::placeholders::_1, &m_canHibernate)); 0154 } 0155 { 0156 auto watcher = new QDBusPendingCallWatcher(m_login1->CanSuspendThenHibernate(), this); 0157 connect(watcher, &QDBusPendingCallWatcher::finished, this, std::bind(propLoaded, std::placeholders::_1, &m_canSuspendThenHibernate)); 0158 } 0159 0160 connect(m_login1, &OrgFreedesktopLogin1ManagerInterface::PrepareForSleep, this, [this](bool sleeping) { 0161 if (sleeping) { 0162 Q_EMIT aboutToSuspend(); 0163 } else { 0164 Q_EMIT resumingFromSuspend(); 0165 } 0166 }); 0167 } 0168 0169 SessionManagement::State LogindSessionBackend::state() const 0170 { 0171 return m_state; 0172 } 0173 0174 void LogindSessionBackend::shutdown() 0175 { 0176 // logind will confirm credentials with the caller, if the app quits after sending this 0177 // this may fail 0178 m_login1->PowerOff(true).waitForFinished(); 0179 } 0180 0181 void LogindSessionBackend::reboot() 0182 { 0183 m_login1->Reboot(true).waitForFinished(); 0184 } 0185 0186 void LogindSessionBackend::suspend() 0187 { 0188 // these need to be synchronous as well - ksmserver-logout-greeter specifically calls these 0189 // and will quit immediately after 0190 m_login1->Suspend(true).waitForFinished(); 0191 } 0192 0193 void LogindSessionBackend::hybridSuspend() 0194 { 0195 m_login1->HybridSleep(true).waitForFinished(); 0196 } 0197 0198 void LogindSessionBackend::hibernate() 0199 { 0200 m_login1->Hibernate(true).waitForFinished(); 0201 } 0202 0203 void LogindSessionBackend::suspendThenHibernate() 0204 { 0205 m_login1->SuspendThenHibernate(true).waitForFinished(); 0206 } 0207 0208 bool LogindSessionBackend::canShutdown() const 0209 { 0210 return m_canShutdown; 0211 } 0212 0213 bool LogindSessionBackend::canReboot() const 0214 { 0215 return m_canReboot; 0216 } 0217 0218 bool LogindSessionBackend::canSuspend() const 0219 { 0220 return m_canSuspend; 0221 } 0222 0223 bool LogindSessionBackend::canHybridSuspend() const 0224 { 0225 return m_canHybridSuspend; 0226 } 0227 0228 bool LogindSessionBackend::canHibernate() const 0229 { 0230 return m_canHibernate; 0231 } 0232 0233 bool LogindSessionBackend::canSuspendThenHibernate() const 0234 { 0235 return m_canSuspendThenHibernate; 0236 } 0237 0238 bool LogindSessionBackend::canSwitchUser() const 0239 { 0240 return true; 0241 }