From a2f03129628bcdcba54cb13d8b2384ce80b1f31a Mon Sep 17 00:00:00 2001 From: Andrej Novikov Date: Thu, 18 Dec 2025 17:06:30 +0200 Subject: [PATCH] feat(hyprland/workspaces): add deduplicate-windows option Add a new configuration option 'deduplicate-windows' that filters duplicate application entries from workspace window lists. When enabled, this feature tracks seen window representations and skips duplicates based on their rewritten representation (after window-rewrite rules are applied). The deduplication works for both display modes: - Regular {windows} format string substitution - Workspace taskbar feature This is useful when multiple windows of the same application appear in a workspace and users prefer to see only unique entries. Usage: "hyprland/workspaces": { "deduplicate-windows": true } --- include/modules/hyprland/workspaces.hpp | 2 ++ src/modules/hyprland/workspace.cpp | 18 ++++++++++++++++++ src/modules/hyprland/workspaces.cpp | 1 + 3 files changed, 21 insertions(+) diff --git a/include/modules/hyprland/workspaces.hpp b/include/modules/hyprland/workspaces.hpp index a5d94bbf7..28d7e8c99 100644 --- a/include/modules/hyprland/workspaces.hpp +++ b/include/modules/hyprland/workspaces.hpp @@ -41,6 +41,7 @@ class Workspaces : public AModule, public EventHandler { auto specialVisibleOnly() const -> bool { return m_specialVisibleOnly; } auto persistentOnly() const -> bool { return m_persistentOnly; } auto moveToMonitor() const -> bool { return m_moveToMonitor; } + auto deduplicateWindows() const -> bool { return m_deduplicateWindows; } auto enableTaskbar() const -> bool { return m_enableTaskbar; } auto taskbarWithIcon() const -> bool { return m_taskbarWithIcon; } @@ -145,6 +146,7 @@ class Workspaces : public AModule, public EventHandler { bool m_specialVisibleOnly = false; bool m_persistentOnly = false; bool m_moveToMonitor = false; + bool m_deduplicateWindows = false; Json::Value m_persistentWorkspaceConfig; // Map for windows stored in workspaces not present in the current bar. diff --git a/src/modules/hyprland/workspace.cpp b/src/modules/hyprland/workspace.cpp index ae66bc845..753f6e95d 100644 --- a/src/modules/hyprland/workspace.cpp +++ b/src/modules/hyprland/workspace.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -247,8 +248,18 @@ void Workspace::update(const std::string &workspace_icon) { auto windowSeparator = m_workspaceManager.getWindowSeparator(); bool isNotFirst = false; + std::set seenWindows; for (const auto &window_repr : m_windowMap) { + if (shouldSkipWindow(window_repr)) { + continue; + } + if (m_workspaceManager.deduplicateWindows()) { + if (seenWindows.contains(window_repr.repr_rewrite)) { + continue; // skip duplicate + } + seenWindows.insert(window_repr.repr_rewrite); + } if (isNotFirst) { windows.append(windowSeparator); } @@ -287,10 +298,17 @@ void Workspace::updateTaskbar(const std::string &workspace_icon) { } bool isFirst = true; + std::set seenWindows; auto processWindow = [&](const WindowRepr &window_repr) { if (shouldSkipWindow(window_repr)) { return; // skip } + if (m_workspaceManager.deduplicateWindows()) { + if (seenWindows.contains(window_repr.repr_rewrite)) { + return; // skip duplicate + } + seenWindows.insert(window_repr.repr_rewrite); + } if (isFirst) { isFirst = false; } else if (m_workspaceManager.getWindowSeparator() != "") { diff --git a/src/modules/hyprland/workspaces.cpp b/src/modules/hyprland/workspaces.cpp index 8360137f4..d1c654edd 100644 --- a/src/modules/hyprland/workspaces.cpp +++ b/src/modules/hyprland/workspaces.cpp @@ -631,6 +631,7 @@ auto Workspaces::parseConfig(const Json::Value &config) -> void { populateBoolConfig(config, "persistent-only", m_persistentOnly); populateBoolConfig(config, "active-only", m_activeOnly); populateBoolConfig(config, "move-to-monitor", m_moveToMonitor); + populateBoolConfig(config, "deduplicate-windows", m_deduplicateWindows); m_persistentWorkspaceConfig = config.get("persistent-workspaces", Json::Value()); populateSortByConfig(config);