diff --git a/include/ALabel.hpp b/include/ALabel.hpp index 00daf3c..6befe03 100644 --- a/include/ALabel.hpp +++ b/include/ALabel.hpp @@ -7,7 +7,7 @@ namespace waybar { class ALabel : public IModule { public: - ALabel(const Json::Value&, const std::string format); + ALabel(const Json::Value&, const std::string format, uint16_t interval = 0); virtual ~ALabel() = default; virtual auto update() -> void; virtual std::string getIcon(uint16_t, const std::string& alt = ""); @@ -19,6 +19,7 @@ class ALabel : public IModule { const Json::Value& config_; std::string format_; std::mutex mutex_; + const std::chrono::seconds interval_; private: bool handleToggle(GdkEventButton* const& ev); diff --git a/include/client.hpp b/include/client.hpp index 0155105..f3ef135 100644 --- a/include/client.hpp +++ b/include/client.hpp @@ -29,6 +29,7 @@ class Client { private: void bindInterfaces(); auto setupCss(); + const std::string getValidPath(std::vector paths); static void handleGlobal(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version); diff --git a/include/modules/battery.hpp b/include/modules/battery.hpp index f4fec2e..c3eadba 100644 --- a/include/modules/battery.hpp +++ b/include/modules/battery.hpp @@ -30,8 +30,8 @@ class Battery : public ALabel { static inline const fs::path data_dir_ = "/sys/class/power_supply/"; void worker(); - std::tuple getInfos(); - std::string getState(uint16_t); + const std::tuple getInfos() const; + const std::string getState(uint8_t) const; util::SleeperThread thread_; util::SleeperThread thread_timer_; diff --git a/include/modules/sni/host.hpp b/include/modules/sni/host.hpp index 5f952fd..6c6618e 100644 --- a/include/modules/sni/host.hpp +++ b/include/modules/sni/host.hpp @@ -34,8 +34,8 @@ class Host { GCancellable* cancellable_ = nullptr; SnWatcher* watcher_ = nullptr; const Json::Value &config_; - std::function&)> on_add_; - std::function&)> on_remove_; + const std::function&)> on_add_; + const std::function&)> on_remove_; }; } diff --git a/include/modules/sni/watcher.hpp b/include/modules/sni/watcher.hpp index 6e925fb..79f5cbf 100644 --- a/include/modules/sni/watcher.hpp +++ b/include/modules/sni/watcher.hpp @@ -8,7 +8,7 @@ namespace waybar::modules::SNI { class Watcher { public: Watcher(); - ~Watcher(); + ~Watcher() = default; private: typedef enum { GF_WATCH_TYPE_HOST, GF_WATCH_TYPE_ITEM } GfWatchType; @@ -22,7 +22,7 @@ private: guint watch_id; } GfWatch; - static void busAcquired(GDBusConnection *, const gchar *, gpointer); + void busAcquired(const Glib::RefPtr&, Glib::ustring); static gboolean handleRegisterHost(Watcher *, GDBusMethodInvocation *, const gchar *); static gboolean handleRegisterItem(Watcher *, GDBusMethodInvocation *, diff --git a/meson.build b/meson.build index 844cda7..4dc9db6 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project( 'waybar', 'cpp', 'c', - version: '0.2.1', + version: '0.2.2', license: 'MIT', default_options : [ 'cpp_std=c++17', diff --git a/src/ALabel.cpp b/src/ALabel.cpp index 9dd590e..0a1c2b5 100644 --- a/src/ALabel.cpp +++ b/src/ALabel.cpp @@ -3,10 +3,11 @@ #include -waybar::ALabel::ALabel(const Json::Value& config, const std::string format) +waybar::ALabel::ALabel(const Json::Value& config, const std::string format, uint16_t interval) : config_(config), format_(config_["format"].isString() ? config_["format"].asString() : format), - default_format_(format_) + interval_(std::chrono::seconds(config_["interval"].isUInt() + ? config_["interval"].asUInt() : interval)), default_format_(format_) { event_box_.add(label_); if (config_["max-length"].isUInt()) { @@ -20,17 +21,12 @@ waybar::ALabel::ALabel(const Json::Value& config, const std::string format) } // configure events' user commands - if (config_["on-click"].isString()) { + if (config_["on-click"].isString() || config_["on-click-right"].isString()) { event_box_.add_events(Gdk::BUTTON_PRESS_MASK); event_box_.signal_button_press_event().connect( sigc::mem_fun(*this, &ALabel::handleToggle)); } - if (config_["on-scroll-up"].isString()) { - event_box_.add_events(Gdk::SCROLL_MASK); - event_box_.signal_scroll_event().connect( - sigc::mem_fun(*this, &ALabel::handleScroll)); - } - if (config_["on-scroll-down"].isString()) { + if (config_["on-scroll-up"].isString() || config_["on-scroll-down"].isString()) { event_box_.add_events(Gdk::SCROLL_MASK); event_box_.signal_scroll_event().connect( sigc::mem_fun(*this, &ALabel::handleScroll)); @@ -44,6 +40,8 @@ auto waybar::ALabel::update() -> void { bool waybar::ALabel::handleToggle(GdkEventButton* const& e) { if (config_["on-click"].isString() && e->button == 1) { waybar::util::command::forkExec(config_["on-click"].asString()); + } else if (config_["on-click-right"].isString() && e->button == 3) { + waybar::util::command::forkExec(config_["on-click-right"].asString()); } else { alt = !alt; if (alt) { diff --git a/src/bar.cpp b/src/bar.cpp index 961a321..b28e920 100644 --- a/src/bar.cpp +++ b/src/bar.cpp @@ -184,7 +184,13 @@ void waybar::Bar::getModules(const Factory& factory, const std::string& pos) if (pos == "modules-right") { modules_right_.emplace_back(module); } - module->dp.connect([module] { module->update(); }); + module->dp.connect([module, &name] { + try { + module->update(); + } catch (const std::exception& e) { + std::cerr << name.asString() + ": " + e.what() << std::endl; + } + }); } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } diff --git a/src/client.cpp b/src/client.cpp index 945e38a..daa52cf 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -12,38 +12,43 @@ waybar::Client::Client(int argc, char* argv[]) throw std::runtime_error("Bar need to run under Wayland"); } wl_display = gdk_wayland_display_get_wl_display(gdk_display->gobj()); - auto getFirstValidPath = [] (std::vector possiblePaths) { - wordexp_t p; - for (const std::string &path: possiblePaths) { - if (wordexp(path.c_str(), &p, 0) == 0) { - if (access(*p.we_wordv, F_OK) == 0) { - std::string result = *p.we_wordv; - wordfree(&p); - return result; - } - wordfree(&p); - } - } - - return std::string(); - }; - - config_file = getFirstValidPath({ + config_file = getValidPath({ "$XDG_CONFIG_HOME/waybar/config", "$HOME/waybar/config", "/etc/xdg/waybar/config", "./resources/config", }); - css_file = getFirstValidPath({ + css_file = getValidPath({ "$XDG_CONFIG_HOME/waybar/style.css", "$HOME/waybar/style.css", "/etc/xdg/waybar/style.css", "./resources/style.css", }); + if (css_file.empty() || config_file.empty()) { + throw std::runtime_error("Missing required resources files"); + } std::cout << "Resources files: " + config_file + ", " + css_file << std::endl; } +const std::string waybar::Client::getValidPath(std::vector paths) +{ + wordexp_t p; + + for (const std::string &path: paths) { + if (wordexp(path.c_str(), &p, 0) == 0) { + if (access(*p.we_wordv, F_OK) == 0) { + std::string result = *p.we_wordv; + wordfree(&p); + return result; + } + wordfree(&p); + } + } + + return std::string(); +} + void waybar::Client::handleGlobal(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version) { diff --git a/src/main.cpp b/src/main.cpp index 85e120e..54cc9a0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -15,7 +15,7 @@ int main(int argc, char* argv[]) waybar::client = &c; std::signal(SIGUSR1, [] (int /*signal*/) { for (auto& bar : waybar::client->bars) { - (*bar).toggle(); + bar->toggle(); } }); diff --git a/src/modules/battery.cpp b/src/modules/battery.cpp index a9b98b5..9fae5ed 100644 --- a/src/modules/battery.cpp +++ b/src/modules/battery.cpp @@ -1,7 +1,7 @@ #include "modules/battery.hpp" waybar::modules::Battery::Battery(const Json::Value& config) - : ALabel(config, "{capacity}%") + : ALabel(config, "{capacity}%", 60) { try { if (config_["bat"].isString()) { @@ -46,9 +46,8 @@ void waybar::modules::Battery::worker() { // Trigger first values update(); - uint32_t interval = config_["interval"].isUInt() ? config_["interval"].asUInt() : 60; - thread_timer_ = [this, interval] { - thread_.sleep_for(chrono::seconds(interval)); + thread_timer_ = [this] { + thread_.sleep_for(interval_); dp.emit(); }; thread_ = [this] { @@ -63,7 +62,7 @@ void waybar::modules::Battery::worker() }; } -std::tuple waybar::modules::Battery::getInfos() +const std::tuple waybar::modules::Battery::getInfos() const { try { uint16_t total = 0; @@ -86,10 +85,10 @@ std::tuple waybar::modules::Battery::getInfos() } } -std::string waybar::modules::Battery::getState(uint16_t capacity) +const std::string waybar::modules::Battery::getState(uint8_t capacity) const { // Get current state - std::vector> states; + std::vector> states; if (config_["states"].isObject()) { for (auto it = config_["states"].begin(); it != config_["states"].end(); ++it) { if (it->isUInt() && it.key().isString()) { @@ -101,16 +100,16 @@ std::string waybar::modules::Battery::getState(uint16_t capacity) std::sort(states.begin(), states.end(), [](auto &a, auto &b) { return a.second < b.second; }); - std::string validState = ""; - for (auto state : states) { - if (capacity <= state.second && validState.empty()) { + std::string valid_state; + for (auto const& state : states) { + if (capacity <= state.second && valid_state.empty()) { label_.get_style_context()->add_class(state.first); - validState = state.first; + valid_state = state.first; } else { label_.get_style_context()->remove_class(state.first); } } - return validState; + return valid_state; } auto waybar::modules::Battery::update() -> void diff --git a/src/modules/clock.cpp b/src/modules/clock.cpp index 5cc7459..c4462ed 100644 --- a/src/modules/clock.cpp +++ b/src/modules/clock.cpp @@ -1,16 +1,17 @@ #include "modules/clock.hpp" waybar::modules::Clock::Clock(const Json::Value& config) - : ALabel(config, "{:%H:%M}") + : ALabel(config, "{:%H:%M}", 60) { label_.set_name("clock"); - uint32_t interval = config_["interval"].isUInt() ? config_["interval"].asUInt() : 60; - thread_ = [this, interval] { + thread_ = [this] { auto now = waybar::chrono::clock::now(); dp.emit(); - auto timeout = std::chrono::floor(now - + std::chrono::seconds(interval)); - thread_.sleep_until(timeout); + auto timeout = std::chrono::floor(now + interval_); + auto time_s = std::chrono::time_point_cast(timeout); + auto sub_m = + std::chrono::duration_cast(time_s.time_since_epoch()).count() % 60; + thread_.sleep_until(timeout - std::chrono::seconds(sub_m - 1)); }; } diff --git a/src/modules/cpu.cpp b/src/modules/cpu.cpp index 586bece..91e177d 100644 --- a/src/modules/cpu.cpp +++ b/src/modules/cpu.cpp @@ -1,28 +1,23 @@ #include "modules/cpu.hpp" waybar::modules::Cpu::Cpu(const Json::Value& config) - : ALabel(config, "{usage}%") + : ALabel(config, "{usage}%", 10) { label_.set_name("cpu"); - uint32_t interval = config_["interval"].isUInt() ? config_["interval"].asUInt() : 10; - thread_ = [this, interval] { + thread_ = [this] { dp.emit(); - thread_.sleep_for(chrono::seconds(interval)); + thread_.sleep_for(interval_); }; } auto waybar::modules::Cpu::update() -> void { - try { - // TODO: as creating dynamic fmt::arg arrays is buggy we have to calc both - auto cpu_load = getCpuLoad(); - auto [cpu_usage, tooltip] = getCpuUsage(); - label_.set_tooltip_text(tooltip); - label_.set_markup(fmt::format(format_, - fmt::arg("load", cpu_load), fmt::arg("usage", cpu_usage))); - } catch (const std::exception& e) { - std::cerr << e.what() << std::endl; - } + // TODO: as creating dynamic fmt::arg arrays is buggy we have to calc both + auto cpu_load = getCpuLoad(); + auto [cpu_usage, tooltip] = getCpuUsage(); + label_.set_tooltip_text(tooltip); + label_.set_markup(fmt::format(format_, + fmt::arg("load", cpu_load), fmt::arg("usage", cpu_usage))); } uint16_t waybar::modules::Cpu::getCpuLoad() diff --git a/src/modules/custom.cpp b/src/modules/custom.cpp index a00459b..74ae0f2 100644 --- a/src/modules/custom.cpp +++ b/src/modules/custom.cpp @@ -4,20 +4,20 @@ waybar::modules::Custom::Custom(const std::string name, const Json::Value& config) : ALabel(config, "{}"), name_(name) { - if (!config_["exec"].isString()) { - throw std::runtime_error(name_ + " has no exec path."); - } - if (config_["interval"].isUInt()) { - delayWorker(); + if (config_["exec"].isString()) { + if (interval_.count() > 0) { + delayWorker(); + } else { + continuousWorker(); + } } else { - continuousWorker(); + update(); } } void waybar::modules::Custom::delayWorker() { - auto interval = config_["interval"].asUInt(); - thread_ = [this, interval] { + thread_ = [this] { bool can_update = true; if (config_["exec-if"].isString()) { auto res = waybar::util::command::exec(config_["exec-if"].asString()); @@ -31,7 +31,7 @@ void waybar::modules::Custom::delayWorker() output_ = waybar::util::command::exec(config_["exec"].asString()); dp.emit(); } - thread_.sleep_for(chrono::seconds(interval)); + thread_.sleep_for(interval_); }; } @@ -67,7 +67,7 @@ void waybar::modules::Custom::continuousWorker() auto waybar::modules::Custom::update() -> void { // Hide label if output is empty - if (output_.out.empty() || output_.exit_code != 0) { + if (config_["exec"].isString() && (output_.out.empty() || output_.exit_code != 0)) { label_.hide(); label_.set_name(""); } else { @@ -133,4 +133,4 @@ void waybar::modules::Custom::parseOutputJson() class_ = parsed["class"].asString(); break; } -} \ No newline at end of file +} diff --git a/src/modules/memory.cpp b/src/modules/memory.cpp index 3464cd7..591c32a 100644 --- a/src/modules/memory.cpp +++ b/src/modules/memory.cpp @@ -1,12 +1,11 @@ #include "modules/memory.hpp" waybar::modules::Memory::Memory(const Json::Value& config) - : ALabel(config, "{}%") + : ALabel(config, "{}%", 30) { - uint32_t interval = config_["interval"].isUInt() ? config_["interval"].asUInt() : 30; - thread_ = [this, interval] { + thread_ = [this] { dp.emit(); - thread_.sleep_for(chrono::seconds(interval)); + thread_.sleep_for(interval_); }; } diff --git a/src/modules/network.cpp b/src/modules/network.cpp index 08901ae..c73ed00 100644 --- a/src/modules/network.cpp +++ b/src/modules/network.cpp @@ -1,7 +1,7 @@ #include "modules/network.hpp" waybar::modules::Network::Network(const Json::Value& config) - : ALabel(config, "{ifname}"), family_(AF_INET), + : ALabel(config, "{ifname}", 60), family_(AF_INET), signal_strength_dbm_(0), signal_strength_(0) { sock_fd_ = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); @@ -47,8 +47,10 @@ void waybar::modules::Network::worker() { thread_ = [this] { char buf[4096]; - uint64_t len = netlinkResponse(sock_fd_, buf, sizeof(buf), - RTMGRP_LINK | RTMGRP_IPV4_IFADDR); + auto len = netlinkResponse(sock_fd_, buf, sizeof(buf), RTMGRP_LINK | RTMGRP_IPV4_IFADDR); + if (len == 0) { + return; + } bool need_update = false; for (auto nh = reinterpret_cast(buf); NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len)) { @@ -81,13 +83,14 @@ void waybar::modules::Network::worker() } } if (need_update) { - getInfo(); + if (ifid_ > 0) { + getInfo(); + } dp.emit(); } }; - uint32_t interval = config_["interval"].isUInt() ? config_["interval"].asUInt() : 60; - thread_timer_ = [this, interval] { - thread_.sleep_for(std::chrono::seconds(interval)); + thread_timer_ = [this] { + thread_.sleep_for(interval_); if (ifid_ > 0) { getInfo(); dp.emit(); @@ -320,13 +323,12 @@ int waybar::modules::Network::netlinkRequest(int fd, void *req, int waybar::modules::Network::netlinkResponse(int fd, void *resp, uint32_t resplen, uint32_t groups) { - int ret; struct sockaddr_nl sa = {}; sa.nl_family = AF_NETLINK; sa.nl_groups = groups; struct iovec iov = { resp, resplen }; struct msghdr msg = { &sa, sizeof(sa), &iov, 1, nullptr, 0, 0 }; - ret = recvmsg(fd, &msg, 0); + auto ret = recvmsg(fd, &msg, 0); if (msg.msg_flags & MSG_TRUNC) { return -1; } @@ -421,7 +423,7 @@ auto waybar::modules::Network::getInfo() -> void { struct nl_msg* nl_msg = nlmsg_alloc(); if (nl_msg == nullptr) { - nl_socket_free(sk_); + nlmsg_free(nl_msg); return; } if (genlmsg_put(nl_msg, NL_AUTO_PORT, NL_AUTO_SEQ, nl80211_id_, 0, NLM_F_DUMP, diff --git a/src/modules/sni/watcher.cpp b/src/modules/sni/watcher.cpp index 0cb714e..59dc213 100644 --- a/src/modules/sni/watcher.cpp +++ b/src/modules/sni/watcher.cpp @@ -5,37 +5,28 @@ using namespace waybar::modules::SNI; Watcher::Watcher() -{ - GBusNameOwnerFlags flags = static_cast( - G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT - | G_BUS_NAME_OWNER_FLAGS_REPLACE); - bus_name_id_ = g_bus_own_name(G_BUS_TYPE_SESSION, - "org.kde.StatusNotifierWatcher", flags, - &Watcher::busAcquired, nullptr, nullptr, this, nullptr); - watcher_ = sn_watcher_skeleton_new(); - sn_watcher_set_protocol_version(watcher_, 1); -} - -Watcher::~Watcher() + : bus_name_id_(Gio::DBus::own_name(Gio::DBus::BusType::BUS_TYPE_SESSION, + "org.kde.StatusNotifierWatcher", sigc::mem_fun(*this, &Watcher::busAcquired), + Gio::DBus::SlotNameAcquired(), Gio::DBus::SlotNameLost(), + Gio::DBus::BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT | Gio::DBus::BUS_NAME_OWNER_FLAGS_REPLACE)), + watcher_(sn_watcher_skeleton_new()) { } -void Watcher::busAcquired(GDBusConnection* connection, const gchar* name, - gpointer data) +void Watcher::busAcquired(const Glib::RefPtr& conn, Glib::ustring name) { GError* error = nullptr; - auto host = static_cast(data); - g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(host->watcher_), - connection, "/StatusNotifierWatcher", &error); + g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(watcher_), + conn->gobj(), "/StatusNotifierWatcher", &error); if (error != nullptr) { std::cerr << error->message << std::endl; g_error_free(error); return; } - g_signal_connect_swapped(host->watcher_, "handle-register-item", - G_CALLBACK(&Watcher::handleRegisterItem), data); - g_signal_connect_swapped(host->watcher_, "handle-register-host", - G_CALLBACK(&Watcher::handleRegisterHost), data); + g_signal_connect_swapped(watcher_, "handle-register-item", + G_CALLBACK(&Watcher::handleRegisterItem), this); + g_signal_connect_swapped(watcher_, "handle-register-host", + G_CALLBACK(&Watcher::handleRegisterHost), this); } gboolean Watcher::handleRegisterHost(Watcher* obj,