From f2efc5d56f88a7ef727de41b3e2cce2b0089850c Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Thu, 11 Apr 2024 13:47:37 -0700 Subject: [PATCH] shell: Fix `MoveGrab` with touch not on output pointer is on --- src/backend/render/mod.rs | 2 +- src/shell/grabs/moving.rs | 25 +++-- src/shell/mod.rs | 190 +++++++++++++++++++++----------------- 3 files changed, 118 insertions(+), 99 deletions(-) diff --git a/src/backend/render/mod.rs b/src/backend/render/mod.rs index c9f8d81e..6131ac11 100644 --- a/src/backend/render/mod.rs +++ b/src/backend/render/mod.rs @@ -445,7 +445,7 @@ where .unwrap() .borrow() .as_ref() - .map(|state| state.render::, R>(renderer, seat, output, theme)) + .map(|state| state.render::, R>(renderer, output, theme)) { elements.extend(grab_elements); } diff --git a/src/shell/grabs/moving.rs b/src/shell/grabs/moving.rs index 7803b385..51c21818 100644 --- a/src/shell/grabs/moving.rs +++ b/src/shell/grabs/moving.rs @@ -60,17 +60,12 @@ pub struct MoveGrabState { snapping_zone: Option, stacking_indicator: Option<(StackHover, Point)>, location: Point, + cursor_output: Output, } impl MoveGrabState { #[profiling::function] - pub fn render( - &self, - renderer: &mut R, - seat: &Seat, - output: &Output, - theme: &CosmicTheme, - ) -> Vec + pub fn render(&self, renderer: &mut R, output: &Output, theme: &CosmicTheme) -> Vec where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, ::TextureId: 'static, @@ -86,7 +81,7 @@ impl MoveGrabState { } else { 1.0 }; - let alpha = if &seat.active_output() == output { + let alpha = if &self.cursor_output == output { 1.0 } else { 0.4 @@ -147,7 +142,7 @@ impl MoveGrabState { }; let snapping_indicator = match &self.snapping_zone { - Some(t) if &seat.active_output() == output => { + Some(t) if &self.cursor_output == output => { let base_color = theme.palette.neutral_9; let overlay_geometry = t.overlay_geometry(non_exclusive_geometry); vec![ @@ -363,6 +358,7 @@ impl MoveGrab { .map(|s| s.borrow_mut()); if let Some(grab_state) = borrow.as_mut().and_then(|s| s.as_mut()) { grab_state.location = location; + grab_state.cursor_output = self.cursor_output.clone(); let mut window_geo = self.window.geometry(); window_geo.loc += location.to_i32_round() + grab_state.window_offset; @@ -644,15 +640,15 @@ impl MoveGrab { window: CosmicMapped, seat: &Seat, initial_window_location: Point, + cursor_output: Output, indicator_thickness: u8, previous_layer: ManagedLayer, release: ReleaseMode, evlh: LoopHandle<'static, State>, ) -> MoveGrab { - let output = seat.active_output(); let mut outputs = HashSet::new(); - outputs.insert(output.clone()); - window.output_enter(&output, window.geometry()); // not accurate but... + outputs.insert(cursor_output.clone()); + window.output_enter(&cursor_output, window.geometry()); // not accurate but... window.moved_since_mapped.store(true, Ordering::SeqCst); let grab_state = MoveGrabState { @@ -666,6 +662,7 @@ impl MoveGrab { snapping_zone: None, previous: previous_layer, location: start_data.location(), + cursor_output: cursor_output.clone(), }; *seat @@ -684,7 +681,7 @@ impl MoveGrab { start_data, seat: seat.clone(), window_outputs: outputs, - cursor_output: output, + cursor_output, previous: previous_layer, release, evlh: NotSend(evlh), @@ -699,7 +696,7 @@ impl MoveGrab { impl Drop for MoveGrab { fn drop(&mut self) { // No more buttons are pressed, release the grab. - let output = self.seat.active_output(); + let output = self.cursor_output.clone(); let seat = self.seat.clone(); let window_outputs = self.window_outputs.drain().collect::>(); let previous = self.previous; diff --git a/src/shell/mod.rs b/src/shell/mod.rs index d61f3bb0..481d2b0f 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -2460,7 +2460,6 @@ impl Shell { move_out_of_stack: bool, ) { let serial = serial.into(); - let output = seat.active_output(); if let Some(mut start_data) = check_grab_preconditions(&seat, surface, serial, release) { if let Some(mut old_mapped) = state.common.shell.element_for_surface(surface).cloned() { @@ -2505,91 +2504,113 @@ impl Shell { }; let pos = start_data.location().as_global(); - let (initial_window_location, layer, workspace_handle) = - if let Some(workspace) = state.common.shell.space_for_mut(&old_mapped) { - if workspace - .fullscreen - .as_ref() - .is_some_and(|f| f.surface == window) - { - let _ = workspace.remove_fullscreen(); // We are moving this window, we don't need to send it back to it's original workspace - } - - let Some(elem_geo) = workspace.element_geometry(&old_mapped) else { - return; - }; - let mut initial_window_location = elem_geo.loc.to_global(&output); - - if mapped.maximized_state.lock().unwrap().is_some() { - // If surface is maximized then unmaximize it - let new_size = workspace.unmaximize_request(&mapped); - 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(); - } - - 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()); - was_tiled.is_some() - } else { - workspace - .tiling_layer - .mapped() - .any(|(m, _)| m == &old_mapped) - } - .then_some(ManagedLayer::Tiling) - .unwrap_or(ManagedLayer::Floating); - - (initial_window_location, layer, workspace.handle) - } else if let Some(sticky_layer) = state - .common - .shell - .workspaces - .sets - .get_mut(&output) - .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(&output); - - 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(); - sticky_layer.map_internal( - mapped.clone(), - Some(state.original_geometry.loc), - Some(new_size), - None, - ); - - let ratio = pos.to_local(&output).x / output.geometry().size.w as f64; - initial_window_location = - Point::::from((pos.x - (new_size.w as f64 * ratio), pos.y)) - .to_i32_round(); - } - - if mapped == old_mapped { - sticky_layer.unmap(&mapped); - } - - ( - initial_window_location, - ManagedLayer::Sticky, - state.common.shell.active_space(&output).handle, + let cursor_output = if let Some(output) = state + .common + .shell + .outputs() + .find(|output| { + output.geometry().as_logical().overlaps_or_touches( + Rectangle::from_loc_and_size( + start_data.location().to_i32_floor(), + (0, 0), + ), ) - } else { + }) + .cloned() + { + output + } else { + seat.active_output() + }; + + let (initial_window_location, layer, workspace_handle) = if let Some(workspace) = + state.common.shell.space_for_mut(&old_mapped) + { + if workspace + .fullscreen + .as_ref() + .is_some_and(|f| f.surface == window) + { + let _ = workspace.remove_fullscreen(); // We are moving this window, we don't need to send it back to it's original workspace + } + + let Some(elem_geo) = workspace.element_geometry(&old_mapped) else { return; }; + let mut initial_window_location = elem_geo.loc.to_global(&workspace.output()); + + 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(); + } + + 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()); + was_tiled.is_some() + } else { + workspace + .tiling_layer + .mapped() + .any(|(m, _)| m == &old_mapped) + } + .then_some(ManagedLayer::Tiling) + .unwrap_or(ManagedLayer::Floating); + + (initial_window_location, layer, workspace.handle) + } else if let Some(sticky_layer) = state + .common + .shell + .workspaces + .sets + .get_mut(&cursor_output) + .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); + + 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(); + sticky_layer.map_internal( + mapped.clone(), + Some(state.original_geometry.loc), + Some(new_size), + 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(); + } + + if mapped == old_mapped { + sticky_layer.unmap(&mapped); + } + + ( + initial_window_location, + ManagedLayer::Sticky, + state.common.shell.active_space(&cursor_output).handle, + ) + } else { + return; + }; state .common @@ -2600,7 +2621,7 @@ impl Shell { .common .shell .toplevel_info_state - .toplevel_leave_output(&window, &output); + .toplevel_leave_output(&window, &cursor_output); if move_out_of_stack { old_mapped.stack_ref_mut().unwrap().remove_window(&window); @@ -2620,6 +2641,7 @@ impl Shell { mapped, seat, initial_window_location, + cursor_output, active_hint as u8, layer, release,