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
This commit is contained in:
Austin Horstman
2026-07-05 10:23:06 -05:00
parent bf59a21815
commit cbad42bc9b
2 changed files with 58 additions and 34 deletions
+6
View File
@@ -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 */
+42 -24
View File
@@ -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,12 +361,34 @@ void Task::handle_output_enter(struct wl_output* output) {
return;
}
spdlog::debug("{} entered output {}", repr(), (void*)output);
if (tbar_->all_outputs() || on_bar_output_) {
/* The task entered the output of the current bar, make the button visible */
show_button();
}
}
if (!button_visible_ && (tbar_->all_outputs() || tbar_->show_output(output))) {
/* The task entered the output of the current bar make the button visible */
void Task::handle_output_leave(struct wl_output* output) {
spdlog::debug("{} left output {}", repr(), (void*)output);
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();
@@ -375,20 +396,17 @@ void Task::handle_output_enter(struct wl_output* output) {
button_visible_ = true;
spdlog::debug("{} now visible on {}", repr(), bar_.output->name);
tbar_->update_bar_css_classes();
}
}
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 */
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();
}
}
}