diff --git a/src/shell/layout/floating/mod.rs b/src/shell/layout/floating/mod.rs index a77a2bdf..e30e9291 100644 --- a/src/shell/layout/floating/mod.rs +++ b/src/shell/layout/floating/mod.rs @@ -624,7 +624,9 @@ impl FloatingLayout { ); } - pub fn unmap(&mut self, window: &CosmicMapped) -> bool { + pub fn unmap(&mut self, window: &CosmicMapped) -> Option> { + let mut new_size = None; + if let Some(_) = window.floating_tiled.lock().unwrap().take() { if let Some(last_size) = window.last_geometry.lock().unwrap().map(|geo| geo.size) { if let Some(location) = self.space.element_location(window) { @@ -635,6 +637,7 @@ impl FloatingLayout { .to_global(self.space.outputs().next().unwrap()), ); window.configure(); + new_size = Some(last_size.as_logical()); } } } else if !window.is_maximized(true) && !window.is_fullscreen(true) { @@ -655,13 +658,16 @@ impl FloatingLayout { let was_unmaped = self.space.elements().any(|e| e == window); self.space.unmap_elem(&window); + if was_unmaped { if let Some(pos) = self.spawn_order.iter().position(|w| w == window) { self.spawn_order.truncate(pos); } window.moved_since_mapped.store(true, Ordering::SeqCst); + Some(new_size.unwrap_or_else(|| window.geometry().size)) + } else { + None } - was_unmaped } pub fn unmap_minimize( diff --git a/src/shell/mod.rs b/src/shell/mod.rs index 6b62d352..54749663 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -102,6 +102,7 @@ const ANIMATION_DURATION: Duration = Duration::from_millis(200); const GESTURE_MAX_LENGTH: f64 = 150.0; const GESTURE_POSITION_THRESHOLD: f64 = 0.5; const GESTURE_VELOCITY_THRESHOLD: f64 = 0.02; +const MOVE_GRAB_Y_OFFSET: f64 = 16.; #[derive(Debug, Clone)] pub enum Trigger { @@ -2403,22 +2404,20 @@ impl Shell { let elem_geo = workspace.element_geometry(&old_mapped)?; let mut initial_window_location = elem_geo.loc.to_global(workspace.output()); - if mapped.maximized_state.lock().unwrap().is_some() { + let mut new_size = if mapped.maximized_state.lock().unwrap().is_some() { // If surface is maximized then unmaximize it - let new_size = workspace.unmaximize_request(&mapped); - let output = workspace.output(); - let ratio = pos.to_local(&output).x / output.geometry().size.w as f64; - - initial_window_location = new_size - .map(|size| (pos.x - (size.w as f64 * ratio), pos.y).into()) - .unwrap_or_else(|| pos) - .to_i32_round(); - } + workspace.unmaximize_request(&mapped) + } else { + None + }; let layer = if mapped == old_mapped { let was_floating = workspace.floating_layer.unmap(&mapped); let was_tiled = workspace.tiling_layer.unmap_as_placeholder(&mapped); - assert!(was_floating != was_tiled.is_some()); + assert!(was_floating.is_some() != was_tiled.is_some()); + if was_floating.is_some_and(|size| size != elem_geo.size.as_logical()) { + new_size = was_floating; + } was_tiled.is_some() } else { workspace @@ -2429,6 +2428,18 @@ impl Shell { .then_some(ManagedLayer::Tiling) .unwrap_or(ManagedLayer::Floating); + // if this changed the width, the window was tiled in floating mode + if let Some(new_size) = new_size { + let output = workspace.output(); + let ratio = pos.to_local(&output).x / (elem_geo.loc.x + elem_geo.size.w) as f64; + + initial_window_location = Point::from(( + pos.x - (new_size.w as f64 * ratio), + pos.y - MOVE_GRAB_Y_OFFSET, + )) + .to_i32_round(); + } + (initial_window_location, layer, workspace.handle) } else if let Some(sticky_layer) = self .workspaces @@ -2437,13 +2448,10 @@ impl Shell { .filter(|set| set.sticky_layer.mapped().any(|m| m == &old_mapped)) .map(|set| &mut set.sticky_layer) { - let mut initial_window_location = sticky_layer - .element_geometry(&old_mapped) - .unwrap() - .loc - .to_global(&cursor_output); + let elem_geo = sticky_layer.element_geometry(&old_mapped).unwrap(); + let mut initial_window_location = elem_geo.loc.to_global(&cursor_output); - if let Some(state) = mapped.maximized_state.lock().unwrap().take() { + let mut new_size = if let Some(state) = mapped.maximized_state.lock().unwrap().take() { // If surface is maximized then unmaximize it mapped.set_maximized(false); let new_size = state.original_geometry.size.as_logical(); @@ -2454,14 +2462,27 @@ impl Shell { None, ); - let ratio = pos.to_local(&cursor_output).x / cursor_output.geometry().size.w as f64; - initial_window_location = - Point::::from((pos.x - (new_size.w as f64 * ratio), pos.y)) - .to_i32_round(); - } + Some(new_size) + } else { + None + }; if mapped == old_mapped { - sticky_layer.unmap(&mapped); + if let Some(size) = sticky_layer.unmap(&mapped) { + if size != elem_geo.size.as_logical() { + new_size = Some(size); + } + } + } + + if let Some(new_size) = new_size { + let ratio = + pos.to_local(&cursor_output).x / (elem_geo.loc.x + elem_geo.size.w) as f64; + initial_window_location = Point::::from(( + pos.x - (new_size.w as f64 * ratio), + pos.y - MOVE_GRAB_Y_OFFSET, + )) + .to_i32_round(); } ( diff --git a/src/shell/workspace.rs b/src/shell/workspace.rs index 2192bcf3..f59680ee 100644 --- a/src/shell/workspace.rs +++ b/src/shell/workspace.rs @@ -411,7 +411,7 @@ impl Workspace { let _ = self.unmaximize_request(mapped); } - let mut was_floating = self.floating_layer.unmap(&mapped); + let mut was_floating = self.floating_layer.unmap(&mapped).is_some(); let mut was_tiling = self.tiling_layer.unmap(&mapped); if was_floating || was_tiling { assert!(was_floating != was_tiling); @@ -567,7 +567,7 @@ impl Workspace { }; if self.tiling_layer.mapped().any(|(m, _)| m == elem) { - let was_maximized = self.floating_layer.unmap(&elem); + let was_maximized = self.floating_layer.unmap(&elem).is_some(); let tiling_state = self.tiling_layer.unmap_minimize(elem, to); Some(MinimizedWindow { window: elem.clone(),