diff --git a/src/state.rs b/src/state.rs index fc2ba06e..ce3b456f 100644 --- a/src/state.rs +++ b/src/state.rs @@ -499,7 +499,8 @@ impl State { let fractional_scale_state = FractionalScaleManagerState::new::(dh); let keyboard_shortcuts_inhibit_state = KeyboardShortcutsInhibitState::new::(dh); let output_state = OutputManagerState::new_with_xdg_output::(dh); - let output_configuration_state = OutputConfigurationState::new(dh, client_is_privileged); + let output_configuration_state = + OutputConfigurationState::new(dh, handle.clone(), client_is_privileged); let output_power_state = OutputPowerState::new::(dh, client_is_privileged); let overlap_notify_state = OverlapNotifyState::new::(dh, client_has_no_security_context); diff --git a/src/wayland/protocols/output_configuration/mod.rs b/src/wayland/protocols/output_configuration/mod.rs index a75c1d16..9cffb102 100644 --- a/src/wayland/protocols/output_configuration/mod.rs +++ b/src/wayland/protocols/output_configuration/mod.rs @@ -1,5 +1,9 @@ // SPDX-License-Identifier: GPL-3.0-only +use calloop::{ + timer::{TimeoutAction, Timer}, + LoopHandle, +}; use cosmic_protocols::output_management::v1::server::{ zcosmic_output_configuration_head_v1::ZcosmicOutputConfigurationHeadV1, zcosmic_output_configuration_v1::ZcosmicOutputConfigurationV1, @@ -25,7 +29,7 @@ use smithay::{ utils::{Logical, Physical, Point, Size, Transform}, wayland::output::WlOutputData, }; -use std::{convert::TryFrom, sync::Mutex}; +use std::{convert::TryFrom, sync::Mutex, time::Duration}; mod handlers; @@ -45,6 +49,7 @@ pub struct OutputConfigurationState { global: GlobalId, extension_global: GlobalId, dh: DisplayHandle, + event_loop_handle: LoopHandle<'static, D>, _dispatch: std::marker::PhantomData, } @@ -168,7 +173,11 @@ where + OutputConfigurationHandler + 'static, { - pub fn new(dh: &DisplayHandle, client_filter: F) -> OutputConfigurationState + pub fn new( + dh: &DisplayHandle, + event_loop_handle: LoopHandle<'static, D>, + client_filter: F, + ) -> OutputConfigurationState where F: for<'a> Fn(&'a Client) -> bool + Clone + Send + Sync + 'static, { @@ -194,6 +203,7 @@ where global, extension_global, dh: dh.clone(), + event_loop_handle: event_loop_handle.clone(), _dispatch: std::marker::PhantomData, } } @@ -240,7 +250,7 @@ where let mut inner = inner.lock().unwrap(); inner.enabled = false; if let Some(global) = inner.global.take() { - self.dh.remove_global::(global); + remove_global_with_timer(&self.dh, &self.event_loop_handle, global); } } } @@ -292,7 +302,11 @@ where inner.global = Some(output.create_global::(&self.dh)); } if !inner.enabled && inner.global.is_some() { - self.dh.remove_global::(inner.global.take().unwrap()); + remove_global_with_timer( + &self.dh, + &self.event_loop_handle, + inner.global.take().unwrap(), + ); } } for manager in self.instances.iter_mut() { @@ -493,6 +507,26 @@ where } } +fn remove_global_with_timer( + dh: &DisplayHandle, + event_loop_handle: &LoopHandle, + id: GlobalId, +) { + dh.disable_global::(id.clone()); + let source = Timer::from_duration(Duration::from_secs(5)); + let dh = dh.clone(); + let res = event_loop_handle.insert_source(source, move |_, _, _state| { + dh.remove_global::(id.clone()); + TimeoutAction::Drop + }); + if let Err(err) = res { + tracing::error!( + "failed to insert timer source to destroy output global: {}", + err + ); + } +} + macro_rules! delegate_output_configuration { ($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => { smithay::reexports::wayland_server::delegate_global_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [