File indexing completed on 2024-05-05 17:45:03
0001 /* 0002 SPDX-FileCopyrightText: 2006 Aaron Seigo <aseigo@kde.org> 0003 SPDX-FileCopyrightText: 2022 Natalie Clarius <natalie_clarius@yahoo.de> 0004 0005 SPDX-License-Identifier: LGPL-2.0-only 0006 */ 0007 0008 #include "sessionrunner.h" 0009 0010 #include <KGuiItem> 0011 #include <KLocalizedString> 0012 #include <KMessageBox> 0013 #include <KSharedConfig> 0014 0015 K_PLUGIN_CLASS_WITH_JSON(SessionRunner, "plasma-runner-sessions.json") 0016 0017 SessionRunner::SessionRunner(QObject *parent, const KPluginMetaData &metaData, const QVariantList &args) 0018 : Plasma::AbstractRunner(parent, metaData, args) 0019 { 0020 setObjectName(QStringLiteral("Sessions")); 0021 setPriority(LowPriority); 0022 0023 m_logoutKeywords = i18nc("KRunner keywords (split by semicolons without whitespace) to log out of the session", "logout;log out") 0024 .split(QLatin1Char(';'), Qt::SkipEmptyParts); 0025 if (m_session.canLogout()) { 0026 Plasma::RunnerSyntax logoutSyntax(m_logoutKeywords.first(), i18n("Logs out, exiting the current desktop session")); 0027 for (QString keyword : m_logoutKeywords.mid(1)) { 0028 logoutSyntax.addExampleQuery(keyword); 0029 } 0030 addSyntax(logoutSyntax); 0031 } 0032 0033 m_shutdownKeywords = i18nc("KRunner keywords (split by semicolons without whitespace) to shut down the computer", "shutdown;shut down") 0034 .split(QLatin1Char(';'), Qt::SkipEmptyParts); 0035 if (m_session.canShutdown()) { 0036 Plasma::RunnerSyntax shutdownSyntax(m_shutdownKeywords.first(), i18n("Turns off the computer")); 0037 for (QString keyword : m_shutdownKeywords.mid(1)) { 0038 shutdownSyntax.addExampleQuery(keyword); 0039 } 0040 addSyntax(shutdownSyntax); 0041 } 0042 0043 m_restartKeywords = i18nc("KRunner keywords (split by semicolons without whitespace) to restart the computer", "restart;reboot") 0044 .split(QLatin1Char(';'), Qt::SkipEmptyParts); 0045 if (m_session.canReboot()) { 0046 Plasma::RunnerSyntax restartSyntax(m_restartKeywords.first(), i18n("Reboots the computer")); 0047 for (QString keyword : m_restartKeywords.mid(1)) { 0048 restartSyntax.addExampleQuery(keyword); 0049 } 0050 addSyntax(restartSyntax); 0051 } 0052 0053 m_lockKeywords = 0054 i18nc("KRunner keywords (split by semicolons without whitespace) to lock the screen", "lock;lock screen").split(QLatin1Char(';'), Qt::SkipEmptyParts); 0055 if (m_session.canLock()) { 0056 Plasma::RunnerSyntax lockSyntax(m_lockKeywords.first(), i18n("Locks the current sessions and starts the screen saver")); 0057 for (QString keyword : m_lockKeywords.mid(1)) { 0058 lockSyntax.addExampleQuery(keyword); 0059 } 0060 addSyntax(lockSyntax); 0061 } 0062 0063 m_saveKeywords = i18nc("KRunner keywords (split by semicolons without whitespace) to save the desktop session", "save;save session") 0064 .split(QLatin1Char(';'), Qt::SkipEmptyParts); 0065 if (m_session.canSaveSession()) { 0066 Plasma::RunnerSyntax saveSyntax(m_saveKeywords.first(), i18n("Saves the current session for session restoration")); 0067 for (QString keyword : m_saveKeywords.mid(1)) { 0068 saveSyntax.addExampleQuery(keyword); 0069 } 0070 addSyntax(saveSyntax); 0071 } 0072 0073 m_usersKeywords = i18nc("KRunner keywords (split by semicolons without whitespace) to switch user sessions", "switch user;new session") 0074 .split(QLatin1Char(';'), Qt::SkipEmptyParts); 0075 if (m_session.canSwitchUser()) { 0076 Plasma::RunnerSyntax usersSyntax(m_usersKeywords.first(), i18n("Starts a new session as a different user")); 0077 for (QString keyword : m_usersKeywords.mid(1)) { 0078 usersSyntax.addExampleQuery(keyword); 0079 } 0080 addSyntax(usersSyntax); 0081 } 0082 0083 m_sessionsKeyword = i18nc("KRunner keyword to list user sessions", "sessions"); 0084 Plasma::RunnerSyntax sessionsSyntax(m_sessionsKeyword, i18n("Lists all sessions")); 0085 addSyntax(sessionsSyntax); 0086 0087 m_switchKeyword = i18nc("KRunner keyword to switch user sessions", "switch"); 0088 Plasma::RunnerSyntax switchSyntax(m_switchKeyword + QStringLiteral(" :q:"), 0089 i18n("Switches to the active session for the user :q:, or lists all active sessions if :q: is not provided")); 0090 addSyntax(switchSyntax); 0091 0092 setMinLetterCount(3); 0093 } 0094 0095 SessionRunner::~SessionRunner() 0096 { 0097 } 0098 0099 static inline bool anyKeywordMatches(const QStringList &keywords, const QString &term) 0100 { 0101 return std::any_of(keywords.cbegin(), keywords.cend(), [&term](const QString &keyword) { 0102 return term.compare(keyword, Qt::CaseInsensitive) == 0; 0103 }); 0104 } 0105 0106 void SessionRunner::matchCommands(QList<Plasma::QueryMatch> &matches, const QString &term) 0107 { 0108 if (anyKeywordMatches(m_logoutKeywords, term)) { 0109 if (m_session.canLogout()) { 0110 Plasma::QueryMatch match(this); 0111 match.setText(i18nc("log out command", "Log Out")); 0112 match.setIconName(QStringLiteral("system-log-out")); 0113 match.setData(LogoutAction); 0114 match.setType(Plasma::QueryMatch::ExactMatch); 0115 match.setRelevance(0.9); 0116 matches << match; 0117 } 0118 } else if (anyKeywordMatches(m_shutdownKeywords, term)) { 0119 if (m_session.canShutdown()) { 0120 Plasma::QueryMatch match(this); 0121 match.setText(i18nc("turn off computer command", "Shut Down")); 0122 match.setIconName(QStringLiteral("system-shutdown")); 0123 match.setData(ShutdownAction); 0124 match.setType(Plasma::QueryMatch::ExactMatch); 0125 match.setRelevance(0.9); 0126 matches << match; 0127 } 0128 } else if (anyKeywordMatches(m_restartKeywords, term)) { 0129 if (m_session.canReboot()) { 0130 Plasma::QueryMatch match(this); 0131 match.setText(i18nc("restart computer command", "Restart")); 0132 match.setIconName(QStringLiteral("system-reboot")); 0133 match.setData(RestartAction); 0134 match.setType(Plasma::QueryMatch::ExactMatch); 0135 match.setRelevance(0.9); 0136 matches << match; 0137 } 0138 } else if (anyKeywordMatches(m_lockKeywords, term)) { 0139 if (m_session.canLock()) { 0140 Plasma::QueryMatch match(this); 0141 match.setText(i18nc("lock screen command", "Lock")); 0142 match.setIconName(QStringLiteral("system-lock-screen")); 0143 match.setData(LockAction); 0144 match.setType(Plasma::QueryMatch::ExactMatch); 0145 match.setRelevance(0.9); 0146 matches << match; 0147 } 0148 } else if (anyKeywordMatches(m_saveKeywords, term)) { 0149 if (m_session.canSaveSession()) { 0150 Plasma::QueryMatch match(this); 0151 match.setText(i18n("Save Session")); 0152 match.setIconName(QStringLiteral("system-save-session")); 0153 match.setData(SaveAction); 0154 match.setType(Plasma::QueryMatch::ExactMatch); 0155 match.setRelevance(0.9); 0156 matches << match; 0157 } 0158 } 0159 } 0160 0161 void SessionRunner::match(Plasma::RunnerContext &context) 0162 { 0163 const QString term = context.query(); 0164 QString user; 0165 bool matchUser = false; 0166 0167 QList<Plasma::QueryMatch> matches; 0168 0169 // first compare with "sessions" keyword 0170 // "SESSIONS" must *NOT* be translated (i18n) 0171 // as it is used as an internal command trigger (e.g. via d-bus), 0172 // not as a user supplied query. and yes, "Ugh, magic strings" 0173 bool listAll = anyKeywordMatches(QStringList({QStringLiteral("SESSIONS"), m_sessionsKeyword}), term); 0174 0175 if (!listAll) { 0176 // no luck, try the "switch" user command 0177 if (term.startsWith(m_switchKeyword, Qt::CaseInsensitive)) { 0178 user = term.right(term.size() - m_switchKeyword.length()).trimmed(); 0179 listAll = user.isEmpty(); 0180 matchUser = !listAll; 0181 } else { 0182 // we know it's not "sessions" or "switch <something>", so let's 0183 // try some other possibilities 0184 matchCommands(matches, term); 0185 } 0186 } 0187 0188 bool switchUser = listAll || anyKeywordMatches(m_usersKeywords, term); 0189 0190 if (switchUser && m_session.canSwitchUser() && dm.isSwitchable() && dm.numReserve() >= 0) { 0191 Plasma::QueryMatch match(this); 0192 match.setType(Plasma::QueryMatch::ExactMatch); 0193 match.setIconName(QStringLiteral("system-switch-user")); 0194 match.setText(i18n("Switch User")); 0195 matches << match; 0196 } 0197 0198 // now add the active sessions 0199 if (listAll || matchUser) { 0200 SessList sessions; 0201 dm.localSessions(sessions); 0202 0203 for (const SessEnt &session : qAsConst(sessions)) { 0204 if (!session.vt || session.self) { 0205 continue; 0206 } 0207 0208 QString name = KDisplayManager::sess2Str(session); 0209 Plasma::QueryMatch::Type type = Plasma::QueryMatch::NoMatch; 0210 qreal relevance = 0.7; 0211 0212 if (listAll) { 0213 type = Plasma::QueryMatch::ExactMatch; 0214 relevance = 1; 0215 } else if (matchUser) { 0216 if (name.compare(user, Qt::CaseInsensitive) == 0) { 0217 // we need an elif branch here because we don't 0218 // want the last conditional to be checked if !listAll 0219 type = Plasma::QueryMatch::ExactMatch; 0220 relevance = 1; 0221 } else if (name.contains(user, Qt::CaseInsensitive)) { 0222 type = Plasma::QueryMatch::PossibleMatch; 0223 } 0224 } 0225 0226 if (type != Plasma::QueryMatch::NoMatch) { 0227 Plasma::QueryMatch match(this); 0228 match.setType(type); 0229 match.setRelevance(relevance); 0230 match.setIconName(QStringLiteral("user-identity")); 0231 match.setText(name); 0232 match.setData(QString::number(session.vt)); 0233 matches << match; 0234 } 0235 } 0236 } 0237 0238 context.addMatches(matches); 0239 } 0240 0241 void SessionRunner::run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &match) 0242 { 0243 Q_UNUSED(context); 0244 if (match.data().type() == QVariant::Int) { 0245 switch (match.data().toInt()) { 0246 case LogoutAction: 0247 m_session.requestLogout(); 0248 break; 0249 case RestartAction: 0250 m_session.requestReboot(); 0251 break; 0252 case ShutdownAction: 0253 m_session.requestShutdown(); 0254 break; 0255 case LockAction: 0256 m_session.lock(); 0257 break; 0258 case SaveAction: 0259 m_session.saveSession(); 0260 break; 0261 } 0262 return; 0263 } 0264 0265 if (!match.data().toString().isEmpty()) { 0266 dm.lockSwitchVT(match.data().toString().toInt()); 0267 return; 0268 } 0269 0270 const auto config = KSharedConfig::openConfig(QStringLiteral("ksmserverrc")); 0271 KMessageBox::setDontShowAgainConfig(config.data()); 0272 KGuiItem continueButton = KStandardGuiItem::cont(); 0273 continueButton.setText("Enter new session"); 0274 KGuiItem cancelButton = KStandardGuiItem::cancel(); 0275 cancelButton.setText("Stay in current session"); 0276 KMessageBox::ButtonCode confirmNewSession = 0277 KMessageBox::warningContinueCancel(nullptr, 0278 i18n("<p>You are about to enter a new desktop session.</p>" 0279 "<p>A login screen will be displayed and the current session will be hidden.</p>" 0280 "<p>You can switch between desktop sessions using:</p>" 0281 "<ul>" 0282 "<li>Ctrl+Alt+F{number of session}</li>" 0283 "<li>Plasma search (type '%1')</li>" 0284 "<li>Plasma widgets (such as the application launcher)</li>" 0285 "</ul>", 0286 m_switchKeyword), 0287 i18n("New Desktop Session"), 0288 continueButton, 0289 cancelButton, 0290 QStringLiteral("ConfirmNewSession")); 0291 if (confirmNewSession == KMessageBox::Continue) { 0292 m_session.lock(); 0293 dm.startReserve(); 0294 } 0295 } 0296 0297 #include "sessionrunner.moc"