blitz_shell/
event.rs

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