Add workspace switch animations

This commit is contained in:
Ivan Molodetskikh
2023-08-14 17:25:28 +04:00
parent ec5953319c
commit b5c02253ff
+118 -26
View File
@@ -34,6 +34,9 @@ use std::mem;
use std::time::Duration; use std::time::Duration;
use smithay::backend::renderer::element::surface::WaylandSurfaceRenderElement; 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::element::AsRenderElements;
use smithay::backend::renderer::gles::GlesRenderer; use smithay::backend::renderer::gles::GlesRenderer;
use smithay::desktop::space::SpaceElement; use smithay::desktop::space::SpaceElement;
@@ -52,7 +55,8 @@ const PADDING: i32 = 16;
pub struct OutputId(String); pub struct OutputId(String);
pub type WorkspaceRenderElement<R> = WaylandSurfaceRenderElement<R>; 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 { pub trait LayoutElement: SpaceElement + PartialEq + Clone {
fn request_size(&self, size: Size<i32, Logical>); fn request_size(&self, size: Size<i32, Logical>);
@@ -92,6 +96,8 @@ pub struct Monitor<W: LayoutElement> {
workspaces: Vec<Workspace<W>>, workspaces: Vec<Workspace<W>>,
/// Index of the currently active workspace. /// Index of the currently active workspace.
active_workspace_idx: usize, active_workspace_idx: usize,
/// Animation for workspace switching.
workspace_idx_anim: Option<Animation>,
} }
#[derive(Debug)] #[derive(Debug)]
@@ -237,11 +243,7 @@ impl<W: LayoutElement> MonitorSet<W> {
ws.set_output(Some(output.clone())); ws.set_output(Some(output.clone()));
} }
monitors.push(Monitor { monitors.push(Monitor::new(output, workspaces));
output,
workspaces,
active_workspace_idx: 0,
});
MonitorSet::Normal { MonitorSet::Normal {
monitors, monitors,
primary_idx, primary_idx,
@@ -256,11 +258,7 @@ impl<W: LayoutElement> MonitorSet<W> {
workspace.set_output(Some(output.clone())); workspace.set_output(Some(output.clone()));
} }
let monitor = Monitor { let monitor = Monitor::new(output, workspaces);
output,
workspaces,
active_workspace_idx: 0,
};
MonitorSet::Normal { MonitorSet::Normal {
monitors: vec![monitor], monitors: vec![monitor],
primary_idx: 0, primary_idx: 0,
@@ -481,7 +479,8 @@ impl<W: LayoutElement> MonitorSet<W> {
for (workspace_idx, ws) in mon.workspaces.iter_mut().enumerate() { for (workspace_idx, ws) in mon.workspaces.iter_mut().enumerate() {
if ws.has_window(window) { if ws.has_window(window) {
*active_monitor_idx = monitor_idx; *active_monitor_idx = monitor_idx;
mon.active_workspace_idx = workspace_idx; // TODO
assert_eq!(mon.active_workspace_idx, workspace_idx);
ws.activate_window(window); ws.activate_window(window);
break; break;
} }
@@ -757,17 +756,42 @@ impl<W: LayoutElement> Default for MonitorSet<W> {
} }
impl<W: LayoutElement> Monitor<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> { fn active_workspace(&mut self) -> &mut Workspace<W> {
&mut self.workspaces[self.active_workspace_idx] &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) { pub fn add_window(&mut self, workspace_idx: usize, window: W, activate: bool) {
let workspace = &mut self.workspaces[workspace_idx]; let workspace = &mut self.workspaces[workspace_idx];
if activate {
self.active_workspace_idx = workspace_idx;
}
workspace.add_window(window.clone(), activate); workspace.add_window(window.clone(), activate);
if workspace_idx == self.workspaces.len() - 1 { if workspace_idx == self.workspaces.len() - 1 {
@@ -775,9 +799,15 @@ impl<W: LayoutElement> Monitor<W> {
let ws = Workspace::new(self.output.clone()); let ws = Workspace::new(self.output.clone());
self.workspaces.push(ws); self.workspaces.push(ws);
} }
if activate {
self.activate_workspace(workspace_idx);
}
} }
fn clean_up_workspaces(&mut self) { fn clean_up_workspaces(&mut self) {
assert!(self.workspace_idx_anim.is_none());
for idx in (0..self.workspaces.len() - 1).rev() { for idx in (0..self.workspaces.len() - 1).rev() {
if self.active_workspace_idx == idx { if self.active_workspace_idx == idx {
continue; continue;
@@ -842,8 +872,6 @@ impl<W: LayoutElement> Monitor<W> {
workspace.remove_window(&window); workspace.remove_window(&window);
self.add_window(new_idx, window, true); self.add_window(new_idx, window, true);
self.clean_up_workspaces();
} }
pub fn move_to_workspace_down(&mut self) { pub fn move_to_workspace_down(&mut self) {
@@ -864,18 +892,17 @@ impl<W: LayoutElement> Monitor<W> {
workspace.remove_window(&window); workspace.remove_window(&window);
self.add_window(new_idx, window, true); self.add_window(new_idx, window, true);
self.clean_up_workspaces();
} }
pub fn switch_workspace_up(&mut self) { pub fn switch_workspace_up(&mut self) {
self.active_workspace_idx = self.active_workspace_idx.saturating_sub(1); self.activate_workspace(self.active_workspace_idx.saturating_sub(1));
self.clean_up_workspaces();
} }
pub fn switch_workspace_down(&mut self) { pub fn switch_workspace_down(&mut self) {
self.active_workspace_idx = min(self.active_workspace_idx + 1, self.workspaces.len() - 1); self.activate_workspace(min(
self.clean_up_workspaces(); self.active_workspace_idx + 1,
self.workspaces.len() - 1,
));
} }
pub fn consume_into_column(&mut self) { 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) { 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 { for ws in &mut self.workspaces {
ws.advance_animations(current_time); ws.advance_animations(current_time);
} }
@@ -907,8 +942,65 @@ impl Monitor<Window> {
pub fn render_elements( pub fn render_elements(
&self, &self,
renderer: &mut GlesRenderer, renderer: &mut GlesRenderer,
) -> Vec<WorkspaceRenderElement<GlesRenderer>> { ) -> Vec<MonitorRenderElement<GlesRenderer>> {
self.workspaces[self.active_workspace_idx].render_elements(renderer) 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()
}
}
} }
} }