Add pointer gestures support

This commit is contained in:
Ian Douglas Scott 2023-09-05 13:41:21 -07:00
parent e7e9b768c8
commit c68625ff78
4 changed files with 402 additions and 304 deletions

View file

@ -18,13 +18,19 @@ use cosmic_protocols::screencopy::v1::server::zcosmic_screencopy_session_v1::Inp
#[allow(deprecated)] #[allow(deprecated)]
use smithay::{ use smithay::{
backend::input::{ backend::input::{
Axis, AxisSource, Device, DeviceCapability, InputBackend, InputEvent, KeyState, Axis, AxisSource, Device, DeviceCapability, GestureBeginEvent, GestureEndEvent,
PointerAxisEvent, GesturePinchUpdateEvent as _, GestureSwipeUpdateEvent as _, InputBackend, InputEvent,
KeyState, PointerAxisEvent,
}, },
desktop::{layer_map_for_output, space::SpaceElement, WindowSurfaceType}, desktop::{layer_map_for_output, space::SpaceElement, WindowSurfaceType},
input::{ input::{
keyboard::{keysyms, FilterResult, KeysymHandle, XkbConfig}, keyboard::{keysyms, FilterResult, KeysymHandle, XkbConfig},
pointer::{AxisFrame, ButtonEvent, CursorImageStatus, MotionEvent, RelativeMotionEvent}, pointer::{
AxisFrame, ButtonEvent, CursorImageStatus, GestureHoldBeginEvent, GestureHoldEndEvent,
GesturePinchBeginEvent, GesturePinchEndEvent, GesturePinchUpdateEvent,
GestureSwipeBeginEvent, GestureSwipeEndEvent, GestureSwipeUpdateEvent, MotionEvent,
RelativeMotionEvent,
},
Seat, SeatState, Seat, SeatState,
}, },
output::Output, output::Output,
@ -220,14 +226,15 @@ impl State {
use smithay::backend::input::KeyboardKeyEvent; use smithay::backend::input::KeyboardKeyEvent;
let loop_handle = self.common.event_loop_handle.clone(); let loop_handle = self.common.event_loop_handle.clone();
let device = event.device();
for seat in self.common.seats().cloned().collect::<Vec<_>>().iter() { if let Some(seat) = self.common.seat_with_device(&event.device()).cloned() {
let userdata = seat.user_data();
let current_output = seat.active_output(); let current_output = seat.active_output();
let workspace = self.common.shell.active_space_mut(&current_output); let workspace = self.common.shell.active_space_mut(&current_output);
let shortcuts_inhibited = workspace let shortcuts_inhibited = workspace
.focus_stack .focus_stack
.get(seat) .get(&seat)
.last() .last()
.and_then(|window| { .and_then(|window| {
window.wl_surface().and_then(|surface| { window.wl_surface().and_then(|surface| {
@ -237,9 +244,6 @@ impl State {
.map(|inhibitor| inhibitor.is_active()) .map(|inhibitor| inhibitor.is_active())
.unwrap_or(false); .unwrap_or(false);
let userdata = seat.user_data();
let devices = userdata.get::<Devices>().unwrap();
if devices.has_device(&device) {
let keycode = event.key_code(); let keycode = event.key_code();
let state = event.state(); let state = event.state();
trace!(?keycode, ?state, "key"); trace!(?keycode, ?state, "key");
@ -366,7 +370,7 @@ impl State {
// Pass keys to debug interface, if it has focus // Pass keys to debug interface, if it has focus
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
{ {
if data.common.seats().position(|x| x == seat).unwrap() == 0 if data.common.seats().position(|x| x == &seat).unwrap() == 0
&& data.common.egui.active && data.common.egui.active
{ {
if data.common.egui.state.wants_keyboard() { if data.common.egui.state.wants_keyboard() {
@ -427,20 +431,14 @@ impl State {
) )
.flatten() .flatten()
{ {
self.handle_action(action, seat, serial, time, pattern, None) self.handle_action(action, &seat, serial, time, pattern, None)
}
break;
} }
} }
} }
InputEvent::PointerMotion { event, .. } => { InputEvent::PointerMotion { event, .. } => {
use smithay::backend::input::PointerMotionEvent; use smithay::backend::input::PointerMotionEvent;
let device = event.device(); if let Some(seat) = self.common.seat_with_device(&event.device()).cloned() {
for seat in self.common.seats().cloned().collect::<Vec<_>>().iter() {
let userdata = seat.user_data();
let devices = userdata.get::<Devices>().unwrap();
if devices.has_device(&device) {
let current_output = seat.active_output(); let current_output = seat.active_output();
let mut position = seat.get_pointer().unwrap().current_location(); let mut position = seat.get_pointer().unwrap().current_location();
@ -455,11 +453,11 @@ impl State {
.unwrap_or(current_output.clone()); .unwrap_or(current_output.clone());
if output != current_output { if output != current_output {
for session in sessions_for_output(&self.common, &current_output) { for session in sessions_for_output(&self.common, &current_output) {
session.cursor_leave(seat, InputType::Pointer); session.cursor_leave(&seat, InputType::Pointer);
} }
for session in sessions_for_output(&self.common, &output) { for session in sessions_for_output(&self.common, &output) {
session.cursor_enter(seat, InputType::Pointer); session.cursor_enter(&seat, InputType::Pointer);
} }
seat.set_active_output(&output); seat.set_active_output(&output);
@ -496,7 +494,7 @@ impl State {
), ),
self.common.clock.now(), self.common.clock.now(),
) { ) {
session.cursor_info(seat, InputType::Pointer, geometry, offset); session.cursor_info(&seat, InputType::Pointer, geometry, offset);
} }
} }
let ptr = seat.get_pointer().unwrap(); let ptr = seat.get_pointer().unwrap();
@ -519,7 +517,7 @@ impl State {
}, },
); );
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
if self.common.seats().position(|x| x == seat).unwrap() == 0 { if self.common.seats().position(|x| x == &seat).unwrap() == 0 {
let location = if let Some(output) = self.common.shell.outputs.first() { let location = if let Some(output) = self.common.shell.outputs.first() {
self.common self.common
.shell .shell
@ -530,16 +528,10 @@ impl State {
}; };
self.common.egui.state.handle_pointer_motion(location); self.common.egui.state.handle_pointer_motion(location);
} }
break;
}
} }
} }
InputEvent::PointerMotionAbsolute { event, .. } => { InputEvent::PointerMotionAbsolute { event, .. } => {
let device = event.device(); if let Some(seat) = self.common.seat_with_device(&event.device()).cloned() {
for seat in self.common.seats().cloned().collect::<Vec<_>>().iter() {
let userdata = seat.user_data();
let devices = userdata.get::<Devices>().unwrap();
if devices.has_device(&device) {
let output = seat.active_output(); let output = seat.active_output();
let geometry = output.geometry(); let geometry = output.geometry();
let position = geometry.loc.to_f64() let position = geometry.loc.to_f64()
@ -570,7 +562,7 @@ impl State {
), ),
self.common.clock.now(), self.common.clock.now(),
) { ) {
session.cursor_info(seat, InputType::Pointer, geometry, offset); session.cursor_info(&seat, InputType::Pointer, geometry, offset);
} }
} }
seat.get_pointer().unwrap().motion( seat.get_pointer().unwrap().motion(
@ -583,7 +575,7 @@ impl State {
}, },
); );
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
if self.common.seats().position(|x| x == seat).unwrap() == 0 { if self.common.seats().position(|x| x == &seat).unwrap() == 0 {
let location = if let Some(output) = self.common.shell.outputs.first() { let location = if let Some(output) = self.common.shell.outputs.first() {
self.common self.common
.shell .shell
@ -594,21 +586,14 @@ impl State {
}; };
self.common.egui.state.handle_pointer_motion(location); self.common.egui.state.handle_pointer_motion(location);
} }
break;
}
} }
} }
InputEvent::PointerButton { event, .. } => { InputEvent::PointerButton { event, .. } => {
use smithay::backend::input::{ButtonState, PointerButtonEvent}; use smithay::backend::input::{ButtonState, PointerButtonEvent};
let device = event.device(); if let Some(seat) = self.common.seat_with_device(&event.device()).cloned() {
for seat in self.common.seats().cloned().collect::<Vec<_>>().iter() {
let userdata = seat.user_data();
let devices = userdata.get::<Devices>().unwrap();
if devices.has_device(&device) {
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
if self.common.seats().position(|x| x == seat).unwrap() == 0 if self.common.seats().position(|x| x == &seat).unwrap() == 0
&& self.common.egui.active && self.common.egui.active
{ {
if self.common.egui.state.wants_pointer() { if self.common.egui.state.wants_pointer() {
@ -618,7 +603,7 @@ impl State {
event.state() == ButtonState::Pressed, event.state() == ButtonState::Pressed,
); );
} }
break; return;
} }
} }
@ -634,8 +619,7 @@ impl State {
{ {
let output = seat.active_output(); let output = seat.active_output();
let pos = seat.get_pointer().unwrap().current_location(); let pos = seat.get_pointer().unwrap().current_location();
let relative_pos = let relative_pos = self.common.shell.map_global_to_space(pos, &output);
self.common.shell.map_global_to_space(pos, &output);
let overview = self.common.shell.overview_mode(); let overview = self.common.shell.overview_mode();
let workspace = self.common.shell.active_space_mut(&output); let workspace = self.common.shell.active_space_mut(&output);
let mut under = None; let mut under = None;
@ -664,12 +648,9 @@ impl State {
let layers = layer_map_for_output(&output); let layers = layer_map_for_output(&output);
if let Some(layer) = layers if let Some(layer) = layers
.layer_under(WlrLayer::Overlay, relative_pos) .layer_under(WlrLayer::Overlay, relative_pos)
.or_else(|| { .or_else(|| layers.layer_under(WlrLayer::Top, relative_pos))
layers.layer_under(WlrLayer::Top, relative_pos)
})
{ {
let layer_loc = let layer_loc = layers.layer_geometry(layer).unwrap().loc;
layers.layer_geometry(layer).unwrap().loc;
if layer.can_receive_keyboard_focus() if layer.can_receive_keyboard_focus()
&& layer && layer
.surface_under( .surface_under(
@ -692,11 +673,10 @@ impl State {
under = Some(target); under = Some(target);
} else { } else {
let layers = layer_map_for_output(&output); let layers = layer_map_for_output(&output);
if let Some(layer) = layers if let Some(layer) =
.layer_under(WlrLayer::Bottom, pos) layers.layer_under(WlrLayer::Bottom, pos).or_else(
.or_else(|| { || layers.layer_under(WlrLayer::Background, pos),
layers.layer_under(WlrLayer::Background, pos) )
})
{ {
let layer_loc = let layer_loc =
layers.layer_geometry(layer).unwrap().loc; layers.layer_geometry(layer).unwrap().loc;
@ -717,7 +697,7 @@ impl State {
Common::set_focus( Common::set_focus(
self, self,
under.and_then(|target| target.try_into().ok()).as_ref(), under.and_then(|target| target.try_into().ok()).as_ref(),
seat, &seat,
Some(serial), Some(serial),
); );
} }
@ -739,8 +719,6 @@ impl State {
time: event.time_msec(), time: event.time_msec(),
}, },
); );
break;
}
} }
} }
InputEvent::PointerAxis { event, .. } => { InputEvent::PointerAxis { event, .. } => {
@ -753,8 +731,7 @@ impl State {
1.0 1.0
}; };
let device = event.device(); if let Some(seat) = self.common.seat_with_device(&event.device()) {
for seat in self.common.seats().cloned().collect::<Vec<_>>().iter() {
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
if self.common.seats().position(|x| x == seat).unwrap() == 0 if self.common.seats().position(|x| x == seat).unwrap() == 0
&& self.common.egui.active && self.common.egui.active
@ -770,15 +747,11 @@ impl State {
.or_else(|| event.amount(Axis::Vertical).map(|x| x * 3.0)) .or_else(|| event.amount(Axis::Vertical).map(|x| x * 3.0))
.unwrap_or(0.0), .unwrap_or(0.0),
); );
break; return;
} }
} }
let userdata = seat.user_data(); let horizontal_amount = event.amount(Axis::Horizontal).unwrap_or_else(|| {
let devices = userdata.get::<Devices>().unwrap();
if devices.has_device(&device) {
let horizontal_amount =
event.amount(Axis::Horizontal).unwrap_or_else(|| {
event.amount_discrete(Axis::Horizontal).unwrap_or(0.0) * 3.0 event.amount_discrete(Axis::Horizontal).unwrap_or(0.0) * 3.0
}); });
let vertical_amount = event.amount(Axis::Vertical).unwrap_or_else(|| { let vertical_amount = event.amount(Axis::Vertical).unwrap_or_else(|| {
@ -788,11 +761,10 @@ impl State {
let vertical_amount_discrete = event.amount_discrete(Axis::Vertical); let vertical_amount_discrete = event.amount_discrete(Axis::Vertical);
{ {
let mut frame = let mut frame = AxisFrame::new(event.time_msec()).source(event.source());
AxisFrame::new(event.time_msec()).source(event.source());
if horizontal_amount != 0.0 { if horizontal_amount != 0.0 {
frame = frame frame =
.value(Axis::Horizontal, scroll_factor * horizontal_amount); frame.value(Axis::Horizontal, scroll_factor * horizontal_amount);
if let Some(discrete) = horizontal_amount_discrete { if let Some(discrete) = horizontal_amount_discrete {
frame = frame.discrete(Axis::Horizontal, discrete as i32); frame = frame.discrete(Axis::Horizontal, discrete as i32);
} }
@ -800,8 +772,7 @@ impl State {
frame = frame.stop(Axis::Horizontal); frame = frame.stop(Axis::Horizontal);
} }
if vertical_amount != 0.0 { if vertical_amount != 0.0 {
frame = frame = frame.value(Axis::Vertical, scroll_factor * vertical_amount);
frame.value(Axis::Vertical, scroll_factor * vertical_amount);
if let Some(discrete) = vertical_amount_discrete { if let Some(discrete) = vertical_amount_discrete {
frame = frame.discrete(Axis::Vertical, discrete as i32); frame = frame.discrete(Axis::Vertical, discrete as i32);
} }
@ -810,9 +781,117 @@ impl State {
} }
seat.get_pointer().unwrap().axis(self, frame); seat.get_pointer().unwrap().axis(self, frame);
} }
break;
} }
} }
InputEvent::GestureSwipeBegin { event, .. } => {
if let Some(seat) = self.common.seat_with_device(&event.device()) {
let serial = SERIAL_COUNTER.next_serial();
let pointer = seat.get_pointer().unwrap();
pointer.gesture_swipe_begin(
self,
&GestureSwipeBeginEvent {
serial,
time: event.time_msec(),
fingers: event.fingers(),
},
);
}
}
InputEvent::GestureSwipeUpdate { event, .. } => {
if let Some(seat) = self.common.seat_with_device(&event.device()) {
let pointer = seat.get_pointer().unwrap();
pointer.gesture_swipe_update(
self,
&GestureSwipeUpdateEvent {
time: event.time_msec(),
delta: event.delta(),
},
);
}
}
InputEvent::GestureSwipeEnd { event, .. } => {
if let Some(seat) = self.common.seat_with_device(&event.device()) {
let serial = SERIAL_COUNTER.next_serial();
let pointer = seat.get_pointer().unwrap();
pointer.gesture_swipe_end(
self,
&GestureSwipeEndEvent {
serial,
time: event.time_msec(),
cancelled: event.cancelled(),
},
);
}
}
InputEvent::GesturePinchBegin { event, .. } => {
if let Some(seat) = self.common.seat_with_device(&event.device()) {
let serial = SERIAL_COUNTER.next_serial();
let pointer = seat.get_pointer().unwrap();
pointer.gesture_pinch_begin(
self,
&GesturePinchBeginEvent {
serial,
time: event.time_msec(),
fingers: event.fingers(),
},
);
}
}
InputEvent::GesturePinchUpdate { event, .. } => {
if let Some(seat) = self.common.seat_with_device(&event.device()) {
let pointer = seat.get_pointer().unwrap();
pointer.gesture_pinch_update(
self,
&GesturePinchUpdateEvent {
time: event.time_msec(),
delta: event.delta(),
scale: event.scale(),
rotation: event.rotation(),
},
);
}
}
InputEvent::GesturePinchEnd { event, .. } => {
if let Some(seat) = self.common.seat_with_device(&event.device()) {
let serial = SERIAL_COUNTER.next_serial();
let pointer = seat.get_pointer().unwrap();
pointer.gesture_pinch_end(
self,
&GesturePinchEndEvent {
serial,
time: event.time_msec(),
cancelled: event.cancelled(),
},
);
}
}
InputEvent::GestureHoldBegin { event, .. } => {
if let Some(seat) = self.common.seat_with_device(&event.device()) {
let serial = SERIAL_COUNTER.next_serial();
let pointer = seat.get_pointer().unwrap();
pointer.gesture_hold_begin(
self,
&GestureHoldBeginEvent {
serial,
time: event.time_msec(),
fingers: event.fingers(),
},
);
}
}
InputEvent::GestureHoldEnd { event, .. } => {
if let Some(seat) = self.common.seat_with_device(&event.device()) {
let serial = SERIAL_COUNTER.next_serial();
let pointer = seat.get_pointer().unwrap();
pointer.gesture_hold_end(
self,
&GestureHoldEndEvent {
serial,
time: event.time_msec(),
cancelled: event.cancelled(),
},
);
}
} }
_ => { /* TODO e.g. tablet or touch events */ } _ => { /* TODO e.g. tablet or touch events */ }
} }

View file

@ -7,6 +7,7 @@ use crate::{
x11::X11State, x11::X11State,
}, },
config::{Config, OutputConfig}, config::{Config, OutputConfig},
input::Devices,
shell::{grabs::SeatMoveGrabState, Shell}, shell::{grabs::SeatMoveGrabState, Shell},
utils::prelude::*, utils::prelude::*,
wayland::protocols::{ wayland::protocols::{
@ -30,6 +31,7 @@ use smithay::utils::Rectangle;
use smithay::{ use smithay::{
backend::{ backend::{
drm::DrmNode, drm::DrmNode,
input::Device,
renderer::{ renderer::{
element::{ element::{
default_primary_scanout_output_compare, utils::select_dmabuf_feedback, default_primary_scanout_output_compare, utils::select_dmabuf_feedback,
@ -63,6 +65,7 @@ use smithay::{
fractional_scale::{with_fractional_scale, FractionalScaleManagerState}, fractional_scale::{with_fractional_scale, FractionalScaleManagerState},
keyboard_shortcuts_inhibit::KeyboardShortcutsInhibitState, keyboard_shortcuts_inhibit::KeyboardShortcutsInhibitState,
output::OutputManagerState, output::OutputManagerState,
pointer_gestures::PointerGesturesState,
presentation::PresentationState, presentation::PresentationState,
primary_selection::PrimarySelectionState, primary_selection::PrimarySelectionState,
seat::WaylandFocus, seat::WaylandFocus,
@ -301,6 +304,7 @@ impl State {
let kde_decoration_state = KdeDecorationState::new::<Self>(&dh, Mode::Client); let kde_decoration_state = KdeDecorationState::new::<Self>(&dh, Mode::Client);
let xdg_decoration_state = XdgDecorationState::new::<Self>(&dh); let xdg_decoration_state = XdgDecorationState::new::<Self>(&dh);
XWaylandKeyboardGrabState::new::<Self>(&dh); XWaylandKeyboardGrabState::new::<Self>(&dh);
PointerGesturesState::new::<Self>(&dh);
let shell = Shell::new(&config, dh); let shell = Shell::new(&config, dh);
@ -421,6 +425,14 @@ impl Common {
self.seats.iter() self.seats.iter()
} }
pub fn seat_with_device<D: Device>(&self, device: &D) -> Option<&Seat<State>> {
self.seats().find(|seat| {
let userdata = seat.user_data();
let devices = userdata.get::<Devices>().unwrap();
devices.has_device(device)
})
}
pub fn last_active_seat(&self) -> &Seat<State> { pub fn last_active_seat(&self) -> &Seat<State> {
self.last_active_seat.as_ref().expect("No seat?") self.last_active_seat.as_ref().expect("No seat?")
} }

View file

@ -10,6 +10,7 @@ pub mod keyboard_shortcuts_inhibit;
pub mod layer_shell; pub mod layer_shell;
pub mod output; pub mod output;
pub mod output_configuration; pub mod output_configuration;
pub mod pointer_gestures;
pub mod presentation; pub mod presentation;
pub mod primary_selection; pub mod primary_selection;
pub mod relative_pointer; pub mod relative_pointer;

View file

@ -0,0 +1,6 @@
// SPDX-License-Identifier: GPL-3.0-only
use crate::state::State;
use smithay::delegate_pointer_gestures;
delegate_pointer_gestures!(State);