From e3700b924ef86151da9dd38a229e55a2e7e8a079 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20W=C3=B6lfel?= Date: Wed, 6 Apr 2022 15:53:49 +0200 Subject: [PATCH 1/5] Show bar if a workspace becomes urgent Add a second reason to show the bar besides visible by modifier. Update the visibility based on changes in the workspace urgency. Check all workspaces for urgency and keep the bar visible if at least one has an urgency hint. --- include/modules/sway/bar.hpp | 4 ++ src/modules/sway/bar.cpp | 79 +++++++++++++++++++++++++++++------- 2 files changed, 69 insertions(+), 14 deletions(-) diff --git a/include/modules/sway/bar.hpp b/include/modules/sway/bar.hpp index e54fc09..84f74d6 100644 --- a/include/modules/sway/bar.hpp +++ b/include/modules/sway/bar.hpp @@ -30,8 +30,10 @@ class BarIpcClient { private: void onInitialConfig(const struct Ipc::ipc_response& res); void onIpcEvent(const struct Ipc::ipc_response&); + void onCmd(const struct Ipc::ipc_response&); void onConfigUpdate(const swaybar_config& config); void onVisibilityUpdate(bool visible_by_modifier); + void onUrgencyUpdate(bool visible_by_urgency); void update(); Bar& bar_; @@ -40,8 +42,10 @@ class BarIpcClient { swaybar_config bar_config_; bool visible_by_modifier_ = false; + bool visible_by_urgency_ = false; SafeSignal signal_visible_; + SafeSignal signal_urgency_; SafeSignal signal_config_; }; diff --git a/src/modules/sway/bar.cpp b/src/modules/sway/bar.cpp index 7a235ae..0e20797 100644 --- a/src/modules/sway/bar.cpp +++ b/src/modules/sway/bar.cpp @@ -21,9 +21,11 @@ BarIpcClient::BarIpcClient(waybar::Bar& bar) : bar_{bar} { signal_config_.connect(sigc::mem_fun(*this, &BarIpcClient::onConfigUpdate)); signal_visible_.connect(sigc::mem_fun(*this, &BarIpcClient::onVisibilityUpdate)); + signal_urgency_.connect(sigc::mem_fun(*this, &BarIpcClient::onUrgencyUpdate)); - ipc_.subscribe(R"(["bar_state_update", "barconfig_update"])"); + ipc_.subscribe(R"(["bar_state_update", "barconfig_update", "workspace"])"); ipc_.signal_event.connect(sigc::mem_fun(*this, &BarIpcClient::onIpcEvent)); + ipc_.signal_cmd.connect(sigc::mem_fun(*this, &BarIpcClient::onCmd)); // Launch worker ipc_.setWorker([this] { try { @@ -61,23 +63,66 @@ void BarIpcClient::onInitialConfig(const struct Ipc::ipc_response& res) { void BarIpcClient::onIpcEvent(const struct Ipc::ipc_response& res) { try { auto payload = parser_.parse(res.payload); - if (auto id = payload["id"]; id.isString() && id.asString() != bar_.bar_id) { - spdlog::trace("swaybar ipc: ignore event for {}", id.asString()); - return; - } - if (payload.isMember("visible_by_modifier")) { - // visibility change for hidden bar - signal_visible_(payload["visible_by_modifier"].asBool()); - } else { - // configuration update - auto config = parseConfig(payload); - signal_config_(std::move(config)); + switch (res.type) { + case IPC_EVENT_WORKSPACE: + if (payload.isMember("change")) { + // only check and send signal if the workspace update reason was because of a urgent + // change + if (payload["change"] == "urgent") { + auto urgent = payload["current"]["urgent"]; + if (urgent.asBool()) { + // Event for a new urgency, update the visibly + signal_urgency_(true); + } else if (!urgent.asBool() && visible_by_urgency_) { + // Event clearing an urgency, bar is visible, check if another workspace still has + // the urgency hint set + ipc_.sendCmd(IPC_GET_WORKSPACES); + } + } + } + break; + case IPC_EVENT_BAR_STATE_UPDATE: + case IPC_EVENT_BARCONFIG_UPDATE: + if (auto id = payload["id"]; id.isString() && id.asString() != bar_.bar_id) { + spdlog::trace("swaybar ipc: ignore event for {}", id.asString()); + return; + } + if (payload.isMember("visible_by_modifier")) { + // visibility change for hidden bar + signal_visible_(payload["visible_by_modifier"].asBool()); + } else { + // configuration update + auto config = parseConfig(payload); + signal_config_(std::move(config)); + } + break; } } catch (const std::exception& e) { spdlog::error("BarIpcClient::onEvent {}", e.what()); } } +void BarIpcClient::onCmd(const struct Ipc::ipc_response& res) { + if (res.type == IPC_GET_WORKSPACES) { + try { + auto payload = parser_.parse(res.payload); + for (auto& ws : payload) { + if (ws["urgent"].asBool()) { + spdlog::debug("Found workspace {} with urgency set. Stopping search.", ws["name"]); + // Found one workspace with urgency set, signal bar visibility + signal_urgency_(true); + return; + } + } + // Command to get workspaces was sent after a change in workspaces was based on "urgent", + // if no workspace has this flag set to true, all flags must be cleared. + signal_urgency_(false); + } catch (const std::exception& e) { + spdlog::error("Bar: {}", e.what()); + } + } +} + void BarIpcClient::onConfigUpdate(const swaybar_config& config) { spdlog::info("config update for {}: id {}, mode {}, hidden_state {}", bar_.bar_id, config.id, config.mode, config.hidden_state); @@ -86,13 +131,19 @@ void BarIpcClient::onConfigUpdate(const swaybar_config& config) { } void BarIpcClient::onVisibilityUpdate(bool visible_by_modifier) { - spdlog::debug("visiblity update for {}: {}", bar_.bar_id, visible_by_modifier); + spdlog::debug("visibility update for {}: {}", bar_.bar_id, visible_by_modifier); visible_by_modifier_ = visible_by_modifier; update(); } +void BarIpcClient::onUrgencyUpdate(bool visible_by_urgency) { + spdlog::debug("urgency update for {}: {}", bar_.bar_id, visible_by_urgency); + visible_by_urgency_ = visible_by_urgency; + update(); +} + void BarIpcClient::update() { - bool visible = visible_by_modifier_; + bool visible = visible_by_modifier_ || visible_by_urgency_; if (bar_config_.mode == "invisible") { visible = false; } else if (bar_config_.mode != "hide" || bar_config_.hidden_state != "hide") { From 93f9b3d213578e92fbb3f409eff4f97d65d6f6e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20W=C3=B6lfel?= Date: Sat, 9 Apr 2022 13:18:03 +0200 Subject: [PATCH 2/5] Clear urgency hint with modifier press If the modifier is pressed and release without another event, the intended behaviour is to clear an urgency hint and hide the bar again. Note that if multiple workspaces have the urgency hint set, the bar is hidden again and an urgent workspace is focused, the bar does not stay hidden anymore. --- include/modules/sway/bar.hpp | 2 ++ src/modules/sway/bar.cpp | 19 ++++++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/include/modules/sway/bar.hpp b/include/modules/sway/bar.hpp index 84f74d6..7642c32 100644 --- a/include/modules/sway/bar.hpp +++ b/include/modules/sway/bar.hpp @@ -1,4 +1,5 @@ #pragma once +#include #include #include "modules/sway/ipc/client.hpp" @@ -43,6 +44,7 @@ class BarIpcClient { swaybar_config bar_config_; bool visible_by_modifier_ = false; bool visible_by_urgency_ = false; + std::atomic modifier_no_action_ = false; SafeSignal signal_visible_; SafeSignal signal_urgency_; diff --git a/src/modules/sway/bar.cpp b/src/modules/sway/bar.cpp index 0e20797..5b50100 100644 --- a/src/modules/sway/bar.cpp +++ b/src/modules/sway/bar.cpp @@ -23,7 +23,9 @@ BarIpcClient::BarIpcClient(waybar::Bar& bar) : bar_{bar} { signal_visible_.connect(sigc::mem_fun(*this, &BarIpcClient::onVisibilityUpdate)); signal_urgency_.connect(sigc::mem_fun(*this, &BarIpcClient::onUrgencyUpdate)); - ipc_.subscribe(R"(["bar_state_update", "barconfig_update", "workspace"])"); + // Subscribe to non bar events to determine if the modifier key press is followed by another + // action. + ipc_.subscribe(R"(["bar_state_update", "barconfig_update", "workspace", "mode", "binding"])"); ipc_.signal_event.connect(sigc::mem_fun(*this, &BarIpcClient::onIpcEvent)); ipc_.signal_cmd.connect(sigc::mem_fun(*this, &BarIpcClient::onCmd)); // Launch worker @@ -79,8 +81,13 @@ void BarIpcClient::onIpcEvent(const struct Ipc::ipc_response& res) { ipc_.sendCmd(IPC_GET_WORKSPACES); } } + modifier_no_action_ = false; } break; + case IPC_EVENT_MODE: + case IPC_EVENT_BINDING: + modifier_no_action_ = false; + break; case IPC_EVENT_BAR_STATE_UPDATE: case IPC_EVENT_BARCONFIG_UPDATE: if (auto id = payload["id"]; id.isString() && id.asString() != bar_.bar_id) { @@ -133,6 +140,16 @@ void BarIpcClient::onConfigUpdate(const swaybar_config& config) { void BarIpcClient::onVisibilityUpdate(bool visible_by_modifier) { spdlog::debug("visibility update for {}: {}", bar_.bar_id, visible_by_modifier); visible_by_modifier_ = visible_by_modifier; + if (visible_by_modifier) { + modifier_no_action_ = true; + } + if (!visible_by_modifier_ && modifier_no_action_) { + // Modifier key was pressed and released without a different action. + // This signals an acknowledgment and should hide the bar again. + // Hide the bar and clear the urgency flag. + visible_by_urgency_ = false; + } + update(); } From 1dcd36b06c619ee5c93c0dc33ba0dc0be07f0be0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20W=C3=B6lfel?= Date: Sat, 9 Apr 2022 13:49:22 +0200 Subject: [PATCH 3/5] Show bar on sway mode Display the bar if the sway mode is not the default mode. --- include/modules/sway/bar.hpp | 3 +++ src/modules/sway/bar.cpp | 15 ++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/include/modules/sway/bar.hpp b/include/modules/sway/bar.hpp index 7642c32..821bff1 100644 --- a/include/modules/sway/bar.hpp +++ b/include/modules/sway/bar.hpp @@ -34,6 +34,7 @@ class BarIpcClient { void onCmd(const struct Ipc::ipc_response&); void onConfigUpdate(const swaybar_config& config); void onVisibilityUpdate(bool visible_by_modifier); + void onModeUpdate(bool visible_by_modifier); void onUrgencyUpdate(bool visible_by_urgency); void update(); @@ -42,10 +43,12 @@ class BarIpcClient { Ipc ipc_; swaybar_config bar_config_; + bool visible_by_mode_ = false; bool visible_by_modifier_ = false; bool visible_by_urgency_ = false; std::atomic modifier_no_action_ = false; + SafeSignal signal_mode_; SafeSignal signal_visible_; SafeSignal signal_urgency_; SafeSignal signal_config_; diff --git a/src/modules/sway/bar.cpp b/src/modules/sway/bar.cpp index 5b50100..82e14be 100644 --- a/src/modules/sway/bar.cpp +++ b/src/modules/sway/bar.cpp @@ -22,6 +22,7 @@ BarIpcClient::BarIpcClient(waybar::Bar& bar) : bar_{bar} { signal_config_.connect(sigc::mem_fun(*this, &BarIpcClient::onConfigUpdate)); signal_visible_.connect(sigc::mem_fun(*this, &BarIpcClient::onVisibilityUpdate)); signal_urgency_.connect(sigc::mem_fun(*this, &BarIpcClient::onUrgencyUpdate)); + signal_mode_.connect(sigc::mem_fun(*this, &BarIpcClient::onModeUpdate)); // Subscribe to non bar events to determine if the modifier key press is followed by another // action. @@ -85,6 +86,11 @@ void BarIpcClient::onIpcEvent(const struct Ipc::ipc_response& res) { } break; case IPC_EVENT_MODE: + if (payload.isMember("change")) { + signal_mode_(payload["change"] != "default"); + modifier_no_action_ = false; + } + break; case IPC_EVENT_BINDING: modifier_no_action_ = false; break; @@ -137,6 +143,12 @@ void BarIpcClient::onConfigUpdate(const swaybar_config& config) { update(); } +void BarIpcClient::onModeUpdate(bool visible_by_mode) { + spdlog::debug("mode update for {}: {}", bar_.bar_id, visible_by_mode); + visible_by_mode_ = visible_by_mode; + update(); +} + void BarIpcClient::onVisibilityUpdate(bool visible_by_modifier) { spdlog::debug("visibility update for {}: {}", bar_.bar_id, visible_by_modifier); visible_by_modifier_ = visible_by_modifier; @@ -148,6 +160,7 @@ void BarIpcClient::onVisibilityUpdate(bool visible_by_modifier) { // This signals an acknowledgment and should hide the bar again. // Hide the bar and clear the urgency flag. visible_by_urgency_ = false; + visible_by_mode_ = false; } update(); @@ -160,7 +173,7 @@ void BarIpcClient::onUrgencyUpdate(bool visible_by_urgency) { } void BarIpcClient::update() { - bool visible = visible_by_modifier_ || visible_by_urgency_; + bool visible = visible_by_modifier_ || visible_by_mode_ || visible_by_urgency_; if (bar_config_.mode == "invisible") { visible = false; } else if (bar_config_.mode != "hide" || bar_config_.hidden_state != "hide") { From 5a0e42cc76493713cc0a3cfddc5eee4c2d57ce83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20W=C3=B6lfel?= Date: Tue, 12 Apr 2022 20:34:04 +0200 Subject: [PATCH 4/5] Limit visibility updates Prevent visibility updates to occur for inactive modules. Check active modules and subscribe to only those events. --- include/modules/sway/bar.hpp | 1 + src/modules/sway/bar.cpp | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/include/modules/sway/bar.hpp b/include/modules/sway/bar.hpp index 821bff1..01be788 100644 --- a/include/modules/sway/bar.hpp +++ b/include/modules/sway/bar.hpp @@ -37,6 +37,7 @@ class BarIpcClient { void onModeUpdate(bool visible_by_modifier); void onUrgencyUpdate(bool visible_by_urgency); void update(); + bool isModuleEnabled(std::string name); Bar& bar_; util::JsonParser parser_; diff --git a/src/modules/sway/bar.cpp b/src/modules/sway/bar.cpp index 82e14be..5968d3a 100644 --- a/src/modules/sway/bar.cpp +++ b/src/modules/sway/bar.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include "bar.hpp" @@ -19,6 +20,23 @@ BarIpcClient::BarIpcClient(waybar::Bar& bar) : bar_{bar} { handle.disconnect(); } + Json::Value subscribe_events{Json::arrayValue}; + subscribe_events.append("bar_state_update"); + subscribe_events.append("barconfig_update"); + + bool has_mode = isModuleEnabled("sway/mode"); + bool has_workspaces = isModuleEnabled("sway/workspaces"); + + if (has_mode) { + subscribe_events.append("mode"); + } + if (has_workspaces) { + subscribe_events.append("workspace"); + } + if (has_mode || has_workspaces) { + subscribe_events.append("binding"); + } + signal_config_.connect(sigc::mem_fun(*this, &BarIpcClient::onConfigUpdate)); signal_visible_.connect(sigc::mem_fun(*this, &BarIpcClient::onVisibilityUpdate)); signal_urgency_.connect(sigc::mem_fun(*this, &BarIpcClient::onUrgencyUpdate)); @@ -26,7 +44,9 @@ BarIpcClient::BarIpcClient(waybar::Bar& bar) : bar_{bar} { // Subscribe to non bar events to determine if the modifier key press is followed by another // action. - ipc_.subscribe(R"(["bar_state_update", "barconfig_update", "workspace", "mode", "binding"])"); + std::ostringstream oss_events; + oss_events << subscribe_events; + ipc_.subscribe(oss_events.str()); ipc_.signal_event.connect(sigc::mem_fun(*this, &BarIpcClient::onIpcEvent)); ipc_.signal_cmd.connect(sigc::mem_fun(*this, &BarIpcClient::onCmd)); // Launch worker @@ -39,6 +59,19 @@ BarIpcClient::BarIpcClient(waybar::Bar& bar) : bar_{bar} { }); } +bool BarIpcClient::isModuleEnabled(std::string name) { + for (const auto& section : {"modules-left", "modules-center", "modules-right"}) { + if (const auto& modules = bar_.config.get(section, {}); modules.isArray()) { + for (const auto& module : modules) { + if (module.asString().rfind(name, 0) == 0) { + return true; + } + } + } + } + return false; +} + struct swaybar_config parseConfig(const Json::Value& payload) { swaybar_config conf; if (auto id = payload["id"]; id.isString()) { From 7763d506912933cf4342073448c634ebccef067d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20W=C3=B6lfel?= Date: Thu, 14 Apr 2022 14:39:42 +0200 Subject: [PATCH 5/5] Add reset behaviour of modifier key Add an option to change the behaviour of the modifier key to reset the visibility. --- include/modules/sway/bar.hpp | 1 + man/waybar.5.scd.in | 7 +++++++ src/modules/sway/bar.cpp | 12 ++++++++---- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/include/modules/sway/bar.hpp b/include/modules/sway/bar.hpp index 01be788..fd48e5a 100644 --- a/include/modules/sway/bar.hpp +++ b/include/modules/sway/bar.hpp @@ -44,6 +44,7 @@ class BarIpcClient { Ipc ipc_; swaybar_config bar_config_; + std::string modifier_reset_; bool visible_by_mode_ = false; bool visible_by_modifier_ = false; bool visible_by_urgency_ = false; diff --git a/man/waybar.5.scd.in b/man/waybar.5.scd.in index 249ca7e..1ff219b 100644 --- a/man/waybar.5.scd.in +++ b/man/waybar.5.scd.in @@ -77,6 +77,13 @@ Also a minimal example configuration can be found on the at the bottom of this m Selects one of the preconfigured display modes. This is an equivalent of the sway-bar(5) *mode* command and supports the same values: *dock*, *hide*, *invisible*, *overlay*. ++ Note: *hide* and *invisible* modes may be not as useful without Sway IPC. +modifier-reset ++ + typeof: string ++ + default: *press* + Defines the timing of modifier key to reset the bar visibility. + To reset the visibility of the bar with the press of the modifier key use *press*. + Use *release* to reset the visibility upon the release of the modifier key and only if no other action happened while the key was pressed. This prevents hiding the bar when the modifier is used to switch a workspace, change binding mode or start a keybinding. + *exclusive* ++ typeof: bool ++ default: *true* ++ diff --git a/src/modules/sway/bar.cpp b/src/modules/sway/bar.cpp index 5968d3a..26234e3 100644 --- a/src/modules/sway/bar.cpp +++ b/src/modules/sway/bar.cpp @@ -37,6 +37,8 @@ BarIpcClient::BarIpcClient(waybar::Bar& bar) : bar_{bar} { subscribe_events.append("binding"); } + modifier_reset_ = bar.config.get("modifier-reset", "press").asString(); + signal_config_.connect(sigc::mem_fun(*this, &BarIpcClient::onConfigUpdate)); signal_visible_.connect(sigc::mem_fun(*this, &BarIpcClient::onVisibilityUpdate)); signal_urgency_.connect(sigc::mem_fun(*this, &BarIpcClient::onUrgencyUpdate)); @@ -188,10 +190,12 @@ void BarIpcClient::onVisibilityUpdate(bool visible_by_modifier) { if (visible_by_modifier) { modifier_no_action_ = true; } - if (!visible_by_modifier_ && modifier_no_action_) { - // Modifier key was pressed and released without a different action. - // This signals an acknowledgment and should hide the bar again. - // Hide the bar and clear the urgency flag. + + // Clear on either press or release depending on bar_.bar_config_.action value. + // For the check on release, make sure that the modifier key was not used for another action. + if (((modifier_reset_ == "press" && visible_by_modifier_) || + (modifier_reset_ == "release" && !visible_by_modifier_ && modifier_no_action_))) { + // Clear the flags to hide the bar. visible_by_urgency_ = false; visible_by_mode_ = false; }