From 5c859bf520fe91d37127937e9a0af534b487d4ea Mon Sep 17 00:00:00 2001 From: Khiet Tam Nguyen Date: Sat, 24 Aug 2024 00:06:24 +1000 Subject: [PATCH 01/15] temp: changed window -> windowcount --- include/modules/hyprland/windowcount.hpp | 65 +++++++ man/waybar-hyprland-windowcount.5.scd | 89 +++++++++ meson.build | 1 + src/factory.cpp | 4 + src/modules/hyprland/windowcount.cpp | 233 +++++++++++++++++++++++ 5 files changed, 392 insertions(+) create mode 100644 include/modules/hyprland/windowcount.hpp create mode 100644 man/waybar-hyprland-windowcount.5.scd create mode 100644 src/modules/hyprland/windowcount.cpp diff --git a/include/modules/hyprland/windowcount.hpp b/include/modules/hyprland/windowcount.hpp new file mode 100644 index 00000000..3972c66a --- /dev/null +++ b/include/modules/hyprland/windowcount.hpp @@ -0,0 +1,65 @@ +#pragma once + +#include + +#include + +#include "AAppIconLabel.hpp" +#include "bar.hpp" +#include "modules/hyprland/backend.hpp" +#include "util/json.hpp" + +namespace waybar::modules::hyprland { + +class WindowCount : public waybar::AAppIconLabel, public EventHandler { + public: + WindowCount(const std::string&, const waybar::Bar&, const Json::Value&); + ~WindowCount() override; + + auto update() -> void override; + + private: + struct Workspace { + int id; + int windows; + std::string last_window; + std::string last_window_title; + + static auto parse(const Json::Value& value) -> Workspace; + }; + + struct WindowCountData { + bool floating; + int monitor = -1; + std::string class_name; + std::string initial_class_name; + std::string title; + std::string initial_title; + bool fullscreen; + bool grouped; + + static auto parse(const Json::Value&) -> WindowCountData; + }; + + static auto getActiveWorkspace(const std::string&) -> Workspace; + static auto getActiveWorkspace() -> Workspace; + void onEvent(const std::string& ev) override; + void queryActiveWorkspace(); + void setClass(const std::string&, bool enable); + + bool separateOutputs_; + std::mutex mutex_; + const Bar& bar_; + util::JsonParser parser_; + WindowCountData windowData_; + Workspace workspace_; + std::string soloClass_; + std::string lastSoloClass_; + bool solo_; + bool allFloating_; + bool swallowing_; + bool fullscreen_; + bool focused_; +}; + +} // namespace waybar::modules::hyprland diff --git a/man/waybar-hyprland-windowcount.5.scd b/man/waybar-hyprland-windowcount.5.scd new file mode 100644 index 00000000..4e9c5d18 --- /dev/null +++ b/man/waybar-hyprland-windowcount.5.scd @@ -0,0 +1,89 @@ +waybar-hyprland-window(5) + +# NAME + +waybar - hyprland window module + +# DESCRIPTION + +The *window* module displays the title of the currently focused window in Hyprland. + +# CONFIGURATION + +Addressed by *hyprland/window* + +*format*: ++ + typeof: string ++ + default: {title} ++ + The format, how information should be displayed. On {} the current window title is displayed. + +*rewrite*: ++ + typeof: object ++ + Rules to rewrite window title. See *rewrite rules*. + +*separate-outputs*: ++ + typeof: bool ++ + Show the active window of the monitor the bar belongs to, instead of the focused window. + +*icon*: ++ + typeof: bool ++ + default: false ++ + Option to hide the application icon. + +*icon-size*: ++ + typeof: integer ++ + default: 24 ++ + Option to change the size of the application icon. + +# FORMAT REPLACEMENTS +See the output of "hyprctl clients" for examples + +*{title}*: The current title of the focused window. + +*{initialTitle}*: The initial title of the focused window. + +*{class}*: The current class of the focused window. + +*{initialClass}*: The initial class of the focused window. + +# REWRITE RULES + +*rewrite* is an object where keys are regular expressions and values are +rewrite rules if the expression matches. Rules may contain references to +captures of the expression. + +Regular expression and replacement follow ECMA-script rules. + +If no expression matches, the title is left unchanged. + +Invalid expressions (e.g., mismatched parentheses) are skipped. + +# EXAMPLES + +``` +"hyprland/window": { + "format": "{}", + "rewrite": { + "(.*) - Mozilla Firefox": "🌎 $1", + "(.*) - zsh": "> [$1]" + } +} +``` + +# STYLE + +- *#window* +- *window#waybar.empty #window* When no windows are in the workspace + +The following classes are applied to the entire Waybar rather than just the +window widget: + +- *window#waybar.empty* When no windows are in the workspace +- *window#waybar.solo* When one tiled window is visible in the workspace + (floating windows may be present) +- *window#waybar.* Where ** is the *class* (e.g. *chromium*) of + the solo tiled window in the workspace (use *hyprctl clients* to see classes) +- *window#waybar.floating* When there are only floating windows in the workspace +- *window#waybar.fullscreen* When there is a fullscreen window in the workspace; + useful with Hyprland's *fullscreen, 1* mode +- *window#waybar.swallowing* When there is a swallowed window in the workspace diff --git a/meson.build b/meson.build index 8daa6c9c..1a7a94df 100644 --- a/meson.build +++ b/meson.build @@ -306,6 +306,7 @@ if true 'src/modules/hyprland/language.cpp', 'src/modules/hyprland/submap.cpp', 'src/modules/hyprland/window.cpp', + 'src/modules/hyprland/windowcount.cpp', 'src/modules/hyprland/workspace.cpp', 'src/modules/hyprland/workspaces.cpp', 'src/modules/hyprland/windowcreationpayload.cpp', diff --git a/src/factory.cpp b/src/factory.cpp index ca10ef95..2344160f 100644 --- a/src/factory.cpp +++ b/src/factory.cpp @@ -34,6 +34,7 @@ #include "modules/hyprland/language.hpp" #include "modules/hyprland/submap.hpp" #include "modules/hyprland/window.hpp" +#include "modules/hyprland/windowcount.hpp" #include "modules/hyprland/workspaces.hpp" #endif #if defined(__FreeBSD__) || defined(__linux__) @@ -196,6 +197,9 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name, if (ref == "hyprland/window") { return new waybar::modules::hyprland::Window(id, bar_, config_[name]); } + if (ref == "hyprland/windowcount") { + return new waybar::modules::hyprland::WindowCount(id, bar_, config_[name]); + } if (ref == "hyprland/language") { return new waybar::modules::hyprland::Language(id, bar_, config_[name]); } diff --git a/src/modules/hyprland/windowcount.cpp b/src/modules/hyprland/windowcount.cpp new file mode 100644 index 00000000..52c25978 --- /dev/null +++ b/src/modules/hyprland/windowcount.cpp @@ -0,0 +1,233 @@ +#include "modules/hyprland/windowcount.hpp" + +#include +#include +#include +#include + +#include +#include + +#include "modules/hyprland/backend.hpp" +#include "util/rewrite_string.hpp" +#include "util/sanitize_str.hpp" + +namespace waybar::modules::hyprland { + +WindowCount::WindowCount(const std::string& id, const Bar& bar, const Json::Value& config) + : AAppIconLabel(config, "window", id, "{title}", 0, true), bar_(bar) { + modulesReady = true; + separateOutputs_ = config["separate-outputs"].asBool(); + + if (!gIPC) { + gIPC = std::make_unique(); + } + + queryActiveWorkspace(); + update(); + dp.emit(); + + // register for hyprland ipc + gIPC->registerForIPC("activewindow", this); + gIPC->registerForIPC("closewindow", this); + gIPC->registerForIPC("movewindow", this); + gIPC->registerForIPC("changefloatingmode", this); + gIPC->registerForIPC("fullscreen", this); +} + +WindowCount::~WindowCount() { + gIPC->unregisterForIPC(this); + // wait for possible event handler to finish + std::lock_guard lg(mutex_); +} + +auto WindowCount::update() -> void { + // fix ampersands + std::lock_guard lg(mutex_); + + std::string windowName = waybar::util::sanitize_string(workspace_.last_window_title); + std::string windowAddress = workspace_.last_window; + + windowData_.title = windowName; + + if (!format_.empty()) { + label_.show(); + label_.set_markup(waybar::util::rewriteString( + fmt::format(fmt::runtime(format_), fmt::arg("title", windowName), + fmt::arg("initialTitle", windowData_.initial_title), + fmt::arg("class", windowData_.class_name), + fmt::arg("initialClass", windowData_.initial_class_name)), + config_["rewrite"])); + } else { + label_.hide(); + } + + if (focused_) { + image_.show(); + } else { + image_.hide(); + } + + setClass("empty", workspace_.windows == 0); + setClass("solo", solo_); + setClass("floating", allFloating_); + setClass("swallowing", swallowing_); + setClass("fullscreen", fullscreen_); + + if (!lastSoloClass_.empty() && soloClass_ != lastSoloClass_) { + if (bar_.window.get_style_context()->has_class(lastSoloClass_)) { + bar_.window.get_style_context()->remove_class(lastSoloClass_); + spdlog::trace("Removing solo class: {}", lastSoloClass_); + } + } + + if (!soloClass_.empty() && soloClass_ != lastSoloClass_) { + bar_.window.get_style_context()->add_class(soloClass_); + spdlog::trace("Adding solo class: {}", soloClass_); + } + lastSoloClass_ = soloClass_; + + AAppIconLabel::update(); +} + +auto WindowCount::getActiveWorkspace() -> Workspace { + const auto workspace = gIPC->getSocket1JsonReply("activeworkspace"); + + if (workspace.isObject()) { + return Workspace::parse(workspace); + } + + return {}; +} + +auto WindowCount::getActiveWorkspace(const std::string& monitorName) -> Workspace { + const auto monitors = gIPC->getSocket1JsonReply("monitors"); + if (monitors.isArray()) { + auto monitor = std::find_if(monitors.begin(), monitors.end(), [&](Json::Value monitor) { + return monitor["name"] == monitorName; + }); + if (monitor == std::end(monitors)) { + spdlog::warn("Monitor not found: {}", monitorName); + return Workspace{-1, 0, "", ""}; + } + const int id = (*monitor)["activeWorkspace"]["id"].asInt(); + + const auto workspaces = gIPC->getSocket1JsonReply("workspaces"); + if (workspaces.isArray()) { + auto workspace = std::find_if(workspaces.begin(), workspaces.end(), + [&](Json::Value workspace) { return workspace["id"] == id; }); + if (workspace == std::end(workspaces)) { + spdlog::warn("No workspace with id {}", id); + return Workspace{-1, 0, "", ""}; + } + return Workspace::parse(*workspace); + }; + }; + + return {}; +} + +auto WindowCount::Workspace::parse(const Json::Value& value) -> WindowCount::Workspace { + return Workspace{ + value["id"].asInt(), + value["windows"].asInt(), + value["lastwindow"].asString(), + value["lastwindowtitle"].asString(), + }; +} + +auto WindowCount::WindowCountData::parse(const Json::Value& value) -> WindowCount::WindowCountData { + return WindowCountData{value["floating"].asBool(), value["monitor"].asInt(), + value["class"].asString(), value["initialClass"].asString(), + value["title"].asString(), value["initialTitle"].asString(), + value["fullscreen"].asBool(), !value["grouped"].empty()}; +} + +void WindowCount::queryActiveWorkspace() { + std::lock_guard lg(mutex_); + + if (separateOutputs_) { + workspace_ = getActiveWorkspace(this->bar_.output->name); + } else { + workspace_ = getActiveWorkspace(); + } + + focused_ = true; + if (workspace_.windows > 0) { + const auto clients = gIPC->getSocket1JsonReply("clients"); + if (clients.isArray()) { + auto activeWindowCount = std::find_if(clients.begin(), clients.end(), [&](Json::Value window) { + return window["address"] == workspace_.last_window; + }); + + if (activeWindowCount == std::end(clients)) { + focused_ = false; + return; + } + + windowData_ = WindowCountData::parse(*activeWindowCount); + updateAppIconName(windowData_.class_name, windowData_.initial_class_name); + std::vector workspaceWindowCounts; + std::copy_if(clients.begin(), clients.end(), std::back_inserter(workspaceWindowCounts), + [&](Json::Value window) { + return window["workspace"]["id"] == workspace_.id && window["mapped"].asBool(); + }); + swallowing_ = + std::any_of(workspaceWindowCounts.begin(), workspaceWindowCounts.end(), [&](Json::Value window) { + return !window["swallowing"].isNull() && window["swallowing"].asString() != "0x0"; + }); + std::vector visibleWindowCounts; + std::copy_if(workspaceWindowCounts.begin(), workspaceWindowCounts.end(), + std::back_inserter(visibleWindowCounts), + [&](Json::Value window) { return !window["hidden"].asBool(); }); + solo_ = 1 == std::count_if(visibleWindowCounts.begin(), visibleWindowCounts.end(), + [&](Json::Value window) { return !window["floating"].asBool(); }); + allFloating_ = std::all_of(visibleWindowCounts.begin(), visibleWindowCounts.end(), + [&](Json::Value window) { return window["floating"].asBool(); }); + fullscreen_ = windowData_.fullscreen; + + // Fullscreen windows look like they are solo + if (fullscreen_) { + solo_ = true; + } + + // Grouped windows have a tab bar and therefore don't look fullscreen or solo + if (windowData_.grouped) { + fullscreen_ = false; + solo_ = false; + } + + if (solo_) { + soloClass_ = windowData_.class_name; + } else { + soloClass_ = ""; + } + }; + } else { + focused_ = false; + windowData_ = WindowCountData{}; + allFloating_ = false; + swallowing_ = false; + fullscreen_ = false; + solo_ = false; + soloClass_ = ""; + } +} + +void WindowCount::onEvent(const std::string& ev) { + queryActiveWorkspace(); + + dp.emit(); +} + +void WindowCount::setClass(const std::string& classname, bool enable) { + if (enable) { + if (!bar_.window.get_style_context()->has_class(classname)) { + bar_.window.get_style_context()->add_class(classname); + } + } else { + bar_.window.get_style_context()->remove_class(classname); + } +} + +} // namespace waybar::modules::hyprland From d64c80e234e69872239d3a2d4c24e8077771014f Mon Sep 17 00:00:00 2001 From: Khiet Tam Nguyen Date: Sat, 24 Aug 2024 00:14:30 +1000 Subject: [PATCH 02/15] temp: working implementation --- include/modules/hyprland/windowcount.hpp | 24 +---- src/modules/hyprland/windowcount.cpp | 115 +++-------------------- 2 files changed, 14 insertions(+), 125 deletions(-) diff --git a/include/modules/hyprland/windowcount.hpp b/include/modules/hyprland/windowcount.hpp index 3972c66a..d5fd9565 100644 --- a/include/modules/hyprland/windowcount.hpp +++ b/include/modules/hyprland/windowcount.hpp @@ -28,19 +28,6 @@ class WindowCount : public waybar::AAppIconLabel, public EventHandler { static auto parse(const Json::Value& value) -> Workspace; }; - struct WindowCountData { - bool floating; - int monitor = -1; - std::string class_name; - std::string initial_class_name; - std::string title; - std::string initial_title; - bool fullscreen; - bool grouped; - - static auto parse(const Json::Value&) -> WindowCountData; - }; - static auto getActiveWorkspace(const std::string&) -> Workspace; static auto getActiveWorkspace() -> Workspace; void onEvent(const std::string& ev) override; @@ -50,16 +37,9 @@ class WindowCount : public waybar::AAppIconLabel, public EventHandler { bool separateOutputs_; std::mutex mutex_; const Bar& bar_; - util::JsonParser parser_; - WindowCountData windowData_; Workspace workspace_; - std::string soloClass_; - std::string lastSoloClass_; - bool solo_; - bool allFloating_; - bool swallowing_; - bool fullscreen_; bool focused_; + int windowCount_; }; -} // namespace waybar::modules::hyprland +} // namespace waybar::modules::hyprland \ No newline at end of file diff --git a/src/modules/hyprland/windowcount.cpp b/src/modules/hyprland/windowcount.cpp index 52c25978..da600379 100644 --- a/src/modules/hyprland/windowcount.cpp +++ b/src/modules/hyprland/windowcount.cpp @@ -15,7 +15,7 @@ namespace waybar::modules::hyprland { WindowCount::WindowCount(const std::string& id, const Bar& bar, const Json::Value& config) - : AAppIconLabel(config, "window", id, "{title}", 0, true), bar_(bar) { + : AAppIconLabel(config, "windowcount", id, "{count}", 0, true), bar_(bar) { modulesReady = true; separateOutputs_ = config["separate-outputs"].asBool(); @@ -28,11 +28,12 @@ WindowCount::WindowCount(const std::string& id, const Bar& bar, const Json::Valu dp.emit(); // register for hyprland ipc - gIPC->registerForIPC("activewindow", this); + gIPC->registerForIPC("fullscreen", this); + gIPC->registerForIPC("workspace", this); + gIPC->registerForIPC("focusedmon", this); + gIPC->registerForIPC("openwindow", this); gIPC->registerForIPC("closewindow", this); gIPC->registerForIPC("movewindow", this); - gIPC->registerForIPC("changefloatingmode", this); - gIPC->registerForIPC("fullscreen", this); } WindowCount::~WindowCount() { @@ -42,50 +43,19 @@ WindowCount::~WindowCount() { } auto WindowCount::update() -> void { - // fix ampersands std::lock_guard lg(mutex_); - std::string windowName = waybar::util::sanitize_string(workspace_.last_window_title); - std::string windowAddress = workspace_.last_window; - - windowData_.title = windowName; - if (!format_.empty()) { label_.show(); label_.set_markup(waybar::util::rewriteString( - fmt::format(fmt::runtime(format_), fmt::arg("title", windowName), - fmt::arg("initialTitle", windowData_.initial_title), - fmt::arg("class", windowData_.class_name), - fmt::arg("initialClass", windowData_.initial_class_name)), + fmt::format(fmt::runtime(format_), fmt::arg("count", workspace_.windows)), config_["rewrite"])); } else { label_.hide(); } - if (focused_) { - image_.show(); - } else { - image_.hide(); - } - - setClass("empty", workspace_.windows == 0); - setClass("solo", solo_); - setClass("floating", allFloating_); - setClass("swallowing", swallowing_); - setClass("fullscreen", fullscreen_); - - if (!lastSoloClass_.empty() && soloClass_ != lastSoloClass_) { - if (bar_.window.get_style_context()->has_class(lastSoloClass_)) { - bar_.window.get_style_context()->remove_class(lastSoloClass_); - spdlog::trace("Removing solo class: {}", lastSoloClass_); - } - } - - if (!soloClass_.empty() && soloClass_ != lastSoloClass_) { - bar_.window.get_style_context()->add_class(soloClass_); - spdlog::trace("Adding solo class: {}", soloClass_); - } - lastSoloClass_ = soloClass_; + // Display the count as the label text + label_.set_text(fmt::format("{}", workspace_.windows)); AAppIconLabel::update(); } @@ -136,13 +106,6 @@ auto WindowCount::Workspace::parse(const Json::Value& value) -> WindowCount::Wor }; } -auto WindowCount::WindowCountData::parse(const Json::Value& value) -> WindowCount::WindowCountData { - return WindowCountData{value["floating"].asBool(), value["monitor"].asInt(), - value["class"].asString(), value["initialClass"].asString(), - value["title"].asString(), value["initialTitle"].asString(), - value["fullscreen"].asBool(), !value["grouped"].empty()}; -} - void WindowCount::queryActiveWorkspace() { std::lock_guard lg(mutex_); @@ -153,70 +116,16 @@ void WindowCount::queryActiveWorkspace() { } focused_ = true; - if (workspace_.windows > 0) { - const auto clients = gIPC->getSocket1JsonReply("clients"); - if (clients.isArray()) { - auto activeWindowCount = std::find_if(clients.begin(), clients.end(), [&](Json::Value window) { - return window["address"] == workspace_.last_window; - }); + windowCount_ = workspace_.windows; - if (activeWindowCount == std::end(clients)) { - focused_ = false; - return; - } - - windowData_ = WindowCountData::parse(*activeWindowCount); - updateAppIconName(windowData_.class_name, windowData_.initial_class_name); - std::vector workspaceWindowCounts; - std::copy_if(clients.begin(), clients.end(), std::back_inserter(workspaceWindowCounts), - [&](Json::Value window) { - return window["workspace"]["id"] == workspace_.id && window["mapped"].asBool(); - }); - swallowing_ = - std::any_of(workspaceWindowCounts.begin(), workspaceWindowCounts.end(), [&](Json::Value window) { - return !window["swallowing"].isNull() && window["swallowing"].asString() != "0x0"; - }); - std::vector visibleWindowCounts; - std::copy_if(workspaceWindowCounts.begin(), workspaceWindowCounts.end(), - std::back_inserter(visibleWindowCounts), - [&](Json::Value window) { return !window["hidden"].asBool(); }); - solo_ = 1 == std::count_if(visibleWindowCounts.begin(), visibleWindowCounts.end(), - [&](Json::Value window) { return !window["floating"].asBool(); }); - allFloating_ = std::all_of(visibleWindowCounts.begin(), visibleWindowCounts.end(), - [&](Json::Value window) { return window["floating"].asBool(); }); - fullscreen_ = windowData_.fullscreen; - - // Fullscreen windows look like they are solo - if (fullscreen_) { - solo_ = true; - } - - // Grouped windows have a tab bar and therefore don't look fullscreen or solo - if (windowData_.grouped) { - fullscreen_ = false; - solo_ = false; - } - - if (solo_) { - soloClass_ = windowData_.class_name; - } else { - soloClass_ = ""; - } - }; - } else { + if (workspace_.windows == 0) { focused_ = false; - windowData_ = WindowCountData{}; - allFloating_ = false; - swallowing_ = false; - fullscreen_ = false; - solo_ = false; - soloClass_ = ""; } } void WindowCount::onEvent(const std::string& ev) { queryActiveWorkspace(); - + update(); dp.emit(); } @@ -230,4 +139,4 @@ void WindowCount::setClass(const std::string& classname, bool enable) { } } -} // namespace waybar::modules::hyprland +} // namespace waybar::modules::hyprland \ No newline at end of file From 58e4f89a82057612ea12b688dc099203899f1d32 Mon Sep 17 00:00:00 2001 From: Khiet Tam Nguyen Date: Sat, 24 Aug 2024 00:40:22 +1000 Subject: [PATCH 03/15] fix: allow custom format --- src/modules/hyprland/windowcount.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/modules/hyprland/windowcount.cpp b/src/modules/hyprland/windowcount.cpp index da600379..f5b180a0 100644 --- a/src/modules/hyprland/windowcount.cpp +++ b/src/modules/hyprland/windowcount.cpp @@ -45,18 +45,21 @@ WindowCount::~WindowCount() { auto WindowCount::update() -> void { std::lock_guard lg(mutex_); - if (!format_.empty()) { - label_.show(); + std::string format = config_["format"].asString(); + std::string formattedText; + + if (!format.empty()) { + formattedText = fmt::format(fmt::runtime(format), workspace_.windows); label_.set_markup(waybar::util::rewriteString( - fmt::format(fmt::runtime(format_), fmt::arg("count", workspace_.windows)), + formattedText, config_["rewrite"])); + label_.show(); } else { + // Default display + label_.set_text(fmt::format("{}", workspace_.windows)); label_.hide(); } - // Display the count as the label text - label_.set_text(fmt::format("{}", workspace_.windows)); - AAppIconLabel::update(); } @@ -125,7 +128,6 @@ void WindowCount::queryActiveWorkspace() { void WindowCount::onEvent(const std::string& ev) { queryActiveWorkspace(); - update(); dp.emit(); } From e40bc27257d1c9699e3291b8406c68e3da575e8b Mon Sep 17 00:00:00 2001 From: Khiet Tam Nguyen Date: Sat, 24 Aug 2024 00:40:41 +1000 Subject: [PATCH 04/15] fix: default separate-outputs to true --- src/modules/hyprland/windowcount.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/hyprland/windowcount.cpp b/src/modules/hyprland/windowcount.cpp index f5b180a0..04c62153 100644 --- a/src/modules/hyprland/windowcount.cpp +++ b/src/modules/hyprland/windowcount.cpp @@ -17,7 +17,7 @@ namespace waybar::modules::hyprland { WindowCount::WindowCount(const std::string& id, const Bar& bar, const Json::Value& config) : AAppIconLabel(config, "windowcount", id, "{count}", 0, true), bar_(bar) { modulesReady = true; - separateOutputs_ = config["separate-outputs"].asBool(); + separateOutputs_ = config.isMember("separate-outputs") ? config["separate-outputs"].asBool() : true; if (!gIPC) { gIPC = std::make_unique(); From 1806edcb06c167a5e75993ecbb36b7a5867d6920 Mon Sep 17 00:00:00 2001 From: Khiet Tam Nguyen Date: Sat, 24 Aug 2024 01:04:58 +1000 Subject: [PATCH 05/15] fix: remove unused variable --- include/modules/hyprland/windowcount.hpp | 1 - src/modules/hyprland/windowcount.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/include/modules/hyprland/windowcount.hpp b/include/modules/hyprland/windowcount.hpp index d5fd9565..f9644f5a 100644 --- a/include/modules/hyprland/windowcount.hpp +++ b/include/modules/hyprland/windowcount.hpp @@ -39,7 +39,6 @@ class WindowCount : public waybar::AAppIconLabel, public EventHandler { const Bar& bar_; Workspace workspace_; bool focused_; - int windowCount_; }; } // namespace waybar::modules::hyprland \ No newline at end of file diff --git a/src/modules/hyprland/windowcount.cpp b/src/modules/hyprland/windowcount.cpp index 04c62153..d1429c25 100644 --- a/src/modules/hyprland/windowcount.cpp +++ b/src/modules/hyprland/windowcount.cpp @@ -119,7 +119,6 @@ void WindowCount::queryActiveWorkspace() { } focused_ = true; - windowCount_ = workspace_.windows; if (workspace_.windows == 0) { focused_ = false; From 1b282e67a7fd2ef1abad474574e13efcdd1b5ffa Mon Sep 17 00:00:00 2001 From: Khiet Tam Nguyen Date: Sat, 24 Aug 2024 01:06:00 +1000 Subject: [PATCH 06/15] fix: remove unused attributes --- include/modules/hyprland/windowcount.hpp | 3 --- src/modules/hyprland/windowcount.cpp | 6 ++---- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/include/modules/hyprland/windowcount.hpp b/include/modules/hyprland/windowcount.hpp index f9644f5a..1d283b67 100644 --- a/include/modules/hyprland/windowcount.hpp +++ b/include/modules/hyprland/windowcount.hpp @@ -22,9 +22,6 @@ class WindowCount : public waybar::AAppIconLabel, public EventHandler { struct Workspace { int id; int windows; - std::string last_window; - std::string last_window_title; - static auto parse(const Json::Value& value) -> Workspace; }; diff --git a/src/modules/hyprland/windowcount.cpp b/src/modules/hyprland/windowcount.cpp index d1429c25..e6e36238 100644 --- a/src/modules/hyprland/windowcount.cpp +++ b/src/modules/hyprland/windowcount.cpp @@ -81,7 +81,7 @@ auto WindowCount::getActiveWorkspace(const std::string& monitorName) -> Workspac }); if (monitor == std::end(monitors)) { spdlog::warn("Monitor not found: {}", monitorName); - return Workspace{-1, 0, "", ""}; + return Workspace{-1, 0}; } const int id = (*monitor)["activeWorkspace"]["id"].asInt(); @@ -91,7 +91,7 @@ auto WindowCount::getActiveWorkspace(const std::string& monitorName) -> Workspac [&](Json::Value workspace) { return workspace["id"] == id; }); if (workspace == std::end(workspaces)) { spdlog::warn("No workspace with id {}", id); - return Workspace{-1, 0, "", ""}; + return Workspace{-1, 0}; } return Workspace::parse(*workspace); }; @@ -104,8 +104,6 @@ auto WindowCount::Workspace::parse(const Json::Value& value) -> WindowCount::Wor return Workspace{ value["id"].asInt(), value["windows"].asInt(), - value["lastwindow"].asString(), - value["lastwindowtitle"].asString(), }; } From 38ffb24c526bb9cd88dbd078d9e4618a5bea9e84 Mon Sep 17 00:00:00 2001 From: Khiet Tam Nguyen Date: Sat, 24 Aug 2024 01:25:50 +1000 Subject: [PATCH 07/15] feat: format-fullscreen and format-windowed override added --- include/modules/hyprland/windowcount.hpp | 1 + src/modules/hyprland/windowcount.cpp | 24 ++++++++++++++++-------- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/include/modules/hyprland/windowcount.hpp b/include/modules/hyprland/windowcount.hpp index 1d283b67..c8cfcf6d 100644 --- a/include/modules/hyprland/windowcount.hpp +++ b/include/modules/hyprland/windowcount.hpp @@ -22,6 +22,7 @@ class WindowCount : public waybar::AAppIconLabel, public EventHandler { struct Workspace { int id; int windows; + bool hasfullscreen; static auto parse(const Json::Value& value) -> Workspace; }; diff --git a/src/modules/hyprland/windowcount.cpp b/src/modules/hyprland/windowcount.cpp index e6e36238..8e9e77bc 100644 --- a/src/modules/hyprland/windowcount.cpp +++ b/src/modules/hyprland/windowcount.cpp @@ -46,20 +46,27 @@ auto WindowCount::update() -> void { std::lock_guard lg(mutex_); std::string format = config_["format"].asString(); + std::string formatFullscreen = config_["format-fullscreen"].asString(); + std::string formatWindowed = config_["format-windowed"].asString(); std::string formattedText; - if (!format.empty()) { - formattedText = fmt::format(fmt::runtime(format), workspace_.windows); + if (workspace_.hasfullscreen && !formatFullscreen.empty()) { label_.set_markup(waybar::util::rewriteString( - formattedText, + fmt::format(fmt::runtime(formatFullscreen), workspace_.windows), + config_["rewrite"])); + } else if (!workspace_.hasfullscreen && !formatWindowed.empty()) { + label_.set_markup(waybar::util::rewriteString( + fmt::format(fmt::runtime(formatWindowed), workspace_.windows), + config_["rewrite"])); + } else if (!format.empty()) { + label_.set_markup(waybar::util::rewriteString( + fmt::format(fmt::runtime(format), workspace_.windows), config_["rewrite"])); - label_.show(); } else { - // Default display label_.set_text(fmt::format("{}", workspace_.windows)); - label_.hide(); } + label_.show(); AAppIconLabel::update(); } @@ -81,7 +88,7 @@ auto WindowCount::getActiveWorkspace(const std::string& monitorName) -> Workspac }); if (monitor == std::end(monitors)) { spdlog::warn("Monitor not found: {}", monitorName); - return Workspace{-1, 0}; + return Workspace{-1, 0, false}; } const int id = (*monitor)["activeWorkspace"]["id"].asInt(); @@ -91,7 +98,7 @@ auto WindowCount::getActiveWorkspace(const std::string& monitorName) -> Workspac [&](Json::Value workspace) { return workspace["id"] == id; }); if (workspace == std::end(workspaces)) { spdlog::warn("No workspace with id {}", id); - return Workspace{-1, 0}; + return Workspace{-1, 0, false}; } return Workspace::parse(*workspace); }; @@ -104,6 +111,7 @@ auto WindowCount::Workspace::parse(const Json::Value& value) -> WindowCount::Wor return Workspace{ value["id"].asInt(), value["windows"].asInt(), + value["hasfullscreen"].asBool(), }; } From f7e1d3425153feb99981af66962df3745bc1b045 Mon Sep 17 00:00:00 2001 From: Khiet Tam Nguyen Date: Sat, 24 Aug 2024 01:33:07 +1000 Subject: [PATCH 08/15] feat: added empty and fullscreen style classes --- src/modules/hyprland/windowcount.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/modules/hyprland/windowcount.cpp b/src/modules/hyprland/windowcount.cpp index 8e9e77bc..d6fff2c1 100644 --- a/src/modules/hyprland/windowcount.cpp +++ b/src/modules/hyprland/windowcount.cpp @@ -48,7 +48,9 @@ auto WindowCount::update() -> void { std::string format = config_["format"].asString(); std::string formatFullscreen = config_["format-fullscreen"].asString(); std::string formatWindowed = config_["format-windowed"].asString(); - std::string formattedText; + + setClass("empty", workspace_.windows == 0); + setClass("fullscreen", workspace_.hasfullscreen); if (workspace_.hasfullscreen && !formatFullscreen.empty()) { label_.set_markup(waybar::util::rewriteString( From 6aa8aa3b2279fce790b68766b60b38a2905594f4 Mon Sep 17 00:00:00 2001 From: Khiet Tam Nguyen Date: Sat, 24 Aug 2024 12:57:10 +1000 Subject: [PATCH 09/15] fix: remove focused_ --- include/modules/hyprland/windowcount.hpp | 1 - src/modules/hyprland/windowcount.cpp | 6 ------ 2 files changed, 7 deletions(-) diff --git a/include/modules/hyprland/windowcount.hpp b/include/modules/hyprland/windowcount.hpp index c8cfcf6d..1b89d1a3 100644 --- a/include/modules/hyprland/windowcount.hpp +++ b/include/modules/hyprland/windowcount.hpp @@ -36,7 +36,6 @@ class WindowCount : public waybar::AAppIconLabel, public EventHandler { std::mutex mutex_; const Bar& bar_; Workspace workspace_; - bool focused_; }; } // namespace waybar::modules::hyprland \ No newline at end of file diff --git a/src/modules/hyprland/windowcount.cpp b/src/modules/hyprland/windowcount.cpp index d6fff2c1..b8142f72 100644 --- a/src/modules/hyprland/windowcount.cpp +++ b/src/modules/hyprland/windowcount.cpp @@ -125,12 +125,6 @@ void WindowCount::queryActiveWorkspace() { } else { workspace_ = getActiveWorkspace(); } - - focused_ = true; - - if (workspace_.windows == 0) { - focused_ = false; - } } void WindowCount::onEvent(const std::string& ev) { From a5e322ee66752307996c2fa8e6ca9e2c9add7830 Mon Sep 17 00:00:00 2001 From: Khiet Tam Nguyen Date: Sat, 24 Aug 2024 12:59:57 +1000 Subject: [PATCH 10/15] fix: remove rewrite --- src/modules/hyprland/windowcount.cpp | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/modules/hyprland/windowcount.cpp b/src/modules/hyprland/windowcount.cpp index b8142f72..c9fc3050 100644 --- a/src/modules/hyprland/windowcount.cpp +++ b/src/modules/hyprland/windowcount.cpp @@ -9,7 +9,6 @@ #include #include "modules/hyprland/backend.hpp" -#include "util/rewrite_string.hpp" #include "util/sanitize_str.hpp" namespace waybar::modules::hyprland { @@ -53,17 +52,11 @@ auto WindowCount::update() -> void { setClass("fullscreen", workspace_.hasfullscreen); if (workspace_.hasfullscreen && !formatFullscreen.empty()) { - label_.set_markup(waybar::util::rewriteString( - fmt::format(fmt::runtime(formatFullscreen), workspace_.windows), - config_["rewrite"])); + label_.set_markup(fmt::format(fmt::runtime(formatFullscreen), workspace_.windows)); } else if (!workspace_.hasfullscreen && !formatWindowed.empty()) { - label_.set_markup(waybar::util::rewriteString( - fmt::format(fmt::runtime(formatWindowed), workspace_.windows), - config_["rewrite"])); + label_.set_markup(fmt::format(fmt::runtime(formatWindowed), workspace_.windows)); } else if (!format.empty()) { - label_.set_markup(waybar::util::rewriteString( - fmt::format(fmt::runtime(format), workspace_.windows), - config_["rewrite"])); + label_.set_markup(fmt::format(fmt::runtime(format), workspace_.windows)); } else { label_.set_text(fmt::format("{}", workspace_.windows)); } From 9254ef6f2f909130d3ad2dabbe9ebc479a662484 Mon Sep 17 00:00:00 2001 From: Khiet Tam Nguyen Date: Sat, 24 Aug 2024 13:29:46 +1000 Subject: [PATCH 11/15] docs: updated scd man pages --- man/waybar-hyprland-windowcount.5.scd | 75 ++++----------------------- 1 file changed, 10 insertions(+), 65 deletions(-) diff --git a/man/waybar-hyprland-windowcount.5.scd b/man/waybar-hyprland-windowcount.5.scd index 4e9c5d18..0b6b2171 100644 --- a/man/waybar-hyprland-windowcount.5.scd +++ b/man/waybar-hyprland-windowcount.5.scd @@ -1,89 +1,34 @@ -waybar-hyprland-window(5) +waybar-hyprland-windowcount(5) # NAME -waybar - hyprland window module +waybar - hyprland window count module # DESCRIPTION -The *window* module displays the title of the currently focused window in Hyprland. +The *windowcount* module displays the number of windows in the current Hyprland workspace. # CONFIGURATION -Addressed by *hyprland/window* +Addressed by *hyprland/windowcount* *format*: ++ typeof: string ++ - default: {title} ++ - The format, how information should be displayed. On {} the current window title is displayed. - -*rewrite*: ++ - typeof: object ++ - Rules to rewrite window title. See *rewrite rules*. + default: {} ++ + The format, how information should be displayed. On {} the current window count is displayed. *separate-outputs*: ++ typeof: bool ++ - Show the active window of the monitor the bar belongs to, instead of the focused window. - -*icon*: ++ - typeof: bool ++ - default: false ++ - Option to hide the application icon. - -*icon-size*: ++ - typeof: integer ++ - default: 24 ++ - Option to change the size of the application icon. - -# FORMAT REPLACEMENTS -See the output of "hyprctl clients" for examples - -*{title}*: The current title of the focused window. - -*{initialTitle}*: The initial title of the focused window. - -*{class}*: The current class of the focused window. - -*{initialClass}*: The initial class of the focused window. - -# REWRITE RULES - -*rewrite* is an object where keys are regular expressions and values are -rewrite rules if the expression matches. Rules may contain references to -captures of the expression. - -Regular expression and replacement follow ECMA-script rules. - -If no expression matches, the title is left unchanged. - -Invalid expressions (e.g., mismatched parentheses) are skipped. - -# EXAMPLES - -``` -"hyprland/window": { - "format": "{}", - "rewrite": { - "(.*) - Mozilla Firefox": "🌎 $1", - "(.*) - zsh": "> [$1]" - } -} -``` + default: true ++ + Show the active window count of the monitor the bar belongs to, instead of the focused window. # STYLE -- *#window* -- *window#waybar.empty #window* When no windows are in the workspace +- *#windowcount* The following classes are applied to the entire Waybar rather than just the -window widget: +windowcount widget: - *window#waybar.empty* When no windows are in the workspace -- *window#waybar.solo* When one tiled window is visible in the workspace - (floating windows may be present) -- *window#waybar.* Where ** is the *class* (e.g. *chromium*) of - the solo tiled window in the workspace (use *hyprctl clients* to see classes) -- *window#waybar.floating* When there are only floating windows in the workspace - *window#waybar.fullscreen* When there is a fullscreen window in the workspace; useful with Hyprland's *fullscreen, 1* mode -- *window#waybar.swallowing* When there is a swallowed window in the workspace From 8254bd72b72f16c37d1dad11a0e5d9045e1c423a Mon Sep 17 00:00:00 2001 From: Khiet Tam Nguyen Date: Sat, 24 Aug 2024 13:36:00 +1000 Subject: [PATCH 12/15] style: applied clang-format on windowcount.cpp --- src/modules/hyprland/windowcount.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/modules/hyprland/windowcount.cpp b/src/modules/hyprland/windowcount.cpp index c9fc3050..001cdf6c 100644 --- a/src/modules/hyprland/windowcount.cpp +++ b/src/modules/hyprland/windowcount.cpp @@ -16,7 +16,8 @@ namespace waybar::modules::hyprland { WindowCount::WindowCount(const std::string& id, const Bar& bar, const Json::Value& config) : AAppIconLabel(config, "windowcount", id, "{count}", 0, true), bar_(bar) { modulesReady = true; - separateOutputs_ = config.isMember("separate-outputs") ? config["separate-outputs"].asBool() : true; + separateOutputs_ = + config.isMember("separate-outputs") ? config["separate-outputs"].asBool() : true; if (!gIPC) { gIPC = std::make_unique(); From 13bc497abd9bad3e46c4f3832d1d57b201e2b5d3 Mon Sep 17 00:00:00 2001 From: Khiet Tam Nguyen Date: Sat, 24 Aug 2024 15:21:04 +1000 Subject: [PATCH 13/15] style: clang-format --- include/modules/hyprland/windowcount.hpp | 2 +- src/modules/hyprland/windowcount.cpp | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/include/modules/hyprland/windowcount.hpp b/include/modules/hyprland/windowcount.hpp index 1b89d1a3..195e6a34 100644 --- a/include/modules/hyprland/windowcount.hpp +++ b/include/modules/hyprland/windowcount.hpp @@ -38,4 +38,4 @@ class WindowCount : public waybar::AAppIconLabel, public EventHandler { Workspace workspace_; }; -} // namespace waybar::modules::hyprland \ No newline at end of file +} // namespace waybar::modules::hyprland diff --git a/src/modules/hyprland/windowcount.cpp b/src/modules/hyprland/windowcount.cpp index 001cdf6c..68f7c3b4 100644 --- a/src/modules/hyprland/windowcount.cpp +++ b/src/modules/hyprland/windowcount.cpp @@ -46,16 +46,19 @@ auto WindowCount::update() -> void { std::lock_guard lg(mutex_); std::string format = config_["format"].asString(); - std::string formatFullscreen = config_["format-fullscreen"].asString(); + std::string formatEmpty = config_["format-empty"].asString(); std::string formatWindowed = config_["format-windowed"].asString(); + std::string formatFullscreen = config_["format-fullscreen"].asString(); setClass("empty", workspace_.windows == 0); setClass("fullscreen", workspace_.hasfullscreen); - if (workspace_.hasfullscreen && !formatFullscreen.empty()) { - label_.set_markup(fmt::format(fmt::runtime(formatFullscreen), workspace_.windows)); + if (workspace_.windows == 0 && !formatEmpty.empty()) { + label_.set_markup(fmt::format(fmt::runtime(formatEmpty), workspace_.windows)); } else if (!workspace_.hasfullscreen && !formatWindowed.empty()) { label_.set_markup(fmt::format(fmt::runtime(formatWindowed), workspace_.windows)); + } else if (workspace_.hasfullscreen && !formatFullscreen.empty()) { + label_.set_markup(fmt::format(fmt::runtime(formatFullscreen), workspace_.windows)); } else if (!format.empty()) { label_.set_markup(fmt::format(fmt::runtime(format), workspace_.windows)); } else { @@ -136,4 +139,4 @@ void WindowCount::setClass(const std::string& classname, bool enable) { } } -} // namespace waybar::modules::hyprland \ No newline at end of file +} // namespace waybar::modules::hyprland From b82bcdb515b9b74cdd5f69745eac151e97439c39 Mon Sep 17 00:00:00 2001 From: Khiet Tam Nguyen Date: Sat, 24 Aug 2024 15:21:33 +1000 Subject: [PATCH 14/15] docs: updated documentation for windowcount.5.scd --- man/waybar-hyprland-windowcount.5.scd | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/man/waybar-hyprland-windowcount.5.scd b/man/waybar-hyprland-windowcount.5.scd index 0b6b2171..0ea7de09 100644 --- a/man/waybar-hyprland-windowcount.5.scd +++ b/man/waybar-hyprland-windowcount.5.scd @@ -15,7 +15,19 @@ Addressed by *hyprland/windowcount* *format*: ++ typeof: string ++ default: {} ++ - The format, how information should be displayed. On {} the current window count is displayed. + The format for how information should be displayed. On {} the current workspace window count is displayed. + +*format-empty*: ++ + typeof: string ++ + Override the format when the workspace contains no windows window + +*format-windowed*: ++ + typeof: string ++ + Override the format when the workspace contains no fullscreen windows + +*format-fullscreen*: ++ + typeof: string ++ + Override the format when the workspace contains a fullscreen window *separate-outputs*: ++ typeof: bool ++ From fd67c6e9157464207a22bcd4021d5c3d81234c75 Mon Sep 17 00:00:00 2001 From: Khiet Tam Nguyen Date: Sun, 25 Aug 2024 00:05:41 +1000 Subject: [PATCH 15/15] docs: rewording of separate-outputs in man page --- man/waybar-hyprland-windowcount.5.scd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/waybar-hyprland-windowcount.5.scd b/man/waybar-hyprland-windowcount.5.scd index 0ea7de09..6a4f87d1 100644 --- a/man/waybar-hyprland-windowcount.5.scd +++ b/man/waybar-hyprland-windowcount.5.scd @@ -32,7 +32,7 @@ Addressed by *hyprland/windowcount* *separate-outputs*: ++ typeof: bool ++ default: true ++ - Show the active window count of the monitor the bar belongs to, instead of the focused window. + Show the active workspace window count of the monitor the bar belongs to, instead of the focused workspace. # STYLE