mirror of
https://github.com/niri-wm/niri.git
synced 2026-06-23 02:05:33 +07:00
Add workspace switch animations
This commit is contained in:
+118
-26
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user