From 8de89fbf51985917570f56c50e0495efe2583ebd Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Fri, 1 May 2026 17:46:14 -0700 Subject: [PATCH 1/2] keyboard: Assume `T` and `D` parameters are the same Presumably the type argument for the `LoopHandle` is expected to match the the `D` type used for wayland-rs dispatch? Unless the calloop event loop isn't being used to dispatch Wayland events. Without `keyboard:` specified in `delegate_keyboard!`, this did use `KeyboardData<$ty>`, so in that case these are assumed to match. --- src/seat/keyboard/mod.rs | 10 +++++----- src/seat/keyboard/repeat.rs | 11 +++++------ 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/seat/keyboard/mod.rs b/src/seat/keyboard/mod.rs index 2c6384ace..ecfaab26c 100644 --- a/src/seat/keyboard/mod.rs +++ b/src/seat/keyboard/mod.rs @@ -58,14 +58,14 @@ impl SeatState { /// ## Errors /// /// This will return [`SeatError::UnsupportedCapability`] if the seat does not support a keyboard. - pub fn get_keyboard( + pub fn get_keyboard( &mut self, qh: &QueueHandle, seat: &wl_seat::WlSeat, rmlvo: Option, ) -> Result where - D: Dispatch> + D: Dispatch> + SeatHandler + KeyboardHandler + 'static, @@ -96,7 +96,7 @@ impl SeatState { ) -> Result where D: Dispatch + SeatHandler + KeyboardHandler + 'static, - U: KeyboardDataExt + 'static, + U: KeyboardDataExt + 'static, { let inner = self.seats.iter().find(|inner| &inner.seat == seat).ok_or(SeatError::DeadObject)?; @@ -504,8 +504,8 @@ impl KeyboardDataExt for KeyboardData { impl Dispatch for SeatState where - D: Dispatch + KeyboardHandler, - U: KeyboardDataExt, + D: Dispatch + KeyboardHandler + 'static, + U: KeyboardDataExt, { fn event( data: &mut D, diff --git a/src/seat/keyboard/repeat.rs b/src/seat/keyboard/repeat.rs index 0a549c9ce..bb09e8954 100644 --- a/src/seat/keyboard/repeat.rs +++ b/src/seat/keyboard/repeat.rs @@ -55,17 +55,16 @@ impl SeatState { /// This will return [`SeatError::UnsupportedCapability`] if the seat does not support a keyboard. /// /// [`EventSource`]: calloop::EventSource - pub fn get_keyboard_with_repeat( + pub fn get_keyboard_with_repeat( &mut self, qh: &QueueHandle, seat: &wl_seat::WlSeat, rmlvo: Option, - loop_handle: LoopHandle<'static, T>, - callback: RepeatCallback, + loop_handle: LoopHandle<'static, D>, + callback: RepeatCallback, ) -> Result where - D: Dispatch> + KeyboardHandler + 'static, - T: 'static, + D: Dispatch> + KeyboardHandler + 'static, { let udata = match rmlvo { Some(rmlvo) => KeyboardData::from_rmlvo(seat.clone(), rmlvo)?, @@ -99,7 +98,7 @@ impl SeatState { ) -> Result where D: Dispatch + KeyboardHandler + 'static, - U: KeyboardDataExt + 'static, + U: KeyboardDataExt + 'static, { let inner = self.seats.iter().find(|inner| &inner.seat == seat).ok_or(SeatError::DeadObject)?; From 6f20afa5e2439ef8f0aede913537a3ddddc0d0ef Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Sun, 10 May 2026 21:04:17 -0700 Subject: [PATCH 2/2] WIP keyboard: Wrap udata instead of using `Ext` trait WIP surface udata fix macro macro WIP pointer macro WIP DataSourceData macro did earlier version not actually provide any way to implement dispatch for custom type here? constructor and accessors pub constructors touch WIP activation not compiling types in example? should be fine to get rid of trait and just rely on immutable wrapper struct. WIP don't make `delegate_activation!` generic Not compiling... can that work? see how that works with new wayland-rs. input method should fix custom data types previously was seemingly broken for delegating dispatch, constructing with custom data, or commit() aaccessing `.data` input-method-v3 --- examples/simple_window.rs | 5 +- examples/themed_window.rs | 4 +- src/activation.rs | 92 +++++---------------- src/compositor.rs | 95 +++++++++++---------- src/data_device_manager/data_source.rs | 27 +++--- src/data_device_manager/mod.rs | 10 +-- src/seat/input_method.rs | 63 ++++++++------ src/seat/input_method_v3.rs | 75 ++++++++++------- src/seat/keyboard/mod.rs | 109 ++++++++++++------------- src/seat/keyboard/repeat.rs | 45 ++++++---- src/seat/mod.rs | 50 +++++------- src/seat/pointer/mod.rs | 86 ++++++++----------- src/seat/touch.rs | 51 ++++-------- src/shell/xdg/fallback_frame.rs | 7 +- src/shell/xdg/popup.rs | 2 +- src/subcompositor.rs | 10 ++- 16 files changed, 345 insertions(+), 386 deletions(-) diff --git a/examples/simple_window.rs b/examples/simple_window.rs index 97aaba556..4020fe22f 100644 --- a/examples/simple_window.rs +++ b/examples/simple_window.rs @@ -85,6 +85,7 @@ fn main() { seat_and_serial: None, surface: Some(window.wl_surface().clone()), app_id: Some(String::from("io.github.smithay.client-toolkit.SimpleWindow")), + udata: (), }, ) } @@ -258,9 +259,9 @@ impl WindowHandler for SimpleWindow { } impl ActivationHandler for SimpleWindow { - type RequestData = RequestData; + type RequestUdata = (); - fn new_token(&mut self, token: String, _data: &Self::RequestData) { + fn new_token(&mut self, token: String, _data: &RequestData<()>) { self.xdg_activation .as_ref() .unwrap() diff --git a/examples/themed_window.rs b/examples/themed_window.rs index 10d6fd405..6c215f9ea 100644 --- a/examples/themed_window.rs +++ b/examples/themed_window.rs @@ -387,7 +387,7 @@ impl SeatHandler for SimpleWindow { let surface = self.compositor_state.create_surface(qh); let themed_pointer = self .seat_state - .get_pointer_with_theme( + .get_pointer_with_theme::<_, ()>( qh, &seat, self.shm_state.wl_shm(), @@ -563,7 +563,7 @@ impl PointerHandler for SimpleWindow { impl SimpleWindow { fn frame_action(&mut self, pointer: &wl_pointer::WlPointer, serial: u32, action: FrameAction) { - let pointer_data = pointer.data::().unwrap(); + let pointer_data = pointer.data::>().unwrap(); let seat = pointer_data.seat(); match action { FrameAction::Close => self.exit = true, diff --git a/src/activation.rs b/src/activation.rs index 69914f031..c3109e074 100644 --- a/src/activation.rs +++ b/src/activation.rs @@ -15,7 +15,7 @@ use crate::{ /// Use a custom type implementing [`RequestDataExt`] to store more data with a token request /// e.g. to identify which request produced which token. #[derive(Debug, Clone)] -pub struct RequestData { +pub struct RequestData { /// App_id of the application requesting the token, if applicable pub app_id: Option, /// Seat and serial of the window requesting the token, if applicable. @@ -28,44 +28,17 @@ pub struct RequestData { /// *Warning*: Many compositors will issue invalid tokens for requests from /// unfocused surfaces. There is no way to detect this from the client-side. pub surface: Option, -} - -/// Data attached to a token request -pub trait RequestDataExt: Send + Sync { - /// App_id of the application requesting the token, if applicable - fn app_id(&self) -> Option<&str>; - /// Seat and serial of the window requesting the token, if applicable. - /// - /// *Warning*: Many compositors will issue invalid tokens for requests without - /// recent serials. There is no way to detect this from the client-side. - fn seat_and_serial(&self) -> Option<(&wl_seat::WlSeat, u32)>; - /// Surface of the window requesting the token, if applicable. - /// - /// *Warning*: Many compositors will issue invalid tokens for requests from - /// unfocused surfaces. There is no way to detect this from the client-side. - fn surface(&self) -> Option<&wl_surface::WlSurface>; -} - -impl RequestDataExt for RequestData { - fn app_id(&self) -> Option<&str> { - self.app_id.as_deref() - } - - fn seat_and_serial(&self) -> Option<(&wl_seat::WlSeat, u32)> { - self.seat_and_serial.as_ref().map(|(seat, serial)| (seat, *serial)) - } - fn surface(&self) -> Option<&wl_surface::WlSurface> { - self.surface.as_ref() - } + pub udata: U, } /// Handler for xdg-activation pub trait ActivationHandler: Sized { /// Data type used for requesting activation tokens - type RequestData: RequestDataExt; + // TODO: Default to `()` if default associated types are ever supported + type RequestUdata; /// A token was issued for a previous request with `data`. - fn new_token(&mut self, token: String, data: &Self::RequestData); + fn new_token(&mut self, token: String, data: &RequestData); } /// State for xdg-activation @@ -96,33 +69,21 @@ impl ActivationState { /// /// To attach custom data to the request implement [`RequestDataExt`] on a custom type /// and use [`Self::request_token_with_data`] instead. - pub fn request_token(&self, qh: &QueueHandle, request_data: RequestData) - where - D: ActivationHandler, - D: Dispatch + 'static, - { - Self::request_token_with_data::(self, qh, request_data) - } - - /// Request a token for surface activation with user data. - /// - /// To use this method you need to provide [`delegate_activation`][crate::delegate_activation] with your custom type. - /// E.g. `delegate_activation!(SimpleWindow, MyRequestData);` - pub fn request_token_with_data(&self, qh: &QueueHandle, request_data: R) + pub fn request_token(&self, qh: &QueueHandle, request_data: RequestData) where - D: ActivationHandler, - D: Dispatch + 'static, - R: RequestDataExt + 'static, + D: ActivationHandler, + D: Dispatch> + 'static, + U: Send + Sync + 'static, { let token = self.xdg_activation.get_activation_token(qh, request_data); - let data = token.data::().unwrap(); - if let Some(app_id) = data.app_id() { + let data = token.data::>().unwrap(); + if let Some(app_id) = &data.app_id { token.set_app_id(String::from(app_id)); } - if let Some((seat, serial)) = data.seat_and_serial() { - token.set_serial(serial, seat); + if let Some((seat, serial)) = &data.seat_and_serial { + token.set_serial(*serial, seat); } - if let Some(surface) = data.surface() { + if let Some(surface) = &data.surface { token.set_surface(surface); } token.commit(); @@ -151,17 +112,17 @@ impl ProvidesBoundGlobal for ActivationSt } } -impl Dispatch for ActivationState +impl Dispatch, D> + for ActivationState where - D: Dispatch - + ActivationHandler, - R: RequestDataExt, + D: Dispatch> + + ActivationHandler, { fn event( state: &mut D, _proxy: &xdg_activation_token_v1::XdgActivationTokenV1, event: ::Event, - data: &R, + data: &RequestData, _conn: &wayland_client::Connection, _qhandle: &QueueHandle, ) { @@ -174,17 +135,8 @@ where #[macro_export] macro_rules! delegate_activation { ($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => { - $crate::reexports::client::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: - [ - $crate::reexports::protocols::xdg::activation::v1::client::xdg_activation_v1::XdgActivationV1: $crate::globals::GlobalData - ] => $crate::activation::ActivationState - ); - $crate::reexports::client::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: - [ - $crate::reexports::protocols::xdg::activation::v1::client::xdg_activation_token_v1::XdgActivationTokenV1: $crate::activation::RequestData - ] => $crate::activation::ActivationState - ); - }; + $crate::delegate_activation!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty, ()); + }; ($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty, $data: ty) => { $crate::reexports::client::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [ @@ -193,7 +145,7 @@ macro_rules! delegate_activation { ); $crate::reexports::client::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [ - $crate::reexports::protocols::xdg::activation::v1::client::xdg_activation_token_v1::XdgActivationTokenV1: $data + $crate::reexports::protocols::xdg::activation::v1::client::xdg_activation_token_v1::XdgActivationTokenV1: $crate::activation::RequestData<$data> ] => $crate::activation::ActivationState ); }; diff --git a/src/compositor.rs b/src/compositor.rs index ba0f4ad34..0637f4240 100644 --- a/src/compositor.rs +++ b/src/compositor.rs @@ -77,16 +77,6 @@ pub trait CompositorHandler: Sized { ); } -pub trait SurfaceDataExt: Send + Sync { - fn surface_data(&self) -> &SurfaceData; -} - -impl SurfaceDataExt for SurfaceData { - fn surface_data(&self) -> &SurfaceData { - self - } -} - #[derive(Clone, Debug)] pub struct CompositorState { wl_compositor: wl_compositor::WlCompositor, @@ -116,27 +106,30 @@ impl CompositorState { pub fn create_surface(&self, qh: &QueueHandle) -> wl_surface::WlSurface where - D: Dispatch + 'static, + D: Dispatch> + 'static, { - self.create_surface_with_data(qh, Default::default()) + self.create_surface_with_data(qh, None, 1, ()) } pub fn create_surface_with_data( &self, qh: &QueueHandle, + parent_surface: Option, + scale_factor: i32, data: U, ) -> wl_surface::WlSurface where - D: Dispatch + 'static, - U: SurfaceDataExt + 'static, + D: Dispatch> + 'static, + U: Send + Sync + 'static, { + let data = SurfaceData::new(parent_surface, scale_factor, data); self.wl_compositor.create_surface(qh, data) } } /// Data associated with a [`WlSurface`]. #[derive(Debug)] -pub struct SurfaceData { +pub struct SurfaceData { /// The scale factor of the output with the highest scale factor. pub(crate) scale_factor: AtomicI32, @@ -147,18 +140,29 @@ pub struct SurfaceData { /// The inner mutable storage. inner: Mutex, + + udata: U, } -impl SurfaceData { +impl SurfaceData { /// Create a new surface that initially reports the given scale factor and parent. - pub fn new(parent_surface: Option, scale_factor: i32) -> Self { + pub fn new(parent_surface: Option, scale_factor: i32, udata: U) -> Self { Self { scale_factor: AtomicI32::new(scale_factor), parent_surface, inner: Default::default(), + udata, } } + pub fn data(&self) -> &U { + &self.udata + } + + pub fn data_mut(&mut self) -> &mut U { + &mut self.udata + } + /// The scale factor of the output with the highest scale factor. pub fn scale_factor(&self) -> i32 { self.scale_factor.load(Ordering::Relaxed) @@ -183,11 +187,13 @@ impl SurfaceData { } } +/* XXX impl Default for SurfaceData { fn default() -> Self { Self::new(None, 1) } } +*/ #[derive(Debug)] struct SurfaceDataInner { @@ -222,9 +228,9 @@ impl Surface { qh: &QueueHandle, ) -> Result where - D: Dispatch + 'static, + D: Dispatch> + 'static, { - Self::with_data(compositor, qh, Default::default()) + Self::with_data(compositor, qh, None, 1, ()) } pub fn with_data( @@ -233,12 +239,15 @@ impl Surface { { CompositorState::API_VERSION_MAX }, >, qh: &QueueHandle, + parent_surface: Option, + scale_factor: i32, data: U, ) -> Result where - D: Dispatch + 'static, + D: Dispatch> + 'static, U: Send + Sync + 'static, { + let data = SurfaceData::new(parent_surface, scale_factor, data); Ok(Surface(compositor.bound_global()?.create_surface(qh, data))) } @@ -262,53 +271,40 @@ impl Drop for Surface { #[macro_export] macro_rules! delegate_compositor { ($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => { - $crate::delegate_compositor!(@{ $(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty }; surface: []); - $crate::delegate_compositor!(@{ $(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty }; surface-only: $crate::compositor::SurfaceData); - }; - ($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty, surface: [$($surface: ty),*$(,)?]) => { - $crate::delegate_compositor!(@{ $(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty }; surface: [ $($surface),* ]); - }; - (@{$($ty:tt)*}; surface: []) => { - $crate::reexports::client::delegate_dispatch!($($ty)*: + $crate::reexports::client::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [ $crate::reexports::client::protocol::wl_compositor::WlCompositor: $crate::globals::GlobalData ] => $crate::compositor::CompositorState ); - $crate::reexports::client::delegate_dispatch!($($ty)*: + $crate::reexports::client::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [ $crate::reexports::client::protocol::wl_callback::WlCallback: $crate::reexports::client::protocol::wl_surface::WlSurface ] => $crate::compositor::CompositorState ); - }; - (@{$($ty:tt)*}; surface-only: $surface:ty) => { - $crate::reexports::client::delegate_dispatch!($($ty)*: + $crate::reexports::client::delegate_dispatch!(@< $( $( $lt $( : $clt $(+ $dlt )* )? ,)+ )? U: Send + Sync + 'static > $ty: [ - $crate::reexports::client::protocol::wl_surface::WlSurface: $surface + $crate::reexports::client::protocol::wl_surface::WlSurface: $crate::compositor::SurfaceData ] => $crate::compositor::CompositorState ); }; - (@$ty:tt; surface: [ $($surface:ty),+ ]) => { - $crate::delegate_compositor!(@$ty; surface: []); - $( - $crate::delegate_compositor!(@$ty; surface-only: $surface); - )* - }; } -impl Dispatch for CompositorState +impl Dispatch, D> for CompositorState where - D: Dispatch + CompositorHandler + OutputHandler + 'static, - U: SurfaceDataExt + 'static, + D: Dispatch> + + CompositorHandler + + OutputHandler + + 'static, + U: Send + Sync + 'static, { fn event( state: &mut D, surface: &wl_surface::WlSurface, event: wl_surface::Event, - data: &U, + data: &SurfaceData, conn: &Connection, qh: &QueueHandle, ) { - let data = data.surface_data(); let mut inner = data.inner.lock().unwrap(); let mut enter_or_leave_output: Option<(wl_output::WlOutput, bool)> = None; @@ -365,8 +361,7 @@ where OutputState::add_scale_watcher(state, move |state, conn, qh, _| { let id = id.clone(); if let Ok(surface) = wl_surface::WlSurface::from_id(conn, id) { - if let Some(data) = surface.data::() { - let data = data.surface_data(); + if let Some(data) = surface.data::>() { let inner = data.inner.lock().unwrap(); dispatch_surface_state_updates(state, conn, qh, &surface, data, inner); } @@ -389,11 +384,13 @@ fn dispatch_surface_state_updates( conn: &Connection, qh: &QueueHandle, surface: &WlSurface, - data: &SurfaceData, + data: &SurfaceData, mut inner: MutexGuard, ) where - D: Dispatch + CompositorHandler + OutputHandler + 'static, - U: SurfaceDataExt + 'static, + D: Dispatch> + + CompositorHandler + + OutputHandler + + 'static, { let current_scale = data.scale_factor.load(Ordering::Relaxed); let (factor, transform) = match inner diff --git a/src/data_device_manager/data_source.rs b/src/data_device_manager/data_source.rs index aa523549b..0a1bffe2e 100644 --- a/src/data_device_manager/data_source.rs +++ b/src/data_device_manager/data_source.rs @@ -10,15 +10,21 @@ use crate::reexports::client::{ use super::{data_device::DataDevice, DataDeviceManagerState, WritePipe}; #[derive(Debug, Default)] -pub struct DataSourceData {} - -pub trait DataSourceDataExt: Send + Sync { - fn data_source_data(&self) -> &DataSourceData; +pub struct DataSourceData { + udata: U, } -impl DataSourceDataExt for DataSourceData { - fn data_source_data(&self) -> &DataSourceData { - self +impl DataSourceData { + pub fn new(udata: U) -> Self { + Self { udata } + } + + pub fn data(&self) -> &U { + &self.udata + } + + pub fn data_mut(&mut self) -> &mut U { + &mut self.udata } } @@ -68,16 +74,15 @@ pub trait DataSourceHandler: Sized { ); } -impl Dispatch for DataDeviceManagerState +impl Dispatch, D> for DataDeviceManagerState where - D: Dispatch + DataSourceHandler, - U: DataSourceDataExt, + D: Dispatch> + DataSourceHandler, { fn event( state: &mut D, source: &wl_data_source::WlDataSource, event: ::Event, - _data: &U, + _data: &DataSourceData, conn: &wayland_client::Connection, qh: &wayland_client::QueueHandle, ) { diff --git a/src/data_device_manager/mod.rs b/src/data_device_manager/mod.rs index a61693ae4..2ce67a9c8 100644 --- a/src/data_device_manager/mod.rs +++ b/src/data_device_manager/mod.rs @@ -48,7 +48,7 @@ impl DataDeviceManagerState { mime_types: impl IntoIterator, ) -> CopyPasteSource where - D: Dispatch + 'static, + D: Dispatch> + 'static, { CopyPasteSource { inner: self.create_data_source(qh, mime_types, None) } } @@ -61,7 +61,7 @@ impl DataDeviceManagerState { dnd_actions: DndAction, ) -> DragSource where - D: Dispatch + 'static, + D: Dispatch> + 'static, { DragSource { inner: self.create_data_source(qh, mime_types, Some(dnd_actions)) } } @@ -74,7 +74,7 @@ impl DataDeviceManagerState { dnd_actions: Option, ) -> WlDataSource where - D: Dispatch + 'static, + D: Dispatch> + 'static, { let source = self.manager.create_data_source(qh, Default::default()); @@ -135,9 +135,9 @@ macro_rules! delegate_data_device { [ $crate::reexports::client::protocol::wl_data_offer::WlDataOffer: $crate::data_device_manager::data_offer::DataOfferData ] => $crate::data_device_manager::DataDeviceManagerState); - $crate::reexports::client::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: + $crate::reexports::client::delegate_dispatch!(@< $( $( $lt $( : $clt $(+ $dlt )* )? ,)+ )? U > $ty: [ - $crate::reexports::client::protocol::wl_data_source::WlDataSource: $crate::data_device_manager::data_source::DataSourceData + $crate::reexports::client::protocol::wl_data_source::WlDataSource: $crate::data_device_manager::data_source::DataSourceData ] => $crate::data_device_manager::DataDeviceManagerState ); $crate::reexports::client::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: diff --git a/src/seat/input_method.rs b/src/seat/input_method.rs index 6ab3b18e4..eee3f571d 100644 --- a/src/seat/input_method.rs +++ b/src/seat/input_method.rs @@ -45,13 +45,26 @@ impl InputMethodManager { /// seat. pub fn get_input_method(&self, qh: &QueueHandle, seat: &WlSeat) -> InputMethod where - State: Dispatch + 'static, + State: Dispatch, State> + 'static, + { + self.get_input_method_with_data(qh, seat, ()) + } + + pub fn get_input_method_with_data( + &self, + qh: &QueueHandle, + seat: &WlSeat, + udata: U, + ) -> InputMethod + where + State: Dispatch, State> + 'static, + U: Send + Sync + 'static, { InputMethod { input_method: self.manager.get_input_method( seat, qh, - InputMethodData::new(seat.clone()), + InputMethodData::new(seat.clone(), udata), ), } } @@ -109,23 +122,23 @@ impl InputMethod { self.input_method.delete_surrounding_text(before_length, after_length) } - pub fn commit(&self) { - let data = self.input_method.data::().unwrap(); + pub fn commit(&self) { + let data = self.input_method.data::>().unwrap(); let inner = data.inner.lock().unwrap(); self.input_method.commit(inner.serial.0) } } #[derive(Debug)] -pub struct InputMethodData { +pub struct InputMethodData { seat: WlSeat, - inner: Mutex, + udata: U, } -impl InputMethodData { +impl InputMethodData { /// Create the new input method data associated with the given seat. - pub fn new(seat: WlSeat) -> Self { + pub fn new(seat: WlSeat, udata: U) -> Self { Self { seat, inner: Mutex::new(InputMethodDataInner { @@ -133,9 +146,18 @@ impl InputMethodData { current_state: Default::default(), serial: Wrapping(0), }), + udata, } } + pub fn data(&self) -> &U { + &self.udata + } + + pub fn data_mut(&mut self) -> &mut U { + &mut self.udata + } + /// Get the associated seat from the data. pub fn seat(&self) -> &WlSeat { &self.seat @@ -246,22 +268,12 @@ macro_rules! delegate_input_method { $crate::reexports::client::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [ $crate::reexports::protocols_misc::zwp_input_method_v2::client::zwp_input_method_manager_v2::ZwpInputMethodManagerV2: $crate::globals::GlobalData ] => $crate::seat::input_method::InputMethodManager); - $crate::reexports::client::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [ - $crate::reexports::protocols_misc::zwp_input_method_v2::client::zwp_input_method_v2::ZwpInputMethodV2: $crate::seat::input_method::InputMethodData + $crate::reexports::client::delegate_dispatch!(@< $( $( $lt $( : $clt $(+ $dlt )* )? ,)+ )? U > $ty: [ + $crate::reexports::protocols_misc::zwp_input_method_v2::client::zwp_input_method_v2::ZwpInputMethodV2: $crate::seat::input_method::InputMethodData ] => $crate::seat::input_method::InputMethod); }; } -pub trait InputMethodDataExt: Send + Sync { - fn input_method_data(&self) -> &InputMethodData; -} - -impl InputMethodDataExt for InputMethodData { - fn input_method_data(&self) -> &InputMethodData { - self - } -} - pub trait InputMethodHandler: Sized { fn handle_done( &self, @@ -278,21 +290,20 @@ pub trait InputMethodHandler: Sized { ); } -impl Dispatch for InputMethod +impl Dispatch, D> for InputMethod where - D: Dispatch + InputMethodHandler, - U: InputMethodDataExt, + D: Dispatch> + InputMethodHandler, { fn event( data: &mut D, input_method: &ZwpInputMethodV2, event: zwp_input_method_v2::Event, - udata: &U, + udata: &InputMethodData, conn: &Connection, qh: &QueueHandle, ) { let mut imdata: std::sync::MutexGuard<'_, InputMethodDataInner> = - udata.input_method_data().inner.lock().unwrap(); + udata.inner.lock().unwrap(); use zwp_input_method_v2::Event; @@ -402,7 +413,7 @@ mod test { fn assert_is_delegate() where - T: wayland_client::Dispatch, + T: wayland_client::Dispatch>, { } diff --git a/src/seat/input_method_v3.rs b/src/seat/input_method_v3.rs index 4ab61537c..c90e4d64b 100644 --- a/src/seat/input_method_v3.rs +++ b/src/seat/input_method_v3.rs @@ -74,13 +74,26 @@ impl InputMethodManager { /// seat. pub fn get_input_method(&self, qh: &QueueHandle, seat: &WlSeat) -> InputMethod where - State: Dispatch + 'static, + State: Dispatch, State> + 'static, + { + self.get_input_method_with_data(qh, seat, ()) + } + + pub fn get_input_method_with_data( + &self, + qh: &QueueHandle, + seat: &WlSeat, + udata: U, + ) -> InputMethod + where + State: Dispatch, State> + 'static, + U: Send + Sync + 'static, { InputMethod { input_method: self.manager.get_input_method( seat, qh, - InputMethodData::new(seat.clone()), + InputMethodData::new(seat.clone(), udata), ), } } @@ -226,13 +239,16 @@ impl InputMethod { self.input_method.move_cursor(cursor, anchor) } - pub fn commit(&self) { - let data = self.input_method.data::().unwrap(); + pub fn commit(&self) + where + U: Send + Sync + 'static, + { + let data = self.input_method.data::>().unwrap(); let inner = &data.inner.lock().unwrap(); self.input_method.commit(inner.serial.0) } - pub fn get_input_popup_surface( + pub fn get_input_popup_surface( &self, qh: &QueueHandle, surface: impl Into, @@ -240,8 +256,9 @@ impl InputMethod { ) -> Popup where D: Dispatch + 'static, + U: Send + Sync + 'static, { - let data = self.input_method.data::().unwrap(); + let data = self.input_method.data::>().unwrap(); let surface = surface.into(); Popup { input_method: self.input_method.clone(), @@ -257,15 +274,15 @@ impl InputMethod { } #[derive(Debug)] -pub struct InputMethodData { +pub struct InputMethodData { seat: WlSeat, - inner: Arc>, + udata: U, } -impl InputMethodData { +impl InputMethodData { /// Create the new touch data associated with the given seat. - pub fn new(seat: WlSeat) -> Self { + pub fn new(seat: WlSeat, udata: U) -> Self { Self { seat, inner: Arc::new(Mutex::new(InputMethodDataInner { @@ -273,9 +290,18 @@ impl InputMethodData { current_state: Default::default(), serial: Wrapping(0), })), + udata, } } + pub fn data(&self) -> &U { + &self.udata + } + + pub fn data_mut(&mut self) -> &mut U { + &mut self.udata + } + /// Get the associated seat from the data. pub fn seat(&self) -> &WlSeat { &self.seat @@ -594,8 +620,8 @@ macro_rules! delegate_input_method_v3 { $crate::reexports::client::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [ $crate::reexports::protocols_experimental::input_method::v1::client::xx_input_method_manager_v2::XxInputMethodManagerV2: $crate::globals::GlobalData ] => $crate::seat::input_method_v3::InputMethodManager); - $crate::reexports::client::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [ - $crate::reexports::protocols_experimental::input_method::v1::client::xx_input_method_v1::XxInputMethodV1: $crate::seat::input_method_v3::InputMethodData + $crate::reexports::client::delegate_dispatch!(@< $( $( $lt $( : $clt $(+ $dlt )* )? ,)+ )? U > $ty: [ + $crate::reexports::protocols_experimental::input_method::v1::client::xx_input_method_v1::XxInputMethodV1: $crate::seat::input_method_v3::InputMethodData ] => $crate::seat::input_method_v3::InputMethod); $crate::reexports::client::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [ $crate::reexports::protocols_experimental::input_method::v1::client::xx_input_popup_surface_v2::XxInputPopupSurfaceV2: $crate::seat::input_method_v3::PopupData @@ -606,16 +632,6 @@ macro_rules! delegate_input_method_v3 { }; } -pub trait InputMethodDataExt: Send + Sync { - fn input_method_data(&self) -> &InputMethodData; -} - -impl InputMethodDataExt for InputMethodData { - fn input_method_data(&self) -> &InputMethodData { - self - } -} - pub trait InputMethodHandler: Sized { fn handle_done( &mut self, @@ -633,21 +649,19 @@ pub trait InputMethodHandler: Sized { fn handle_unavailable(&mut self, qh: &QueueHandle, input_method: &XxInputMethodV1); } -impl Dispatch for InputMethod +impl Dispatch, D> for InputMethod where - D: Dispatch + InputMethodHandler, - U: InputMethodDataExt, + D: Dispatch> + InputMethodHandler, { fn event( data: &mut D, input_method: &XxInputMethodV1, event: xx_input_method_v1::Event, - udata: &U, + udata: &InputMethodData, _conn: &Connection, qh: &QueueHandle, ) { - let mut imdata: MutexGuard<'_, InputMethodDataInner> = - udata.input_method_data().inner.lock().unwrap(); + let mut imdata: MutexGuard<'_, InputMethodDataInner> = udata.inner.lock().unwrap(); use xx_input_method_v1::Event; @@ -791,7 +805,10 @@ mod test { fn assert_is_delegate() where - T: wayland_client::Dispatch, + T: wayland_client::Dispatch< + protocol::xx_input_method_v1::XxInputMethodV1, + InputMethodData<()>, + >, { } diff --git a/src/seat/keyboard/mod.rs b/src/seat/keyboard/mod.rs index ecfaab26c..bd31045af 100644 --- a/src/seat/keyboard/mod.rs +++ b/src/seat/keyboard/mod.rs @@ -65,17 +65,24 @@ impl SeatState { rmlvo: Option, ) -> Result where - D: Dispatch> + D: Dispatch> + SeatHandler + KeyboardHandler + 'static, { let udata = match rmlvo { - Some(rmlvo) => KeyboardData::from_rmlvo(seat.clone(), rmlvo)?, - None => KeyboardData::new(seat.clone()), + Some(rmlvo) => KeyboardData::from_rmlvo(seat.clone(), rmlvo, ())?, + None => KeyboardData::new(seat.clone(), ()), }; - self.get_keyboard_with_data(qh, seat, udata) + let inner = + self.seats.iter().find(|inner| &inner.seat == seat).ok_or(SeatError::DeadObject)?; + + if !inner.data.has_keyboard.load(Ordering::SeqCst) { + return Err(SeatError::UnsupportedCapability(Capability::Keyboard).into()); + } + + Ok(seat.get_keyboard(qh, udata)) } /// Creates a keyboard from a seat. @@ -95,8 +102,11 @@ impl SeatState { udata: U, ) -> Result where - D: Dispatch + SeatHandler + KeyboardHandler + 'static, - U: KeyboardDataExt + 'static, + D: Dispatch> + + SeatHandler + + KeyboardHandler + + 'static, + U: Send + Sync + 'static, { let inner = self.seats.iter().find(|inner| &inner.seat == seat).ok_or(SeatError::DeadObject)?; @@ -105,6 +115,8 @@ impl SeatState { return Err(SeatError::UnsupportedCapability(Capability::Keyboard).into()); } + let udata = KeyboardData::new(seat.clone(), udata); + Ok(seat.get_keyboard(qh, udata)) } } @@ -338,7 +350,7 @@ pub struct RMLVO { pub options: Option, } -pub struct KeyboardData { +pub struct KeyboardData { seat: wl_seat::WlSeat, first_event: AtomicBool, xkb_context: Mutex, @@ -347,12 +359,13 @@ pub struct KeyboardData { xkb_state: Mutex>, xkb_compose: Mutex>, #[cfg(feature = "calloop")] - repeat_data: Arc>>>, + repeat_data: Arc>>>, focus: Mutex>, - _phantom_data: PhantomData, + _phantom_data: PhantomData, + udata: U, } -impl Debug for KeyboardData { +impl Debug for KeyboardData { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("KeyboardData").finish_non_exhaustive() } @@ -361,32 +374,23 @@ impl Debug for KeyboardData { #[macro_export] macro_rules! delegate_keyboard { ($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => { - $crate::reexports::client::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: + $crate::reexports::client::delegate_dispatch!(@< $( $( $lt $( : $clt $(+ $dlt )* )? ,)+ )? U > $ty: [ - $crate::reexports::client::protocol::wl_keyboard::WlKeyboard: $crate::seat::keyboard::KeyboardData<$ty> - ] => $crate::seat::SeatState - ); - }; - ($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty, keyboard: [$($udata:ty),* $(,)?]) => { - $crate::reexports::client::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: - [ - $( - $crate::reexports::client::protocol::wl_keyboard::WlKeyboard: $udata, - )* + $crate::reexports::client::protocol::wl_keyboard::WlKeyboard: $crate::seat::keyboard::KeyboardData<$ty, U> ] => $crate::seat::SeatState ); }; } // SAFETY: The state does not share state with any other rust types. -unsafe impl Send for KeyboardData {} +unsafe impl Send for KeyboardData {} // SAFETY: The state is guarded by a mutex since libxkbcommon has no internal synchronization. -unsafe impl Sync for KeyboardData {} +unsafe impl Sync for KeyboardData {} -impl KeyboardData { - pub fn new(seat: wl_seat::WlSeat) -> Self { +impl KeyboardData { + pub fn new(seat: wl_seat::WlSeat, udata: U) -> Self { let xkb_context = xkb::Context::new(xkb::CONTEXT_NO_FLAGS); - let udata = KeyboardData { + let keyboard_data = KeyboardData { seat, first_event: AtomicBool::new(false), xkb_context: Mutex::new(xkb_context), @@ -397,18 +401,31 @@ impl KeyboardData { repeat_data: Arc::new(Mutex::new(None)), focus: Mutex::new(None), _phantom_data: PhantomData, + udata, }; - udata.init_compose(); + keyboard_data.init_compose(); + + keyboard_data + } - udata + pub fn data(&mut self) -> &U { + &self.udata + } + + pub fn data_mut(&mut self) -> &U { + &self.udata } pub fn seat(&self) -> &wl_seat::WlSeat { &self.seat } - pub fn from_rmlvo(seat: wl_seat::WlSeat, rmlvo: RMLVO) -> Result { + pub fn from_rmlvo( + seat: wl_seat::WlSeat, + rmlvo: RMLVO, + udata: U, + ) -> Result { let xkb_context = xkb::Context::new(xkb::CONTEXT_NO_FLAGS); let keymap = xkb::Keymap::new_from_names( &xkb_context, @@ -426,7 +443,7 @@ impl KeyboardData { let xkb_state = Some(xkb::State::new(&keymap.unwrap())); - let udata = KeyboardData { + let keyboard_data = KeyboardData { seat, first_event: AtomicBool::new(false), xkb_context: Mutex::new(xkb_context), @@ -437,11 +454,12 @@ impl KeyboardData { repeat_data: Arc::new(Mutex::new(None)), focus: Mutex::new(None), _phantom_data: PhantomData, + udata, }; - udata.init_compose(); + keyboard_data.init_compose(); - Ok(udata) + Ok(keyboard_data) } fn init_compose(&self) { @@ -484,39 +502,18 @@ impl KeyboardData { } } -pub trait KeyboardDataExt: Send + Sync { - type State: 'static; - fn keyboard_data(&self) -> &KeyboardData; - fn keyboard_data_mut(&mut self) -> &mut KeyboardData; -} - -impl KeyboardDataExt for KeyboardData { - /// The type of the user defined state - type State = T; - fn keyboard_data(&self) -> &KeyboardData { - self - } - - fn keyboard_data_mut(&mut self) -> &mut KeyboardData { - self - } -} - -impl Dispatch for SeatState +impl Dispatch, D> for SeatState where - D: Dispatch + KeyboardHandler + 'static, - U: KeyboardDataExt, + D: Dispatch> + KeyboardHandler + 'static, { fn event( data: &mut D, keyboard: &wl_keyboard::WlKeyboard, event: wl_keyboard::Event, - udata: &U, + udata: &KeyboardData, conn: &Connection, qh: &QueueHandle, ) { - let udata = udata.keyboard_data(); - // The compositor has no way to tell clients if the seat is not version 4 or above. // In this case, send a synthetic repeat info event using the default repeat values used by the X // server. diff --git a/src/seat/keyboard/repeat.rs b/src/seat/keyboard/repeat.rs index bb09e8954..3160315f2 100644 --- a/src/seat/keyboard/repeat.rs +++ b/src/seat/keyboard/repeat.rs @@ -10,8 +10,8 @@ use wayland_client::{ }; use super::{ - Capability, KeyEvent, KeyboardData, KeyboardDataExt, KeyboardError, KeyboardHandler, - RepeatInfo, SeatError, RMLVO, + Capability, KeyEvent, KeyboardData, KeyboardError, KeyboardHandler, RepeatInfo, SeatError, + RMLVO, }; use crate::seat::SeatState; @@ -64,14 +64,30 @@ impl SeatState { callback: RepeatCallback, ) -> Result where - D: Dispatch> + KeyboardHandler + 'static, + D: Dispatch> + KeyboardHandler + 'static, { let udata = match rmlvo { - Some(rmlvo) => KeyboardData::from_rmlvo(seat.clone(), rmlvo)?, - None => KeyboardData::new(seat.clone()), + Some(rmlvo) => KeyboardData::from_rmlvo(seat.clone(), rmlvo, ())?, + None => KeyboardData::new(seat.clone(), ()), }; - self.get_keyboard_with_repeat_with_data(qh, seat, udata, loop_handle, callback) + let inner = + self.seats.iter().find(|inner| &inner.seat == seat).ok_or(SeatError::DeadObject)?; + + if !inner.data.has_keyboard.load(Ordering::SeqCst) { + return Err(SeatError::UnsupportedCapability(Capability::Keyboard).into()); + } + + udata.repeat_data.lock().unwrap().replace(RepeatData { + current_repeat: None, + repeat_info: RepeatInfo::Disable, + loop_handle: loop_handle.clone(), + callback, + repeat_token: None, + }); + udata.init_compose(); + + Ok(seat.get_keyboard(qh, udata)) } /// Creates a keyboard from a seat. @@ -92,13 +108,13 @@ impl SeatState { &mut self, qh: &QueueHandle, seat: &wl_seat::WlSeat, - mut udata: U, - loop_handle: LoopHandle<'static, ::State>, - callback: RepeatCallback<::State>, + udata: U, + loop_handle: LoopHandle<'static, D>, + callback: RepeatCallback, ) -> Result where - D: Dispatch + KeyboardHandler + 'static, - U: KeyboardDataExt + 'static, + D: Dispatch> + KeyboardHandler + 'static, + U: Send + Sync + 'static, { let inner = self.seats.iter().find(|inner| &inner.seat == seat).ok_or(SeatError::DeadObject)?; @@ -107,15 +123,16 @@ impl SeatState { return Err(SeatError::UnsupportedCapability(Capability::Keyboard).into()); } - let kbd_data = udata.keyboard_data_mut(); - kbd_data.repeat_data.lock().unwrap().replace(RepeatData { + let udata = KeyboardData::new(seat.clone(), udata); + + udata.repeat_data.lock().unwrap().replace(RepeatData { current_repeat: None, repeat_info: RepeatInfo::Disable, loop_handle: loop_handle.clone(), callback, repeat_token: None, }); - kbd_data.init_compose(); + udata.init_compose(); Ok(seat.get_keyboard(qh, udata)) } diff --git a/src/seat/mod.rs b/src/seat/mod.rs index 82764025c..063532fa4 100644 --- a/src/seat/mod.rs +++ b/src/seat/mod.rs @@ -15,7 +15,7 @@ use crate::reexports::client::{ use crate::reexports::protocols::wp::cursor_shape::v1::client::wp_cursor_shape_device_v1::WpCursorShapeDeviceV1; use crate::reexports::protocols::wp::cursor_shape::v1::client::wp_cursor_shape_manager_v1::WpCursorShapeManagerV1; use crate::{ - compositor::SurfaceDataExt, + compositor::SurfaceData, globals::GlobalData, registry::{ProvidesRegistryState, RegistryHandler}, }; @@ -31,8 +31,8 @@ pub mod relative_pointer; pub mod touch; use pointer::cursor_shape::CursorShapeManager; -use pointer::{PointerData, PointerDataExt, PointerHandler, ThemeSpec, ThemedPointer, Themes}; -use touch::{TouchData, TouchDataExt, TouchHandler}; +use pointer::{PointerData, PointerHandler, ThemeSpec, ThemedPointer, Themes}; +use touch::{TouchData, TouchHandler}; #[non_exhaustive] #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -152,9 +152,9 @@ impl SeatState { seat: &wl_seat::WlSeat, ) -> Result where - D: Dispatch + PointerHandler + 'static, + D: Dispatch> + PointerHandler + 'static, { - self.get_pointer_with_data(qh, seat, PointerData::new(seat.clone())) + self.get_pointer_with_data(qh, seat, ()) } /// Creates a pointer from a seat with the provided theme. @@ -171,24 +171,16 @@ impl SeatState { shm: &wl_shm::WlShm, surface: wl_surface::WlSurface, theme: ThemeSpec, - ) -> Result, SeatError> + ) -> Result, SeatError> where - D: Dispatch - + Dispatch + D: Dispatch> + + Dispatch> + Dispatch + Dispatch + PointerHandler + 'static, - S: SurfaceDataExt + 'static, { - self.get_pointer_with_theme_and_data( - qh, - seat, - shm, - surface, - theme, - PointerData::new(seat.clone()), - ) + self.get_pointer_with_theme_and_data(qh, seat, shm, surface, theme, ()) } /// Creates a pointer from a seat. @@ -203,8 +195,8 @@ impl SeatState { pointer_data: U, ) -> Result where - D: Dispatch + PointerHandler + 'static, - U: PointerDataExt + 'static, + D: Dispatch> + PointerHandler + 'static, + U: Send + Sync + 'static, { let inner = self.seats.iter().find(|inner| &inner.seat == seat).ok_or(SeatError::DeadObject)?; @@ -213,6 +205,7 @@ impl SeatState { return Err(SeatError::UnsupportedCapability(Capability::Pointer)); } + let pointer_data = PointerData::new(seat.clone(), pointer_data); Ok(seat.get_pointer(qh, pointer_data)) } @@ -231,14 +224,13 @@ impl SeatState { pointer_data: U, ) -> Result, SeatError> where - D: Dispatch - + Dispatch + D: Dispatch> + + Dispatch> + Dispatch + Dispatch + PointerHandler + 'static, - S: SurfaceDataExt + 'static, - U: PointerDataExt + 'static, + U: Send + Sync + 'static, { let inner = self.seats.iter().find(|inner| &inner.seat == seat).ok_or(SeatError::DeadObject)?; @@ -247,6 +239,7 @@ impl SeatState { return Err(SeatError::UnsupportedCapability(Capability::Pointer)); } + let pointer_data = PointerData::new(seat.clone(), pointer_data); let wl_ptr = seat.get_pointer(qh, pointer_data); if let CursorShapeManagerState::Pending { registry, global } = @@ -295,9 +288,9 @@ impl SeatState { seat: &wl_seat::WlSeat, ) -> Result where - D: Dispatch + TouchHandler + 'static, + D: Dispatch> + TouchHandler + 'static, { - self.get_touch_with_data(qh, seat, TouchData::new(seat.clone())) + self.get_touch_with_data(qh, seat, ()) } /// Creates a touch handle from a seat. @@ -312,8 +305,8 @@ impl SeatState { udata: U, ) -> Result where - D: Dispatch + TouchHandler + 'static, - U: TouchDataExt + 'static, + D: Dispatch> + TouchHandler + 'static, + U: Send + Sync + 'static, { let inner = self.seats.iter().find(|inner| &inner.seat == seat).ok_or(SeatError::DeadObject)?; @@ -322,7 +315,8 @@ impl SeatState { return Err(SeatError::UnsupportedCapability(Capability::Touch)); } - Ok(seat.get_touch(qh, udata)) + let data = TouchData::new(seat.clone(), udata); + Ok(seat.get_touch(qh, data)) } } diff --git a/src/seat/pointer/mod.rs b/src/seat/pointer/mod.rs index 137ec0acc..4a8086b70 100644 --- a/src/seat/pointer/mod.rs +++ b/src/seat/pointer/mod.rs @@ -17,10 +17,7 @@ use wayland_client::{ use wayland_cursor::{Cursor, CursorTheme}; use wayland_protocols::wp::cursor_shape::v1::client::wp_cursor_shape_device_v1::WpCursorShapeDeviceV1; -use crate::{ - compositor::{SurfaceData, SurfaceDataExt}, - error::GlobalError, -}; +use crate::{compositor::SurfaceData, error::GlobalError}; use super::SeatState; @@ -158,14 +155,23 @@ pub trait PointerHandler: Sized { } #[derive(Debug)] -pub struct PointerData { +pub struct PointerData { seat: WlSeat, pub(crate) inner: Mutex, + udata: U, } -impl PointerData { - pub fn new(seat: WlSeat) -> Self { - Self { seat, inner: Default::default() } +impl PointerData { + pub fn new(seat: WlSeat, udata: U) -> Self { + Self { seat, inner: Default::default(), udata } + } + + pub fn data(&self) -> &U { + &self.udata + } + + pub fn data_mut(&mut self) -> &mut U { + &mut self.udata } /// The seat associated with this pointer. @@ -185,48 +191,25 @@ impl PointerData { } } -pub trait PointerDataExt: Send + Sync { - fn pointer_data(&self) -> &PointerData; -} - -impl PointerDataExt for PointerData { - fn pointer_data(&self) -> &PointerData { - self - } -} - #[macro_export] macro_rules! delegate_pointer { ($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => { - $crate::delegate_pointer!(@{ $(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty }; pointer: []); - $crate::delegate_pointer!(@{ $(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty }; pointer-only: $crate::seat::pointer::PointerData); - }; - ($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty, pointer: [$($pointer_data:ty),* $(,)?]) => { - $crate::delegate_pointer!(@{ $(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty }; pointer: [ $($pointer_data),* ]); - }; - (@{$($ty:tt)*}; pointer: []) => { - $crate::reexports::client::delegate_dispatch!($($ty)*: + $crate::reexports::client::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [ $crate::reexports::protocols::wp::cursor_shape::v1::client::wp_cursor_shape_manager_v1::WpCursorShapeManagerV1: $crate::globals::GlobalData ] => $crate::seat::pointer::cursor_shape::CursorShapeManager ); - $crate::reexports::client::delegate_dispatch!($($ty)*: + $crate::reexports::client::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [ $crate::reexports::protocols::wp::cursor_shape::v1::client::wp_cursor_shape_device_v1::WpCursorShapeDeviceV1: $crate::globals::GlobalData ] => $crate::seat::pointer::cursor_shape::CursorShapeManager ); - }; - (@{$($ty:tt)*}; pointer-only: $pointer_data:ty) => { - $crate::reexports::client::delegate_dispatch!($($ty)*: + $crate::reexports::client::delegate_dispatch!(@< $( $( $lt $( : $clt $(+ $dlt )* )? ,)+ )? U: Send + Sync + 'static > $ty: [ - $crate::reexports::client::protocol::wl_pointer::WlPointer: $pointer_data + $crate::reexports::client::protocol::wl_pointer::WlPointer: $crate::seat::pointer::PointerData ] => $crate::seat::SeatState ); }; - (@$ty:tt; pointer: [$($pointer:ty),*]) => { - $crate::delegate_pointer!(@$ty; pointer: []); - $( $crate::delegate_pointer!(@$ty; pointer-only: $pointer); )* - } } #[derive(Debug, Default)] @@ -246,20 +229,19 @@ pub(crate) struct PointerDataInner { pub(crate) latest_btn: Option, } -impl Dispatch for SeatState +impl Dispatch, D> for SeatState where - D: Dispatch + PointerHandler, - U: PointerDataExt, + D: Dispatch> + PointerHandler, + U: Send + Sync + 'static, { fn event( data: &mut D, pointer: &WlPointer, event: wl_pointer::Event, - udata: &U, + udata: &PointerData, conn: &Connection, qh: &QueueHandle, ) { - let udata = udata.pointer_data(); let mut guard = udata.inner.lock().unwrap(); let mut leave_surface = None; let kind = match event { @@ -501,7 +483,7 @@ where /// Pointer themeing #[derive(Debug)] -pub struct ThemedPointer { +pub struct ThemedPointer { pub(super) themes: Arc>, /// The underlying wl_pointer. pub(super) pointer: WlPointer, @@ -513,19 +495,17 @@ pub struct ThemedPointer { pub(super) _surface_data: std::marker::PhantomData, } -impl ThemedPointer { +impl ThemedPointer { /// Set the cursor to the given [`CursorIcon`]. /// /// The cursor icon should be reloaded on every [`PointerEventKind::Enter`] event. pub fn set_cursor(&self, conn: &Connection, icon: CursorIcon) -> Result<(), PointerThemeError> { - let serial = match self - .pointer - .data::() - .and_then(|data| data.pointer_data().latest_enter_serial()) - { - Some(serial) => serial, - None => return Err(PointerThemeError::MissingEnterSerial), - }; + let serial = + match self.pointer.data::>().and_then(|data| data.latest_enter_serial()) + { + Some(serial) => serial, + None => return Err(PointerThemeError::MissingEnterSerial), + }; if let Some(shape_device) = self.shape_device.as_ref() { shape_device.set_shape(serial, cursor_icon_to_shape(icon, shape_device.version())); @@ -545,7 +525,7 @@ impl ThemedPointer Result<(), PointerThemeError> { let mut themes = self.themes.lock().unwrap(); - let scale = self.surface.data::().unwrap().surface_data().scale_factor(); + let scale = self.surface.data::>().unwrap().scale_factor(); for cursor_icon_name in iter::once(&icon.name()).chain(icon.alt_names().iter()) { if let Some(cursor) = themes .get_cursor(conn, cursor_icon_name, scale as u32, &self.shm) @@ -587,8 +567,8 @@ impl ThemedPointer