/* SPDX-FileCopyrightText: 2008 Dario Freddi SPDX-FileCopyrightText: 2008 Sebastian Kügler SPDX-License-Identifier: GPL-2.0-or-later */ #include "PowerDevilRunner.h" // kde-workspace/libs #include #include #include #include #include #include #include #include #include K_PLUGIN_CLASS_WITH_JSON(PowerDevilRunner, "plasma-runner-powerdevil.json") PowerDevilRunner::PowerDevilRunner(QObject *parent, const KPluginMetaData &metaData, const QVariantList &args) : Plasma::AbstractRunner(parent, metaData, args) , m_session(new SessionManagement(this)) { setObjectName(QStringLiteral("PowerDevil")); setMinLetterCount(3); const KLocalizedString suspend = ki18nc("Note this is a KRunner keyword", "suspend"); m_suspend = RunnerKeyword{suspend.untranslatedText(), suspend.toString()}; const KLocalizedString toRam = ki18nc("Note this is a KRunner keyword", "to ram"); m_toRam = RunnerKeyword{toRam.untranslatedText(), toRam.toString(), false}; const KLocalizedString sleep = ki18nc("Note this is a KRunner keyword", "sleep"); m_sleep = RunnerKeyword{sleep.untranslatedText(), sleep.toString()}; const KLocalizedString hibernate = ki18nc("Note this is a KRunner keyword", "hibernate"); m_hibernate = RunnerKeyword{hibernate.untranslatedText(), hibernate.toString()}; const KLocalizedString toDisk = ki18nc("Note this is a KRunner keyword", "to disk"); m_toDisk = RunnerKeyword{toDisk.untranslatedText(), toDisk.toString(), false}; const KLocalizedString dimScreen = ki18nc("Note this is a KRunner keyword", "dim screen"); m_dimScreen = RunnerKeyword{dimScreen.untranslatedText(), dimScreen.toString()}; const KLocalizedString screenBrightness = ki18nc("Note this is a KRunner keyword", "dim screen"); m_screenBrightness = RunnerKeyword{screenBrightness.untranslatedText(), screenBrightness.toString()}; updateStatus(); } void PowerDevilRunner::updateSyntaxes() { setSyntaxes({}); // Clear the existing ones addSyntaxForKeyword({m_suspend}, i18n("Lists system suspend (e.g. sleep, hibernate) options " "and allows them to be activated")); if (m_session->canSuspend()) { addSyntaxForKeyword({m_sleep, m_toRam}, i18n("Suspends the system to RAM")); } if (m_session->canHibernate()) { addSyntaxForKeyword({m_hibernate, m_toDisk}, i18n("Suspends the system to disk")); } Plasma::RunnerSyntax brightnessSyntax( i18nc("Note this is a KRunner keyword, <> is a placeholder and should be at the end", "screen brightness "), // xgettext:no-c-format i18n("Lists screen brightness options or sets it to the brightness defined by the search term; " "e.g. screen brightness 50 would dim the screen to 50% maximum brightness")); brightnessSyntax.addExampleQuery(i18nc("Note this is a KRunner keyword", "dim screen")); addSyntax(brightnessSyntax); } PowerDevilRunner::~PowerDevilRunner() { } void PowerDevilRunner::updateStatus() { updateSyntaxes(); } enum SleepState { StandbyState = 1, SuspendState = 2, HibernateState = 4, HybridSuspendState = 8 }; void PowerDevilRunner::match(Plasma::RunnerContext &context) { const QString term = context.query(); Plasma::QueryMatch::Type type = Plasma::QueryMatch::ExactMatch; QList matches; int screenBrightnessResults = matchesScreenBrightnessKeywords(term); if (screenBrightnessResults != -1) { Plasma::QueryMatch match(this); match.setType(type); match.setIconName(QStringLiteral("preferences-system-power-management")); match.setText(i18n("Set Brightness to %1%", screenBrightnessResults)); match.setData(screenBrightnessResults); match.setRelevance(1); match.setId(QStringLiteral("BrightnessChange")); matches.append(match); } else if (matchesRunnerKeywords({m_screenBrightness, m_dimScreen}, type, term)) { Plasma::QueryMatch match1(this); match1.setType(Plasma::QueryMatch::ExactMatch); match1.setIconName(QStringLiteral("preferences-system-power-management")); match1.setText(i18n("Dim screen totally")); match1.setRelevance(1); match1.setId(QStringLiteral("DimTotal")); matches.append(match1); Plasma::QueryMatch match2(this); match2.setType(type); match2.setIconName(QStringLiteral("preferences-system-power-management")); match2.setText(i18n("Dim screen by half")); match2.setRelevance(1); match2.setId(QStringLiteral("DimHalf")); matches.append(match2); } else if (matchesRunnerKeywords({m_sleep}, type, term)) { if (m_session->canSuspend()) { addSuspendMatch(SuspendState, matches, type); } if (m_session->canHibernate()) { addSuspendMatch(HibernateState, matches, type); } } else if (matchesRunnerKeywords({m_suspend, m_toRam}, type, term)) { addSuspendMatch(SuspendState, matches, type); } else if (matchesRunnerKeywords({m_hibernate, m_toDisk}, type, term)) { addSuspendMatch(HibernateState, matches, type); } context.addMatches(matches); } void PowerDevilRunner::addSuspendMatch(int value, QList &matches, Plasma::QueryMatch::Type type) { Plasma::QueryMatch match(this); match.setType(type); switch ((SleepState)value) { case SuspendState: case StandbyState: match.setIconName(QStringLiteral("system-suspend")); match.setText(i18nc("Suspend to RAM", "Sleep")); match.setSubtext(i18n("Suspend to RAM")); match.setRelevance(1); break; case HibernateState: match.setIconName(QStringLiteral("system-suspend-hibernate")); match.setText(i18nc("Suspend to disk", "Hibernate")); match.setSubtext(i18n("Suspend to disk")); match.setRelevance(0.99); break; } match.setData(value); match.setId(QStringLiteral("Sleep")); matches.append(match); } void PowerDevilRunner::run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &match) { Q_UNUSED(context) QDBusInterface iface(QStringLiteral("org.kde.Solid.PowerManagement"), QStringLiteral("/org/kde/Solid/PowerManagement"), QStringLiteral("org.kde.Solid.PowerManagement")); QDBusInterface brightnessIface(QStringLiteral("org.kde.Solid.PowerManagement"), QStringLiteral("/org/kde/Solid/PowerManagement/Actions/BrightnessControl"), QStringLiteral("org.kde.Solid.PowerManagement.Actions.BrightnessControl")); if (match.id().startsWith(QLatin1String("PowerDevil_ProfileChange"))) { iface.asyncCall(QStringLiteral("loadProfile"), match.data().toString()); } else if (match.id() == QLatin1String("PowerDevil_BrightnessChange")) { QDBusReply max = brightnessIface.call("brightnessMax"); const int value = max.isValid() ? std::round(match.data().toInt() * max / 100.0) : match.data().toInt(); brightnessIface.asyncCall("setBrightness", value); } else if (match.id() == QLatin1String("PowerDevil_DimTotal")) { brightnessIface.asyncCall(QStringLiteral("setBrightness"), 0); } else if (match.id() == QLatin1String("PowerDevil_DimHalf")) { QDBusReply brightness = brightnessIface.asyncCall(QStringLiteral("brightness")); brightnessIface.asyncCall(QStringLiteral("setBrightness"), static_cast(brightness / 2)); } else if (match.id().startsWith(QLatin1String("PowerDevil_Sleep"))) { switch ((SleepState)match.data().toInt()) { case SuspendState: case StandbyState: m_session->suspend(); break; case HibernateState: m_session->hibernate(); break; } } } bool PowerDevilRunner::matchesRunnerKeywords(const QList &keywords, Plasma::QueryMatch::Type &type, const QString &query) const { return std::any_of(keywords.begin(), keywords.end(), [&query, &type](const RunnerKeyword &keyword) { bool exactMatch = keyword.triggerWord.compare(query, Qt::CaseInsensitive) == 0 || keyword.translatedTriggerWord.compare(query, Qt::CaseInsensitive) == 0; type = exactMatch ? Plasma::QueryMatch::ExactMatch : Plasma::QueryMatch::CompletionMatch; if (!exactMatch && keyword.supportPartialMatch) { return keyword.triggerWord.startsWith(query, Qt::CaseInsensitive) || keyword.translatedTriggerWord.startsWith(query, Qt::CaseInsensitive); } return exactMatch; }); } void PowerDevilRunner::addSyntaxForKeyword(const QList &keywords, const QString &description) { Plasma::RunnerSyntax syntax(keywords.first().translatedTriggerWord, description); for (int i = 1; i < keywords.size(); ++i) { syntax.addExampleQuery(keywords.at(i).translatedTriggerWord); } addSyntax(syntax); } int PowerDevilRunner::matchesScreenBrightnessKeywords(const QString &query) const { const static QStringList expressions = {QStringLiteral("screen brightness "), i18nc("Note this is a KRunner keyword, it should end with a space", "screen brightness "), QStringLiteral("dim screen "), i18nc("Note this is a KRunner keyword, it should end with a space", "dim screen ")}; for (const QString &expression : expressions) { if (query.startsWith(expression)) { const QString number = query.mid(expression.size()); bool ok; int result = qBound(0, number.toInt(&ok), 100); return ok ? result : -1; } } return -1; } #include "PowerDevilRunner.moc"