2024-02-18 21:06:21 +00:00
|
|
|
#include "modules/power_profiles_daemon.hpp"
|
|
|
|
|
|
|
|
// In the 80000 version of fmt library authors decided to optimize imports
|
|
|
|
// and moved declarations required for fmt::dynamic_format_arg_store in new
|
|
|
|
// header fmt/args.h
|
|
|
|
#if (FMT_VERSION >= 80000)
|
|
|
|
#include <fmt/args.h>
|
|
|
|
#else
|
|
|
|
#include <fmt/core.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <glibmm.h>
|
|
|
|
#include <glibmm/variant.h>
|
2024-02-26 13:40:28 +00:00
|
|
|
#include <spdlog/spdlog.h>
|
2024-02-18 21:06:21 +00:00
|
|
|
|
|
|
|
namespace waybar::modules {
|
|
|
|
|
|
|
|
PowerProfilesDaemon::PowerProfilesDaemon(const std::string& id, const Json::Value& config)
|
2024-02-26 13:40:28 +00:00
|
|
|
: ALabel(config, "power-profiles-daemon", id, "{profile}", 0, false, true) {
|
2024-03-01 10:13:57 +00:00
|
|
|
if (config_["format"].isString()) {
|
|
|
|
format_ = config_["format"].asString();
|
|
|
|
} else {
|
|
|
|
format_ = "{icon}";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (config_["tooltip-format"].isString()) {
|
|
|
|
tooltipFormat_ = config_["tooltip-format"].asString();
|
|
|
|
} else {
|
|
|
|
tooltipFormat_ = "Power profile: {profile}\nDriver: {driver}";
|
|
|
|
}
|
|
|
|
|
2024-02-18 21:06:21 +00:00
|
|
|
// NOTE: the DBus adresses are under migration. They should be
|
|
|
|
// changed to org.freedesktop.UPower.PowerProfiles at some point.
|
|
|
|
//
|
|
|
|
// See
|
|
|
|
// https://gitlab.freedesktop.org/upower/power-profiles-daemon/-/releases/0.20
|
|
|
|
//
|
|
|
|
// The old name is still announced for now. Let's rather use the old
|
|
|
|
// adresses for compatibility sake.
|
|
|
|
//
|
|
|
|
// Revisit this in 2026, systems should be updated by then.
|
2024-02-26 14:07:21 +00:00
|
|
|
powerProfilesProxy_ = Gio::DBus::Proxy::create_for_bus_sync(
|
2024-02-26 13:40:28 +00:00
|
|
|
Gio::DBus::BusType::BUS_TYPE_SYSTEM, "net.hadess.PowerProfiles", "/net/hadess/PowerProfiles",
|
|
|
|
"net.hadess.PowerProfiles");
|
2024-02-26 14:07:21 +00:00
|
|
|
if (!powerProfilesProxy_) {
|
2024-02-18 21:06:21 +00:00
|
|
|
spdlog::error("PowerProfilesDaemon: DBus error, cannot connect to net.hasdess.PowerProfile");
|
|
|
|
} else {
|
|
|
|
// Connect active profile callback
|
2024-02-26 14:07:21 +00:00
|
|
|
powerProfileChangeSignal_ = powerProfilesProxy_->signal_properties_changed().connect(
|
|
|
|
sigc::mem_fun(*this, &PowerProfilesDaemon::profileChangedCb));
|
2024-02-18 21:06:21 +00:00
|
|
|
populateInitState();
|
|
|
|
dp.emit();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Look for the profile str in our internal profiles list. Using a
|
|
|
|
// vector to store the profiles ain't the smartest move
|
|
|
|
// complexity-wise, but it makes toggling between the mode easy. This
|
|
|
|
// vector is 3 elements max, we'll be fine :P
|
2024-02-26 14:07:21 +00:00
|
|
|
void PowerProfilesDaemon::switchToProfile(std::string const& str) {
|
|
|
|
auto pred = [str](Profile const& p) { return p.name == str; };
|
|
|
|
this->activeProfile_ = std::find_if(availableProfiles_.begin(), availableProfiles_.end(), pred);
|
2024-02-18 21:06:21 +00:00
|
|
|
if (activeProfile_ == availableProfiles_.end()) {
|
|
|
|
throw std::runtime_error("FATAL, can't find the active profile in the available profiles list");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void PowerProfilesDaemon::populateInitState() {
|
|
|
|
// Retrieve current active profile
|
|
|
|
Glib::Variant<std::string> profileStr;
|
2024-02-26 14:07:21 +00:00
|
|
|
powerProfilesProxy_->get_cached_property(profileStr, "ActiveProfile");
|
2024-02-18 21:06:21 +00:00
|
|
|
|
|
|
|
// Retrieve profiles list, it's aa{sv}.
|
|
|
|
using ProfilesType = std::vector<std::map<Glib::ustring, Glib::Variant<std::string>>>;
|
|
|
|
Glib::Variant<ProfilesType> profilesVariant;
|
2024-02-26 14:07:21 +00:00
|
|
|
powerProfilesProxy_->get_cached_property(profilesVariant, "Profiles");
|
|
|
|
Glib::ustring name;
|
|
|
|
Glib::ustring driver;
|
2024-02-18 21:06:21 +00:00
|
|
|
Profile profile;
|
2024-02-26 13:40:28 +00:00
|
|
|
for (auto& variantDict : profilesVariant.get()) {
|
2024-02-18 21:06:21 +00:00
|
|
|
if (auto p = variantDict.find("Profile"); p != variantDict.end()) {
|
|
|
|
name = p->second.get();
|
|
|
|
}
|
|
|
|
if (auto d = variantDict.find("Driver"); d != variantDict.end()) {
|
|
|
|
driver = d->second.get();
|
|
|
|
}
|
2024-02-26 13:40:28 +00:00
|
|
|
profile = {name, driver};
|
2024-02-18 21:06:21 +00:00
|
|
|
availableProfiles_.push_back(profile);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find the index of the current activated mode (to toggle)
|
|
|
|
std::string str = profileStr.get();
|
2024-02-26 14:07:21 +00:00
|
|
|
switchToProfile(str);
|
2024-02-18 21:06:21 +00:00
|
|
|
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
|
|
|
|
PowerProfilesDaemon::~PowerProfilesDaemon() {
|
|
|
|
if (powerProfileChangeSignal_.connected()) {
|
|
|
|
powerProfileChangeSignal_.disconnect();
|
|
|
|
}
|
2024-02-26 14:07:21 +00:00
|
|
|
if (powerProfilesProxy_) {
|
|
|
|
powerProfilesProxy_.reset();
|
2024-02-18 21:06:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-26 14:07:21 +00:00
|
|
|
void PowerProfilesDaemon::profileChangedCb(
|
2024-02-26 13:40:28 +00:00
|
|
|
const Gio::DBus::Proxy::MapChangedProperties& changedProperties,
|
|
|
|
const std::vector<Glib::ustring>& invalidatedProperties) {
|
|
|
|
if (auto activeProfileVariant = changedProperties.find("ActiveProfile");
|
|
|
|
activeProfileVariant != changedProperties.end()) {
|
|
|
|
std::string activeProfile =
|
|
|
|
Glib::VariantBase::cast_dynamic<Glib::Variant<std::string>>(activeProfileVariant->second)
|
|
|
|
.get();
|
2024-02-26 14:07:21 +00:00
|
|
|
switchToProfile(activeProfile);
|
2024-02-18 21:06:21 +00:00
|
|
|
update();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-26 13:40:28 +00:00
|
|
|
auto PowerProfilesDaemon::update() -> void {
|
2024-02-18 21:06:21 +00:00
|
|
|
auto profile = (*activeProfile_);
|
|
|
|
// Set label
|
|
|
|
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
|
|
|
store.push_back(fmt::arg("profile", profile.name));
|
2024-03-01 10:13:57 +00:00
|
|
|
store.push_back(fmt::arg("driver", profile.driver));
|
|
|
|
store.push_back(fmt::arg("icon", getIcon(0, profile.name)));
|
|
|
|
label_.set_markup(fmt::vformat(format_, store));
|
2024-02-18 21:06:21 +00:00
|
|
|
if (tooltipEnabled()) {
|
2024-03-01 10:13:57 +00:00
|
|
|
label_.set_tooltip_text(fmt::vformat(tooltipFormat_, store));
|
2024-02-18 21:06:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Set CSS class
|
|
|
|
if (!currentStyle_.empty()) {
|
|
|
|
label_.get_style_context()->remove_class(currentStyle_);
|
|
|
|
}
|
|
|
|
label_.get_style_context()->add_class(profile.name);
|
|
|
|
currentStyle_ = profile.name;
|
|
|
|
|
|
|
|
ALabel::update();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool PowerProfilesDaemon::handleToggle(GdkEventButton* const& e) {
|
2024-02-26 14:07:21 +00:00
|
|
|
if (e->type == GdkEventType::GDK_BUTTON_PRESS && powerProfilesProxy_) {
|
2024-02-18 21:06:21 +00:00
|
|
|
activeProfile_++;
|
|
|
|
if (activeProfile_ == availableProfiles_.end()) {
|
|
|
|
activeProfile_ = availableProfiles_.begin();
|
|
|
|
}
|
|
|
|
|
|
|
|
using VarStr = Glib::Variant<Glib::ustring>;
|
2024-02-26 13:40:28 +00:00
|
|
|
using SetPowerProfileVar = Glib::Variant<std::tuple<Glib::ustring, Glib::ustring, VarStr>>;
|
2024-02-18 21:06:21 +00:00
|
|
|
VarStr activeProfileVariant = VarStr::create(activeProfile_->name);
|
2024-02-26 14:07:21 +00:00
|
|
|
auto callArgs = SetPowerProfileVar::create(
|
2024-02-26 13:40:28 +00:00
|
|
|
std::make_tuple("net.hadess.PowerProfiles", "ActiveProfile", activeProfileVariant));
|
2024-02-26 14:07:21 +00:00
|
|
|
auto container = Glib::VariantBase::cast_dynamic<Glib::VariantContainerBase>(callArgs);
|
|
|
|
powerProfilesProxy_->call_sync("org.freedesktop.DBus.Properties.Set", container);
|
2024-02-18 21:06:21 +00:00
|
|
|
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2024-02-26 13:40:28 +00:00
|
|
|
} // namespace waybar::modules
|