🔒 Repository is read-only – file editing is disabled.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
//! Utilities for graphics tablet support
//!
//! This module provides helpers to handle graphics tablets.
//!
//! ```
//! use smithay::{delegate_seat, delegate_tablet_manager};
//! # use smithay::delegate_compositor;
//! use smithay::backend::input::TabletToolDescriptor;
//! use smithay::input::{Seat, SeatState, SeatHandler, pointer::CursorImageStatus};
//! # use smithay::wayland::compositor::{CompositorHandler, CompositorState, CompositorClientState};
//! use smithay::wayland::tablet_manager::{TabletManagerState, TabletDescriptor, TabletSeatHandler};
//! use smithay::reexports::wayland_server::{Display, protocol::wl_surface::WlSurface};
//! # use smithay::reexports::wayland_server::Client;
//!
//! # struct State { seat_state: SeatState<Self> };
//! # let mut display = Display::<State>::new().unwrap();
//! # let display_handle = display.handle();
//!
//! let mut seat_state = SeatState::<State>::new();
//! let tablet_state = TabletManagerState::new::<State>(&display_handle);
//! // add the seat state to your state
//! // ...
//!
//! // create the seat
//! let seat = seat_state.new_wl_seat(
//! &display_handle, // the display
//! "seat-0", // the name of the seat, will be advertized to clients
//! );
//!
//! use smithay::wayland::tablet_manager::TabletSeatTrait;
//!
//! seat
//! .tablet_seat() // Get TabletSeat asosiated with this seat
//! .add_tablet::<State>( // Add a new tablet to a seat
//! &display_handle,
//! &TabletDescriptor {
//! name: "Test".into(),
//! usb_id: None,
//! syspath: None,
//! }
//! );
//!
//! // implement the required traits
//! impl SeatHandler for State {
//! type KeyboardFocus = WlSurface;
//! type PointerFocus = WlSurface;
//! type TouchFocus = WlSurface;
//! fn seat_state(&mut self) -> &mut SeatState<Self> {
//! &mut self.seat_state
//! }
//! fn focus_changed(&mut self, seat: &Seat<Self>, focused: Option<&WlSurface>) {
//! // ...
//! }
//! fn cursor_image(&mut self, seat: &Seat<Self>, image: CursorImageStatus) {
//! // ...
//! }
//! }
//! delegate_seat!(State);
//!
//! impl TabletSeatHandler for State {
//! fn tablet_tool_image(&mut self, tool: &TabletToolDescriptor, image: CursorImageStatus) {
//! // ...
//! }
//! }
//! delegate_tablet_manager!(State);
//!
//! # impl CompositorHandler for State {
//! # fn compositor_state(&mut self) -> &mut CompositorState { unimplemented!() }
//! # fn client_compositor_state<'a>(&self, client: &'a Client) -> &'a CompositorClientState { unimplemented!() }
//! # fn commit(&mut self, surface: &WlSurface) {}
//! # }
//! # delegate_compositor!(State);
//! ```
//! ```ignore
//! // Init the manager global
//! let state = TabletManagerState::new::<D>(&display);
//!
//! // Init the seat
//! let seat = Seat::<D>::new(
//! &display,
//! "seat-0".into(),
//! None
//! );
//!
//! use smithay::wyaldnd::tablet_manager::TabletSeatTrait;
//!
//! seat
//! .tablet_seat() // Get TabletSeat asosiated with this seat
//! .add_tablet( // Add a new tablet to a seat
//! display
//! &TabletDescriptor {
//! name: "Test".into(),
//! usb_id: None,
//! syspath: None,
//! }
//! );
//! ```
use crate::input::{Seat, SeatHandler};
use wayland_protocols::wp::tablet::zv2::server::{
zwp_tablet_manager_v2::{self, ZwpTabletManagerV2},
zwp_tablet_seat_v2::ZwpTabletSeatV2,
zwp_tablet_tool_v2::ZwpTabletToolV2,
zwp_tablet_v2::ZwpTabletV2,
};
use wayland_server::{backend::GlobalId, Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New};
const MANAGER_VERSION: u32 = 1;
mod tablet;
mod tablet_seat;
pub(crate) mod tablet_tool;
pub use tablet::{TabletDescriptor, TabletHandle, TabletUserData};
pub use tablet_seat::{TabletSeatHandle, TabletSeatHandler, TabletSeatUserData};
pub use tablet_tool::{TabletToolHandle, TabletToolUserData};
use super::compositor::CompositorHandler;
/// Extends [Seat] with graphic tablet specific functionality
pub trait TabletSeatTrait {
/// Get tablet seat associated with this seat
fn tablet_seat(&self) -> TabletSeatHandle;
}
impl<D: SeatHandler + 'static> TabletSeatTrait for Seat<D> {
fn tablet_seat(&self) -> TabletSeatHandle {
let user_data = self.user_data();
user_data.insert_if_missing(TabletSeatHandle::default);
user_data.get::<TabletSeatHandle>().unwrap().clone()
}
}
/// State of wp tablet protocol
#[derive(Debug)]
pub struct TabletManagerState {
global: GlobalId,
}
impl TabletManagerState {
/// Initialize a tablet manager global.
pub fn new<D>(display: &DisplayHandle) -> Self
where
D: GlobalDispatch<ZwpTabletManagerV2, ()>,
D: Dispatch<ZwpTabletManagerV2, ()>,
D: Dispatch<ZwpTabletSeatV2, TabletSeatUserData>,
D: Dispatch<ZwpTabletToolV2, TabletToolUserData>,
D: 'static,
{
let global = display.create_global::<D, ZwpTabletManagerV2, _>(MANAGER_VERSION, ());
Self { global }
}
/// Get the id of ZwpTabletManagerV2 global
pub fn global(&self) -> GlobalId {
self.global.clone()
}
}
impl<D> GlobalDispatch<ZwpTabletManagerV2, (), D> for TabletManagerState
where
D: GlobalDispatch<ZwpTabletManagerV2, ()>,
D: Dispatch<ZwpTabletManagerV2, ()>,
D: Dispatch<ZwpTabletSeatV2, TabletSeatUserData>,
D: 'static,
{
fn bind(
_: &mut D,
_: &DisplayHandle,
_: &Client,
resource: New<ZwpTabletManagerV2>,
_: &(),
data_init: &mut DataInit<'_, D>,
) {
data_init.init(resource, ());
}
}
impl<D> Dispatch<ZwpTabletManagerV2, (), D> for TabletManagerState
where
D: Dispatch<ZwpTabletManagerV2, ()>,
D: Dispatch<ZwpTabletSeatV2, TabletSeatUserData>,
D: Dispatch<ZwpTabletV2, TabletUserData>,
D: Dispatch<ZwpTabletToolV2, TabletToolUserData>,
D: SeatHandler + TabletSeatHandler + 'static,
D: CompositorHandler,
{
fn request(
state: &mut D,
client: &Client,
_: &ZwpTabletManagerV2,
request: zwp_tablet_manager_v2::Request,
_: &(),
dh: &DisplayHandle,
data_init: &mut DataInit<'_, D>,
) {
match request {
zwp_tablet_manager_v2::Request::GetTabletSeat { tablet_seat, seat } => {
let seat = Seat::<D>::from_resource(&seat).unwrap();
let user_data = seat.user_data();
user_data.insert_if_missing(TabletSeatHandle::default);
let handle = user_data.get::<TabletSeatHandle>().unwrap();
let instance = data_init.init(
tablet_seat,
TabletSeatUserData {
handle: handle.clone(),
},
);
handle.add_instance::<D>(state, dh, &instance, client);
}
zwp_tablet_manager_v2::Request::Destroy => {
// Nothing to do
}
_ => unreachable!(),
}
}
}
#[allow(missing_docs)] // TODO
#[macro_export]
macro_rules! delegate_tablet_manager {
($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => {
$crate::reexports::wayland_server::delegate_global_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
$crate::reexports::wayland_protocols::wp::tablet::zv2::server::zwp_tablet_manager_v2::ZwpTabletManagerV2: ()
] => $crate::wayland::tablet_manager::TabletManagerState);
$crate::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
$crate::reexports::wayland_protocols::wp::tablet::zv2::server::zwp_tablet_manager_v2::ZwpTabletManagerV2: ()
] => $crate::wayland::tablet_manager::TabletManagerState);
$crate::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
$crate::reexports::wayland_protocols::wp::tablet::zv2::server::zwp_tablet_seat_v2::ZwpTabletSeatV2: $crate::wayland::tablet_manager::TabletSeatUserData
] => $crate::wayland::tablet_manager::TabletManagerState);
$crate::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
$crate::reexports::wayland_protocols::wp::tablet::zv2::server::zwp_tablet_tool_v2::ZwpTabletToolV2: $crate::wayland::tablet_manager::TabletToolUserData
] => $crate::wayland::tablet_manager::TabletManagerState);
$crate::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
$crate::reexports::wayland_protocols::wp::tablet::zv2::server::zwp_tablet_v2::ZwpTabletV2: $crate::wayland::tablet_manager::TabletUserData
] => $crate::wayland::tablet_manager::TabletManagerState);
};
}