From 9da41d46f8aaf0fa2da86a826b9ef37ea139834d Mon Sep 17 00:00:00 2001 From: Victoria Brekenfeld Date: Fri, 5 Jan 2024 20:38:13 +0000 Subject: [PATCH 1/2] floating: Maximize animation --- src/shell/layout/floating/mod.rs | 219 +++++++++++++++++++------------ src/shell/mod.rs | 24 +++- src/shell/workspace.rs | 1 + 3 files changed, 154 insertions(+), 90 deletions(-) diff --git a/src/shell/layout/floating/mod.rs b/src/shell/layout/floating/mod.rs index 5565c1cf..051a78bd 100644 --- a/src/shell/layout/floating/mod.rs +++ b/src/shell/layout/floating/mod.rs @@ -29,14 +29,14 @@ use crate::{ resize_indicator::ResizeIndicator, stack::{CosmicStackRenderElement, MoveResult as StackMoveResult, TAB_HEIGHT}, window::CosmicWindowRenderElement, - CosmicMapped, CosmicMappedRenderElement, CosmicWindow, + CosmicMapped, CosmicMappedRenderElement, CosmicWindow, MaximizedState, }, focus::{ target::{KeyboardFocusTarget, PointerFocusTarget}, FocusStackMut, }, grabs::{ReleaseMode, ResizeEdge}, - CosmicSurface, Direction, MoveResult, ResizeDirection, ResizeMode, + CosmicSurface, Direction, ManagedLayer, MoveResult, ResizeDirection, ResizeMode, }, state::State, utils::{prelude::*, tween::EaseRectangle}, @@ -163,7 +163,12 @@ impl FloatingLayout { let tiled_state = mapped.floating_tiled.lock().unwrap().clone(); if let Some(tiled_state) = tiled_state { let geometry = tiled_state.relative_geometry(output_geometry); - self.map_internal(mapped, Some(geometry.loc), Some(geometry.size.as_logical())); + self.map_internal( + mapped, + Some(geometry.loc), + Some(geometry.size.as_logical()), + None, + ); } else { let geometry = self.space.element_geometry(&mapped).unwrap(); let new_loc = ( @@ -176,7 +181,7 @@ impl FloatingLayout { * output_geometry.size.h + output_geometry.loc.y, ); - self.map_internal(mapped, Some(Point::from(new_loc)), None); + self.map_internal(mapped, Some(Point::from(new_loc)), None, None); } } @@ -191,10 +196,14 @@ impl FloatingLayout { let mapped = mapped.into(); let position = position.into(); - self.map_internal(mapped, position, None) + self.map_internal(mapped, position, None, None) } - pub fn map_maximized(&mut self, mapped: CosmicMapped) { + pub fn map_maximized( + &mut self, + mapped: CosmicMapped, + previous_geometry: Rectangle, + ) { let output = self.space.outputs().next().unwrap().clone(); let layers = layer_map_for_output(&output); let geometry = layers.non_exclusive_zone().as_local(); @@ -211,6 +220,15 @@ impl FloatingLayout { mapped.moved_since_mapped.store(true, Ordering::SeqCst); + self.tiling_animations + .insert(mapped.clone(), (Instant::now(), previous_geometry)); + if mapped.floating_tiled.lock().unwrap().take().is_some() { + if let Some(mut state) = mapped.maximized_state.lock().unwrap().as_mut() { + if let Some(real_old_geo) = mapped.last_geometry.lock().unwrap().clone() { + state.original_geometry = real_old_geo; + } + }; + } self.space .map_element(mapped, geometry.loc.as_logical(), true); } @@ -220,7 +238,9 @@ impl FloatingLayout { mapped: CosmicMapped, position: Option>, size: Option>, + prev: Option>, ) { + let already_mapped = self.space.element_geometry(&mapped).map(RectExt::as_local); let mut win_geo = mapped.geometry().as_local(); let output = self.space.outputs().next().unwrap().clone(); @@ -412,6 +432,11 @@ impl FloatingLayout { mapped .set_geometry(Rectangle::from_loc_and_size(position, win_geo.size).to_global(&output)); mapped.configure(); + + if let Some(previous_geo) = prev.or(already_mapped) { + self.tiling_animations + .insert(mapped.clone(), (Instant::now(), previous_geo)); + } self.space.map_element(mapped, position.as_logical(), false); } @@ -442,6 +467,8 @@ impl FloatingLayout { } } + let _ = self.tiling_animations.remove(window); + let was_unmaped = self.space.elements().any(|e| e == window); self.space.unmap_elem(&window); if was_unmaped { @@ -465,7 +492,7 @@ impl FloatingLayout { } (mapped, geo.loc) } else { - self.map_internal(window.clone(), Some(position), None); + self.map_internal(window.clone(), Some(position), None, None); (window, position) } } @@ -627,7 +654,12 @@ impl FloatingLayout { // if it is just a window self.space.unmap_elem(&mapped); mapped.convert_to_stack((&output, mapped.bbox()), self.theme.clone()); - self.map_internal(mapped.clone(), Some(location.as_local()), Some(geo.size)); + self.map_internal( + mapped.clone(), + Some(location.as_local()), + Some(geo.size), + None, + ); Some(KeyboardFocusTarget::Element(mapped)) } else { // if we have a stack @@ -680,6 +712,7 @@ impl FloatingLayout { &mut self, direction: Direction, seat: &Seat, + layer: ManagedLayer, theme: cosmic::Theme, ) -> MoveResult { let Some(target) = seat.get_keyboard().unwrap().current_focus() else { @@ -725,7 +758,7 @@ impl FloatingLayout { }) .then_some(pos); - self.map_internal(mapped.clone(), position.map(PointExt::as_local), None); + self.map_internal(mapped.clone(), position.map(PointExt::as_local), None, None); MoveResult::ShiftFocus(KeyboardFocusTarget::Element(mapped)) } StackMoveResult::Default => { @@ -803,12 +836,16 @@ impl FloatingLayout { | (Direction::Down, Some(TiledCorners::Top)) | (Direction::Left, Some(TiledCorners::Right)) | (Direction::Right, Some(TiledCorners::Left)) => { - self.tiling_animations - .insert(focused.clone(), (Instant::now(), start_rectangle)); - *tiled_state = None; std::mem::drop(tiled_state); - self.map_maximized(focused.clone()); + let mut maximized_state = focused.maximized_state.lock().unwrap(); + *maximized_state = Some(MaximizedState { + original_geometry: start_rectangle, + original_layer: layer, + }); + std::mem::drop(maximized_state); + + self.map_maximized(focused.clone(), start_rectangle); return MoveResult::Done; } @@ -842,19 +879,29 @@ impl FloatingLayout { focused.set_tiled(true); // TODO: More fine grained? focused.set_maximized(false); - if tiled_state.is_none() && focused.is_maximized(false) { - *focused.last_geometry.lock().unwrap() = - self.space.element_geometry(focused).map(RectExt::as_local); + if tiled_state.is_none() { + let last_geometry = focused + .maximized_state + .lock() + .unwrap() + .take() + .map(|state| state.original_geometry) + .or_else(|| self.space.element_geometry(focused).map(RectExt::as_local)); + + *focused.last_geometry.lock().unwrap() = last_geometry; } - self.tiling_animations - .insert(focused.clone(), (Instant::now(), start_rectangle)); *tiled_state = Some(new_state); std::mem::drop(tiled_state); focused.moved_since_mapped.store(true, Ordering::SeqCst); let focused = focused.clone(); - self.map_internal(focused, Some(new_pos), Some(new_size.as_logical())); + self.map_internal( + focused, + Some(new_pos), + Some(new_size.as_logical()), + Some(start_rectangle), + ); MoveResult::Done } @@ -889,7 +936,7 @@ impl FloatingLayout { { // TODO what about windows leaving to the top with no headerbar to drag? can that happen? (Probably if the user is moving outputs down) *element.last_geometry.lock().unwrap() = None; - self.map_internal(element, None, None); + self.map_internal(element, None, None, None); } } @@ -913,7 +960,7 @@ impl FloatingLayout { .unwrap() .loc .as_local(); - self.map_internal(element.clone(), Some(elem_loc), None); + self.map_internal(element.clone(), Some(elem_loc), None, None); } self.refresh(); //fixup any out of bounds elements } @@ -968,7 +1015,7 @@ impl FloatingLayout { ); if let Some((start, original_geo)) = self.tiling_animations.get(elem) { - if let Some(target_rect) = elem + let target_rect = elem .floating_tiled .lock() .unwrap() @@ -978,72 +1025,72 @@ impl FloatingLayout { elem.is_maximized(true) .then_some(output_geometry.as_local()) }) - { - 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(); + .unwrap_or_else(|| self.space.element_geometry(elem).unwrap().as_local()); + + 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, - }; + 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(); - } + 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) { diff --git a/src/shell/mod.rs b/src/shell/mod.rs index 8c0333f5..2cfa1cbe 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -2324,6 +2324,7 @@ impl Shell { mapped.clone(), Some(state.original_geometry.loc), Some(new_size), + None, ); let ratio = pos.to_local(&output).x / output.geometry().size.w as f64; @@ -2531,6 +2532,16 @@ impl Shell { }; let fullscreen = workspace.fullscreen.as_ref().map(|f| f.surface.clone()); + if last + .maximized_state + .lock() + .unwrap() + .as_ref() + .is_some_and(|state| state.original_layer == ManagedLayer::Tiling) + { + self.unmaximize_request(&last); + } + if let Some(surface) = fullscreen { MoveResult::MoveFurther(KeyboardFocusTarget::Fullscreen(surface)) } else if let Some(set) = self @@ -2539,14 +2550,18 @@ impl Shell { .values_mut() .find(|set| set.sticky_layer.mapped().any(|m| m == &last)) { - set.sticky_layer - .move_current_element(direction, seat, self.theme.clone()) + set.sticky_layer.move_current_element( + direction, + seat, + ManagedLayer::Sticky, + self.theme.clone(), + ) } else { let theme = self.theme.clone(); let workspace = self.active_space_mut(&output); workspace .floating_layer - .move_current_element(direction, seat, theme) + .move_current_element(direction, seat, ManagedLayer::Floating, theme) .or_else(|| workspace.tiling_layer.move_current_node(direction, seat)) } } @@ -2662,7 +2677,7 @@ impl Shell { original_layer, }); std::mem::drop(state); - floating_layer.map_maximized(mapped.clone()); + floating_layer.map_maximized(mapped.clone(), original_geometry); } } @@ -2681,6 +2696,7 @@ impl Shell { mapped.clone(), Some(state.original_geometry.loc), Some(state.original_geometry.size.as_logical()), + None, ); Some(state.original_geometry.size.as_logical()) } else { diff --git a/src/shell/workspace.rs b/src/shell/workspace.rs index 72ec94ed..daecb0f7 100644 --- a/src/shell/workspace.rs +++ b/src/shell/workspace.rs @@ -462,6 +462,7 @@ impl Workspace { elem.clone(), Some(state.original_geometry.loc), Some(state.original_geometry.size.as_logical()), + None, ); Some(state.original_geometry.size.as_logical()) } From 8804a7c543b8953cb0b460562ee12f7511dd682b Mon Sep 17 00:00:00 2001 From: Victoria Brekenfeld Date: Fri, 26 Jan 2024 18:47:59 +0000 Subject: [PATCH 2/2] shell: Handle tiling_enabled for previous_state better --- src/shell/grabs/moving.rs | 31 +++++++++++++++++-------------- src/shell/mod.rs | 14 +++++++------- src/shell/workspace.rs | 6 +++--- 3 files changed, 27 insertions(+), 24 deletions(-) diff --git a/src/shell/grabs/moving.rs b/src/shell/grabs/moving.rs index d7ae34ca..e8545b68 100644 --- a/src/shell/grabs/moving.rs +++ b/src/shell/grabs/moving.rs @@ -546,7 +546,22 @@ impl Drop for MoveGrab { } match previous { - ManagedLayer::Tiling => { + ManagedLayer::Sticky => { + grab_state.window.set_geometry(Rectangle::from_loc_and_size( + window_location, + grab_state.window.geometry().size.as_global(), + )); + let set = state.common.shell.workspaces.sets.get_mut(&output).unwrap(); + let (window, location) = set + .sticky_layer + .drop_window(grab_state.window, window_location.to_local(&output)); + + Some((window, location.to_global(&output))) + } + ManagedLayer::Tiling if state + .common + .shell + .active_space(&output).tiling_enabled => { let (window, location) = state .common .shell @@ -555,7 +570,7 @@ impl Drop for MoveGrab { .drop_window(grab_state.window); Some((window, location.to_global(&output))) } - ManagedLayer::Floating => { + _ => { grab_state.window.set_geometry(Rectangle::from_loc_and_size( window_location, grab_state.window.geometry().size.as_global(), @@ -567,18 +582,6 @@ impl Drop for MoveGrab { ); Some((window, location.to_global(&output))) } - ManagedLayer::Sticky => { - grab_state.window.set_geometry(Rectangle::from_loc_and_size( - window_location, - grab_state.window.geometry().size.as_global(), - )); - let set = state.common.shell.workspaces.sets.get_mut(&output).unwrap(); - let (window, location) = set - .sticky_layer - .drop_window(grab_state.window, window_location.to_local(&output)); - - Some((window, location.to_global(&output))) - } } } else { None diff --git a/src/shell/mod.rs b/src/shell/mod.rs index 2cfa1cbe..2cc44baf 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -1605,12 +1605,12 @@ impl Shell { .sticky_layer .map(mapped, None) } - ManagedLayer::Floating => new_workspace.floating_layer.map(mapped, None), - ManagedLayer::Tiling => { + ManagedLayer::Tiling if new_workspace.tiling_enabled => { new_workspace .tiling_layer .map(mapped, Option::>::None, None) } + _ => new_workspace.floating_layer.map(mapped, None), }; } @@ -1949,7 +1949,7 @@ impl Shell { .space_for_handle_mut(to) .unwrap(); // checked above let focus_stack = seat.map(|seat| to_workspace.focus_stack.get(&seat)); - if window_state.layer == ManagedLayer::Floating { + if window_state.layer == ManagedLayer::Floating || !to_workspace.tiling_enabled { to_workspace.floating_layer.map(mapped.clone(), None); } else { to_workspace.tiling_layer.map( @@ -2934,16 +2934,16 @@ impl Shell { .take() .unwrap_or(ManagedLayer::Floating) { - ManagedLayer::Floating => { - workspace.floating_layer.map(mapped.clone(), geometry.loc) - } - ManagedLayer::Tiling => { + ManagedLayer::Tiling if workspace.tiling_enabled => { let focus_stack = workspace.focus_stack.get(seat); workspace .tiling_layer .map(mapped.clone(), Some(focus_stack.iter()), None); } ManagedLayer::Sticky => unreachable!(), + _ => { + workspace.floating_layer.map(mapped.clone(), geometry.loc) + } } } } diff --git a/src/shell/workspace.rs b/src/shell/workspace.rs index daecb0f7..a9b8e090 100644 --- a/src/shell/workspace.rs +++ b/src/shell/workspace.rs @@ -444,7 +444,7 @@ impl Workspace { let mut state = elem.maximized_state.lock().unwrap(); if let Some(state) = state.take() { match state.original_layer { - ManagedLayer::Tiling => { + ManagedLayer::Tiling if self.tiling_enabled => { // should still be mapped in tiling self.floating_layer.unmap(&elem); elem.output_enter(&self.output, elem.bbox()); @@ -456,7 +456,8 @@ impl Workspace { .element_geometry(&elem) .map(|geo| geo.size.as_logical()) } - ManagedLayer::Floating => { + ManagedLayer::Sticky => unreachable!(), + _ => { elem.set_maximized(false); self.floating_layer.map_internal( elem.clone(), @@ -466,7 +467,6 @@ impl Workspace { ); Some(state.original_geometry.size.as_logical()) } - ManagedLayer::Sticky => unreachable!(), } } else { None