diff options
| author | Ivan Molodetskikh <yalterz@gmail.com> | 2023-08-14 17:25:28 +0400 |
|---|---|---|
| committer | Ivan Molodetskikh <yalterz@gmail.com> | 2023-08-14 18:37:33 +0400 |
| commit | b5c02253ff893c1679aebffb06aafc5aa9db6b58 (patch) | |
| tree | c4bf600d1458f1e8a7a57e09b20c587d902680e2 /src/layout.rs | |
| parent | ec5953319c4387219d38a9b6ce3664d2a83ab39e (diff) | |
| download | niri-b5c02253ff893c1679aebffb06aafc5aa9db6b58.tar.gz niri-b5c02253ff893c1679aebffb06aafc5aa9db6b58.tar.bz2 niri-b5c02253ff893c1679aebffb06aafc5aa9db6b58.zip | |
Add workspace switch animations
Diffstat (limited to 'src/layout.rs')
| -rw-r--r-- | src/layout.rs | 144 |
1 files changed, 118 insertions, 26 deletions
diff --git a/src/layout.rs b/src/layout.rs index 5b0c666c..e938ff86 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -34,6 +34,9 @@ use std::mem; use std::time::Duration; use smithay::backend::renderer::element::surface::WaylandSurfaceRenderElement; +use smithay::backend::renderer::element::utils::{ + CropRenderElement, Relocate, RelocateRenderElement, +}; use smithay::backend::renderer::element::AsRenderElements; use smithay::backend::renderer::gles::GlesRenderer; use smithay::desktop::space::SpaceElement; @@ -52,7 +55,8 @@ const PADDING: i32 = 16; pub struct OutputId(String); pub type WorkspaceRenderElement<R> = WaylandSurfaceRenderElement<R>; -pub type MonitorRenderElement<R> = WorkspaceRenderElement<R>; +pub type MonitorRenderElement<R> = + RelocateRenderElement<CropRenderElement<WorkspaceRenderElement<R>>>; pub trait LayoutElement: SpaceElement + PartialEq + Clone { fn request_size(&self, size: Size<i32, Logical>); @@ -92,6 +96,8 @@ pub struct Monitor<W: LayoutElement> { workspaces: Vec<Workspace<W>>, /// Index of the currently active workspace. active_workspace_idx: usize, + /// Animation for workspace switching. + workspace_idx_anim: Option<Animation>, } #[derive(Debug)] @@ -237,11 +243,7 @@ impl<W: LayoutElement> MonitorSet<W> { ws.set_output(Some(output.clone())); } - monitors.push(Monitor { - output, - workspaces, - active_workspace_idx: 0, - }); + monitors.push(Monitor::new(output, workspaces)); MonitorSet::Normal { monitors, primary_idx, @@ -256,11 +258,7 @@ impl<W: LayoutElement> MonitorSet<W> { workspace.set_output(Some(output.clone())); } - let monitor = Monitor { - output, - workspaces, - active_workspace_idx: 0, - }; + let monitor = Monitor::new(output, workspaces); MonitorSet::Normal { monitors: vec![monitor], primary_idx: 0, @@ -481,7 +479,8 @@ impl<W: LayoutElement> MonitorSet<W> { for (workspace_idx, ws) in mon.workspaces.iter_mut().enumerate() { if ws.has_window(window) { *active_monitor_idx = monitor_idx; - mon.active_workspace_idx = workspace_idx; + // TODO + assert_eq!(mon.active_workspace_idx, workspace_idx); ws.activate_window(window); break; } @@ -757,17 +756,42 @@ impl<W: LayoutElement> Default for MonitorSet<W> { } impl<W: LayoutElement> Monitor<W> { + fn new(output: Output, workspaces: Vec<Workspace<W>>) -> Self { + Self { + output, + workspaces, + active_workspace_idx: 0, + workspace_idx_anim: None, + } + } + fn active_workspace(&mut self) -> &mut Workspace<W> { &mut self.workspaces[self.active_workspace_idx] } + fn activate_workspace(&mut self, idx: usize) { + if self.active_workspace_idx == idx { + return; + } + + let current_idx = self + .workspace_idx_anim + .as_ref() + .map(|anim| anim.value()) + .unwrap_or(self.active_workspace_idx as f64); + + self.active_workspace_idx = idx; + + self.workspace_idx_anim = Some(Animation::new( + current_idx, + idx as f64, + Duration::from_millis(250), + )); + } + pub fn add_window(&mut self, workspace_idx: usize, window: W, activate: bool) { let workspace = &mut self.workspaces[workspace_idx]; - if activate { - self.active_workspace_idx = workspace_idx; - } - workspace.add_window(window.clone(), activate); if workspace_idx == self.workspaces.len() - 1 { @@ -775,9 +799,15 @@ impl<W: LayoutElement> Monitor<W> { let ws = Workspace::new(self.output.clone()); self.workspaces.push(ws); } + + if activate { + self.activate_workspace(workspace_idx); + } } fn clean_up_workspaces(&mut self) { + assert!(self.workspace_idx_anim.is_none()); + for idx in (0..self.workspaces.len() - 1).rev() { if self.active_workspace_idx == idx { continue; @@ -842,8 +872,6 @@ impl<W: LayoutElement> Monitor<W> { workspace.remove_window(&window); self.add_window(new_idx, window, true); - - self.clean_up_workspaces(); } pub fn move_to_workspace_down(&mut self) { @@ -864,18 +892,17 @@ impl<W: LayoutElement> Monitor<W> { workspace.remove_window(&window); self.add_window(new_idx, window, true); - - self.clean_up_workspaces(); } pub fn switch_workspace_up(&mut self) { - self.active_workspace_idx = self.active_workspace_idx.saturating_sub(1); - self.clean_up_workspaces(); + self.activate_workspace(self.active_workspace_idx.saturating_sub(1)); } pub fn switch_workspace_down(&mut self) { - self.active_workspace_idx = min(self.active_workspace_idx + 1, self.workspaces.len() - 1); - self.clean_up_workspaces(); + self.activate_workspace(min( + self.active_workspace_idx + 1, + self.workspaces.len() - 1, + )); } pub fn consume_into_column(&mut self) { @@ -897,6 +924,14 @@ impl<W: LayoutElement> Monitor<W> { } pub fn advance_animations(&mut self, current_time: Duration) { + if let Some(anim) = &mut self.workspace_idx_anim { + anim.set_current_time(current_time); + if anim.is_done() { + self.workspace_idx_anim = None; + self.clean_up_workspaces(); + } + } + for ws in &mut self.workspaces { ws.advance_animations(current_time); } @@ -907,8 +942,65 @@ impl Monitor<Window> { pub fn render_elements( &self, renderer: &mut GlesRenderer, - ) -> Vec<WorkspaceRenderElement<GlesRenderer>> { - self.workspaces[self.active_workspace_idx].render_elements(renderer) + ) -> Vec<MonitorRenderElement<GlesRenderer>> { + let output_transform = self.output.current_transform(); + let output_mode = self.output.current_mode().unwrap(); + let output_size = output_transform.transform_size(output_mode.size); + + match &self.workspace_idx_anim { + Some(anim) => { + let render_idx = anim.value(); + let below_idx = render_idx.floor() as usize; + let above_idx = render_idx.ceil() as usize; + + let offset = + ((render_idx - below_idx as f64) * output_size.h as f64).round() as i32; + + let below = self.workspaces[below_idx].render_elements(renderer); + let above = self.workspaces[above_idx].render_elements(renderer); + + let below = below.into_iter().filter_map(|elem| { + Some(RelocateRenderElement::from_element( + CropRenderElement::from_element( + elem, + 1., + Rectangle::from_loc_and_size((0, 0), output_size), + )?, + (0, -offset), + Relocate::Relative, + )) + }); + let above = above.into_iter().filter_map(|elem| { + Some(RelocateRenderElement::from_element( + CropRenderElement::from_element( + elem, + 1., + Rectangle::from_loc_and_size((0, 0), output_size), + )?, + (0, -offset + output_size.h), + Relocate::Relative, + )) + }); + below.chain(above).collect() + } + None => { + let elements = self.workspaces[self.active_workspace_idx].render_elements(renderer); + elements + .into_iter() + .filter_map(|elem| { + Some(RelocateRenderElement::from_element( + CropRenderElement::from_element( + elem, + 1., + Rectangle::from_loc_and_size((0, 0), output_size), + )?, + (0, 0), + Relocate::Relative, + )) + }) + .collect() + } + } } } |
