Skip to content

Commit

Permalink
output: store a weak ref in the global to avoid...
Browse files Browse the repository at this point in the history
...a cycle keeping the output alive indefinitely
  • Loading branch information
cmeissl committed Nov 16, 2024
1 parent 28417d2 commit 9697477
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 26 deletions.
1 change: 1 addition & 0 deletions src/output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ pub struct WeakOutput {

/// Data of an Output
pub(crate) type OutputData = Arc<(Mutex<Inner>, UserDataMap)>;
pub(crate) type WeakOutputData = Weak<(Mutex<Inner>, UserDataMap)>;

impl Output {
/// Create a new output with given name and physical properties.
Expand Down
44 changes: 25 additions & 19 deletions src/wayland/output/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,13 @@ 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.inner.upgrade().map(|inner| Output { inner }) else {
tracing::warn!("trying to bind a destroyed output, forgot to disable a output global?");
return;
};

let wl_output = data_init.init(
resource,
OutputUserData {
global_data: global_data.inner.clone(),
Expand All @@ -47,7 +53,7 @@ where
},
);

let mut inner = global_data.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();
Expand All @@ -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();
Expand All @@ -74,35 +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);
let o = Output {
inner: global_data.inner.clone(),
};
state.output_bound(o, output);
state.output_bound(output, wl_output);
}
}

Expand All @@ -124,15 +127,18 @@ where
fn destroyed(
_state: &mut D,
_client_id: wayland_server::backend::ClientId,
output: &WlOutput,
wl_output: &WlOutput,
data: &OutputUserData,
) {
data.global_data
let Some(output_data) = data.global_data.upgrade() else {
return;
};
output_data
.0
.lock()
.unwrap()
.instances
.retain(|o| o.id() != output.id());
.retain(|o| o.id() != wl_output.id());
}
}

Expand Down
15 changes: 8 additions & 7 deletions src/wayland/output/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ use std::sync::{
Arc,
};

use crate::output::{Inner, Mode, Output, OutputData, Scale, Subpixel};
use crate::output::{Inner, Mode, Output, Scale, Subpixel, WeakOutputData};

use tracing::info;
use wayland_protocols::xdg::xdg_output::zv1::server::zxdg_output_manager_v1::ZxdgOutputManagerV1;
Expand All @@ -104,7 +104,7 @@ pub struct OutputManagerState {
/// Internal data of a wl_output global
#[derive(Debug)]
pub struct WlOutputData {
inner: OutputData,
inner: WeakOutputData,
}

/// Events initiated by the clients interacting with outputs
Expand Down Expand Up @@ -144,7 +144,7 @@ impl OutputManagerState {
/// User data for WlOutput
#[derive(Debug)]
pub struct OutputUserData {
pub(crate) global_data: OutputData,
pub(crate) global_data: WeakOutputData,
last_client_scale: AtomicU32,
client_scale: Arc<AtomicU32>,
}
Expand Down Expand Up @@ -207,16 +207,17 @@ impl Output {
display.create_global::<D, WlOutput, _>(
4,
WlOutputData {
inner: self.inner.clone(),
inner: Arc::downgrade(&self.inner),
},
)
}

/// Attempt to retrieve a [`Output`] from an existing resource
pub fn from_resource(output: &WlOutput) -> Option<Output> {
output.data::<OutputUserData>().map(|ud| Output {
inner: ud.global_data.clone(),
})
output
.data::<OutputUserData>()
.and_then(|ud| ud.global_data.upgrade())
.map(|inner| Output { inner })
}

pub(crate) fn wl_change_current_state(
Expand Down

0 comments on commit 9697477

Please sign in to comment.