diff --git a/include/factory.hpp b/include/factory.hpp index 3e45996..b572a57 100644 --- a/include/factory.hpp +++ b/include/factory.hpp @@ -15,7 +15,7 @@ namespace waybar { class Factory { public: Factory(Bar &bar, Json::Value config); - IModule &makeModule(std::string name); + IModule *makeModule(std::string name); private: Bar &_bar; Json::Value _config; diff --git a/include/modules/battery.hpp b/include/modules/battery.hpp index 5200037..38729ec 100644 --- a/include/modules/battery.hpp +++ b/include/modules/battery.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "util/chrono.hpp" #include "IModule.hpp" @@ -18,7 +19,7 @@ namespace waybar::modules { auto update() -> void; operator Gtk::Widget&(); private: - std::string _getIcon(uint32_t percentage); + std::string _getIcon(uint16_t percentage); static inline const fs::path _data_dir = "/sys/class/power_supply/"; std::vector _batteries; util::SleeperThread _thread; diff --git a/include/util/chrono.hpp b/include/util/chrono.hpp index e1f51f7..f0ad9a7 100644 --- a/include/util/chrono.hpp +++ b/include/util/chrono.hpp @@ -39,7 +39,9 @@ namespace waybar::util { func(); } while (do_run); }} - {} + { + defined = true; + } SleeperThread& operator=(std::function func) { @@ -48,6 +50,7 @@ namespace waybar::util { func(); } while (do_run); }); + defined = true; return *this; } @@ -72,14 +75,17 @@ namespace waybar::util { ~SleeperThread() { do_run = false; - condvar.notify_all(); - thread.join(); + if (defined) { + condvar.notify_all(); + thread.join(); + } } private: std::thread thread; std::condition_variable condvar; std::mutex mutex; + bool defined = false; bool do_run = true; }; diff --git a/src/bar.cpp b/src/bar.cpp index 5145631..115dca4 100644 --- a/src/bar.cpp +++ b/src/bar.cpp @@ -167,24 +167,27 @@ auto waybar::Bar::_setupWidgets() -> void box1.pack_end(right, true, true); Factory factory(*this, _config); - + if (_config["modules-left"]) { for (auto name : _config["modules-left"]) { - auto &module = factory.makeModule(name.asString()); - left.pack_start(module, false, true, 0); + auto module = factory.makeModule(name.asString()); + if (module) + left.pack_start(*module, false, true, 0); } } if (_config["modules-center"]) { for (auto name : _config["modules-center"]) { - auto &module = factory.makeModule(name.asString()); - center.pack_start(module, true, false, 10); + auto module = factory.makeModule(name.asString()); + if (module) + center.pack_start(*module, true, false, 10); } } if (_config["modules-right"]) { std::reverse(_config["modules-right"].begin(), _config["modules-right"].end()); for (auto name : _config["modules-right"]) { - auto &module = factory.makeModule(name.asString()); - right.pack_end(module, false, false, 0); + auto module = factory.makeModule(name.asString()); + if (module) + right.pack_end(*module, false, false, 0); } } } diff --git a/src/factory.cpp b/src/factory.cpp index a5a034f..1bf0c12 100644 --- a/src/factory.cpp +++ b/src/factory.cpp @@ -4,23 +4,32 @@ waybar::Factory::Factory(Bar &bar, Json::Value config) : _bar(bar), _config(config) {} -waybar::IModule &waybar::Factory::makeModule(std::string name) +waybar::IModule *waybar::Factory::makeModule(std::string name) { - if (name == "battery") - return *new waybar::modules::Battery(_config[name]); - if (name == "workspaces") - return *new waybar::modules::Workspaces(_bar); - if (name == "memory") - return *new waybar::modules::Memory(_config[name]); - if (name == "cpu") - return *new waybar::modules::Cpu(_config[name]); - if (name == "clock") - return *new waybar::modules::Clock(_config[name]); - if (name == "network") - return *new waybar::modules::Network(_config[name]); - if (name == "pulseaudio") - return *new waybar::modules::Pulseaudio(_config[name]); - if (!name.compare(0, 7, "custom/") && name.size() > 7) - return *new waybar::modules::Custom(name.substr(7), _config[name]); - throw std::runtime_error("Unknown module: " + name); + try { + if (name == "battery") + return new waybar::modules::Battery(_config[name]); + if (name == "workspaces") + return new waybar::modules::Workspaces(_bar); + if (name == "memory") + return new waybar::modules::Memory(_config[name]); + if (name == "cpu") + return new waybar::modules::Cpu(_config[name]); + if (name == "clock") + return new waybar::modules::Clock(_config[name]); + if (name == "network") + return new waybar::modules::Network(_config[name]); + if (name == "pulseaudio") + return new waybar::modules::Pulseaudio(_config[name]); + if (!name.compare(0, 7, "custom/") && name.size() > 7) + return new waybar::modules::Custom(name.substr(7), _config[name]); + std::cerr << "Unknown module: " + name << std::endl; + } catch (const std::exception& e) { + auto err = fmt::format("Disabling module \"{}\", {}", name, e.what()); + std::cerr << err << std::endl; + } catch (...) { + auto err = fmt::format("Disabling module \"{}\", Unknown reason", name); + std::cerr << err << std::endl; + } + return nullptr; } diff --git a/src/modules/battery.cpp b/src/modules/battery.cpp index fe76b8e..05e1b87 100644 --- a/src/modules/battery.cpp +++ b/src/modules/battery.cpp @@ -5,62 +5,66 @@ waybar::modules::Battery::Battery(Json::Value config) { try { for (auto &node : fs::directory_iterator(_data_dir)) { - if (fs::is_directory(node) && fs::exists(node / "capacity") - && fs::exists(node / "status")) { + if (fs::is_directory(node) && fs::exists(node / "capacity")) _batteries.push_back(node); - } } } catch (fs::filesystem_error &e) { - std::cerr << e.what() << std::endl; + throw std::runtime_error(e.what()); } - if (!_batteries.size()) { - std::cerr << "No batteries." << std::endl; - return; - } + if (!_batteries.size()) + throw std::runtime_error("No batteries."); + auto fd = inotify_init(); + if (fd == -1) + throw std::runtime_error("Unable to listen batteries."); + for (auto &bat : _batteries) + inotify_add_watch(fd, (bat / "uevent").c_str(), IN_ACCESS); + // Trigger first value + update(); _label.get_style_context()->add_class("battery"); - int interval = _config["interval"] ? _config["inveral"].asInt() : 1; - _thread = [this, interval] { + _thread = [this, fd] { + struct inotify_event event; + int nbytes = read(fd, &event, sizeof(event)); + if (nbytes != sizeof(event)) + return; Glib::signal_idle().connect_once(sigc::mem_fun(*this, &Battery::update)); - _thread.sleep_for(chrono::seconds(interval)); }; } auto waybar::modules::Battery::update() -> void { try { - int total = 0; + uint16_t total = 0; bool charging = false; + std::string status; for (auto &bat : _batteries) { - int capacity; - std::string status; + uint16_t capacity; std::ifstream(bat / "capacity") >> capacity; - total += capacity; std::ifstream(bat / "status") >> status; - if (status == "Charging") { + if (status == "Charging") charging = true; - } + total += capacity; } + uint16_t capacity = total / _batteries.size(); auto format = _config["format"] ? _config["format"].asString() : "{}%"; - auto value = total / _batteries.size(); - _label.set_text(fmt::format(format, fmt::arg("value", value), - fmt::arg("icon", _getIcon(value)))); - _label.set_tooltip_text(charging ? "Charging" : "Discharging"); + _label.set_text(fmt::format(format, fmt::arg("value", capacity), + fmt::arg("icon", _getIcon(capacity)))); + _label.set_tooltip_text(status); if (charging) _label.get_style_context()->add_class("charging"); else _label.get_style_context()->remove_class("charging"); - if (value < 16 && !charging) + if (capacity < 16 && !charging) _label.get_style_context()->add_class("warning"); else _label.get_style_context()->remove_class("warning"); - } catch (std::exception &e) { + } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } } -std::string waybar::modules::Battery::_getIcon(uint32_t percentage) +std::string waybar::modules::Battery::_getIcon(uint16_t percentage) { if (!_config["format-icons"] || !_config["format-icons"].isArray()) return ""; auto step = 100 / _config["format-icons"].size(); diff --git a/src/modules/custom.cpp b/src/modules/custom.cpp index a2decc0..ee8a9da 100644 --- a/src/modules/custom.cpp +++ b/src/modules/custom.cpp @@ -4,10 +4,8 @@ waybar::modules::Custom::Custom(std::string name, Json::Value config) : _name(name), _config(config) { - if (!_config["exec"]) { - std::cerr << name + " has no exec path." << std::endl; - return; - } + if (!_config["exec"]) + throw std::runtime_error(name + " has no exec path."); int interval = _config["interval"] ? _config["inveral"].asInt() : 30; _thread = [this, interval] { Glib::signal_idle().connect_once(sigc::mem_fun(*this, &Custom::update)); diff --git a/src/modules/network.cpp b/src/modules/network.cpp index 721b2f9..b724b69 100644 --- a/src/modules/network.cpp +++ b/src/modules/network.cpp @@ -1,8 +1,10 @@ #include "modules/network.hpp" waybar::modules::Network::Network(Json::Value config) - : _config(config), _ifid(if_nametoindex(config["interface"].asString().c_str())) + : _config(config), _ifid(if_nametoindex(config["interface"].asCString())) { + if (_ifid == 0) + throw std::runtime_error("Can't found network interface"); _label.get_style_context()->add_class("network"); int interval = _config["interval"] ? _config["inveral"].asInt() : 30; _thread = [this, interval] { @@ -103,8 +105,6 @@ bool waybar::modules::Network::_associatedOrJoined(struct nlattr** bss) auto waybar::modules::Network::_getInfo() -> void { - if (_ifid == 0) - return; struct nl_sock *sk = nl_socket_alloc(); if (genl_connect(sk) != 0) { nl_socket_free(sk); diff --git a/src/modules/workspaces.cpp b/src/modules/workspaces.cpp index f3910e9..634847d 100644 --- a/src/modules/workspaces.cpp +++ b/src/modules/workspaces.cpp @@ -5,17 +5,12 @@ waybar::modules::Workspaces::Workspaces(Bar &bar) : _bar(bar) { _box.get_style_context()->add_class("workspaces"); - try { - std::string socketPath = get_socketpath(); - _ipcSocketfd = ipc_open_socket(socketPath); - _ipcEventSocketfd = ipc_open_socket(socketPath); - const char *subscribe = "[ \"workspace\", \"mode\" ]"; - uint32_t len = strlen(subscribe); - ipc_single_command(_ipcEventSocketfd, IPC_SUBSCRIBE, subscribe, &len); - } catch (const std::exception& e) { - std::cerr << e.what() << std::endl; - return; - } + std::string socketPath = get_socketpath(); + _ipcSocketfd = ipc_open_socket(socketPath); + _ipcEventSocketfd = ipc_open_socket(socketPath); + const char *subscribe = "[ \"workspace\", \"mode\" ]"; + uint32_t len = strlen(subscribe); + ipc_single_command(_ipcEventSocketfd, IPC_SUBSCRIBE, subscribe, &len); _thread = [this] { Glib::signal_idle().connect_once(sigc::mem_fun(*this, &Workspaces::update)); _thread.sleep_for(chrono::milliseconds(250));