diff --git a/include/bar.hpp b/include/bar.hpp index e7d9c6d8..924cdb53 100644 --- a/include/bar.hpp +++ b/include/bar.hpp @@ -18,6 +18,7 @@ class Bar { public: Bar(const Client&, std::unique_ptr&&, uint32_t); Bar(const Bar&) = delete; + ~Bar() = default; auto toggle() -> void; @@ -54,6 +55,10 @@ class Bar { Glib::RefPtr style_context_; Glib::RefPtr css_provider_; struct zxdg_output_v1 *xdg_output_; + Gtk::Box left_; + Gtk::Box center_; + Gtk::Box right_; + Gtk::Box box_; std::vector> modules_left_; std::vector> modules_center_; std::vector> modules_right_; diff --git a/include/modules/battery.hpp b/include/modules/battery.hpp index b8080d82..f933a0c9 100644 --- a/include/modules/battery.hpp +++ b/include/modules/battery.hpp @@ -10,7 +10,7 @@ #include #include #include -#include "util/chrono.hpp" +#include "util/sleeper_thread.hpp" #include "ALabel.hpp" namespace waybar::modules { diff --git a/include/modules/clock.hpp b/include/modules/clock.hpp index 687f3feb..fe80dc5f 100644 --- a/include/modules/clock.hpp +++ b/include/modules/clock.hpp @@ -2,7 +2,7 @@ #include #include "fmt/time.h" -#include "util/chrono.hpp" +#include "util/sleeper_thread.hpp" #include "ALabel.hpp" namespace waybar::modules { @@ -10,6 +10,7 @@ namespace waybar::modules { class Clock : public ALabel { public: Clock(const std::string&, const Json::Value&); + ~Clock() = default; auto update() -> void; private: waybar::util::SleeperThread thread_; diff --git a/include/modules/cpu.hpp b/include/modules/cpu.hpp index 35c00177..467b11f4 100644 --- a/include/modules/cpu.hpp +++ b/include/modules/cpu.hpp @@ -6,7 +6,7 @@ #include #include #include -#include "util/chrono.hpp" +#include "util/sleeper_thread.hpp" #include "ALabel.hpp" namespace waybar::modules { @@ -14,6 +14,7 @@ namespace waybar::modules { class Cpu : public ALabel { public: Cpu(const std::string&, const Json::Value&); + ~Cpu() = default; auto update() -> void; private: static inline const std::string data_dir_ = "/proc/stat"; diff --git a/include/modules/custom.hpp b/include/modules/custom.hpp index 074ed04a..f9e4dec6 100644 --- a/include/modules/custom.hpp +++ b/include/modules/custom.hpp @@ -2,7 +2,7 @@ #include #include -#include "util/chrono.hpp" +#include "util/sleeper_thread.hpp" #include "util/command.hpp" #include "util/json.hpp" #include "ALabel.hpp" diff --git a/include/modules/memory.hpp b/include/modules/memory.hpp index bb138d03..1b21e8a2 100644 --- a/include/modules/memory.hpp +++ b/include/modules/memory.hpp @@ -2,7 +2,7 @@ #include #include -#include "util/chrono.hpp" +#include "util/sleeper_thread.hpp" #include "ALabel.hpp" namespace waybar::modules { @@ -10,6 +10,7 @@ namespace waybar::modules { class Memory : public ALabel { public: Memory(const std::string&, const Json::Value&); + ~Memory() = default; auto update() -> void; private: static inline const std::string data_dir_ = "/proc/meminfo"; diff --git a/include/modules/network.hpp b/include/modules/network.hpp index 2f20e180..41bc04d4 100644 --- a/include/modules/network.hpp +++ b/include/modules/network.hpp @@ -7,8 +7,9 @@ #include #include #include +#include #include -#include "util/chrono.hpp" +#include "util/sleeper_thread.hpp" #include "ALabel.hpp" namespace waybar::modules { @@ -19,15 +20,17 @@ class Network : public ALabel { ~Network(); auto update() -> void; private: - static int netlinkRequest(int, void*, uint32_t, uint32_t groups = 0); - static int netlinkResponse(int, void*, uint32_t, uint32_t groups = 0); - static int scanCb(struct nl_msg*, void*); + static int handleEvents(struct nl_msg*, void*); + static int handleScan(struct nl_msg*, void*); void worker(); void disconnected(); - void initNL80211(); + void createInfoSocket(); + void createEventSocket(); int getExternalInterface(); void getInterfaceAddress(); + int netlinkRequest(void*, uint32_t, uint32_t groups = 0); + int netlinkResponse(void*, uint32_t, uint32_t groups = 0); void parseEssid(struct nlattr**); void parseSignal(struct nlattr**); bool associatedOrJoined(struct nlattr**); @@ -37,9 +40,11 @@ class Network : public ALabel { waybar::util::SleeperThread thread_timer_; int ifid_; sa_family_t family_; - int sock_fd_; struct sockaddr_nl nladdr_ = {0}; struct nl_sock* sk_ = nullptr; + struct nl_sock* info_sock_ = nullptr; + int efd_; + int ev_fd_; int nl80211_id_; std::string essid_; diff --git a/include/modules/sni/tray.hpp b/include/modules/sni/tray.hpp index 9ee0c9e7..2b27604a 100644 --- a/include/modules/sni/tray.hpp +++ b/include/modules/sni/tray.hpp @@ -1,7 +1,6 @@ #pragma once #include -#include #include "bar.hpp" #include "util/json.hpp" #include "IModule.hpp" @@ -13,6 +12,7 @@ namespace waybar::modules::SNI { class Tray : public IModule { public: Tray(const std::string&, const Json::Value&); + ~Tray() = default; auto update() -> void; operator Gtk::Widget &(); private: @@ -20,7 +20,6 @@ class Tray : public IModule { void onRemove(std::unique_ptr& item); static inline std::size_t nb_hosts_ = 0; - std::thread thread_; const Json::Value& config_; Gtk::Box box_; SNI::Watcher watcher_ ; diff --git a/include/modules/sway/ipc/client.hpp b/include/modules/sway/ipc/client.hpp index a621a927..3dbbc0ff 100644 --- a/include/modules/sway/ipc/client.hpp +++ b/include/modules/sway/ipc/client.hpp @@ -10,33 +10,31 @@ namespace waybar::modules::sway { class Ipc { - public: - Ipc(); - ~Ipc(); +public: + Ipc(); + ~Ipc(); - struct ipc_response { - uint32_t size; - uint32_t type; - std::string payload; - }; + struct ipc_response { + uint32_t size; + uint32_t type; + std::string payload; + }; - void connect(); - struct ipc_response sendCmd(uint32_t type, - const std::string& payload = "") const; - void subscribe(const std::string& payload) const; - struct ipc_response handleEvent() const; - protected: - static inline const std::string ipc_magic_ = "i3-ipc"; - static inline const size_t ipc_header_size_ = ipc_magic_.size() + 8; + struct ipc_response sendCmd(uint32_t type, const std::string &payload = "") const; + void subscribe(const std::string &payload) const; + struct ipc_response handleEvent() const; - const std::string getSocketPath() const; - int open(const std::string&) const; - struct ipc_response send(int fd, uint32_t type, - const std::string& payload = "") const; - struct ipc_response recv(int fd) const; +protected: + static inline const std::string ipc_magic_ = "i3-ipc"; + static inline const size_t ipc_header_size_ = ipc_magic_.size() + 8; - int fd_; - int fd_event_; + const std::string getSocketPath() const; + int open(const std::string &) const; + struct ipc_response send(int fd, uint32_t type, const std::string &payload = "") const; + struct ipc_response recv(int fd) const; + + int fd_; + int fd_event_; }; -} +} // namespace waybar::modules::sway diff --git a/include/modules/sway/ipc/ipc.hpp b/include/modules/sway/ipc/ipc.hpp index ba3439ea..2c5a7a6e 100644 --- a/include/modules/sway/ipc/ipc.hpp +++ b/include/modules/sway/ipc/ipc.hpp @@ -3,30 +3,30 @@ #define event_mask(ev) (1u << (ev & 0x7F)) enum ipc_command_type { - // i3 command types - see i3's I3_REPLY_TYPE constants - IPC_COMMAND = 0, - IPC_GET_WORKSPACES = 1, - IPC_SUBSCRIBE = 2, - IPC_GET_OUTPUTS = 3, - IPC_GET_TREE = 4, - IPC_GET_MARKS = 5, - IPC_GET_BAR_CONFIG = 6, - IPC_GET_VERSION = 7, - IPC_GET_BINDING_MODES = 8, - IPC_GET_CONFIG = 9, - IPC_SEND_TICK = 10, + // i3 command types - see i3's I3_REPLY_TYPE constants + IPC_COMMAND = 0, + IPC_GET_WORKSPACES = 1, + IPC_SUBSCRIBE = 2, + IPC_GET_OUTPUTS = 3, + IPC_GET_TREE = 4, + IPC_GET_MARKS = 5, + IPC_GET_BAR_CONFIG = 6, + IPC_GET_VERSION = 7, + IPC_GET_BINDING_MODES = 8, + IPC_GET_CONFIG = 9, + IPC_SEND_TICK = 10, - // sway-specific command types - IPC_GET_INPUTS = 100, - IPC_GET_SEATS = 101, + // sway-specific command types + IPC_GET_INPUTS = 100, + IPC_GET_SEATS = 101, - // Events sent from sway to clients. Events have the highest bits set. - IPC_EVENT_WORKSPACE = ((1<<31) | 0), - IPC_EVENT_OUTPUT = ((1<<31) | 1), - IPC_EVENT_MODE = ((1<<31) | 2), - IPC_EVENT_WINDOW = ((1<<31) | 3), - IPC_EVENT_BARCONFIG_UPDATE = ((1<<31) | 4), - IPC_EVENT_BINDING = ((1<<31) | 5), - IPC_EVENT_SHUTDOWN = ((1<<31) | 6), - IPC_EVENT_TICK = ((1<<31) | 7), + // Events sent from sway to clients. Events have the highest bits set. + IPC_EVENT_WORKSPACE = ((1 << 31) | 0), + IPC_EVENT_OUTPUT = ((1 << 31) | 1), + IPC_EVENT_MODE = ((1 << 31) | 2), + IPC_EVENT_WINDOW = ((1 << 31) | 3), + IPC_EVENT_BARCONFIG_UPDATE = ((1 << 31) | 4), + IPC_EVENT_BINDING = ((1 << 31) | 5), + IPC_EVENT_SHUTDOWN = ((1 << 31) | 6), + IPC_EVENT_TICK = ((1 << 31) | 7), }; diff --git a/include/modules/sway/mode.hpp b/include/modules/sway/mode.hpp index 51bb086f..326342c8 100644 --- a/include/modules/sway/mode.hpp +++ b/include/modules/sway/mode.hpp @@ -3,7 +3,7 @@ #include #include "bar.hpp" #include "client.hpp" -#include "util/chrono.hpp" +#include "util/sleeper_thread.hpp" #include "util/json.hpp" #include "ALabel.hpp" #include "modules/sway/ipc/client.hpp" @@ -13,6 +13,7 @@ namespace waybar::modules::sway { class Mode : public ALabel { public: Mode(const std::string&, const waybar::Bar&, const Json::Value&); + ~Mode() = default; auto update() -> void; private: void worker(); diff --git a/include/modules/sway/window.hpp b/include/modules/sway/window.hpp index 8cf11b3e..d89d0669 100644 --- a/include/modules/sway/window.hpp +++ b/include/modules/sway/window.hpp @@ -4,7 +4,7 @@ #include #include "bar.hpp" #include "client.hpp" -#include "util/chrono.hpp" +#include "util/sleeper_thread.hpp" #include "util/json.hpp" #include "ALabel.hpp" #include "modules/sway/ipc/client.hpp" @@ -14,6 +14,7 @@ namespace waybar::modules::sway { class Window : public ALabel { public: Window(const std::string&, const waybar::Bar&, const Json::Value&); + ~Window() = default; auto update() -> void; private: void worker(); diff --git a/include/modules/sway/workspaces.hpp b/include/modules/sway/workspaces.hpp index 25cf8679..f3fe7b62 100644 --- a/include/modules/sway/workspaces.hpp +++ b/include/modules/sway/workspaces.hpp @@ -3,7 +3,7 @@ #include #include "bar.hpp" #include "client.hpp" -#include "util/chrono.hpp" +#include "util/sleeper_thread.hpp" #include "util/json.hpp" #include "IModule.hpp" #include "modules/sway/ipc/client.hpp" @@ -14,6 +14,7 @@ namespace waybar::modules::sway { class Workspaces : public IModule { public: Workspaces(const std::string&, const waybar::Bar&, const Json::Value&); + ~Workspaces() = default; auto update() -> void; operator Gtk::Widget &(); private: @@ -27,14 +28,14 @@ class Workspaces : public IModule { const Bar& bar_; const Json::Value& config_; + Json::Value workspaces_; waybar::util::SleeperThread thread_; Gtk::Box box_; util::JsonParser parser_; + Ipc ipc_; std::mutex mutex_; bool scrolling_; std::unordered_map buttons_; - Json::Value workspaces_; - Ipc ipc_; }; } diff --git a/include/util/command.hpp b/include/util/command.hpp index fd37e511..02468b8f 100644 --- a/include/util/command.hpp +++ b/include/util/command.hpp @@ -2,6 +2,7 @@ #include #include +#include namespace waybar::util::command { diff --git a/include/util/json.hpp b/include/util/json.hpp index 279936fa..7671fa11 100644 --- a/include/util/json.hpp +++ b/include/util/json.hpp @@ -10,7 +10,7 @@ struct JsonParser { : reader_(builder_.newCharReader()) {} - const Json::Value parse(const std::string data) const + const Json::Value parse(const std::string& data) const { Json::Value root; std::string err; diff --git a/include/util/chrono.hpp b/include/util/sleeper_thread.hpp similarity index 56% rename from include/util/chrono.hpp rename to include/util/sleeper_thread.hpp index c06373e3..5f403ccb 100644 --- a/include/util/chrono.hpp +++ b/include/util/sleeper_thread.hpp @@ -6,30 +6,20 @@ #include #include -namespace waybar::chrono { - -using namespace std::chrono; - -using clock = std::chrono::system_clock; -using duration = clock::duration; -using time_point = std::chrono::time_point; - -} - namespace waybar::util { -struct SleeperThread { +class SleeperThread { +public: SleeperThread() = default; SleeperThread(std::function func) - : do_run_(true), thread_{[this, func] { + : thread_{[this, func] { while (do_run_) func(); }} {} SleeperThread& operator=(std::function func) { - do_run_ = true; thread_ = std::thread([this, func] { while (do_run_) func(); }); @@ -41,16 +31,17 @@ struct SleeperThread { return do_run_; } - auto sleep_for(chrono::duration dur) + auto sleep_for(std::chrono::system_clock::duration dur) { - auto lock = std::unique_lock(mutex_); - return condvar_.wait_for(lock, dur); + std::unique_lock lk(mutex_); + return condvar_.wait_for(lk, dur, [this] { return !do_run_; }); } - auto sleep_until(chrono::time_point time) + auto sleep_until(std::chrono::time_point time_point) { - auto lock = std::unique_lock(mutex_); - return condvar_.wait_until(lock, time); + std::unique_lock lk(mutex_); + return condvar_.wait_until(lk, time_point, [this] { return !do_run_; }); } auto wake_up() @@ -60,7 +51,10 @@ struct SleeperThread { auto stop() { - do_run_ = false; + { + std::lock_guard lck(mutex_); + do_run_ = false; + } condvar_.notify_all(); } @@ -68,15 +62,15 @@ struct SleeperThread { { stop(); if (thread_.joinable()) { - thread_.detach(); + thread_.join(); } } private: - bool do_run_ = false; std::thread thread_; std::condition_variable condvar_; std::mutex mutex_; + bool do_run_ = true; }; } diff --git a/meson.build b/meson.build index 51e2c109..9bf5c437 100644 --- a/meson.build +++ b/meson.build @@ -9,7 +9,7 @@ project( ], ) -cpp_args = ['-DVERSION="@0@"'.format(meson.project_version())] +cpp_args = [] cpp_link_args = [] if false # libc++ @@ -22,6 +22,16 @@ else endif compiler = meson.get_compiler('cpp') +git = find_program('git', required: false) + +if not git.found() + add_project_arguments('-DVERSION="@0@"'.format(meson.project_version()), language: 'cpp') +else + git_commit_hash = run_command([git.path(), 'describe', '--always', '--tags']).stdout().strip() + git_branch = run_command([git.path(), 'rev-parse', '--abbrev-ref', 'HEAD']).stdout().strip() + version = '"@0@ (" __DATE__ ", branch \'@1@\')"'.format(git_commit_hash, git_branch) + add_project_arguments('-DVERSION=@0@'.format(version), language: 'cpp') +endif if not compiler.has_header('filesystem') add_project_arguments('-DFILESYSTEM_EXPERIMENTAL', language: 'cpp') diff --git a/src/bar.cpp b/src/bar.cpp index b28e9200..0561af58 100644 --- a/src/bar.cpp +++ b/src/bar.cpp @@ -7,7 +7,9 @@ waybar::Bar::Bar(const Client& client, std::unique_ptr &&p_output, uint32_t p_wl_name) : client(client), window{Gtk::WindowType::WINDOW_TOPLEVEL}, surface(nullptr), layer_surface(nullptr), - output(std::move(p_output)), wl_name(p_wl_name) + output(std::move(p_output)), wl_name(p_wl_name), + left_(Gtk::ORIENTATION_HORIZONTAL, 0), center_(Gtk::ORIENTATION_HORIZONTAL, 0), + right_(Gtk::ORIENTATION_HORIZONTAL, 0), box_(Gtk::ORIENTATION_HORIZONTAL, 0) { static const struct zxdg_output_v1_listener xdgOutputListener = { .logical_position = handleLogicalPosition, @@ -200,28 +202,23 @@ void waybar::Bar::getModules(const Factory& factory, const std::string& pos) auto waybar::Bar::setupWidgets() -> void { - auto &left = *Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_HORIZONTAL, 0)); - auto ¢er = *Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_HORIZONTAL, 0)); - auto &right = *Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_HORIZONTAL, 0)); - - auto &box = *Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_HORIZONTAL, 0)); - window.add(box); - box.pack_start(left, true, true); - box.set_center_widget(center); - box.pack_end(right, true, true); + window.add(box_); + box_.pack_start(left_, true, true); + box_.set_center_widget(center_); + box_.pack_end(right_, true, true); Factory factory(*this, config_); getModules(factory, "modules-left"); getModules(factory, "modules-center"); getModules(factory, "modules-right"); for (auto const& module : modules_left_) { - left.pack_start(*module, false, true, 0); + left_.pack_start(*module, false, true, 0); } for (auto const& module : modules_center_) { - center.pack_start(*module, true, true, 0); + center_.pack_start(*module, true, true, 0); } std::reverse(modules_right_.begin(), modules_right_.end()); for (auto const& module : modules_right_) { - right.pack_end(*module, false, false, 0); + right_.pack_end(*module, false, false, 0); } } diff --git a/src/modules/clock.cpp b/src/modules/clock.cpp index 2b7b41fb..85bcd5f8 100644 --- a/src/modules/clock.cpp +++ b/src/modules/clock.cpp @@ -8,7 +8,7 @@ waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config) label_.get_style_context()->add_class(id); } thread_ = [this] { - auto now = waybar::chrono::clock::now(); + auto now = std::chrono::system_clock::now(); dp.emit(); auto timeout = std::chrono::floor(now + interval_); auto time_s = std::chrono::time_point_cast(timeout); diff --git a/src/modules/cpu.cpp b/src/modules/cpu.cpp index 5d9a1c87..3e01aff1 100644 --- a/src/modules/cpu.cpp +++ b/src/modules/cpu.cpp @@ -38,7 +38,7 @@ std::tuple waybar::modules::Cpu::getCpuUsage() { if (prev_times_.empty()) { prev_times_ = parseCpuinfo(); - std::this_thread::sleep_for(chrono::milliseconds(100)); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); } std::vector> curr_times = parseCpuinfo(); std::string tooltip; diff --git a/src/modules/network.cpp b/src/modules/network.cpp index ef68cb6a..fec2d2e9 100644 --- a/src/modules/network.cpp +++ b/src/modules/network.cpp @@ -1,23 +1,16 @@ +#include #include "modules/network.hpp" waybar::modules::Network::Network(const std::string& id, const Json::Value& config) - : ALabel(config, "{ifname}", 60), family_(AF_INET), + : ALabel(config, "{ifname}", 60), family_(AF_INET), efd_(-1), ev_fd_(-1), cidr_(-1), signal_strength_dbm_(0), signal_strength_(0) { label_.set_name("network"); if (!id.empty()) { label_.get_style_context()->add_class(id); } - sock_fd_ = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); - if (sock_fd_ < 0) { - throw std::runtime_error("Can't open network socket"); - } - nladdr_.nl_family = AF_NETLINK; - nladdr_.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR; - if (bind(sock_fd_, reinterpret_cast(&nladdr_), - sizeof(nladdr_)) != 0) { - throw std::runtime_error("Can't bind network socket"); - } + createInfoSocket(); + createEventSocket(); if (config_["interface"].isString()) { ifid_ = if_nametoindex(config_["interface"].asCString()); ifname_ = config_["interface"].asString(); @@ -32,73 +25,112 @@ waybar::modules::Network::Network(const std::string& id, const Json::Value& conf ifname_ = ifname; } } - initNL80211(); - // Trigger first values - getInfo(); dp.emit(); worker(); } waybar::modules::Network::~Network() { - close(sock_fd_); - nl_socket_free(sk_); + if (ev_fd_ > -1) { + eventfd_write(ev_fd_, 1); + std::this_thread::sleep_for(std::chrono::milliseconds(150)); + close(ev_fd_); + } + if (efd_ > -1) { + close(efd_); + } + if (info_sock_ != nullptr) { + nl_socket_drop_membership(info_sock_, RTMGRP_LINK); + nl_socket_drop_membership(info_sock_, RTMGRP_IPV4_IFADDR); + nl_close(info_sock_); + nl_socket_free(info_sock_); + } + if (sk_ != nullptr) { + nl_close(sk_); + nl_socket_free(sk_); + } +} + +void waybar::modules::Network::createInfoSocket() +{ + info_sock_ = nl_socket_alloc(); + if (nl_connect(info_sock_, NETLINK_ROUTE) != 0) { + throw std::runtime_error("Can't connect network socket"); + } + if (nl_socket_add_membership(info_sock_, RTMGRP_LINK) != 0) { + throw std::runtime_error("Can't add membership"); + } + if (nl_socket_add_membership(info_sock_, RTMGRP_IPV4_IFADDR) != 0) { + throw std::runtime_error("Can't add membership"); + } + nl_socket_disable_seq_check(info_sock_); + nl_socket_set_nonblocking(info_sock_); + nl_socket_modify_cb(info_sock_, NL_CB_MSG_IN, NL_CB_CUSTOM, handleEvents, this); + efd_ = epoll_create1(0); + if (efd_ < 0) { + throw std::runtime_error("Can't create epoll"); + } + { + ev_fd_ = eventfd(0, EFD_NONBLOCK); + struct epoll_event event; + event.events = EPOLLIN | EPOLLET; + event.data.fd = ev_fd_; + if (epoll_ctl(efd_, EPOLL_CTL_ADD, ev_fd_, &event) == -1) { + throw std::runtime_error("Can't add epoll event"); + } + } + { + auto fd = nl_socket_get_fd(info_sock_); + struct epoll_event event; + event.events = EPOLLIN; + event.data.fd = fd; + if (epoll_ctl(efd_, EPOLL_CTL_ADD, fd, &event) == -1) { + throw std::runtime_error("Can't add epoll event"); + } + } +} + +void waybar::modules::Network::createEventSocket() +{ + sk_ = nl_socket_alloc(); + if (genl_connect(sk_) != 0) { + throw std::runtime_error("Can't connect to netlink socket"); + } + nl_socket_disable_seq_check(sk_); + if (nl_socket_modify_cb(sk_, NL_CB_VALID, NL_CB_CUSTOM, handleScan, this) < 0) { + throw std::runtime_error("Can't set callback"); + } + nl80211_id_ = genl_ctrl_resolve(sk_, "nl80211"); + if (nl80211_id_ < 0) { + throw std::runtime_error("Can't resolve nl80211 interface"); + } } void waybar::modules::Network::worker() { - thread_ = [this] { - char buf[4096]; - 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)) { - if (nh->nlmsg_type == NLMSG_DONE) { - break; - } - if (nh->nlmsg_type == NLMSG_ERROR) { - continue; - } - if (nh->nlmsg_type == RTM_NEWADDR) { - need_update = true; - } - if (nh->nlmsg_type < RTM_NEWADDR) { - auto rtif = static_cast(NLMSG_DATA(nh)); - if (rtif->ifi_index == static_cast(ifid_)) { - need_update = true; - if (!(rtif->ifi_flags & IFF_RUNNING)) { - disconnected(); - } - } - } - } - if (ifid_ <= 0 && !config_["interface"].isString()) { - // Need to wait before get external interface - thread_.sleep_for(std::chrono::seconds(1)); - ifid_ = getExternalInterface(); - if (ifid_ > 0) { - char ifname[IF_NAMESIZE]; - if_indextoname(ifid_, ifname); - ifname_ = ifname; - need_update = true; - } - } - if (need_update) { - if (ifid_ > 0) { - getInfo(); - } - dp.emit(); - } - }; thread_timer_ = [this] { - thread_timer_.sleep_for(interval_); if (ifid_ > 0) { getInfo(); dp.emit(); } + thread_timer_.sleep_for(interval_); + }; + thread_ = [this] { + struct epoll_event events[16]; + int ec = epoll_wait(efd_, events, 16, -1); + if (ec > 0) { + for (auto i = 0; i < ec; i++) { + if (events[i].events & EPOLLIN + && events[i].data.fd == nl_socket_get_fd(info_sock_)) { + nl_recvmsgs_default(info_sock_); + } else { + thread_.stop(); + break; + } + } + } else if (ec == -1) { + thread_.stop(); + } }; } @@ -151,24 +183,6 @@ void waybar::modules::Network::disconnected() thread_.sleep_for(std::chrono::seconds(1)); } -void waybar::modules::Network::initNL80211() -{ - sk_ = nl_socket_alloc(); - if (genl_connect(sk_) != 0) { - nl_socket_free(sk_); - throw std::runtime_error("Can't connect to netlink socket"); - } - if (nl_socket_modify_cb(sk_, NL_CB_VALID, NL_CB_CUSTOM, scanCb, this) < 0) { - nl_socket_free(sk_); - throw std::runtime_error("Can't connect to netlink socket"); - } - nl80211_id_ = genl_ctrl_resolve(sk_, "nl80211"); - if (nl80211_id_ < 0) { - nl_socket_free(sk_); - throw std::runtime_error("Can't resolve nl80211 interface"); - } -} - // Based on https://gist.github.com/Yawning/c70d804d4b8ae78cc698 int waybar::modules::Network::getExternalInterface() { @@ -192,7 +206,7 @@ int waybar::modules::Network::getExternalInterface() rt->rtm_table = RT_TABLE_MAIN; /* Issue the query. */ - if (netlinkRequest(sock_fd_, req, reqlen) < 0) { + if (netlinkRequest(req, reqlen) < 0) { goto out; } @@ -202,7 +216,7 @@ int waybar::modules::Network::getExternalInterface() * consume responses till NLMSG_DONE/NLMSG_ERROR is encountered). */ do { - auto len = netlinkResponse(sock_fd_, resp, route_buffer_size); + auto len = netlinkResponse(resp, route_buffer_size); if (len < 0) { goto out; } @@ -322,7 +336,7 @@ void waybar::modules::Network::getInterfaceAddress() { } } -int waybar::modules::Network::netlinkRequest(int fd, void *req, +int waybar::modules::Network::netlinkRequest(void *req, uint32_t reqlen, uint32_t groups) { struct sockaddr_nl sa = {}; @@ -330,10 +344,10 @@ int waybar::modules::Network::netlinkRequest(int fd, void *req, sa.nl_groups = groups; struct iovec iov = { req, reqlen }; struct msghdr msg = { &sa, sizeof(sa), &iov, 1, nullptr, 0, 0 }; - return sendmsg(fd, &msg, 0); + return sendmsg(nl_socket_get_fd(info_sock_), &msg, 0); } -int waybar::modules::Network::netlinkResponse(int fd, void *resp, +int waybar::modules::Network::netlinkResponse(void *resp, uint32_t resplen, uint32_t groups) { struct sockaddr_nl sa = {}; @@ -341,14 +355,50 @@ int waybar::modules::Network::netlinkResponse(int fd, void *resp, sa.nl_groups = groups; struct iovec iov = { resp, resplen }; struct msghdr msg = { &sa, sizeof(sa), &iov, 1, nullptr, 0, 0 }; - auto ret = recvmsg(fd, &msg, 0); + auto ret = recvmsg(nl_socket_get_fd(info_sock_), &msg, 0); if (msg.msg_flags & MSG_TRUNC) { return -1; } return ret; } -int waybar::modules::Network::scanCb(struct nl_msg *msg, void *data) { +int waybar::modules::Network::handleEvents(struct nl_msg *msg, void *data) { + auto net = static_cast(data); + bool need_update = false; + nlmsghdr *nh = nlmsg_hdr(msg); + if (nh->nlmsg_type == RTM_NEWADDR) { + need_update = true; + } + if (nh->nlmsg_type < RTM_NEWADDR) { + auto rtif = static_cast(NLMSG_DATA(nh)); + if (rtif->ifi_index == static_cast(net->ifid_)) { + need_update = true; + if (!(rtif->ifi_flags & IFF_RUNNING)) { + net->disconnected(); + } + } + } + if (net->ifid_ <= 0 && !net->config_["interface"].isString()) { + // Need to wait before get external interface + net->thread_.sleep_for(std::chrono::seconds(1)); + net->ifid_ = net->getExternalInterface(); + if (net->ifid_ > 0) { + char ifname[IF_NAMESIZE]; + if_indextoname(net->ifid_, ifname); + net->ifname_ = ifname; + need_update = true; + } + } + if (need_update) { + if (net->ifid_ > 0) { + net->getInfo(); + } + net->dp.emit(); + } + return NL_SKIP; +} + +int waybar::modules::Network::handleScan(struct nl_msg *msg, void *data) { auto net = static_cast(data); auto gnlh = static_cast(nlmsg_data(nlmsg_hdr(msg))); struct nlattr* tb[NL80211_ATTR_MAX + 1]; @@ -404,7 +454,7 @@ void waybar::modules::Network::parseEssid(struct nlattr **bss) void waybar::modules::Network::parseSignal(struct nlattr **bss) { if (bss[NL80211_BSS_SIGNAL_MBM] != nullptr) { - // signalstrength in dBm + // signalstrength in dBm from mBm signal_strength_dbm_ = static_cast(nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM])) / 100; @@ -414,6 +464,9 @@ void waybar::modules::Network::parseSignal(struct nlattr **bss) { signal_strength_ = ((signal_strength_dbm_ - hardwareMin) / double{hardwareMax - hardwareMin}) * 100; } + if (bss[NL80211_BSS_SIGNAL_UNSPEC] != nullptr) { + signal_strength_ = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]); + } } bool waybar::modules::Network::associatedOrJoined(struct nlattr** bss) @@ -446,5 +499,5 @@ auto waybar::modules::Network::getInfo() -> void nlmsg_free(nl_msg); return; } - nl_send_sync(sk_, nl_msg); + nl_send_auto(sk_, nl_msg); } diff --git a/src/modules/sway/ipc/client.cpp b/src/modules/sway/ipc/client.cpp index 4abe51fd..8205af23 100644 --- a/src/modules/sway/ipc/client.cpp +++ b/src/modules/sway/ipc/client.cpp @@ -1,11 +1,18 @@ #include "modules/sway/ipc/client.hpp" waybar::modules::sway::Ipc::Ipc() - : fd_(-1), fd_event_(-1) -{} +{ + const std::string& socketPath = getSocketPath(); + fd_ = open(socketPath); + fd_event_ = open(socketPath); +} waybar::modules::sway::Ipc::~Ipc() { + // To fail the IPC header + write(fd_, "close-sway-ipc", 14); + write(fd_event_, "close-sway-ipc", 14); + close(fd_); close(fd_event_); } @@ -53,13 +60,6 @@ int waybar::modules::sway::Ipc::open(const std::string& socketPath) const return fd; } -void waybar::modules::sway::Ipc::connect() -{ - const std::string& socketPath = getSocketPath(); - fd_ = open(socketPath); - fd_event_ = open(socketPath); -} - struct waybar::modules::sway::Ipc::ipc_response waybar::modules::sway::Ipc::recv(int fd) const { @@ -71,18 +71,23 @@ struct waybar::modules::sway::Ipc::ipc_response while (total < ipc_header_size_) { auto res = ::recv(fd, header.data() + total, ipc_header_size_ - total, 0); if (res <= 0) { - throw std::runtime_error("Unable to receive IPC response"); + throw std::runtime_error("Unable to receive IPC header"); } total += res; } + auto magic = std::string(header.data(), header.data() + ipc_magic_.size()); + if (magic != ipc_magic_) { + throw std::runtime_error("Invalid IPC magic"); + } + total = 0; std::string payload; payload.reserve(data32[0] + 1); while (total < data32[0]) { auto res = ::recv(fd, payload.data() + total, data32[0] - total, 0); if (res < 0) { - throw std::runtime_error("Unable to receive IPC response"); + throw std::runtime_error("Unable to receive IPC payload"); } total += res; } diff --git a/src/modules/sway/mode.cpp b/src/modules/sway/mode.cpp index 2b25a925..83ab43bf 100644 --- a/src/modules/sway/mode.cpp +++ b/src/modules/sway/mode.cpp @@ -7,7 +7,6 @@ waybar::modules::sway::Mode::Mode(const std::string& id, const Bar& bar, const J if (!id.empty()) { label_.get_style_context()->add_class(id); } - ipc_.connect(); ipc_.subscribe("[ \"mode\" ]"); // Launch worker worker(); @@ -20,14 +19,12 @@ void waybar::modules::sway::Mode::worker() try { auto res = ipc_.handleEvent(); auto parsed = parser_.parse(res.payload); - if ((parsed["change"]) != "default" ) { + if (parsed["change"] != "default") { mode_ = parsed["change"].asString(); - dp.emit(); - } - else if ((parsed["change"]) == "default" ) { + } else { mode_.clear(); - dp.emit(); } + dp.emit(); } catch (const std::exception& e) { std::cerr << "Mode: " << e.what() << std::endl; } diff --git a/src/modules/sway/window.cpp b/src/modules/sway/window.cpp index 6f18f65c..b3baca19 100644 --- a/src/modules/sway/window.cpp +++ b/src/modules/sway/window.cpp @@ -11,7 +11,6 @@ waybar::modules::sway::Window::Window(const std::string& id, const Bar &bar, con label_.set_hexpand(true); label_.set_ellipsize(Pango::EllipsizeMode::ELLIPSIZE_END); } - ipc_.connect(); ipc_.subscribe("[\"window\",\"workspace\"]"); getFocusedWindow(); // Launch worker diff --git a/src/modules/sway/workspaces.cpp b/src/modules/sway/workspaces.cpp index 048c5d12..1fb38057 100644 --- a/src/modules/sway/workspaces.cpp +++ b/src/modules/sway/workspaces.cpp @@ -8,7 +8,6 @@ waybar::modules::sway::Workspaces::Workspaces(const std::string& id, const Bar& if (!id.empty()) { box_.get_style_context()->add_class(id); } - ipc_.connect(); ipc_.subscribe("[ \"workspace\" ]"); // Launch worker worker(); @@ -21,9 +20,9 @@ void waybar::modules::sway::Workspaces::worker() // Wait for the name of the output if (!config_["all-outputs"].asBool() && bar_.output_name.empty()) { while (bar_.output_name.empty()) { - thread_.sleep_for(chrono::milliseconds(150)); + thread_.sleep_for(std::chrono::milliseconds(150)); } - } else if (thread_.isRunning() && !workspaces_.empty()) { + } else if (!workspaces_.empty()) { ipc_.handleEvent(); } {