From cccf60c30ec093362bc2c825dc8ccb9316d6bb32 Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 23 Apr 2019 11:41:49 +0200 Subject: [PATCH] fix(Workspaces): fix concurrence and move json parser to ipc client --- include/modules/sway/ipc/client.hpp | 13 ++-- include/modules/sway/mode.hpp | 2 - include/modules/sway/window.hpp | 2 - include/modules/sway/workspaces.hpp | 3 +- include/util/json.hpp | 9 +-- src/modules/mpd.cpp | 3 +- src/modules/sway/ipc/client.cpp | 8 ++- src/modules/sway/mode.cpp | 5 +- src/modules/sway/window.cpp | 22 ++++--- src/modules/sway/workspaces.cpp | 92 +++++++++++++++-------------- 10 files changed, 82 insertions(+), 77 deletions(-) diff --git a/include/modules/sway/ipc/client.hpp b/include/modules/sway/ipc/client.hpp index 1d149cb..48ec18d 100644 --- a/include/modules/sway/ipc/client.hpp +++ b/include/modules/sway/ipc/client.hpp @@ -6,8 +6,10 @@ #include #include #include +#include #include #include "ipc.hpp" +#include "util/json.hpp" namespace waybar::modules::sway { @@ -19,7 +21,7 @@ class Ipc { struct ipc_response { uint32_t size; uint32_t type; - std::string payload; + Json::Value payload; }; sigc::signal signal_event; @@ -38,10 +40,11 @@ class Ipc { struct ipc_response send(int fd, uint32_t type, const std::string &payload = ""); struct ipc_response recv(int fd); - int fd_; - int fd_event_; - std::mutex mutex_; - std::mutex mutex_event_; + int fd_; + int fd_event_; + std::mutex mutex_; + std::mutex mutex_event_; + util::JsonParser parser_; }; } // namespace waybar::modules::sway diff --git a/include/modules/sway/mode.hpp b/include/modules/sway/mode.hpp index 89c9a8b..9f3b0e0 100644 --- a/include/modules/sway/mode.hpp +++ b/include/modules/sway/mode.hpp @@ -5,7 +5,6 @@ #include "bar.hpp" #include "client.hpp" #include "modules/sway/ipc/client.hpp" -#include "util/json.hpp" #include "util/sleeper_thread.hpp" namespace waybar::modules::sway { @@ -22,7 +21,6 @@ class Mode : public ALabel { const Bar& bar_; waybar::util::SleeperThread thread_; - util::JsonParser parser_; Ipc ipc_; std::string mode_; }; diff --git a/include/modules/sway/window.hpp b/include/modules/sway/window.hpp index aaeb2d3..d43ed25 100644 --- a/include/modules/sway/window.hpp +++ b/include/modules/sway/window.hpp @@ -6,7 +6,6 @@ #include "bar.hpp" #include "client.hpp" #include "modules/sway/ipc/client.hpp" -#include "util/json.hpp" #include "util/sleeper_thread.hpp" namespace waybar::modules::sway { @@ -26,7 +25,6 @@ class Window : public ALabel { const Bar& bar_; waybar::util::SleeperThread thread_; - util::JsonParser parser_; Ipc ipc_; std::string window_; int windowId_; diff --git a/include/modules/sway/workspaces.hpp b/include/modules/sway/workspaces.hpp index 187e5cb..c7b6c92 100644 --- a/include/modules/sway/workspaces.hpp +++ b/include/modules/sway/workspaces.hpp @@ -7,7 +7,6 @@ #include "bar.hpp" #include "client.hpp" #include "modules/sway/ipc/client.hpp" -#include "util/json.hpp" #include "util/sleeper_thread.hpp" namespace waybar::modules::sway { @@ -36,8 +35,8 @@ class Workspaces : public IModule { const Json::Value& config_; std::vector workspaces_; waybar::util::SleeperThread thread_; + std::mutex mutex_; Gtk::Box box_; - util::JsonParser parser_; Ipc ipc_; bool scrolling_; std::unordered_map buttons_; diff --git a/include/util/json.hpp b/include/util/json.hpp index cc0d86c..4ce3ca5 100644 --- a/include/util/json.hpp +++ b/include/util/json.hpp @@ -7,13 +7,14 @@ namespace waybar::util { struct JsonParser { JsonParser() : reader_(builder_.newCharReader()) {} - const Json::Value parse(const std::string& data) const { - Json::Value root; - std::string err; + const Json::Value parse(const std::string& data, std::size_t size = 0) const { + Json::Value root(Json::objectValue); if (data.empty()) { return root; } - bool res = reader_->parse(data.c_str(), data.c_str() + data.size(), &root, &err); + std::string err; + auto data_size = size > 0 ? size : data.size(); + bool res = reader_->parse(data.c_str(), data.c_str() + data_size, &root, &err); if (!res) throw std::runtime_error(err); return root; } diff --git a/src/modules/mpd.cpp b/src/modules/mpd.cpp index 9951a61..c019d36 100644 --- a/src/modules/mpd.cpp +++ b/src/modules/mpd.cpp @@ -259,13 +259,12 @@ void waybar::modules::MPD::tryConnect() { try { checkErrors(connection_.get()); + std::cerr << module_name_ << ": Connected to MPD" << std::endl; } catch (std::runtime_error& e) { std::cerr << module_name_ << ": Failed to connect to MPD: " << e.what() << std::endl; connection_.reset(); alternate_connection_.reset(); } - - std::cerr << module_name_ << ": Connected to MPD" << std::endl; } void waybar::modules::MPD::checkErrors(mpd_connection* conn) { diff --git a/src/modules/sway/ipc/client.cpp b/src/modules/sway/ipc/client.cpp index eafca41..de110b3 100644 --- a/src/modules/sway/ipc/client.cpp +++ b/src/modules/sway/ipc/client.cpp @@ -97,11 +97,15 @@ struct Ipc::ipc_response Ipc::recv(int fd) { while (total < data32[0]) { auto res = ::recv(fd, payload.data() + total, data32[0] - total, 0); if (res < 0) { + if (errno == EINTR || errno == EAGAIN) { + continue; + } throw std::runtime_error("Unable to receive IPC payload"); } total += res; } - return {data32[0], data32[1], &payload.front()}; + auto parsed = parser_.parse(&payload.front(), data32[0]); + return {data32[0], data32[1], parsed}; } struct Ipc::ipc_response Ipc::send(int fd, uint32_t type, const std::string& payload) { @@ -130,7 +134,7 @@ void Ipc::sendCmd(uint32_t type, const std::string& payload) { void Ipc::subscribe(const std::string& payload) { std::lock_guard lock(mutex_event_); auto res = Ipc::send(fd_event_, IPC_SUBSCRIBE, payload); - if (res.payload != "{\"success\": true}") { + if (!res.payload["success"].asBool()) { throw std::runtime_error("Unable to subscribe ipc event"); } } diff --git a/src/modules/sway/mode.cpp b/src/modules/sway/mode.cpp index f43f929..fabc2f9 100644 --- a/src/modules/sway/mode.cpp +++ b/src/modules/sway/mode.cpp @@ -16,9 +16,8 @@ Mode::Mode(const std::string& id, const Bar& bar, const Json::Value& config) } void Mode::onEvent(const struct Ipc::ipc_response res) { - auto parsed = parser_.parse(res.payload); - if (parsed["change"] != "default") { - mode_ = parsed["change"].asString(); + if (res.payload["change"] != "default") { + mode_ = res.payload["change"].asString(); } else { mode_.clear(); } diff --git a/src/modules/sway/window.cpp b/src/modules/sway/window.cpp index 7173fec..192e6ff 100644 --- a/src/modules/sway/window.cpp +++ b/src/modules/sway/window.cpp @@ -21,18 +21,17 @@ Window::Window(const std::string& id, const Bar& bar, const Json::Value& config) } void Window::onEvent(const struct Ipc::ipc_response res) { - auto parsed = parser_.parse(res.payload); + auto data = res.payload; // Check for waybar prevents flicker when hovering window module - if ((parsed["change"] == "focus" || parsed["change"] == "title") && - parsed["container"]["focused"].asBool() && - parsed["container"]["name"].asString() != "waybar") { - window_ = Glib::Markup::escape_text(parsed["container"]["name"].asString()); - windowId_ = parsed["container"]["id"].asInt(); + if ((data["change"] == "focus" || data["change"] == "title") && + data["container"]["focused"].asBool() && data["container"]["name"].asString() != "waybar") { + window_ = Glib::Markup::escape_text(data["container"]["name"].asString()); + windowId_ = data["container"]["id"].asInt(); dp.emit(); - } else if ((parsed["change"] == "close" && parsed["container"]["focused"].asBool() && - windowId_ == parsed["container"]["id"].asInt()) || - (parsed["change"] == "focus" && parsed["current"]["focus"].isArray() && - parsed["current"]["focus"].empty())) { + } else if ((data["change"] == "close" && data["container"]["focused"].asBool() && + windowId_ == data["container"]["id"].asInt()) || + (data["change"] == "focus" && data["current"]["focus"].isArray() && + data["current"]["focus"].empty())) { window_.clear(); windowId_ = -1; dp.emit(); @@ -40,8 +39,7 @@ void Window::onEvent(const struct Ipc::ipc_response res) { } void Window::onCmd(const struct Ipc::ipc_response res) { - auto parsed = parser_.parse(res.payload); - auto [id, name] = getFocusedNode(parsed["nodes"]); + auto [id, name] = getFocusedNode(res.payload["nodes"]); windowId_ = id; window_ = name; dp.emit(); diff --git a/src/modules/sway/workspaces.cpp b/src/modules/sway/workspaces.cpp index b3ebeef..401bb1a 100644 --- a/src/modules/sway/workspaces.cpp +++ b/src/modules/sway/workspaces.cpp @@ -23,17 +23,19 @@ void Workspaces::onEvent(const struct Ipc::ipc_response res) { ipc_.sendCmd(IPC_ void Workspaces::onCmd(const struct Ipc::ipc_response res) { if (res.type == IPC_GET_WORKSPACES) { - auto workspaces = parser_.parse(res.payload); - workspaces_.clear(); - std::copy_if(workspaces.begin(), - workspaces.end(), - std::back_inserter(workspaces_), - [&](const auto &workspace) { - return !config_["all-outputs"].asBool() - ? workspace["output"].asString() == bar_.output->name - : true; - }); - dp.emit(); + if (res.payload.isArray()) { + std::lock_guard lock(mutex_); + workspaces_.clear(); + std::copy_if(res.payload.begin(), + res.payload.end(), + std::back_inserter(workspaces_), + [&](const auto &workspace) { + return !config_["all-outputs"].asBool() + ? workspace["output"].asString() == bar_.output->name + : true; + }); + dp.emit(); + } } else { if (scrolling_) { scrolling_ = false; @@ -69,7 +71,8 @@ bool Workspaces::filterButtons() { } auto Workspaces::update() -> void { - bool needReorder = filterButtons(); + std::lock_guard lock(mutex_); + bool needReorder = filterButtons(); for (auto it = workspaces_.begin(); it != workspaces_.end(); ++it) { auto bit = buttons_.find((*it)["name"].asString()); if (bit == buttons_.end()) { @@ -149,39 +152,42 @@ bool Workspaces::handleScroll(GdkEventScroll *e) { if (scrolling_) { return false; } - scrolling_ = true; std::string name; - auto it = std::find_if(workspaces_.begin(), workspaces_.end(), [](const auto &workspace) { - return workspace["focused"].asBool(); - }); - if (it == workspaces_.end()) { - scrolling_ = false; - return false; - } - switch (e->direction) { - case GDK_SCROLL_DOWN: - case GDK_SCROLL_RIGHT: - name = getCycleWorkspace(it, false); - break; - case GDK_SCROLL_UP: - case GDK_SCROLL_LEFT: - name = getCycleWorkspace(it, true); - break; - case GDK_SCROLL_SMOOTH: - gdouble delta_x, delta_y; - gdk_event_get_scroll_deltas(reinterpret_cast(e), &delta_x, &delta_y); - if (delta_y < 0) { - name = getCycleWorkspace(it, true); - } else if (delta_y > 0) { + scrolling_ = true; + { + std::lock_guard lock(mutex_); + auto it = std::find_if(workspaces_.begin(), workspaces_.end(), [](const auto &workspace) { + return workspace["focused"].asBool(); + }); + if (it == workspaces_.end()) { + scrolling_ = false; + return false; + } + switch (e->direction) { + case GDK_SCROLL_DOWN: + case GDK_SCROLL_RIGHT: name = getCycleWorkspace(it, false); - } - break; - default: - break; - } - if (name.empty() || name == (*it)["name"].asString()) { - scrolling_ = false; - return false; + break; + case GDK_SCROLL_UP: + case GDK_SCROLL_LEFT: + name = getCycleWorkspace(it, true); + break; + case GDK_SCROLL_SMOOTH: + gdouble delta_x, delta_y; + gdk_event_get_scroll_deltas(reinterpret_cast(e), &delta_x, &delta_y); + if (delta_y < 0) { + name = getCycleWorkspace(it, true); + } else if (delta_y > 0) { + name = getCycleWorkspace(it, false); + } + break; + default: + break; + } + if (name.empty() || name == (*it)["name"].asString()) { + scrolling_ = false; + return false; + } } ipc_.sendCmd(IPC_COMMAND, fmt::format("workspace \"{}\"", name)); return true;