diff options
Diffstat (limited to 'src/layout')
| -rw-r--r-- | src/layout/closing_window.rs | 79 | ||||
| -rw-r--r-- | src/layout/mod.rs | 32 | ||||
| -rw-r--r-- | src/layout/monitor.rs | 22 | ||||
| -rw-r--r-- | src/layout/workspace.rs | 57 |
4 files changed, 155 insertions, 35 deletions
diff --git a/src/layout/closing_window.rs b/src/layout/closing_window.rs index cbaf29be..8bbf0258 100644 --- a/src/layout/closing_window.rs +++ b/src/layout/closing_window.rs @@ -12,6 +12,7 @@ use smithay::backend::renderer::element::{Kind, RenderElement}; use smithay::backend::renderer::gles::{GlesRenderer, GlesTexture, Uniform}; use smithay::backend::renderer::Texture; use smithay::utils::{Logical, Point, Rectangle, Scale, Size, Transform}; +use smithay::wayland::compositor::{Blocker, BlockerState}; use crate::animation::Animation; use crate::niri_render_elements; @@ -21,6 +22,7 @@ use crate::render_helpers::shaders::{mat3_uniform, ProgramType, Shaders}; use crate::render_helpers::snapshot::RenderSnapshot; use crate::render_helpers::texture::{TextureBuffer, TextureRenderElement}; use crate::render_helpers::{render_to_encompassing_texture, RenderTarget}; +use crate::utils::transaction::TransactionBlocker; #[derive(Debug)] pub struct ClosingWindow { @@ -46,7 +48,7 @@ pub struct ClosingWindow { blocked_out_buffer_offset: Point<f64, Logical>, /// The closing animation. - anim: Animation, + anim_state: AnimationState, /// Random seed for the shader. random_seed: f32, @@ -59,6 +61,29 @@ niri_render_elements! { } } +#[derive(Debug)] +enum AnimationState { + Waiting { + /// Blocker for a transaction before starting the animation. + blocker: TransactionBlocker, + anim: Animation, + }, + Animating(Animation), +} + +impl AnimationState { + pub fn new(blocker: TransactionBlocker, anim: Animation) -> Self { + if blocker.state() == BlockerState::Pending { + Self::Waiting { blocker, anim } + } else { + // This actually doesn't normally happen because the window is removed only after the + // closing animation is created. Though, it does happen with disable-transactions debug + // flag. + Self::Animating(anim) + } + } +} + impl ClosingWindow { pub fn new<E: RenderElement<GlesRenderer>>( renderer: &mut GlesRenderer, @@ -66,6 +91,7 @@ impl ClosingWindow { scale: Scale<f64>, geo_size: Size<f64, Logical>, pos: Point<f64, Logical>, + blocker: TransactionBlocker, anim: Animation, ) -> anyhow::Result<Self> { let _span = tracy_client::span!("ClosingWindow::new"); @@ -107,17 +133,29 @@ impl ClosingWindow { pos, buffer_offset, blocked_out_buffer_offset, - anim, + anim_state: AnimationState::new(blocker, anim), random_seed: fastrand::f32(), }) } pub fn advance_animations(&mut self, current_time: Duration) { - self.anim.set_current_time(current_time); + match &mut self.anim_state { + AnimationState::Waiting { blocker, anim } => { + if blocker.state() != BlockerState::Pending { + let mut anim = anim.restarted(0., 1., 0.); + anim.set_current_time(current_time); + self.anim_state = AnimationState::Animating(anim); + } + } + AnimationState::Animating(anim) => anim.set_current_time(current_time), + } } pub fn are_animations_ongoing(&self) -> bool { - !self.anim.is_done() + match &self.anim_state { + AnimationState::Waiting { .. } => true, + AnimationState::Animating(anim) => !anim.is_done(), + } } pub fn render( @@ -127,15 +165,42 @@ impl ClosingWindow { scale: Scale<f64>, target: RenderTarget, ) -> ClosingWindowRenderElement { - let progress = self.anim.value(); - let clamped_progress = self.anim.clamped_value().clamp(0., 1.); - let (buffer, offset) = if target.should_block_out(self.block_out_from) { (&self.blocked_out_buffer, self.blocked_out_buffer_offset) } else { (&self.buffer, self.buffer_offset) }; + let anim = match &self.anim_state { + AnimationState::Waiting { .. } => { + let elem = TextureRenderElement::from_texture_buffer( + buffer.clone(), + Point::from((0., 0.)), + 1., + None, + None, + Kind::Unspecified, + ); + + let elem = PrimaryGpuTextureRenderElement(elem); + let elem = RescaleRenderElement::from_element(elem, Point::from((0, 0)), 1.); + + let mut location = self.pos + offset; + location.x -= view_rect.loc.x; + let elem = RelocateRenderElement::from_element( + elem, + location.to_physical_precise_round(scale), + Relocate::Relative, + ); + + return elem.into(); + } + AnimationState::Animating(anim) => anim, + }; + + let progress = anim.value(); + let clamped_progress = anim.clamped_value().clamp(0., 1.); + if Shaders::get(renderer).program(ProgramType::Close).is_some() { let area_loc = Vec2::new(view_rect.loc.x as f32, view_rect.loc.y as f32); let area_size = Vec2::new(view_rect.size.w as f32, view_rect.size.h as f32); diff --git a/src/layout/mod.rs b/src/layout/mod.rs index 9376112f..2b684ddf 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -52,7 +52,7 @@ use crate::render_helpers::snapshot::RenderSnapshot; use crate::render_helpers::solid_color::{SolidColorBuffer, SolidColorRenderElement}; use crate::render_helpers::texture::TextureBuffer; use crate::render_helpers::{BakedBuffer, RenderTarget, SplitElements}; -use crate::utils::transaction::Transaction; +use crate::utils::transaction::{Transaction, TransactionBlocker}; use crate::utils::{output_size, round_logical_in_physical_max1, ResizeEdge}; use crate::window::ResolvedWindowRules; @@ -752,15 +752,13 @@ impl<W: LayoutElement> Layout<W> { ); } - pub fn remove_window(&mut self, window: &W::Id) -> Option<W> { - let mut rv = None; - + pub fn remove_window(&mut self, window: &W::Id, transaction: Transaction) -> Option<W> { match &mut self.monitor_set { MonitorSet::Normal { monitors, .. } => { for mon in monitors { for (idx, ws) in mon.workspaces.iter_mut().enumerate() { if ws.has_window(window) { - rv = Some(ws.remove_window(window)); + let win = ws.remove_window(window, transaction); // Clean up empty workspaces that are not active and not last. if !ws.has_windows() @@ -776,7 +774,7 @@ impl<W: LayoutElement> Layout<W> { } } - break; + return Some(win); } } } @@ -784,20 +782,20 @@ impl<W: LayoutElement> Layout<W> { MonitorSet::NoOutputs { workspaces, .. } => { for (idx, ws) in workspaces.iter_mut().enumerate() { if ws.has_window(window) { - rv = Some(ws.remove_window(window)); + let win = ws.remove_window(window, transaction); // Clean up empty workspaces. if !ws.has_windows() && workspaces[idx].name.is_none() { workspaces.remove(idx); } - break; + return Some(win); } } } } - rv + None } pub fn update_window(&mut self, window: &W::Id, serial: Option<Serial>) { @@ -1970,7 +1968,12 @@ impl<W: LayoutElement> Layout<W> { let width = column.width; let is_full_width = column.is_full_width; let window = ws - .remove_tile_by_idx(ws.active_column_idx, column.active_tile_idx, None) + .remove_tile_by_idx( + ws.active_column_idx, + column.active_tile_idx, + Transaction::new(), + None, + ) .into_window(); let workspace_idx = monitors[new_idx].active_workspace_idx; @@ -2022,7 +2025,7 @@ impl<W: LayoutElement> Layout<W> { let Some(width) = width else { return }; - let window = self.remove_window(window).unwrap(); + let window = self.remove_window(window, Transaction::new()).unwrap(); if let MonitorSet::Normal { monitors, .. } = &mut self.monitor_set { let new_idx = monitors @@ -2425,6 +2428,7 @@ impl<W: LayoutElement> Layout<W> { &mut self, renderer: &mut GlesRenderer, window: &W::Id, + blocker: TransactionBlocker, ) { let _span = tracy_client::span!("Layout::start_close_animation_for_window"); @@ -2433,7 +2437,7 @@ impl<W: LayoutElement> Layout<W> { for mon in monitors { for ws in &mut mon.workspaces { if ws.has_window(window) { - ws.start_close_animation_for_window(renderer, window); + ws.start_close_animation_for_window(renderer, window, blocker); return; } } @@ -2442,7 +2446,7 @@ impl<W: LayoutElement> Layout<W> { MonitorSet::NoOutputs { workspaces, .. } => { for ws in workspaces { if ws.has_window(window) { - ws.start_close_animation_for_window(renderer, window); + ws.start_close_animation_for_window(renderer, window, blocker); return; } } @@ -3143,7 +3147,7 @@ mod tests { layout.add_window_to_named_workspace(&ws_name, win, None, false); } Op::CloseWindow(id) => { - layout.remove_window(&id); + layout.remove_window(&id, Transaction::new()); } Op::FullscreenWindow(id) => { layout.toggle_fullscreen(&id); diff --git a/src/layout/monitor.rs b/src/layout/monitor.rs index 423b2ef9..07223521 100644 --- a/src/layout/monitor.rs +++ b/src/layout/monitor.rs @@ -19,6 +19,7 @@ use crate::input::swipe_tracker::SwipeTracker; use crate::render_helpers::renderer::NiriRenderer; use crate::render_helpers::RenderTarget; use crate::rubber_band::RubberBand; +use crate::utils::transaction::Transaction; use crate::utils::{output_size, to_physical_precise_round, ResizeEdge}; /// Amount of touchpad movement to scroll the height of one workspace. @@ -442,7 +443,12 @@ impl<W: LayoutElement> Monitor<W> { let width = column.width; let is_full_width = column.is_full_width; let window = workspace - .remove_tile_by_idx(workspace.active_column_idx, column.active_tile_idx, None) + .remove_tile_by_idx( + workspace.active_column_idx, + column.active_tile_idx, + Transaction::new(), + None, + ) .into_window(); self.add_window(new_idx, window, true, width, is_full_width); @@ -465,7 +471,12 @@ impl<W: LayoutElement> Monitor<W> { let width = column.width; let is_full_width = column.is_full_width; let window = workspace - .remove_tile_by_idx(workspace.active_column_idx, column.active_tile_idx, None) + .remove_tile_by_idx( + workspace.active_column_idx, + column.active_tile_idx, + Transaction::new(), + None, + ) .into_window(); self.add_window(new_idx, window, true, width, is_full_width); @@ -488,7 +499,12 @@ impl<W: LayoutElement> Monitor<W> { let width = column.width; let is_full_width = column.is_full_width; let window = workspace - .remove_tile_by_idx(workspace.active_column_idx, column.active_tile_idx, None) + .remove_tile_by_idx( + workspace.active_column_idx, + column.active_tile_idx, + Transaction::new(), + None, + ) .into_window(); self.add_window(new_idx, window, true, width, is_full_width); diff --git a/src/layout/workspace.rs b/src/layout/workspace.rs index 7548dc10..272a153b 100644 --- a/src/layout/workspace.rs +++ b/src/layout/workspace.rs @@ -22,7 +22,7 @@ use crate::niri_render_elements; use crate::render_helpers::renderer::NiriRenderer; use crate::render_helpers::RenderTarget; use crate::utils::id::IdCounter; -use crate::utils::transaction::Transaction; +use crate::utils::transaction::{Transaction, TransactionBlocker}; use crate::utils::{output_size, send_scale_transform, ResizeEdge}; use crate::window::ResolvedWindowRules; @@ -1098,6 +1098,7 @@ impl<W: LayoutElement> Workspace<W> { &mut self, column_idx: usize, window_idx: usize, + transaction: Transaction, anim_config: Option<niri_config::Animation>, ) -> Tile<W> { let offset = self.column_x(column_idx + 1) - self.column_x(column_idx); @@ -1139,7 +1140,7 @@ impl<W: LayoutElement> Workspace<W> { offset } else { column.active_tile_idx = min(column.active_tile_idx, column.tiles.len() - 1); - column.update_tile_sizes(true); + column.update_tile_sizes_with_transaction(true, transaction); self.data[column_idx].update(column); prev_width - column.width() @@ -1294,7 +1295,7 @@ impl<W: LayoutElement> Workspace<W> { column } - pub fn remove_window(&mut self, window: &W::Id) -> W { + pub fn remove_window(&mut self, window: &W::Id, transaction: Transaction) -> W { let column_idx = self .columns .iter() @@ -1303,7 +1304,7 @@ impl<W: LayoutElement> Workspace<W> { let column = &self.columns[column_idx]; let window_idx = column.position(window).unwrap(); - self.remove_tile_by_idx(column_idx, window_idx, None) + self.remove_tile_by_idx(column_idx, window_idx, transaction, None) .into_window() } @@ -1490,6 +1491,7 @@ impl<W: LayoutElement> Workspace<W> { &mut self, renderer: &mut GlesRenderer, window: &W::Id, + blocker: TransactionBlocker, ) { let output_scale = Scale::from(self.scale.fractional_scale()); @@ -1542,7 +1544,21 @@ impl<W: LayoutElement> Workspace<W> { let anim = Animation::new(0., 1., 0., self.options.animations.window_close.anim); - let res = ClosingWindow::new(renderer, snapshot, output_scale, tile_size, tile_pos, anim); + let blocker = if self.options.disable_transactions { + TransactionBlocker::completed() + } else { + blocker + }; + + let res = ClosingWindow::new( + renderer, + snapshot, + output_scale, + tile_size, + tile_pos, + blocker, + anim, + ); match res { Ok(closing) => { self.closing_windows.push(closing); @@ -1781,6 +1797,7 @@ impl<W: LayoutElement> Workspace<W> { let tile = self.remove_tile_by_idx( source_col_idx, 0, + Transaction::new(), Some(self.options.animations.window_movement.0), ); self.enter_output_for_window(tile.window()); @@ -1813,7 +1830,12 @@ impl<W: LayoutElement> Workspace<W> { let mut offset = Point::from((source_column.render_offset().x, 0.)); - let tile = self.remove_tile_by_idx(source_col_idx, source_column.active_tile_idx, None); + let tile = self.remove_tile_by_idx( + source_col_idx, + source_column.active_tile_idx, + Transaction::new(), + None, + ); self.add_tile_at( self.active_column_idx, @@ -1861,6 +1883,7 @@ impl<W: LayoutElement> Workspace<W> { let tile = self.remove_tile_by_idx( source_col_idx, 0, + Transaction::new(), Some(self.options.animations.window_movement.0), ); self.enter_output_for_window(tile.window()); @@ -1888,7 +1911,12 @@ impl<W: LayoutElement> Workspace<W> { let width = source_column.width; let is_full_width = source_column.is_full_width; - let tile = self.remove_tile_by_idx(source_col_idx, source_column.active_tile_idx, None); + let tile = self.remove_tile_by_idx( + source_col_idx, + source_column.active_tile_idx, + Transaction::new(), + None, + ); self.add_tile( tile, @@ -1921,7 +1949,7 @@ impl<W: LayoutElement> Workspace<W> { let mut offset = Point::from((offset, 0.)); let prev_off = self.columns[source_column_idx].tile_offset(0); - let tile = self.remove_tile_by_idx(source_column_idx, 0, None); + let tile = self.remove_tile_by_idx(source_column_idx, 0, Transaction::new(), None); self.enter_output_for_window(tile.window()); let prev_next_x = self.column_x(self.active_column_idx + 1); @@ -1970,8 +1998,12 @@ impl<W: LayoutElement> Workspace<W> { let width = source_column.width; let is_full_width = source_column.is_full_width; - let tile = - self.remove_tile_by_idx(self.active_column_idx, source_column.active_tile_idx, None); + let tile = self.remove_tile_by_idx( + self.active_column_idx, + source_column.active_tile_idx, + Transaction::new(), + None, + ); self.add_tile( tile, @@ -3031,6 +3063,10 @@ impl<W: LayoutElement> Column<W> { } fn update_tile_sizes(&mut self, animate: bool) { + self.update_tile_sizes_with_transaction(animate, Transaction::new()); + } + + fn update_tile_sizes_with_transaction(&mut self, animate: bool, transaction: Transaction) { if self.is_fullscreen { self.tiles[0].request_fullscreen(self.view_size); return; @@ -3195,7 +3231,6 @@ impl<W: LayoutElement> Column<W> { assert_eq!(auto_tiles_left, 0); } - let transaction = Transaction::new(); for (tile, h) in zip(&mut self.tiles, heights) { let WindowHeight::Fixed(height) = h else { unreachable!() |
