diff --git a/daemon/CMakeLists.txt b/daemon/CMakeLists.txt
index f99a2201e42328b4167becc918d1fa2f896d147a..789f99605b689a4c4b335545224afbebdec84e2d 100644
--- a/daemon/CMakeLists.txt
+++ b/daemon/CMakeLists.txt
@@ -19,8 +19,10 @@ set(powerdevil_bundled_actions_SRCS
actions/bundled/xcbdpmshelper.cpp
actions/bundled/waylanddpmshelper.cpp
${PowerDevil_SOURCE_DIR}/daemon/kwinkscreenhelpereffect.cpp
+ actions/bundled/powerprofile.cpp
)
+
if(HAVE_WIRELESS_SUPPORT)
set(powerdevil_bundled_actions_SRCS ${powerdevil_bundled_actions_SRCS}
actions/bundled/wirelesspowersaving.cpp
@@ -66,9 +68,15 @@ if(HAVE_WIRELESS_SUPPORT)
qt_add_dbus_adaptor(powerdevilcore_SRCS actions/bundled/org.kde.Solid.PowerManagement.Actions.WirelessPowerSaving.xml
actions/bundled/wirelesspowersaving.h PowerDevil::BundledActions::WirelessPowerSaving)
endif()
+qt5_add_dbus_adaptor(powerdevilcore_SRCS actions/bundled/org.kde.Solid.PowerManagement.Actions.PowerProfile.xml
+ actions/bundled/powerprofile.h PowerDevil::BundledActions::PowerProfile)
qt_add_dbus_interface(powerdevilcore_SRCS org.freedesktop.ScreenSaver.xml screenlocker_interface)
+qt5_add_dbus_interface(powerdevilcore_SRCS actions/bundled/org.freedesktop.DBus.Properties.xml properties_interface)
+
+qt5_add_dbus_interface(powerdevilcore_SRCS actions/bundled/net.hadess.PowerProfiles.xml power_profiles_interface)
+
add_library(powerdevilcore SHARED ${powerdevilcore_SRCS} ${powerdevil_bundled_actions_SRCS})
set_target_properties(powerdevilcore PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION 2)
diff --git a/daemon/actions/bundled/CMakeLists.txt b/daemon/actions/bundled/CMakeLists.txt
index b7c16a962ff1632ddc1d7d5370a39e9f0848c5f1..6b26927bbe9b9f5f89012ca5e43b238524f63b72 100644
--- a/daemon/actions/bundled/CMakeLists.txt
+++ b/daemon/actions/bundled/CMakeLists.txt
@@ -21,6 +21,7 @@ add_powerdevil_bundled_action(dimdisplay)
add_powerdevil_bundled_action(runscript KF5::KIOCore KF5::KIOWidgets)
add_powerdevil_bundled_action(suspendsession KF5::KIOCore KF5::KIOWidgets)
add_powerdevil_bundled_action(dpms)
+add_powerdevil_bundled_action(powerprofile)
if(HAVE_WIRELESS_SUPPORT)
add_powerdevil_bundled_action(wirelesspowersaving KF5::NetworkManagerQt KF5::BluezQt)
endif()
diff --git a/daemon/actions/bundled/net.hadess.PowerProfiles.xml b/daemon/actions/bundled/net.hadess.PowerProfiles.xml
new file mode 100644
index 0000000000000000000000000000000000000000..20383379d07ea81e364294d1b6446121e7bacc67
--- /dev/null
+++ b/daemon/actions/bundled/net.hadess.PowerProfiles.xml
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/daemon/actions/bundled/org.freedesktop.DBus.Properties.xml b/daemon/actions/bundled/org.freedesktop.DBus.Properties.xml
new file mode 100644
index 0000000000000000000000000000000000000000..3e729ca643d6dfe592ba37fac26573af38abe02a
--- /dev/null
+++ b/daemon/actions/bundled/org.freedesktop.DBus.Properties.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/daemon/actions/bundled/org.kde.Solid.PowerManagement.Actions.PowerProfile.xml b/daemon/actions/bundled/org.kde.Solid.PowerManagement.Actions.PowerProfile.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d8db191a90aaaa7322496ed2fc7d87f3a3630577
--- /dev/null
+++ b/daemon/actions/bundled/org.kde.Solid.PowerManagement.Actions.PowerProfile.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/daemon/actions/bundled/powerdevilpowerprofileaction.desktop b/daemon/actions/bundled/powerdevilpowerprofileaction.desktop
new file mode 100644
index 0000000000000000000000000000000000000000..f3ac591b3203e441aa92d9753f2e86c8e4eb5070
--- /dev/null
+++ b/daemon/actions/bundled/powerdevilpowerprofileaction.desktop
@@ -0,0 +1,13 @@
+[Desktop Entry]
+Type=Service
+X-KDE-ServiceTypes=PowerDevil/Action
+Icon=preferences-system-power-management-profile
+Name=Power management profile
+Comment=Apply a power management profile
+
+X-KDE-PowerDevil-Action-ID=PowerProfile
+X-KDE-PowerDevil-Action-IsBundled=true
+X-KDE-PowerDevil-Action-UIComponentLibrary=powerdevilpowerprofileaction_config
+X-KDE-PowerDevil-Action-ConfigPriority=70
+X-KDE-PowerDevil-Action-HasRuntimeRequirement=true
+X-KDE-PowerDevil-Action-RegistersDBusInterface=true
diff --git a/daemon/actions/bundled/powerprofile.cpp b/daemon/actions/bundled/powerprofile.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..72608a622a9d78a0495d453542faed3564c2a3d8
--- /dev/null
+++ b/daemon/actions/bundled/powerprofile.cpp
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2020 Kai Uwe Broulik
+ * Copyright 2021 David Redondo
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License or (at your option) version 3 or any later version
+ * accepted by the membership of KDE e.V. (or its successor approved
+ * by the membership of KDE e.V.), which shall act as a proxy
+ * defined in Section 14 of version 3 of the license.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "powerprofile.h"
+
+#include "power_profiles_interface.h"
+#include "powerprofileadaptor.h"
+#include "properties_interface.h"
+
+#include
+
+#include
+
+using namespace PowerDevil::BundledActions;
+
+static const QString activeProfileProperty = QStringLiteral("ActiveProfile");
+static const QString profilesProperty = QStringLiteral("Profiles");
+static const QString performanceInhibitedProperty = QStringLiteral("PerformanceInhibited");
+
+static const QString ppdName = QStringLiteral("net.hadess.PowerProfiles");
+static const QString ppdPath = QStringLiteral("/net/hadess/PowerProfiles");
+
+PowerProfile::PowerProfile(QObject *parent)
+ : Action(parent)
+ , m_powerProfilesInterface(new NetHadessPowerProfilesInterface(ppdName, ppdPath, QDBusConnection::systemBus(), this))
+ , m_powerProfilesPropertiesInterface(new OrgFreedesktopDBusPropertiesInterface(ppdName, ppdPath, QDBusConnection::systemBus(), this))
+{
+ new PowerProfileAdaptor(this);
+
+ connect(m_powerProfilesPropertiesInterface, &OrgFreedesktopDBusPropertiesInterface::PropertiesChanged, this, &PowerProfile::propertiesChanged);
+
+ auto watcher = new QDBusPendingCallWatcher(m_powerProfilesPropertiesInterface->GetAll(m_powerProfilesInterface->interface()));
+ connect(watcher, &QDBusPendingCallWatcher::finished, this, [this, watcher] {
+ watcher->deleteLater();
+ QDBusPendingReply reply = *watcher;
+ if (watcher->isError()) {
+ return;
+ }
+ readProperties(reply.value());
+ });
+}
+
+PowerProfile::~PowerProfile() = default;
+
+void PowerProfile::onProfileLoad()
+{
+ if (!m_configuredProfile.isEmpty()) {
+ setProfile(m_configuredProfile);
+ }
+}
+
+void PowerProfile::onWakeupFromIdle()
+{
+}
+
+void PowerProfile::onIdleTimeout(int msec)
+{
+ Q_UNUSED(msec);
+}
+
+void PowerProfile::onProfileUnload()
+{
+}
+
+void PowerProfile::triggerImpl(const QVariantMap &args)
+{
+ Q_UNUSED(args);
+}
+
+bool PowerProfile::loadAction(const KConfigGroup &config)
+{
+ if (config.hasKey("profile")) {
+ m_configuredProfile = config.readEntry("profile", QString());
+ }
+
+ return true;
+}
+
+bool PowerProfile::isSupported()
+{
+ return QDBusConnection::systemBus().interface()->activatableServiceNames().value().contains(ppdName);
+}
+
+QStringList PowerProfile::profileChoices() const
+{
+ return m_profileChoices;
+}
+
+QString PowerProfile::currentProfile() const
+{
+ return m_currentProfile;
+}
+
+QString PowerProfile::performanceInhibitedReason() const
+{
+ return m_performanceInhibitedReason;
+}
+
+void PowerProfile::setProfile(const QString &profile)
+{
+ auto call = m_powerProfilesPropertiesInterface->Set(m_powerProfilesInterface->interface(), activeProfileProperty, QDBusVariant(profile));
+ if (calledFromDBus()) {
+ setDelayedReply(true);
+ const auto msg = message();
+ auto watcher = new QDBusPendingCallWatcher(call);
+ connect(watcher, &QDBusPendingCallWatcher::finished, this, [msg, watcher] {
+ watcher->deleteLater();
+ if (watcher->isError()) {
+ QDBusConnection::sessionBus().send(msg.createErrorReply(watcher->error()));
+ } else {
+ QDBusConnection::sessionBus().send(msg.createReply());
+ }
+ });
+ }
+}
+
+void PowerProfile::readProperties(const QVariantMap &properties)
+{
+ if (properties.contains(activeProfileProperty)) {
+ m_currentProfile = properties[activeProfileProperty].toString();
+ Q_EMIT currentProfileChanged(m_currentProfile);
+ }
+
+ if (properties.contains(profilesProperty)) {
+ QList profiles;
+ properties[profilesProperty].value() >> profiles;
+ m_profileChoices.clear();
+ if (profiles.first()[QStringLiteral("Driver")] != QLatin1String("placeholder")) {
+ std::transform(profiles.cbegin(), profiles.cend(), std::back_inserter(m_profileChoices), [](const QVariantMap &dict) {
+ return dict[QStringLiteral("Profile")].toString();
+ });
+ }
+ Q_EMIT profileChoicesChanged(m_profileChoices);
+ }
+
+ if (properties.contains(performanceInhibitedProperty)) {
+ m_performanceInhibitedReason = properties[performanceInhibitedProperty].toString();
+ Q_EMIT performanceInhibitedReasonChanged(m_performanceInhibitedReason);
+ }
+}
+
+void PowerProfile::propertiesChanged(const QString &interface, const QVariantMap &changed, const QStringList &invalidated)
+{
+ Q_UNUSED(invalidated)
+ if (interface != m_powerProfilesInterface->interface()) {
+ return;
+ }
+ readProperties(changed);
+}
diff --git a/daemon/actions/bundled/powerprofile.h b/daemon/actions/bundled/powerprofile.h
new file mode 100644
index 0000000000000000000000000000000000000000..6c64b276679480807e610ea277574527f3e8e162
--- /dev/null
+++ b/daemon/actions/bundled/powerprofile.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2020 Kai Uwe Broulik
+ * Copyright 2021 David Redondo
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License or (at your option) version 3 or any later version
+ * accepted by the membership of KDE e.V. (or its successor approved
+ * by the membership of KDE e.V.), which shall act as a proxy
+ * defined in Section 14 of version 3 of the license.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
+
+#include
+
+class OrgFreedesktopDBusPropertiesInterface;
+class NetHadessPowerProfilesInterface;
+
+namespace PowerDevil
+{
+namespace BundledActions
+{
+class PowerProfile : public PowerDevil::Action, protected QDBusContext
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(PowerProfile)
+ Q_CLASSINFO("D-Bus Interface", "org.kde.Solid.PowerManagement.Actions.PowerProfile")
+
+ Q_PROPERTY(QStringList profileChoices READ profileChoices NOTIFY profileChoicesChanged)
+ Q_PROPERTY(QString currentProfile READ currentProfile NOTIFY currentProfileChanged)
+
+public:
+ explicit PowerProfile(QObject *parent);
+ ~PowerProfile() override;
+
+ bool loadAction(const KConfigGroup &config) override;
+
+ QStringList profileChoices() const;
+ QString currentProfile() const;
+ void setProfile(const QString &profile);
+ QString performanceInhibitedReason() const;
+
+Q_SIGNALS:
+ void currentProfileChanged(const QString &profile);
+ void profileChoicesChanged(const QStringList &profiles);
+ void performanceInhibitedReasonChanged(const QString &reason);
+
+protected:
+ void onProfileLoad() override;
+ void onWakeupFromIdle() override;
+ void onIdleTimeout(int msec) override;
+ void onProfileUnload() override;
+ void triggerImpl(const QVariantMap &args) override;
+ bool isSupported() override;
+private Q_SLOTS:
+ void propertiesChanged(const QString &interface, const QVariantMap &changed, const QStringList &invalidated);
+
+private:
+ void readProperties(const QVariantMap &properties);
+
+ NetHadessPowerProfilesInterface *m_powerProfilesInterface;
+ OrgFreedesktopDBusPropertiesInterface *m_powerProfilesPropertiesInterface;
+ QStringList m_profileChoices;
+ QString m_currentProfile;
+ QString m_performanceInhibitedReason;
+
+ QString m_configuredProfile;
+};
+
+} // namespace BundledActions
+} // namespace PowerDevil
diff --git a/daemon/actions/bundled/powerprofileconfig.cpp b/daemon/actions/bundled/powerprofileconfig.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3c5e7944bfa4915ffe604992190fe9e7a526db39
--- /dev/null
+++ b/daemon/actions/bundled/powerprofileconfig.cpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2020 Kai Uwe Broulik
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License or (at your option) version 3 or any later version
+ * accepted by the membership of KDE e.V. (or its successor approved
+ * by the membership of KDE e.V.), which shall act as a proxy
+ * defined in Section 14 of version 3 of the license.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "powerprofileconfig.h"
+
+#include "powerdevilpowermanagement.h"
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+K_PLUGIN_FACTORY(PowerDevilPowerProfileConfigFactory, registerPlugin();)
+
+using namespace PowerDevil::BundledActions;
+
+PowerProfileConfig::PowerProfileConfig(QObject *parent, const QVariantList &args)
+ : ActionConfig(parent)
+{
+ Q_UNUSED(args)
+}
+
+PowerProfileConfig::~PowerProfileConfig() = default;
+
+void PowerProfileConfig::save()
+{
+ const QString profile = m_profileCombo->currentData().toString();
+ configGroup().writeEntry("profile", profile);
+
+ configGroup().sync();
+}
+
+void PowerProfileConfig::load()
+{
+ configGroup().config()->reparseConfiguration();
+
+ const QString profile = configGroup().readEntry("profile", QString());
+
+ QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral("org.kde.Solid.PowerManagement"),
+ QStringLiteral("/org/kde/Solid/PowerManagement/Actions/PowerProfile"),
+ QStringLiteral("org.kde.Solid.PowerManagement.Actions.PowerProfile"),
+ QStringLiteral("profileChoices"));
+
+ auto *watcher = new QDBusPendingCallWatcher(QDBusConnection::sessionBus().asyncCall(msg), this);
+ QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this, [this, profile](QDBusPendingCallWatcher *watcher) {
+ QDBusPendingReply reply = *watcher;
+ watcher->deleteLater();
+
+ m_profileCombo->clear();
+ m_profileCombo->addItem(i18n("Leave unchanged"));
+
+ if (reply.isError()) {
+ qWarning() << "Failed to query platform profile choices" << reply.error().message();
+ return;
+ }
+
+ const QHash profileNames = {
+ {QStringLiteral("power-saver"), i18n("Power Save")},
+ {QStringLiteral("balanced"), i18n("Balanced")},
+ {QStringLiteral("performance"), i18n("Performance")},
+ };
+
+ const QStringList choices = reply.value();
+ for (const QString &choice : choices) {
+ m_profileCombo->addItem(profileNames.value(choice, choice), choice);
+ }
+ m_profileCombo->setCurrentIndex(qMax(0, m_profileCombo->findData(profile)));
+ });
+}
+
+QList> PowerProfileConfig::buildUi()
+{
+ m_profileCombo = new QComboBox;
+ // Uniform ComboBox width throughout all action config modules
+ m_profileCombo->setMinimumWidth(300);
+ m_profileCombo->setMaximumWidth(300);
+ connect(m_profileCombo, QOverload::of(&QComboBox::currentIndexChanged), this, &PowerProfileConfig::setChanged);
+
+ return {qMakePair(i18nc("Switch to power management profile", "Switch to:"), m_profileCombo)};
+}
+
+#include "powerprofileconfig.moc"
diff --git a/daemon/actions/bundled/powerprofileconfig.h b/daemon/actions/bundled/powerprofileconfig.h
new file mode 100644
index 0000000000000000000000000000000000000000..ce215c1f3fdc90b42853f6c568fbc903fed72a0f
--- /dev/null
+++ b/daemon/actions/bundled/powerprofileconfig.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2020 Kai Uwe Broulik
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License or (at your option) version 3 or any later version
+ * accepted by the membership of KDE e.V. (or its successor approved
+ * by the membership of KDE e.V.), which shall act as a proxy
+ * defined in Section 14 of version 3 of the license.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
+
+#include
+
+class QComboBox;
+
+namespace PowerDevil
+{
+namespace BundledActions
+{
+class PowerProfileConfig : public PowerDevil::ActionConfig
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(PowerProfileConfig)
+public:
+ PowerProfileConfig(QObject *parent, const QVariantList &args);
+ ~PowerProfileConfig() override;
+
+ void save() override;
+ void load() override;
+ QList> buildUi() override;
+
+private:
+ QComboBox *m_profileCombo;
+};
+
+} // namespace BundledActions
+} // namespace PowerDevil
diff --git a/daemon/powerdevilactionpool.cpp b/daemon/powerdevilactionpool.cpp
index ec84b0edfaebe585229f214047635ae3a56a0bb4..7ced41e4aef7b145f1260b5677d8502dda6a3e59 100644
--- a/daemon/powerdevilactionpool.cpp
+++ b/daemon/powerdevilactionpool.cpp
@@ -43,6 +43,7 @@
#ifdef HAVE_WIRELESS_SUPPORT
#include "actions/bundled/wirelesspowersaving.h"
#endif
+#include "actions/bundled/powerprofile.h"
namespace PowerDevil
{
@@ -135,6 +136,7 @@ void ActionPool::init(PowerDevil::Core *parent)
#ifdef HAVE_WIRELESS_SUPPORT
m_actionPool.insert(QStringLiteral("WirelessPowerSaving"), new BundledActions::WirelessPowerSaving(parent));
#endif
+ m_actionPool.insert(QStringLiteral("PowerProfile"), new BundledActions::PowerProfile(parent));
// Verify support
QHash::iterator i = m_actionPool.begin();