From ea9a08d473a1f05d17cbc91ea488df2ff51aa13c Mon Sep 17 00:00:00 2001 From: Alexis Date: Mon, 13 Aug 2018 21:23:43 +0200 Subject: [PATCH] refactor(workspaces): listen ipc event --- include/modules/workspaces.hpp | 10 ++- include/util/json.hpp | 34 ++++++++ src/bar.cpp | 11 +-- src/ipc/client.cpp | 137 ++++++++++++++++----------------- src/modules/workspaces.cpp | 70 +++++++++-------- 5 files changed, 146 insertions(+), 116 deletions(-) create mode 100644 include/util/json.hpp diff --git a/include/modules/workspaces.hpp b/include/modules/workspaces.hpp index 33e47994..ac3cc889 100644 --- a/include/modules/workspaces.hpp +++ b/include/modules/workspaces.hpp @@ -4,6 +4,7 @@ #include "bar.hpp" #include "client.hpp" #include "util/chrono.hpp" +#include "util/json.hpp" #include "IModule.hpp" namespace waybar::modules { @@ -15,13 +16,16 @@ namespace waybar::modules { operator Gtk::Widget &(); private: void _addWorkspace(Json::Value node); - Json::Value _getWorkspaces(); + Json::Value _getWorkspaces(const std::string data); Bar &_bar; waybar::util::SleeperThread _thread; Gtk::Box _box; + util::JsonParser _parser; + std::mutex _mutex; std::unordered_map _buttons; - int _ipcSocketfd; - int _ipcEventSocketfd; + Json::Value _workspaces; + int _ipcfd; + int _ipcEventfd; }; } diff --git a/include/util/json.hpp b/include/util/json.hpp new file mode 100644 index 00000000..53b93458 --- /dev/null +++ b/include/util/json.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include + +namespace waybar::util { + + struct JsonParser { + + JsonParser() + : _reader(_builder.newCharReader()) + {} + + Json::Value parse(const std::string data) + { + Json::Value root; + std::string err; + bool res = + _reader->parse(data.c_str(), data.c_str() + data.size(), &root, &err); + if (!res) + throw std::runtime_error(err); + return root; + } + + ~JsonParser() + { + delete _reader; + } + + private: + Json::CharReaderBuilder _builder; + Json::CharReader *_reader; + }; + +} diff --git a/src/bar.cpp b/src/bar.cpp index 115dca44..be8d386b 100644 --- a/src/bar.cpp +++ b/src/bar.cpp @@ -1,6 +1,7 @@ #include "bar.hpp" #include "client.hpp" #include "factory.hpp" +#include "util/json.hpp" waybar::Bar::Bar(Client &client, std::unique_ptr &&p_output) : client(client), window{Gtk::WindowType::WINDOW_TOPLEVEL}, @@ -125,19 +126,13 @@ auto waybar::Bar::toggle() -> void auto waybar::Bar::_setupConfig() -> void { - Json::Value root; - Json::CharReaderBuilder builder; - Json::CharReader* reader = builder.newCharReader(); - std::string err; + util::JsonParser parser; std::ifstream file(client.configFile); if (!file.is_open()) throw std::runtime_error("Can't open config file"); std::string str((std::istreambuf_iterator(file)), std::istreambuf_iterator()); - bool res = reader->parse(str.c_str(), str.c_str() + str.size(), &_config, &err); - delete reader; - if (!res) - throw std::runtime_error(err); + _config = parser.parse(str); } auto waybar::Bar::_setupCss() -> void diff --git a/src/ipc/client.cpp b/src/ipc/client.cpp index 42db3d2c..ab4a2761 100644 --- a/src/ipc/client.cpp +++ b/src/ipc/client.cpp @@ -11,90 +11,85 @@ static const size_t ipc_header_size = sizeof(ipc_magic)+8; std::string get_socketpath(void) { const char *env = getenv("SWAYSOCK"); if (env) return std::string(env); - std::string str; + std::string str; { - std::string str_buf; - FILE* in; - char buf[512] = { 0 }; - if (!(in = popen("sway --get-socketpath 2>/dev/null", "r"))) { - throw std::runtime_error("Failed to get socket path"); - } - while (fgets(buf, sizeof(buf), in) != nullptr) { - str_buf.append(buf, sizeof(buf)); - } - pclose(in); - str = str_buf; - } - if (str.back() == '\n') { - str.pop_back(); - } - return str; + std::string str_buf; + FILE* in; + char buf[512] = { 0 }; + if (!(in = popen("sway --get-socketpath 2>/dev/null", "r"))) { + throw std::runtime_error("Failed to get socket path"); + } + while (fgets(buf, sizeof(buf), in) != nullptr) { + str_buf.append(buf, sizeof(buf)); + } + pclose(in); + str = str_buf; + } + if (str.back() == '\n') { + str.pop_back(); + } + return str; } int ipc_open_socket(std::string socket_path) { - struct sockaddr_un addr; - int socketfd; - if ((socketfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { - throw std::runtime_error("Unable to open Unix socket"); - } - addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, socket_path.c_str(), sizeof(addr.sun_path) - 1); - addr.sun_path[sizeof(addr.sun_path) - 1] = 0; - int l = sizeof(struct sockaddr_un); - if (connect(socketfd, (struct sockaddr *)&addr, l) == -1) { - throw std::runtime_error("Unable to connect to " + socket_path); - } - return socketfd; + struct sockaddr_un addr; + int socketfd; + if ((socketfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + throw std::runtime_error("Unable to open Unix socket"); + } + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, socket_path.c_str(), sizeof(addr.sun_path) - 1); + addr.sun_path[sizeof(addr.sun_path) - 1] = 0; + int l = sizeof(struct sockaddr_un); + if (connect(socketfd, (struct sockaddr *)&addr, l) == -1) { + throw std::runtime_error("Unable to connect to " + socket_path); + } + return socketfd; } struct ipc_response ipc_recv_response(int socketfd) { - char data[ipc_header_size]; - uint32_t *data32 = (uint32_t *)(data + sizeof(ipc_magic)); + struct ipc_response response; + char data[ipc_header_size]; + uint32_t *data32 = (uint32_t *)(data + sizeof(ipc_magic)); + size_t total = 0; - size_t total = 0; - while (total < ipc_header_size) { - ssize_t received = recv(socketfd, data + total, ipc_header_size - total, 0); - if (received <= 0) { - throw std::runtime_error("Unable to receive IPC response"); - } - total += received; - } + while (total < ipc_header_size) { + ssize_t received = recv(socketfd, data + total, ipc_header_size - total, 0); + if (received <= 0) { + throw std::runtime_error("Unable to receive IPC response"); + } + total += received; + } - struct ipc_response response; - - total = 0; - response.size = data32[0]; - response.type = data32[1]; + total = 0; + response.size = data32[0]; + response.type = data32[1]; char payload[response.size + 1]; - while (total < response.size) { - ssize_t received = recv(socketfd, payload + total, response.size - total, 0); - if (received < 0) { - throw std::runtime_error("Unable to receive IPC response"); - } - total += received; - } - payload[response.size] = '\0'; - response.payload = std::string(payload); - return response; + while (total < response.size) { + ssize_t received = recv(socketfd, payload + total, response.size - total, 0); + if (received < 0) { + throw std::runtime_error("Unable to receive IPC response"); + } + total += received; + } + payload[response.size] = '\0'; + response.payload = std::string(payload); + return response; } std::string ipc_single_command(int socketfd, uint32_t type, const char *payload, uint32_t *len) { - char data[ipc_header_size]; - uint32_t *data32 = (uint32_t *)(data + sizeof(ipc_magic)); - memcpy(data, ipc_magic, sizeof(ipc_magic)); - data32[0] = *len; - data32[1] = type; + char data[ipc_header_size]; + uint32_t *data32 = (uint32_t *)(data + sizeof(ipc_magic)); + memcpy(data, ipc_magic, sizeof(ipc_magic)); + data32[0] = *len; + data32[1] = type; - if (send(socketfd, data, ipc_header_size, 0) == -1) { - throw std::runtime_error("Unable to send IPC header"); - } - - if (send(socketfd, payload, *len, 0) == -1) { - throw std::runtime_error("Unable to send IPC payload"); - } - - struct ipc_response resp = ipc_recv_response(socketfd); - *len = resp.size; - return resp.payload; + if (send(socketfd, data, ipc_header_size, 0) == -1) + throw std::runtime_error("Unable to send IPC header"); + if (send(socketfd, payload, *len, 0) == -1) + throw std::runtime_error("Unable to send IPC payload"); + struct ipc_response resp = ipc_recv_response(socketfd); + *len = resp.size; + return resp.payload; } diff --git a/src/modules/workspaces.cpp b/src/modules/workspaces.cpp index 634847da..115cf4f6 100644 --- a/src/modules/workspaces.cpp +++ b/src/modules/workspaces.cpp @@ -6,47 +6,60 @@ waybar::modules::Workspaces::Workspaces(Bar &bar) { _box.get_style_context()->add_class("workspaces"); std::string socketPath = get_socketpath(); - _ipcSocketfd = ipc_open_socket(socketPath); - _ipcEventSocketfd = ipc_open_socket(socketPath); - const char *subscribe = "[ \"workspace\", \"mode\" ]"; + _ipcfd = ipc_open_socket(socketPath); + _ipcEventfd = ipc_open_socket(socketPath); + const char *subscribe = "[ \"workspace\" ]"; uint32_t len = strlen(subscribe); - ipc_single_command(_ipcEventSocketfd, IPC_SUBSCRIBE, subscribe, &len); + ipc_single_command(_ipcEventfd, IPC_SUBSCRIBE, subscribe, &len); _thread = [this] { - Glib::signal_idle().connect_once(sigc::mem_fun(*this, &Workspaces::update)); - _thread.sleep_for(chrono::milliseconds(250)); + try { + if (_bar.outputName.empty()) { + // Wait for the name of the output + while (_bar.outputName.empty()) + _thread.sleep_for(chrono::milliseconds(150)); + } else + ipc_recv_response(_ipcEventfd); + uint32_t len = 0; + auto str = ipc_single_command(_ipcfd, IPC_GET_WORKSPACES, nullptr, &len); + std::lock_guard lock(_mutex); + _workspaces = _getWorkspaces(str); + Glib::signal_idle().connect_once(sigc::mem_fun(*this, &Workspaces::update)); + } catch (const std::exception& e) { + std::cerr << e.what() << std::endl; + } }; } - auto waybar::modules::Workspaces::update() -> void { - if (_bar.outputName.empty()) return; - Json::Value workspaces = _getWorkspaces(); + std::lock_guard lock(_mutex); bool needReorder = false; for (auto it = _buttons.begin(); it != _buttons.end(); ++it) { - auto ws = std::find_if(workspaces.begin(), workspaces.end(), + auto ws = std::find_if(_workspaces.begin(), _workspaces.end(), [it](auto node) -> bool { return node["num"].asInt() == it->first; }); - if (ws == workspaces.end()) { + if (ws == _workspaces.end()) { it = _buttons.erase(it); needReorder = true; } } - for (auto node : workspaces) { + for (auto node : _workspaces) { + if (_bar.outputName != node["output"].asString()) + continue; auto it = _buttons.find(node["num"].asInt()); - if (it == _buttons.end() && _bar.outputName == node["output"].asString()) { + if (it == _buttons.end()) { _addWorkspace(node); needReorder = true; } else { - auto styleContext = it->second.get_style_context(); + auto &button = it->second; bool isCurrent = node["focused"].asBool(); if (!isCurrent) { - styleContext->remove_class("current"); + button.get_style_context()->remove_class("current"); } else if (isCurrent) { - styleContext->add_class("current"); + button.get_style_context()->add_class("current"); } if (needReorder) - _box.reorder_child(it->second, node["num"].asInt() - 1); - it->second.show(); + _box.reorder_child(button, node["num"].asInt() - 1); + button.show(); } } } @@ -61,7 +74,7 @@ void waybar::modules::Workspaces::_addWorkspace(Json::Value node) try { auto value = fmt::format("workspace \"{}\"", pair.first->first); uint32_t size = value.size(); - ipc_single_command(_ipcSocketfd, IPC_COMMAND, value.c_str(), &size); + ipc_single_command(_ipcfd, IPC_COMMAND, value.c_str(), &size); } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } @@ -73,27 +86,16 @@ void waybar::modules::Workspaces::_addWorkspace(Json::Value node) button.show(); } -Json::Value waybar::modules::Workspaces::_getWorkspaces() +Json::Value waybar::modules::Workspaces::_getWorkspaces(const std::string data) { - uint32_t len = 0; - Json::Value root; - Json::CharReaderBuilder builder; - Json::CharReader* reader = builder.newCharReader(); + Json::Value res; try { - std::string str = ipc_single_command(_ipcSocketfd, IPC_GET_WORKSPACES, - nullptr, &len); std::string err; - bool res = - reader->parse(str.c_str(), str.c_str() + str.size(), &root, &err); - delete reader; - if (!res) { - std::cerr << err << std::endl; - return root; - } + res = _parser.parse(data); } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } - return root; + return res; } waybar::modules::Workspaces::operator Gtk::Widget &() {