1 | use std::cell::RefCell; |
2 | use std::sync::atomic::Ordering; |
3 | use std::sync::{Arc, Mutex}; |
4 | |
5 | use ahash::AHashMap; |
6 | |
7 | use sctk::reexports::calloop::LoopHandle; |
8 | use sctk::reexports::client::backend::ObjectId; |
9 | use sctk::reexports::client::globals::GlobalList; |
10 | use sctk::reexports::client::protocol::wl_output::WlOutput; |
11 | use sctk::reexports::client::protocol::wl_surface::WlSurface; |
12 | use sctk::reexports::client::{Connection, Proxy, QueueHandle}; |
13 | |
14 | use sctk::compositor::{CompositorHandler, CompositorState}; |
15 | use sctk::output::{OutputHandler, OutputState}; |
16 | use sctk::registry::{ProvidesRegistryState, RegistryState}; |
17 | use sctk::seat::pointer::ThemedPointer; |
18 | use sctk::seat::SeatState; |
19 | use sctk::shell::xdg::window::{Window, WindowConfigure, WindowHandler}; |
20 | use sctk::shell::xdg::XdgShell; |
21 | use sctk::shell::WaylandSurface; |
22 | use sctk::shm::{Shm, ShmHandler}; |
23 | use sctk::subcompositor::SubcompositorState; |
24 | |
25 | use crate::platform_impl::wayland::event_loop::sink::EventSink; |
26 | use crate::platform_impl::wayland::output::MonitorHandle; |
27 | use crate::platform_impl::wayland::seat::{ |
28 | PointerConstraintsState, RelativePointerState, TextInputState, WinitPointerData, |
29 | WinitPointerDataExt, WinitSeatState, |
30 | }; |
31 | use crate::platform_impl::wayland::types::kwin_blur::KWinBlurManager; |
32 | use crate::platform_impl::wayland::types::wp_fractional_scaling::FractionalScalingManager; |
33 | use crate::platform_impl::wayland::types::wp_viewporter::ViewporterState; |
34 | use crate::platform_impl::wayland::types::xdg_activation::XdgActivationState; |
35 | use crate::platform_impl::wayland::window::{WindowRequests, WindowState}; |
36 | use crate::platform_impl::wayland::{WaylandError, WindowId}; |
37 | use crate::platform_impl::OsError; |
38 | |
39 | /// Winit's Wayland state. |
40 | pub struct WinitState { |
41 | /// The WlRegistry. |
42 | pub registry_state: RegistryState, |
43 | |
44 | /// The state of the WlOutput handling. |
45 | pub output_state: OutputState, |
46 | |
47 | /// The compositor state which is used to create new windows and regions. |
48 | pub compositor_state: Arc<CompositorState>, |
49 | |
50 | /// The state of the subcompositor. |
51 | pub subcompositor_state: Option<Arc<SubcompositorState>>, |
52 | |
53 | /// The seat state responsible for all sorts of input. |
54 | pub seat_state: SeatState, |
55 | |
56 | /// The shm for software buffers, such as cursors. |
57 | pub shm: Shm, |
58 | |
59 | /// The XDG shell that is used for widnows. |
60 | pub xdg_shell: XdgShell, |
61 | |
62 | /// The currently present windows. |
63 | pub windows: RefCell<AHashMap<WindowId, Arc<Mutex<WindowState>>>>, |
64 | |
65 | /// The requests from the `Window` to EventLoop, such as close operations and redraw requests. |
66 | pub window_requests: RefCell<AHashMap<WindowId, Arc<WindowRequests>>>, |
67 | |
68 | /// The events that were generated directly from the window. |
69 | pub window_events_sink: Arc<Mutex<EventSink>>, |
70 | |
71 | /// The update for the `windows` comming from the compositor. |
72 | pub window_compositor_updates: Vec<WindowCompositorUpdate>, |
73 | |
74 | /// Currently handled seats. |
75 | pub seats: AHashMap<ObjectId, WinitSeatState>, |
76 | |
77 | /// Currently present cursor surfaces. |
78 | pub pointer_surfaces: AHashMap<ObjectId, Arc<ThemedPointer<WinitPointerData>>>, |
79 | |
80 | /// The state of the text input on the client. |
81 | pub text_input_state: Option<TextInputState>, |
82 | |
83 | /// Observed monitors. |
84 | pub monitors: Arc<Mutex<Vec<MonitorHandle>>>, |
85 | |
86 | /// Sink to accumulate window events from the compositor, which is latter dispatched in |
87 | /// event loop run. |
88 | pub events_sink: EventSink, |
89 | |
90 | /// Xdg activation. |
91 | pub xdg_activation: Option<XdgActivationState>, |
92 | |
93 | /// Relative pointer. |
94 | pub relative_pointer: Option<RelativePointerState>, |
95 | |
96 | /// Pointer constraints to handle pointer locking and confining. |
97 | pub pointer_constraints: Option<Arc<PointerConstraintsState>>, |
98 | |
99 | /// Viewporter state on the given window. |
100 | pub viewporter_state: Option<ViewporterState>, |
101 | |
102 | /// Fractional scaling manager. |
103 | pub fractional_scaling_manager: Option<FractionalScalingManager>, |
104 | |
105 | /// KWin blur manager. |
106 | pub kwin_blur_manager: Option<KWinBlurManager>, |
107 | |
108 | /// Loop handle to re-register event sources, such as keyboard repeat. |
109 | pub loop_handle: LoopHandle<'static, Self>, |
110 | |
111 | /// Whether we have dispatched events to the user thus we want to |
112 | /// send `AboutToWait` and normally wakeup the user. |
113 | pub dispatched_events: bool, |
114 | } |
115 | |
116 | impl WinitState { |
117 | pub fn new( |
118 | globals: &GlobalList, |
119 | queue_handle: &QueueHandle<Self>, |
120 | loop_handle: LoopHandle<'static, WinitState>, |
121 | ) -> Result<Self, OsError> { |
122 | let registry_state = RegistryState::new(globals); |
123 | let compositor_state = |
124 | CompositorState::bind(globals, queue_handle).map_err(WaylandError::Bind)?; |
125 | let subcompositor_state = match SubcompositorState::bind( |
126 | compositor_state.wl_compositor().clone(), |
127 | globals, |
128 | queue_handle, |
129 | ) { |
130 | Ok(c) => Some(c), |
131 | Err(e) => { |
132 | warn!("Subcompositor protocol not available, ignoring CSD: {e:?}" ); |
133 | None |
134 | } |
135 | }; |
136 | |
137 | let output_state = OutputState::new(globals, queue_handle); |
138 | let monitors = output_state.outputs().map(MonitorHandle::new).collect(); |
139 | |
140 | let seat_state = SeatState::new(globals, queue_handle); |
141 | |
142 | let mut seats = AHashMap::default(); |
143 | for seat in seat_state.seats() { |
144 | seats.insert(seat.id(), WinitSeatState::new()); |
145 | } |
146 | |
147 | let (viewporter_state, fractional_scaling_manager) = |
148 | if let Ok(fsm) = FractionalScalingManager::new(globals, queue_handle) { |
149 | (ViewporterState::new(globals, queue_handle).ok(), Some(fsm)) |
150 | } else { |
151 | (None, None) |
152 | }; |
153 | |
154 | Ok(Self { |
155 | registry_state, |
156 | compositor_state: Arc::new(compositor_state), |
157 | subcompositor_state: subcompositor_state.map(Arc::new), |
158 | output_state, |
159 | seat_state, |
160 | shm: Shm::bind(globals, queue_handle).map_err(WaylandError::Bind)?, |
161 | |
162 | xdg_shell: XdgShell::bind(globals, queue_handle).map_err(WaylandError::Bind)?, |
163 | xdg_activation: XdgActivationState::bind(globals, queue_handle).ok(), |
164 | |
165 | windows: Default::default(), |
166 | window_requests: Default::default(), |
167 | window_compositor_updates: Vec::new(), |
168 | window_events_sink: Default::default(), |
169 | viewporter_state, |
170 | fractional_scaling_manager, |
171 | kwin_blur_manager: KWinBlurManager::new(globals, queue_handle).ok(), |
172 | |
173 | seats, |
174 | text_input_state: TextInputState::new(globals, queue_handle).ok(), |
175 | |
176 | relative_pointer: RelativePointerState::new(globals, queue_handle).ok(), |
177 | pointer_constraints: PointerConstraintsState::new(globals, queue_handle) |
178 | .map(Arc::new) |
179 | .ok(), |
180 | pointer_surfaces: Default::default(), |
181 | |
182 | monitors: Arc::new(Mutex::new(monitors)), |
183 | events_sink: EventSink::new(), |
184 | loop_handle, |
185 | // Make it true by default. |
186 | dispatched_events: true, |
187 | }) |
188 | } |
189 | |
190 | pub fn scale_factor_changed( |
191 | &mut self, |
192 | surface: &WlSurface, |
193 | scale_factor: f64, |
194 | is_legacy: bool, |
195 | ) { |
196 | // Check if the cursor surface. |
197 | let window_id = super::make_wid(surface); |
198 | |
199 | if let Some(window) = self.windows.get_mut().get(&window_id) { |
200 | // Don't update the scaling factor, when legacy method is used. |
201 | if is_legacy && self.fractional_scaling_manager.is_some() { |
202 | return; |
203 | } |
204 | |
205 | // The scale factor change is for the window. |
206 | let pos = if let Some(pos) = self |
207 | .window_compositor_updates |
208 | .iter() |
209 | .position(|update| update.window_id == window_id) |
210 | { |
211 | pos |
212 | } else { |
213 | self.window_compositor_updates |
214 | .push(WindowCompositorUpdate::new(window_id)); |
215 | self.window_compositor_updates.len() - 1 |
216 | }; |
217 | |
218 | // Update the scale factor right away. |
219 | window.lock().unwrap().set_scale_factor(scale_factor); |
220 | self.window_compositor_updates[pos].scale_changed = true; |
221 | } else if let Some(pointer) = self.pointer_surfaces.get(&surface.id()) { |
222 | // Get the window, where the pointer resides right now. |
223 | let focused_window = match pointer.pointer().winit_data().focused_window() { |
224 | Some(focused_window) => focused_window, |
225 | None => return, |
226 | }; |
227 | |
228 | if let Some(window_state) = self.windows.get_mut().get(&focused_window) { |
229 | window_state.lock().unwrap().reload_cursor_style() |
230 | } |
231 | } |
232 | } |
233 | |
234 | pub fn queue_close(updates: &mut Vec<WindowCompositorUpdate>, window_id: WindowId) { |
235 | let pos = if let Some(pos) = updates |
236 | .iter() |
237 | .position(|update| update.window_id == window_id) |
238 | { |
239 | pos |
240 | } else { |
241 | updates.push(WindowCompositorUpdate::new(window_id)); |
242 | updates.len() - 1 |
243 | }; |
244 | |
245 | updates[pos].close_window = true; |
246 | } |
247 | } |
248 | |
249 | impl ShmHandler for WinitState { |
250 | fn shm_state(&mut self) -> &mut Shm { |
251 | &mut self.shm |
252 | } |
253 | } |
254 | |
255 | impl WindowHandler for WinitState { |
256 | fn request_close(&mut self, _: &Connection, _: &QueueHandle<Self>, window: &Window) { |
257 | let window_id = super::make_wid(window.wl_surface()); |
258 | Self::queue_close(&mut self.window_compositor_updates, window_id); |
259 | } |
260 | |
261 | fn configure( |
262 | &mut self, |
263 | _: &Connection, |
264 | _: &QueueHandle<Self>, |
265 | window: &Window, |
266 | configure: WindowConfigure, |
267 | _serial: u32, |
268 | ) { |
269 | let window_id = super::make_wid(window.wl_surface()); |
270 | |
271 | let pos = if let Some(pos) = self |
272 | .window_compositor_updates |
273 | .iter() |
274 | .position(|update| update.window_id == window_id) |
275 | { |
276 | pos |
277 | } else { |
278 | self.window_compositor_updates |
279 | .push(WindowCompositorUpdate::new(window_id)); |
280 | self.window_compositor_updates.len() - 1 |
281 | }; |
282 | |
283 | // Populate the configure to the window. |
284 | self.window_compositor_updates[pos].resized |= self |
285 | .windows |
286 | .get_mut() |
287 | .get_mut(&window_id) |
288 | .expect("got configure for dead window." ) |
289 | .lock() |
290 | .unwrap() |
291 | .configure(configure, &self.shm, &self.subcompositor_state); |
292 | |
293 | // NOTE: configure demands wl_surface::commit, however winit doesn't commit on behalf of the |
294 | // users, since it can break a lot of things, thus it'll ask users to redraw instead. |
295 | self.window_requests |
296 | .get_mut() |
297 | .get(&window_id) |
298 | .unwrap() |
299 | .redraw_requested |
300 | .store(true, Ordering::Relaxed); |
301 | |
302 | // Manually mark that we've got an event, since configure may not generate a resize. |
303 | self.dispatched_events = true; |
304 | } |
305 | } |
306 | |
307 | impl OutputHandler for WinitState { |
308 | fn output_state(&mut self) -> &mut OutputState { |
309 | &mut self.output_state |
310 | } |
311 | |
312 | fn new_output(&mut self, _: &Connection, _: &QueueHandle<Self>, output: WlOutput) { |
313 | self.monitors |
314 | .lock() |
315 | .unwrap() |
316 | .push(MonitorHandle::new(output)); |
317 | } |
318 | |
319 | fn update_output(&mut self, _: &Connection, _: &QueueHandle<Self>, updated: WlOutput) { |
320 | let mut monitors = self.monitors.lock().unwrap(); |
321 | let updated = MonitorHandle::new(updated); |
322 | if let Some(pos) = monitors.iter().position(|output| output == &updated) { |
323 | monitors[pos] = updated |
324 | } else { |
325 | monitors.push(updated) |
326 | } |
327 | } |
328 | |
329 | fn output_destroyed(&mut self, _: &Connection, _: &QueueHandle<Self>, removed: WlOutput) { |
330 | let mut monitors = self.monitors.lock().unwrap(); |
331 | let removed = MonitorHandle::new(removed); |
332 | if let Some(pos) = monitors.iter().position(|output| output == &removed) { |
333 | monitors.remove(pos); |
334 | } |
335 | } |
336 | } |
337 | |
338 | impl CompositorHandler for WinitState { |
339 | fn transform_changed( |
340 | &mut self, |
341 | _: &Connection, |
342 | _: &QueueHandle<Self>, |
343 | _: &wayland_client::protocol::wl_surface::WlSurface, |
344 | _: wayland_client::protocol::wl_output::Transform, |
345 | ) { |
346 | // TODO(kchibisov) we need to expose it somehow in winit. |
347 | } |
348 | |
349 | fn scale_factor_changed( |
350 | &mut self, |
351 | _: &Connection, |
352 | _: &QueueHandle<Self>, |
353 | surface: &WlSurface, |
354 | scale_factor: i32, |
355 | ) { |
356 | self.scale_factor_changed(surface, scale_factor as f64, true) |
357 | } |
358 | |
359 | fn frame(&mut self, _: &Connection, _: &QueueHandle<Self>, surface: &WlSurface, _: u32) { |
360 | let window_id = super::make_wid(surface); |
361 | let window = match self.windows.get_mut().get(&window_id) { |
362 | Some(window) => window, |
363 | None => return, |
364 | }; |
365 | |
366 | // In case we have a redraw requested we must indicate the wake up. |
367 | if self |
368 | .window_requests |
369 | .get_mut() |
370 | .get(&window_id) |
371 | .unwrap() |
372 | .redraw_requested |
373 | .load(Ordering::Relaxed) |
374 | { |
375 | self.dispatched_events = true; |
376 | } |
377 | |
378 | window.lock().unwrap().frame_callback_received(); |
379 | } |
380 | } |
381 | |
382 | impl ProvidesRegistryState for WinitState { |
383 | fn registry(&mut self) -> &mut RegistryState { |
384 | &mut self.registry_state |
385 | } |
386 | |
387 | sctk::registry_handlers![OutputState, SeatState]; |
388 | } |
389 | |
390 | // The window update comming from the compositor. |
391 | #[derive (Debug, Clone, Copy)] |
392 | pub struct WindowCompositorUpdate { |
393 | /// The id of the window this updates belongs to. |
394 | pub window_id: WindowId, |
395 | |
396 | /// New window size. |
397 | pub resized: bool, |
398 | |
399 | /// New scale factor. |
400 | pub scale_changed: bool, |
401 | |
402 | /// Close the window. |
403 | pub close_window: bool, |
404 | } |
405 | |
406 | impl WindowCompositorUpdate { |
407 | fn new(window_id: WindowId) -> Self { |
408 | Self { |
409 | window_id, |
410 | resized: false, |
411 | scale_changed: false, |
412 | close_window: false, |
413 | } |
414 | } |
415 | } |
416 | |
417 | sctk::delegate_subcompositor!(WinitState); |
418 | sctk::delegate_compositor!(WinitState); |
419 | sctk::delegate_output!(WinitState); |
420 | sctk::delegate_registry!(WinitState); |
421 | sctk::delegate_shm!(WinitState); |
422 | sctk::delegate_xdg_shell!(WinitState); |
423 | sctk::delegate_xdg_window!(WinitState); |
424 | |