diff --git a/src/backend/kms/surface/mod.rs b/src/backend/kms/surface/mod.rs index 70fcf1df9..b3c82be00 100644 --- a/src/backend/kms/surface/mod.rs +++ b/src/backend/kms/surface/mod.rs @@ -991,6 +991,13 @@ impl SurfaceThreadState { vrr = has_active_fullscreen; } + // TODO commit timing `signal_until` + { + let shell = self.shell.read(); + // XXX correct way to set time? + shell.signal_commit_timing(&self.output, self.clock.now() + estimated_presentation); + } + let mut elements = output_elements( Some(&render_node), &mut renderer, @@ -1307,6 +1314,9 @@ impl SurfaceThreadState { // If postprocessing, use states from first render let states = pre_postprocess_data.states.unwrap_or(frame_result.states); self.send_dmabuf_feedback(states); + + let shell = self.shell.read(); + shell.signal_fifos(&self.output); } if x.is_ok() { diff --git a/src/shell/mod.rs b/src/shell/mod.rs index 19c7b9410..d1e86f3ab 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -34,7 +34,8 @@ use smithay::{ space::SpaceElement, utils::{ surface_presentation_feedback_flags_from_states, surface_primary_scanout_output, - take_presentation_feedback_surface_tree, OutputPresentationFeedback, + take_presentation_feedback_surface_tree, with_surfaces_surface_tree, + OutputPresentationFeedback, }, LayerSurface, PopupKind, WindowSurface, WindowSurfaceType, }, @@ -49,9 +50,11 @@ use smithay::{ wayland_protocols::ext::session_lock::v1::server::ext_session_lock_v1::ExtSessionLockV1, wayland_server::{protocol::wl_surface::WlSurface, Client}, }, - utils::{IsAlive, Logical, Point, Rectangle, Serial, Size}, + utils::{IsAlive, Logical, Monotonic, Point, Rectangle, Serial, Size, Time}, wayland::{ - compositor::{with_states, SurfaceAttributes}, + commit_timing::CommitTimerBarrierStateUserData, + compositor::{with_states, SurfaceAttributes, SurfaceData}, + fifo::FifoBarrierCachedState, seat::WaylandFocus, session_lock::LockSurface, shell::wlr_layer::{KeyboardInteractivity, Layer, LayerSurfaceCachedState}, @@ -1905,6 +1908,188 @@ impl Shell { }) } + pub fn signal_commit_timing(&self, output: &Output, until: Time) { + let processor = |_surface: &WlSurface, states: &SurfaceData| { + if let Some(mut commit_timer_state) = states + .data_map + .get::() + .map(|commit_timer| commit_timer.lock().unwrap()) + { + commit_timer_state.signal_until(until); + } + }; + + if let Some(session_lock) = self.session_lock.as_ref() { + if let Some(lock_surface) = session_lock.surfaces.get(output) { + with_surfaces_surface_tree(lock_surface.wl_surface(), processor); + } + } + + self.workspaces + .sets + .get(output) + .unwrap() + .sticky_layer + .mapped() + .for_each(|mapped| { + for (window, _) in mapped.windows() { + window.0.with_surfaces(processor); + } + }); + + for workspace in self.workspaces.spaces_for_output(output) { + if let Some(window) = workspace.get_fullscreen() { + window.0.with_surfaces(processor); + } + workspace.mapped().for_each(|mapped| { + for (window, _) in mapped.windows() { + window.0.with_surfaces(processor); + } + }); + workspace.minimized_windows.iter().for_each(|m| { + for window in m.windows() { + window.0.with_surfaces(processor); + } + }); + } + + let map = smithay::desktop::layer_map_for_output(output); + for layer_surface in map.layers() { + layer_surface.with_surfaces(processor); + } + + self.override_redirect_windows.iter().for_each(|or| { + // Find output the override redirect window overlaps the most with + let or_geo = or.geometry().as_global(); + let max_intersect_output = self + .outputs() + .filter_map(|o| Some((o, o.geometry().intersection(or_geo)?))) + .max_by_key(|(_, intersection)| intersection.size.w * intersection.size.h) + .map(|(o, _)| o); + if max_intersect_output == Some(output) { + if let Some(wl_surface) = or.wl_surface() { + with_surfaces_surface_tree(&wl_surface, processor); + } + } + }); + + for seat in self + .seats + .iter() + .filter(|seat| &seat.active_output() == output) + { + let cursor_status = seat.cursor_image_status(); + + if let CursorImageStatus::Surface(wl_surface) = cursor_status { + with_surfaces_surface_tree(&wl_surface, processor); + } + + if let Some(move_grab) = seat.user_data().get::() { + if let Some(grab_state) = move_grab.lock().unwrap().as_ref() { + for (window, _) in grab_state.element().windows() { + window.0.with_surfaces(processor); + } + } + } + + if let Some(icon) = get_dnd_icon(seat) { + with_surfaces_surface_tree(&icon.surface, processor); + } + } + } + + pub fn signal_fifos(&self, output: &Output) { + fn processor(_surface: &WlSurface, states: &SurfaceData) { + let fifo_barrier = states + .cached_state + .get::() + .current() + .barrier + .take(); + if let Some(fifo_barrier) = fifo_barrier { + fifo_barrier.signal(); + } + } + + if let Some(session_lock) = self.session_lock.as_ref() { + if let Some(lock_surface) = session_lock.surfaces.get(output) { + with_surfaces_surface_tree(lock_surface.wl_surface(), processor); + } + } + + self.workspaces + .sets + .get(output) + .unwrap() + .sticky_layer + .mapped() + .for_each(|mapped| { + for (window, _) in mapped.windows() { + window.0.with_surfaces(processor); + } + }); + + for workspace in self.workspaces.spaces_for_output(output) { + if let Some(window) = workspace.get_fullscreen() { + window.0.with_surfaces(processor); + } + workspace.mapped().for_each(|mapped| { + for (window, _) in mapped.windows() { + window.0.with_surfaces(processor); + } + }); + workspace.minimized_windows.iter().for_each(|m| { + for window in m.windows() { + window.0.with_surfaces(processor); + } + }); + } + + let map = smithay::desktop::layer_map_for_output(output); + for layer_surface in map.layers() { + layer_surface.with_surfaces(processor); + } + + self.override_redirect_windows.iter().for_each(|or| { + // Find output the override redirect window overlaps the most with + let or_geo = or.geometry().as_global(); + let max_intersect_output = self + .outputs() + .filter_map(|o| Some((o, o.geometry().intersection(or_geo)?))) + .max_by_key(|(_, intersection)| intersection.size.w * intersection.size.h) + .map(|(o, _)| o); + if max_intersect_output == Some(output) { + if let Some(wl_surface) = or.wl_surface() { + with_surfaces_surface_tree(&wl_surface, processor); + } + } + }); + + for seat in self + .seats + .iter() + .filter(|seat| &seat.active_output() == output) + { + let cursor_status = seat.cursor_image_status(); + + if let CursorImageStatus::Surface(wl_surface) = cursor_status { + with_surfaces_surface_tree(&wl_surface, processor); + } + + if let Some(move_grab) = seat.user_data().get::() { + if let Some(grab_state) = move_grab.lock().unwrap().as_ref() { + for (window, _) in grab_state.element().windows() { + window.0.with_surfaces(processor); + } + } + } + + if let Some(icon) = get_dnd_icon(seat) { + with_surfaces_surface_tree(&icon.surface, processor); + } + } + } + pub fn workspace_for_surface(&self, surface: &WlSurface) -> Option<(WorkspaceHandle, Output)> { match self.outputs().find(|o| { let map = layer_map_for_output(o); diff --git a/src/state.rs b/src/state.rs index 4b46a90f1..330a78599 100644 --- a/src/state.rs +++ b/src/state.rs @@ -76,6 +76,7 @@ use smithay::{ compositor::{CompositorClientState, CompositorState, SurfaceData}, cursor_shape::CursorShapeManagerState, dmabuf::{DmabufFeedback, DmabufGlobal, DmabufState}, + fifo::FifoManagerState, fractional_scale::{with_fractional_scale, FractionalScaleManagerState}, idle_inhibit::IdleInhibitManagerState, idle_notify::IdleNotifierState, @@ -236,6 +237,7 @@ pub struct Common { pub xdg_decoration_state: XdgDecorationState, pub overlap_notify_state: OverlapNotifyState, pub a11y_state: A11yState, + pub fifo_manager_state: FifoManagerState, // shell-related wayland state pub xdg_shell_state: XdgShellState, @@ -653,6 +655,8 @@ impl State { // TODO: Restrict to only specific client? let atspi_state = AtspiState::new::(dh, |_| true); + let fifo_manager_state = FifoManagerState::new::(dh); + State { common: Common { config, @@ -707,6 +711,7 @@ impl State { xdg_foreign_state, workspace_state, a11y_state, + fifo_manager_state, xwayland_scale: None, xwayland_state: None, xwayland_shell_state, diff --git a/src/wayland/handlers/commit_timing.rs b/src/wayland/handlers/commit_timing.rs new file mode 100644 index 000000000..a73e9492a --- /dev/null +++ b/src/wayland/handlers/commit_timing.rs @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-3.0-only + +use crate::state::State; + +smithay::delegate_commit_timing!(State); diff --git a/src/wayland/handlers/fifo.rs b/src/wayland/handlers/fifo.rs new file mode 100644 index 000000000..29f99d4cc --- /dev/null +++ b/src/wayland/handlers/fifo.rs @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-3.0-only + +use crate::state::State; + +smithay::delegate_fifo!(State); diff --git a/src/wayland/handlers/mod.rs b/src/wayland/handlers/mod.rs index 3d446c140..d0395fc3d 100644 --- a/src/wayland/handlers/mod.rs +++ b/src/wayland/handlers/mod.rs @@ -4,6 +4,7 @@ pub mod a11y; pub mod alpha_modifier; pub mod atspi; pub mod buffer; +pub mod commit_timing; pub mod compositor; pub mod data_control; pub mod data_device; @@ -12,6 +13,7 @@ pub mod dmabuf; pub mod drm; pub mod drm_lease; pub mod drm_syncobj; +pub mod fifo; pub mod foreign_toplevel_list; pub mod fractional_scale; pub mod idle_inhibit;