Skip to content

Commit 16efbea

Browse files
committed
wayland: add delayed blockers
1 parent 16b0416 commit 16efbea

File tree

2 files changed

+61
-4
lines changed

2 files changed

+61
-4
lines changed

src/wayland/compositor/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ use std::{any::Any, sync::Mutex};
118118
pub use self::cache::{Cacheable, CachedState, MultiCache};
119119
pub use self::handlers::{RegionUserData, SubsurfaceCachedState, SubsurfaceUserData, SurfaceUserData};
120120
use self::transaction::TransactionQueue;
121-
pub use self::transaction::{Barrier, Blocker, BlockerState};
121+
pub use self::transaction::{Barrier, Blocker, BlockerState, BlockerKind};
122122
pub use self::tree::{AlreadyHasRole, TraversalAction};
123123
use self::tree::{PrivateSurfaceData, SuggestedSurfaceState};
124124
pub use crate::utils::hook::HookId;

src/wayland/compositor/transaction.rs

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,31 @@ use crate::utils::Serial;
5050

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

53+
/// Kind for a [`Blocker`]
54+
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
55+
pub enum BlockerKind {
56+
/// A immediate blocker which needs to be cleared before all delayed blockers.
57+
Immediate,
58+
/// Defines a delayed blocker which will be evaluated after
59+
/// all immediate blockers are cleared.
60+
Delayed,
61+
}
62+
5363
/// Types potentially blocking state changes
5464
pub trait Blocker {
5565
/// Retrieve the current state of the blocker
5666
fn state(&self) -> BlockerState;
67+
68+
/// Retrieve the kind of the blocker
69+
fn kind(&self) -> BlockerKind {
70+
BlockerKind::Immediate
71+
}
72+
73+
/// Notifies the blocker that all immediate blockers have been cleared
74+
/// for a particular surface
75+
fn notify(&self, surface: &WlSurface) {
76+
let _ = surface;
77+
}
5778
}
5879

5980
/// States of a [`Blocker`]
@@ -241,7 +262,7 @@ impl Transaction {
241262
/// - if at least one blocker is cancelled, the transaction is cancelled
242263
/// - otherwise, if at least one blocker is pending, the transaction is pending
243264
/// - otherwise, all blockers are released, and the transaction is also released
244-
pub(crate) fn state(&self) -> BlockerState {
265+
pub(crate) fn state(&self, kind: Option<BlockerKind>) -> BlockerState {
245266
// In case all of our surfaces have been destroyed we can cancel this transaction
246267
// as we won't apply its state anyway
247268
if !self.surfaces.iter().any(|surface| surface.0.is_alive()) {
@@ -251,13 +272,26 @@ impl Transaction {
251272
use BlockerState::*;
252273
self.blockers
253274
.iter()
275+
.filter(|blocker| kind.map(|kind| kind == blocker.kind()).unwrap_or(true))
254276
.fold(Released, |acc, blocker| match (acc, blocker.state()) {
255277
(Cancelled, _) | (_, Cancelled) => Cancelled,
256278
(Pending, _) | (_, Pending) => Pending,
257279
(Released, Released) => Released,
258280
})
259281
}
260282

283+
pub(crate) fn notify_blockers(&self) {
284+
for (s, _) in &self.surfaces {
285+
let Ok(surface) = s.upgrade() else {
286+
continue;
287+
};
288+
289+
for blocker in self.blockers.iter() {
290+
blocker.notify(&surface);
291+
}
292+
}
293+
}
294+
261295
pub(crate) fn apply<C: CompositorHandler + 'static>(self, dh: &DisplayHandle, state: &mut C) {
262296
for (surface, id) in self.surfaces {
263297
let Ok(surface) = surface.upgrade() else {
@@ -304,7 +338,7 @@ impl TransactionQueue {
304338
while i < self.transactions.len() {
305339
let mut skip = false;
306340
// does the transaction have any active blocker?
307-
match self.transactions[i].state() {
341+
match self.transactions[i].state(Some(BlockerKind::Immediate)) {
308342
BlockerState::Cancelled => {
309343
// this transaction is cancelled, remove it without further processing
310344
self.transactions.remove(i);
@@ -342,7 +376,30 @@ impl TransactionQueue {
342376
i += 1;
343377
} else {
344378
// this transaction is to be applied, yay!
345-
ready_transactions.push(self.transactions.remove(i));
379+
let transaction = &mut self.transactions[i];
380+
381+
transaction.notify_blockers();
382+
383+
match transaction.state(None) {
384+
BlockerState::Pending => {
385+
// this transaction is not yet ready and should be skipped, add its surfaces to our
386+
// seen list
387+
for (s, _) in &transaction.surfaces {
388+
// TODO: is this alive check still needed?
389+
if !s.is_alive() {
390+
continue;
391+
}
392+
self.seen_surfaces.insert(s.id().protocol_id());
393+
}
394+
i += 1;
395+
}
396+
BlockerState::Released => ready_transactions.push(self.transactions.remove(i)),
397+
BlockerState::Cancelled =>
398+
// this transaction is cancelled, remove it without further processing
399+
{
400+
self.transactions.remove(i);
401+
}
402+
}
346403
}
347404
}
348405

0 commit comments

Comments
 (0)