Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions cosmic-comp-config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ pub struct CosmicCompConfig {
pub xwayland_eavesdropping: XwaylandEavesdropping,
/// 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,
pub accessibility_zoom: ZoomConfig,
}

Expand Down Expand Up @@ -86,6 +88,7 @@ impl Default for CosmicCompConfig {
descale_xwayland: XwaylandDescaling::Fractional,
xwayland_eavesdropping: XwaylandEavesdropping::default(),
edge_snap_threshold: 0,
pointer_moved_epsilon: 10,
accessibility_zoom: ZoomConfig::default(),
}
}
Expand Down
239 changes: 189 additions & 50 deletions src/input/mod.rs

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions src/shell/element/stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -929,6 +929,7 @@ impl Program for CosmicStackInternal {
true,
&state.common.config,
&state.common.event_loop_handle,
true,
);

std::mem::drop(shell);
Expand Down Expand Up @@ -971,6 +972,7 @@ impl Program for CosmicStackInternal {
false,
&state.common.config,
&state.common.event_loop_handle,
true,
);

std::mem::drop(shell);
Expand Down
1 change: 1 addition & 0 deletions src/shell/element/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,7 @@ impl Program for CosmicWindowInternal {
false,
&state.common.config,
&state.common.event_loop_handle,
true,
);

std::mem::drop(shell);
Expand Down
5 changes: 3 additions & 2 deletions src/shell/grabs/menu/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,8 +202,9 @@ impl Item {
}
}

/// Menu that comes up when right-clicking an application header bar
#[derive(Debug)]
/// Menu that comes up when:
/// - Right-clicking an application header bar, or
/// - Super + Right-clicking a window
pub struct ContextMenu {
items: Vec<Item>,
selected: AtomicBool,
Expand Down
172 changes: 172 additions & 0 deletions src/shell/grabs/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::cell::Cell;

use cosmic_settings_config::shortcuts;
use smithay::{
input::{
Expand Down Expand Up @@ -67,6 +69,176 @@ pub enum ReleaseMode {
NoMouseButtons,
}

#[derive(Debug, Clone)]
pub struct DistanceSwitchGrab<Moved: FnOnce(&mut State), Unmoved: FnOnce(&mut State)> {
pub moved: Option<Moved>,
pub unmoved: Option<Unmoved>,
pub start: GrabStartData,
pub pointer_moved_epsilon: u32,
}
impl<Moved: Send + 'static + FnOnce(&mut State), Unmoved: Send + 'static + FnOnce(&mut State)>
PointerGrab<State> for DistanceSwitchGrab<Moved, Unmoved>
{
fn motion(
&mut self,
data: &mut State,
handle: &mut PointerInnerHandle<'_, State>,
focus: Option<(PointerFocusTarget, Point<f64, Logical>)>,
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<(
<State as smithay::input::SeatHandler>::PointerFocus,
Point<f64, Logical>,
)>,
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<State> {
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<bool>);
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;
Expand Down
31 changes: 29 additions & 2 deletions src/shell/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use calloop::LoopHandle;
use focus::target::WindowGroup;
use grabs::{MenuAlignment, SeatMoveGrabState};
use grabs::{DistanceSwitchGrab, MenuAlignment, SeatMoveGrabState};
use indexmap::IndexMap;
use layout::TilingExceptions;
use std::{
Expand Down Expand Up @@ -3279,10 +3279,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, serial, Some(surface))
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
};
Expand Down Expand Up @@ -3391,6 +3392,32 @@ impl Shell {
Some((grab, Focus::Keep))
}

pub fn distance_switch_request<Moved: FnOnce(&mut State), Unmoved: FnOnce(&mut State)>(
&mut self,
surface: &WlSurface,
seat: &Seat<State>,
serial: impl Into<Option<Serial>>,
config: &Config,
on_moved: Moved,
on_unmoved: Unmoved,
client_initiated: bool,
) -> Option<(DistanceSwitchGrab<Moved, Unmoved>, Focus)> {
let serial = serial.into();

let start_data =
check_grab_preconditions(&seat, serial, client_initiated.then_some(surface))?;

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,
Expand Down
1 change: 1 addition & 0 deletions src/wayland/handlers/xdg_shell/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,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);
Expand Down
Loading