Watch
1
0
Fork
You've already forked smithay
0

anvil: Support touch events in winit backend

Need to handle touch events, and `DeviceAdded`.
This commit is contained in:
Ian Douglas Scott 2026-06-10 11:02:06 -07:00 • committed by Ian Douglas Scott
commit 4cb814df62

View file

@ -9,13 +9,14 @@ use smithay::backend::renderer::DebugFlags;
use smithay::{
backend::input::{
self, Axis, AxisSource, Event, InputBackend, InputEvent, KeyState, KeyboardKeyEvent,
PointerAxisEvent, PointerButtonEvent,
self, Axis, AxisSource, Device, DeviceCapability, Event, InputBackend, InputEvent, KeyState,
KeyboardKeyEvent, PointerAxisEvent, PointerButtonEvent, TouchEvent,
},
desktop::{WindowSurfaceType, layer_map_for_output},
input::{
keyboard::{FilterResult, Keysym, ModifiersState, keysyms as xkb},
pointer::{AxisFrame, ButtonEvent, MotionEvent},
touch::{DownEvent, UpEvent},
},
output::Scale,
reexports::{
@ -27,10 +28,10 @@ use smithay::{
input_method::InputMethodSeat,
keyboard_shortcuts_inhibit::KeyboardShortcutsInhibitorSeat,
shell::wlr_layer::{KeyboardInteractivity, Layer as WlrLayer},
tablet_manager::{TabletDescriptor, TabletSeatTrait},
},
};
#[cfg(any(feature = "winit", feature = "x11", feature = "udev"))]
use smithay::backend::input::AbsolutePositionEvent;
#[cfg(any(feature = "winit", feature = "x11"))]
@ -42,25 +43,21 @@ use crate::state::Backend;
use smithay::{
backend::{
input::{
Device, DeviceCapability, GestureBeginEvent, GestureEndEvent, GesturePinchUpdateEvent as _,
GestureSwipeUpdateEvent as _, PointerMotionEvent, ProximityState, TabletToolButtonEvent,
TabletToolEvent, TabletToolProximityEvent, TabletToolTipEvent, TabletToolTipState, TouchEvent,
GestureBeginEvent, GestureEndEvent, GesturePinchUpdateEvent as _, GestureSwipeUpdateEvent as _,
PointerMotionEvent, ProximityState, TabletToolButtonEvent, TabletToolEvent,
TabletToolProximityEvent, TabletToolTipEvent, TabletToolTipState,
},
session::Session,
},
input::{
pointer::{
GestureHoldBeginEvent, GestureHoldEndEvent, GesturePinchBeginEvent, GesturePinchEndEvent,
GesturePinchUpdateEvent, GestureSwipeBeginEvent, GestureSwipeEndEvent, GestureSwipeUpdateEvent,
RelativeMotionEvent,
},
touch::{DownEvent, UpEvent},
input::pointer::{
GestureHoldBeginEvent, GestureHoldEndEvent, GesturePinchBeginEvent, GesturePinchEndEvent,
GesturePinchUpdateEvent, GestureSwipeBeginEvent, GestureSwipeEndEvent, GestureSwipeUpdateEvent,
RelativeMotionEvent,
},
reexports::wayland_server::DisplayHandle,
wayland::{
pointer_constraints::{PointerConstraint, with_pointer_constraint},
seat::WaylandFocus,
tablet_manager::{TabletDescriptor, TabletSeatTrait},
},
};
@ -436,6 +433,126 @@ impl<BackendData: Backend> AnvilState<BackendData> {
pointer.frame(self);
}
}
fn touch_location_transformed<B: InputBackend, E: AbsolutePositionEvent<B>>(
&self,
evt: &E,
) -> Option<Point<f64, Logical>> {
let output = self
.space
.outputs()
.find(|output| output.name().starts_with("eDP"))
.or_else(|| self.space.outputs().next());
let output = output?;
let output_geometry = self.space.output_geometry(output)?;
let transform = output.current_transform();
let size = transform.invert().transform_size(output_geometry.size);
Some(
transform.transform_point_in(evt.position_transformed(size), &size.to_f64())
+ output_geometry.loc.to_f64(),
)
}
fn on_touch_down<B: InputBackend>(&mut self, evt: B::TouchDownEvent) {
let Some(handle) = self.seat.get_touch() else {
return;
};
let Some(touch_location) = self.touch_location_transformed(&evt) else {
return;
};
let serial = SCOUNTER.next_serial();
self.update_keyboard_focus(touch_location, serial);
let under = self.surface_under(touch_location);
handle.down(
self,
under,
&DownEvent {
slot: evt.slot(),
location: touch_location,
serial,
time: evt.time_msec(),
},
);
}
fn on_touch_up<B: InputBackend>(&mut self, evt: B::TouchUpEvent) {
let Some(handle) = self.seat.get_touch() else {
return;
};
let serial = SCOUNTER.next_serial();
handle.up(
self,
&UpEvent {
slot: evt.slot(),
serial,
time: evt.time_msec(),
},
)
}
fn on_touch_motion<B: InputBackend>(&mut self, evt: B::TouchMotionEvent) {
let Some(handle) = self.seat.get_touch() else {
return;
};
let Some(touch_location) = self.touch_location_transformed(&evt) else {
return;
};
let under = self.surface_under(touch_location);
handle.motion(
self,
under,
&smithay::input::touch::MotionEvent {
slot: evt.slot(),
location: touch_location,
time: evt.time_msec(),
},
);
}
fn on_touch_frame<B: InputBackend>(&mut self, _evt: B::TouchFrameEvent) {
let Some(handle) = self.seat.get_touch() else {
return;
};
handle.frame(self);
}
fn on_touch_cancel<B: InputBackend>(&mut self, _evt: B::TouchCancelEvent) {
let Some(handle) = self.seat.get_touch() else {
return;
};
handle.cancel(self);
}
fn on_device_added<B: InputBackend>(&mut self, device: B::Device) {
let dh = &self.display_handle;
if device.has_capability(DeviceCapability::TabletTool) {
self.seat
.tablet_seat()
.add_tablet::<Self>(dh, &TabletDescriptor::from(&device));
}
if device.has_capability(DeviceCapability::Touch) && self.seat.get_touch().is_none() {
self.seat.add_touch();
}
}
fn on_device_removed<B: InputBackend>(&mut self, device: B::Device) {
if device.has_capability(DeviceCapability::TabletTool) {
let tablet_seat = self.seat.tablet_seat();
tablet_seat.remove_tablet(&TabletDescriptor::from(&device));
// If there are no tablets in seat we can remove all tools
if tablet_seat.count_tablets() == 0 {
tablet_seat.clear_tools();
}
}
}
}
#[cfg(any(feature = "winit", feature = "x11"))]
@ -526,6 +643,13 @@ impl<BackendData: Backend> AnvilState<BackendData> {
}
InputEvent::PointerButton { event } => self.on_pointer_button::<B>(event),
InputEvent::PointerAxis { event } => self.on_pointer_axis::<B>(event),
InputEvent::TouchDown { event } => self.on_touch_down::<B>(event),
InputEvent::TouchUp { event } => self.on_touch_up::<B>(event),
InputEvent::TouchMotion { event } => self.on_touch_motion::<B>(event),
InputEvent::TouchFrame { event } => self.on_touch_frame::<B>(event),
InputEvent::TouchCancel { event } => self.on_touch_cancel::<B>(event),
InputEvent::DeviceAdded { device } => self.on_device_added::<B>(device),
InputEvent::DeviceRemoved { device } => self.on_device_removed::<B>(device),
_ => (), // other events are not handled in anvil (yet)
}
}
@ -748,28 +872,8 @@ impl AnvilState<UdevData> {
InputEvent::TouchFrame { event } => self.on_touch_frame::<B>(event),
InputEvent::TouchCancel { event } => self.on_touch_cancel::<B>(event),
InputEvent::DeviceAdded { device } => {
if device.has_capability(DeviceCapability::TabletTool) {
self.seat
.tablet_seat()
.add_tablet::<Self>(dh, &TabletDescriptor::from(&device));
}
if device.has_capability(DeviceCapability::Touch) && self.seat.get_touch().is_none() {
self.seat.add_touch();
}
}
InputEvent::DeviceRemoved { device } => {
if device.has_capability(DeviceCapability::TabletTool) {
let tablet_seat = self.seat.tablet_seat();
tablet_seat.remove_tablet(&TabletDescriptor::from(&device));
// If there are no tablets in seat we can remove all tools
if tablet_seat.count_tablets() == 0 {
tablet_seat.clear_tools();
}
}
}
InputEvent::DeviceAdded { device } => self.on_device_added::<B>(device),
InputEvent::DeviceRemoved { device } => self.on_device_removed::<B>(device),
_ => {
// other events are not handled in anvil (yet)
}
@ -1153,97 +1257,6 @@ impl AnvilState<UdevData> {
);
}
fn touch_location_transformed<B: InputBackend, E: AbsolutePositionEvent<B>>(
&self,
evt: &E,
) -> Option<Point<f64, Logical>> {
let output = self
.space
.outputs()
.find(|output| output.name().starts_with("eDP"))
.or_else(|| self.space.outputs().next());
let output = output?;
let output_geometry = self.space.output_geometry(output)?;
let transform = output.current_transform();
let size = transform.invert().transform_size(output_geometry.size);
Some(
transform.transform_point_in(evt.position_transformed(size), &size.to_f64())
+ output_geometry.loc.to_f64(),
)
}
fn on_touch_down<B: InputBackend>(&mut self, evt: B::TouchDownEvent) {
let Some(handle) = self.seat.get_touch() else {
return;
};
let Some(touch_location) = self.touch_location_transformed(&evt) else {
return;
};
let serial = SCOUNTER.next_serial();
self.update_keyboard_focus(touch_location, serial);
let under = self.surface_under(touch_location);
handle.down(
self,
under,
&DownEvent {
slot: evt.slot(),
location: touch_location,
serial,
time: evt.time_msec(),
},
);
}
fn on_touch_up<B: InputBackend>(&mut self, evt: B::TouchUpEvent) {
let Some(handle) = self.seat.get_touch() else {
return;
};
let serial = SCOUNTER.next_serial();
handle.up(
self,
&UpEvent {
slot: evt.slot(),
serial,
time: evt.time_msec(),
},
)
}
fn on_touch_motion<B: InputBackend>(&mut self, evt: B::TouchMotionEvent) {
let Some(handle) = self.seat.get_touch() else {
return;
};
let Some(touch_location) = self.touch_location_transformed(&evt) else {
return;
};
let under = self.surface_under(touch_location);
handle.motion(
self,
under,
&smithay::input::touch::MotionEvent {
slot: evt.slot(),
location: touch_location,
time: evt.time_msec(),
},
);
}
fn on_touch_frame<B: InputBackend>(&mut self, _evt: B::TouchFrameEvent) {
let Some(handle) = self.seat.get_touch() else {
return;
};
handle.frame(self);
}
fn on_touch_cancel<B: InputBackend>(&mut self, _evt: B::TouchCancelEvent) {
let Some(handle) = self.seat.get_touch() else {
return;
};
handle.cancel(self);
}
fn clamp_coords(&self, pos: Point<f64, Logical>) -> Point<f64, Logical> {
if self.space.outputs().next().is_none() {
return pos;