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