Skip to content

Commit

Permalink
input: add infrastucture for proper touch support
Browse files Browse the repository at this point in the history
this brings touch handling to the same level as we
already provide for pointer and keyboard.
  • Loading branch information
cmeissl committed Feb 18, 2024
1 parent 863ef2e commit a624a43
Show file tree
Hide file tree
Showing 36 changed files with 2,382 additions and 399 deletions.
104 changes: 101 additions & 3 deletions anvil/src/focus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,12 @@ pub use smithay::{
};
use smithay::{
desktop::Window,
input::pointer::{
GestureHoldBeginEvent, GestureHoldEndEvent, GesturePinchBeginEvent, GesturePinchEndEvent,
GesturePinchUpdateEvent, GestureSwipeBeginEvent, GestureSwipeEndEvent, GestureSwipeUpdateEvent,
input::{
pointer::{
GestureHoldBeginEvent, GestureHoldEndEvent, GesturePinchBeginEvent, GesturePinchEndEvent,
GesturePinchUpdateEvent, GestureSwipeBeginEvent, GestureSwipeEndEvent, GestureSwipeUpdateEvent,
},
touch::TouchTarget,
},
};

Expand Down Expand Up @@ -349,6 +352,101 @@ impl<BackendData: Backend> KeyboardTarget<AnvilState<BackendData>> for KeyboardF
}
}

impl<BackendData: Backend> TouchTarget<AnvilState<BackendData>> for PointerFocusTarget {
fn down(
&self,
seat: &Seat<AnvilState<BackendData>>,
data: &mut AnvilState<BackendData>,
event: &smithay::input::touch::DownEvent,
seq: Serial,
) {
match self {
PointerFocusTarget::WlSurface(w) => TouchTarget::down(w, seat, data, event, seq),
#[cfg(feature = "xwayland")]
PointerFocusTarget::X11Surface(w) => TouchTarget::down(w, seat, data, event, seq),
PointerFocusTarget::SSD(w) => TouchTarget::down(w, seat, data, event, seq),
}
}

fn up(
&self,
seat: &Seat<AnvilState<BackendData>>,
data: &mut AnvilState<BackendData>,
event: &smithay::input::touch::UpEvent,
seq: Serial,
) {
match self {
PointerFocusTarget::WlSurface(w) => TouchTarget::up(w, seat, data, event, seq),
#[cfg(feature = "xwayland")]
PointerFocusTarget::X11Surface(w) => TouchTarget::up(w, seat, data, event, seq),
PointerFocusTarget::SSD(w) => TouchTarget::up(w, seat, data, event, seq),
}
}

fn motion(
&self,
seat: &Seat<AnvilState<BackendData>>,
data: &mut AnvilState<BackendData>,
event: &smithay::input::touch::MotionEvent,
seq: Serial,
) {
match self {
PointerFocusTarget::WlSurface(w) => TouchTarget::motion(w, seat, data, event, seq),
#[cfg(feature = "xwayland")]
PointerFocusTarget::X11Surface(w) => TouchTarget::motion(w, seat, data, event, seq),
PointerFocusTarget::SSD(w) => TouchTarget::motion(w, seat, data, event, seq),
}
}

fn frame(&self, seat: &Seat<AnvilState<BackendData>>, data: &mut AnvilState<BackendData>, seq: Serial) {
match self {
PointerFocusTarget::WlSurface(w) => TouchTarget::frame(w, seat, data, seq),
#[cfg(feature = "xwayland")]
PointerFocusTarget::X11Surface(w) => TouchTarget::frame(w, seat, data, seq),
PointerFocusTarget::SSD(w) => TouchTarget::frame(w, seat, data, seq),
}
}

fn cancel(&self, seat: &Seat<AnvilState<BackendData>>, data: &mut AnvilState<BackendData>, seq: Serial) {
match self {
PointerFocusTarget::WlSurface(w) => TouchTarget::cancel(w, seat, data, seq),
#[cfg(feature = "xwayland")]
PointerFocusTarget::X11Surface(w) => TouchTarget::cancel(w, seat, data, seq),
PointerFocusTarget::SSD(w) => TouchTarget::cancel(w, seat, data, seq),
}
}

fn shape(
&self,
seat: &Seat<AnvilState<BackendData>>,
data: &mut AnvilState<BackendData>,
event: &smithay::input::touch::ShapeEvent,
seq: Serial,
) {
match self {
PointerFocusTarget::WlSurface(w) => TouchTarget::shape(w, seat, data, event, seq),
#[cfg(feature = "xwayland")]
PointerFocusTarget::X11Surface(w) => TouchTarget::shape(w, seat, data, event, seq),
PointerFocusTarget::SSD(w) => TouchTarget::shape(w, seat, data, event, seq),
}
}

fn orientation(
&self,
seat: &Seat<AnvilState<BackendData>>,
data: &mut AnvilState<BackendData>,
event: &smithay::input::touch::OrientationEvent,
seq: Serial,
) {
match self {
PointerFocusTarget::WlSurface(w) => TouchTarget::orientation(w, seat, data, event, seq),
#[cfg(feature = "xwayland")]
PointerFocusTarget::X11Surface(w) => TouchTarget::orientation(w, seat, data, event, seq),
PointerFocusTarget::SSD(w) => TouchTarget::orientation(w, seat, data, event, seq),
}
}
}

