Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add client touch capability support #499

Merged
merged 7 commits into from
Mar 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
- `MouseButton` is now non-exhaustive.
- Remove `Other` and add `Forward` and `Back` variants to `MouseButton`. Use the new `PointerButtonEvent::button_code` in place of `Other`.
- `GrabStartData` has been renamed to `PointerGrabStartData`
- The `slot` method on touch events no longer returns an `Option` and multi-touch capability is thus opaque to the compositor

#### Backends

Expand Down Expand Up @@ -57,14 +58,15 @@
- Added a `KeyboardGrab` similar to the existing `PointerGrab`
- `wayland::output::Output` now has a `current_scale` method to quickly retrieve its set scale.
- `wayland::shell::wlr_layer::KeyboardInteractivity` now implements `PartialEq` and `Eq`.
- Added `TouchHandle` for Wayland client touch support (see `Seat::get_touch`)

#### Backends

- New `x11` backend to run the compositor as an X11 client. Enabled through the `backend_x11` feature.
- `x11rb` event source integration used in anvil's XWayland implementation is now part of smithay at `utils::x11rb`. Enabled through the `x11rb_event_source` feature.
- `x11rb` event source integration used in anvil's XWayland implementation is now part of smithay at `utils::x11rb`. Enabled through the `x11rb_event_source` feature.
- `KeyState`, `MouseButton`, `ButtonState` and `Axis` in `backend::input` now derive `Hash`.
- New `DrmNode` type in drm backend. This is primarily for use a backend which needs to run as client inside another session.
- The button code for a `PointerButtonEvent` may now be obtained using `PointerButtonEvent::button_code`.
- The button code for a `PointerButtonEvent` may now be obtained using `PointerButtonEvent::button_code`.
- `Renderer` now allows texture filtering methods to be set.
- `backend::renderer` has a new `utils`-module that can take care of client buffer management for you.
- `EGLSurface::buffer_age` can be used to query the surface buffer age.
Expand Down
41 changes: 23 additions & 18 deletions src/backend/input/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -336,22 +336,27 @@ impl<B: InputBackend> PointerMotionAbsoluteEvent<B> for UnusedEvent {
/// Touch events are grouped by slots, usually to identify different
/// fingers on a multi-touch enabled input device. Events should only
/// be interpreted in the context of other events on the same slot.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct TouchSlot {
id: u64,
id: Option<u32>,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've decided to change the TouchSlot here because it already was creating some friction inside my compositor when handling touch events and just created more problems when it came to converting the Option<TouchSlot> back to a i32 to send it to the client.

So since I'd assume nobody is using touch yet (since it doesn't work for clients), changing it now will prevent headaches in the future.

}

