File indexing completed on 2024-05-05 17:45:02
0001 /* 0002 SPDX-FileCopyrightText: 2008 Dario Freddi <drf@kdemod.ath.cx> 0003 SPDX-FileCopyrightText: 2008 Sebastian Kügler <sebas@kde.org> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include "PowerDevilRunner.h" 0009 0010 // kde-workspace/libs 0011 #include <sessionmanagement.h> 0012 0013 #include <QDBusConnectionInterface> 0014 #include <QDBusInterface> 0015 #include <QDBusReply> 0016 #include <QDebug> 0017 #include <QIcon> 0018 0019 #include <KLocalizedString> 0020 #include <KSharedConfig> 0021 0022 #include <cmath> 0023 0024 K_PLUGIN_CLASS_WITH_JSON(PowerDevilRunner, "plasma-runner-powerdevil.json") 0025 0026 PowerDevilRunner::PowerDevilRunner(QObject *parent, const KPluginMetaData &metaData, const QVariantList &args) 0027 : Plasma::AbstractRunner(parent, metaData, args) 0028 , m_session(new SessionManagement(this)) 0029 { 0030 setObjectName(QStringLiteral("PowerDevil")); 0031 setMinLetterCount(3); 0032 const KLocalizedString suspend = ki18nc("Note this is a KRunner keyword", "suspend"); 0033 m_suspend = RunnerKeyword{suspend.untranslatedText(), suspend.toString()}; 0034 const KLocalizedString toRam = ki18nc("Note this is a KRunner keyword", "to ram"); 0035 m_toRam = RunnerKeyword{toRam.untranslatedText(), toRam.toString(), false}; 0036 const KLocalizedString sleep = ki18nc("Note this is a KRunner keyword", "sleep"); 0037 m_sleep = RunnerKeyword{sleep.untranslatedText(), sleep.toString()}; 0038 const KLocalizedString hibernate = ki18nc("Note this is a KRunner keyword", "hibernate"); 0039 m_hibernate = RunnerKeyword{hibernate.untranslatedText(), hibernate.toString()}; 0040 const KLocalizedString toDisk = ki18nc("Note this is a KRunner keyword", "to disk"); 0041 m_toDisk = RunnerKeyword{toDisk.untranslatedText(), toDisk.toString(), false}; 0042 const KLocalizedString dimScreen = ki18nc("Note this is a KRunner keyword", "dim screen"); 0043 m_dimScreen = RunnerKeyword{dimScreen.untranslatedText(), dimScreen.toString()}; 0044 const KLocalizedString screenBrightness = ki18nc("Note this is a KRunner keyword", "dim screen"); 0045 m_screenBrightness = RunnerKeyword{screenBrightness.untranslatedText(), screenBrightness.toString()}; 0046 updateStatus(); 0047 } 0048 0049 void PowerDevilRunner::updateSyntaxes() 0050 { 0051 setSyntaxes({}); // Clear the existing ones 0052 addSyntaxForKeyword({m_suspend}, 0053 i18n("Lists system suspend (e.g. sleep, hibernate) options " 0054 "and allows them to be activated")); 0055 0056 if (m_session->canSuspend()) { 0057 addSyntaxForKeyword({m_sleep, m_toRam}, i18n("Suspends the system to RAM")); 0058 } 0059 0060 if (m_session->canHibernate()) { 0061 addSyntaxForKeyword({m_hibernate, m_toDisk}, i18n("Suspends the system to disk")); 0062 } 0063 0064 Plasma::RunnerSyntax brightnessSyntax( 0065 i18nc("Note this is a KRunner keyword, <> is a placeholder and should be at the end", "screen brightness <percent value>"), 0066 // xgettext:no-c-format 0067 i18n("Lists screen brightness options or sets it to the brightness defined by the search term; " 0068 "e.g. screen brightness 50 would dim the screen to 50% maximum brightness")); 0069 brightnessSyntax.addExampleQuery(i18nc("Note this is a KRunner keyword", "dim screen")); 0070 addSyntax(brightnessSyntax); 0071 } 0072 0073 PowerDevilRunner::~PowerDevilRunner() 0074 { 0075 } 0076 0077 void PowerDevilRunner::updateStatus() 0078 { 0079 updateSyntaxes(); 0080 } 0081 0082 enum SleepState { StandbyState = 1, SuspendState = 2, HibernateState = 4, HybridSuspendState = 8 }; 0083 0084 void PowerDevilRunner::match(Plasma::RunnerContext &context) 0085 { 0086 const QString term = context.query(); 0087 Plasma::QueryMatch::Type type = Plasma::QueryMatch::ExactMatch; 0088 QList<Plasma::QueryMatch> matches; 0089 0090 int screenBrightnessResults = matchesScreenBrightnessKeywords(term); 0091 if (screenBrightnessResults != -1) { 0092 Plasma::QueryMatch match(this); 0093 match.setType(type); 0094 match.setIconName(QStringLiteral("preferences-system-power-management")); 0095 match.setText(i18n("Set Brightness to %1%", screenBrightnessResults)); 0096 match.setData(screenBrightnessResults); 0097 match.setRelevance(1); 0098 match.setId(QStringLiteral("BrightnessChange")); 0099 matches.append(match); 0100 } else if (matchesRunnerKeywords({m_screenBrightness, m_dimScreen}, type, term)) { 0101 Plasma::QueryMatch match1(this); 0102 match1.setType(Plasma::QueryMatch::ExactMatch); 0103 match1.setIconName(QStringLiteral("preferences-system-power-management")); 0104 match1.setText(i18n("Dim screen totally")); 0105 match1.setRelevance(1); 0106 match1.setId(QStringLiteral("DimTotal")); 0107 matches.append(match1); 0108 0109 Plasma::QueryMatch match2(this); 0110 match2.setType(type); 0111 match2.setIconName(QStringLiteral("preferences-system-power-management")); 0112 match2.setText(i18n("Dim screen by half")); 0113 match2.setRelevance(1); 0114 match2.setId(QStringLiteral("DimHalf")); 0115 matches.append(match2); 0116 } else if (matchesRunnerKeywords({m_sleep}, type, term)) { 0117 if (m_session->canSuspend()) { 0118 addSuspendMatch(SuspendState, matches, type); 0119 } 0120 0121 if (m_session->canHibernate()) { 0122 addSuspendMatch(HibernateState, matches, type); 0123 } 0124 } else if (matchesRunnerKeywords({m_suspend, m_toRam}, type, term)) { 0125 addSuspendMatch(SuspendState, matches, type); 0126 } else if (matchesRunnerKeywords({m_hibernate, m_toDisk}, type, term)) { 0127 addSuspendMatch(HibernateState, matches, type); 0128 } 0129 0130 context.addMatches(matches); 0131 } 0132 0133 void PowerDevilRunner::addSuspendMatch(int value, QList<Plasma::QueryMatch> &matches, Plasma::QueryMatch::Type type) 0134 { 0135 Plasma::QueryMatch match(this); 0136 match.setType(type); 0137 0138 switch ((SleepState)value) { 0139 case SuspendState: 0140 case StandbyState: 0141 match.setIconName(QStringLiteral("system-suspend")); 0142 match.setText(i18nc("Suspend to RAM", "Sleep")); 0143 match.setSubtext(i18n("Suspend to RAM")); 0144 match.setRelevance(1); 0145 break; 0146 case HibernateState: 0147 match.setIconName(QStringLiteral("system-suspend-hibernate")); 0148 match.setText(i18nc("Suspend to disk", "Hibernate")); 0149 match.setSubtext(i18n("Suspend to disk")); 0150 match.setRelevance(0.99); 0151 break; 0152 } 0153 0154 match.setData(value); 0155 match.setId(QStringLiteral("Sleep")); 0156 matches.append(match); 0157 } 0158 0159 void PowerDevilRunner::run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &match) 0160 { 0161 Q_UNUSED(context) 0162 0163 QDBusInterface iface(QStringLiteral("org.kde.Solid.PowerManagement"), 0164 QStringLiteral("/org/kde/Solid/PowerManagement"), 0165 QStringLiteral("org.kde.Solid.PowerManagement")); 0166 QDBusInterface brightnessIface(QStringLiteral("org.kde.Solid.PowerManagement"), 0167 QStringLiteral("/org/kde/Solid/PowerManagement/Actions/BrightnessControl"), 0168 QStringLiteral("org.kde.Solid.PowerManagement.Actions.BrightnessControl")); 0169 if (match.id().startsWith(QLatin1String("PowerDevil_ProfileChange"))) { 0170 iface.asyncCall(QStringLiteral("loadProfile"), match.data().toString()); 0171 } else if (match.id() == QLatin1String("PowerDevil_BrightnessChange")) { 0172 QDBusReply<int> max = brightnessIface.call("brightnessMax"); 0173 const int value = max.isValid() ? std::round(match.data().toInt() * max / 100.0) : match.data().toInt(); 0174 brightnessIface.asyncCall("setBrightness", value); 0175 } else if (match.id() == QLatin1String("PowerDevil_DimTotal")) { 0176 brightnessIface.asyncCall(QStringLiteral("setBrightness"), 0); 0177 } else if (match.id() == QLatin1String("PowerDevil_DimHalf")) { 0178 QDBusReply<int> brightness = brightnessIface.asyncCall(QStringLiteral("brightness")); 0179 brightnessIface.asyncCall(QStringLiteral("setBrightness"), static_cast<int>(brightness / 2)); 0180 } else if (match.id().startsWith(QLatin1String("PowerDevil_Sleep"))) { 0181 switch ((SleepState)match.data().toInt()) { 0182 case SuspendState: 0183 case StandbyState: 0184 m_session->suspend(); 0185 break; 0186 case HibernateState: 0187 m_session->hibernate(); 0188 break; 0189 } 0190 } 0191 } 0192 0193 bool PowerDevilRunner::matchesRunnerKeywords(const QList<RunnerKeyword> &keywords, Plasma::QueryMatch::Type &type, const QString &query) const 0194 { 0195 return std::any_of(keywords.begin(), keywords.end(), [&query, &type](const RunnerKeyword &keyword) { 0196 bool exactMatch = 0197 keyword.triggerWord.compare(query, Qt::CaseInsensitive) == 0 || keyword.translatedTriggerWord.compare(query, Qt::CaseInsensitive) == 0; 0198 type = exactMatch ? Plasma::QueryMatch::ExactMatch : Plasma::QueryMatch::CompletionMatch; 0199 if (!exactMatch && keyword.supportPartialMatch) { 0200 return keyword.triggerWord.startsWith(query, Qt::CaseInsensitive) || keyword.translatedTriggerWord.startsWith(query, Qt::CaseInsensitive); 0201 } 0202 return exactMatch; 0203 }); 0204 } 0205 0206 void PowerDevilRunner::addSyntaxForKeyword(const QList<RunnerKeyword> &keywords, const QString &description) 0207 { 0208 Plasma::RunnerSyntax syntax(keywords.first().translatedTriggerWord, description); 0209 for (int i = 1; i < keywords.size(); ++i) { 0210 syntax.addExampleQuery(keywords.at(i).translatedTriggerWord); 0211 } 0212 addSyntax(syntax); 0213 } 0214 0215 int PowerDevilRunner::matchesScreenBrightnessKeywords(const QString &query) const 0216 { 0217 const static QStringList expressions = {QStringLiteral("screen brightness "), 0218 i18nc("Note this is a KRunner keyword, it should end with a space", "screen brightness "), 0219 QStringLiteral("dim screen "), 0220 i18nc("Note this is a KRunner keyword, it should end with a space", "dim screen ")}; 0221 0222 for (const QString &expression : expressions) { 0223 if (query.startsWith(expression)) { 0224 const QString number = query.mid(expression.size()); 0225 bool ok; 0226 int result = qBound(0, number.toInt(&ok), 100); 0227 return ok ? result : -1; 0228 } 0229 } 0230 return -1; 0231 } 0232 0233 #include "PowerDevilRunner.moc"