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"