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,16 +244,13 @@ impl State {
.map(|inhibitor| inhibitor.is_active()) .map(|inhibitor| inhibitor.is_active())
.unwrap_or(false); .unwrap_or(false);
let userdata = seat.user_data(); let keycode = event.key_code();
let devices = userdata.get::<Devices>().unwrap(); let state = event.state();
if devices.has_device(&device) { trace!(?keycode, ?state, "key");
let keycode = event.key_code();
let state = event.state();
trace!(?keycode, ?state, "key");
let serial = SERIAL_COUNTER.next_serial(); let serial = SERIAL_COUNTER.next_serial();
let time = Event::time_msec(&event); let time = Event::time_msec(&event);
if let Some((action, pattern)) = seat if let Some((action, pattern)) = seat
.get_keyboard() .get_keyboard()
.unwrap() .unwrap()
.input( .input(
@ -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,223 +431,224 @@ 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 current_output = seat.active_output();
let userdata = seat.user_data();
let devices = userdata.get::<Devices>().unwrap();
if devices.has_device(&device) {
let current_output = seat.active_output();
let mut position = seat.get_pointer().unwrap().current_location(); let mut position = seat.get_pointer().unwrap().current_location();
position += event.delta(); position += event.delta();
let output = self let output = self
.common .common
.shell .shell
.outputs() .outputs()
.find(|output| output.geometry().to_f64().contains(position)) .find(|output| output.geometry().to_f64().contains(position))
.cloned() .cloned()
.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) {
session.cursor_enter(seat, InputType::Pointer);
}
seat.set_active_output(&output);
} }
let output_geometry = output.geometry();
position.x = (output_geometry.loc.x as f64)
.max(position.x)
.min((output_geometry.loc.x + output_geometry.size.w) as f64);
position.y = (output_geometry.loc.y as f64)
.max(position.y)
.min((output_geometry.loc.y + output_geometry.size.h) as f64);
let serial = SERIAL_COUNTER.next_serial();
let relative_pos = self.common.shell.map_global_to_space(position, &output);
let overview = self.common.shell.overview_mode();
let workspace = self.common.shell.workspaces.active_mut(&output);
let under = State::surface_under(
position,
relative_pos,
&output,
output_geometry,
&self.common.shell.override_redirect_windows,
overview,
workspace,
);
for session in sessions_for_output(&self.common, &output) { for session in sessions_for_output(&self.common, &output) {
if let Some((geometry, offset)) = seat.cursor_geometry( session.cursor_enter(&seat, InputType::Pointer);
position.to_buffer(
output.current_scale().fractional_scale(),
output.current_transform(),
&output.geometry().size.to_f64(),
),
self.common.clock.now(),
) {
session.cursor_info(seat, InputType::Pointer, geometry, offset);
}
} }
let ptr = seat.get_pointer().unwrap();
ptr.motion( seat.set_active_output(&output);
self, }
under.clone(), let output_geometry = output.geometry();
&MotionEvent {
location: position, position.x = (output_geometry.loc.x as f64)
serial, .max(position.x)
time: event.time_msec(), .min((output_geometry.loc.x + output_geometry.size.w) as f64);
}, position.y = (output_geometry.loc.y as f64)
); .max(position.y)
ptr.relative_motion( .min((output_geometry.loc.y + output_geometry.size.h) as f64);
self,
under, let serial = SERIAL_COUNTER.next_serial();
&RelativeMotionEvent { let relative_pos = self.common.shell.map_global_to_space(position, &output);
delta: event.delta(), let overview = self.common.shell.overview_mode();
delta_unaccel: event.delta_unaccel(), let workspace = self.common.shell.workspaces.active_mut(&output);
utime: event.time(), let under = State::surface_under(
}, position,
); relative_pos,
#[cfg(feature = "debug")] &output,
if self.common.seats().position(|x| x == seat).unwrap() == 0 { output_geometry,
let location = if let Some(output) = self.common.shell.outputs.first() { &self.common.shell.override_redirect_windows,
self.common overview,
.shell workspace,
.map_global_to_space(position, output) );
.to_i32_round()
} else { for session in sessions_for_output(&self.common, &output) {
position.to_i32_round() if let Some((geometry, offset)) = seat.cursor_geometry(
}; position.to_buffer(
self.common.egui.state.handle_pointer_motion(location); output.current_scale().fractional_scale(),
output.current_transform(),
&output.geometry().size.to_f64(),
),
self.common.clock.now(),
) {
session.cursor_info(&seat, InputType::Pointer, geometry, offset);
} }
break; }
let ptr = seat.get_pointer().unwrap();
ptr.motion(
self,
under.clone(),
&MotionEvent {
location: position,
serial,
time: event.time_msec(),
},
);
ptr.relative_motion(
self,
under,
&RelativeMotionEvent {
delta: event.delta(),
delta_unaccel: event.delta_unaccel(),
utime: event.time(),
},
);
#[cfg(feature = "debug")]
if self.common.seats().position(|x| x == &seat).unwrap() == 0 {
let location = if let Some(output) = self.common.shell.outputs.first() {
self.common
.shell
.map_global_to_space(position, output)
.to_i32_round()
} else {
position.to_i32_round()
};
self.common.egui.state.handle_pointer_motion(location);
} }
} }
} }
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 output = seat.active_output();
let userdata = seat.user_data(); let geometry = output.geometry();
let devices = userdata.get::<Devices>().unwrap(); let position = geometry.loc.to_f64()
if devices.has_device(&device) { + smithay::backend::input::AbsolutePositionEvent::position_transformed(
let output = seat.active_output(); &event,
let geometry = output.geometry(); geometry.size,
let position = geometry.loc.to_f64()
+ smithay::backend::input::AbsolutePositionEvent::position_transformed(
&event,
geometry.size,
);
let relative_pos = self.common.shell.map_global_to_space(position, &output);
let overview = self.common.shell.overview_mode();
let workspace = self.common.shell.workspaces.active_mut(&output);
let serial = SERIAL_COUNTER.next_serial();
let under = State::surface_under(
position,
relative_pos,
&output,
geometry,
&self.common.shell.override_redirect_windows,
overview,
workspace,
); );
let relative_pos = self.common.shell.map_global_to_space(position, &output);
let overview = self.common.shell.overview_mode();
let workspace = self.common.shell.workspaces.active_mut(&output);
let serial = SERIAL_COUNTER.next_serial();
let under = State::surface_under(
position,
relative_pos,
&output,
geometry,
&self.common.shell.override_redirect_windows,
overview,
workspace,
);
for session in sessions_for_output(&self.common, &output) { for session in sessions_for_output(&self.common, &output) {
if let Some((geometry, offset)) = seat.cursor_geometry( if let Some((geometry, offset)) = seat.cursor_geometry(
position.to_buffer( position.to_buffer(
output.current_scale().fractional_scale(), output.current_scale().fractional_scale(),
output.current_transform(), output.current_transform(),
&output.geometry().size.to_f64(), &output.geometry().size.to_f64(),
), ),
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( }
self, seat.get_pointer().unwrap().motion(
under, self,
&MotionEvent { under,
location: position, &MotionEvent {
serial, location: position,
time: event.time_msec(), serial,
}, time: event.time_msec(),
); },
#[cfg(feature = "debug")] );
if self.common.seats().position(|x| x == seat).unwrap() == 0 { #[cfg(feature = "debug")]
let location = if let Some(output) = self.common.shell.outputs.first() { if self.common.seats().position(|x| x == &seat).unwrap() == 0 {
self.common let location = if let Some(output) = self.common.shell.outputs.first() {
.shell self.common
.map_global_to_space(position, output) .shell
.to_i32_round() .map_global_to_space(position, output)
} else { .to_i32_round()
position.to_i32_round() } else {
}; position.to_i32_round()
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() { #[cfg(feature = "debug")]
let userdata = seat.user_data(); if self.common.seats().position(|x| x == &seat).unwrap() == 0
let devices = userdata.get::<Devices>().unwrap(); && self.common.egui.active
if devices.has_device(&device) { {
#[cfg(feature = "debug")] if self.common.egui.state.wants_pointer() {
if self.common.seats().position(|x| x == seat).unwrap() == 0 if let Some(button) = event.button() {
&& self.common.egui.active self.common.egui.state.handle_pointer_button(
{ button,
if self.common.egui.state.wants_pointer() { event.state() == ButtonState::Pressed,
if let Some(button) = event.button() { );
self.common.egui.state.handle_pointer_button(
button,
event.state() == ButtonState::Pressed,
);
}
break;
} }
return;
} }
}
let serial = SERIAL_COUNTER.next_serial(); let serial = SERIAL_COUNTER.next_serial();
let button = event.button_code(); let button = event.button_code();
if event.state() == ButtonState::Pressed { if event.state() == ButtonState::Pressed {
// change the keyboard focus unless the pointer or keyboard is grabbed // change the keyboard focus unless the pointer or keyboard is grabbed
// We test for any matching surface type here but always use the root // We test for any matching surface type here but always use the root
// (in case of a window the toplevel) surface for the focus. // (in case of a window the toplevel) surface for the focus.
// see: https://gitlab.freedesktop.org/wayland/wayland/-/issues/294 // see: https://gitlab.freedesktop.org/wayland/wayland/-/issues/294
if !seat.get_pointer().unwrap().is_grabbed() if !seat.get_pointer().unwrap().is_grabbed()
&& !seat.get_keyboard().map(|k| k.is_grabbed()).unwrap_or(false) && !seat.get_keyboard().map(|k| k.is_grabbed()).unwrap_or(false)
{ {
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;
if let Some(window) = workspace.get_fullscreen(&output) { if let Some(window) = workspace.get_fullscreen(&output) {
let layers = layer_map_for_output(&output);
if let Some(layer) =
layers.layer_under(WlrLayer::Overlay, relative_pos)
{
let layer_loc = layers.layer_geometry(layer).unwrap().loc;
if layer.can_receive_keyboard_focus()
&& layer
.surface_under(
relative_pos - layer_loc.to_f64(),
WindowSurfaceType::ALL,
)
.is_some()
{
under = Some(layer.clone().into());
}
} else {
under = Some(window.clone().into());
}
} else {
let done = {
let layers = layer_map_for_output(&output); let layers = layer_map_for_output(&output);
if let Some(layer) = if let Some(layer) = layers
layers.layer_under(WlrLayer::Overlay, relative_pos) .layer_under(WlrLayer::Overlay, 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() if layer.can_receive_keyboard_focus()
@ -656,17 +661,22 @@ impl State {
{ {
under = Some(layer.clone().into()); under = Some(layer.clone().into());
} }
true
} else { } else {
under = Some(window.clone().into()); false
} }
} else { };
let done = { if !done {
if let Some((target, _)) =
workspace.element_under(relative_pos, overview)
{
under = Some(target);
} 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::Overlay, relative_pos) layers.layer_under(WlrLayer::Bottom, pos).or_else(
.or_else(|| { || layers.layer_under(WlrLayer::Background, 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;
@ -680,67 +690,35 @@ impl State {
{ {
under = Some(layer.clone().into()); under = Some(layer.clone().into());
} }
true };
} else {
false
}
};
if !done {
if let Some((target, _)) =
workspace.element_under(relative_pos, overview)
{
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)
})
{
let layer_loc =
layers.layer_geometry(layer).unwrap().loc;
if layer.can_receive_keyboard_focus()
&& layer
.surface_under(
relative_pos - layer_loc.to_f64(),
WindowSurfaceType::ALL,
)
.is_some()
{
under = Some(layer.clone().into());
}
};
}
} }
} }
Common::set_focus(
self,
under.and_then(|target| target.try_into().ok()).as_ref(),
seat,
Some(serial),
);
} }
} else { Common::set_focus(
if let OverviewMode::Started(Trigger::Pointer(action_button), _) = self,
self.common.shell.overview_mode() under.and_then(|target| target.try_into().ok()).as_ref(),
{ &seat,
if action_button == button { Some(serial),
self.common.shell.set_overview_mode(None); );
} }
} else {
if let OverviewMode::Started(Trigger::Pointer(action_button), _) =
self.common.shell.overview_mode()
{
if action_button == button {
self.common.shell.set_overview_mode(None);
} }
}; }
seat.get_pointer().unwrap().button( };
self, seat.get_pointer().unwrap().button(
&ButtonEvent { self,
button, &ButtonEvent {
state: event.state(), button,
serial, state: event.state(),
time: event.time_msec(), serial,
}, 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,50 +747,152 @@ 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(); event.amount_discrete(Axis::Horizontal).unwrap_or(0.0) * 3.0
if devices.has_device(&device) { });
let horizontal_amount = let vertical_amount = event.amount(Axis::Vertical).unwrap_or_else(|| {
event.amount(Axis::Horizontal).unwrap_or_else(|| { event.amount_discrete(Axis::Vertical).unwrap_or(0.0) * 3.0
event.amount_discrete(Axis::Horizontal).unwrap_or(0.0) * 3.0 });
}); let horizontal_amount_discrete = event.amount_discrete(Axis::Horizontal);
let vertical_amount = event.amount(Axis::Vertical).unwrap_or_else(|| { let vertical_amount_discrete = event.amount_discrete(Axis::Vertical);
event.amount_discrete(Axis::Vertical).unwrap_or(0.0) * 3.0
});
let horizontal_amount_discrete = event.amount_discrete(Axis::Horizontal);
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 frame.value(Axis::Horizontal, scroll_factor * horizontal_amount);
.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);
}
} else if event.source() == AxisSource::Finger {
frame = frame.stop(Axis::Horizontal);
} }
if vertical_amount != 0.0 { } else if event.source() == AxisSource::Finger {
frame = frame = frame.stop(Axis::Horizontal);
frame.value(Axis::Vertical, scroll_factor * vertical_amount);
if let Some(discrete) = vertical_amount_discrete {
frame = frame.discrete(Axis::Vertical, discrete as i32);
}
} else if event.source() == AxisSource::Finger {
frame = frame.stop(Axis::Vertical);
}
seat.get_pointer().unwrap().axis(self, frame);
} }
break; if vertical_amount != 0.0 {
frame = frame.value(Axis::Vertical, scroll_factor * vertical_amount);
if let Some(discrete) = vertical_amount_discrete {
frame = frame.discrete(Axis::Vertical, discrete as i32);
}
} else if event.source() == AxisSource::Finger {
frame = frame.stop(Axis::Vertical);
}
seat.get_pointer().unwrap().axis(self, frame);
} }
} }
} }
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);