workspace: Fix race between binding wl_output and output_enter

https://github.com/pop-os/cosmic-comp/pull/668 previously did this for
toplevel events, but missed the fact that the workspaces protocol has
the same issue.

Fixes https://github.com/pop-os/cosmic-workspaces-epoch/issues/61.
This commit is contained in:
Ian Douglas Scott 2025-01-27 14:15:59 -08:00 • committed by Ian Douglas Scott
parent 605bb63a4d
commit 7822030e0b

View file

@ -6,6 +6,7 @@ use smithay::{
output::Output, output::Output,
reexports::wayland_server::{ reexports::wayland_server::{
backend::{ClientData, ClientId, GlobalId, ObjectId}, backend::{ClientData, ClientId, GlobalId, ObjectId},
protocol::wl_output::WlOutput,
Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New, Resource, Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New, Resource,
}, },
}; };
@ -70,6 +71,7 @@ pub struct WorkspaceGroupHandle {
#[derive(Default)] #[derive(Default)]
pub struct WorkspaceGroupDataInner { pub struct WorkspaceGroupDataInner {
outputs: Vec<Output>, outputs: Vec<Output>,
wl_outputs: HashSet<WlOutput>,
capabilities: Vec<GroupCapabilities>, capabilities: Vec<GroupCapabilities>,
workspace_count: usize, workspace_count: usize,
} }
@ -905,26 +907,25 @@ where
.unwrap(); .unwrap();
let mut changed = false; let mut changed = false;
if let Ok(client) = dh.get_client(instance.id()) { if let Ok(client) = dh.get_client(instance.id()) {
for new_output in group for output in &group.outputs {
.outputs for wl_output in output.client_outputs(&client) {
.iter() if handle_state.wl_outputs.insert(wl_output.clone()) {
.filter(|o| !handle_state.outputs.contains(o)) instance.output_enter(&wl_output);
{ changed = true;
for wl_output in new_output.client_outputs(&client) { }
instance.output_enter(&wl_output);
} }
changed = true;
} }
for old_output in handle_state
.outputs handle_state.wl_outputs.retain(|wl_output| {
.iter() let retain =
.filter(|o| !group.outputs.contains(o)) wl_output.is_alive() && group.outputs.iter().any(|output| output.owns(wl_output));
{ if !retain {
for wl_output in old_output.client_outputs(&client) {
instance.output_leave(&wl_output); instance.output_leave(&wl_output);
changed = true;
} }
changed = true; retain
} });
handle_state.outputs = group.outputs.clone(); handle_state.outputs = group.outputs.clone();
} }