1//! Seat handling.
2
3use std::sync::Arc;
4
5use ahash::AHashMap;
6
7use sctk::reexports::client::backend::ObjectId;
8use sctk::reexports::client::protocol::wl_seat::WlSeat;
9use sctk::reexports::client::protocol::wl_touch::WlTouch;
10use sctk::reexports::client::{Connection, Proxy, QueueHandle};
11use sctk::reexports::protocols::wp::relative_pointer::zv1::client::zwp_relative_pointer_v1::ZwpRelativePointerV1;
12use sctk::reexports::protocols::wp::text_input::zv3::client::zwp_text_input_v3::ZwpTextInputV3;
13
14use sctk::seat::pointer::{ThemeSpec, ThemedPointer};
15use sctk::seat::{Capability as SeatCapability, SeatHandler, SeatState};
16
17use crate::event::WindowEvent;
18use crate::keyboard::ModifiersState;
19use crate::platform_impl::wayland::state::WinitState;
20
21mod keyboard;
22mod pointer;
23mod text_input;
24mod touch;
25
26pub use pointer::relative_pointer::RelativePointerState;
27pub use pointer::{PointerConstraintsState, WinitPointerData, WinitPointerDataExt};
28pub use text_input::{TextInputState, ZwpTextInputV3Ext};
29
30use keyboard::{KeyboardData, KeyboardState};
31use text_input::TextInputData;
32use touch::TouchPoint;
33
34#[derive(Debug, Default)]
35pub struct WinitSeatState {
36 /// The pointer bound on the seat.
37 pointer: Option<Arc<ThemedPointer<WinitPointerData>>>,
38
39 /// The touch bound on the seat.
40 touch: Option<WlTouch>,
41
42 /// The mapping from touched points to the surfaces they're present.
43 touch_map: AHashMap<i32, TouchPoint>,
44
45 /// The text input bound on the seat.
46 text_input: Option<Arc<ZwpTextInputV3>>,
47
48 /// The relative pointer bound on the seat.
49 relative_pointer: Option<ZwpRelativePointerV1>,
50
51 /// The keyboard bound on the seat.
52 keyboard_state: Option<KeyboardState>,
53
54 /// The current modifiers state on the seat.
55 modifiers: ModifiersState,
56
57 /// Wether we have pending modifiers.
58 modifiers_pending: bool,
59}
60
61impl WinitSeatState {
62 pub fn new() -> Self {
63 Default::default()
64 }
65}
66
67impl SeatHandler for WinitState {
68 fn seat_state(&mut self) -> &mut SeatState {
69 &mut self.seat_state
70 }
71
72 fn new_capability(
73 &mut self,
74 _: &Connection,
75 queue_handle: &QueueHandle<Self>,
76 seat: WlSeat,
77 capability: SeatCapability,
78 ) {
79 let seat_state = self.seats.get_mut(&seat.id()).unwrap();
80
81 match capability {
82 SeatCapability::Touch if seat_state.touch.is_none() => {
83 seat_state.touch = self.seat_state.get_touch(queue_handle, &seat).ok();
84 }
85 SeatCapability::Keyboard if seat_state.keyboard_state.is_none() => {
86 let keyboard = seat.get_keyboard(queue_handle, KeyboardData::new(seat.clone()));
87 seat_state.keyboard_state =
88 Some(KeyboardState::new(keyboard, self.loop_handle.clone()));
89 }
90 SeatCapability::Pointer if seat_state.pointer.is_none() => {
91 let surface = self.compositor_state.create_surface(queue_handle);
92 let surface_id = surface.id();
93 let pointer_data = WinitPointerData::new(seat.clone());
94 let themed_pointer = self
95 .seat_state
96 .get_pointer_with_theme_and_data(
97 queue_handle,
98 &seat,
99 self.shm.wl_shm(),
100 surface,
101 ThemeSpec::System,
102 pointer_data,
103 )
104 .expect("failed to create pointer with present capability.");
105
106 seat_state.relative_pointer = self.relative_pointer.as_ref().map(|manager| {
107 manager.get_relative_pointer(
108 themed_pointer.pointer(),
109 queue_handle,
110 sctk::globals::GlobalData,
111 )
112 });
113
114 let themed_pointer = Arc::new(themed_pointer);
115
116 // Register cursor surface.
117 self.pointer_surfaces
118 .insert(surface_id, themed_pointer.clone());
119
120 seat_state.pointer = Some(themed_pointer);
121 }
122 _ => (),
123 }
124
125 if let Some(text_input_state) = seat_state
126 .text_input
127 .is_none()
128 .then_some(self.text_input_state.as_ref())
129 .flatten()
130 {
131 seat_state.text_input = Some(Arc::new(text_input_state.get_text_input(
132 &seat,
133 queue_handle,
134 TextInputData::default(),
135 )));
136 }
137 }
138
139 fn remove_capability(
140 &mut self,
141 _: &Connection,
142 _queue_handle: &QueueHandle<Self>,
143 seat: WlSeat,
144 capability: SeatCapability,
145 ) {
146 let seat_state = self.seats.get_mut(&seat.id()).unwrap();
147
148 if let Some(text_input) = seat_state.text_input.take() {
149 text_input.destroy();
150 }
151
152 match capability {
153 SeatCapability::Touch => {
154 if let Some(touch) = seat_state.touch.take() {
155 if touch.version() >= 3 {
156 touch.release();
157 }
158 }
159 }
160 SeatCapability::Pointer => {
161 if let Some(relative_pointer) = seat_state.relative_pointer.take() {
162 relative_pointer.destroy();
163 }
164
165 if let Some(pointer) = seat_state.pointer.take() {
166 let pointer_data = pointer.pointer().winit_data();
167
168 // Remove the cursor from the mapping.
169 let surface_id = pointer.surface().id();
170 let _ = self.pointer_surfaces.remove(&surface_id);
171
172 // Remove the inner locks/confines before dropping the pointer.
173 pointer_data.unlock_pointer();
174 pointer_data.unconfine_pointer();
175
176 if pointer.pointer().version() >= 3 {
177 pointer.pointer().release();
178 }
179 }
180 }
181 SeatCapability::Keyboard => {
182 seat_state.keyboard_state = None;
183 self.on_keyboard_destroy(&seat.id());
184 }
185 _ => (),
186 }
187 }
188
189 fn new_seat(
190 &mut self,
191 _connection: &Connection,
192 _queue_handle: &QueueHandle<Self>,
193 seat: WlSeat,
194 ) {
195 self.seats.insert(seat.id(), WinitSeatState::new());
196 }
197
198 fn remove_seat(
199 &mut self,
200 _connection: &Connection,
201 _queue_handle: &QueueHandle<Self>,
202 seat: WlSeat,
203 ) {
204 let _ = self.seats.remove(&seat.id());
205 self.on_keyboard_destroy(&seat.id());
206 }
207}
208
209impl WinitState {
210 fn on_keyboard_destroy(&mut self, seat: &ObjectId) {
211 for (window_id: &WindowId, window: &mut Arc>) in self.windows.get_mut() {
212 let mut window: MutexGuard<'_, WindowState> = window.lock().unwrap();
213 let had_focus: bool = window.has_focus();
214 window.remove_seat_focus(seat);
215 if had_focus != window.has_focus() {
216 self.events_sink
217 .push_window_event(event:WindowEvent::Focused(false), *window_id);
218 }
219 }
220 }
221}
222
223sctk::delegate_seat!(WinitState);
224