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