#[cfg(any(feature = "backend_winit", feature = "backend_libinput"))]
impl TouchSlot {
pub(crate) fn new(id: u64) -> Self {
TouchSlot { id }
impl From<Option<u32>> for TouchSlot {
fn from(id: Option<u32>) -> Self {
Self { id }
}
}

impl From<TouchSlot> for i32 {
fn from(slot: TouchSlot) -> i32 {
slot.id.map(|id| id as i32).unwrap_or(-1)
}
}

/// Trait for touch events starting at a given position.
pub trait TouchDownEvent<B: InputBackend>: Event<B> {
/// [`TouchSlot`], if the device has multi-touch capabilities
fn slot(&self) -> Option<TouchSlot>;
/// Multi-touch slot identifier.
fn slot(&self) -> TouchSlot;

/// Touch position in the device's native coordinate space
///
Expand Down Expand Up @@ -390,7 +395,7 @@ pub trait TouchDownEvent<B: InputBackend>: Event<B> {
}

impl<B: InputBackend> TouchDownEvent<B> for UnusedEvent {
fn slot(&self) -> Option<TouchSlot> {
fn slot(&self) -> TouchSlot {
match *self {}
}

Expand All @@ -413,8 +418,8 @@ impl<B: InputBackend> TouchDownEvent<B> for UnusedEvent {

/// Trait for touch events regarding movement on the screen
pub trait TouchMotionEvent<B: InputBackend>: Event<B> {
/// [`TouchSlot`], if the device has multi-touch capabilities
fn slot(&self) -> Option<TouchSlot>;
/// Multi-touch slot identifier.
fn slot(&self) -> TouchSlot;

/// Touch position in the device's native coordinate space
///
Expand Down Expand Up @@ -453,7 +458,7 @@ pub trait TouchMotionEvent<B: InputBackend>: Event<B> {
}

impl<B: InputBackend> TouchMotionEvent<B> for UnusedEvent {
fn slot(&self) -> Option<TouchSlot> {
fn slot(&self) -> TouchSlot {
match *self {}
}

Expand All @@ -476,24 +481,24 @@ impl<B: InputBackend> TouchMotionEvent<B> for UnusedEvent {

/// Trait for touch events finishing.
pub trait TouchUpEvent<B: InputBackend>: Event<B> {
/// [`TouchSlot`], if the device has multi-touch capabilities
fn slot(&self) -> Option<TouchSlot>;
/// Multi-touch slot identifier.
fn slot(&self) -> TouchSlot;
}

impl<B: InputBackend> TouchUpEvent<B> for UnusedEvent {
fn slot(&self) -> Option<TouchSlot> {
fn slot(&self) -> TouchSlot {
match *self {}
}
}

/// Trait for touch events canceling the chain
pub trait TouchCancelEvent<B: InputBackend>: Event<B> {
/// [`TouchSlot`], if the device has multi-touch capabilities
fn slot(&self) -> Option<TouchSlot>;
/// Multi-touch slot identifier.
fn slot(&self) -> TouchSlot;
}

impl<B: InputBackend> TouchCancelEvent<B> for UnusedEvent {
fn slot(&self) -> Option<TouchSlot> {
fn slot(&self) -> TouchSlot {
match *self {}
}
}
Expand Down
16 changes: 8 additions & 8 deletions src/backend/libinput/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,8 +256,8 @@ impl backend::Event<LibinputInputBackend> for event::touch::TouchDownEvent {
}

impl backend::TouchDownEvent<LibinputInputBackend> for event::touch::TouchDownEvent {
fn slot(&self) -> Option<backend::TouchSlot> {
event::touch::TouchEventSlot::slot(self).map(|x| backend::TouchSlot::new(x as u64))
fn slot(&self) -> backend::TouchSlot {
event::touch::TouchEventSlot::slot(self).into()
}

fn x(&self) -> f64 {
Expand Down Expand Up @@ -288,8 +288,8 @@ impl backend::Event<LibinputInputBackend> for event::touch::TouchMotionEvent {
}

impl backend::TouchMotionEvent<LibinputInputBackend> for event::touch::TouchMotionEvent {
fn slot(&self) -> Option<backend::TouchSlot> {
event::touch::TouchEventSlot::slot(self).map(|x| backend::TouchSlot::new(x as u64))
fn slot(&self) -> backend::TouchSlot {
event::touch::TouchEventSlot::slot(self).into()
}

fn x(&self) -> f64 {
Expand Down Expand Up @@ -320,8 +320,8 @@ impl backend::Event<LibinputInputBackend> for event::touch::TouchUpEvent {
}

impl backend::TouchUpEvent<LibinputInputBackend> for event::touch::TouchUpEvent {
fn slot(&self) -> Option<backend::TouchSlot> {
event::touch::TouchEventSlot::slot(self).map(|x| backend::TouchSlot::new(x as u64))
fn slot(&self) -> backend::TouchSlot {
event::touch::TouchEventSlot::slot(self).into()
}
}

Expand All @@ -336,8 +336,8 @@ impl backend::Event<LibinputInputBackend> for event::touch::TouchCancelEvent {
}

impl backend::TouchCancelEvent<LibinputInputBackend> for event::touch::TouchCancelEvent {
fn slot(&self) -> Option<backend::TouchSlot> {
event::touch::TouchEventSlot::slot(self).map(|x| backend::TouchSlot::new(x as u64))
fn slot(&self) -> backend::TouchSlot {
event::touch::TouchEventSlot::slot(self).into()
}
}

Expand Down
16 changes: 8 additions & 8 deletions src/backend/winit/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,8 +224,8 @@ impl Event<WinitInput> for WinitTouchStartedEvent {
}

impl TouchDownEvent<WinitInput> for WinitTouchStartedEvent {
fn slot(&self) -> Option<TouchSlot> {
Some(TouchSlot::new(self.id))
fn slot(&self) -> TouchSlot {
Some(self.id as u32).into()
}

fn x(&self) -> f64 {
Expand Down Expand Up @@ -271,8 +271,8 @@ impl Event<WinitInput> for WinitTouchMovedEvent {
}

impl TouchMotionEvent<WinitInput> for WinitTouchMovedEvent {
fn slot(&self) -> Option<TouchSlot> {
Some(TouchSlot::new(self.id))
fn slot(&self) -> TouchSlot {
Some(self.id as u32).into()
}

fn x(&self) -> f64 {
Expand Down Expand Up @@ -316,8 +316,8 @@ impl Event<WinitInput> for WinitTouchEndedEvent {
}

impl TouchUpEvent<WinitInput> for WinitTouchEndedEvent {
fn slot(&self) -> Option<TouchSlot> {
Some(TouchSlot::new(self.id))
fn slot(&self) -> TouchSlot {
Some(self.id as u32).into()
}
}

Expand All @@ -339,8 +339,8 @@ impl Event<WinitInput> for WinitTouchCancelledEvent {
}

impl TouchCancelEvent<WinitInput> for WinitTouchCancelledEvent {
fn slot(&self) -> Option<TouchSlot> {
Some(TouchSlot::new(self.id))
fn slot(&self) -> TouchSlot {
Some(self.id as u32).into()
}
}

Expand Down
69 changes: 67 additions & 2 deletions src/wayland/seat/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ use std::{cell::RefCell, fmt, ops::Deref as _, rc::Rc};

mod keyboard;
mod pointer;
mod touch;

pub use self::{
keyboard::{
Expand All @@ -48,6 +49,7 @@ pub use self::{
AxisFrame, CursorImageAttributes, CursorImageStatus, GrabStartData as PointerGrabStartData,
PointerGrab, PointerHandle, PointerInnerHandle,
},
touch::TouchHandle,
};

use wayland_server::{
Expand All @@ -59,6 +61,7 @@ use wayland_server::{
struct Inner {
pointer: Option<PointerHandle>,
keyboard: Option<KeyboardHandle>,
touch: Option<TouchHandle>,
known_seats: Vec<wl_seat::WlSeat>,
}

Expand Down Expand Up @@ -90,6 +93,9 @@ impl Inner {
if self.keyboard.is_some() {
caps |= wl_seat::Capability::Keyboard;
}
if self.touch.is_some() {
caps |= wl_seat::Capability::Touch;
}
caps
}

Expand Down Expand Up @@ -134,6 +140,7 @@ impl Seat {
inner: RefCell::new(Inner {
pointer: None,
keyboard: None,
touch: None,
known_seats: Vec::new(),
}),
log: log.new(slog::o!("smithay_module" => "seat_handler", "seat_name" => name.clone())),
Expand Down Expand Up @@ -313,6 +320,59 @@ impl Seat {
}
}

/// Adds the touch capability to this seat
///
/// You are provided a [`TouchHandle`], which allows you to send input events
/// to this pointer. This handle can be cloned.
///
/// Calling this method on a seat that already has a touch capability
/// will overwrite it, and will be seen by the clients as if the
/// touchscreen was unplugged and a new one was plugged in.
///
/// # Examples
///
/// ```
/// # extern crate wayland_server;
/// #
/// # use smithay::wayland::seat::Seat;
/// #
/// # let mut display = wayland_server::Display::new();
/// # let (mut seat, seat_global) = Seat::new(
/// # &mut display,
/// # "seat-0".into(),
/// # None
/// # );
/// let touch_handle = seat.add_touch();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This example doesn't really explain anything more than the function docs itself.

If the seat creation are made visible it would be more jusitifed to have.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct, but I'd say the same applies for the existing code examples for keyboard/pointer?

If the seat creation are made visible it would be more jusitifed to have.

What do you mean by this? Removing the # before the seat stuff?

/// ```
pub fn add_touch(&mut self) -> TouchHandle {
let mut inner = self.arc.inner.borrow_mut();
let touch = TouchHandle::new();
if inner.touch.is_some() {
// If there's already a tocuh device, remove it notify the clients about the change.
inner.touch = None;
inner.send_all_caps();
}
inner.touch = Some(touch.clone());
inner.send_all_caps();
touch
}

/// Access the touch device of this seat, if any.
pub fn get_touch(&self) -> Option<TouchHandle> {
self.arc.inner.borrow_mut().touch.clone()
}

/// Remove the touch capability from this seat
///
/// Clients will be appropriately notified.
pub fn remove_touch(&mut self) {
let mut inner = self.arc.inner.borrow_mut();
if inner.touch.is_some() {
inner.touch = None;
inner.send_all_caps();
}
}

/// Checks whether a given [`WlSeat`](wl_seat::WlSeat) is associated with this [`Seat`]
pub fn owns(&self, seat: &wl_seat::WlSeat) -> bool {
let inner = self.arc.inner.borrow_mut();
Expand Down Expand Up @@ -349,8 +409,13 @@ fn implement_seat(seat: Main<wl_seat::WlSeat>, arc: Rc<SeatRc>) -> wl_seat::WlSe
// same as pointer, should error but cannot
}
}
wl_seat::Request::GetTouch { .. } => {
// TODO
wl_seat::Request::GetTouch { id } => {
let touch = self::touch::implement_touch(id, inner.touch.as_ref());
if let Some(ref touch_handle) = inner.touch {
touch_handle.new_touch(touch);
} else {
// same as pointer, should error but cannot
}
}
wl_seat::Request::Release => {
// Our destructors already handle it
Expand Down
Loading