From 85aac3fee7e8eea8bb359febfec79eed4dd668a2 Mon Sep 17 00:00:00 2001 From: mike b Date: Thu, 11 Dec 2025 14:46:32 -0500 Subject: [PATCH] feature to limit the number of icons displayed --- include/modules/hyprland/workspaces.hpp | 2 + man/waybar-hyprland-workspaces.5.scd | 5 +++ src/modules/hyprland/workspace.cpp | 59 +++++++++++++++++-------- src/modules/hyprland/workspaces.cpp | 3 ++ subprojects/.wraplock | 0 5 files changed, 50 insertions(+), 19 deletions(-) create mode 100644 subprojects/.wraplock diff --git a/include/modules/hyprland/workspaces.hpp b/include/modules/hyprland/workspaces.hpp index a5d94bbf..bb0d27f4 100644 --- a/include/modules/hyprland/workspaces.hpp +++ b/include/modules/hyprland/workspaces.hpp @@ -50,6 +50,7 @@ class Workspaces : public AModule, public EventHandler { auto taskbarFormatBefore() const -> std::string { return m_taskbarFormatBefore; } auto taskbarFormatAfter() const -> std::string { return m_taskbarFormatAfter; } auto taskbarIconSize() const -> int { return m_taskbarIconSize; } + auto taskbarMaxIcons() const -> int { return m_taskbarMaxIcons; } auto taskbarOrientation() const -> Gtk::Orientation { return m_taskbarOrientation; } auto taskbarReverseDirection() const -> bool { return m_taskbarReverseDirection; } auto onClickWindow() const -> std::string { return m_onClickWindow; } @@ -186,6 +187,7 @@ class Workspaces : public AModule, public EventHandler { std::string m_taskbarFormatBefore; std::string m_taskbarFormatAfter; int m_taskbarIconSize = 16; + int m_taskbarMaxIcons = 0; // 0 means unlimited Gtk::Orientation m_taskbarOrientation = Gtk::ORIENTATION_HORIZONTAL; bool m_taskbarReverseDirection = false; util::EnumParser m_activeWindowEnumParser; diff --git a/man/waybar-hyprland-workspaces.5.scd b/man/waybar-hyprland-workspaces.5.scd index 1d04157b..1aed0787 100644 --- a/man/waybar-hyprland-workspaces.5.scd +++ b/man/waybar-hyprland-workspaces.5.scd @@ -75,6 +75,11 @@ This setting is ignored if *workspace-taskbar.enable* is set to true. default: 16 ++ Size of the icons in the workspace taskbar. + *max-icons*: ++ + typeof: int ++ + default: 0 (unlimited) ++ + Maximum number of icons to show per workspace. When set, duplicate icons (windows with the same class) are removed first, then the list is trimmed to this limit. Set to 0 for unlimited icons. + *icon-theme*: ++ typeof: string | array ++ default: [] ++ diff --git a/src/modules/hyprland/workspace.cpp b/src/modules/hyprland/workspace.cpp index ae66bc84..c14a8545 100644 --- a/src/modules/hyprland/workspace.cpp +++ b/src/modules/hyprland/workspace.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -286,11 +287,41 @@ void Workspace::updateTaskbar(const std::string &workspace_icon) { } } - bool isFirst = true; - auto processWindow = [&](const WindowRepr &window_repr) { + // Build a list of windows to display, removing duplicates by window_class + // and respecting max-icons limit + std::vector windowsToShow; + std::set seenClasses; + + auto addWindowIfUnique = [&](const WindowRepr &window_repr) { if (shouldSkipWindow(window_repr)) { - return; // skip + return; } + // Deduplicate by window_class + if (seenClasses.find(window_repr.window_class) != seenClasses.end()) { + return; + } + seenClasses.insert(window_repr.window_class); + windowsToShow.push_back(&window_repr); + }; + + if (m_workspaceManager.taskbarReverseDirection()) { + for (auto it = m_windowMap.rbegin(); it != m_windowMap.rend(); ++it) { + addWindowIfUnique(*it); + } + } else { + for (const auto &window_repr : m_windowMap) { + addWindowIfUnique(window_repr); + } + } + + // Apply max-icons limit if configured + int maxIcons = m_workspaceManager.taskbarMaxIcons(); + if (maxIcons > 0 && static_cast(windowsToShow.size()) > maxIcons) { + windowsToShow.resize(maxIcons); + } + + bool isFirst = true; + for (const auto *window_repr : windowsToShow) { if (isFirst) { isFirst = false; } else if (m_workspaceManager.getWindowSeparator() != "") { @@ -300,27 +331,27 @@ void Workspace::updateTaskbar(const std::string &workspace_icon) { } auto window_box = Gtk::make_managed(Gtk::ORIENTATION_HORIZONTAL); - window_box->set_tooltip_text(window_repr.window_title); + window_box->set_tooltip_text(window_repr->window_title); window_box->get_style_context()->add_class("taskbar-window"); - if (window_repr.isActive) { + if (window_repr->isActive) { window_box->get_style_context()->add_class("active"); } auto event_box = Gtk::manage(new Gtk::EventBox()); event_box->add(*window_box); if (m_workspaceManager.onClickWindow() != "") { event_box->signal_button_press_event().connect( - sigc::bind(sigc::mem_fun(*this, &Workspace::handleClick), window_repr.address)); + sigc::bind(sigc::mem_fun(*this, &Workspace::handleClick), window_repr->address)); } auto text_before = fmt::format(fmt::runtime(m_workspaceManager.taskbarFormatBefore()), - fmt::arg("title", window_repr.window_title)); + fmt::arg("title", window_repr->window_title)); if (!text_before.empty()) { auto window_label_before = Gtk::make_managed(text_before); window_box->pack_start(*window_label_before, true, true); } if (m_workspaceManager.taskbarWithIcon()) { - auto app_info_ = IconLoader::get_app_info_from_app_id_list(window_repr.window_class); + auto app_info_ = IconLoader::get_app_info_from_app_id_list(window_repr->window_class); int icon_size = m_workspaceManager.taskbarIconSize(); auto window_icon = Gtk::make_managed(); m_workspaceManager.iconLoader().image_load_icon(*window_icon, app_info_, icon_size); @@ -328,7 +359,7 @@ void Workspace::updateTaskbar(const std::string &workspace_icon) { } auto text_after = fmt::format(fmt::runtime(m_workspaceManager.taskbarFormatAfter()), - fmt::arg("title", window_repr.window_title)); + fmt::arg("title", window_repr->window_title)); if (!text_after.empty()) { auto window_label_after = Gtk::make_managed(text_after); window_box->pack_start(*window_label_after, true, true); @@ -336,16 +367,6 @@ void Workspace::updateTaskbar(const std::string &workspace_icon) { m_content.pack_start(*event_box, true, false); event_box->show_all(); - }; - - if (m_workspaceManager.taskbarReverseDirection()) { - for (auto it = m_windowMap.rbegin(); it != m_windowMap.rend(); ++it) { - processWindow(*it); - } - } else { - for (const auto &window_repr : m_windowMap) { - processWindow(window_repr); - } } auto formatAfter = m_workspaceManager.formatAfter(); diff --git a/src/modules/hyprland/workspaces.cpp b/src/modules/hyprland/workspaces.cpp index 8360137f..1f29ac9b 100644 --- a/src/modules/hyprland/workspaces.cpp +++ b/src/modules/hyprland/workspaces.cpp @@ -756,6 +756,9 @@ auto Workspaces::populateWorkspaceTaskbarConfig(const Json::Value &config) -> vo if (workspaceTaskbar["icon-size"].isInt()) { m_taskbarIconSize = workspaceTaskbar["icon-size"].asInt(); } + if (workspaceTaskbar["max-icons"].isInt()) { + m_taskbarMaxIcons = workspaceTaskbar["max-icons"].asInt(); + } if (workspaceTaskbar["orientation"].isString() && toLower(workspaceTaskbar["orientation"].asString()) == "vertical") { m_taskbarOrientation = Gtk::ORIENTATION_VERTICAL; diff --git a/subprojects/.wraplock b/subprojects/.wraplock new file mode 100644 index 00000000..e69de29b