floating: Animate tiling state changes

This commit is contained in:
Victoria Brekenfeld 2023-11-14 16:32:49 +01:00 committed by Victoria Brekenfeld
parent 2d15fb9766
commit cf5b21f437
3 changed files with 199 additions and 20 deletions

View file

@ -1154,6 +1154,12 @@ where
TiledOverlay(
RelocateRenderElement<RescaleRenderElement<CropRenderElement<PixelShaderElement>>>,
),
MovingStack(
RelocateRenderElement<RescaleRenderElement<self::stack::CosmicStackRenderElement<R>>>,
),
MovingWindow(
RelocateRenderElement<RescaleRenderElement<self::window::CosmicWindowRenderElement<R>>>,
),
GrabbedStack(RescaleRenderElement<self::stack::CosmicStackRenderElement<R>>),
GrabbedWindow(RescaleRenderElement<self::window::CosmicWindowRenderElement<R>>),
FocusIndicator(PixelShaderElement),
@ -1175,6 +1181,8 @@ where
CosmicMappedRenderElement::TiledStack(elem) => elem.id(),
CosmicMappedRenderElement::TiledWindow(elem) => elem.id(),
CosmicMappedRenderElement::TiledOverlay(elem) => elem.id(),
CosmicMappedRenderElement::MovingStack(elem) => elem.id(),
CosmicMappedRenderElement::MovingWindow(elem) => elem.id(),
CosmicMappedRenderElement::GrabbedStack(elem) => elem.id(),
CosmicMappedRenderElement::GrabbedWindow(elem) => elem.id(),
CosmicMappedRenderElement::FocusIndicator(elem) => elem.id(),
@ -1192,6 +1200,8 @@ where
CosmicMappedRenderElement::TiledStack(elem) => elem.current_commit(),
CosmicMappedRenderElement::TiledWindow(elem) => elem.current_commit(),
CosmicMappedRenderElement::TiledOverlay(elem) => elem.current_commit(),
CosmicMappedRenderElement::MovingStack(elem) => elem.current_commit(),
CosmicMappedRenderElement::MovingWindow(elem) => elem.current_commit(),
CosmicMappedRenderElement::GrabbedStack(elem) => elem.current_commit(),
CosmicMappedRenderElement::GrabbedWindow(elem) => elem.current_commit(),
CosmicMappedRenderElement::FocusIndicator(elem) => elem.current_commit(),
@ -1209,6 +1219,8 @@ where
CosmicMappedRenderElement::TiledStack(elem) => elem.src(),
CosmicMappedRenderElement::TiledWindow(elem) => elem.src(),
CosmicMappedRenderElement::TiledOverlay(elem) => elem.src(),
CosmicMappedRenderElement::MovingStack(elem) => elem.src(),
CosmicMappedRenderElement::MovingWindow(elem) => elem.src(),
CosmicMappedRenderElement::GrabbedStack(elem) => elem.src(),
CosmicMappedRenderElement::GrabbedWindow(elem) => elem.src(),
CosmicMappedRenderElement::FocusIndicator(elem) => elem.src(),
@ -1226,6 +1238,8 @@ where
CosmicMappedRenderElement::TiledStack(elem) => elem.geometry(scale),
CosmicMappedRenderElement::TiledWindow(elem) => elem.geometry(scale),
CosmicMappedRenderElement::TiledOverlay(elem) => elem.geometry(scale),
CosmicMappedRenderElement::MovingStack(elem) => elem.geometry(scale),
CosmicMappedRenderElement::MovingWindow(elem) => elem.geometry(scale),
CosmicMappedRenderElement::GrabbedStack(elem) => elem.geometry(scale),
CosmicMappedRenderElement::GrabbedWindow(elem) => elem.geometry(scale),
CosmicMappedRenderElement::FocusIndicator(elem) => elem.geometry(scale),
@ -1243,6 +1257,8 @@ where
CosmicMappedRenderElement::TiledStack(elem) => elem.location(scale),
CosmicMappedRenderElement::TiledWindow(elem) => elem.location(scale),
CosmicMappedRenderElement::TiledOverlay(elem) => elem.location(scale),
CosmicMappedRenderElement::MovingStack(elem) => elem.location(scale),
CosmicMappedRenderElement::MovingWindow(elem) => elem.location(scale),
CosmicMappedRenderElement::GrabbedStack(elem) => elem.location(scale),
CosmicMappedRenderElement::GrabbedWindow(elem) => elem.location(scale),
CosmicMappedRenderElement::FocusIndicator(elem) => elem.location(scale),
@ -1260,6 +1276,8 @@ where
CosmicMappedRenderElement::TiledStack(elem) => elem.transform(),
CosmicMappedRenderElement::TiledWindow(elem) => elem.transform(),
CosmicMappedRenderElement::TiledOverlay(elem) => elem.transform(),
CosmicMappedRenderElement::MovingStack(elem) => elem.transform(),
CosmicMappedRenderElement::MovingWindow(elem) => elem.transform(),
CosmicMappedRenderElement::GrabbedStack(elem) => elem.transform(),
CosmicMappedRenderElement::GrabbedWindow(elem) => elem.transform(),
CosmicMappedRenderElement::FocusIndicator(elem) => elem.transform(),
@ -1281,6 +1299,8 @@ where
CosmicMappedRenderElement::TiledStack(elem) => elem.damage_since(scale, commit),
CosmicMappedRenderElement::TiledWindow(elem) => elem.damage_since(scale, commit),
CosmicMappedRenderElement::TiledOverlay(elem) => elem.damage_since(scale, commit),
CosmicMappedRenderElement::MovingStack(elem) => elem.damage_since(scale, commit),
CosmicMappedRenderElement::MovingWindow(elem) => elem.damage_since(scale, commit),
CosmicMappedRenderElement::GrabbedStack(elem) => elem.damage_since(scale, commit),
CosmicMappedRenderElement::GrabbedWindow(elem) => elem.damage_since(scale, commit),
CosmicMappedRenderElement::FocusIndicator(elem) => elem.damage_since(scale, commit),
@ -1300,6 +1320,8 @@ where
CosmicMappedRenderElement::TiledStack(elem) => elem.opaque_regions(scale),
CosmicMappedRenderElement::TiledWindow(elem) => elem.opaque_regions(scale),
CosmicMappedRenderElement::TiledOverlay(elem) => elem.opaque_regions(scale),
CosmicMappedRenderElement::MovingStack(elem) => elem.opaque_regions(scale),
CosmicMappedRenderElement::MovingWindow(elem) => elem.opaque_regions(scale),
CosmicMappedRenderElement::GrabbedStack(elem) => elem.opaque_regions(scale),
CosmicMappedRenderElement::GrabbedWindow(elem) => elem.opaque_regions(scale),
CosmicMappedRenderElement::FocusIndicator(elem) => elem.opaque_regions(scale),
@ -1317,6 +1339,8 @@ where
CosmicMappedRenderElement::TiledStack(elem) => elem.alpha(),
CosmicMappedRenderElement::TiledWindow(elem) => elem.alpha(),
CosmicMappedRenderElement::TiledOverlay(elem) => elem.alpha(),
CosmicMappedRenderElement::MovingStack(elem) => elem.alpha(),
CosmicMappedRenderElement::MovingWindow(elem) => elem.alpha(),
CosmicMappedRenderElement::GrabbedStack(elem) => elem.alpha(),
CosmicMappedRenderElement::GrabbedWindow(elem) => elem.alpha(),
CosmicMappedRenderElement::FocusIndicator(elem) => elem.alpha(),
@ -1344,6 +1368,8 @@ impl RenderElement<GlowRenderer> for CosmicMappedRenderElement<GlowRenderer> {
CosmicMappedRenderElement::TiledOverlay(elem) => {
RenderElement::<GlowRenderer>::draw(elem, frame, src, dst, damage)
}
CosmicMappedRenderElement::MovingStack(elem) => elem.draw(frame, src, dst, damage),
CosmicMappedRenderElement::MovingWindow(elem) => elem.draw(frame, src, dst, damage),
CosmicMappedRenderElement::GrabbedStack(elem) => elem.draw(frame, src, dst, damage),
CosmicMappedRenderElement::GrabbedWindow(elem) => elem.draw(frame, src, dst, damage),
CosmicMappedRenderElement::FocusIndicator(elem) => {
@ -1369,6 +1395,8 @@ impl RenderElement<GlowRenderer> for CosmicMappedRenderElement<GlowRenderer> {
CosmicMappedRenderElement::TiledStack(elem) => elem.underlying_storage(renderer),
CosmicMappedRenderElement::TiledWindow(elem) => elem.underlying_storage(renderer),
CosmicMappedRenderElement::TiledOverlay(elem) => elem.underlying_storage(renderer),
CosmicMappedRenderElement::MovingStack(elem) => elem.underlying_storage(renderer),
CosmicMappedRenderElement::MovingWindow(elem) => elem.underlying_storage(renderer),
CosmicMappedRenderElement::GrabbedStack(elem) => elem.underlying_storage(renderer),
CosmicMappedRenderElement::GrabbedWindow(elem) => elem.underlying_storage(renderer),
CosmicMappedRenderElement::FocusIndicator(elem) => elem.underlying_storage(renderer),
@ -1401,6 +1429,8 @@ impl<'a, 'b> RenderElement<GlMultiRenderer<'a, 'b>>
RenderElement::<GlowRenderer>::draw(elem, frame.glow_frame_mut(), src, dst, damage)
.map_err(|err| GlMultiError::Render(err))
}
CosmicMappedRenderElement::MovingStack(elem) => elem.draw(frame, src, dst, damage),
CosmicMappedRenderElement::MovingWindow(elem) => elem.draw(frame, src, dst, damage),
CosmicMappedRenderElement::GrabbedStack(elem) => elem.draw(frame, src, dst, damage),
CosmicMappedRenderElement::GrabbedWindow(elem) => elem.draw(frame, src, dst, damage),
CosmicMappedRenderElement::FocusIndicator(elem) => {
@ -1435,6 +1465,8 @@ impl<'a, 'b> RenderElement<GlMultiRenderer<'a, 'b>>
CosmicMappedRenderElement::TiledOverlay(elem) => {
elem.underlying_storage(renderer.glow_renderer_mut())
}
CosmicMappedRenderElement::MovingStack(elem) => elem.underlying_storage(renderer),
CosmicMappedRenderElement::MovingWindow(elem) => elem.underlying_storage(renderer),
CosmicMappedRenderElement::GrabbedStack(elem) => elem.underlying_storage(renderer),
CosmicMappedRenderElement::GrabbedWindow(elem) => elem.underlying_storage(renderer),
CosmicMappedRenderElement::FocusIndicator(elem) => {

View file

@ -1,16 +1,24 @@
// SPDX-License-Identifier: GPL-3.0-only
use std::sync::atomic::Ordering;
use std::{
collections::HashMap,
sync::atomic::{AtomicBool, Ordering},
time::{Duration, Instant},
};
use keyframe::{ease, functions::EaseInOutCubic};
use smithay::{
backend::renderer::{
element::{AsRenderElements, RenderElement},
element::{
utils::{Relocate, RelocateRenderElement, RescaleRenderElement},
AsRenderElements, RenderElement,
},
ImportAll, ImportMem, Renderer,
},
desktop::{layer_map_for_output, space::SpaceElement, PopupKind, Space, WindowSurfaceType},
input::{pointer::GrabStartData as PointerGrabStartData, Seat},
output::Output,
utils::{IsAlive, Logical, Point, Rectangle, Size},
utils::{IsAlive, Logical, Point, Rectangle, Scale, Size},
wayland::seat::WaylandFocus,
};
@ -28,17 +36,21 @@ use crate::{
CosmicSurface, Direction, FocusResult, MoveResult, ResizeDirection, ResizeMode,
},
state::State,
utils::prelude::*,
utils::{prelude::*, tween::EaseRectangle},
wayland::handlers::xdg_shell::popup::get_popup_toplevel,
};
mod grabs;
pub use self::grabs::*;
pub const ANIMATION_DURATION: Duration = Duration::from_millis(200);
#[derive(Debug, Default)]
pub struct FloatingLayout {
pub(crate) space: Space<CosmicMapped>,
spawn_order: Vec<CosmicMapped>,
tiling_animations: HashMap<CosmicMapped, (Instant, Rectangle<i32, Local>)>,
dirty: AtomicBool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@ -746,11 +758,47 @@ impl FloatingLayout {
let (new_pos, new_size) = (new_geo.loc, new_geo.size);
focused.set_tiled(true); // TODO: More fine grained?
let start_rectangle = if let Some((previous_start, previous_rect)) =
self.tiling_animations.remove(focused)
{
if let Some(target_rect) = tiled_state
.as_ref()
.map(|state| state.relative_geometry(output_geometry))
{
ease(
EaseInOutCubic,
EaseRectangle(previous_rect),
EaseRectangle(target_rect),
Instant::now()
.duration_since(previous_start)
.max(ANIMATION_DURATION)
.as_secs_f64()
/ ANIMATION_DURATION.as_secs_f64(),
)
.unwrap()
} else {
self.space
.element_geometry(focused)
.map(RectExt::as_local)
.unwrap()
}
} else {
self.space
.element_geometry(focused)
.map(RectExt::as_local)
.unwrap()
};
if tiled_state.is_none() {
*focused.last_geometry.lock().unwrap() =
self.space.element_geometry(focused).map(RectExt::as_local);
}
self.tiling_animations
.insert(focused.clone(), (Instant::now(), start_rectangle));
*tiled_state = Some(new_state);
std::mem::drop(tiled_state);
*focused.last_geometry.lock().unwrap() =
self.space.element_geometry(focused).map(RectExt::as_local);
focused.moved_since_mapped.store(true, Ordering::SeqCst);
let focused = focused.clone();
self.map_internal(focused, Some(new_pos), Some(new_size.as_logical()));
@ -773,9 +821,11 @@ impl FloatingLayout {
puffin::profile_function!();
self.space.refresh();
if let Some(pos) = self.spawn_order.iter().position(|w| !w.alive()) {
self.spawn_order.truncate(pos);
}
for element in self
.space
.elements()
@ -790,6 +840,18 @@ impl FloatingLayout {
}
}
pub fn animations_going(&self) -> bool {
self.dirty.swap(false, Ordering::SeqCst) || !self.tiling_animations.is_empty()
}
pub fn update_animation_state(&mut self) {
self.tiling_animations
.retain(|_, (start, _)| Instant::now().duration_since(*start) < ANIMATION_DURATION);
if self.tiling_animations.is_empty() {
self.dirty.store(true, Ordering::SeqCst);
}
}
pub fn merge(&mut self, other: FloatingLayout) {
for element in other.space.elements() {
let elem_loc = other
@ -826,37 +888,120 @@ impl FloatingLayout {
puffin::profile_function!();
let output = self.space.outputs().next().unwrap();
let output_geometry = {
let layers = layer_map_for_output(output);
layers.non_exclusive_zone()
};
let output_scale = output.current_scale().fractional_scale();
let mut window_elements = Vec::new();
let mut popup_elements = Vec::new();
self.space.elements().rev().for_each(|elem| {
let render_location = self.space.element_location(elem).unwrap() - elem.geometry().loc;
let (w_elements, p_elements) = elem.split_render_elements(
let mut geometry = self
.tiling_animations
.get(elem)
.map(|(_, rect)| *rect)
.unwrap_or_else(|| self.space.element_geometry(elem).unwrap().as_local());
let render_location = geometry.loc - elem.geometry().loc.as_local();
let (mut w_elements, p_elements) = elem.split_render_elements(
renderer,
render_location.to_physical_precise_round(output_scale),
render_location
.as_logical()
.to_physical_precise_round(output_scale),
output_scale.into(),
alpha,
);
if focused == Some(elem) && !elem.is_maximized(false) {
let mut indicator_geometry = Rectangle::from_loc_and_size(
self.space.element_location(elem).unwrap(),
elem.geometry().size,
)
.as_local();
if let Some((start, original_geo)) = self.tiling_animations.get(elem) {
if let Some(target_rect) = elem
.floating_tiled
.lock()
.unwrap()
.as_ref()
.map(|state| state.relative_geometry(output_geometry))
{
geometry = ease(
EaseInOutCubic,
EaseRectangle(original_geo.clone()),
EaseRectangle(target_rect),
Instant::now()
.duration_since(*start)
.min(ANIMATION_DURATION)
.as_millis() as f32
/ ANIMATION_DURATION.as_millis() as f32,
)
.unwrap();
let buffer_size = elem.geometry().size;
let scale = Scale {
x: geometry.size.w as f64 / buffer_size.w as f64,
y: geometry.size.h as f64 / buffer_size.h as f64,
};
w_elements = w_elements
.into_iter()
.map(|element| match element {
CosmicMappedRenderElement::Stack(elem) => {
CosmicMappedRenderElement::MovingStack({
let rescaled = RescaleRenderElement::from_element(
elem,
original_geo
.loc
.as_logical()
.to_physical_precise_round(output_scale),
scale,
);
let relocated = RelocateRenderElement::from_element(
rescaled,
(geometry.loc - original_geo.loc)
.as_logical()
.to_physical_precise_round(output_scale),
Relocate::Relative,
);
relocated
})
}
CosmicMappedRenderElement::Window(elem) => {
CosmicMappedRenderElement::MovingWindow({
let rescaled = RescaleRenderElement::from_element(
elem,
original_geo
.loc
.as_logical()
.to_physical_precise_round(output_scale),
scale,
);
let relocated = RelocateRenderElement::from_element(
rescaled,
(geometry.loc - original_geo.loc)
.as_logical()
.to_physical_precise_round(output_scale),
Relocate::Relative,
);
relocated
})
}
x => x,
})
.collect();
}
}
if focused == Some(elem) && !elem.is_maximized(false) {
if let Some((mode, resize)) = resize_indicator.as_mut() {
indicator_geometry.loc -= (18, 18).into();
indicator_geometry.size += (36, 36).into();
resize.resize(indicator_geometry.size.as_logical());
let mut resize_geometry = geometry.clone();
resize_geometry.loc -= (18, 18).into();
resize_geometry.size += (36, 36).into();
resize.resize(resize_geometry.size.as_logical());
resize.output_enter(output, Rectangle::default() /* unused */);
window_elements.extend(
resize
.render_elements::<CosmicWindowRenderElement<R>>(
renderer,
indicator_geometry
resize_geometry
.loc
.as_logical()
.to_physical_precise_round(output_scale),
@ -874,7 +1019,7 @@ impl FloatingLayout {
let element = IndicatorShader::focus_element(
renderer,
Key::Window(Usage::FocusIndicator, elem.clone()),
indicator_geometry,
geometry,
indicator_thickness,
output_scale,
alpha,

View file

@ -260,6 +260,7 @@ impl Workspace {
pub fn animations_going(&self) -> bool {
self.tiling_layer.animations_going()
|| self.floating_layer.animations_going()
|| self
.fullscreen
.as_ref()
@ -310,6 +311,7 @@ impl Workspace {
}
clients.extend(self.tiling_layer.update_animation_state());
self.floating_layer.update_animation_state();
clients
}