File indexing completed on 2024-05-19 09:31:19
0001 /* 0002 SPDX-FileCopyrightText: 2019 David Edmundson <davidedmundson@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "sessionmanagement.h" 0008 0009 #include "sessionmanagementbackend.h" 0010 0011 #include <KAuthorized> 0012 #include <KConfigGroup> 0013 #include <KSharedConfig> 0014 0015 #include <iostream> 0016 0017 #include "ksmserver_interface.h" 0018 #include "logoutprompt_interface.h" 0019 #include "screenlocker_interface.h" 0020 #include "shutdown_interface.h" 0021 0022 #include "libkworkspace_debug.h" 0023 0024 using namespace Qt::StringLiterals; 0025 0026 // add a constructor with the service names and paths pre-populated 0027 class LogoutPromptIface : public OrgKdeLogoutPromptInterface 0028 { 0029 Q_OBJECT 0030 public: 0031 LogoutPromptIface() 0032 : OrgKdeLogoutPromptInterface(QStringLiteral("org.kde.LogoutPrompt"), QStringLiteral("/LogoutPrompt"), QDBusConnection::sessionBus()) 0033 { 0034 } 0035 }; 0036 0037 class ShutdownIface : public OrgKdeShutdownInterface 0038 { 0039 Q_OBJECT 0040 public: 0041 ShutdownIface() 0042 : OrgKdeShutdownInterface(QStringLiteral("org.kde.Shutdown"), QStringLiteral("/Shutdown"), QDBusConnection::sessionBus()) 0043 { 0044 } 0045 }; 0046 0047 SessionManagement::SessionManagement(QObject *parent) 0048 : QObject(parent) 0049 { 0050 auto backend = SessionBackend::self(); 0051 connect(backend, &SessionBackend::stateChanged, this, &SessionManagement::stateChanged); 0052 connect(backend, &SessionBackend::canShutdownChanged, this, &SessionManagement::canShutdownChanged); 0053 connect(backend, &SessionBackend::canRebootChanged, this, &SessionManagement::canRebootChanged); 0054 connect(backend, &SessionBackend::canSuspendChanged, this, &SessionManagement::canSuspendChanged); 0055 connect(backend, &SessionBackend::canHybridSuspendChanged, this, &SessionManagement::canHybridSuspendChanged); 0056 connect(backend, &SessionBackend::canHibernateChanged, this, &SessionManagement::canHibernateChanged); 0057 connect(backend, &SessionBackend::canSuspendThenHibernateChanged, this, &SessionManagement::canSuspendThenHibernateChanged); 0058 connect(backend, &SessionBackend::aboutToSuspend, this, &SessionManagement::aboutToSuspend); 0059 connect(backend, &SessionBackend::resumingFromSuspend, this, &SessionManagement::resumingFromSuspend); 0060 } 0061 0062 bool SessionManagement::canShutdown() const 0063 { 0064 return canLogout() && SessionBackend::self()->canShutdown(); 0065 } 0066 0067 bool SessionManagement::canReboot() const 0068 { 0069 return canLogout() && SessionBackend::self()->canReboot(); 0070 } 0071 0072 bool SessionManagement::canLogout() const 0073 { 0074 // checking both is for compatibility with old kiosk configs 0075 // authorizeAction is the "correct" one 0076 return KAuthorized::authorizeAction(QStringLiteral("logout")) && KAuthorized::authorize(QStringLiteral("logout")); 0077 } 0078 0079 bool SessionManagement::canSuspend() const 0080 { 0081 return SessionBackend::self()->canSuspend(); 0082 } 0083 0084 bool SessionManagement::canHybridSuspend() const 0085 { 0086 return SessionBackend::self()->canHybridSuspend(); 0087 } 0088 0089 bool SessionManagement::canHibernate() const 0090 { 0091 return SessionBackend::self()->canHibernate(); 0092 } 0093 0094 bool SessionManagement::canSuspendThenHibernate() const 0095 { 0096 return SessionBackend::self()->canSuspendThenHibernate(); 0097 } 0098 0099 bool SessionManagement::canSwitchUser() const 0100 { 0101 return KAuthorized::authorizeAction(QStringLiteral("start_new_session")) && SessionBackend::self()->canSwitchUser(); 0102 } 0103 0104 bool SessionManagement::canLock() const 0105 { 0106 return KAuthorized::authorizeAction(QStringLiteral("lock_screen")); 0107 } 0108 0109 bool SessionManagement::canSaveSession() const 0110 { 0111 const KConfigGroup c(KSharedConfig::openConfig(u"ksmserverrc"_s), u"General"_s); 0112 return canLogout() && c.readEntry("loginMode") == QLatin1String("restoreSavedSession"); 0113 } 0114 0115 SessionManagement::State SessionManagement::state() const 0116 { 0117 return SessionBackend::self()->state(); 0118 } 0119 0120 void SessionManagement::requestShutdown(ConfirmationMode confirmationMode) 0121 { 0122 if (!canShutdown()) { 0123 return; 0124 } 0125 0126 if (qEnvironmentVariableIntValue("PLASMA_SESSION_GUI_TEST")) { 0127 std::cout << "shutdown" << std::endl; 0128 return; 0129 } 0130 0131 bool confirm = confirmationMode == ConfirmationMode::ForcePrompt; 0132 if (confirmationMode == ConfirmationMode::Default) { 0133 confirm = SessionBackend::self()->confirmLogout(); 0134 } 0135 if (confirm) { 0136 LogoutPromptIface iface; 0137 iface.promptShutDown().waitForFinished(); 0138 } else { 0139 ShutdownIface iface; 0140 iface.logoutAndShutdown().waitForFinished(); 0141 } 0142 } 0143 0144 void SessionManagement::requestReboot(ConfirmationMode confirmationMode) 0145 { 0146 if (!canReboot()) { 0147 return; 0148 } 0149 0150 if (qEnvironmentVariableIntValue("PLASMA_SESSION_GUI_TEST")) { 0151 std::cout << "reboot" << std::endl; 0152 return; 0153 } 0154 0155 bool confirm = confirmationMode == ConfirmationMode::ForcePrompt; 0156 if (confirmationMode == ConfirmationMode::Default) { 0157 confirm = SessionBackend::self()->confirmLogout(); 0158 } 0159 if (confirm) { 0160 LogoutPromptIface iface; 0161 iface.promptReboot().waitForFinished(); 0162 } else { 0163 ShutdownIface iface; 0164 iface.logoutAndReboot().waitForFinished(); 0165 } 0166 } 0167 0168 void SessionManagement::requestLogout(ConfirmationMode confirmationMode) 0169 { 0170 if (!canLogout()) { 0171 return; 0172 } 0173 bool confirm = confirmationMode == ConfirmationMode::ForcePrompt; 0174 if (confirmationMode == ConfirmationMode::Default) { 0175 confirm = SessionBackend::self()->confirmLogout(); 0176 } 0177 if (confirm) { 0178 LogoutPromptIface iface; 0179 iface.promptLogout().waitForFinished(); 0180 } else { 0181 ShutdownIface iface; 0182 iface.logout().waitForFinished(); 0183 } 0184 } 0185 0186 void SessionManagement::suspend() 0187 { 0188 if (!canSuspend()) { 0189 return; 0190 } 0191 SessionBackend::self()->suspend(); 0192 } 0193 0194 void SessionManagement::hybridSuspend() 0195 { 0196 if (!canHybridSuspend()) { 0197 return; 0198 } 0199 SessionBackend::self()->hybridSuspend(); 0200 } 0201 0202 void SessionManagement::hibernate() 0203 { 0204 if (!canHibernate()) { 0205 return; 0206 } 0207 SessionBackend::self()->hibernate(); 0208 } 0209 0210 void SessionManagement::suspendThenHibernate() 0211 { 0212 if (!canSuspendThenHibernate()) { 0213 return; 0214 } 0215 SessionBackend::self()->suspendThenHibernate(); 0216 } 0217 0218 void SessionManagement::lock() 0219 { 0220 if (!canLock()) { 0221 return; 0222 } 0223 OrgFreedesktopScreenSaverInterface iface(QStringLiteral("org.freedesktop.ScreenSaver"), QStringLiteral("/ScreenSaver"), QDBusConnection::sessionBus()); 0224 iface.Lock(); 0225 } 0226 0227 void SessionManagement::switchUser() 0228 { 0229 if (!canSwitchUser() || !canLock()) { 0230 return; 0231 } 0232 0233 if (!qEnvironmentVariableIsSet("XDG_SEAT_PATH")) { 0234 qCWarning(LIBKWORKSPACE_DEBUG) << "Cannot switch user: XDG_SEAT_PATH not set"; 0235 return; 0236 } 0237 0238 // lock first 0239 OrgFreedesktopScreenSaverInterface screenSaverIface(QStringLiteral("org.freedesktop.ScreenSaver"), 0240 QStringLiteral("/ScreenSaver"), 0241 QDBusConnection::sessionBus()); 0242 QDBusPendingReply<> pendingLock = screenSaverIface.Lock(); 0243 0244 // then tell the display manager to switch 0245 auto watcher = new QDBusPendingCallWatcher(pendingLock, this); 0246 connect(watcher, &QDBusPendingCallWatcher::finished, watcher, &QObject::deleteLater); 0247 connect(watcher, &QDBusPendingCallWatcher::finished, this, [](QDBusPendingCallWatcher *watcher) { 0248 if (watcher->isError()) { 0249 qCWarning(LIBKWORKSPACE_DEBUG) << "Failed to lock screen before switching user:" << watcher->error().message(); 0250 return; 0251 } 0252 QDBusMessage switchToGreeterMessage = QDBusMessage::createMethodCall(QStringLiteral("org.freedesktop.DisplayManager"), 0253 qgetenv("XDG_SEAT_PATH"), 0254 QStringLiteral("org.freedesktop.DisplayManager.Seat"), 0255 "SwitchToGreeter"); 0256 0257 QDBusConnection::systemBus().asyncCall(switchToGreeterMessage); 0258 }); 0259 } 0260 0261 void SessionManagement::saveSession() 0262 { 0263 if (!canSaveSession()) { 0264 return; 0265 } 0266 OrgKdeKSMServerInterfaceInterface ksmserver(QStringLiteral("org.kde.ksmserver"), QStringLiteral("/KSMServer"), QDBusConnection::sessionBus()); 0267 ksmserver.saveCurrentSession(); 0268 } 0269 0270 #include "sessionmanagement.moc"