move_grab: End correctly when removed externally
This commit is contained in:
parent
131ab8fe9e
commit
e347076145
4 changed files with 102 additions and 87 deletions
|
|
@ -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(
|
||||||
|
|
|
||||||
|
|
@ -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),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue