From 4ee81c8dea877c42a55342400b534460e9ba4afb Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Tue, 15 Mar 2022 17:54:06 +0100 Subject: [PATCH 01/23] Added all callbacks --- include/factory.hpp | 3 + include/modules/upower/upower.hpp | 43 ++++++++++ meson.build | 9 ++- meson_options.txt | 1 + src/factory.cpp | 5 ++ src/modules/upower/upower.cpp | 126 ++++++++++++++++++++++++++++++ 6 files changed, 186 insertions(+), 1 deletion(-) create mode 100644 include/modules/upower/upower.hpp create mode 100644 src/modules/upower/upower.cpp diff --git a/include/factory.hpp b/include/factory.hpp index 3855ce2..3954dac 100644 --- a/include/factory.hpp +++ b/include/factory.hpp @@ -42,6 +42,9 @@ #ifdef HAVE_LIBEVDEV #include "modules/keyboard_state.hpp" #endif +#ifdef HAVE_UPOWER +#include "modules/upower/upower.hpp" +#endif #ifdef HAVE_LIBPULSE #include "modules/pulseaudio.hpp" #endif diff --git a/include/modules/upower/upower.hpp b/include/modules/upower/upower.hpp new file mode 100644 index 0000000..ede6d7f --- /dev/null +++ b/include/modules/upower/upower.hpp @@ -0,0 +1,43 @@ +#pragma once + +#include + +#include +#include +#include +#include +#include + +#include "ALabel.hpp" +#include "gtkmm/box.h" +#include "gtkmm/image.h" +#include "gtkmm/label.h" + +namespace waybar::modules { + +class UPower : public AModule { + public: + UPower(const std::string &, const Json::Value &); + ~UPower(); + auto update() -> void; + + private: + static void deviceAdded_cb(UpClient *client, UpDevice *device, gpointer data); + static void deviceRemoved_cb(UpClient *client, const gchar *object_path, gpointer data); + static void deviceNotify_cb(gpointer data); + void removeDevice(const std::string devicePath); + void addDevice(UpDevice *device); + void setDisplayDevice(); + void resetDevices(); + static void clicked(); + + Gtk::Box box_; + Gtk::Image icon_; + Gtk::Label label_; + + UpClient *client = NULL; + UpDevice *displayDevice = NULL; + std::map devices; +}; + +} // namespace waybar::modules diff --git a/meson.build b/meson.build index dcc6187..d34ce95 100644 --- a/meson.build +++ b/meson.build @@ -92,6 +92,7 @@ sigcpp = dependency('sigc++-2.0') libepoll = dependency('epoll-shim', required: false) libnl = dependency('libnl-3.0', required: get_option('libnl')) libnlgen = dependency('libnl-genl-3.0', required: get_option('libnl')) +upower_glib = dependency('upower-glib', required: get_option('upower_glib')) libpulse = dependency('libpulse', required: get_option('pulseaudio')) libudev = dependency('libudev', required: get_option('libudev')) libevdev = dependency('libevdev', required: get_option('libevdev')) @@ -203,6 +204,11 @@ if libnl.found() and libnlgen.found() src_files += 'src/modules/network.cpp' endif +if upower_glib.found() + add_project_arguments('-DHAVE_UPOWER', language: 'cpp') + src_files += 'src/modules/upower/upower.cpp' +endif + if libpulse.found() add_project_arguments('-DHAVE_LIBPULSE', language: 'cpp') src_files += 'src/modules/pulseaudio.cpp' @@ -288,6 +294,7 @@ executable( giounix, libnl, libnlgen, + upower_glib, libpulse, libudev, libepoll, @@ -296,7 +303,7 @@ executable( gtk_layer_shell, libsndio, tz_dep, - xkbregistry + xkbregistry ], include_directories: [include_directories('include')], install: true, diff --git a/meson_options.txt b/meson_options.txt index 230a53d..d2e9847 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -3,6 +3,7 @@ option('libnl', type: 'feature', value: 'auto', description: 'Enable libnl suppo option('libudev', type: 'feature', value: 'auto', description: 'Enable libudev support for udev related features') option('libevdev', type: 'feature', value: 'auto', description: 'Enable libevdev support for evdev related features') option('pulseaudio', type: 'feature', value: 'auto', description: 'Enable support for pulseaudio') +option('upower_glib', type: 'feature', value: 'auto', description: 'Enable support for upower') option('systemd', type: 'feature', value: 'auto', description: 'Install systemd user service unit') option('dbusmenu-gtk', type: 'feature', value: 'auto', description: 'Enable support for tray') option('man-pages', type: 'feature', value: 'auto', description: 'Generate and install man pages') diff --git a/src/factory.cpp b/src/factory.cpp index 900653b..a866c37 100644 --- a/src/factory.cpp +++ b/src/factory.cpp @@ -12,6 +12,11 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name) const { return new waybar::modules::Battery(id, config_[name]); } #endif +#ifdef HAVE_UPOWER + if (ref == "upower") { + return new waybar::modules::UPower(id, config_[name]); + } +#endif #ifdef HAVE_SWAY if (ref == "sway/mode") { return new waybar::modules::sway::Mode(id, config_[name]); diff --git a/src/modules/upower/upower.cpp b/src/modules/upower/upower.cpp new file mode 100644 index 0000000..c455c52 --- /dev/null +++ b/src/modules/upower/upower.cpp @@ -0,0 +1,126 @@ +#include "modules/upower/upower.hpp" + +#include +#include +#include + +namespace waybar::modules { +UPower::UPower(const std::string& id, const Json::Value& config) + : AModule(config, "tray", id), + box_(Gtk::ORIENTATION_HORIZONTAL, 0), + icon_(), + label_(), + devices() { + box_.pack_start(icon_); + box_.pack_start(label_); + event_box_.add(box_); + + GError* error = NULL; + client = up_client_new_full(NULL, &error); + if (client == NULL) { + throw std::runtime_error("Unable to create UPower client!"); + } + + g_signal_connect(client, "device-added", G_CALLBACK(deviceAdded_cb), this); + g_signal_connect(client, "device-removed", G_CALLBACK(deviceRemoved_cb), this); + g_signal_connect(client, "notify", G_CALLBACK(deviceNotify_cb), this); + + resetDevices(); + + dp.emit(); +} + +UPower::~UPower() {} + +void UPower::clicked() { printf("CLICK\n"); } + +void UPower::deviceAdded_cb(UpClient* client, UpDevice* device, gpointer data) { + UPower* up = static_cast(data); + up->addDevice(device); + up->setDisplayDevice(); + // Update the widget + up->dp.emit(); +} +void UPower::deviceRemoved_cb(UpClient* client, const gchar* object_path, gpointer data) { + UPower* up = static_cast(data); + up->removeDevice(object_path); + up->setDisplayDevice(); + // Update the widget + up->dp.emit(); +} +void UPower::deviceNotify_cb(gpointer data) { + UPower* up = static_cast(data); + // Update the widget + up->dp.emit(); +} + +void UPower::removeDevice(const std::string devicePath) { devices.erase(devicePath); } + +void UPower::addDevice(UpDevice* device) { + if (device) { + const gchar* objectPath = up_device_get_object_path(device); + devices[objectPath] = device; + g_signal_connect(devices[objectPath], "notify", G_CALLBACK(deviceNotify_cb), this); + } +} + +void UPower::setDisplayDevice() { + displayDevice = up_client_get_display_device(client); + g_signal_connect(displayDevice, "notify", G_CALLBACK(deviceNotify_cb), this); +} + +/** Removes all devices and adds the current devices */ +void UPower::resetDevices() { + // Removes all devices + if (devices.size() > 0) { + auto it = devices.cbegin(); + while (it != devices.cend()) { + devices.erase(it++); + } + } + + // Adds all devices + GPtrArray* newDevices = up_client_get_devices2(client); + for (guint i = 0; i < newDevices->len; i++) { + UpDevice* device = (UpDevice*)g_ptr_array_index(newDevices, i); + if (device) addDevice(device); + } + + setDisplayDevice(); + + // Update the widget + dp.emit(); +} + +auto UPower::update() -> void { + printf("UPDATE!\n"); + + UpDeviceKind kind; + UpDeviceState state; + double percentage; + gboolean is_power_supply; + gboolean is_present; + gchar* icon_name; + + g_object_get(displayDevice, + "kind", + &kind, + "state", + &state, + "is-present", + &is_present, + "power-supply", + &is_power_supply, + "percentage", + &percentage, + "icon-name", + &icon_name, + NULL); + + printf("ICON: %s\n", icon_name); + + // Call parent update + AModule::update(); +} + +} // namespace waybar::modules From 5e9faeb2d055b250f8d435c852de7c6492e96381 Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Tue, 15 Mar 2022 20:22:04 +0100 Subject: [PATCH 02/23] Now shows the percentage and the correct icon --- include/modules/upower/upower.hpp | 5 ++- src/modules/upower/upower.cpp | 71 ++++++++++++++++++++----------- 2 files changed, 51 insertions(+), 25 deletions(-) diff --git a/include/modules/upower/upower.hpp b/include/modules/upower/upower.hpp index ede6d7f..bce89e5 100644 --- a/include/modules/upower/upower.hpp +++ b/include/modules/upower/upower.hpp @@ -29,12 +29,15 @@ class UPower : public AModule { void addDevice(UpDevice *device); void setDisplayDevice(); void resetDevices(); - static void clicked(); Gtk::Box box_; Gtk::Image icon_; Gtk::Label label_; + // Config + bool hideIfEmpty = true; + uint iconSize = 32; + UpClient *client = NULL; UpDevice *displayDevice = NULL; std::map devices; diff --git a/src/modules/upower/upower.cpp b/src/modules/upower/upower.cpp index c455c52..1575c87 100644 --- a/src/modules/upower/upower.cpp +++ b/src/modules/upower/upower.cpp @@ -4,6 +4,9 @@ #include #include +#include "gtkmm/enums.h" +#include "gtkmm/icontheme.h" + namespace waybar::modules { UPower::UPower(const std::string& id, const Json::Value& config) : AModule(config, "tray", id), @@ -15,12 +18,16 @@ UPower::UPower(const std::string& id, const Json::Value& config) box_.pack_start(label_); event_box_.add(box_); + icon_.set_pixel_size(iconSize); + GError* error = NULL; client = up_client_new_full(NULL, &error); if (client == NULL) { throw std::runtime_error("Unable to create UPower client!"); } + // TODO: Connect to login1 prepare_for_sleep signal + g_signal_connect(client, "device-added", G_CALLBACK(deviceAdded_cb), this); g_signal_connect(client, "device-removed", G_CALLBACK(deviceRemoved_cb), this); g_signal_connect(client, "notify", G_CALLBACK(deviceNotify_cb), this); @@ -32,8 +39,6 @@ UPower::UPower(const std::string& id, const Json::Value& config) UPower::~UPower() {} -void UPower::clicked() { printf("CLICK\n"); } - void UPower::deviceAdded_cb(UpClient* client, UpDevice* device, gpointer data) { UPower* up = static_cast(data); up->addDevice(device); @@ -93,31 +98,49 @@ void UPower::resetDevices() { } auto UPower::update() -> void { - printf("UPDATE!\n"); + if (devices.size() == 0 && hideIfEmpty) { + box_.set_visible(false); + } else { + box_.set_visible(true); - UpDeviceKind kind; - UpDeviceState state; - double percentage; - gboolean is_power_supply; - gboolean is_present; - gchar* icon_name; + UpDeviceKind kind; + UpDeviceState state; + double percentage; + gboolean is_power_supply; + gboolean is_present; + gchar* icon_name; - g_object_get(displayDevice, - "kind", - &kind, - "state", - &state, - "is-present", - &is_present, - "power-supply", - &is_power_supply, - "percentage", - &percentage, - "icon-name", - &icon_name, - NULL); + g_object_get(displayDevice, + "kind", + &kind, + "state", + &state, + "is-present", + &is_present, + "power-supply", + &is_power_supply, + "percentage", + &percentage, + "icon-name", + &icon_name, + NULL); - printf("ICON: %s\n", icon_name); + bool displayDeviceValid = + kind == UpDeviceKind::UP_DEVICE_KIND_BATTERY || kind == UpDeviceKind::UP_DEVICE_KIND_UPS; + + // TODO: Tooltip + + // Set percentage + std::string percent_string = + displayDeviceValid ? std::to_string(int(percentage) + 0.5) + "%" : ""; + label_.set_text(percent_string); + + // Set icon + if (!Gtk::IconTheme::get_default()->has_icon(icon_name)) { + icon_name = (char*)"battery-missing-symbolic"; + } + icon_.set_from_icon_name(icon_name, Gtk::ICON_SIZE_INVALID); + } // Call parent update AModule::update(); From 5396ffb71fa4169d031776de6ff96af09059e39b Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Tue, 15 Mar 2022 20:22:32 +0100 Subject: [PATCH 03/23] Added "icon-size" and "hide-if-empty" config options --- src/modules/upower/upower.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/modules/upower/upower.cpp b/src/modules/upower/upower.cpp index 1575c87..0e6796c 100644 --- a/src/modules/upower/upower.cpp +++ b/src/modules/upower/upower.cpp @@ -18,8 +18,17 @@ UPower::UPower(const std::string& id, const Json::Value& config) box_.pack_start(label_); event_box_.add(box_); + // Icon Size + if (config_["icon-size"].isUInt()) { + iconSize = config_["icon-size"].asUInt(); + } icon_.set_pixel_size(iconSize); + // Hide If Empty + if (config_["hide-if-empty"].isBool()) { + hideIfEmpty = config_["hide-if-empty"].asBool(); + } + GError* error = NULL; client = up_client_new_full(NULL, &error); if (client == NULL) { From d47073ef13041935791d97ae1e071f58cf9ef135 Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Tue, 15 Mar 2022 22:49:40 +0100 Subject: [PATCH 04/23] Reload all devices after wake from suspend --- include/modules/upower/upower.hpp | 6 +++++ meson.build | 4 ++-- src/modules/upower/upower.cpp | 40 +++++++++++++++++++++++++++++-- 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/include/modules/upower/upower.hpp b/include/modules/upower/upower.hpp index bce89e5..3160499 100644 --- a/include/modules/upower/upower.hpp +++ b/include/modules/upower/upower.hpp @@ -25,6 +25,10 @@ class UPower : public AModule { static void deviceAdded_cb(UpClient *client, UpDevice *device, gpointer data); static void deviceRemoved_cb(UpClient *client, const gchar *object_path, gpointer data); static void deviceNotify_cb(gpointer data); + static void prepareForSleep_cb(GDBusConnection *system_bus, const gchar *sender_name, + const gchar *object_path, const gchar *interface_name, + const gchar *signal_name, GVariant *parameters, + gpointer user_data); void removeDevice(const std::string devicePath); void addDevice(UpDevice *device); void setDisplayDevice(); @@ -41,6 +45,8 @@ class UPower : public AModule { UpClient *client = NULL; UpDevice *displayDevice = NULL; std::map devices; + guint login1_id; + GDBusConnection *login1_connection; }; } // namespace waybar::modules diff --git a/meson.build b/meson.build index d34ce95..5e76181 100644 --- a/meson.build +++ b/meson.build @@ -86,7 +86,7 @@ wayland_cursor = dependency('wayland-cursor') wayland_protos = dependency('wayland-protocols') gtkmm = dependency('gtkmm-3.0', version : ['>=3.22.0']) dbusmenu_gtk = dependency('dbusmenu-gtk3-0.4', required: get_option('dbusmenu-gtk')) -giounix = dependency('gio-unix-2.0', required: (get_option('dbusmenu-gtk').enabled() or get_option('logind').enabled())) +giounix = dependency('gio-unix-2.0', required: (get_option('dbusmenu-gtk').enabled() or get_option('logind').enabled() or get_option('upower_glib').enabled())) jsoncpp = dependency('jsoncpp') sigcpp = dependency('sigc++-2.0') libepoll = dependency('epoll-shim', required: false) @@ -204,7 +204,7 @@ if libnl.found() and libnlgen.found() src_files += 'src/modules/network.cpp' endif -if upower_glib.found() +if (upower_glib.found() and giounix.found() and not get_option('logind').disabled()) add_project_arguments('-DHAVE_UPOWER', language: 'cpp') src_files += 'src/modules/upower/upower.cpp' endif diff --git a/src/modules/upower/upower.cpp b/src/modules/upower/upower.cpp index 0e6796c..a26dc9e 100644 --- a/src/modules/upower/upower.cpp +++ b/src/modules/upower/upower.cpp @@ -1,5 +1,7 @@ #include "modules/upower/upower.hpp" +#include + #include #include #include @@ -35,7 +37,22 @@ UPower::UPower(const std::string& id, const Json::Value& config) throw std::runtime_error("Unable to create UPower client!"); } - // TODO: Connect to login1 prepare_for_sleep signal + // Connect to Login1 PrepareForSleep signal + login1_connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error); + if (!login1_connection) { + throw std::runtime_error("Unable to connect to the SYSTEM Bus!..."); + } else { + login1_id = g_dbus_connection_signal_subscribe(login1_connection, + "org.freedesktop.login1", + "org.freedesktop.login1.Manager", + "PrepareForSleep", + "/org/freedesktop/login1", + NULL, + G_DBUS_SIGNAL_FLAGS_NONE, + prepareForSleep_cb, + this, + NULL); + } g_signal_connect(client, "device-added", G_CALLBACK(deviceAdded_cb), this); g_signal_connect(client, "device-removed", G_CALLBACK(deviceRemoved_cb), this); @@ -46,7 +63,13 @@ UPower::UPower(const std::string& id, const Json::Value& config) dp.emit(); } -UPower::~UPower() {} +UPower::~UPower() { + if (client != NULL) g_object_unref(client); + if (login1_id > 0) { + g_dbus_connection_signal_unsubscribe(login1_connection, login1_id); + login1_id = 0; + } +} void UPower::deviceAdded_cb(UpClient* client, UpDevice* device, gpointer data) { UPower* up = static_cast(data); @@ -67,6 +90,19 @@ void UPower::deviceNotify_cb(gpointer data) { // Update the widget up->dp.emit(); } +void UPower::prepareForSleep_cb(GDBusConnection* system_bus, const gchar* sender_name, + const gchar* object_path, const gchar* interface_name, + const gchar* signal_name, GVariant* parameters, gpointer data) { + if (g_variant_is_of_type(parameters, G_VARIANT_TYPE("(b)"))) { + gboolean sleeping; + g_variant_get(parameters, "(b)", &sleeping); + + if (!sleeping) { + UPower* up = static_cast(data); + up->resetDevices(); + } + } +} void UPower::removeDevice(const std::string devicePath) { devices.erase(devicePath); } From 9b9e42fc5fc1164e76e4a0783629380878d68c02 Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Tue, 15 Mar 2022 22:50:11 +0100 Subject: [PATCH 05/23] use device variable instead of getting the device from the map --- src/modules/upower/upower.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/upower/upower.cpp b/src/modules/upower/upower.cpp index a26dc9e..153f2b6 100644 --- a/src/modules/upower/upower.cpp +++ b/src/modules/upower/upower.cpp @@ -110,7 +110,7 @@ void UPower::addDevice(UpDevice* device) { if (device) { const gchar* objectPath = up_device_get_object_path(device); devices[objectPath] = device; - g_signal_connect(devices[objectPath], "notify", G_CALLBACK(deviceNotify_cb), this); + g_signal_connect(device, "notify", G_CALLBACK(deviceNotify_cb), this); } } From 6eb187a23ec2be46f0d5bd26c1deacc99578fc57 Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Tue, 15 Mar 2022 23:00:09 +0100 Subject: [PATCH 06/23] Moved upower.*pp out of the upower directories --- include/factory.hpp | 2 +- include/modules/{upower => }/upower.hpp | 0 meson.build | 2 +- src/modules/{upower => }/upower.cpp | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) rename include/modules/{upower => }/upower.hpp (100%) rename src/modules/{upower => }/upower.cpp (99%) diff --git a/include/factory.hpp b/include/factory.hpp index 3954dac..e4e8fa7 100644 --- a/include/factory.hpp +++ b/include/factory.hpp @@ -43,7 +43,7 @@ #include "modules/keyboard_state.hpp" #endif #ifdef HAVE_UPOWER -#include "modules/upower/upower.hpp" +#include "modules/upower.hpp" #endif #ifdef HAVE_LIBPULSE #include "modules/pulseaudio.hpp" diff --git a/include/modules/upower/upower.hpp b/include/modules/upower.hpp similarity index 100% rename from include/modules/upower/upower.hpp rename to include/modules/upower.hpp diff --git a/meson.build b/meson.build index 5e76181..3155137 100644 --- a/meson.build +++ b/meson.build @@ -206,7 +206,7 @@ endif if (upower_glib.found() and giounix.found() and not get_option('logind').disabled()) add_project_arguments('-DHAVE_UPOWER', language: 'cpp') - src_files += 'src/modules/upower/upower.cpp' + src_files += 'src/modules/upower.cpp' endif if libpulse.found() diff --git a/src/modules/upower/upower.cpp b/src/modules/upower.cpp similarity index 99% rename from src/modules/upower/upower.cpp rename to src/modules/upower.cpp index 153f2b6..abcfa94 100644 --- a/src/modules/upower/upower.cpp +++ b/src/modules/upower.cpp @@ -1,4 +1,4 @@ -#include "modules/upower/upower.hpp" +#include "modules/upower.hpp" #include From 136b47ce0d84df665349973140a0e5746c9d3e23 Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Tue, 15 Mar 2022 23:03:13 +0100 Subject: [PATCH 07/23] Fixed percentage not getting rounded --- src/modules/upower.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/upower.cpp b/src/modules/upower.cpp index abcfa94..c688777 100644 --- a/src/modules/upower.cpp +++ b/src/modules/upower.cpp @@ -177,7 +177,7 @@ auto UPower::update() -> void { // Set percentage std::string percent_string = - displayDeviceValid ? std::to_string(int(percentage) + 0.5) + "%" : ""; + displayDeviceValid ? std::to_string(int(percentage + 0.5)) + "%" : ""; label_.set_text(percent_string); // Set icon From 2a563f54e73c97d7a022b0c053a2822da1d6e944 Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Wed, 16 Mar 2022 15:33:39 +0100 Subject: [PATCH 08/23] Change name to upower --- src/modules/upower.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/upower.cpp b/src/modules/upower.cpp index c688777..78914fd 100644 --- a/src/modules/upower.cpp +++ b/src/modules/upower.cpp @@ -11,7 +11,7 @@ namespace waybar::modules { UPower::UPower(const std::string& id, const Json::Value& config) - : AModule(config, "tray", id), + : AModule(config, "upower", id), box_(Gtk::ORIENTATION_HORIZONTAL, 0), icon_(), label_(), From 105f1cefe1a7aff160a8b4f30a8b996f5b3dc8ca Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Sat, 19 Mar 2022 10:52:05 +0100 Subject: [PATCH 09/23] Fixed device unrefed --- include/modules/upower.hpp | 21 ++++++------ src/modules/upower.cpp | 66 ++++++++++++++++++++++++++------------ 2 files changed, 57 insertions(+), 30 deletions(-) diff --git a/include/modules/upower.hpp b/include/modules/upower.hpp index 3160499..9b09046 100644 --- a/include/modules/upower.hpp +++ b/include/modules/upower.hpp @@ -2,11 +2,9 @@ #include -#include #include #include #include -#include #include "ALabel.hpp" #include "gtkmm/box.h" @@ -22,14 +20,16 @@ class UPower : public AModule { auto update() -> void; private: + typedef std::unordered_map Devices; + static void deviceAdded_cb(UpClient *client, UpDevice *device, gpointer data); - static void deviceRemoved_cb(UpClient *client, const gchar *object_path, gpointer data); - static void deviceNotify_cb(gpointer data); + static void deviceRemoved_cb(UpClient *client, const gchar *objectPath, gpointer data); + static void deviceNotify_cb(UpDevice *device, GParamSpec *pspec, gpointer user_data); static void prepareForSleep_cb(GDBusConnection *system_bus, const gchar *sender_name, const gchar *object_path, const gchar *interface_name, const gchar *signal_name, GVariant *parameters, gpointer user_data); - void removeDevice(const std::string devicePath); + void removeDevice(const gchar *objectPath); void addDevice(UpDevice *device); void setDisplayDevice(); void resetDevices(); @@ -42,11 +42,12 @@ class UPower : public AModule { bool hideIfEmpty = true; uint iconSize = 32; - UpClient *client = NULL; - UpDevice *displayDevice = NULL; - std::map devices; - guint login1_id; - GDBusConnection *login1_connection; + Devices devices; + std::mutex m_Mutex; + UpClient *client; + UpDevice *displayDevice; + guint login1_id; + GDBusConnection *login1_connection; }; } // namespace waybar::modules diff --git a/src/modules/upower.cpp b/src/modules/upower.cpp index 78914fd..8f1a373 100644 --- a/src/modules/upower.cpp +++ b/src/modules/upower.cpp @@ -1,12 +1,5 @@ #include "modules/upower.hpp" -#include - -#include -#include -#include - -#include "gtkmm/enums.h" #include "gtkmm/icontheme.h" namespace waybar::modules { @@ -15,7 +8,9 @@ UPower::UPower(const std::string& id, const Json::Value& config) box_(Gtk::ORIENTATION_HORIZONTAL, 0), icon_(), label_(), - devices() { + devices(), + m_Mutex(), + client() { box_.pack_start(icon_); box_.pack_start(label_); event_box_.add(box_); @@ -56,11 +51,8 @@ UPower::UPower(const std::string& id, const Json::Value& config) g_signal_connect(client, "device-added", G_CALLBACK(deviceAdded_cb), this); g_signal_connect(client, "device-removed", G_CALLBACK(deviceRemoved_cb), this); - g_signal_connect(client, "notify", G_CALLBACK(deviceNotify_cb), this); resetDevices(); - - dp.emit(); } UPower::~UPower() { @@ -78,14 +70,14 @@ void UPower::deviceAdded_cb(UpClient* client, UpDevice* device, gpointer data) { // Update the widget up->dp.emit(); } -void UPower::deviceRemoved_cb(UpClient* client, const gchar* object_path, gpointer data) { +void UPower::deviceRemoved_cb(UpClient* client, const gchar* objectPath, gpointer data) { UPower* up = static_cast(data); - up->removeDevice(object_path); + up->removeDevice(objectPath); up->setDisplayDevice(); // Update the widget up->dp.emit(); } -void UPower::deviceNotify_cb(gpointer data) { +void UPower::deviceNotify_cb(UpDevice* device, GParamSpec* pspec, gpointer data) { UPower* up = static_cast(data); // Update the widget up->dp.emit(); @@ -104,17 +96,47 @@ void UPower::prepareForSleep_cb(GDBusConnection* system_bus, const gchar* sender } } -void UPower::removeDevice(const std::string devicePath) { devices.erase(devicePath); } +void UPower::removeDevice(const gchar* objectPath) { + std::lock_guard guard(m_Mutex); + if (devices.find(objectPath) != devices.end()) { + UpDevice* device = devices[objectPath]; + if (G_IS_OBJECT(device)) { + g_object_unref(device); + } + devices.erase(objectPath); + } +} void UPower::addDevice(UpDevice* device) { - if (device) { + if (G_IS_OBJECT(device)) { const gchar* objectPath = up_device_get_object_path(device); - devices[objectPath] = device; + + // Due to the device getting cleared after this event is fired, we + // create a new object pointing to its objectPath + gboolean ret; + device = up_device_new(); + ret = up_device_set_object_path_sync(device, objectPath, NULL, NULL); + if (!ret) { + g_object_unref(G_OBJECT(device)); + return; + } + + std::lock_guard guard(m_Mutex); + if (devices.find(objectPath) != devices.end()) { + UpDevice* device = devices[objectPath]; + if (G_IS_OBJECT(device)) { + g_object_unref(device); + } + devices.erase(objectPath); + } + g_signal_connect(device, "notify", G_CALLBACK(deviceNotify_cb), this); + devices.emplace(Devices::value_type(objectPath, device)); } } void UPower::setDisplayDevice() { + std::lock_guard guard(m_Mutex); displayDevice = up_client_get_display_device(client); g_signal_connect(displayDevice, "notify", G_CALLBACK(deviceNotify_cb), this); } @@ -122,9 +144,12 @@ void UPower::setDisplayDevice() { /** Removes all devices and adds the current devices */ void UPower::resetDevices() { // Removes all devices - if (devices.size() > 0) { + if (!devices.empty()) { auto it = devices.cbegin(); while (it != devices.cend()) { + if (G_IS_OBJECT(it->second)) { + g_object_unref(it->second); + } devices.erase(it++); } } @@ -143,10 +168,11 @@ void UPower::resetDevices() { } auto UPower::update() -> void { + std::lock_guard guard(m_Mutex); if (devices.size() == 0 && hideIfEmpty) { - box_.set_visible(false); + event_box_.set_visible(false); } else { - box_.set_visible(true); + event_box_.set_visible(true); UpDeviceKind kind; UpDeviceState state; From 7345918f84ba520f71c287f799c033cdf2b190d5 Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Sat, 19 Mar 2022 11:18:51 +0100 Subject: [PATCH 10/23] Added mutex locking to resetDevices --- include/modules/upower.hpp | 2 +- src/modules/upower.cpp | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/include/modules/upower.hpp b/include/modules/upower.hpp index 9b09046..45467d3 100644 --- a/include/modules/upower.hpp +++ b/include/modules/upower.hpp @@ -30,7 +30,7 @@ class UPower : public AModule { const gchar *signal_name, GVariant *parameters, gpointer user_data); void removeDevice(const gchar *objectPath); - void addDevice(UpDevice *device); + void addDevice(UpDevice *device, bool lockMutex = true); void setDisplayDevice(); void resetDevices(); diff --git a/src/modules/upower.cpp b/src/modules/upower.cpp index 8f1a373..d42caa5 100644 --- a/src/modules/upower.cpp +++ b/src/modules/upower.cpp @@ -53,6 +53,7 @@ UPower::UPower(const std::string& id, const Json::Value& config) g_signal_connect(client, "device-removed", G_CALLBACK(deviceRemoved_cb), this); resetDevices(); + setDisplayDevice(); } UPower::~UPower() { @@ -92,6 +93,7 @@ void UPower::prepareForSleep_cb(GDBusConnection* system_bus, const gchar* sender if (!sleeping) { UPower* up = static_cast(data); up->resetDevices(); + up->setDisplayDevice(); } } } @@ -107,7 +109,7 @@ void UPower::removeDevice(const gchar* objectPath) { } } -void UPower::addDevice(UpDevice* device) { +void UPower::addDevice(UpDevice* device, bool lockMutex) { if (G_IS_OBJECT(device)) { const gchar* objectPath = up_device_get_object_path(device); @@ -121,7 +123,8 @@ void UPower::addDevice(UpDevice* device) { return; } - std::lock_guard guard(m_Mutex); + if (lockMutex) std::lock_guard guard(m_Mutex); + if (devices.find(objectPath) != devices.end()) { UpDevice* device = devices[objectPath]; if (G_IS_OBJECT(device)) { @@ -143,6 +146,7 @@ void UPower::setDisplayDevice() { /** Removes all devices and adds the current devices */ void UPower::resetDevices() { + std::lock_guard guard(m_Mutex); // Removes all devices if (!devices.empty()) { auto it = devices.cbegin(); @@ -158,11 +162,9 @@ void UPower::resetDevices() { GPtrArray* newDevices = up_client_get_devices2(client); for (guint i = 0; i < newDevices->len; i++) { UpDevice* device = (UpDevice*)g_ptr_array_index(newDevices, i); - if (device) addDevice(device); + if (device) addDevice(device, false); } - setDisplayDevice(); - // Update the widget dp.emit(); } From d7a030daf3cea708e4707d154812b81d398a1384 Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Sat, 19 Mar 2022 11:19:08 +0100 Subject: [PATCH 11/23] Lowered default icon size to 20 --- include/modules/upower.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/modules/upower.hpp b/include/modules/upower.hpp index 45467d3..cf72a47 100644 --- a/include/modules/upower.hpp +++ b/include/modules/upower.hpp @@ -40,7 +40,7 @@ class UPower : public AModule { // Config bool hideIfEmpty = true; - uint iconSize = 32; + uint iconSize = 20; Devices devices; std::mutex m_Mutex; From 2b2ac311d50ac23744861c12a5b671436cccd54d Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Sat, 19 Mar 2022 11:19:39 +0100 Subject: [PATCH 12/23] Fixed not visible when only battery is plugged in --- src/modules/upower.cpp | 90 +++++++++++++++++++++++------------------- 1 file changed, 49 insertions(+), 41 deletions(-) diff --git a/src/modules/upower.cpp b/src/modules/upower.cpp index d42caa5..5becb91 100644 --- a/src/modules/upower.cpp +++ b/src/modules/upower.cpp @@ -171,50 +171,58 @@ void UPower::resetDevices() { auto UPower::update() -> void { std::lock_guard guard(m_Mutex); - if (devices.size() == 0 && hideIfEmpty) { + + UpDeviceKind kind; + UpDeviceState state; + double percentage; + gboolean is_power_supply; + gboolean is_present; + gchar* icon_name; + + g_object_get(displayDevice, + "kind", + &kind, + "state", + &state, + "is-present", + &is_present, + "power-supply", + &is_power_supply, + "percentage", + &percentage, + "icon-name", + &icon_name, + NULL); + + bool displayDeviceValid = + kind == UpDeviceKind::UP_DEVICE_KIND_BATTERY || kind == UpDeviceKind::UP_DEVICE_KIND_UPS; + + std::string percentString = ""; + + std::string tooltip = ""; + + if (devices.size() == 0 && !displayDeviceValid && hideIfEmpty) { event_box_.set_visible(false); - } else { - event_box_.set_visible(true); - - UpDeviceKind kind; - UpDeviceState state; - double percentage; - gboolean is_power_supply; - gboolean is_present; - gchar* icon_name; - - g_object_get(displayDevice, - "kind", - &kind, - "state", - &state, - "is-present", - &is_present, - "power-supply", - &is_power_supply, - "percentage", - &percentage, - "icon-name", - &icon_name, - NULL); - - bool displayDeviceValid = - kind == UpDeviceKind::UP_DEVICE_KIND_BATTERY || kind == UpDeviceKind::UP_DEVICE_KIND_UPS; - - // TODO: Tooltip - - // Set percentage - std::string percent_string = - displayDeviceValid ? std::to_string(int(percentage + 0.5)) + "%" : ""; - label_.set_text(percent_string); - - // Set icon - if (!Gtk::IconTheme::get_default()->has_icon(icon_name)) { - icon_name = (char*)"battery-missing-symbolic"; - } - icon_.set_from_icon_name(icon_name, Gtk::ICON_SIZE_INVALID); + goto update; } + event_box_.set_visible(true); + + // TODO: Tooltip + + // Set percentage + if (displayDeviceValid) { + percentString = std::to_string(int(percentage + 0.5)) + "%"; + } + label_.set_text(percentString); + + // Set icon + if (!Gtk::IconTheme::get_default()->has_icon(icon_name)) { + icon_name = (char*)"battery-missing-symbolic"; + } + icon_.set_from_icon_name(icon_name, Gtk::ICON_SIZE_INVALID); + +update: // Call parent update AModule::update(); } From 14a2a7027ffc5ea6e8bf129d84ffce3f076f338a Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Sat, 19 Mar 2022 11:34:34 +0100 Subject: [PATCH 13/23] Moved upower into its own directory --- include/factory.hpp | 2 +- include/modules/{ => upower}/upower.hpp | 5 +++-- meson.build | 2 +- src/modules/{ => upower}/upower.cpp | 29 +++++++++++++++++++------ 4 files changed, 27 insertions(+), 11 deletions(-) rename include/modules/{ => upower}/upower.hpp (95%) rename src/modules/{ => upower}/upower.cpp (91%) diff --git a/include/factory.hpp b/include/factory.hpp index e4e8fa7..3954dac 100644 --- a/include/factory.hpp +++ b/include/factory.hpp @@ -43,7 +43,7 @@ #include "modules/keyboard_state.hpp" #endif #ifdef HAVE_UPOWER -#include "modules/upower.hpp" +#include "modules/upower/upower.hpp" #endif #ifdef HAVE_LIBPULSE #include "modules/pulseaudio.hpp" diff --git a/include/modules/upower.hpp b/include/modules/upower/upower.hpp similarity index 95% rename from include/modules/upower.hpp rename to include/modules/upower/upower.hpp index cf72a47..6145a15 100644 --- a/include/modules/upower.hpp +++ b/include/modules/upower/upower.hpp @@ -19,9 +19,9 @@ class UPower : public AModule { ~UPower(); auto update() -> void; - private: typedef std::unordered_map Devices; + private: 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); @@ -30,9 +30,10 @@ class UPower : public AModule { const gchar *signal_name, GVariant *parameters, gpointer user_data); void removeDevice(const gchar *objectPath); - void addDevice(UpDevice *device, bool lockMutex = true); + void addDevice(UpDevice *device); void setDisplayDevice(); void resetDevices(); + void removeDevices(); Gtk::Box box_; Gtk::Image icon_; diff --git a/meson.build b/meson.build index 3155137..5e76181 100644 --- a/meson.build +++ b/meson.build @@ -206,7 +206,7 @@ endif if (upower_glib.found() and giounix.found() and not get_option('logind').disabled()) add_project_arguments('-DHAVE_UPOWER', language: 'cpp') - src_files += 'src/modules/upower.cpp' + src_files += 'src/modules/upower/upower.cpp' endif if libpulse.found() diff --git a/src/modules/upower.cpp b/src/modules/upower/upower.cpp similarity index 91% rename from src/modules/upower.cpp rename to src/modules/upower/upower.cpp index 5becb91..a4f6200 100644 --- a/src/modules/upower.cpp +++ b/src/modules/upower/upower.cpp @@ -1,4 +1,4 @@ -#include "modules/upower.hpp" +#include "modules/upower/upower.hpp" #include "gtkmm/icontheme.h" @@ -109,7 +109,7 @@ void UPower::removeDevice(const gchar* objectPath) { } } -void UPower::addDevice(UpDevice* device, bool lockMutex) { +void UPower::addDevice(UpDevice* device) { if (G_IS_OBJECT(device)) { const gchar* objectPath = up_device_get_object_path(device); @@ -123,7 +123,7 @@ void UPower::addDevice(UpDevice* device, bool lockMutex) { return; } - if (lockMutex) std::lock_guard guard(m_Mutex); + std::lock_guard guard(m_Mutex); if (devices.find(objectPath) != devices.end()) { UpDevice* device = devices[objectPath]; @@ -144,10 +144,8 @@ void UPower::setDisplayDevice() { g_signal_connect(displayDevice, "notify", G_CALLBACK(deviceNotify_cb), this); } -/** Removes all devices and adds the current devices */ -void UPower::resetDevices() { +void UPower::removeDevices() { std::lock_guard guard(m_Mutex); - // Removes all devices if (!devices.empty()) { auto it = devices.cbegin(); while (it != devices.cend()) { @@ -157,12 +155,18 @@ void UPower::resetDevices() { devices.erase(it++); } } +} + +/** Removes all devices and adds the current devices */ +void UPower::resetDevices() { + // Removes all devices + removeDevices(); // Adds all devices GPtrArray* newDevices = up_client_get_devices2(client); for (guint i = 0; i < newDevices->len; i++) { UpDevice* device = (UpDevice*)g_ptr_array_index(newDevices, i); - if (device) addDevice(device, false); + if (device && G_IS_OBJECT(device)) addDevice(device); } // Update the widget @@ -209,6 +213,17 @@ auto UPower::update() -> void { event_box_.set_visible(true); // TODO: Tooltip + if (!devices.empty()) { + for (auto& e : devices) { + const gchar* objectPath = up_device_get_object_path(e.second); + double percentage; + g_object_get(e.second, "percentage", &percentage, NULL); + printf("Device: %s, VALID: %f\n", objectPath, percentage); + } + } else { + printf("No devices\n"); + } + // box_.set_tooltip // Set percentage if (displayDeviceValid) { From 4196e0d5d1d7c12251ca1429e2f9f1fd91974679 Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Sat, 19 Mar 2022 11:35:13 +0100 Subject: [PATCH 14/23] Unref all devices on destruct --- src/modules/upower/upower.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modules/upower/upower.cpp b/src/modules/upower/upower.cpp index a4f6200..1573796 100644 --- a/src/modules/upower/upower.cpp +++ b/src/modules/upower/upower.cpp @@ -62,6 +62,7 @@ UPower::~UPower() { g_dbus_connection_signal_unsubscribe(login1_connection, login1_id); login1_id = 0; } + removeDevices(); } void UPower::deviceAdded_cb(UpClient* client, UpDevice* device, gpointer data) { From 7fac2afb85dfa4081a373564e0a21b072157a1be Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Sat, 19 Mar 2022 17:09:55 +0100 Subject: [PATCH 15/23] Added custom tooltip with device icon, device name and battery status --- include/modules/upower/upower.hpp | 11 +- include/modules/upower/upower_tooltip.hpp | 29 ++++ meson.build | 1 + src/factory.cpp | 2 +- src/modules/upower/upower.cpp | 46 +++++-- src/modules/upower/upower_tooltip.cpp | 158 ++++++++++++++++++++++ 6 files changed, 229 insertions(+), 18 deletions(-) create mode 100644 include/modules/upower/upower_tooltip.hpp create mode 100644 src/modules/upower/upower_tooltip.cpp diff --git a/include/modules/upower/upower.hpp b/include/modules/upower/upower.hpp index 6145a15..c73a072 100644 --- a/include/modules/upower/upower.hpp +++ b/include/modules/upower/upower.hpp @@ -10,8 +10,9 @@ #include "gtkmm/box.h" #include "gtkmm/image.h" #include "gtkmm/label.h" +#include "modules/upower/upower_tooltip.hpp" -namespace waybar::modules { +namespace waybar::modules::upower { class UPower : public AModule { public: @@ -19,9 +20,9 @@ class UPower : public AModule { ~UPower(); auto update() -> void; + private: typedef std::unordered_map Devices; - private: 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); @@ -34,6 +35,7 @@ class UPower : public AModule { void setDisplayDevice(); void resetDevices(); void removeDevices(); + bool show_tooltip_callback(int, int, bool, const Glib::RefPtr &tooltip); Gtk::Box box_; Gtk::Image icon_; @@ -41,6 +43,8 @@ class UPower : public AModule { // Config bool hideIfEmpty = true; + bool tooltip_enabled = true; + uint tooltip_spacing = 4; uint iconSize = 20; Devices devices; @@ -49,6 +53,7 @@ class UPower : public AModule { UpDevice *displayDevice; guint login1_id; GDBusConnection *login1_connection; + UPowerTooltip *upower_tooltip; }; -} // namespace waybar::modules +} // namespace waybar::modules::upower diff --git a/include/modules/upower/upower_tooltip.hpp b/include/modules/upower/upower_tooltip.hpp new file mode 100644 index 0000000..09f6e60 --- /dev/null +++ b/include/modules/upower/upower_tooltip.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include + +#include "gtkmm/box.h" +#include "gtkmm/label.h" +#include "gtkmm/window.h" + +namespace waybar::modules::upower { + +class UPowerTooltip : public Gtk::Window { + private: + typedef std::unordered_map Devices; + + std::string getDeviceIcon(UpDeviceKind& kind); + + Gtk::Box* contentBox; + + uint iconSize; + uint tooltipSpacing; + + public: + UPowerTooltip(uint iconSize, uint tooltipSpacing); + ~UPowerTooltip(); + + uint updateTooltip(Devices& devices); +}; + +} // namespace waybar::modules::upower diff --git a/meson.build b/meson.build index 5e76181..e9daeca 100644 --- a/meson.build +++ b/meson.build @@ -207,6 +207,7 @@ endif if (upower_glib.found() and giounix.found() and not get_option('logind').disabled()) add_project_arguments('-DHAVE_UPOWER', language: 'cpp') src_files += 'src/modules/upower/upower.cpp' + src_files += 'src/modules/upower/upower_tooltip.cpp' endif if libpulse.found() diff --git a/src/factory.cpp b/src/factory.cpp index a866c37..ab0dc43 100644 --- a/src/factory.cpp +++ b/src/factory.cpp @@ -14,7 +14,7 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name) const { #endif #ifdef HAVE_UPOWER if (ref == "upower") { - return new waybar::modules::UPower(id, config_[name]); + return new waybar::modules::upower::UPower(id, config_[name]); } #endif #ifdef HAVE_SWAY diff --git a/src/modules/upower/upower.cpp b/src/modules/upower/upower.cpp index 1573796..aef874b 100644 --- a/src/modules/upower/upower.cpp +++ b/src/modules/upower/upower.cpp @@ -1,8 +1,11 @@ #include "modules/upower/upower.hpp" #include "gtkmm/icontheme.h" +#include "gtkmm/label.h" +#include "gtkmm/tooltip.h" +#include "modules/upower/upower_tooltip.hpp" -namespace waybar::modules { +namespace waybar::modules::upower { UPower::UPower(const std::string& id, const Json::Value& config) : AModule(config, "upower", id), box_(Gtk::ORIENTATION_HORIZONTAL, 0), @@ -26,6 +29,23 @@ UPower::UPower(const std::string& id, const Json::Value& config) hideIfEmpty = config_["hide-if-empty"].asBool(); } + // Tooltip Spacing + if (config_["tooltip-spacing"].isUInt()) { + tooltip_spacing = config_["tooltip-spacing"].asUInt(); + } + + // Tooltip + if (config_["tooltip"].isBool()) { + tooltip_enabled = config_["tooltip"].asBool(); + } + box_.set_has_tooltip(tooltip_enabled); + if (tooltip_enabled) { + // Sets the window to use when showing the tooltip + upower_tooltip = new UPowerTooltip(iconSize, tooltip_spacing); + box_.set_tooltip_window(*upower_tooltip); + box_.signal_query_tooltip().connect(sigc::mem_fun(*this, &UPower::show_tooltip_callback)); + } + GError* error = NULL; client = up_client_new_full(NULL, &error); if (client == NULL) { @@ -174,6 +194,10 @@ void UPower::resetDevices() { dp.emit(); } +bool UPower::show_tooltip_callback(int, int, bool, const Glib::RefPtr& tooltip) { + return true; +} + auto UPower::update() -> void { std::lock_guard guard(m_Mutex); @@ -204,7 +228,7 @@ auto UPower::update() -> void { std::string percentString = ""; - std::string tooltip = ""; + uint tooltipCount = 0; if (devices.size() == 0 && !displayDeviceValid && hideIfEmpty) { event_box_.set_visible(false); @@ -213,18 +237,12 @@ auto UPower::update() -> void { event_box_.set_visible(true); - // TODO: Tooltip - if (!devices.empty()) { - for (auto& e : devices) { - const gchar* objectPath = up_device_get_object_path(e.second); - double percentage; - g_object_get(e.second, "percentage", &percentage, NULL); - printf("Device: %s, VALID: %f\n", objectPath, percentage); - } - } else { - printf("No devices\n"); + // Tooltip + if (tooltip_enabled) { + tooltipCount = upower_tooltip->updateTooltip(devices); + // Disable the tooltip if there aren't any devices in the tooltip + box_.set_has_tooltip(!devices.empty() && tooltipCount > 0); } - // box_.set_tooltip // Set percentage if (displayDeviceValid) { @@ -243,4 +261,4 @@ update: AModule::update(); } -} // namespace waybar::modules +} // namespace waybar::modules::upower diff --git a/src/modules/upower/upower_tooltip.cpp b/src/modules/upower/upower_tooltip.cpp new file mode 100644 index 0000000..2bff69c --- /dev/null +++ b/src/modules/upower/upower_tooltip.cpp @@ -0,0 +1,158 @@ +#include "modules/upower/upower_tooltip.hpp" + +#include "gtkmm/box.h" +#include "gtkmm/enums.h" +#include "gtkmm/icontheme.h" +#include "gtkmm/image.h" +#include "gtkmm/label.h" + +namespace waybar::modules::upower { +UPowerTooltip::UPowerTooltip(uint iconSize_, uint tooltipSpacing_) + : Gtk::Window(), iconSize(iconSize_), tooltipSpacing(tooltipSpacing_) { + contentBox = new Gtk::Box(Gtk::ORIENTATION_VERTICAL); + add(*contentBox); + contentBox->show(); +} + +UPowerTooltip::~UPowerTooltip() {} + +uint UPowerTooltip::updateTooltip(Devices& devices) { + // Removes all old devices + for (auto child : contentBox->get_children()) { + child->~Widget(); + } + + uint deviceCount = 0; + // Adds all valid devices + for (auto pair : devices) { + UpDevice* device = pair.second; + std::string objectPath = pair.first; + + if (!G_IS_OBJECT(device)) continue; + + Gtk::Box* box = new Gtk::Box(Gtk::ORIENTATION_HORIZONTAL, tooltipSpacing); + + UpDeviceKind kind; + double percentage; + gchar* native_path; + gchar* model; + gchar* icon_name; + + g_object_get(device, + "kind", + &kind, + "percentage", + &percentage, + "native-path", + &native_path, + "model", + &model, + "icon-name", + &icon_name, + NULL); + + // Skip Line_Power and BAT0 devices + if (kind == UP_DEVICE_KIND_LINE_POWER || strcmp(native_path, "BAT0") == 0) continue; + + Gtk::Box* modelBox = new Gtk::Box(Gtk::ORIENTATION_HORIZONTAL); + box->add(*modelBox); + // Set device icon + std::string deviceIconName = getDeviceIcon(kind); + Gtk::Image* deviceIcon = new Gtk::Image(); + deviceIcon->set_pixel_size(iconSize); + if (!Gtk::IconTheme::get_default()->has_icon(deviceIconName)) { + deviceIconName = "battery-missing-symbolic"; + } + deviceIcon->set_from_icon_name(deviceIconName, Gtk::ICON_SIZE_INVALID); + modelBox->add(*deviceIcon); + + // Set model + Gtk::Label* modelLabel = new Gtk::Label(model); + modelBox->add(*modelLabel); + + Gtk::Box* chargeBox = new Gtk::Box(Gtk::ORIENTATION_HORIZONTAL); + box->add(*chargeBox); + + // Set icon + Gtk::Image* icon = new Gtk::Image(); + icon->set_pixel_size(iconSize); + if (!Gtk::IconTheme::get_default()->has_icon(icon_name)) { + icon_name = (char*)"battery-missing-symbolic"; + } + icon->set_from_icon_name(icon_name, Gtk::ICON_SIZE_INVALID); + chargeBox->add(*icon); + + // Set percentage + std::string percentString = std::to_string(int(percentage + 0.5)) + "%"; + Gtk::Label* percentLabel = new Gtk::Label(percentString); + chargeBox->add(*percentLabel); + + contentBox->add(*box); + + deviceCount++; + } + + contentBox->show_all(); + return deviceCount; +} + +std::string UPowerTooltip::getDeviceIcon(UpDeviceKind& kind) { + switch (kind) { + case UP_DEVICE_KIND_LINE_POWER: + return "ac-adapter-symbolic"; + case UP_DEVICE_KIND_BATTERY: + return "battery"; + case UP_DEVICE_KIND_UPS: + return "uninterruptible-power-supply-symbolic"; + case UP_DEVICE_KIND_MONITOR: + return "video-display-symbolic"; + case UP_DEVICE_KIND_MOUSE: + return "input-mouse-symbolic"; + case UP_DEVICE_KIND_KEYBOARD: + return "input-keyboard-symbolic"; + case UP_DEVICE_KIND_PDA: + return "pda-symbolic"; + case UP_DEVICE_KIND_PHONE: + return "phone-symbolic"; + case UP_DEVICE_KIND_MEDIA_PLAYER: + return "multimedia-player-symbolic"; + case UP_DEVICE_KIND_TABLET: + return "computer-apple-ipad-symbolic"; + case UP_DEVICE_KIND_COMPUTER: + return "computer-symbolic"; + case UP_DEVICE_KIND_GAMING_INPUT: + return "input-gaming-symbolic"; + case UP_DEVICE_KIND_PEN: + return "input-tablet-symbolic"; + case UP_DEVICE_KIND_TOUCHPAD: + return "input-touchpad-symbolic"; + case UP_DEVICE_KIND_MODEM: + return "modem-symbolic"; + case UP_DEVICE_KIND_NETWORK: + return "network-wired-symbolic"; + case UP_DEVICE_KIND_HEADSET: + return "audio-headset-symbolic"; + case UP_DEVICE_KIND_HEADPHONES: + return "audio-headphones-symbolic"; + case UP_DEVICE_KIND_OTHER_AUDIO: + case UP_DEVICE_KIND_SPEAKERS: + return "audio-speakers-symbolic"; + case UP_DEVICE_KIND_VIDEO: + return "camera-web-symbolic"; + case UP_DEVICE_KIND_PRINTER: + return "printer-symbolic"; + case UP_DEVICE_KIND_SCANNER: + return "scanner-symbolic"; + case UP_DEVICE_KIND_CAMERA: + return "camera-photo-symbolic"; + case UP_DEVICE_KIND_BLUETOOTH_GENERIC: + return "bluetooth-active-symbolic"; + case UP_DEVICE_KIND_TOY: + case UP_DEVICE_KIND_REMOTE_CONTROL: + case UP_DEVICE_KIND_WEARABLE: + case UP_DEVICE_KIND_LAST: + default: + return "battery-symbolic"; + } +} +} // namespace waybar::modules::upower From 5f19a54debca482793ec121b19299e1a451b0b0f Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Sat, 19 Mar 2022 17:25:43 +0100 Subject: [PATCH 16/23] Added man page --- man/waybar-upower.5.scd | 45 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 man/waybar-upower.5.scd diff --git a/man/waybar-upower.5.scd b/man/waybar-upower.5.scd new file mode 100644 index 0000000..b16bca1 --- /dev/null +++ b/man/waybar-upower.5.scd @@ -0,0 +1,45 @@ +waybar-upower(5) + +# NAME + +waybar - upower module + +# DESCRIPTION + +The *upower* module displays the main battery capacity with all other upower +compatible devices in the tooltip. + +# CONFIGURATION + +*icon-size*: ++ + typeof: integer ++ + default: 20 ++ + Defines the size of the icons. + +*hide-if-empty*: ++ + typeof: bool ++ + default: true ++ + Defines visibility of the module if no devices can be found. + +*tooltip*: ++ + typeof: bool ++ + defualt: true ++ + Option to disable tooltip on hover. + +*tooltip-spacing*: ++ + typeof: integer ++ + default: 4 ++ + Defines the spacing between the tooltip device name and device battery ++ + status. + +# EXAMPLES + +``` +"upower": { + "icon-size": 20, + "hide-if-empty": true, + "tooltip": true, + "tooltip-spacing": 20 +} + +``` From 05effad18bf12fb0de92369003703a263872b39e Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Sat, 19 Mar 2022 19:22:00 +0100 Subject: [PATCH 17/23] Added CSS status classes --- include/modules/upower/upower.hpp | 3 +++ man/waybar-upower.5.scd | 7 +++++++ src/modules/upower/upower.cpp | 27 +++++++++++++++++++++++++++ 3 files changed, 37 insertions(+) diff --git a/include/modules/upower/upower.hpp b/include/modules/upower/upower.hpp index c73a072..7907027 100644 --- a/include/modules/upower/upower.hpp +++ b/include/modules/upower/upower.hpp @@ -37,6 +37,8 @@ class UPower : public AModule { void removeDevices(); bool show_tooltip_callback(int, int, bool, const Glib::RefPtr &tooltip); + const std::string getDeviceStatus(UpDeviceState &state); + Gtk::Box box_; Gtk::Image icon_; Gtk::Label label_; @@ -54,6 +56,7 @@ class UPower : public AModule { guint login1_id; GDBusConnection *login1_connection; UPowerTooltip *upower_tooltip; + std::string lastStatus; }; } // namespace waybar::modules::upower diff --git a/man/waybar-upower.5.scd b/man/waybar-upower.5.scd index b16bca1..94ba866 100644 --- a/man/waybar-upower.5.scd +++ b/man/waybar-upower.5.scd @@ -43,3 +43,10 @@ compatible devices in the tooltip. } ``` + +# STYLE + +- *#upower* +- *#upower.charging* +- *#upower.discharging* +- *#upower.unknown-status* diff --git a/src/modules/upower/upower.cpp b/src/modules/upower/upower.cpp index aef874b..0cbe010 100644 --- a/src/modules/upower/upower.cpp +++ b/src/modules/upower/upower.cpp @@ -198,6 +198,21 @@ bool UPower::show_tooltip_callback(int, int, bool, const Glib::RefPtr void { std::lock_guard guard(m_Mutex); @@ -230,6 +245,18 @@ auto UPower::update() -> void { uint tooltipCount = 0; + // CSS status class + const std::string status = getDeviceStatus(state); + // Remove last status if it exists + if (!lastStatus.empty() && box_.get_style_context()->has_class(lastStatus)) { + box_.get_style_context()->remove_class(lastStatus); + } + // Add the new status class to the Box + if (!box_.get_style_context()->has_class(status)) { + box_.get_style_context()->add_class(status); + } + lastStatus = status; + if (devices.size() == 0 && !displayDeviceValid && hideIfEmpty) { event_box_.set_visible(false); goto update; From c4282cfaccb440b2a2a46c5aa0ae65de9746c85d Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Sat, 19 Mar 2022 19:22:21 +0100 Subject: [PATCH 18/23] Made tooltip getDeviceIcon return const string --- include/modules/upower/upower_tooltip.hpp | 2 +- src/modules/upower/upower_tooltip.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/modules/upower/upower_tooltip.hpp b/include/modules/upower/upower_tooltip.hpp index 09f6e60..9f6f16e 100644 --- a/include/modules/upower/upower_tooltip.hpp +++ b/include/modules/upower/upower_tooltip.hpp @@ -12,7 +12,7 @@ class UPowerTooltip : public Gtk::Window { private: typedef std::unordered_map Devices; - std::string getDeviceIcon(UpDeviceKind& kind); + const std::string getDeviceIcon(UpDeviceKind& kind); Gtk::Box* contentBox; diff --git a/src/modules/upower/upower_tooltip.cpp b/src/modules/upower/upower_tooltip.cpp index 2bff69c..7ae3e89 100644 --- a/src/modules/upower/upower_tooltip.cpp +++ b/src/modules/upower/upower_tooltip.cpp @@ -96,7 +96,7 @@ uint UPowerTooltip::updateTooltip(Devices& devices) { return deviceCount; } -std::string UPowerTooltip::getDeviceIcon(UpDeviceKind& kind) { +const std::string UPowerTooltip::getDeviceIcon(UpDeviceKind& kind) { switch (kind) { case UP_DEVICE_KIND_LINE_POWER: return "ac-adapter-symbolic"; From 0764e9ad6eec8c34b8d9b96ad2bd8463c57f992a Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Sat, 19 Mar 2022 21:15:48 +0100 Subject: [PATCH 19/23] Added format and format-alt config properties --- include/modules/upower/upower.hpp | 17 ++++++-- man/waybar-upower.5.scd | 17 ++++++++ src/modules/upower/upower.cpp | 72 +++++++++++++++++++++++++++---- 3 files changed, 94 insertions(+), 12 deletions(-) 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)) { From 2633ff3fb996ccf471d04a7c2b94ba07bbfed126 Mon Sep 17 00:00:00 2001 From: Erik Reider Date: Sat, 19 Mar 2022 23:00:08 +0100 Subject: [PATCH 20/23] Fixed time_left string not being set properly --- src/modules/upower/upower.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/modules/upower/upower.cpp b/src/modules/upower/upower.cpp index 5f4d00b..9b13c95 100644 --- a/src/modules/upower/upower.cpp +++ b/src/modules/upower/upower.cpp @@ -281,17 +281,15 @@ 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; + time_format = timeToString(time_full); break; case UP_DEVICE_STATE_DISCHARGING: case UP_DEVICE_STATE_PENDING_DISCHARGE: - time_format = time_empty_format; + time_format = timeToString(time_empty); break; default: break; From 7b071567ea00f273271cfa563b29afbc26d1a0c8 Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Sun, 20 Mar 2022 00:36:13 +0100 Subject: [PATCH 21/23] Removed goto in update method --- src/modules/upower/upower.cpp | 26 +++++--------------------- 1 file changed, 5 insertions(+), 21 deletions(-) diff --git a/src/modules/upower/upower.cpp b/src/modules/upower/upower.cpp index 9b13c95..c5c51d9 100644 --- a/src/modules/upower/upower.cpp +++ b/src/modules/upower/upower.cpp @@ -277,24 +277,6 @@ auto UPower::update() -> void { bool displayDeviceValid = kind == UpDeviceKind::UP_DEVICE_KIND_BATTERY || kind == UpDeviceKind::UP_DEVICE_KIND_UPS; - std::string percentString = ""; - - uint tooltipCount = 0; - - std::string time_format = ""; - switch (state) { - case UP_DEVICE_STATE_CHARGING: - case UP_DEVICE_STATE_PENDING_CHARGE: - time_format = timeToString(time_full); - break; - case UP_DEVICE_STATE_DISCHARGING: - case UP_DEVICE_STATE_PENDING_DISCHARGE: - time_format = timeToString(time_empty); - break; - default: - break; - } - // CSS status class const std::string status = getDeviceStatus(state); // Remove last status if it exists @@ -309,19 +291,22 @@ auto UPower::update() -> void { if (devices.size() == 0 && !displayDeviceValid && hideIfEmpty) { event_box_.set_visible(false); - goto update; + // Call parent update + AModule::update(); + return; } event_box_.set_visible(true); // Tooltip if (tooltip_enabled) { - tooltipCount = upower_tooltip->updateTooltip(devices); + uint tooltipCount = upower_tooltip->updateTooltip(devices); // Disable the tooltip if there aren't any devices in the tooltip box_.set_has_tooltip(!devices.empty() && tooltipCount > 0); } // Set percentage + std::string percentString = ""; if (displayDeviceValid) { percentString = std::to_string(int(percentage + 0.5)) + "%"; } @@ -337,7 +322,6 @@ auto UPower::update() -> void { } icon_.set_from_icon_name(icon_name, Gtk::ICON_SIZE_INVALID); -update: // Call parent update AModule::update(); } From e06316c80b04c58638616094f1dda9ad27393914 Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Sun, 20 Mar 2022 00:36:53 +0100 Subject: [PATCH 22/23] Only set label text if string doesn't only contain spaces --- src/modules/upower/upower.cpp | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/modules/upower/upower.cpp b/src/modules/upower/upower.cpp index c5c51d9..9e4b8ee 100644 --- a/src/modules/upower/upower.cpp +++ b/src/modules/upower/upower.cpp @@ -2,6 +2,7 @@ #include +#include #include #include "gtkmm/icontheme.h" @@ -312,9 +313,30 @@ auto UPower::update() -> void { } // Label format - label_.set_markup(fmt::format(showAltText ? format_alt : format, - fmt::arg("percentage", percentString), - fmt::arg("time", time_format))); + std::string time_format = ""; + switch (state) { + case UP_DEVICE_STATE_CHARGING: + case UP_DEVICE_STATE_PENDING_CHARGE: + time_format = timeToString(time_full); + break; + case UP_DEVICE_STATE_DISCHARGING: + case UP_DEVICE_STATE_PENDING_DISCHARGE: + time_format = timeToString(time_empty); + break; + default: + break; + } + std::string label_format = fmt::format(showAltText ? format_alt : format, + fmt::arg("percentage", percentString), + fmt::arg("time", time_format)); + // Only set the label text if it doesn't only contain spaces + bool onlySpaces = true; + for (auto& character : label_format) { + if (character == ' ') continue; + onlySpaces = false; + break; + } + label_.set_markup(onlySpaces ? "" : label_format); // Set icon if (!Gtk::IconTheme::get_default()->has_icon(icon_name)) { From 84dc82e1c189b4671bc400b3e2ff511882f449af Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Mon, 21 Mar 2022 13:50:46 +0100 Subject: [PATCH 23/23] Added tooltip-padding --- include/modules/upower/upower.hpp | 1 + include/modules/upower/upower_tooltip.hpp | 3 ++- man/waybar-upower.5.scd | 5 +++++ src/modules/upower/upower.cpp | 7 ++++++- src/modules/upower/upower_tooltip.cpp | 14 ++++++++++++-- 5 files changed, 26 insertions(+), 4 deletions(-) diff --git a/include/modules/upower/upower.hpp b/include/modules/upower/upower.hpp index 4ee2b1e..5b4d2f5 100644 --- a/include/modules/upower/upower.hpp +++ b/include/modules/upower/upower.hpp @@ -53,6 +53,7 @@ class UPower : public AModule { bool hideIfEmpty = true; bool tooltip_enabled = true; uint tooltip_spacing = 4; + uint tooltip_padding = 4; uint iconSize = 20; std::string format = DEFAULT_FORMAT; std::string format_alt = DEFAULT_FORMAT_ALT; diff --git a/include/modules/upower/upower_tooltip.hpp b/include/modules/upower/upower_tooltip.hpp index 9f6f16e..9d36a70 100644 --- a/include/modules/upower/upower_tooltip.hpp +++ b/include/modules/upower/upower_tooltip.hpp @@ -18,9 +18,10 @@ class UPowerTooltip : public Gtk::Window { uint iconSize; uint tooltipSpacing; + uint tooltipPadding; public: - UPowerTooltip(uint iconSize, uint tooltipSpacing); + UPowerTooltip(uint iconSize, uint tooltipSpacing, uint tooltipPadding); ~UPowerTooltip(); uint updateTooltip(Devices& devices); diff --git a/man/waybar-upower.5.scd b/man/waybar-upower.5.scd index 76af849..e6f6307 100644 --- a/man/waybar-upower.5.scd +++ b/man/waybar-upower.5.scd @@ -42,6 +42,11 @@ compatible devices in the tooltip. Defines the spacing between the tooltip device name and device battery ++ status. +*tooltip-padding*: ++ + typeof: integer ++ + default: 4 ++ + Defines the spacing between the tooltip window edge and the tooltip content. + # FORMAT REPLACEMENTS *{percentage}*: The battery capacity in percentage diff --git a/src/modules/upower/upower.cpp b/src/modules/upower/upower.cpp index 9e4b8ee..f628514 100644 --- a/src/modules/upower/upower.cpp +++ b/src/modules/upower/upower.cpp @@ -50,6 +50,11 @@ UPower::UPower(const std::string& id, const Json::Value& config) tooltip_spacing = config_["tooltip-spacing"].asUInt(); } + // Tooltip Padding + if (config_["tooltip-padding"].isUInt()) { + tooltip_padding = config_["tooltip-padding"].asUInt(); + } + // Tooltip if (config_["tooltip"].isBool()) { tooltip_enabled = config_["tooltip"].asBool(); @@ -57,7 +62,7 @@ UPower::UPower(const std::string& id, const Json::Value& config) box_.set_has_tooltip(tooltip_enabled); if (tooltip_enabled) { // Sets the window to use when showing the tooltip - upower_tooltip = new UPowerTooltip(iconSize, tooltip_spacing); + upower_tooltip = new UPowerTooltip(iconSize, tooltip_spacing, tooltip_padding); box_.set_tooltip_window(*upower_tooltip); box_.signal_query_tooltip().connect(sigc::mem_fun(*this, &UPower::show_tooltip_callback)); } diff --git a/src/modules/upower/upower_tooltip.cpp b/src/modules/upower/upower_tooltip.cpp index 7ae3e89..644b8e0 100644 --- a/src/modules/upower/upower_tooltip.cpp +++ b/src/modules/upower/upower_tooltip.cpp @@ -7,9 +7,19 @@ #include "gtkmm/label.h" namespace waybar::modules::upower { -UPowerTooltip::UPowerTooltip(uint iconSize_, uint tooltipSpacing_) - : Gtk::Window(), iconSize(iconSize_), tooltipSpacing(tooltipSpacing_) { +UPowerTooltip::UPowerTooltip(uint iconSize_, uint tooltipSpacing_, uint tooltipPadding_) + : Gtk::Window(), + iconSize(iconSize_), + tooltipSpacing(tooltipSpacing_), + tooltipPadding(tooltipPadding_) { contentBox = new Gtk::Box(Gtk::ORIENTATION_VERTICAL); + + // Sets the Tooltip Padding + contentBox->set_margin_top(tooltipPadding); + contentBox->set_margin_bottom(tooltipPadding); + contentBox->set_margin_left(tooltipPadding); + contentBox->set_margin_right(tooltipPadding); + add(*contentBox); contentBox->show(); }