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 "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::requestLogoutPrompt() 0121 { 0122 if (qEnvironmentVariableIntValue("PLASMA_SESSION_GUI_TEST")) { 0123 std::cout << "show logout prompt " << std::endl; 0124 return; 0125 } 0126 0127 // Don't bother to check for whether the user normally wants confirmation or 0128 // not; if this function was invoked, it means they do want to see the logout 0129 // prompt right now 0130 LogoutPromptIface iface; 0131 iface.promptAll().waitForFinished(); 0132 } 0133 0134 void SessionManagement::requestShutdown(ConfirmationMode confirmationMode) 0135 { 0136 if (!canShutdown()) { 0137 return; 0138 } 0139 0140 if (qEnvironmentVariableIntValue("PLASMA_SESSION_GUI_TEST")) { 0141 std::cout << "shutdown" << std::endl; 0142 return; 0143 } 0144 0145 bool confirm = confirmationMode == ConfirmationMode::ForcePrompt; 0146 if (confirmationMode == ConfirmationMode::Default) { 0147 confirm = SessionBackend::self()->confirmLogout(); 0148 } 0149 if (confirm) { 0150 LogoutPromptIface iface; 0151 iface.promptShutDown().waitForFinished(); 0152 } else { 0153 ShutdownIface iface; 0154 iface.logoutAndShutdown().waitForFinished(); 0155 } 0156 } 0157 0158 void SessionManagement::requestReboot(ConfirmationMode confirmationMode) 0159 { 0160 if (!canReboot()) { 0161 return; 0162 } 0163 0164 if (qEnvironmentVariableIntValue("PLASMA_SESSION_GUI_TEST")) { 0165 std::cout << "reboot" << std::endl; 0166 return; 0167 } 0168 0169 bool confirm = confirmationMode == ConfirmationMode::ForcePrompt; 0170 if (confirmationMode == ConfirmationMode::Default) { 0171 confirm = SessionBackend::self()->confirmLogout(); 0172 } 0173 if (confirm) { 0174 LogoutPromptIface iface; 0175 iface.promptReboot().waitForFinished(); 0176 } else { 0177 ShutdownIface iface; 0178 iface.logoutAndReboot().waitForFinished(); 0179 } 0180 } 0181 0182 void SessionManagement::requestLogout(ConfirmationMode confirmationMode) 0183 { 0184 if (!canLogout()) { 0185 return; 0186 } 0187 bool confirm = confirmationMode == ConfirmationMode::ForcePrompt; 0188 if (confirmationMode == ConfirmationMode::Default) { 0189 confirm = SessionBackend::self()->confirmLogout(); 0190 } 0191 if (confirm) { 0192 LogoutPromptIface iface; 0193 iface.promptLogout().waitForFinished(); 0194 } else { 0195 ShutdownIface iface; 0196 iface.logout().waitForFinished(); 0197 } 0198 } 0199 0200 void SessionManagement::suspend() 0201 { 0202 if (!canSuspend()) { 0203 return; 0204 } 0205 SessionBackend::self()->suspend(); 0206 } 0207 0208 void SessionManagement::hybridSuspend() 0209 { 0210 if (!canHybridSuspend()) { 0211 return; 0212 } 0213 SessionBackend::self()->hybridSuspend(); 0214 } 0215 0216 void SessionManagement::hibernate() 0217 { 0218 if (!canHibernate()) { 0219 return; 0220 } 0221 SessionBackend::self()->hibernate(); 0222 } 0223 0224 void SessionManagement::suspendThenHibernate() 0225 { 0226 if (!canSuspendThenHibernate()) { 0227 return; 0228 } 0229 SessionBackend::self()->suspendThenHibernate(); 0230 } 0231 0232 void SessionManagement::lock() 0233 { 0234 if (!canLock()) { 0235 return; 0236 } 0237 OrgFreedesktopScreenSaverInterface iface(QStringLiteral("org.freedesktop.ScreenSaver"), QStringLiteral("/ScreenSaver"), QDBusConnection::sessionBus()); 0238 iface.Lock(); 0239 } 0240 0241 void SessionManagement::switchUser() 0242 { 0243 if (!canSwitchUser() || !canLock()) { 0244 return; 0245 } 0246 0247 if (!qEnvironmentVariableIsSet("XDG_SEAT_PATH")) { 0248 qCWarning(LIBKWORKSPACE_DEBUG) << "Cannot switch user: XDG_SEAT_PATH not set"; 0249 return; 0250 } 0251 0252 // lock first 0253 OrgFreedesktopScreenSaverInterface screenSaverIface(QStringLiteral("org.freedesktop.ScreenSaver"), 0254 QStringLiteral("/ScreenSaver"), 0255 QDBusConnection::sessionBus()); 0256 QDBusPendingReply<> pendingLock = screenSaverIface.Lock(); 0257 0258 // then tell the display manager to switch 0259 auto watcher = new QDBusPendingCallWatcher(pendingLock, this); 0260 connect(watcher, &QDBusPendingCallWatcher::finished, watcher, &QObject::deleteLater); 0261 connect(watcher, &QDBusPendingCallWatcher::finished, this, [](QDBusPendingCallWatcher *watcher) { 0262 if (watcher->isError()) { 0263 qCWarning(LIBKWORKSPACE_DEBUG) << "Failed to lock screen before switching user:" << watcher->error().message(); 0264 return; 0265 } 0266 QDBusMessage switchToGreeterMessage = QDBusMessage::createMethodCall(QStringLiteral("org.freedesktop.DisplayManager"), 0267 qgetenv("XDG_SEAT_PATH"), 0268 QStringLiteral("org.freedesktop.DisplayManager.Seat"), 0269 "SwitchToGreeter"); 0270 0271 QDBusConnection::systemBus().asyncCall(switchToGreeterMessage); 0272 }); 0273 } 0274 0275 void SessionManagement::saveSession() 0276 { 0277 if (!canSaveSession()) { 0278 return; 0279 } 0280 OrgKdeKSMServerInterfaceInterface ksmserver(QStringLiteral("org.kde.ksmserver"), QStringLiteral("/KSMServer"), QDBusConnection::sessionBus()); 0281 ksmserver.saveCurrentSession(); 0282 } 0283 0284 #include "sessionmanagement.moc"