floating: Animate tiling state changes
This commit is contained in:
parent
2d15fb9766
commit
cf5b21f437
3 changed files with 199 additions and 20 deletions
|
|
@ -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) => {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue