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)]
use smithay::{
backend::input::{
Axis, AxisSource, Device, DeviceCapability, InputBackend, InputEvent, KeyState,
PointerAxisEvent,
Axis, AxisSource, Device, DeviceCapability, GestureBeginEvent, GestureEndEvent,
GesturePinchUpdateEvent as _, GestureSwipeUpdateEvent as _, InputBackend, InputEvent,
KeyState, PointerAxisEvent,
},
desktop::{layer_map_for_output, space::SpaceElement, WindowSurfaceType},
input::{
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,
},
output::Output,
@ -220,14 +226,15 @@ impl State {
use smithay::backend::input::KeyboardKeyEvent;
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 workspace = self.common.shell.active_space_mut(&current_output);
let shortcuts_inhibited = workspace
.focus_stack
.get(seat)
.get(&seat)
.last()
.and_then(|window| {
window.wl_surface().and_then(|surface| {
@ -237,9 +244,6 @@ impl State {
.map(|inhibitor| inhibitor.is_active())
.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 state = event.state();
trace!(?keycode, ?state, "key");
@ -366,7 +370,7 @@ impl State {
// Pass keys to debug interface, if it has focus
#[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
{
if data.common.egui.state.wants_keyboard() {
@ -427,20 +431,14 @@ impl State {
)
.flatten()
{
self.handle_action(action, seat, serial, time, pattern, None)
}
break;
self.handle_action(action, &seat, serial, time, pattern, None)
}
}
}
InputEvent::PointerMotion { event, .. } => {
use smithay::backend::input::PointerMotionEvent;
let device = event.device();
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) {
if let Some(seat) = self.common.seat_with_device(&event.device()).cloned() {
let current_output = seat.active_output();
let mut position = seat.get_pointer().unwrap().current_location();
@ -455,11 +453,11 @@ impl State {
.unwrap_or(current_output.clone());
if output != 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) {
session.cursor_enter(seat, InputType::Pointer);
session.cursor_enter(&seat, InputType::Pointer);
}
seat.set_active_output(&output);
@ -496,7 +494,7 @@ impl State {
),
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();
@ -519,7 +517,7 @@ impl State {
},
);
#[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() {
self.common
.shell
@ -530,16 +528,10 @@ impl State {
};
self.common.egui.state.handle_pointer_motion(location);
}
break;
}
}
}
InputEvent::PointerMotionAbsolute { event, .. } => {
let device = event.device();
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) {
if let Some(seat) = self.common.seat_with_device(&event.device()).cloned() {
let output = seat.active_output();
let geometry = output.geometry();
let position = geometry.loc.to_f64()
@ -570,7 +562,7 @@ impl State {
),
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(
@ -583,7 +575,7 @@ impl State {
},
);
#[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() {
self.common
.shell
@ -594,21 +586,14 @@ impl State {
};
self.common.egui.state.handle_pointer_motion(location);
}
break;
}
}
}
InputEvent::PointerButton { event, .. } => {
use smithay::backend::input::{ButtonState, PointerButtonEvent};
let device = event.device();
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) {
if let Some(seat) = self.common.seat_with_device(&event.device()).cloned() {
#[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
{
if self.common.egui.state.wants_pointer() {
@ -618,7 +603,7 @@ impl State {
event.state() == ButtonState::Pressed,
);
}
break;
return;
}
}
@ -634,8 +619,7 @@ impl State {
{
let output = seat.active_output();
let pos = seat.get_pointer().unwrap().current_location();
let relative_pos =
self.common.shell.map_global_to_space(pos, &output);
let relative_pos = self.common.shell.map_global_to_space(pos, &output);
let overview = self.common.shell.overview_mode();
let workspace = self.common.shell.active_space_mut(&output);
let mut under = None;
@ -664,12 +648,9 @@ impl State {
let layers = layer_map_for_output(&output);
if let Some(layer) = layers
.layer_under(WlrLayer::Overlay, relative_pos)
.or_else(|| {
layers.layer_under(WlrLayer::Top, relative_pos)
})
.or_else(|| layers.layer_under(WlrLayer::Top, relative_pos))
{
let layer_loc =
layers.layer_geometry(layer).unwrap().loc;
let layer_loc = layers.layer_geometry(layer).unwrap().loc;
if layer.can_receive_keyboard_focus()
&& layer
.surface_under(
@ -692,11 +673,10 @@ impl State {
under = Some(target);
} else {
let layers = layer_map_for_output(&output);
if let Some(layer) = layers
.layer_under(WlrLayer::Bottom, pos)
.or_else(|| {
layers.layer_under(WlrLayer::Background, pos)
})
if let Some(layer) =
layers.layer_under(WlrLayer::Bottom, pos).or_else(
|| layers.layer_under(WlrLayer::Background, pos),
)
{
let layer_loc =
layers.layer_geometry(layer).unwrap().loc;
@ -717,7 +697,7 @@ impl State {
Common::set_focus(
self,
under.and_then(|target| target.try_into().ok()).as_ref(),
seat,
&seat,
Some(serial),
);
}
@ -739,8 +719,6 @@ impl State {
time: event.time_msec(),
},
);
break;
}
}
}
InputEvent::PointerAxis { event, .. } => {
@ -753,8 +731,7 @@ impl State {
1.0
};
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()) {
#[cfg(feature = "debug")]
if self.common.seats().position(|x| x == seat).unwrap() == 0
&& self.common.egui.active
@ -770,15 +747,11 @@ impl State {
.or_else(|| event.amount(Axis::Vertical).map(|x| x * 3.0))
.unwrap_or(0.0),
);
break;
return;
}
}
let userdata = seat.user_data();
let devices = userdata.get::<Devices>().unwrap();
if devices.has_device(&device) {
let horizontal_amount =
event.amount(Axis::Horizontal).unwrap_or_else(|| {
let horizontal_amount = event.amount(Axis::Horizontal).unwrap_or_else(|| {
event.amount_discrete(Axis::Horizontal).unwrap_or(0.0) * 3.0
});
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 mut frame =
AxisFrame::new(event.time_msec()).source(event.source());
let mut frame = AxisFrame::new(event.time_msec()).source(event.source());
if horizontal_amount != 0.0 {
frame = frame
.value(Axis::Horizontal, scroll_factor * horizontal_amount);
frame =
frame.value(Axis::Horizontal, scroll_factor * horizontal_amount);
if let Some(discrete) = horizontal_amount_discrete {
frame = frame.discrete(Axis::Horizontal, discrete as i32);
}
@ -800,8 +772,7 @@ impl State {
frame = frame.stop(Axis::Horizontal);
}
if vertical_amount != 0.0 {
frame =
frame.value(Axis::Vertical, scroll_factor * vertical_amount);
frame = frame.value(Axis::Vertical, scroll_factor * vertical_amount);
if let Some(discrete) = vertical_amount_discrete {
frame = frame.discrete(Axis::Vertical, discrete as i32);
}
@ -810,9 +781,117 @@ impl State {
}
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 */ }
}

View file

@ -7,6 +7,7 @@ use crate::{
x11::X11State,
},
config::{Config, OutputConfig},
input::Devices,
shell::{grabs::SeatMoveGrabState, Shell},
utils::prelude::*,
wayland::protocols::{
@ -30,6 +31,7 @@ use smithay::utils::Rectangle;
use smithay::{
backend::{
drm::DrmNode,
input::Device,
renderer::{
element::{
default_primary_scanout_output_compare, utils::select_dmabuf_feedback,
@ -63,6 +65,7 @@ use smithay::{
fractional_scale::{with_fractional_scale, FractionalScaleManagerState},
keyboard_shortcuts_inhibit::KeyboardShortcutsInhibitState,
output::OutputManagerState,
pointer_gestures::PointerGesturesState,
presentation::PresentationState,
primary_selection::PrimarySelectionState,
seat::WaylandFocus,
@ -301,6 +304,7 @@ impl State {
let kde_decoration_state = KdeDecorationState::new::<Self>(&dh, Mode::Client);
let xdg_decoration_state = XdgDecorationState::new::<Self>(&dh);
XWaylandKeyboardGrabState::new::<Self>(&dh);
PointerGesturesState::new::<Self>(&dh);
let shell = Shell::new(&config, dh);
@ -421,6 +425,14 @@ impl Common {
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> {
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 output;
pub mod output_configuration;
pub mod pointer_gestures;
pub mod presentation;
pub mod primary_selection;
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);