From eee0362367be8a574b2e9fcd9faa7d594248527e Mon Sep 17 00:00:00 2001 From: Jason Chiu Date: Wed, 17 Sep 2025 22:09:49 +0000 Subject: [PATCH 1/9] Fix clang build error --- src/modules/clock.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/clock.cpp b/src/modules/clock.cpp index a7d57437..e4c48207 100644 --- a/src/modules/clock.cpp +++ b/src/modules/clock.cpp @@ -375,7 +375,7 @@ auto waybar::modules::Clock::get_calendar(const year_month_day& today, const yea } } os << Glib::ustring::format( - (cldWPos_ != WS::LEFT || line == 0) ? std::left : std::right, std::setfill(L' '), + (cldWPos_ != WS::LEFT || line == 0) ? std::left : std::right, std::setfill(' '), std::setw(cldMonColLen_ + ((line < 2) ? cldWnLen_ - wideCharCount : 0)), calendarLine); From c62e987dbd4f8e402f625cdd61cfc2c9dd3c376f Mon Sep 17 00:00:00 2001 From: Visal Vijay <150381094+B2krobbery@users.noreply.github.com> Date: Thu, 19 Mar 2026 01:22:34 +0530 Subject: [PATCH 2/9] Update waybar.5.scd.in --- man/waybar.5.scd.in | 1 + 1 file changed, 1 insertion(+) diff --git a/man/waybar.5.scd.in b/man/waybar.5.scd.in index 624798ed..7223daec 100644 --- a/man/waybar.5.scd.in +++ b/man/waybar.5.scd.in @@ -168,6 +168,7 @@ The visual display elements for waybar use a CSS stylesheet, see *waybar-styles( # MODULE FORMAT You can use PangoMarkupFormat (See https://developer.gnome.org/pango/stable/PangoMarkupFormat.html#PangoMarkupFormat). +Note: Tooltip appearance in Waybar is controlled globally via CSS (e.g., `tooltip { ... }`). It is currently not possible to apply tooltip styles per module. e.g. From d2aad467a7b888e3b0e65be6d44a258433822407 Mon Sep 17 00:00:00 2001 From: Visal Vijay <150381094+B2krobbery@users.noreply.github.com> Date: Sat, 21 Mar 2026 23:12:36 +0530 Subject: [PATCH 3/9] Update waybar.5.scd.in --- man/waybar.5.scd.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/waybar.5.scd.in b/man/waybar.5.scd.in index 7223daec..80628285 100644 --- a/man/waybar.5.scd.in +++ b/man/waybar.5.scd.in @@ -168,7 +168,7 @@ The visual display elements for waybar use a CSS stylesheet, see *waybar-styles( # MODULE FORMAT You can use PangoMarkupFormat (See https://developer.gnome.org/pango/stable/PangoMarkupFormat.html#PangoMarkupFormat). -Note: Tooltip appearance in Waybar is controlled globally via CSS (e.g., `tooltip { ... }`). It is currently not possible to apply tooltip styles per module. +Tooltip appearance is generally controlled globally via CSS and cannot be truly scoped per module. Some modules (such as the clock) provide limited workarounds for customization. e.g. From a8a46d1f1e1834e652bdeff9640e98b5ab36eb25 Mon Sep 17 00:00:00 2001 From: Visal Vijay Date: Thu, 9 Apr 2026 19:40:05 +0530 Subject: [PATCH 4/9] Refactor: simplify complex conditional expressions in Hyprland workspace module --- src/modules/hyprland/workspace.cpp | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/modules/hyprland/workspace.cpp b/src/modules/hyprland/workspace.cpp index 21e7ef9b..da383aa5 100644 --- a/src/modules/hyprland/workspace.cpp +++ b/src/modules/hyprland/workspace.cpp @@ -115,7 +115,11 @@ void Workspace::setActiveWindow(WindowAddress const& addr) { } auto activeWindowPos = m_workspaceManager.activeWindowPosition(); - if (activeIdx.has_value() && activeWindowPos != Workspaces::ActiveWindowPosition::NONE) { + const bool has_active_window = + activeIdx.has_value() && + activeWindowPos != Workspaces::ActiveWindowPosition::NONE; + + if (has_active_window) { auto window = std::move(m_windowMap[*activeIdx]); m_windowMap.erase(m_windowMap.begin() + *activeIdx); if (activeWindowPos == Workspaces::ActiveWindowPosition::FIRST) { @@ -130,7 +134,10 @@ void Workspace::insertWindow(WindowCreationPayload create_window_payload) { if (!create_window_payload.isEmpty(m_workspaceManager)) { auto repr = create_window_payload.repr(m_workspaceManager); - if (!repr.empty() || m_workspaceManager.enableTaskbar()) { + const bool should_display = + !repr.empty() || m_workspaceManager.enableTaskbar(); + + if (should_display) { auto addr = create_window_payload.getAddress(); auto it = std::ranges::find_if( m_windowMap, [&addr](const auto& window) { return window.address == addr; }); @@ -142,7 +149,7 @@ void Workspace::insertWindow(WindowCreationPayload create_window_payload) { } } } -}; +} bool Workspace::onWindowOpened(WindowCreationPayload const& create_window_payload) { if (create_window_payload.getWorkspaceName() == name()) { @@ -270,7 +277,9 @@ void Workspace::update(const std::string& workspace_icon) { bool Workspace::isEmpty() const { auto ignore_list = m_workspaceManager.getIgnoredWindows(); - if (ignore_list.empty()) { + const bool no_ignore_rules = ignore_list.empty(); + + if (no_ignore_rules) { return m_windows == 0; } // If there are windows but they are all ignored, consider the workspace empty @@ -349,7 +358,9 @@ void Workspace::updateTaskbar(const std::string& workspace_icon) { } auto formatAfter = m_workspaceManager.formatAfter(); - if (!formatAfter.empty()) { + const bool has_format_after = !formatAfter.empty(); + + if (has_format_after) { m_labelAfter.set_markup(fmt::format(fmt::runtime(formatAfter), fmt::arg("id", id()), fmt::arg("name", name()), fmt::arg("icon", workspace_icon))); From fcf1fb798cf9674761a4d83a5c11ff15213e2006 Mon Sep 17 00:00:00 2001 From: Ezequiel Colunga Acha Date: Wed, 20 May 2026 15:06:41 -0300 Subject: [PATCH 5/9] fix(wlr/taskbar): let task titles shrink within available space The taskbar currently requests enough width for every task title, which can push right-side modules off-screen when many windows are open. Allow task buttons to share the taskbar allocation and ellipsize title labels instead of forcing the whole module to grow. This keeps neighboring modules visible while preserving the existing taskbar click actions and formatting behavior. Co-authored-by: Cursor --- src/modules/wlr/taskbar.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/modules/wlr/taskbar.cpp b/src/modules/wlr/taskbar.cpp index bde90910..6ba41ce3 100644 --- a/src/modules/wlr/taskbar.cpp +++ b/src/modules/wlr/taskbar.cpp @@ -93,10 +93,20 @@ Task::Task(const waybar::Bar& bar, const Json::Value& config, Taskbar* tbar, zwlr_foreign_toplevel_handle_v1_add_listener(handle_, &toplevel_handle_impl, this); button.set_relief(Gtk::RELIEF_NONE); + button.set_hexpand(true); + content_.set_hexpand(true); + text_before_.set_ellipsize(Pango::ELLIPSIZE_END); + text_before_.set_single_line_mode(true); + text_before_.set_width_chars(1); + text_before_.set_xalign(0.0); + text_after_.set_ellipsize(Pango::ELLIPSIZE_END); + text_after_.set_single_line_mode(true); + text_after_.set_width_chars(1); + text_after_.set_xalign(0.0); - content_.add(text_before_); - content_.add(icon_); - content_.add(text_after_); + content_.pack_start(text_before_, true, true, 0); + content_.pack_start(icon_, false, false, 0); + content_.pack_start(text_after_, true, true, 0); content_.show(); button.add(content_); @@ -718,7 +728,7 @@ void Taskbar::handle_finished() { } void Taskbar::add_button(Gtk::Button& bt) { - box_.pack_start(bt, false, false); + box_.pack_start(bt, true, true); box_.get_style_context()->remove_class("empty"); } From 2190871a68730d52cd0e0ce7e2ed959e11c23ead Mon Sep 17 00:00:00 2001 From: Alexey Ivanov Date: Thu, 4 Jun 2026 15:18:43 -0700 Subject: [PATCH 6/9] perf(label): skip redundant markup updates --- include/ALabel.hpp | 9 +++++++++ src/ALabel.cpp | 20 ++++++++++++++++++++ src/modules/mpd/mpd.cpp | 8 ++++---- src/modules/sway/window.cpp | 4 ++-- 4 files changed, 35 insertions(+), 6 deletions(-) diff --git a/include/ALabel.hpp b/include/ALabel.hpp index b3852877..7c5150a0 100644 --- a/include/ALabel.hpp +++ b/include/ALabel.hpp @@ -4,6 +4,8 @@ #include #include +#include + #include "AModule.hpp" namespace waybar { @@ -25,12 +27,19 @@ class ALabel : public AModule { bool alt_ = false; std::string default_format_; + bool setLabelMarkup(const Glib::ustring& markup); + bool setTooltipMarkup(const Glib::ustring& markup); + bool handleToggle(GdkEventButton* const& e) override; virtual std::string getState(uint8_t value, bool lesser = false); std::map submenus_; std::map menuActionsMap_; static void handleGtkMenuEvent(GtkMenuItem* menuitem, gpointer data); + + private: + std::optional last_label_markup_; + std::optional last_tooltip_markup_; }; } // namespace waybar diff --git a/src/ALabel.cpp b/src/ALabel.cpp index 795f87f1..f2a585fe 100644 --- a/src/ALabel.cpp +++ b/src/ALabel.cpp @@ -139,6 +139,26 @@ ALabel::ALabel(const Json::Value& config, const std::string& name, const std::st auto ALabel::update() -> void { AModule::update(); } +bool ALabel::setLabelMarkup(const Glib::ustring& markup) { + if (last_label_markup_ == markup) { + return false; + } + + label_.set_markup(markup); + last_label_markup_ = markup; + return true; +} + +bool ALabel::setTooltipMarkup(const Glib::ustring& markup) { + if (last_tooltip_markup_ == markup) { + return false; + } + + label_.set_tooltip_markup(markup); + last_tooltip_markup_ = markup; + return true; +} + std::string ALabel::getIcon(uint16_t percentage, const std::string& alt, uint16_t max) { auto format_icons = config_["format-icons"]; if (format_icons.isObject()) { diff --git a/src/modules/mpd/mpd.cpp b/src/modules/mpd/mpd.cpp index 9874f458..873b6251 100644 --- a/src/modules/mpd/mpd.cpp +++ b/src/modules/mpd/mpd.cpp @@ -98,7 +98,7 @@ void waybar::modules::MPD::setLabel() { ? config_["format-disconnected"].asString() : "disconnected"; if (format.empty()) { - label_.set_markup(format); + setLabelMarkup(format); label_.show(); } else { label_.hide(); @@ -110,7 +110,7 @@ void waybar::modules::MPD::setLabel() { ? config_["tooltip-format-disconnected"].asString() : "MPD (disconnected)"; // Nothing to format - label_.set_tooltip_markup(tooltip_format); + setTooltipMarkup(tooltip_format); } return; } @@ -190,7 +190,7 @@ void waybar::modules::MPD::setLabel() { label_.hide(); } else { label_.show(); - label_.set_markup(text); + setLabelMarkup(text); } } catch (fmt::format_error const& e) { spdlog::warn("mpd: format error: {}", e.what()); @@ -210,7 +210,7 @@ void waybar::modules::MPD::setLabel() { fmt::arg("stateIcon", stateIcon), fmt::arg("consumeIcon", consumeIcon), fmt::arg("randomIcon", randomIcon), fmt::arg("repeatIcon", repeatIcon), fmt::arg("singleIcon", singleIcon), fmt::arg("filename", filename), fmt::arg("uri", uri)); - label_.set_tooltip_markup(tooltip_text); + setTooltipMarkup(tooltip_text); } catch (fmt::format_error const& e) { spdlog::warn("mpd: format error (tooltip): {}", e.what()); } diff --git a/src/modules/sway/window.cpp b/src/modules/sway/window.cpp index 2908b85c..2b62da14 100644 --- a/src/modules/sway/window.cpp +++ b/src/modules/sway/window.cpp @@ -94,12 +94,12 @@ auto Window::update() -> void { old_app_id_ = app_id_; } - label_.set_markup(waybar::util::rewriteString( + setLabelMarkup(waybar::util::rewriteString( fmt::format(fmt::runtime(format_), fmt::arg("title", window_), fmt::arg("app_id", app_id_), fmt::arg("shell", shell_), fmt::arg("marks", marks_)), config_["rewrite"])); if (tooltipEnabled()) { - label_.set_tooltip_markup(window_); + setTooltipMarkup(window_); } updateAppIcon(); From 22ce5887835b87653ca6cdccdbc317ec69d7a6f0 Mon Sep 17 00:00:00 2001 From: Muhammed Sahin Date: Sat, 27 Jun 2026 17:18:52 +0200 Subject: [PATCH 7/9] Fallback formatting when format-paused is missing uses ALabel With the minimal change the paused state, if format-paused state is not set, will show the Alabel if the Alabel was active. --- src/modules/mpd/mpd.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/modules/mpd/mpd.cpp b/src/modules/mpd/mpd.cpp index 9874f458..80cb6559 100644 --- a/src/modules/mpd/mpd.cpp +++ b/src/modules/mpd/mpd.cpp @@ -137,8 +137,9 @@ void waybar::modules::MPD::setLabel() { label_.get_style_context()->add_class("playing"); label_.get_style_context()->remove_class("paused"); } else if (paused()) { - format = config_["format-paused"].isString() ? config_["format-paused"].asString() - : config_["format"].asString(); + if (config_["format-paused"].isString()) { + format = config_["format-paused"].asString(); + } label_.get_style_context()->add_class("paused"); label_.get_style_context()->remove_class("playing"); } From 488a75fadaa110c4a4fa16ab73fd3795d38829b3 Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 3 Jul 2026 21:39:48 +0200 Subject: [PATCH 8/9] fix(wlr/taskbar): gate title shrink/expand behind 'expand' option Only stretch buttons and ellipsize titles when the new boolean 'expand' option is enabled and the bar is horizontal. Restores the previous content-based sizing as the default and avoids truncating every title to an ellipsis on vertical bars. --- man/waybar-wlr-taskbar.5.scd | 5 ++++ src/modules/wlr/taskbar.cpp | 52 ++++++++++++++++++++++++++---------- 2 files changed, 43 insertions(+), 14 deletions(-) diff --git a/man/waybar-wlr-taskbar.5.scd b/man/waybar-wlr-taskbar.5.scd index af1ba97f..2aa26f3f 100644 --- a/man/waybar-wlr-taskbar.5.scd +++ b/man/waybar-wlr-taskbar.5.scd @@ -57,6 +57,11 @@ Addressed by *wlr/taskbar* default: false ++ If set to true, group tasks by their app_id. Cannot be used with 'active-first'. +*expand*: ++ + typeof: bool ++ + default: false ++ + If set to true, task buttons stretch to fill the available space in the taskbar and long titles are ellipsized to fit. Only takes effect on a horizontal bar; on a vertical bar the buttons keep their content-based size. If set to false, buttons are sized to their content. + *on-click*: ++ typeof: string ++ The action which should be triggered when clicking on the application button with the left mouse button. diff --git a/src/modules/wlr/taskbar.cpp b/src/modules/wlr/taskbar.cpp index 6ba41ce3..f382e1fc 100644 --- a/src/modules/wlr/taskbar.cpp +++ b/src/modules/wlr/taskbar.cpp @@ -93,20 +93,36 @@ Task::Task(const waybar::Bar& bar, const Json::Value& config, Taskbar* tbar, zwlr_foreign_toplevel_handle_v1_add_listener(handle_, &toplevel_handle_impl, this); button.set_relief(Gtk::RELIEF_NONE); - button.set_hexpand(true); - content_.set_hexpand(true); - text_before_.set_ellipsize(Pango::ELLIPSIZE_END); - text_before_.set_single_line_mode(true); - text_before_.set_width_chars(1); - text_before_.set_xalign(0.0); - text_after_.set_ellipsize(Pango::ELLIPSIZE_END); - text_after_.set_single_line_mode(true); - text_after_.set_width_chars(1); - text_after_.set_xalign(0.0); - content_.pack_start(text_before_, true, true, 0); - content_.pack_start(icon_, false, false, 0); - content_.pack_start(text_after_, true, true, 0); + /* When "expand" is enabled the buttons stretch to fill the taskbar and the + * titles ellipsize to fit within the available space. This only makes sense + * on a horizontal bar; on a vertical bar the box grows along the vertical + * axis, so ellipsizing/forcing width_chars(1) would truncate every title to + * "…". Keep the historical behavior (buttons sized to their content) as the + * default and when the bar is vertical. */ + bool expand = config_["expand"].isBool() && config_["expand"].asBool(); + bool horizontal = bar.orientation == Gtk::ORIENTATION_HORIZONTAL; + + if (expand && horizontal) { + button.set_hexpand(true); + content_.set_hexpand(true); + text_before_.set_ellipsize(Pango::ELLIPSIZE_END); + text_before_.set_single_line_mode(true); + text_before_.set_width_chars(1); + text_before_.set_xalign(0.0); + text_after_.set_ellipsize(Pango::ELLIPSIZE_END); + text_after_.set_single_line_mode(true); + text_after_.set_width_chars(1); + text_after_.set_xalign(0.0); + + content_.pack_start(text_before_, true, true, 0); + content_.pack_start(icon_, false, false, 0); + content_.pack_start(text_after_, true, true, 0); + } else { + content_.add(text_before_); + content_.add(icon_); + content_.add(text_after_); + } content_.show(); button.add(content_); @@ -728,7 +744,15 @@ void Taskbar::handle_finished() { } void Taskbar::add_button(Gtk::Button& bt) { - box_.pack_start(bt, true, true); + /* Only let the buttons expand to fill the taskbar when "expand" is enabled + * and the bar is horizontal (see the Task constructor for details). */ + bool expand = config_["expand"].isBool() && config_["expand"].asBool(); + bool horizontal = bar_.orientation == Gtk::ORIENTATION_HORIZONTAL; + if (expand && horizontal) { + box_.pack_start(bt, true, true); + } else { + box_.pack_start(bt, false, false); + } box_.get_style_context()->remove_class("empty"); } From 9ac3f9b95198408f8bb084f7fc900b29d4be900e Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 3 Jul 2026 21:41:10 +0200 Subject: [PATCH 9/9] clock: make calendar padding portable across FormatStream char types std::setfill is templated on the fill char type, which must match the Glib::ustring FormatStream's char type. That type is wchar_t with libstdc++/glibmm but char with libc++, so no fixed literal (' ' or L' ') compiles everywhere. The stream's default fill is already a space, so drop std::setfill entirely; std::setw/std::left/std::right are char-type-agnostic and keep the exact padding behavior. --- src/modules/clock.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/modules/clock.cpp b/src/modules/clock.cpp index 36581e51..97777667 100644 --- a/src/modules/clock.cpp +++ b/src/modules/clock.cpp @@ -402,8 +402,13 @@ auto waybar::modules::Clock::get_calendar(const year_month_day& today, const yea data = g_utf8_find_next_char(data, end); } } + // Note: the stream's default fill character is already a space (L' ' on + // libstdc++'s wide FormatStream, ' ' on libc++'s narrow one), so no + // std::setfill is needed. Passing std::setfill(' ')/std::setfill(L' ') + // here is not portable because the fill char type must match the + // FormatStream's char type, which differs between standard libraries. os << Glib::ustring::format( - (cldWPos_ != WS::LEFT || line == 0) ? std::left : std::right, std::setfill(' '), + (cldWPos_ != WS::LEFT || line == 0) ? std::left : std::right, std::setw(cldMonColLen_ + ((line < 2) ? cldWnLen_ - wideCharCount : 0)), calendarLine);