Skip to content

Commit 63ae0c3

Browse files
authored
test_client: Introduce pointer constraint test client (#1891)
related: #1890
1 parent 0cd72d1 commit 63ae0c3

3 files changed

Lines changed: 428 additions & 63 deletions

File tree

Lines changed: 343 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,343 @@
1+
//! Constrain the pointer to surface region
2+
3+
use smithay_client_toolkit::{
4+
compositor::{CompositorHandler, CompositorState},
5+
delegate_compositor, delegate_output, delegate_pointer, delegate_pointer_constraints, delegate_registry,
6+
delegate_seat, delegate_shm, delegate_xdg_shell, delegate_xdg_window,
7+
output::{OutputHandler, OutputState},
8+
reexports::{
9+
calloop, client as wayland_client,
10+
protocols::wp::pointer_constraints::zv1::client::{
11+
zwp_confined_pointer_v1::ZwpConfinedPointerV1, zwp_locked_pointer_v1::ZwpLockedPointerV1,
12+
zwp_pointer_constraints_v1,
13+
},
14+
},
15+
registry::{ProvidesRegistryState, RegistryState},
16+
registry_handlers,
17+
seat::{
18+
pointer::{PointerEvent, PointerEventKind, PointerHandler},
19+
pointer_constraints::{PointerConstraintsHandler, PointerConstraintsState},
20+
Capability, SeatHandler, SeatState,
21+
},
22+
shell::{
23+
xdg::{
24+
window::{Window, WindowConfigure, WindowDecorations, WindowHandler},
25+
XdgShell,
26+
},
27+
WaylandSurface,
28+
},
29+
shm::{
30+
slot::{Buffer, SlotPool},
31+
Shm, ShmHandler,
32+
},
33+
};
34+
35+
use wayland_client::{
36+
delegate_noop,
37+
protocol::{
38+
wl_output::{self, WlOutput},
39+
wl_pointer::WlPointer,
40+
wl_region::WlRegion,
41+
wl_seat,
42+
wl_surface::{self, WlSurface},
43+
},
44+
Connection, QueueHandle,
45+
};
46+
47+
use tracing::{info, warn};
48+
49+
fn main() {
50+
test_clients::init_logging();
51+
52+
let (mut event_loop, globals, qh) = test_clients::init_connection::<App>();
53+
54+
let compositor_state = CompositorState::bind(&globals, &qh).unwrap();
55+
let xdg_shell = XdgShell::bind(&globals, &qh).unwrap();
56+
57+
let surface = compositor_state.create_surface(&qh);
58+
let window = xdg_shell.create_window(surface, WindowDecorations::RequestServer, &qh);
59+
60+
let shm = Shm::bind(&globals, &qh).unwrap();
61+
let pool = SlotPool::new(256 * 256 * 4, &shm).unwrap();
62+
63+
let mut simple_window = App {
64+
registry_state: RegistryState::new(&globals),
65+
output_state: OutputState::new(&globals, &qh),
66+
compositor_state,
67+
seat_state: SeatState::new(&globals, &qh),
68+
shm,
69+
pointer: None,
70+
confined_pointer: None,
71+
pointer_constraint_state: PointerConstraintsState::bind(&globals, &qh),
72+
73+
should_be_mapped: false,
74+
75+
first_configure: true,
76+
pool,
77+
width: 256,
78+
height: 256,
79+
shift: 0,
80+
buffer: None,
81+
window,
82+
loop_signal: event_loop.get_signal(),
83+
};
84+
85+
simple_window.map();
86+
87+
event_loop.run(None, &mut simple_window, |_| {}).unwrap();
88+
}
89+
90+
struct App {
91+
registry_state: RegistryState,
92+
output_state: OutputState,
93+
compositor_state: CompositorState,
94+
seat_state: SeatState,
95+
shm: Shm,
96+
97+
pointer: Option<WlPointer>,
98+
confined_pointer: Option<ZwpConfinedPointerV1>,
99+
pointer_constraint_state: PointerConstraintsState,
100+
101+
should_be_mapped: bool,
102+
103+
first_configure: bool,
104+
pool: SlotPool,
105+
width: u32,
106+
height: u32,
107+
shift: u32,
108+
buffer: Option<Buffer>,
109+
window: Window,
110+
loop_signal: calloop::LoopSignal,
111+
}
112+
113+
impl CompositorHandler for App {
114+
fn frame(
115+
&mut self,
116+
conn: &Connection,
117+
qh: &QueueHandle<Self>,
118+
_surface: &wl_surface::WlSurface,
119+
_time: u32,
120+
) {
121+
self.draw(conn, qh);
122+
}
123+
fn surface_enter(&mut self, _: &Connection, _: &QueueHandle<Self>, _: &WlSurface, _: &WlOutput) {}
124+
fn surface_leave(&mut self, _: &Connection, _: &QueueHandle<Self>, _: &WlSurface, _: &WlOutput) {}
125+
fn scale_factor_changed(&mut self, _: &Connection, _: &QueueHandle<Self>, _: &WlSurface, _: i32) {}
126+
fn transform_changed(
127+
&mut self,
128+
_: &Connection,
129+
_: &QueueHandle<Self>,
130+
_: &WlSurface,
131+
_: wl_output::Transform,
132+
) {
133+
}
134+
}
135+
136+
impl WindowHandler for App {
137+
fn request_close(&mut self, _: &Connection, _: &QueueHandle<Self>, _: &Window) {
138+
self.loop_signal.stop();
139+
}
140+
141+
fn configure(
142+
&mut self,
143+
conn: &Connection,
144+
qh: &QueueHandle<Self>,
145+
_window: &Window,
146+
configure: WindowConfigure,
147+
_serial: u32,
148+
) {
149+
self.buffer = None;
150+
self.width = configure.new_size.0.map(|v| v.get()).unwrap_or(256);
151+
self.height = configure.new_size.1.map(|v| v.get()).unwrap_or(256);
152+
153+
if self.first_configure {
154+
self.first_configure = false;
155+
self.draw(conn, qh);
156+
}
157+
}
158+
}
159+
160+
impl App {
161+
fn map(&mut self) {
162+
self.first_configure = true;
163+
self.should_be_mapped = true;
164+
self.window.commit();
165+
}
166+
167+
fn draw(&mut self, _conn: &Connection, qh: &QueueHandle<Self>) {
168+
if !self.should_be_mapped {
169+
return;
170+
}
171+
172+
test_clients::draw(
173+
qh,
174+
&self.window,
175+
&mut self.pool,
176+
&mut self.buffer,
177+
self.width,
178+
self.height,
179+
&mut self.shift,
180+
);
181+
}
182+
}
183+
184+
delegate_compositor!(App);
185+
delegate_output!(App);
186+
delegate_shm!(App);
187+
188+
delegate_xdg_shell!(App);
189+
delegate_xdg_window!(App);
190+
191+
delegate_registry!(App);
192+
delegate_seat!(App);
193+
delegate_pointer!(App);
194+
delegate_pointer_constraints!(App);
195+
delegate_noop!(App: WlRegion);
196+
197+
impl SeatHandler for App {
198+
fn seat_state(&mut self) -> &mut SeatState {
199+
&mut self.seat_state
200+
}
201+
202+
fn new_seat(&mut self, _: &Connection, _: &QueueHandle<Self>, _: wl_seat::WlSeat) {}
203+
204+
fn new_capability(
205+
&mut self,
206+
_conn: &Connection,
207+
qh: &QueueHandle<Self>,
208+
seat: wl_seat::WlSeat,
209+
capability: Capability,
210+
) {
211+
info!("add capability: {capability}");
212+
if capability == Capability::Pointer && self.pointer.is_none() {
213+
let pointer = self
214+
.seat_state
215+
.get_pointer(qh, &seat)
216+
.expect("Failed to create pointer");
217+
218+
let region = self.compositor_state.wl_compositor().create_region(qh, ());
219+
region.add(0, 0, 64, 64);
220+
221+
let confined_pointer = self
222+
.pointer_constraint_state
223+
.confine_pointer(
224+
self.window.wl_surface(),
225+
&pointer,
226+
Some(&region),
227+
zwp_pointer_constraints_v1::Lifetime::Persistent,
228+
qh,
229+
)
230+
.unwrap();
231+
232+
self.pointer = Some(pointer);
233+
self.confined_pointer = Some(confined_pointer);
234+
}
235+
}
236+
237+
fn remove_capability(
238+
&mut self,
239+
_conn: &Connection,
240+
_: &QueueHandle<Self>,
241+
_: wl_seat::WlSeat,
242+
capability: Capability,
243+
) {
244+
warn!("remove capability: {capability}");
245+
if capability == Capability::Pointer && self.pointer.is_some() {
246+
self.confined_pointer.take().unwrap().destroy();
247+
self.pointer.take().unwrap().release();
248+
}
249+
}
250+
251+
fn remove_seat(&mut self, _: &Connection, _: &QueueHandle<Self>, _: wl_seat::WlSeat) {}
252+
}
253+
254+
impl PointerHandler for App {
255+
fn pointer_frame(
256+
&mut self,
257+
_conn: &Connection,
258+
_qh: &QueueHandle<Self>,
259+
_pointer: &WlPointer,
260+
events: &[PointerEvent],
261+
) {
262+
for event in events {
263+
match event.kind {
264+
PointerEventKind::Enter { .. } => {
265+
info!("Pointer entered @{:?}", event.position);
266+
}
267+
PointerEventKind::Leave { .. } => {
268+
info!("Pointer left");
269+
}
270+
PointerEventKind::Motion { .. } => {
271+
info!("Pointer motion: {:?}", event.position);
272+
}
273+
_ => {}
274+
}
275+
}
276+
}
277+
}
278+
279+
impl PointerConstraintsHandler for App {
280+
fn confined(
281+
&mut self,
282+
_conn: &Connection,
283+
_qh: &QueueHandle<Self>,
284+
_confined_pointer: &ZwpConfinedPointerV1,
285+
_surface: &WlSurface,
286+
_pointer: &WlPointer,
287+
) {
288+
info!("Pointer confined");
289+
}
290+
291+
fn unconfined(
292+
&mut self,
293+
_conn: &Connection,
294+
_qh: &QueueHandle<Self>,
295+
_confined_pointer: &ZwpConfinedPointerV1,
296+
_surface: &WlSurface,
297+
_pointer: &WlPointer,
298+
) {
299+
warn!("Pointer unconfined");
300+
}
301+
302+
fn locked(
303+
&mut self,
304+
_conn: &Connection,
305+
_qh: &QueueHandle<Self>,
306+
_locked_pointer: &ZwpLockedPointerV1,
307+
_surface: &WlSurface,
308+
_pointer: &WlPointer,
309+
) {
310+
}
311+
312+
fn unlocked(
313+
&mut self,
314+
_conn: &Connection,
315+
_qh: &QueueHandle<Self>,
316+
_locked_pointer: &ZwpLockedPointerV1,
317+
_surface: &WlSurface,
318+
_pointer: &WlPointer,
319+
) {
320+
}
321+
}
322+
323+
impl OutputHandler for App {
324+
fn output_state(&mut self) -> &mut OutputState {
325+
&mut self.output_state
326+
}
327+
fn new_output(&mut self, _: &Connection, _: &QueueHandle<Self>, _: WlOutput) {}
328+
fn update_output(&mut self, _: &Connection, _: &QueueHandle<Self>, _: WlOutput) {}
329+
fn output_destroyed(&mut self, _: &Connection, _: &QueueHandle<Self>, _: WlOutput) {}
330+
}
331+
332+
impl ShmHandler for App {
333+
fn shm_state(&mut self) -> &mut Shm {
334+
&mut self.shm
335+
}
336+
}
337+
338+
impl ProvidesRegistryState for App {
339+
fn registry(&mut self) -> &mut RegistryState {
340+
&mut self.registry_state
341+
}
342+
registry_handlers![OutputState,];
343+
}

0 commit comments

Comments
 (0)