File indexing completed on 2024-05-19 05:39:09
0001 #include "shutdown.h" 0002 #include "shutdownadaptor.h" 0003 0004 #include <QCoreApplication> 0005 #include <QDBusConnection> 0006 #include <QDir> 0007 #include <QProcess> 0008 #include <QStandardPaths> 0009 0010 #include "debug.h" 0011 #include "ksmserver_interface.h" 0012 #include "kwin_interface.h" 0013 #include "sessionmanagementbackend.h" 0014 0015 Shutdown::Shutdown(QObject *parent) 0016 : QObject(parent) 0017 { 0018 new ShutdownAdaptor(this); 0019 QDBusConnection::sessionBus().registerObject(QStringLiteral("/Shutdown"), QStringLiteral("org.kde.Shutdown"), this); 0020 QDBusConnection::sessionBus().registerService(QStringLiteral("org.kde.Shutdown")); 0021 } 0022 0023 void Shutdown::logout() 0024 { 0025 startLogout(KWorkSpace::ShutdownTypeNone); 0026 } 0027 0028 void Shutdown::logoutAndShutdown() 0029 { 0030 startLogout(KWorkSpace::ShutdownTypeHalt); 0031 } 0032 0033 void Shutdown::logoutAndReboot() 0034 { 0035 startLogout(KWorkSpace::ShutdownTypeReboot); 0036 } 0037 0038 void Shutdown::startLogout(KWorkSpace::ShutdownType shutdownType) 0039 { 0040 m_shutdownType = shutdownType; 0041 0042 OrgKdeKSMServerInterfaceInterface ksmserverIface(QStringLiteral("org.kde.ksmserver"), QStringLiteral("/KSMServer"), QDBusConnection::sessionBus()); 0043 ksmserverIface.setTimeout( 0044 INT32_MAX); // KSMServer closeSession can take a long time to reply, as apps may have prompts. Value corresponds to DBUS_TIMEOUT_INFINITE 0045 0046 auto closeSessionReply = ksmserverIface.closeSession(); 0047 auto watcher = new QDBusPendingCallWatcher(closeSessionReply, this); 0048 connect(watcher, &QDBusPendingCallWatcher::finished, this, [closeSessionReply, watcher, this]() { 0049 watcher->deleteLater(); 0050 if (closeSessionReply.isError()) { 0051 qCInfo(PLASMA_SESSION) << "ksmserver failed to complete logout with error" << closeSessionReply.error().name() << " continuining with shutdown"; 0052 ksmServerComplete(); 0053 return; 0054 } 0055 if (closeSessionReply.value()) { 0056 ksmServerComplete(); 0057 } else { 0058 logoutCancelled(); 0059 } 0060 }); 0061 } 0062 0063 void Shutdown::ksmServerComplete() 0064 { 0065 OrgKdeKWinSessionInterface kwinInterface(QStringLiteral("org.kde.KWin"), QStringLiteral("/Session"), QDBusConnection::sessionBus()); 0066 kwinInterface.setTimeout(INT32_MAX); 0067 auto reply = kwinInterface.closeWaylandWindows(); 0068 auto watcher = new QDBusPendingCallWatcher(reply, this); 0069 connect(watcher, &QDBusPendingCallWatcher::finished, this, [this](QDBusPendingCallWatcher *watcher) { 0070 watcher->deleteLater(); 0071 OrgKdeKSMServerInterfaceInterface ksmserverIface(QStringLiteral("org.kde.ksmserver"), QStringLiteral("/KSMServer"), QDBusConnection::sessionBus()); 0072 auto reply = QDBusReply<bool>(*watcher); 0073 if (!reply.isValid()) { 0074 qCWarning(PLASMA_SESSION) << "KWin failed to complete logout"; 0075 ksmserverIface.resetLogout(); 0076 logoutCancelled(); 0077 return; 0078 } 0079 if (reply.value()) { 0080 logoutComplete(); 0081 } else { 0082 ksmserverIface.resetLogout(); 0083 logoutCancelled(); 0084 } 0085 }); 0086 } 0087 0088 void Shutdown::logoutCancelled() 0089 { 0090 m_shutdownType = KWorkSpace::ShutdownTypeNone; 0091 qApp->quit(); 0092 } 0093 0094 void Shutdown::logoutComplete() 0095 { 0096 runShutdownScripts(); 0097 0098 auto msg = QDBusMessage::createMethodCall(QStringLiteral("org.freedesktop.systemd1"), 0099 QStringLiteral("/org/freedesktop/systemd1"), 0100 QStringLiteral("org.freedesktop.systemd1.Manager"), 0101 QStringLiteral("StopUnit")); 0102 msg << QStringLiteral("graphical-session.target") << QStringLiteral("fail"); 0103 QDBusReply<QDBusObjectPath> reply = QDBusConnection::sessionBus().call(msg); 0104 0105 if (!reply.isValid()) { 0106 auto msg = QDBusMessage::createMethodCall(QStringLiteral("org.kde.ksmserver"), 0107 QStringLiteral("/MainApplication"), 0108 QStringLiteral("org.qtproject.Qt.QCoreApplication"), 0109 QStringLiteral("quit")); 0110 QDBusConnection::sessionBus().call(msg); 0111 0112 OrgKdeKWinSessionInterface kwinInterface(QStringLiteral("org.kde.KWin"), QStringLiteral("/Session"), QDBusConnection::sessionBus()); 0113 QDBusPendingReply<> reply = kwinInterface.quit(); 0114 reply.waitForFinished(); 0115 } 0116 0117 if (m_shutdownType == KWorkSpace::ShutdownTypeHalt) { 0118 SessionBackend::self()->shutdown(); 0119 } else if (m_shutdownType == KWorkSpace::ShutdownTypeReboot) { 0120 SessionBackend::self()->reboot(); 0121 } else { // logout 0122 qApp->quit(); 0123 } 0124 } 0125 0126 void Shutdown::runShutdownScripts() 0127 { 0128 const QStringList shutdownFolders = 0129 QStandardPaths::locateAll(QStandardPaths::GenericConfigLocation, QStringLiteral("plasma-workspace/shutdown"), QStandardPaths::LocateDirectory); 0130 for (const QString &shutDownFolder : shutdownFolders) { 0131 QDir dir(shutDownFolder); 0132 0133 const QStringList entries = dir.entryList(QDir::Files); 0134 for (const QString &file : entries) { 0135 // Don't execute backup files 0136 if (!file.endsWith(QLatin1Char('~')) && !file.endsWith(QLatin1String(".bak")) && (file[0] != QLatin1Char('%') || !file.endsWith(QLatin1Char('%'))) 0137 && (file[0] != QLatin1Char('#') || !file.endsWith(QLatin1Char('#')))) { 0138 const QString fullPath = dir.absolutePath() + QLatin1Char('/') + file; 0139 0140 qCDebug(PLASMA_SESSION) << "running shutdown script" << fullPath; 0141 QProcess::execute(fullPath, QStringList()); 0142 } 0143 } 0144 } 0145 }