From b3215811f5fbdc8832d9da1191b94a559d93c276 Mon Sep 17 00:00:00 2001 From: Christian Meissl Date: Sat, 16 Nov 2024 21:25:45 +0100 Subject: [PATCH] output: store a weak ref in the global to avoid... ...a cycle keeping the output alive indefinitely --- src/wayland/output/handlers.rs | 34 ++++++++++++++++++++-------------- src/wayland/output/mod.rs | 9 +++++++-- 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/src/wayland/output/handlers.rs b/src/wayland/output/handlers.rs index 7cc18b0186c1..8306e95639d5 100644 --- a/src/wayland/output/handlers.rs +++ b/src/wayland/output/handlers.rs @@ -38,16 +38,22 @@ where data_init: &mut DataInit<'_, D>, ) { let client_scale = state.client_compositor_state(client).clone_client_scale(); - let output = data_init.init( + + let Some(output) = global_data.output.upgrade() else { + tracing::warn!("trying to bind a destroyed output, forgot to disable a output global?"); + return; + }; + + let wl_output = data_init.init( resource, OutputUserData { - output: global_data.output.downgrade(), + output: global_data.output.clone(), last_client_scale: AtomicU32::new(client_scale.load(Ordering::Acquire)), client_scale, }, ); - let mut inner = global_data.output.inner.0.lock().unwrap(); + let mut inner = output.inner.0.lock().unwrap(); let span = warn_span!("output_bind", name = inner.name); let _enter = span.enter(); @@ -64,7 +70,7 @@ where warn!("Output is used with not preferred mode set"); } - inner.send_geometry_to(&output); + inner.send_geometry_to(&wl_output); for &mode in &inner.modes { let mut flags = WMode::empty(); @@ -74,32 +80,32 @@ where if Some(mode) == inner.preferred_mode { flags |= WMode::Preferred; } - output.mode(flags, mode.size.w, mode.size.h, mode.refresh); + wl_output.mode(flags, mode.size.w, mode.size.h, mode.refresh); } - if output.version() >= 4 { - output.name(inner.name.clone()); - output.description(inner.description.clone()) + if wl_output.version() >= 4 { + wl_output.name(inner.name.clone()); + wl_output.description(inner.description.clone()) } - if output.version() >= 2 { - output.scale(inner.scale.integer_scale()); - output.done(); + if wl_output.version() >= 2 { + wl_output.scale(inner.scale.integer_scale()); + wl_output.done(); } // Send enter for surfaces already on this output. for surface in &inner.surfaces { if let Ok(surface) = surface.upgrade() { if surface.client().as_ref() == Some(client) { - surface.enter(&output); + surface.enter(&wl_output); } } } - inner.instances.push(output.downgrade()); + inner.instances.push(wl_output.downgrade()); drop(inner); - state.output_bound(global_data.output.clone(), output); + state.output_bound(output, wl_output); } } diff --git a/src/wayland/output/mod.rs b/src/wayland/output/mod.rs index fd260453a6de..2fa28f085f99 100644 --- a/src/wayland/output/mod.rs +++ b/src/wayland/output/mod.rs @@ -104,7 +104,7 @@ pub struct OutputManagerState { /// Internal data of a wl_output global #[derive(Debug)] pub struct WlOutputData { - output: Output, + output: WeakOutput, } /// Events initiated by the clients interacting with outputs @@ -204,7 +204,12 @@ impl Output { { info!(output = self.name(), "Creating new wl_output"); self.inner.0.lock().unwrap().handle = Some(display.backend_handle().downgrade()); - display.create_global::(4, WlOutputData { output: self.clone() }) + display.create_global::( + 4, + WlOutputData { + output: self.downgrade(), + }, + ) } /// Attempt to retrieve a [`Output`] from an existing resource