iced_winit/platform_specific/
mod.rs

1//! Wayland specific shell
2//!
3
4use std::collections::HashMap;
5
6use iced_graphics::Compositor;
7use iced_runtime::{
8    core::{window, Vector},
9    user_interface, Debug,
10};
11use winit::raw_window_handle::HasWindowHandle;
12
13#[cfg(all(feature = "wayland", target_os = "linux"))]
14pub mod wayland;
15
16#[cfg(all(feature = "wayland", target_os = "linux"))]
17pub use wayland::*;
18#[cfg(all(feature = "wayland", target_os = "linux"))]
19use wayland_backend::client::Backend;
20
21use crate::{program::WindowManager, Program};
22
23#[derive(Debug)]
24pub enum Event {
25    #[cfg(all(feature = "wayland", target_os = "linux"))]
26    Wayland(sctk_event::SctkEvent),
27}
28
29#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
30pub enum SurfaceIdWrapper {
31    LayerSurface(window::Id),
32    Window(window::Id),
33    Popup(window::Id),
34    SessionLock(window::Id),
35    Subsurface(window::Id),
36}
37impl SurfaceIdWrapper {
38    pub fn inner(&self) -> window::Id {
39        match self {
40            SurfaceIdWrapper::LayerSurface(id) => *id,
41            SurfaceIdWrapper::Window(id) => *id,
42            SurfaceIdWrapper::Popup(id) => *id,
43            SurfaceIdWrapper::SessionLock(id) => *id,
44            SurfaceIdWrapper::Subsurface(id) => *id,
45        }
46    }
47}
48
49#[derive(Debug, Default)]
50pub struct PlatformSpecific {
51    #[cfg(all(feature = "wayland", target_os = "linux"))]
52    wayland: WaylandSpecific,
53}
54
55impl PlatformSpecific {
56    pub(crate) fn send_action(
57        &mut self,
58        action: iced_runtime::platform_specific::Action,
59    ) {
60        match action {
61            #[cfg(all(feature = "wayland", target_os = "linux"))]
62            iced_runtime::platform_specific::Action::Wayland(a) => {
63                self.send_wayland(wayland::Action::Action(a));
64            }
65        }
66    }
67
68    pub(crate) fn retain_subsurfaces<F: Fn(window::Id) -> bool>(
69        &mut self,
70        keep: F,
71    ) {
72        #[cfg(all(feature = "wayland", target_os = "linux"))]
73        {
74            self.wayland.retain_subsurfaces(keep);
75        }
76    }
77
78    pub(crate) fn clear_subsurface_list(&mut self) {
79        #[cfg(all(feature = "wayland", target_os = "linux"))]
80        {
81            self.wayland.clear_subsurface_list();
82        }
83    }
84
85    pub(crate) fn update_subsurfaces(
86        &mut self,
87        id: window::Id,
88        window: &dyn HasWindowHandle,
89    ) {
90        #[cfg(all(feature = "wayland", target_os = "linux"))]
91        {
92            use cctk::sctk::reexports::client::{
93                protocol::wl_surface::WlSurface, Proxy,
94            };
95            use wayland_backend::client::ObjectId;
96
97            let Some(conn) = self.wayland.conn() else {
98                log::info!("No Wayland conn");
99                return;
100            };
101
102            let Ok(raw) = window.window_handle() else {
103                log::error!("Invalid window handle {id:?}");
104                return;
105            };
106            let wl_surface = match raw.as_raw() {
107                raw_window_handle::RawWindowHandle::Wayland(
108                    wayland_window_handle,
109                ) => {
110                    let res = unsafe {
111                        ObjectId::from_ptr(
112                            WlSurface::interface(),
113                            wayland_window_handle.surface.as_ptr().cast(),
114                        )
115                    };
116                    let Ok(id) = res else {
117                        log::error!(
118                            "Could not create WlSurface Id from window"
119                        );
120                        return;
121                    };
122                    let Ok(surface) = WlSurface::from_id(&conn, id) else {
123                        log::error!("Could not create WlSurface from Id");
124                        return;
125                    };
126                    surface
127                }
128
129                _ => {
130                    log::error!("Unexpected window handle type");
131                    return;
132                }
133            };
134            self.wayland.update_subsurfaces(id, &wl_surface);
135        }
136    }
137
138    pub(crate) fn create_surface(
139        &mut self,
140    ) -> Option<Box<dyn HasWindowHandle + Send + Sync + 'static>> {
141        #[cfg(all(feature = "wayland", target_os = "linux"))]
142        {
143            return self.wayland.create_surface();
144        }
145        None
146    }
147
148    pub(crate) fn update_surface_shm(
149        &mut self,
150        surface: &dyn HasWindowHandle,
151        width: u32,
152        height: u32,
153        scale: f64,
154        data: &[u8],
155        offset: Vector,
156    ) {
157        #[cfg(all(feature = "wayland", target_os = "linux"))]
158        {
159            return self.wayland.update_surface_shm(
160                surface, width, height, scale, data, offset,
161            );
162        }
163    }
164}
165
166pub type UserInterfaces<'a, P> = HashMap<
167    window::Id,
168    user_interface::UserInterface<
169        'a,
170        <P as Program>::Message,
171        <P as Program>::Theme,
172        <P as Program>::Renderer,
173    >,
174    rustc_hash::FxBuildHasher,
175>;
176
177pub(crate) fn handle_event<'a, P, C>(
178    e: Event,
179    events: &mut Vec<(Option<window::Id>, iced_runtime::core::Event)>,
180    platform_specific: &mut PlatformSpecific,
181    program: &'a P,
182    compositor: &mut C,
183    window_manager: &mut WindowManager<P, C>,
184    debug: &mut Debug,
185    user_interfaces: &mut UserInterfaces<'a, P>,
186    clipboard: &mut crate::Clipboard,
187    #[cfg(feature = "a11y")] adapters: &mut std::collections::HashMap<
188        window::Id,
189        (u64, iced_accessibility::accesskit_winit::Adapter),
190    >,
191) where
192    P: 'static + Program,
193    C: Compositor<Renderer = P::Renderer>,
194{
195    match e {
196        #[cfg(all(feature = "wayland", target_os = "linux"))]
197        Event::Wayland(e) => {
198            platform_specific.wayland.handle_event(
199                e,
200                events,
201                program,
202                compositor,
203                window_manager,
204                debug,
205                user_interfaces,
206                clipboard,
207                #[cfg(feature = "a11y")]
208                adapters,
209            );
210        }
211    }
212}