impl WaylandFocus for PointerFocusTarget {
fn wl_surface(&self) -> Option<WlSurface> {
match self {
Expand Down
125 changes: 119 additions & 6 deletions anvil/src/input_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,17 @@ use smithay::{
input::{
Device, DeviceCapability, GestureBeginEvent, GestureEndEvent, GesturePinchUpdateEvent as _,
GestureSwipeUpdateEvent as _, PointerMotionEvent, ProximityState, TabletToolButtonEvent,
TabletToolEvent, TabletToolProximityEvent, TabletToolTipEvent, TabletToolTipState,
TabletToolEvent, TabletToolProximityEvent, TabletToolTipEvent, TabletToolTipState, TouchEvent,
},
session::Session,
},
input::pointer::{
GestureHoldBeginEvent, GestureHoldEndEvent, GesturePinchBeginEvent, GesturePinchEndEvent,
GesturePinchUpdateEvent, GestureSwipeBeginEvent, GestureSwipeEndEvent, GestureSwipeUpdateEvent,
RelativeMotionEvent,
input::{
pointer::{
GestureHoldBeginEvent, GestureHoldEndEvent, GesturePinchBeginEvent, GesturePinchEndEvent,
GesturePinchUpdateEvent, GestureSwipeBeginEvent, GestureSwipeEndEvent, GestureSwipeUpdateEvent,
RelativeMotionEvent,
},
touch::{DownEvent, UpEvent},
},
wayland::{
pointer_constraints::{with_pointer_constraint, PointerConstraint},
Expand Down Expand Up @@ -257,6 +260,7 @@ impl<BackendData: Backend> AnvilState<BackendData> {

fn update_keyboard_focus(&mut self, location: Point<f64, Logical>, serial: Serial) {
let keyboard = self.seat.get_keyboard().unwrap();
let touch = self.seat.get_touch();
let input_method = self.seat.input_method();
// change the keyboard focus unless the pointer or keyboard is grabbed
// We test for any matching surface type here but always use the root
Expand All @@ -267,7 +271,10 @@ impl<BackendData: Backend> AnvilState<BackendData> {
// subsurface menus (for example firefox-wayland).
// see here for a discussion about that issue:
// https://gitlab.freedesktop.org/wayland/wayland/-/issues/294
if !self.pointer.is_grabbed() && (!keyboard.is_grabbed() || input_method.keyboard_grabbed()) {
if !self.pointer.is_grabbed()
&& (!keyboard.is_grabbed() || input_method.keyboard_grabbed())
&& !touch.map(|touch| touch.is_grabbed()).unwrap_or(false)
{
let output = self.space.output_under(location).next().cloned();
if let Some(output) = output.as_ref() {
let output_geo = self.space.output_geometry(output).unwrap();
Expand Down Expand Up @@ -756,12 +763,22 @@ impl AnvilState<UdevData> {
InputEvent::GesturePinchEnd { event, .. } => self.on_gesture_pinch_end::<B>(event),
InputEvent::GestureHoldBegin { event, .. } => self.on_gesture_hold_begin::<B>(event),
InputEvent::GestureHoldEnd { event, .. } => self.on_gesture_hold_end::<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 } => {
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) {
Expand Down Expand Up @@ -1173,6 +1190,102 @@ 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 Some(output) = output else {
return None;
};

let Some(output_geometry) = self.space.output_geometry(output) else {
return None;
};

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;
Expand Down
65 changes: 65 additions & 0 deletions anvil/src/shell/element.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use smithay::{
GesturePinchEndEvent, GesturePinchUpdateEvent, GestureSwipeBeginEvent, GestureSwipeEndEvent,
GestureSwipeUpdateEvent, MotionEvent, PointerTarget, RelativeMotionEvent,
},
touch::TouchTarget,
Seat,
},
output::Output,
Expand Down Expand Up @@ -316,6 +317,70 @@ impl<Backend: crate::state::Backend> PointerTarget<AnvilState<Backend>> for SSD
}
}

impl<Backend: crate::state::Backend> TouchTarget<AnvilState<Backend>> for SSD {
fn down(
&self,
seat: &Seat<AnvilState<Backend>>,
data: &mut AnvilState<Backend>,
event: &smithay::input::touch::DownEvent,
_seq: Serial,
) {
let mut state = self.0.decoration_state();
if state.is_ssd {
state.header_bar.pointer_enter(event.location);
state.header_bar.touch_down(seat, data, &self.0, event.serial);
}
}

fn up(
&self,
seat: &Seat<AnvilState<Backend>>,
data: &mut AnvilState<Backend>,
event: &smithay::input::touch::UpEvent,
_seq: Serial,
) {
let mut state = self.0.decoration_state();
if state.is_ssd {
state.header_bar.touch_up(seat, data, &self.0, event.serial);
}
}

fn motion(
&self,
_seat: &Seat<AnvilState<Backend>>,
_data: &mut AnvilState<Backend>,
event: &smithay::input::touch::MotionEvent,
_seq: Serial,
) {
let mut state = self.0.decoration_state();
if state.is_ssd {
state.header_bar.pointer_enter(event.location);
}
}

fn frame(&self, _seat: &Seat<AnvilState<Backend>>, _data: &mut AnvilState<Backend>, _seq: Serial) {}

fn cancel(&self, _seat: &Seat<AnvilState<Backend>>, _data: &mut AnvilState<Backend>, _seq: Serial) {}

fn shape(
&self,
_seat: &Seat<AnvilState<Backend>>,
_data: &mut AnvilState<Backend>,
_event: &smithay::input::touch::ShapeEvent,
_seq: Serial,
) {
}

fn orientation(
&self,
_seat: &Seat<AnvilState<Backend>>,
_data: &mut AnvilState<Backend>,
_event: &smithay::input::touch::OrientationEvent,
_seq: Serial,
) {
}
}

impl SpaceElement for WindowElement {
fn geometry(&self) -> Rectangle<i32, Logical> {
let mut geo = match self {
Expand Down
Loading

0 comments on commit a624a43

Please sign in to comment.