From 13d2229c71659c2de6f57948d5c881f08a71c5ae Mon Sep 17 00:00:00 2001 From: Daniel <101683475+Koranir@users.noreply.github.com> Date: Wed, 8 Jan 2025 18:24:25 +1100 Subject: [PATCH 1/5] implement context menu grab on inputs --- src/input/mod.rs | 199 ++++++++++++++++++-------- src/shell/element/stack.rs | 2 + src/shell/element/window.rs | 1 + src/shell/grabs/menu/mod.rs | 5 +- src/shell/mod.rs | 3 +- src/wayland/handlers/xdg_shell/mod.rs | 1 + 6 files changed, 153 insertions(+), 58 deletions(-) diff --git a/src/input/mod.rs b/src/input/mod.rs index 327f23efe..ef702cfdf 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -31,7 +31,7 @@ use crate::{ }; use calloop::{ timer::{TimeoutAction, Timer}, - RegistrationToken, + LoopHandle, RegistrationToken, }; use cosmic_comp_config::{workspace::WorkspaceLayout, NumlockState}; use cosmic_settings_config::shortcuts; @@ -58,7 +58,8 @@ use smithay::{ }, output::Output, reexports::{ - input::Device as InputDevice, wayland_server::protocol::wl_shm::Format as ShmFormat, + input::Device as InputDevice, + wayland_server::protocol::{wl_shm::Format as ShmFormat, wl_surface::WlSurface}, }, utils::{Point, Rectangle, Serial, SERIAL_COUNTER}, wayland::{ @@ -693,6 +694,66 @@ impl State { } } + fn window_menu( + seat: Seat, + evlh: &LoopHandle, + surface: WlSurface, + serial: Serial, + ) { + evlh.insert_idle(move |state| { + let shell = state.common.shell.write().unwrap(); + + let grab = if let Some(mapped) = + shell.element_for_surface(&surface).cloned() + { + let position = if let Some((output, set)) = + shell.workspaces.sets.iter().find(|(_, set)| { + set.sticky_layer + .mapped() + .any(|m| m == &mapped) + }) { + set.sticky_layer + .element_geometry(&mapped) + .unwrap() + .loc + .to_global(output) + } else if let Some(workspace) = + shell.space_for(&mapped) + { + let Some(elem_geo) = + workspace.element_geometry(&mapped) + else { + return; + }; + elem_geo.loc.to_global(&workspace.output) + } else { + return; + }; + let cursor = seat + .get_pointer() + .unwrap() + .current_location() + .to_i32_round(); + + shell.menu_request( + &surface, + &seat, + serial, + cursor - position.as_logical(), + false, + &state.common.config, + &state.common.event_loop_handle, + false, + ) + } else { + None + }; + drop(shell); + + dispatch_grab(grab, seat, serial, state); + }); + } + if let Some(mouse_button) = mouse_button { match mouse_button { smithay::backend::input::MouseButton::Left => { @@ -719,61 +780,89 @@ impl State { }, ); } - smithay::backend::input::MouseButton::Right => { + smithay::backend::input::MouseButton::Middle => { supress_button(); - self.common.event_loop_handle.insert_idle( - move |state| { - let mut shell = - state.common.shell.write().unwrap(); - let Some(target_elem) = - shell.element_for_surface(&surface) - else { - return; - }; - let Some(geom) = - shell.space_for(target_elem).and_then( - |f| f.element_geometry(target_elem), - ) - else { - return; - }; - let geom = geom.to_f64(); - let center = - geom.loc + geom.size.downscale(2.0); - let offset = center.to_global(&output) - - global_position; - let edge = match ( - offset.x > 0.0, - offset.y > 0.0, - ) { - (true, true) => ResizeEdge::TOP_LEFT, - (false, true) => ResizeEdge::TOP_RIGHT, - (true, false) => { - ResizeEdge::BOTTOM_LEFT - } - (false, false) => { - ResizeEdge::BOTTOM_RIGHT - } - }; - let res = shell.resize_request( - &surface, - &seat_clone, - serial, - edge, - state - .common - .config - .cosmic_conf - .edge_snap_threshold, - false, - ); - drop(shell); - dispatch_grab( - res, seat_clone, serial, state, - ); - }, + window_menu( + seat_clone, + &self.common.event_loop_handle, + surface, + serial, ); } + smithay::backend::input::MouseButton::Right => { + supress_button(); + if seat + .get_keyboard() + .unwrap() + .modifier_state() + .shift + { + window_menu( + seat_clone, + &self.common.event_loop_handle, + surface, + serial, + ); + } else { + self.common.event_loop_handle.insert_idle( + move |state| { + let mut shell = + state.common.shell.write().unwrap(); + let Some(target_elem) = + shell.element_for_surface(&surface) + else { + return; + }; + let Some(geom) = shell + .space_for(target_elem) + .and_then(|f| { + f.element_geometry(target_elem) + }) + else { + return; + }; + let geom = geom.to_f64(); + let center = + geom.loc + geom.size.downscale(2.0); + let offset = center.to_global(&output) + - global_position; + let edge = match ( + offset.x > 0.0, + offset.y > 0.0, + ) { + (true, true) => { + ResizeEdge::TOP_LEFT + } + (false, true) => { + ResizeEdge::TOP_RIGHT + } + (true, false) => { + ResizeEdge::BOTTOM_LEFT + } + (false, false) => { + ResizeEdge::BOTTOM_RIGHT + } + }; + let res = shell.resize_request( + &surface, + &seat_clone, + serial, + edge, + state + .common + .config + .cosmic_conf + .edge_snap_threshold, + false, + ); + drop(shell); + dispatch_grab( + res, seat_clone, serial, state, + ); + }, + ); + } + } _ => {} } } @@ -807,8 +896,6 @@ impl State { }, ); ptr.frame(self); - } else if event.state() == ButtonState::Released { - ptr.unset_grab(self, serial, event.time_msec()) } } InputEvent::PointerAxis { event, .. } => { diff --git a/src/shell/element/stack.rs b/src/shell/element/stack.rs index 9ee25a6d2..5c9b04ec0 100644 --- a/src/shell/element/stack.rs +++ b/src/shell/element/stack.rs @@ -872,6 +872,7 @@ impl Program for CosmicStackInternal { true, &state.common.config, &state.common.event_loop_handle, + true, ); std::mem::drop(shell); @@ -914,6 +915,7 @@ impl Program for CosmicStackInternal { false, &state.common.config, &state.common.event_loop_handle, + true, ); std::mem::drop(shell); diff --git a/src/shell/element/window.rs b/src/shell/element/window.rs index ac27add13..a20ed08a7 100644 --- a/src/shell/element/window.rs +++ b/src/shell/element/window.rs @@ -515,6 +515,7 @@ impl Program for CosmicWindowInternal { false, &state.common.config, &state.common.event_loop_handle, + true, ); std::mem::drop(shell); diff --git a/src/shell/grabs/menu/mod.rs b/src/shell/grabs/menu/mod.rs index c1ca0c2bd..8e7187fb9 100644 --- a/src/shell/grabs/menu/mod.rs +++ b/src/shell/grabs/menu/mod.rs @@ -161,7 +161,10 @@ impl Item { } } -/// Menu that comes up when right-clicking an application header bar +/// Menu that comes up when: +/// - Right-clicking an application header bar +/// - Super + Middle-clicking a window +/// - Super + Shift + Right-clicking a window pub struct ContextMenu { items: Vec, selected: AtomicBool, diff --git a/src/shell/mod.rs b/src/shell/mod.rs index e5a2c68fd..cd836e066 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -2603,10 +2603,11 @@ impl Shell { target_stack: bool, config: &Config, evlh: &LoopHandle<'static, State>, + client_initiated: bool, ) -> Option<(MenuGrab, Focus)> { let serial = serial.into(); let Some(GrabStartData::Pointer(start_data)) = - check_grab_preconditions(&seat, surface, serial, true) + check_grab_preconditions(&seat, surface, serial, client_initiated) else { return None; }; diff --git a/src/wayland/handlers/xdg_shell/mod.rs b/src/wayland/handlers/xdg_shell/mod.rs index c8695e22d..7894ffb7d 100644 --- a/src/wayland/handlers/xdg_shell/mod.rs +++ b/src/wayland/handlers/xdg_shell/mod.rs @@ -467,6 +467,7 @@ impl XdgShellHandler for State { false, &self.common.config, &self.common.event_loop_handle, + true, ); if let Some((grab, focus)) = res { std::mem::drop(shell); From af3764840cb00cb8d0ffd1ab1a99281e09c1d22e Mon Sep 17 00:00:00 2001 From: Daniel <101683475+Koranir@users.noreply.github.com> Date: Wed, 8 Jan 2025 19:02:56 +1100 Subject: [PATCH 2/5] Handle ungrabbing correctly --- src/input/mod.rs | 24 ++++++++++++++++++++++-- src/shell/grabs/mod.rs | 18 ++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/src/input/mod.rs b/src/input/mod.rs index ef702cfdf..33f5398fb 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -16,7 +16,7 @@ use crate::{ target::{KeyboardFocusTarget, PointerFocusTarget}, Stage, }, - grabs::{ReleaseMode, ResizeEdge}, + grabs::{ReleaseMode, ResizeEdge, UngrabOnPointerUp}, layout::{ floating::ResizeGrabMarker, tiling::{NodeDesc, SwapWindowGrab, TilingLayout}, @@ -75,7 +75,7 @@ use xkbcommon::xkb::{Keycode, Keysym}; use std::{ any::Any, borrow::Cow, - cell::RefCell, + cell::{Cell, RefCell}, collections::HashSet, ops::ControlFlow, time::{Duration, Instant}, @@ -773,7 +773,13 @@ impl State { &state.common.xdg_activation_state, false, ); + drop(shell); + + seat_clone + .user_data() + .get_or_insert(UngrabOnPointerUp::new) + .set(true); dispatch_grab( res, seat_clone, serial, state, ); @@ -856,6 +862,13 @@ impl State { false, ); drop(shell); + + seat_clone + .user_data() + .get_or_insert( + UngrabOnPointerUp::new, + ) + .set(true); dispatch_grab( res, seat_clone, serial, state, ); @@ -896,6 +909,13 @@ impl State { }, ); ptr.frame(self); + } else if event.state() == ButtonState::Released { + if let Some(ungrab) = seat.user_data().get::() { + if ungrab.get() { + ungrab.set(false); + ptr.unset_grab(self, serial, event.time_msec()) + } + } } } InputEvent::PointerAxis { event, .. } => { diff --git a/src/shell/grabs/mod.rs b/src/shell/grabs/mod.rs index def21cfea..cafaeff26 100644 --- a/src/shell/grabs/mod.rs +++ b/src/shell/grabs/mod.rs @@ -1,3 +1,5 @@ +use std::cell::Cell; + use cosmic_settings_config::shortcuts; use smithay::{ input::{ @@ -67,6 +69,22 @@ pub enum ReleaseMode { NoMouseButtons, } +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct UngrabOnPointerUp(Cell); +impl UngrabOnPointerUp { + pub fn new() -> Self { + Self(Cell::new(false)) + } + + pub fn get(&self) -> bool { + self.0.get() + } + + pub fn set(&self, ungrab: bool) { + self.0.set(ungrab); + } +} + mod menu; pub use self::menu::*; mod moving; From fed8290424a841b4a1dbc002e9564e0a720abe82 Mon Sep 17 00:00:00 2001 From: Daniel <101683475+Koranir@users.noreply.github.com> Date: Wed, 8 Jan 2025 19:03:58 +1100 Subject: [PATCH 3/5] remove unused import --- src/input/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/input/mod.rs b/src/input/mod.rs index 33f5398fb..44c729813 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -75,7 +75,7 @@ use xkbcommon::xkb::{Keycode, Keysym}; use std::{ any::Any, borrow::Cow, - cell::{Cell, RefCell}, + cell::RefCell, collections::HashSet, ops::ControlFlow, time::{Duration, Instant}, From a43da8caba68473d81cb54cb40c612be71e98e85 Mon Sep 17 00:00:00 2001 From: Daniel <101683475+Koranir@users.noreply.github.com> Date: Thu, 16 Jan 2025 16:49:15 +1100 Subject: [PATCH 4/5] Just use Meta + Right-Click --- cosmic-comp-config/src/lib.rs | 3 + src/input/mod.rs | 308 +++++++++++++++++++--------------- src/shell/grabs/mod.rs | 154 +++++++++++++++++ src/shell/mod.rs | 27 ++- 4 files changed, 353 insertions(+), 139 deletions(-) diff --git a/cosmic-comp-config/src/lib.rs b/cosmic-comp-config/src/lib.rs index 1f9415008..96fa212f6 100644 --- a/cosmic-comp-config/src/lib.rs +++ b/cosmic-comp-config/src/lib.rs @@ -48,6 +48,8 @@ pub struct CosmicCompConfig { pub descale_xwayland: bool, /// The threshold before windows snap themselves to output edges pub edge_snap_threshold: u32, + /// How far the pointer can travel before it's considered as moved + pub pointer_moved_epsilon: u32, } impl Default for CosmicCompConfig { @@ -79,6 +81,7 @@ impl Default for CosmicCompConfig { focus_follows_cursor_delay: 250, descale_xwayland: false, edge_snap_threshold: 0, + pointer_moved_epsilon: 10, } } } diff --git a/src/input/mod.rs b/src/input/mod.rs index 44c729813..90f0a8198 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -16,7 +16,7 @@ use crate::{ target::{KeyboardFocusTarget, PointerFocusTarget}, Stage, }, - grabs::{ReleaseMode, ResizeEdge, UngrabOnPointerUp}, + grabs::{MenuGrab, ReleaseMode, ResizeEdge, UngrabOnPointerUp}, layout::{ floating::ResizeGrabMarker, tiling::{NodeDesc, SwapWindowGrab, TilingLayout}, @@ -31,7 +31,7 @@ use crate::{ }; use calloop::{ timer::{TimeoutAction, Timer}, - LoopHandle, RegistrationToken, + RegistrationToken, }; use cosmic_comp_config::{workspace::WorkspaceLayout, NumlockState}; use cosmic_settings_config::shortcuts; @@ -694,64 +694,56 @@ impl State { } } - fn window_menu( - seat: Seat, - evlh: &LoopHandle, + fn window_menu_grab( + state: &mut State, + seat: &Seat, surface: WlSurface, serial: Serial, - ) { - evlh.insert_idle(move |state| { - let shell = state.common.shell.write().unwrap(); - - let grab = if let Some(mapped) = - shell.element_for_surface(&surface).cloned() + ) -> Option<(MenuGrab, smithay::input::pointer::Focus)> + { + let shell = state.common.shell.write().unwrap(); + if let Some(mapped) = + shell.element_for_surface(&surface).cloned() + { + let position = if let Some((output, set)) = + shell.workspaces.sets.iter().find(|(_, set)| { + set.sticky_layer.mapped().any(|m| m == &mapped) + }) { + set.sticky_layer + .element_geometry(&mapped) + .unwrap() + .loc + .to_global(output) + } else if let Some(workspace) = shell.space_for(&mapped) { - let position = if let Some((output, set)) = - shell.workspaces.sets.iter().find(|(_, set)| { - set.sticky_layer - .mapped() - .any(|m| m == &mapped) - }) { - set.sticky_layer - .element_geometry(&mapped) - .unwrap() - .loc - .to_global(output) - } else if let Some(workspace) = - shell.space_for(&mapped) - { - let Some(elem_geo) = - workspace.element_geometry(&mapped) - else { - return; - }; - elem_geo.loc.to_global(&workspace.output) - } else { - return; + let Some(elem_geo) = + workspace.element_geometry(&mapped) + else { + return None; }; - let cursor = seat - .get_pointer() - .unwrap() - .current_location() - .to_i32_round(); - - shell.menu_request( - &surface, - &seat, - serial, - cursor - position.as_logical(), - false, - &state.common.config, - &state.common.event_loop_handle, - false, - ) + elem_geo.loc.to_global(&workspace.output) } else { - None + return None; }; - drop(shell); - - dispatch_grab(grab, seat, serial, state); - }); + let cursor = seat + .get_pointer() + .unwrap() + .current_location() + .to_i32_round(); + + shell.menu_request( + &surface, + &seat, + serial, + cursor - position.as_logical(), + false, + &state.common.config, + &state.common.event_loop_handle, + false, + ) + } else { + None + } } if let Some(mouse_button) = mouse_button { @@ -786,95 +778,135 @@ impl State { }, ); } - smithay::backend::input::MouseButton::Middle => { - supress_button(); - window_menu( - seat_clone, - &self.common.event_loop_handle, - surface, - serial, - ); - } smithay::backend::input::MouseButton::Right => { supress_button(); - if seat - .get_keyboard() - .unwrap() - .modifier_state() - .shift - { - window_menu( + let time = event.time_msec(); + self.common.event_loop_handle.insert_idle(move |state| { + let surface_clone = surface.clone(); + let surface_clone2 = surface.clone(); + let seat_clone2 = seat_clone.clone(); + let seat_clone3 = seat_clone.clone(); + + let mut shell = state.common.shell.write().unwrap(); + let res = shell + .distance_switch_request( + &surface_clone, + &seat_clone, + serial, + &state.common.config, + move |state| { + state.common.event_loop_handle.insert_idle(move |state| { + let mut shell = state + .common + .shell + .write() + .unwrap(); + + let Some(target_elem) = + shell.element_for_surface(&surface) + else { + return; + }; + let Some(geom) = shell + .space_for(target_elem) + .and_then(|f| { + f.element_geometry( + target_elem, + ) + }) + else { + return; + }; + let geom = geom.to_f64(); + let center = geom.loc + + geom + .size + .downscale(2.0); + let offset = center + .to_global(&output) + - global_position; + let edge = match ( + offset.x > 0.0, + offset.y > 0.0, + ) { + (true, true) => { + ResizeEdge::TOP_LEFT + } + (false, true) => { + ResizeEdge::TOP_RIGHT + } + (true, false) => { + ResizeEdge::BOTTOM_LEFT + } + (false, false) => { + ResizeEdge::BOTTOM_RIGHT + } + }; + let res = shell + .resize_request( + &surface, + &seat_clone2, + serial, + edge, + state + .common + .config + .cosmic_conf + .edge_snap_threshold, + false, + ); + drop(shell); + + seat_clone2 + .user_data() + .get_or_insert( + UngrabOnPointerUp::new, + ) + .set(true); + + dispatch_grab(res, seat_clone2, serial, state); + }); + }, + move |state| { + state.common.event_loop_handle.insert_idle(move |state| { + let grab = window_menu_grab( + state, + &seat_clone3, + surface_clone2, + serial, + ); + dispatch_grab(grab, seat_clone3.clone(), serial, state); + + let ptr = seat_clone3.get_pointer().unwrap(); + ptr.motion( + state, + ptr.current_focus().map(|f| + (f, ptr.current_location()) + ), + &MotionEvent { + location: ptr.current_location(), + serial, + time + } + ); + }); + }, + false, + ); + + drop(shell); + + seat_clone + .user_data() + .get_or_insert(UngrabOnPointerUp::new) + .set(true); + dispatch_grab( + res, seat_clone, - &self.common.event_loop_handle, - surface, serial, + state, ); - } else { - self.common.event_loop_handle.insert_idle( - move |state| { - let mut shell = - state.common.shell.write().unwrap(); - let Some(target_elem) = - shell.element_for_surface(&surface) - else { - return; - }; - let Some(geom) = shell - .space_for(target_elem) - .and_then(|f| { - f.element_geometry(target_elem) - }) - else { - return; - }; - let geom = geom.to_f64(); - let center = - geom.loc + geom.size.downscale(2.0); - let offset = center.to_global(&output) - - global_position; - let edge = match ( - offset.x > 0.0, - offset.y > 0.0, - ) { - (true, true) => { - ResizeEdge::TOP_LEFT - } - (false, true) => { - ResizeEdge::TOP_RIGHT - } - (true, false) => { - ResizeEdge::BOTTOM_LEFT - } - (false, false) => { - ResizeEdge::BOTTOM_RIGHT - } - }; - let res = shell.resize_request( - &surface, - &seat_clone, - serial, - edge, - state - .common - .config - .cosmic_conf - .edge_snap_threshold, - false, - ); - drop(shell); - - seat_clone - .user_data() - .get_or_insert( - UngrabOnPointerUp::new, - ) - .set(true); - dispatch_grab( - res, seat_clone, serial, state, - ); - }, - ); - } + }); } _ => {} } diff --git a/src/shell/grabs/mod.rs b/src/shell/grabs/mod.rs index cafaeff26..fb409ab09 100644 --- a/src/shell/grabs/mod.rs +++ b/src/shell/grabs/mod.rs @@ -69,6 +69,160 @@ pub enum ReleaseMode { NoMouseButtons, } +#[derive(Debug, Clone)] +pub struct DistanceSwitchGrab { + pub moved: Option, + pub unmoved: Option, + pub start: GrabStartData, + pub pointer_moved_epsilon: u32, +} +impl + PointerGrab for DistanceSwitchGrab +{ + fn motion( + &mut self, + data: &mut State, + handle: &mut PointerInnerHandle<'_, State>, + focus: Option<(PointerFocusTarget, Point)>, + event: &MotionEvent, + ) { + let start = self.start.location(); + let current = event.location; + + let x = start.x - current.x; + let y = start.y - current.y; + + let distance = ((x * x) + (y * y)).sqrt(); + if distance > self.pointer_moved_epsilon as f64 { + drop(data.common.shell.try_write().unwrap()); + self.moved.take().unwrap()(data); + } else { + handle.motion(data, focus, event) + } + } + + fn relative_motion( + &mut self, + data: &mut State, + handle: &mut PointerInnerHandle<'_, State>, + focus: Option<( + ::PointerFocus, + Point, + )>, + event: &RelativeMotionEvent, + ) { + handle.relative_motion(data, focus, event) + } + + fn button( + &mut self, + data: &mut State, + handle: &mut PointerInnerHandle<'_, State>, + event: &ButtonEvent, + ) { + handle.button(data, event) + } + + fn axis( + &mut self, + data: &mut State, + handle: &mut PointerInnerHandle<'_, State>, + details: AxisFrame, + ) { + handle.axis(data, details) + } + + fn frame(&mut self, data: &mut State, handle: &mut PointerInnerHandle<'_, State>) { + handle.frame(data) + } + + fn gesture_swipe_begin( + &mut self, + data: &mut State, + handle: &mut PointerInnerHandle<'_, State>, + event: &GestureSwipeBeginEvent, + ) { + handle.gesture_swipe_begin(data, event) + } + + fn gesture_swipe_update( + &mut self, + data: &mut State, + handle: &mut PointerInnerHandle<'_, State>, + event: &GestureSwipeUpdateEvent, + ) { + handle.gesture_swipe_update(data, event) + } + + fn gesture_swipe_end( + &mut self, + data: &mut State, + handle: &mut PointerInnerHandle<'_, State>, + event: &GestureSwipeEndEvent, + ) { + handle.gesture_swipe_end(data, event) + } + + fn gesture_pinch_begin( + &mut self, + data: &mut State, + handle: &mut PointerInnerHandle<'_, State>, + event: &GesturePinchBeginEvent, + ) { + handle.gesture_pinch_begin(data, event) + } + + fn gesture_pinch_update( + &mut self, + data: &mut State, + handle: &mut PointerInnerHandle<'_, State>, + event: &GesturePinchUpdateEvent, + ) { + handle.gesture_pinch_update(data, event) + } + + fn gesture_pinch_end( + &mut self, + data: &mut State, + handle: &mut PointerInnerHandle<'_, State>, + event: &GesturePinchEndEvent, + ) { + handle.gesture_pinch_end(data, event) + } + + fn gesture_hold_begin( + &mut self, + data: &mut State, + handle: &mut PointerInnerHandle<'_, State>, + event: &GestureHoldBeginEvent, + ) { + handle.gesture_hold_begin(data, event) + } + + fn gesture_hold_end( + &mut self, + data: &mut State, + handle: &mut PointerInnerHandle<'_, State>, + event: &GestureHoldEndEvent, + ) { + handle.gesture_hold_end(data, event) + } + + fn start_data(&self) -> &PointerGrabStartData { + match &self.start { + GrabStartData::Touch(_) => unreachable!(), + GrabStartData::Pointer(p) => p, + } + } + + fn unset(&mut self, data: &mut State) { + if self.moved.is_some() { + self.unmoved.take().unwrap()(data); + } + _ = data; + } +} + #[derive(Debug, Clone, PartialEq, Eq)] pub struct UngrabOnPointerUp(Cell); impl UngrabOnPointerUp { diff --git a/src/shell/mod.rs b/src/shell/mod.rs index cd836e066..52826a09b 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -1,6 +1,6 @@ use calloop::LoopHandle; use focus::target::WindowGroup; -use grabs::SeatMoveGrabState; +use grabs::{DistanceSwitchGrab, SeatMoveGrabState}; use indexmap::IndexMap; use layout::TilingExceptions; use std::{ @@ -2701,6 +2701,31 @@ impl Shell { Some((grab, Focus::Keep)) } + pub fn distance_switch_request( + &mut self, + surface: &WlSurface, + seat: &Seat, + serial: impl Into>, + config: &Config, + on_moved: Moved, + on_unmoved: Unmoved, + client_initiated: bool, + ) -> Option<(DistanceSwitchGrab, Focus)> { + let serial = serial.into(); + + let start_data = check_grab_preconditions(&seat, surface, serial, client_initiated)?; + + Some(( + DistanceSwitchGrab { + moved: Some(on_moved), + unmoved: Some(on_unmoved), + start: start_data, + pointer_moved_epsilon: config.cosmic_conf.pointer_moved_epsilon, + }, + Focus::Keep, + )) + } + pub fn move_request( &mut self, surface: &WlSurface, From 214c91862aac061456c65065b55885186c6967c2 Mon Sep 17 00:00:00 2001 From: Daniel Date: Thu, 17 Jul 2025 16:27:58 +1000 Subject: [PATCH 5/5] fix errors --- src/input/mod.rs | 7 +++---- src/shell/mod.rs | 7 ++++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/input/mod.rs b/src/input/mod.rs index 2912d69ed..f0c04cd34 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -751,7 +751,7 @@ impl State { serial: Serial, ) -> Option<(MenuGrab, smithay::input::pointer::Focus)> { - let shell = state.common.shell.write().unwrap(); + let shell = state.common.shell.write(); if let Some(mapped) = shell.element_for_surface(&surface).cloned() { @@ -835,7 +835,7 @@ impl State { let seat_clone2 = seat_clone.clone(); let seat_clone3 = seat_clone.clone(); - let mut shell = state.common.shell.write().unwrap(); + let mut shell = state.common.shell.write(); let res = shell .distance_switch_request( &surface_clone, @@ -847,8 +847,7 @@ impl State { let mut shell = state .common .shell - .write() - .unwrap(); + .write(); let Some(target_elem) = shell.element_for_surface(&surface) diff --git a/src/shell/mod.rs b/src/shell/mod.rs index 0c1becbf0..fec463a66 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -1,6 +1,6 @@ use calloop::LoopHandle; use focus::target::WindowGroup; -use grabs::{DistanceSwitchGrab, SeatMoveGrabState, MenuAlignment}; +use grabs::{DistanceSwitchGrab, MenuAlignment, SeatMoveGrabState}; use indexmap::IndexMap; use layout::TilingExceptions; use std::{ @@ -3283,7 +3283,7 @@ impl Shell { ) -> Option<(MenuGrab, Focus)> { let serial = serial.into(); let Some(GrabStartData::Pointer(start_data)) = - check_grab_preconditions(&seat, surface, serial, client_initiated) + check_grab_preconditions(&seat, serial, client_initiated.then_some(surface)) else { return None; // TODO: an application can send a menu request for a touch event }; @@ -3404,7 +3404,8 @@ impl Shell { ) -> Option<(DistanceSwitchGrab, Focus)> { let serial = serial.into(); - let start_data = check_grab_preconditions(&seat, surface, serial, client_initiated)?; + let start_data = + check_grab_preconditions(&seat, serial, client_initiated.then_some(surface))?; Some(( DistanceSwitchGrab {