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