blitz_shell/
event.rs

1use futures_util::task::ArcWake;
2use std::{any::Any, sync::Arc};
3use winit::{event_loop::EventLoopProxy, window::WindowId};
4
5#[cfg(feature = "accessibility")]
6use accesskit_winit::{Event as AccessKitEvent, WindowEvent as AccessKitWindowEvent};
7use blitz_dom::net::Resource;
8
9#[derive(Debug, Clone)]
10pub enum BlitzShellEvent {
11    Poll {
12        window_id: WindowId,
13    },
14
15    ResourceLoad {
16        doc_id: usize,
17        data: Resource,
18    },
19
20    /// An accessibility event from `accesskit`.
21    #[cfg(feature = "accessibility")]
22    Accessibility {
23        window_id: WindowId,
24        data: Arc<AccessKitWindowEvent>,
25    },
26
27    /// An arbitary event from the Blitz embedder
28    Embedder(Arc<dyn Any + Send + Sync>),
29
30    /// Navigate to another URL (triggered by e.g. clicking a link)
31    Navigate(String),
32}
33impl BlitzShellEvent {
34    pub fn embedder_event<T: Any + Send + Sync>(value: T) -> Self {
35        let boxed = Arc::new(value) as Arc<dyn Any + Send + Sync>;
36        Self::Embedder(boxed)
37    }
38}
39impl From<(usize, Resource)> for BlitzShellEvent {
40    fn from((doc_id, data): (usize, Resource)) -> Self {
41        BlitzShellEvent::ResourceLoad { doc_id, data }
42    }
43}
44
45#[cfg(feature = "accessibility")]
46impl From<AccessKitEvent> for BlitzShellEvent {
47    fn from(value: AccessKitEvent) -> Self {
48        Self::Accessibility {
49            window_id: value.window_id,
50            data: Arc::new(value.window_event),
51        }
52    }
53}
54
55/// Create a waker that will send a poll event to the event loop.
56///
57/// This lets the VirtualDom "come up for air" and process events while the main thread is blocked by the WebView.
58///
59/// All other IO lives in the Tokio runtime,
60pub fn create_waker(proxy: &EventLoopProxy<BlitzShellEvent>, id: WindowId) -> std::task::Waker {
61    struct DomHandle {
62        proxy: EventLoopProxy<BlitzShellEvent>,
63        id: WindowId,
64    }
65
66    // this should be implemented by most platforms, but ios is missing this until
67    // https://github.com/tauri-apps/wry/issues/830 is resolved
68    unsafe impl Send for DomHandle {}
69    unsafe impl Sync for DomHandle {}
70
71    impl ArcWake for DomHandle {
72        fn wake_by_ref(arc_self: &Arc<Self>) {
73            _ = arc_self.proxy.send_event(BlitzShellEvent::Poll {
74                window_id: arc_self.id,
75            })
76        }
77    }
78
79    futures_util::task::waker(Arc::new(DomHandle {
80        id,
81        proxy: proxy.clone(),
82    }))
83}