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 clear_subsurface_list(&mut self) {
69        #[cfg(all(feature = "wayland", target_os = "linux"))]
70        {
71            self.wayland.clear_subsurface_list();
72        }
73    }
74
75    pub(crate) fn update_subsurfaces(
76        &mut self,
77        id: window::Id,
78        window: &dyn HasWindowHandle,
79    ) {
80        #[cfg(all(feature = "wayland", target_os = "linux"))]
81        {
82            use cctk::sctk::reexports::client::{
83                protocol::wl_surface::WlSurface, Proxy,
84            };
85            use wayland_backend::client::ObjectId;
86
87            let Some(conn) = self.wayland.conn() else {
88                log::error!("No Wayland conn");
89                return;
90            };
91
92            let Ok(raw) = window.window_handle() else {
93                log::error!("Invalid window handle {id:?}");
94                return;
95            };
96            let wl_surface = match raw.as_raw() {
97                raw_window_handle::RawWindowHandle::Wayland(
98                    wayland_window_handle,
99                ) => {
100                    let res = unsafe {
101                        ObjectId::from_ptr(
102                            WlSurface::interface(),
103                            wayland_window_handle.surface.as_ptr().cast(),
104                        )
105                    };
106                    let Ok(id) = res else {
107                        log::error!(
108                            "Could not create WlSurface Id from window"
109                        );
110                        return;
111                    };
112                    let Ok(surface) = WlSurface::from_id(&conn, id) else {
113                        log::error!("Could not create WlSurface from Id");
114                        return;
115                    };
116                    surface
117                }
118
119                _ => {
120                    log::error!("Unexpected window handle type");
121                    return;
122                }
123            };
124            self.wayland.update_subsurfaces(id, &wl_surface);
125        }
126    }
127
128    pub(crate) fn create_surface(
129        &mut self,
130    ) -> Option<Box<dyn HasWindowHandle + Send + Sync + 'static>> {
131        #[cfg(all(feature = "wayland", target_os = "linux"))]
132        {
133            return self.wayland.create_surface();
134        }
135        None
136    }
137
138    pub(crate) fn update_surface_shm(
139        &mut self,
140        surface: &dyn HasWindowHandle,
141        width: u32,
142        height: u32,
143        scale: f64,
144        data: &[u8],
145        offset: Vector,
146    ) {
147        #[cfg(all(feature = "wayland", target_os = "linux"))]
148        {
149            return self.wayland.update_surface_shm(
150                surface, width, height, scale, data, offset,
151            );
152        }
153    }
154}
155
156pub type UserInterfaces<'a, P> = HashMap<
157    window::Id,
158    user_interface::UserInterface<
159        'a,
160        <P as Program>::Message,
161        <P as Program>::Theme,
162        <P as Program>::Renderer,
163    >,
164    rustc_hash::FxBuildHasher,
165>;
166
167pub(crate) fn handle_event<'a, P, C>(
168    e: Event,
169    events: &mut Vec<(Option<window::Id>, iced_runtime::core::Event)>,
170    platform_specific: &mut PlatformSpecific,
171    program: &'a P,
172    compositor: &mut C,
173    window_manager: &mut WindowManager<P, C>,
174    debug: &mut Debug,
175    user_interfaces: &mut UserInterfaces<'a, P>,
176    clipboard: &mut crate::Clipboard,
177    #[cfg(feature = "a11y")] adapters: &mut std::collections::HashMap<
178        window::Id,
179        (u64, iced_accessibility::accesskit_winit::Adapter),
180    >,
181) where
182    P: 'static + Program,
183    C: Compositor<Renderer = P::Renderer>,
184{
185    match e {
186        #[cfg(all(feature = "wayland", target_os = "linux"))]
187        Event::Wayland(e) => {
188            platform_specific.wayland.handle_event(
189                e,
190                events,
191                program,
192                compositor,
193                window_manager,
194                debug,
195                user_interfaces,
196                clipboard,
197                #[cfg(feature = "a11y")]
198                adapters,
199            );
200        }
201    }
202}