1use std::cell::RefCell;
2use std::sync::atomic::Ordering;
3use std::sync::{Arc, Mutex};
4
5use ahash::AHashMap;
6use sctk::compositor::{CompositorHandler, CompositorState};
7use sctk::output::{OutputHandler, OutputState};
8use sctk::reexports::calloop::LoopHandle;
9use sctk::reexports::client::backend::ObjectId;
10use sctk::reexports::client::globals::GlobalList;
11use sctk::reexports::client::protocol::wl_output::WlOutput;
12use sctk::reexports::client::protocol::wl_surface::WlSurface;
13use sctk::reexports::client::{Connection, Proxy, QueueHandle};
14use sctk::registry::{ProvidesRegistryState, RegistryState};
15use sctk::seat::pointer::ThemedPointer;
16use sctk::seat::SeatState;
17use sctk::shell::xdg::window::{Window, WindowConfigure, WindowHandler};
18use sctk::shell::xdg::XdgShell;
19use sctk::shell::WaylandSurface;
20use sctk::shm::slot::SlotPool;
21use sctk::shm::{Shm, ShmHandler};
22use sctk::subcompositor::SubcompositorState;
23
24use crate::error::OsError;
25use crate::platform_impl::wayland::event_loop::sink::EventSink;
26use crate::platform_impl::wayland::output::MonitorHandle;
27use crate::platform_impl::wayland::seat::{
28 PointerConstraintsState, RelativePointerState, TextInputState, WinitPointerData,
29 WinitPointerDataExt, WinitSeatState,
30};
31use crate::platform_impl::wayland::types::kwin_blur::KWinBlurManager;
32use crate::platform_impl::wayland::types::wp_fractional_scaling::FractionalScalingManager;
33use crate::platform_impl::wayland::types::wp_viewporter::ViewporterState;
34use crate::platform_impl::wayland::types::xdg_activation::XdgActivationState;
35use crate::platform_impl::wayland::window::{WindowRequests, WindowState};
36use crate::platform_impl::wayland::WindowId;
37
38pub struct WinitState {
40 pub registry_state: RegistryState,
42
43 pub output_state: OutputState,
45
46 pub compositor_state: Arc<CompositorState>,
48
49 pub subcompositor_state: Option<Arc<SubcompositorState>>,
51
52 pub seat_state: SeatState,
54
55 pub shm: Shm,
57
58 pub custom_cursor_pool: Arc<Mutex<SlotPool>>,
60
61 pub xdg_shell: XdgShell,
63
64 pub windows: RefCell<AHashMap<WindowId, Arc<Mutex<WindowState>>>>,
66
67 pub window_requests: RefCell<AHashMap<WindowId, Arc<WindowRequests>>>,
69
70 pub window_events_sink: Arc<Mutex<EventSink>>,
72
73 pub window_compositor_updates: Vec<WindowCompositorUpdate>,
75
76 pub seats: AHashMap<ObjectId, WinitSeatState>,
78
79 pub pointer_surfaces: AHashMap<ObjectId, Arc<ThemedPointer<WinitPointerData>>>,
81
82 pub text_input_state: Option<TextInputState>,
84
85 pub monitors: Arc<Mutex<Vec<MonitorHandle>>>,
87
88 pub events_sink: EventSink,
91
92 pub xdg_activation: Option<XdgActivationState>,
94
95 pub relative_pointer: Option<RelativePointerState>,
97
98 pub pointer_constraints: Option<Arc<PointerConstraintsState>>,
100
101 pub viewporter_state: Option<ViewporterState>,
103
104 pub fractional_scaling_manager: Option<FractionalScalingManager>,
106
107 pub kwin_blur_manager: Option<KWinBlurManager>,
109
110 pub loop_handle: LoopHandle<'static, Self>,
112
113 pub dispatched_events: bool,
116
117 pub proxy_wake_up: bool,
119}
120
121impl WinitState {
122 pub fn new(
123 globals: &GlobalList,
124 queue_handle: &QueueHandle<Self>,
125 loop_handle: LoopHandle<'static, WinitState>,
126 ) -> Result<Self, OsError> {
127 let registry_state = RegistryState::new(globals);
128 let compositor_state =
129 CompositorState::bind(globals, queue_handle).map_err(|err| os_error!(err))?;
130 let subcompositor_state = match SubcompositorState::bind(
131 compositor_state.wl_compositor().clone(),
132 globals,
133 queue_handle,
134 ) {
135 Ok(c) => Some(c),
136 Err(e) => {
137 tracing::warn!("Subcompositor protocol not available, ignoring CSD: {e:?}");
138 None
139 },
140 };
141
142 let output_state = OutputState::new(globals, queue_handle);
143 let monitors = output_state.outputs().map(MonitorHandle::new).collect();
144
145 let seat_state = SeatState::new(globals, queue_handle);
146
147 let mut seats = AHashMap::default();
148 for seat in seat_state.seats() {
149 seats.insert(seat.id(), WinitSeatState::new());
150 }
151
152 let (viewporter_state, fractional_scaling_manager) =
153 if let Ok(fsm) = FractionalScalingManager::new(globals, queue_handle) {
154 (ViewporterState::new(globals, queue_handle).ok(), Some(fsm))
155 } else {
156 (None, None)
157 };
158
159 let shm = Shm::bind(globals, queue_handle).map_err(|err| os_error!(err))?;
160 let custom_cursor_pool = Arc::new(Mutex::new(SlotPool::new(2, &shm).unwrap()));
161
162 Ok(Self {
163 registry_state,
164 compositor_state: Arc::new(compositor_state),
165 subcompositor_state: subcompositor_state.map(Arc::new),
166 output_state,
167 seat_state,
168 shm,
169 custom_cursor_pool,
170
171 xdg_shell: XdgShell::bind(globals, queue_handle).map_err(|err| os_error!(err))?,
172 xdg_activation: XdgActivationState::bind(globals, queue_handle).ok(),
173
174 windows: Default::default(),
175 window_requests: Default::default(),
176 window_compositor_updates: Vec::new(),
177 window_events_sink: Default::default(),
178 viewporter_state,
179 fractional_scaling_manager,
180 kwin_blur_manager: KWinBlurManager::new(globals, queue_handle).ok(),
181
182 seats,
183 text_input_state: TextInputState::new(globals, queue_handle).ok(),
184
185 relative_pointer: RelativePointerState::new(globals, queue_handle).ok(),
186 pointer_constraints: PointerConstraintsState::new(globals, queue_handle)
187 .map(Arc::new)
188 .ok(),
189 pointer_surfaces: Default::default(),
190
191 monitors: Arc::new(Mutex::new(monitors)),
192 events_sink: EventSink::new(),
193 loop_handle,
194 dispatched_events: true,
196 proxy_wake_up: false,
197 })
198 }
199
200 pub fn scale_factor_changed(
201 &mut self,
202 surface: &WlSurface,
203 scale_factor: f64,
204 is_legacy: bool,
205 ) {
206 let window_id = super::make_wid(surface);
208
209 if let Some(window) = self.windows.get_mut().get(&window_id) {
210 if is_legacy && self.fractional_scaling_manager.is_some() {
212 return;
213 }
214
215 let pos = if let Some(pos) = self
217 .window_compositor_updates
218 .iter()
219 .position(|update| update.window_id == window_id)
220 {
221 pos
222 } else {
223 self.window_compositor_updates.push(WindowCompositorUpdate::new(window_id));
224 self.window_compositor_updates.len() - 1
225 };
226
227 window.lock().unwrap().set_scale_factor(scale_factor);
229 self.window_compositor_updates[pos].scale_changed = true;
230 } else if let Some(pointer) = self.pointer_surfaces.get(&surface.id()) {
231 let focused_window = match pointer.pointer().winit_data().focused_window() {
233 Some(focused_window) => focused_window,
234 None => return,
235 };
236
237 if let Some(window_state) = self.windows.get_mut().get(&focused_window) {
238 window_state.lock().unwrap().reload_cursor_style()
239 }
240 }
241 }
242
243 pub fn queue_close(updates: &mut Vec<WindowCompositorUpdate>, window_id: WindowId) {
244 let pos = if let Some(pos) = updates.iter().position(|update| update.window_id == window_id)
245 {
246 pos
247 } else {
248 updates.push(WindowCompositorUpdate::new(window_id));
249 updates.len() - 1
250 };
251
252 updates[pos].close_window = true;
253 }
254}
255
256impl ShmHandler for WinitState {
257 fn shm_state(&mut self) -> &mut Shm {
258 &mut self.shm
259 }
260}
261
262impl WindowHandler for WinitState {
263 fn request_close(&mut self, _: &Connection, _: &QueueHandle<Self>, window: &Window) {
264 let window_id = super::make_wid(window.wl_surface());
265 Self::queue_close(&mut self.window_compositor_updates, window_id);
266 }
267
268 fn configure(
269 &mut self,
270 _: &Connection,
271 _: &QueueHandle<Self>,
272 window: &Window,
273 configure: WindowConfigure,
274 _serial: u32,
275 ) {
276 let window_id = super::make_wid(window.wl_surface());
277
278 let pos = if let Some(pos) =
279 self.window_compositor_updates.iter().position(|update| update.window_id == window_id)
280 {
281 pos
282 } else {
283 self.window_compositor_updates.push(WindowCompositorUpdate::new(window_id));
284 self.window_compositor_updates.len() - 1
285 };
286
287 let mut winit_window = self
288 .windows
289 .get_mut()
290 .get_mut(&window_id)
291 .expect("got configure for dead window.")
292 .lock()
293 .unwrap();
294 self.window_compositor_updates[pos].suggested_bounds |= configure.suggested_bounds
297 != winit_window.last_configure.as_ref().and_then(|last| last.suggested_bounds);
298
299 self.window_compositor_updates[pos].resized |=
300 winit_window.configure(configure, &self.shm, &self.subcompositor_state);
301
302 self.window_requests
305 .get_mut()
306 .get(&window_id)
307 .unwrap()
308 .redraw_requested
309 .store(true, Ordering::Relaxed);
310
311 self.dispatched_events = true;
313 }
314}
315
316impl OutputHandler for WinitState {
317 fn output_state(&mut self) -> &mut OutputState {
318 &mut self.output_state
319 }
320
321 fn new_output(&mut self, _: &Connection, _: &QueueHandle<Self>, output: WlOutput) {
322 self.monitors.lock().unwrap().push(MonitorHandle::new(output));
323 }
324
325 fn update_output(&mut self, _: &Connection, _: &QueueHandle<Self>, updated: WlOutput) {
326 let mut monitors = self.monitors.lock().unwrap();
327 let updated = MonitorHandle::new(updated);
328 if let Some(pos) = monitors.iter().position(|output| output == &updated) {
329 monitors[pos] = updated
330 } else {
331 monitors.push(updated)
332 }
333 }
334
335 fn output_destroyed(&mut self, _: &Connection, _: &QueueHandle<Self>, removed: WlOutput) {
336 let mut monitors = self.monitors.lock().unwrap();
337 let removed = MonitorHandle::new(removed);
338 if let Some(pos) = monitors.iter().position(|output| output == &removed) {
339 monitors.remove(pos);
340 }
341 }
342}
343
344impl CompositorHandler for WinitState {
345 fn transform_changed(
346 &mut self,
347 _: &Connection,
348 _: &QueueHandle<Self>,
349 _: &WlSurface,
350 _: wayland_client::protocol::wl_output::Transform,
351 ) {
352 }
354
355 fn surface_enter(
356 &mut self,
357 _: &Connection,
358 _: &QueueHandle<Self>,
359 _: &WlSurface,
360 _: &WlOutput,
361 ) {
362 }
363
364 fn surface_leave(
365 &mut self,
366 _: &Connection,
367 _: &QueueHandle<Self>,
368 _: &WlSurface,
369 _: &WlOutput,
370 ) {
371 }
372
373 fn scale_factor_changed(
374 &mut self,
375 _: &Connection,
376 _: &QueueHandle<Self>,
377 surface: &WlSurface,
378 scale_factor: i32,
379 ) {
380 self.scale_factor_changed(surface, scale_factor as f64, true)
381 }
382
383 fn frame(&mut self, _: &Connection, _: &QueueHandle<Self>, surface: &WlSurface, _: u32) {
384 let window_id = super::make_wid(surface);
385 let window = match self.windows.get_mut().get(&window_id) {
386 Some(window) => window,
387 None => return,
388 };
389
390 if self
392 .window_requests
393 .get_mut()
394 .get(&window_id)
395 .unwrap()
396 .redraw_requested
397 .load(Ordering::Relaxed)
398 {
399 self.dispatched_events = true;
400 }
401
402 window.lock().unwrap().frame_callback_received();
403 }
404}
405
406impl ProvidesRegistryState for WinitState {
407 sctk::registry_handlers![OutputState, SeatState];
408
409 fn registry(&mut self) -> &mut RegistryState {
410 &mut self.registry_state
411 }
412}
413
414#[derive(Debug, Clone, Copy)]
416pub struct WindowCompositorUpdate {
417 pub window_id: WindowId,
419
420 pub resized: bool,
422
423 pub scale_changed: bool,
425
426 pub close_window: bool,
428
429 pub suggested_bounds: bool,
431}
432
433impl WindowCompositorUpdate {
434 fn new(window_id: WindowId) -> Self {
435 Self {
436 window_id,
437 resized: false,
438 scale_changed: false,
439 close_window: false,
440 suggested_bounds: false,
441 }
442 }
443}
444
445sctk::delegate_subcompositor!(WinitState);
446sctk::delegate_compositor!(WinitState);
447sctk::delegate_output!(WinitState);
448sctk::delegate_registry!(WinitState);
449sctk::delegate_shm!(WinitState);
450sctk::delegate_xdg_shell!(WinitState);
451sctk::delegate_xdg_window!(WinitState);