Skip to content

Commit a92540d

Browse files
authored
Implement pointer-warp-v1 protocol
1 parent 1c962f9 commit a92540d

File tree

3 files changed

+199
-1
lines changed

3 files changed

+199
-1
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ udev = { version = "0.9.0", optional = true }
5656
wayland-client = { version = "0.31.10", optional = true }
5757
wayland-cursor = { version = "0.31.10", optional = true }
5858
wayland-egl = { version = "0.32.7", optional = true }
59-
wayland-protocols = { version = "0.32.8", features = ["unstable", "staging", "server"], optional = true }
59+
wayland-protocols = { version = "0.32.9", features = ["unstable", "staging", "server"], optional = true }
6060
wayland-protocols-wlr = { version = "0.3.8", features = ["server"], optional = true }
6161
wayland-protocols-misc = { version = "0.3.8", features = ["server"], optional = true }
6262
wayland-server = { version = "0.31.9", optional = true }

src/wayland/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ pub mod keyboard_shortcuts_inhibit;
6868
pub mod output;
6969
pub mod pointer_constraints;
7070
pub mod pointer_gestures;
71+
pub mod pointer_warp;
7172
pub mod presentation;
7273
pub mod relative_pointer;
7374
pub mod seat;

src/wayland/pointer_warp.rs

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
//! Wp Pointer Warp
2+
//!
3+
//! This global interface allows applications to request the pointer to be moved to a position
4+
//! relative to a wl_surface.
5+
//!
6+
//! In order to advertise pointer warp global call [PointerWarpManager::new] and delegate
7+
//! events to it with [`delegate_pointer_warp`](crate::delegate_pointer_warp).
8+
//!
9+
//! ```
10+
//! use smithay::wayland::pointer_warp::{PointerWarpManager, PointerWarpHandler};
11+
//! use wayland_server::protocol::wl_surface::WlSurface;
12+
//! use wayland_server::protocol::wl_pointer::WlPointer;
13+
//! use smithay::delegate_pointer_warp;
14+
//! use smithay::utils::{Serial, Logical, Point};
15+
//!
16+
//! # struct State;
17+
//! # let mut display = wayland_server::Display::<State>::new().unwrap();
18+
//! #
19+
//! # use smithay::wayland::compositor::{CompositorHandler, CompositorState, CompositorClientState};
20+
//! # use smithay::reexports::wayland_server::Client;
21+
//! # impl CompositorHandler for State {
22+
//! # fn compositor_state(&mut self) -> &mut CompositorState { unimplemented!() }
23+
//! # fn client_compositor_state<'a>(&self, client: &'a Client) -> &'a CompositorClientState { unimplemented!() }
24+
//! # fn commit(&mut self, surface: &WlSurface) {}
25+
//! # }
26+
//! # smithay::delegate_compositor!(State);
27+
//! #
28+
//! # impl smithay::input::SeatHandler for State {
29+
//! # type KeyboardFocus = WlSurface;
30+
//! # type PointerFocus = WlSurface;
31+
//! # type TouchFocus = WlSurface;
32+
//! # fn seat_state(&mut self) -> &mut smithay::input::SeatState<Self> {
33+
//! # todo!()
34+
//! # }
35+
//! # }
36+
//! # smithay::delegate_seat!(State);
37+
//!
38+
//! PointerWarpManager::new::<State>(
39+
//! &display.handle(),
40+
//! );
41+
//!
42+
//! impl PointerWarpHandler for State {
43+
//! fn warp_pointer(&mut self, surface: WlSurface, pointer: WlPointer, pos: Point<f64, Logical>, serial: Serial) {
44+
//! // Pointer warp was requested by the client
45+
//! }
46+
//! }
47+
//!
48+
//! delegate_pointer_warp!(State);
49+
//! ```
50+
51+
use std::sync::atomic::Ordering;
52+
53+
use wayland_protocols::wp::pointer_warp::v1::server::wp_pointer_warp_v1::{self, WpPointerWarpV1};
54+
use wayland_server::{
55+
backend::GlobalId,
56+
protocol::{wl_pointer::WlPointer, wl_surface::WlSurface},
57+
Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New, Resource,
58+
};
59+
60+
use crate::{
61+
input::SeatHandler,
62+
utils::{Client as ClientCords, Logical, Point, Serial},
63+
wayland::seat::PointerUserData,
64+
};
65+
66+
/// Handler trait for pointer warp events.
67+
pub trait PointerWarpHandler:
68+
SeatHandler + GlobalDispatch<WpPointerWarpV1, ()> + Dispatch<WpPointerWarpV1, ()> + 'static
69+
{
70+
/// Request the compositor to move the pointer to a surface-local position.
71+
/// Whether or not the compositor honors the request is implementation defined, but it should
72+
/// - honor it if the surface has pointer focus, including when it has an implicit pointer grab
73+
/// - reject it if the enter serial is incorrect
74+
/// - reject it if the requested position is outside of the surface
75+
///
76+
/// Note that the enter serial is valid for any surface of the client, and does not have to be from the surface the pointer is warped to.
77+
///
78+
/// * `serial` - serial number of the surface enter event
79+
#[allow(unused)]
80+
fn warp_pointer(
81+
&mut self,
82+
surface: WlSurface,
83+
pointer: WlPointer,
84+
pos: Point<f64, Logical>,
85+
serial: Serial,
86+
) {
87+
}
88+
}
89+
90+
/// Delegate type for handling pointer warp events.
91+
#[derive(Debug)]
92+
pub struct PointerWarpManager {
93+
global: GlobalId,
94+
}
95+
96+
impl PointerWarpManager {
97+
/// Creates a new delegate type for handling [WpPointerWarpV1] events.
98+
pub fn new<D: PointerWarpHandler>(display: &DisplayHandle) -> Self {
99+
let global = display.create_global::<D, WpPointerWarpV1, _>(1, ());
100+
Self { global }
101+
}
102+
103+
/// Returns the [WpPointerWarpV1] global id.
104+
pub fn global(&self) -> GlobalId {
105+
self.global.clone()
106+
}
107+
}
108+
109+
impl<D: PointerWarpHandler> GlobalDispatch<WpPointerWarpV1, (), D> for PointerWarpManager {
110+
fn bind(
111+
_state: &mut D,
112+
_handle: &DisplayHandle,
113+
_client: &Client,
114+
resource: New<WpPointerWarpV1>,
115+
_global_data: &(),
116+
data_init: &mut DataInit<'_, D>,
117+
) {
118+
data_init.init(resource, ());
119+
}
120+
}
121+
122+
impl<D: PointerWarpHandler> Dispatch<WpPointerWarpV1, (), D> for PointerWarpManager {
123+
fn request(
124+
state: &mut D,
125+
_client: &Client,
126+
_resource: &WpPointerWarpV1,
127+
request: wp_pointer_warp_v1::Request,
128+
_data: &(),
129+
_dhandle: &DisplayHandle,
130+
_data_init: &mut DataInit<'_, D>,
131+
) {
132+
use wp_pointer_warp_v1::Request;
133+
134+
match request {
135+
Request::WarpPointer {
136+
surface,
137+
pointer,
138+
x,
139+
y,
140+
serial,
141+
} => {
142+
let client_scale = pointer
143+
.data::<PointerUserData<D>>()
144+
.unwrap()
145+
.client_scale
146+
.load(Ordering::Acquire);
147+
let location: Point<f64, ClientCords> = Point::new(x, y);
148+
let location = location.to_logical(client_scale);
149+
150+
state.warp_pointer(surface, pointer, location, Serial::from(serial));
151+
}
152+
Request::Destroy => {}
153+
_ => unreachable!(),
154+
}
155+
}
156+
}
157+
158+
/// Macro to delegate implementation of the pointer warp protocol to [`PointerWarpManager`].
159+
///
160+
/// You must also implement [`PointerWarpHandler`] to use this.
161+
#[macro_export]
162+
macro_rules! delegate_pointer_warp {
163+
($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => {
164+
$crate::reexports::wayland_server::delegate_global_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
165+
$crate::reexports::wayland_protocols::wp::pointer_warp::v1::server::wp_pointer_warp_v1::WpPointerWarpV1: ()
166+
] => $crate::wayland::pointer_warp::PointerWarpManager);
167+
168+
$crate::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
169+
$crate::reexports::wayland_protocols::wp::pointer_warp::v1::server::wp_pointer_warp_v1::WpPointerWarpV1: ()
170+
] => $crate::wayland::pointer_warp::PointerWarpManager);
171+
};
172+
}
173+
174+
#[cfg(test)]
175+
mod tests {
176+
use super::*;
177+
178+
#[test]
179+
fn delegate_pointer_warp_macro() {
180+
struct State;
181+
delegate_pointer_warp!(State);
182+
183+
impl SeatHandler for State {
184+
type KeyboardFocus = WlSurface;
185+
type PointerFocus = WlSurface;
186+
type TouchFocus = WlSurface;
187+
fn seat_state(&mut self) -> &mut crate::input::SeatState<Self> {
188+
todo!()
189+
}
190+
}
191+
192+
// `PointerWarpHandler` can only be implemented if the macro works
193+
impl PointerWarpHandler for State {}
194+
fn is_delegated<T: PointerWarpHandler>() {}
195+
is_delegated::<State>();
196+
}
197+
}

0 commit comments

Comments
 (0)