Skip to content

Commit 0f32e8d

Browse files
cmeisslDrakulix
authored andcommitted
wayland: use weak surface ref inside transaction...
...to prevent keeping them alive longer as needed this also resolves a deadlock when trying to send events in a drop impl stored in the surface state of a blocked transaction
1 parent 156dc3f commit 0f32e8d

File tree

1 file changed

+20
-8
lines changed

1 file changed

+20
-8
lines changed

src/wayland/compositor/transaction.rs

+20-8
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,9 @@ use std::{
4444
sync::{atomic::AtomicBool, Arc, Mutex},
4545
};
4646

47-
use wayland_server::{protocol::wl_surface::WlSurface, DisplayHandle, Resource};
47+
use wayland_server::{protocol::wl_surface::WlSurface, DisplayHandle, Resource, Weak};
4848

49-
use crate::{utils::IsAlive, utils::Serial};
49+
use crate::utils::Serial;
5050

5151
use super::{tree::PrivateSurfaceData, CompositorHandler};
5252

@@ -110,7 +110,7 @@ impl Blocker for Barrier {
110110

111111
#[derive(Default)]
112112
struct TransactionState {
113-
surfaces: Vec<(WlSurface, Serial)>,
113+
surfaces: Vec<(Weak<WlSurface>, Serial)>,
114114
blockers: Vec<Box<dyn Blocker + Send>>,
115115
}
116116

@@ -123,7 +123,7 @@ impl TransactionState {
123123
}
124124
} else {
125125
// the surface is not in the list, insert it
126-
self.surfaces.push((surface, id));
126+
self.surfaces.push((surface.downgrade(), id));
127127
}
128128
}
129129
}
@@ -196,7 +196,9 @@ impl PendingTransaction {
196196
// fuse our surfaces into our new transaction state
197197
self.with_inner_state(|state| {
198198
for (surface, id) in my_state.surfaces {
199-
state.insert(surface, id);
199+
if let Ok(surface) = surface.upgrade() {
200+
state.insert(surface, id);
201+
}
200202
}
201203
state.blockers.extend(my_state.blockers);
202204
});
@@ -221,7 +223,7 @@ impl PendingTransaction {
221223

222224
#[derive(Debug)]
223225
pub(crate) struct Transaction {
224-
surfaces: Vec<(WlSurface, Serial)>,
226+
surfaces: Vec<(Weak<WlSurface>, Serial)>,
225227
blockers: Vec<Box<dyn Blocker + Send>>,
226228
}
227229

@@ -240,6 +242,12 @@ impl Transaction {
240242
/// - otherwise, if at least one blocker is pending, the transaction is pending
241243
/// - otherwise, all blockers are released, and the transaction is also released
242244
pub(crate) fn state(&self) -> BlockerState {
245+
// In case all of our surfaces have been destroyed we can cancel this transaction
246+
// as we won't apply its state anyway
247+
if !self.surfaces.iter().any(|surface| surface.0.is_alive()) {
248+
return BlockerState::Cancelled;
249+
}
250+
243251
use BlockerState::*;
244252
self.blockers
245253
.iter()
@@ -252,6 +260,10 @@ impl Transaction {
252260

253261
pub(crate) fn apply<C: CompositorHandler + 'static>(self, dh: &DisplayHandle, state: &mut C) {
254262
for (surface, id) in self.surfaces {
263+
let Ok(surface) = surface.upgrade() else {
264+
continue;
265+
};
266+
255267
PrivateSurfaceData::with_states(&surface, |states| {
256268
states.cached_state.apply_state(id, dh);
257269
});
@@ -307,7 +319,7 @@ impl TransactionQueue {
307319
if !skip {
308320
for (s, _) in &self.transactions[i].surfaces {
309321
// TODO: is this alive check still needed?
310-
if !s.alive() {
322+
if !s.is_alive() {
311323
continue;
312324
}
313325
if self.seen_surfaces.contains(&s.id().protocol_id()) {
@@ -322,7 +334,7 @@ impl TransactionQueue {
322334
// seen list
323335
for (s, _) in &self.transactions[i].surfaces {
324336
// TODO: is this alive check still needed?
325-
if !s.alive() {
337+
if !s.is_alive() {
326338
continue;
327339
}
328340
self.seen_surfaces.insert(s.id().protocol_id());

0 commit comments

Comments
 (0)