aboutsummaryrefslogtreecommitdiff
path: root/src/handlers
diff options
context:
space:
mode:
authorIvan Molodetskikh <yalterz@gmail.com>2024-08-22 14:44:11 +0300
committerIvan Molodetskikh <yalterz@gmail.com>2024-08-22 15:19:11 +0300
commit7bfdf87bf0138d602888fc3167921bc1d029b0ab (patch)
tree48664b930f00be78f4c232a838b8ea4c5254db49 /src/handlers
parentcf357d7058910864018c3e3702a9723194fce916 (diff)
downloadniri-7bfdf87bf0138d602888fc3167921bc1d029b0ab.tar.gz
niri-7bfdf87bf0138d602888fc3167921bc1d029b0ab.tar.bz2
niri-7bfdf87bf0138d602888fc3167921bc1d029b0ab.zip
Implement resize transactions
Diffstat (limited to 'src/handlers')
-rw-r--r--src/handlers/compositor.rs1
-rw-r--r--src/handlers/xdg_shell.rs59
2 files changed, 53 insertions, 7 deletions
diff --git a/src/handlers/compositor.rs b/src/handlers/compositor.rs
index 140d00e0..e833494c 100644
--- a/src/handlers/compositor.rs
+++ b/src/handlers/compositor.rs
@@ -52,6 +52,7 @@ impl CompositorHandler for State {
fn commit(&mut self, surface: &WlSurface) {
let _span = tracy_client::span!("CompositorHandler::commit");
+ trace!(surface = ?surface.id(), "commit");
on_commit_buffer_handler::<Self>(surface);
self.backend.early_import(surface);
diff --git a/src/handlers/xdg_shell.rs b/src/handlers/xdg_shell.rs
index 5f84da3b..ec0b99e3 100644
--- a/src/handlers/xdg_shell.rs
+++ b/src/handlers/xdg_shell.rs
@@ -34,6 +34,7 @@ use smithay::wayland::xdg_foreign::{XdgForeignHandler, XdgForeignState};
use smithay::{
delegate_kde_decoration, delegate_xdg_decoration, delegate_xdg_foreign, delegate_xdg_shell,
};
+use tracing::field::Empty;
use crate::input::resize_grab::ResizeGrab;
use crate::input::DOUBLE_CLICK_TIME;
@@ -1003,6 +1004,8 @@ fn unconstrain_with_padding(
pub fn add_mapped_toplevel_pre_commit_hook(toplevel: &ToplevelSurface) -> HookId {
add_pre_commit_hook::<State, _>(toplevel.wl_surface(), move |state, _dh, surface| {
let _span = tracy_client::span!("mapped toplevel pre-commit");
+ let span =
+ trace_span!("toplevel pre-commit", surface = %surface.id(), serial = Empty).entered();
let Some((mapped, _)) = state.niri.layout.find_window_and_output_mut(surface) else {
error!("pre-commit hook for mapped surfaces must be removed upon unmapping");
@@ -1032,31 +1035,73 @@ pub fn add_mapped_toplevel_pre_commit_hook(toplevel: &ToplevelSurface) -> HookId
(got_unmapped, dmabuf, role.configure_serial)
});
- let mut dmabuf_blocker =
- dmabuf.and_then(|dmabuf| dmabuf.generate_blocker(Interest::READ).ok());
+ let mut transaction_for_dmabuf = None;
+ let mut animate = false;
+ if let Some(serial) = commit_serial {
+ if !span.is_disabled() {
+ span.record("serial", format!("{serial:?}"));
+ }
+
+ trace!("taking pending transaction");
+ if let Some(transaction) = mapped.take_pending_transaction(serial) {
+ // Transaction can be already completed if it ran past the deadline.
+ let disable = state.niri.config.borrow().debug.disable_transactions;
+ if !transaction.is_completed() && !disable {
+ // Register the deadline even if this is the last pending, since dmabuf
+ // rendering can still run over the deadline.
+ transaction.register_deadline_timer(&state.niri.event_loop);
+
+ let is_last = transaction.is_last();
+
+ // If this is the last transaction, we don't need to add a separate
+ // notification, because the transaction will complete in our dmabuf blocker
+ // callback, which already calls blocker_cleared(), or by the end of this
+ // function, in which case there would be no blocker in the first place.
+ if !is_last {
+ // Waiting for some other surface; register a notification and add a
+ // transaction blocker.
+ if let Some(client) = surface.client() {
+ transaction.add_notification(
+ state.niri.blocker_cleared_tx.clone(),
+ client.clone(),
+ );
+ add_blocker(surface, transaction.blocker());
+ }
+ }
+
+ // Delay dropping (and completing) the transaction until the dmabuf is ready.
+ // If there's no dmabuf, this will be dropped by the end of this pre-commit
+ // hook.
+ transaction_for_dmabuf = Some(transaction);
+ }
+ }
- let animate = if let Some(serial) = commit_serial {
- mapped.should_animate_commit(serial)
+ animate = mapped.should_animate_commit(serial);
} else {
error!("commit on a mapped surface without a configured serial");
- false
};
- if let Some((blocker, source)) = dmabuf_blocker.take() {
+ if let Some((blocker, source)) =
+ dmabuf.and_then(|dmabuf| dmabuf.generate_blocker(Interest::READ).ok())
+ {
if let Some(client) = surface.client() {
let res = state
.niri
.event_loop
.insert_source(source, move |_, _, state| {
+ // This surface is now ready for the transaction.
+ drop(transaction_for_dmabuf.take());
+
let display_handle = state.niri.display_handle.clone();
state
.client_compositor_state(&client)
.blocker_cleared(state, &display_handle);
+
Ok(())
});
if res.is_ok() {
add_blocker(surface, blocker);
- trace!("added toplevel dmabuf blocker");
+ trace!("added dmabuf blocker");
}
}
}