diff --git a/src/handlers/layer_shell.rs b/src/handlers/layer_shell.rs index e0f1084f5e..70313c2866 100644 --- a/src/handlers/layer_shell.rs +++ b/src/handlers/layer_shell.rs @@ -27,7 +27,11 @@ impl WlrLayerShellHandler for State { namespace: String, ) { let output = if let Some(wl_output) = &wl_output { + // There might be a race where a client sends an already removed output. + // So instead of just accepting the output check the output against the + // known outputs. Output::from_resource(wl_output) + .filter(|output| self.niri.layout.outputs().any(|o| o == output)) } else { self.niri.layout.active_output().cloned() }; diff --git a/src/niri.rs b/src/niri.rs index 414f702d80..88a3749888 100644 --- a/src/niri.rs +++ b/src/niri.rs @@ -2825,6 +2825,25 @@ impl Niri { } pub fn remove_output(&mut self, output: &Output) { + let state = self.output_state.remove(output).unwrap(); + + // Disable the output global and remove some time later to give the clients some time to + // process it. + let global = state.global; + self.display_handle.disable_global::(global.clone()); + self.event_loop + .insert_source( + Timer::from_duration(Duration::from_secs(10)), + move |_, _, state| { + state + .niri + .display_handle + .remove_global::(global.clone()); + TimeoutAction::Drop + }, + ) + .unwrap(); + for layer in layer_map_for_output(output).layers() { layer.layer_surface().send_close(); } @@ -2834,8 +2853,6 @@ impl Niri { self.reposition_outputs(None); self.gamma_control_manager_state.output_removed(output); - let state = self.output_state.remove(output).unwrap(); - match state.redraw_state { RedrawState::Idle => (), RedrawState::Queued => (), @@ -2847,23 +2864,6 @@ impl Niri { self.stop_casts_for_target(CastTarget::output(output)); self.screencopy_state.remove_output(output); - // Disable the output global and remove some time later to give the clients some time to - // process it. - let global = state.global; - self.display_handle.disable_global::(global.clone()); - self.event_loop - .insert_source( - Timer::from_duration(Duration::from_secs(10)), - move |_, _, state| { - state - .niri - .display_handle - .remove_global::(global.clone()); - TimeoutAction::Drop - }, - ) - .unwrap(); - match mem::take(&mut self.lock_state) { LockState::Locking(confirmation) => { // We're locking and an output was removed, check if the requirements are now met.