aboutsummaryrefslogtreecommitdiff
path: root/src/layout.rs
diff options
context:
space:
mode:
authorIvan Molodetskikh <yalterz@gmail.com>2023-08-14 17:25:28 +0400
committerIvan Molodetskikh <yalterz@gmail.com>2023-08-14 18:37:33 +0400
commitb5c02253ff893c1679aebffb06aafc5aa9db6b58 (patch)
treec4bf600d1458f1e8a7a57e09b20c587d902680e2 /src/layout.rs
parentec5953319c4387219d38a9b6ce3664d2a83ab39e (diff)
downloadniri-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.rs144
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()
+ }
+ }
}
}