diff --git a/include/AModule.hpp b/include/AModule.hpp index c9f1ae2..91606f5 100644 --- a/include/AModule.hpp +++ b/include/AModule.hpp @@ -36,6 +36,23 @@ class AModule : public IModule { std::vector pid_; gdouble distance_scrolled_y_; gdouble distance_scrolled_x_; + static const inline std::map, std::string> eventMap_{ + {std::make_pair(1, GdkEventType::GDK_BUTTON_PRESS), "on-click"}, + {std::make_pair(1, GdkEventType::GDK_2BUTTON_PRESS), "on-double-click"}, + {std::make_pair(1, GdkEventType::GDK_3BUTTON_PRESS), "on-triple-click"}, + {std::make_pair(2, GdkEventType::GDK_BUTTON_PRESS), "on-click-middle"}, + {std::make_pair(2, GdkEventType::GDK_2BUTTON_PRESS), "on-double-click-middle"}, + {std::make_pair(2, GdkEventType::GDK_3BUTTON_PRESS), "on-triple-click-middle"}, + {std::make_pair(3, GdkEventType::GDK_BUTTON_PRESS), "on-click-right"}, + {std::make_pair(3, GdkEventType::GDK_2BUTTON_PRESS), "on-double-click-right"}, + {std::make_pair(3, GdkEventType::GDK_3BUTTON_PRESS), "on-triple-click-right"}, + {std::make_pair(8, GdkEventType::GDK_BUTTON_PRESS), "on-click-backward"}, + {std::make_pair(8, GdkEventType::GDK_2BUTTON_PRESS), "on-double-click-backward"}, + {std::make_pair(8, GdkEventType::GDK_2BUTTON_PRESS), "on-triple-click-backward"}, + {std::make_pair(9, GdkEventType::GDK_BUTTON_PRESS), "on-click-forward"}, + {std::make_pair(9, GdkEventType::GDK_2BUTTON_PRESS), "on-double-click-forward"}, + {std::make_pair(9, GdkEventType::GDK_2BUTTON_PRESS), "on-triple-click-forward"} + }; }; } // namespace waybar diff --git a/include/modules/upower/upower.hpp b/include/modules/upower/upower.hpp index 5b4d2f5..ee70fbe 100644 --- a/include/modules/upower/upower.hpp +++ b/include/modules/upower/upower.hpp @@ -34,6 +34,10 @@ class UPower : public AModule { const gchar *object_path, const gchar *interface_name, const gchar *signal_name, GVariant *parameters, gpointer user_data); + static void upowerAppear(GDBusConnection *conn, const gchar *name, const gchar *name_owner, + gpointer data); + static void upowerDisappear(GDBusConnection *connection, const gchar *name, gpointer user_data); + void removeDevice(const gchar *objectPath); void addDevice(UpDevice *device); void setDisplayDevice(); @@ -67,6 +71,8 @@ class UPower : public AModule { UPowerTooltip *upower_tooltip; std::string lastStatus; bool showAltText; + bool upowerRunning; + guint upowerWatcher_id; }; } // namespace waybar::modules::upower diff --git a/man/waybar-upower.5.scd b/man/waybar-upower.5.scd index e6f6307..99c015a 100644 --- a/man/waybar-upower.5.scd +++ b/man/waybar-upower.5.scd @@ -71,4 +71,6 @@ depending on the charging state. - *#upower* - *#upower.charging* - *#upower.discharging* +- *#upower.full* +- *#upower.empty* - *#upower.unknown-status* diff --git a/meson.build b/meson.build index e9daeca..73e74a5 100644 --- a/meson.build +++ b/meson.build @@ -359,6 +359,7 @@ if scdoc.found() 'waybar-wlr-workspaces.5.scd', 'waybar-bluetooth.5.scd', 'waybar-sndio.5.scd', + 'waybar-upower.5.scd', ] if (giounix.found() and not get_option('logind').disabled()) diff --git a/src/AModule.cpp b/src/AModule.cpp index 0e0f00e..e65067e 100644 --- a/src/AModule.cpp +++ b/src/AModule.cpp @@ -10,16 +10,24 @@ AModule::AModule(const Json::Value& config, const std::string& name, const std:: , distance_scrolled_y_(0.0) , distance_scrolled_x_(0.0) { // configure events' user commands - if (config_["on-click"].isString() || config_["on-click-middle"].isString() || - config_["on-click-backward"].isString() || config_["on-click-forward"].isString() || - config_["on-click-right"].isString() || enable_click) { + if (enable_click) { event_box_.add_events(Gdk::BUTTON_PRESS_MASK); event_box_.signal_button_press_event().connect(sigc::mem_fun(*this, &AModule::handleToggle)); + } else { + std::map, std::string>::const_iterator it{eventMap_.cbegin()}; + while(it != eventMap_.cend()) { + if (config_[it->second].isString()) { + event_box_.add_events(Gdk::BUTTON_PRESS_MASK); + event_box_.signal_button_press_event().connect(sigc::mem_fun(*this, &AModule::handleToggle)); + break; + } + ++it; + } } if (config_["on-scroll-up"].isString() || config_["on-scroll-down"].isString() || enable_scroll) { event_box_.add_events(Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK); event_box_.signal_scroll_event().connect(sigc::mem_fun(*this, &AModule::handleScroll)); - } + } } AModule::~AModule() { @@ -30,7 +38,6 @@ AModule::~AModule() { } } - auto AModule::update() -> void { // Run user-provided update handler if configured if (config_["on-update"].isString()) { @@ -39,18 +46,14 @@ auto AModule::update() -> void { } bool AModule::handleToggle(GdkEventButton* const& e) { - std::string format; - if (config_["on-click"].isString() && e->button == 1) { - format = config_["on-click"].asString(); - } else if (config_["on-click-middle"].isString() && e->button == 2) { - format = config_["on-click-middle"].asString(); - } else if (config_["on-click-right"].isString() && e->button == 3) { - format = config_["on-click-right"].asString(); - } else if (config_["on-click-backward"].isString() && e->button == 8) { - format = config_["on-click-backward"].asString(); - } else if (config_["on-click-forward"].isString() && e->button == 9) { - format = config_["on-click-forward"].asString(); + const std::map, std::string>::const_iterator& rec{eventMap_.find(std::pair(e->button, e->type))}; + std::string format{ (rec != eventMap_.cend()) ? rec->second : std::string{""}}; + + if (!format.empty()) { + if (config_[format].isString()) format = config_[format].asString(); + else format.clear(); } + if (!format.empty()) { pid_.push_back(util::command::forkExec(format)); } diff --git a/src/modules/battery.cpp b/src/modules/battery.cpp index c2dc389..59874f7 100644 --- a/src/modules/battery.cpp +++ b/src/modules/battery.cpp @@ -88,8 +88,9 @@ void waybar::modules::Battery::refreshBatteries() { auto dir_name = node.path().filename(); auto bat_defined = config_["bat"].isString(); if (((bat_defined && dir_name == config_["bat"].asString()) || !bat_defined) && - fs::exists(node.path() / "capacity") && fs::exists(node.path() / "uevent") && - fs::exists(node.path() / "status") && fs::exists(node.path() / "type")) { + (fs::exists(node.path() / "capacity") || fs::exists(node.path() / "charge_now")) && + fs::exists(node.path() / "uevent") && fs::exists(node.path() / "status") && + fs::exists(node.path() / "type")) { std::string type; std::ifstream(node.path() / "type") >> type; @@ -168,14 +169,21 @@ const std::tuple waybar::modules::Battery::g // Some battery will report current and charge in μA/μAh. // Scale these by the voltage to get μW/μWh. - if (fs::exists(bat / "current_now")) { + if (fs::exists(bat / "current_now") || fs::exists(bat / "current_avg")) { uint32_t voltage_now; uint32_t current_now; uint32_t charge_now; uint32_t charge_full; uint32_t charge_full_design; - std::ifstream(bat / "voltage_now") >> voltage_now; - std::ifstream(bat / "current_now") >> current_now; + // Some batteries have only *_avg, not *_now + if (fs::exists(bat / "voltage_now")) + std::ifstream(bat / "voltage_now") >> voltage_now; + else + std::ifstream(bat / "voltage_avg") >> voltage_now; + if (fs::exists(bat / "current_now")) + std::ifstream(bat / "current_now") >> current_now; + else + std::ifstream(bat / "current_avg") >> current_now; std::ifstream(bat / "charge_full") >> charge_full; std::ifstream(bat / "charge_full_design") >> charge_full_design; if (fs::exists(bat / "charge_now")) diff --git a/src/modules/upower/upower.cpp b/src/modules/upower/upower.cpp index f628514..83d3df2 100644 --- a/src/modules/upower/upower.cpp +++ b/src/modules/upower/upower.cpp @@ -22,6 +22,7 @@ UPower::UPower(const std::string& id, const Json::Value& config) showAltText(false) { box_.pack_start(icon_); box_.pack_start(label_); + box_.set_name(name_); event_box_.add(box_); // Icon Size @@ -67,6 +68,14 @@ UPower::UPower(const std::string& id, const Json::Value& config) box_.signal_query_tooltip().connect(sigc::mem_fun(*this, &UPower::show_tooltip_callback)); } + upowerWatcher_id = g_bus_watch_name(G_BUS_TYPE_SYSTEM, + "org.freedesktop.UPower", + G_BUS_NAME_WATCHER_FLAGS_AUTO_START, + upowerAppear, + upowerDisappear, + this, + NULL); + GError* error = NULL; client = up_client_new_full(NULL, &error); if (client == NULL) { @@ -105,6 +114,7 @@ UPower::~UPower() { g_dbus_connection_signal_unsubscribe(login1_connection, login1_id); login1_id = 0; } + g_bus_unwatch_name(upowerWatcher_id); removeDevices(); } @@ -141,6 +151,17 @@ void UPower::prepareForSleep_cb(GDBusConnection* system_bus, const gchar* sender } } } +void UPower::upowerAppear(GDBusConnection* conn, const gchar* name, const gchar* name_owner, + gpointer data) { + UPower* up = static_cast(data); + up->upowerRunning = true; + up->event_box_.set_visible(true); +} +void UPower::upowerDisappear(GDBusConnection* conn, const gchar* name, gpointer data) { + UPower* up = static_cast(data); + up->upowerRunning = false; + up->event_box_.set_visible(false); +} void UPower::removeDevice(const gchar* objectPath) { std::lock_guard guard(m_Mutex); @@ -226,11 +247,13 @@ const std::string UPower::getDeviceStatus(UpDeviceState& state) { case UP_DEVICE_STATE_CHARGING: case UP_DEVICE_STATE_PENDING_CHARGE: return "charging"; - case UP_DEVICE_STATE_EMPTY: - case UP_DEVICE_STATE_FULLY_CHARGED: case UP_DEVICE_STATE_DISCHARGING: case UP_DEVICE_STATE_PENDING_DISCHARGE: return "discharging"; + case UP_DEVICE_STATE_FULLY_CHARGED: + return "full"; + case UP_DEVICE_STATE_EMPTY: + return "empty"; default: return "unknown-status"; } @@ -258,6 +281,9 @@ std::string UPower::timeToString(gint64 time) { auto UPower::update() -> void { std::lock_guard guard(m_Mutex); + // Don't update widget if the UPower service isn't running + if (!upowerRunning) return; + UpDeviceKind kind; UpDeviceState state; double percentage; @@ -344,7 +370,7 @@ auto UPower::update() -> void { label_.set_markup(onlySpaces ? "" : label_format); // Set icon - if (!Gtk::IconTheme::get_default()->has_icon(icon_name)) { + if (icon_name == NULL || !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); diff --git a/src/modules/upower/upower_tooltip.cpp b/src/modules/upower/upower_tooltip.cpp index 644b8e0..8aaba92 100644 --- a/src/modules/upower/upower_tooltip.cpp +++ b/src/modules/upower/upower_tooltip.cpp @@ -62,7 +62,9 @@ uint UPowerTooltip::updateTooltip(Devices& devices) { NULL); // Skip Line_Power and BAT0 devices - if (kind == UP_DEVICE_KIND_LINE_POWER || strcmp(native_path, "BAT0") == 0) continue; + if (kind == UP_DEVICE_KIND_LINE_POWER || native_path == NULL || strlen(native_path) == 0 || + strcmp(native_path, "BAT0") == 0) + continue; Gtk::Box* modelBox = new Gtk::Box(Gtk::ORIENTATION_HORIZONTAL); box->add(*modelBox); @@ -77,6 +79,7 @@ uint UPowerTooltip::updateTooltip(Devices& devices) { modelBox->add(*deviceIcon); // Set model + if (model == NULL) model = (gchar*)""; Gtk::Label* modelLabel = new Gtk::Label(model); modelBox->add(*modelLabel); @@ -86,7 +89,7 @@ uint UPowerTooltip::updateTooltip(Devices& devices) { // Set icon Gtk::Image* icon = new Gtk::Image(); icon->set_pixel_size(iconSize); - if (!Gtk::IconTheme::get_default()->has_icon(icon_name)) { + if (icon_name == NULL || !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);