move_grab: End correctly when removed externally

This commit is contained in:
Victoria Brekenfeld 2023-12-11 16:11:07 +00:00 committed by Victoria Brekenfeld
parent 131ab8fe9e
commit e347076145
4 changed files with 102 additions and 87 deletions

View file

@ -1161,6 +1161,7 @@ impl PointerTarget<State> for CosmicStack {
indicator_thickness, indicator_thickness,
was_tiled, was_tiled,
ReleaseMode::NoMouseButtons, ReleaseMode::NoMouseButtons,
data.common.event_loop_handle.clone(),
); );
if grab.is_tiling_grab() { if grab.is_tiling_grab() {
data.common.shell.set_overview_mode( data.common.shell.set_overview_mode(

View file

@ -17,6 +17,7 @@ use crate::{
utils::prelude::*, utils::prelude::*,
}; };
use calloop::LoopHandle;
use cosmic::theme::CosmicTheme; use cosmic::theme::CosmicTheme;
use smithay::{ use smithay::{
backend::{ backend::{
@ -39,7 +40,7 @@ use smithay::{
}, },
output::Output, output::Output,
reexports::wayland_server::protocol::wl_surface::WlSurface, reexports::wayland_server::protocol::wl_surface::WlSurface,
utils::{IsAlive, Logical, Point, Rectangle, Scale, Serial}, utils::{IsAlive, Logical, Point, Rectangle, Scale, SERIAL_COUNTER},
wayland::compositor::SurfaceData, wayland::compositor::SurfaceData,
}; };
use std::{ use std::{
@ -215,6 +216,9 @@ impl MoveGrabState {
} }
} }
struct NotSend<T>(pub T);
unsafe impl<T> Send for NotSend<T> {}
pub struct MoveGrab { pub struct MoveGrab {
window: CosmicMapped, window: CosmicMapped,
start_data: PointerGrabStartData<State>, start_data: PointerGrabStartData<State>,
@ -223,6 +227,8 @@ pub struct MoveGrab {
window_outputs: HashSet<Output>, window_outputs: HashSet<Output>,
tiling: bool, tiling: bool,
release: ReleaseMode, release: ReleaseMode,
// SAFETY: This is only used on drop which will always be on the main thread
evlh: NotSend<LoopHandle<'static, State>>,
} }
impl PointerGrab<State> for MoveGrab { impl PointerGrab<State> for MoveGrab {
@ -318,7 +324,7 @@ impl PointerGrab<State> for MoveGrab {
// While the grab is active, no client has pointer focus // While the grab is active, no client has pointer focus
handle.motion(state, None, event); handle.motion(state, None, event);
if !self.window.alive() { if !self.window.alive() {
self.ungrab(state, handle, event.serial, event.time); handle.unset_grab(state, event.serial, event.time, true);
} }
} }
@ -343,12 +349,12 @@ impl PointerGrab<State> for MoveGrab {
match self.release { match self.release {
ReleaseMode::NoMouseButtons => { ReleaseMode::NoMouseButtons => {
if handle.current_pressed().is_empty() { if handle.current_pressed().is_empty() {
self.ungrab(state, handle, event.serial, event.time); handle.unset_grab(state, event.serial, event.time, true);
} }
} }
ReleaseMode::Click => { ReleaseMode::Click => {
if event.state == ButtonState::Pressed { if event.state == ButtonState::Pressed {
self.ungrab(state, handle, event.serial, event.time); handle.unset_grab(state, event.serial, event.time, true);
} }
} }
} }
@ -454,6 +460,7 @@ impl MoveGrab {
indicator_thickness: u8, indicator_thickness: u8,
was_tiled: bool, was_tiled: bool,
release: ReleaseMode, release: ReleaseMode,
evlh: LoopHandle<'static, State>,
) -> MoveGrab { ) -> MoveGrab {
let output = seat.active_output(); let output = seat.active_output();
let mut outputs = HashSet::new(); let mut outputs = HashSet::new();
@ -490,106 +497,109 @@ impl MoveGrab {
cursor_output: output, cursor_output: output,
tiling: was_tiled, tiling: was_tiled,
release, release,
evlh: NotSend(evlh),
} }
} }
pub fn is_tiling_grab(&self) -> bool { pub fn is_tiling_grab(&self) -> bool {
self.tiling self.tiling
} }
}
fn ungrab( impl Drop for MoveGrab {
&mut self, fn drop(&mut self) {
state: &mut State,
handle: &mut PointerInnerHandle<'_, State>,
serial: Serial,
time: u32,
) {
// No more buttons are pressed, release the grab. // No more buttons are pressed, release the grab.
let output = self.seat.active_output(); let output = self.seat.active_output();
let seat = self.seat.clone();
let window_outputs = self.window_outputs.drain().collect::<HashSet<_>>();
let tiling = self.tiling;
let window = self.window.clone();
let position: Option<(CosmicMapped, Point<i32, Global>)> = if let Some(grab_state) = self let _ = self.evlh.0.insert_idle(move |state| {
.seat let pointer = seat.get_pointer().unwrap();
.user_data()
.get::<SeatMoveGrabState>()
.and_then(|s| s.borrow_mut().take())
{
if grab_state.window.alive() {
let window_location = (handle.current_location().to_i32_round()
+ grab_state.window_offset)
.as_global();
let workspace_handle = state.common.shell.active_space(&output).handle; let position: Option<(CosmicMapped, Point<i32, Global>)> = if let Some(grab_state) =
for old_output in self.window_outputs.iter().filter(|o| *o != &output) { seat.user_data()
grab_state.window.output_leave(old_output); .get::<SeatMoveGrabState>()
} .and_then(|s| s.borrow_mut().take())
for (window, _) in grab_state.window.windows() { {
state if grab_state.window.alive() {
.common let window_location = (pointer.current_location().to_i32_round()
.shell + grab_state.window_offset)
.toplevel_info_state .as_global();
.toplevel_enter_workspace(&window, &workspace_handle);
state
.common
.shell
.toplevel_info_state
.toplevel_enter_output(&window, &output);
}
if self.tiling { let workspace_handle = state.common.shell.active_space(&output).handle;
let (window, location) = state for old_output in window_outputs.iter().filter(|o| *o != &output) {
.common grab_state.window.output_leave(old_output);
.shell }
.active_space_mut(&output) for (window, _) in grab_state.window.windows() {
.tiling_layer state
.drop_window(grab_state.window); .common
Some((window, location.to_global(&output))) .shell
.toplevel_info_state
.toplevel_enter_workspace(&window, &workspace_handle);
state
.common
.shell
.toplevel_info_state
.toplevel_enter_output(&window, &output);
}
if tiling {
let (window, location) = state
.common
.shell
.active_space_mut(&output)
.tiling_layer
.drop_window(grab_state.window);
Some((window, location.to_global(&output)))
} else {
grab_state.window.set_geometry(Rectangle::from_loc_and_size(
window_location,
grab_state.window.geometry().size.as_global(),
));
let workspace = state.common.shell.active_space_mut(&output);
workspace.floating_layer.map_internal(
grab_state.window,
Some(window_location.to_local(&workspace.output)),
None,
);
Some((window.clone(), window_location))
}
} else { } else {
grab_state.window.set_geometry(Rectangle::from_loc_and_size( None
window_location,
grab_state.window.geometry().size.as_global(),
));
let workspace = state.common.shell.active_space_mut(&output);
workspace.floating_layer.map_internal(
grab_state.window,
Some(window_location.to_local(&workspace.output)),
None,
);
Some((self.window.clone(), window_location))
} }
} else { } else {
None None
};
{
let cursor_state = seat.user_data().get::<CursorState>().unwrap();
cursor_state.set_shape(CursorShape::Default);
} }
} else {
None
};
handle.unset_grab(state, serial, time, true); if let Some((mapped, position)) = position {
let serial = SERIAL_COUNTER.next_serial();
{ pointer.motion(
let cursor_state = self.seat.user_data().get::<CursorState>().unwrap(); state,
cursor_state.set_shape(CursorShape::Default); Some((
} PointerFocusTarget::from(mapped.clone()),
position.as_logical() - window.geometry().loc,
if let Some((mapped, position)) = position { )),
handle.motion( &MotionEvent {
state, location: pointer.current_location(),
Some(( serial,
PointerFocusTarget::from(mapped.clone()), time: 0,
position.as_logical() - self.window.geometry().loc, },
)), );
&MotionEvent { Common::set_focus(
location: handle.current_location(), state,
serial, Some(&KeyboardFocusTarget::from(mapped)),
time, &seat,
}, Some(serial),
); )
Common::set_focus( }
state, });
Some(&KeyboardFocusTarget::from(mapped)),
&self.seat,
Some(serial),
)
}
} }
} }

View file

@ -2007,6 +2007,7 @@ impl Shell {
start_data, start_data,
active_hint as u8, active_hint as u8,
release, release,
state.common.event_loop_handle.clone(),
) { ) {
let handle = workspace.handle; let handle = workspace.handle;
state state

View file

@ -21,6 +21,7 @@ use crate::{
xwayland::XWaylandState, xwayland::XWaylandState,
}; };
use calloop::LoopHandle;
use cosmic::theme::CosmicTheme; use cosmic::theme::CosmicTheme;
use id_tree::Tree; use id_tree::Tree;
use indexmap::IndexSet; use indexmap::IndexSet;
@ -685,6 +686,7 @@ impl Workspace {
start_data: PointerGrabStartData<State>, start_data: PointerGrabStartData<State>,
indicator_thickness: u8, indicator_thickness: u8,
release: ReleaseMode, release: ReleaseMode,
evlh: LoopHandle<'static, State>,
) -> Option<MoveGrab> { ) -> Option<MoveGrab> {
let pointer = seat.get_pointer().unwrap(); let pointer = seat.get_pointer().unwrap();
let pos = pointer.current_location().as_global(); let pos = pointer.current_location().as_global();
@ -728,6 +730,7 @@ impl Workspace {
indicator_thickness, indicator_thickness,
was_tiled.is_some(), was_tiled.is_some(),
release, release,
evlh,
)) ))
} }