From cbad42bc9bb42fb7d40ff9a7e843ec88eb2ba320 Mon Sep 17 00:00:00 2001 From: Austin Horstman Date: Sun, 5 Jul 2026 10:23:06 -0500 Subject: [PATCH 1/2] fix(wlr/taskbar): stop forcing tasks onto every output's bar hide_if_duplicate() unconditionally re-ran handle_output_enter() with the bar's own wl_output for every non-squashed task, so any app_id or title event made the task visible on all bars and "all-outputs": false was effectively ignored. The un-squash path in handle_closed() showed the replacement task unconditionally, with the same effect. Track whether the toplevel is actually on the bar's output from the protocol's output_enter/output_leave events, split the button show/hide logic out of the protocol handlers, and gate every synthetic re-show on all-outputs or the tracked output membership. Fixes #5178 --- include/modules/wlr/taskbar.hpp | 6 +++ src/modules/wlr/taskbar.cpp | 86 ++++++++++++++++++++------------- 2 files changed, 58 insertions(+), 34 deletions(-) diff --git a/include/modules/wlr/taskbar.hpp b/include/modules/wlr/taskbar.hpp index c4e56b14..74269320 100644 --- a/include/modules/wlr/taskbar.hpp +++ b/include/modules/wlr/taskbar.hpp @@ -71,6 +71,10 @@ class Task { bool button_visible_ = false; bool ignored_ = false; bool squashed_ = false; + /* Whether the toplevel is on this bar's output, per the protocol's + * output_enter/output_leave events */ + bool on_bar_output_ = false; + bool size_allocate_connected_ = false; bool with_icon_ = false; bool with_name_ = false; @@ -96,6 +100,8 @@ class Task { void on_button_size_allocated(Gtk::Allocation& alloc); void hide_if_ignored(); void hide_if_duplicate(); + void show_button(); + void hide_button(); public: /* Getter functions */ diff --git a/src/modules/wlr/taskbar.cpp b/src/modules/wlr/taskbar.cpp index 4517aec4..1bba7dd8 100644 --- a/src/modules/wlr/taskbar.cpp +++ b/src/modules/wlr/taskbar.cpp @@ -278,25 +278,18 @@ void Task::hide_if_duplicate() { // Squashes if the app is in the squash list and more than 1 instance is open if (contains_app && (tbar_->task_id_count(app_id_) > 1 || tbar_->task_title_count(title_) > 1)) { squashed_ = true; - if (button_visible_) { - auto output = gdk_wayland_monitor_get_wl_output(bar_.output->monitor->gobj()); - handle_output_leave(output); - } + hide_button(); } - if (!squashed_ && !ignored_) { - auto output = gdk_wayland_monitor_get_wl_output(bar_.output->monitor->gobj()); - handle_output_enter(output); + if (!squashed_ && !ignored_ && (tbar_->all_outputs() || on_bar_output_)) { + show_button(); } } void Task::hide_if_ignored() { if (tbar_->ignore_list().count(app_id_) || tbar_->ignore_list().count(title_)) { ignored_ = true; - if (button_visible_) { - auto output = gdk_wayland_monitor_get_wl_output(bar_.output->monitor->gobj()); - handle_output_leave(output); - } + hide_button(); } if (!ignored_ && !squashed_) { @@ -353,6 +346,12 @@ void Task::on_button_size_allocated(Gtk::Allocation& alloc) { } void Task::handle_output_enter(struct wl_output* output) { + spdlog::debug("{} entered output {}", repr(), (void*)output); + + if (tbar_->show_output(output)) { + on_bar_output_ = true; + } + if (ignored_) { spdlog::debug("{} is ignored", repr()); return; @@ -362,33 +361,52 @@ void Task::handle_output_enter(struct wl_output* output) { return; } - spdlog::debug("{} entered output {}", repr(), (void*)output); - - if (!button_visible_ && (tbar_->all_outputs() || tbar_->show_output(output))) { - /* The task entered the output of the current bar make the button visible */ - button.signal_size_allocate().connect_notify( - sigc::mem_fun(this, &Task::on_button_size_allocated)); - tbar_->add_button(button); - if (!config_["active-only"].asBool() || active()) { - button.show(); - } - button_visible_ = true; - spdlog::debug("{} now visible on {}", repr(), bar_.output->name); - tbar_->update_bar_css_classes(); + if (tbar_->all_outputs() || on_bar_output_) { + /* The task entered the output of the current bar, make the button visible */ + show_button(); } } void Task::handle_output_leave(struct wl_output* output) { spdlog::debug("{} left output {}", repr(), (void*)output); - if (button_visible_ && !tbar_->all_outputs() && tbar_->show_output(output)) { - /* The task left the output of the current bar, make the button invisible */ - tbar_->remove_button(button); - button.hide(); - button_visible_ = false; - spdlog::debug("{} now invisible on {}", repr(), bar_.output->name); - tbar_->update_bar_css_classes(); + if (tbar_->show_output(output)) { + on_bar_output_ = false; } + + if (!tbar_->all_outputs() && !on_bar_output_) { + /* The task left the output of the current bar, make the button invisible */ + hide_button(); + } +} + +void Task::show_button() { + if (button_visible_) { + return; + } + if (!size_allocate_connected_) { + button.signal_size_allocate().connect_notify( + sigc::mem_fun(this, &Task::on_button_size_allocated)); + size_allocate_connected_ = true; + } + tbar_->add_button(button); + if (!config_["active-only"].asBool() || active()) { + button.show(); + } + button_visible_ = true; + spdlog::debug("{} now visible on {}", repr(), bar_.output->name); + tbar_->update_bar_css_classes(); +} + +void Task::hide_button() { + if (!button_visible_) { + return; + } + tbar_->remove_button(button); + button.hide(); + button_visible_ = false; + spdlog::debug("{} now invisible on {}", repr(), bar_.output->name); + tbar_->update_bar_css_classes(); } void Task::handle_state(struct wl_array* state) { @@ -474,9 +492,9 @@ void Task::handle_closed() { if (it != tasks.end() && !(*it).ignored_) { Task& task = *it; task.squashed_ = false; - tbar_->add_button(task.button); - task.button.show(); - task.button_visible_ = true; + if (tbar_->all_outputs() || task.on_bar_output_) { + task.show_button(); + } } } From ebbc7ea4dc8ab397704ec6dc25e3ebd6ce16a4bf Mon Sep 17 00:00:00 2001 From: Austin Horstman Date: Sun, 5 Jul 2026 10:23:58 -0500 Subject: [PATCH 2/2] fix(wlr/taskbar): re-show task when it no longer matches ignore-list The un-ignore branch in hide_if_ignored() computed is_was_ignored after the enclosing condition already required ignored_ to be false, so it never ran, and a task whose app_id/title changed away from an ignore-list entry stayed hidden forever. Reset ignored_ and show the button again, subject to the same all-outputs/output-membership check used everywhere else. --- src/modules/wlr/taskbar.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/modules/wlr/taskbar.cpp b/src/modules/wlr/taskbar.cpp index 1bba7dd8..34960624 100644 --- a/src/modules/wlr/taskbar.cpp +++ b/src/modules/wlr/taskbar.cpp @@ -290,14 +290,14 @@ void Task::hide_if_ignored() { if (tbar_->ignore_list().count(app_id_) || tbar_->ignore_list().count(title_)) { ignored_ = true; hide_button(); + return; } - if (!ignored_ && !squashed_) { - bool is_was_ignored = ignored_; + if (ignored_) { + /* The app_id/title changed to a value that is no longer ignored */ ignored_ = false; - if (is_was_ignored) { - auto output = gdk_wayland_monitor_get_wl_output(bar_.output->monitor->gobj()); - handle_output_enter(output); + if (!squashed_ && (tbar_->all_outputs() || on_bar_output_)) { + show_button(); } } }