diff --git a/include/modules/upower/upower.hpp b/include/modules/upower/upower.hpp index 7907027..4ee2b1e 100644 --- a/include/modules/upower/upower.hpp +++ b/include/modules/upower/upower.hpp @@ -7,6 +7,7 @@ #include #include "ALabel.hpp" +#include "glibconfig.h" #include "gtkmm/box.h" #include "gtkmm/image.h" #include "gtkmm/label.h" @@ -23,6 +24,9 @@ class UPower : public AModule { private: typedef std::unordered_map Devices; + const std::string DEFAULT_FORMAT = "{percentage}"; + const std::string DEFAULT_FORMAT_ALT = "{percentage} {time}"; + static void deviceAdded_cb(UpClient *client, UpDevice *device, gpointer data); static void deviceRemoved_cb(UpClient *client, const gchar *objectPath, gpointer data); static void deviceNotify_cb(UpDevice *device, GParamSpec *pspec, gpointer user_data); @@ -36,6 +40,8 @@ class UPower : public AModule { void resetDevices(); void removeDevices(); bool show_tooltip_callback(int, int, bool, const Glib::RefPtr &tooltip); + bool handleToggle(GdkEventButton *const &); + std::string timeToString(gint64 time); const std::string getDeviceStatus(UpDeviceState &state); @@ -44,10 +50,12 @@ class UPower : public AModule { Gtk::Label label_; // Config - bool hideIfEmpty = true; - bool tooltip_enabled = true; - uint tooltip_spacing = 4; - uint iconSize = 20; + bool hideIfEmpty = true; + bool tooltip_enabled = true; + uint tooltip_spacing = 4; + uint iconSize = 20; + std::string format = DEFAULT_FORMAT; + std::string format_alt = DEFAULT_FORMAT_ALT; Devices devices; std::mutex m_Mutex; @@ -57,6 +65,7 @@ class UPower : public AModule { GDBusConnection *login1_connection; UPowerTooltip *upower_tooltip; std::string lastStatus; + bool showAltText; }; } // namespace waybar::modules::upower diff --git a/man/waybar-upower.5.scd b/man/waybar-upower.5.scd index 94ba866..76af849 100644 --- a/man/waybar-upower.5.scd +++ b/man/waybar-upower.5.scd @@ -16,6 +16,16 @@ compatible devices in the tooltip. default: 20 ++ Defines the size of the icons. +*format*: ++ + typeof: string ++ + default: {percentage} ++ + The text format. + +*format-alt*: ++ + typeof: string ++ + default: {percentage} {time} ++ + The text format when toggled. + *hide-if-empty*: ++ typeof: bool ++ default: true ++ @@ -32,6 +42,13 @@ compatible devices in the tooltip. Defines the spacing between the tooltip device name and device battery ++ status. +# FORMAT REPLACEMENTS + +*{percentage}*: The battery capacity in percentage + +*{time}*: An estimated time either until empty or until fully charged ++ +depending on the charging state. + # EXAMPLES ``` diff --git a/src/modules/upower/upower.cpp b/src/modules/upower/upower.cpp index 0cbe010..5f4d00b 100644 --- a/src/modules/upower/upower.cpp +++ b/src/modules/upower/upower.cpp @@ -1,5 +1,9 @@ #include "modules/upower/upower.hpp" +#include + +#include + #include "gtkmm/icontheme.h" #include "gtkmm/label.h" #include "gtkmm/tooltip.h" @@ -13,7 +17,8 @@ UPower::UPower(const std::string& id, const Json::Value& config) label_(), devices(), m_Mutex(), - client() { + client(), + showAltText(false) { box_.pack_start(icon_); box_.pack_start(label_); event_box_.add(box_); @@ -29,6 +34,16 @@ UPower::UPower(const std::string& id, const Json::Value& config) hideIfEmpty = config_["hide-if-empty"].asBool(); } + // Format + if (config_["format"].isString()) { + format = config_["format"].asString(); + } + + // Format Alt + if (config_["format-alt"].isString()) { + format_alt = config_["format-alt"].asString(); + } + // Tooltip Spacing if (config_["tooltip-spacing"].isUInt()) { tooltip_spacing = config_["tooltip-spacing"].asUInt(); @@ -69,6 +84,8 @@ UPower::UPower(const std::string& id, const Json::Value& config) NULL); } + event_box_.signal_button_press_event().connect(sigc::mem_fun(*this, &UPower::handleToggle)); + g_signal_connect(client, "device-added", G_CALLBACK(deviceAdded_cb), this); g_signal_connect(client, "device-removed", G_CALLBACK(deviceRemoved_cb), this); @@ -213,14 +230,33 @@ const std::string UPower::getDeviceStatus(UpDeviceState& state) { } } +bool UPower::handleToggle(GdkEventButton* const& event) { + std::lock_guard guard(m_Mutex); + showAltText = !showAltText; + dp.emit(); + return true; +} + +std::string UPower::timeToString(gint64 time) { + if (time == 0) return ""; + float hours = (float)time / 3600; + float hours_fixed = static_cast(static_cast(hours * 10)) / 10; + float minutes = static_cast(static_cast(hours * 60 * 10)) / 10; + if (hours_fixed >= 1) { + return fmt::format("{H} h", fmt::arg("H", hours_fixed)); + } else { + return fmt::format("{M} min", fmt::arg("M", minutes)); + } +} + auto UPower::update() -> void { std::lock_guard guard(m_Mutex); UpDeviceKind kind; UpDeviceState state; double percentage; - gboolean is_power_supply; - gboolean is_present; + gint64 time_empty; + gint64 time_full; gchar* icon_name; g_object_get(displayDevice, @@ -228,14 +264,14 @@ auto UPower::update() -> void { &kind, "state", &state, - "is-present", - &is_present, - "power-supply", - &is_power_supply, "percentage", &percentage, "icon-name", &icon_name, + "time-to-empty", + &time_empty, + "time-to-full", + &time_full, NULL); bool displayDeviceValid = @@ -245,6 +281,22 @@ auto UPower::update() -> void { uint tooltipCount = 0; + std::string time_full_format = timeToString(time_full); + std::string time_empty_format = timeToString(time_full); + std::string time_format = ""; + switch (state) { + case UP_DEVICE_STATE_CHARGING: + case UP_DEVICE_STATE_PENDING_CHARGE: + time_format = time_full_format; + break; + case UP_DEVICE_STATE_DISCHARGING: + case UP_DEVICE_STATE_PENDING_DISCHARGE: + time_format = time_empty_format; + break; + default: + break; + } + // CSS status class const std::string status = getDeviceStatus(state); // Remove last status if it exists @@ -275,7 +327,11 @@ auto UPower::update() -> void { if (displayDeviceValid) { percentString = std::to_string(int(percentage + 0.5)) + "%"; } - label_.set_text(percentString); + + // Label format + label_.set_markup(fmt::format(showAltText ? format_alt : format, + fmt::arg("percentage", percentString), + fmt::arg("time", time_format))); // Set icon if (!Gtk::IconTheme::get_default()->has_icon(icon_name)) {