1use blitz_traits::handoff::{EventQueue, EventTarget};
2use blitz_traits::navigation::NavigationOptions;
3use blitz_traits::net::NetWaker;
4use futures_util::task::ArcWake;
5use std::sync::atomic::{AtomicBool, Ordering};
6use std::{any::Any, sync::Arc};
7use winit::{event_loop::EventLoopProxy, window::WindowId};
8
9#[cfg(feature = "accessibility")]
10use accesskit_xplat::WindowEvent as AccessKitEvent;
11
12#[derive(Debug, Clone)]
13pub enum BlitzShellEvent {
14 Poll {
15 window_id: WindowId,
16 },
17
18 ResumeReady {
22 window_id: WindowId,
23 },
24
25 RequestRedraw {
26 doc_id: usize,
27 },
28
29 CloseWindow {
32 window_id: WindowId,
33 },
34
35 #[cfg(feature = "accessibility")]
37 Accessibility {
38 window_id: WindowId,
39 data: Arc<AccessKitEvent>,
40 },
41
42 Embedder(Arc<dyn Any + Send + Sync>),
44
45 Navigate(Box<NavigationOptions>),
47
48 NavigationLoad {
50 url: String,
51 contents: String,
52 retain_scroll_position: bool,
53 is_md: bool,
54 },
55
56 #[cfg(target_arch = "wasm32")]
60 ResizeSettleCheck {
61 window_id: WindowId,
62 },
63}
64impl BlitzShellEvent {
65 pub fn embedder_event<T: Any + Send + Sync>(value: T) -> Self {
66 let boxed = Arc::new(value) as Arc<dyn Any + Send + Sync>;
67 Self::Embedder(boxed)
68 }
69}
70
71pub type BlitzShellEventQueue = EventQueue<BlitzShellEvent>;
72
73#[derive(Clone)]
74pub struct BlitzShellProxy(Arc<BlitzShellProxyInner>);
75pub struct BlitzShellProxyInner {
76 winit_proxy: EventLoopProxy,
77 target: EventTarget<BlitzShellEvent>,
78}
79
80impl BlitzShellProxy {
81 pub fn new(winit_proxy: EventLoopProxy) -> (Self, BlitzShellEventQueue) {
82 let wake_proxy = winit_proxy.clone();
83 let queue = EventQueue::new(move || wake_proxy.wake_up());
84 let proxy = Self(Arc::new(BlitzShellProxyInner {
85 winit_proxy,
86 target: queue.target(),
87 }));
88 (proxy, queue)
89 }
90
91 pub fn wake_up(&self) {
92 self.0.winit_proxy.wake_up();
93 }
94 pub fn send_event(&self, event: impl Into<BlitzShellEvent>) {
95 self.send_event_impl(event.into());
96 }
97 fn send_event_impl(&self, event: BlitzShellEvent) {
98 let _ = self.0.target.publish(Arc::new(event));
99 }
100}
101
102impl NetWaker for BlitzShellProxy {
103 fn wake(&self, client_id: usize) {
104 self.send_event_impl(BlitzShellEvent::RequestRedraw { doc_id: client_id })
105 }
106}
107
108pub fn create_waker(proxy: &BlitzShellProxy, poll_requested: Arc<AtomicBool>) -> std::task::Waker {
119 struct DomHandle {
120 proxy: BlitzShellProxy,
121 poll_requested: Arc<AtomicBool>,
122 }
123 impl ArcWake for DomHandle {
124 fn wake_by_ref(arc_self: &Arc<Self>) {
125 arc_self.poll_requested.store(true, Ordering::Release);
126 arc_self.proxy.wake_up();
127 }
128 }
129
130 let proxy = proxy.clone();
131 futures_util::task::waker(Arc::new(DomHandle {
132 poll_requested,
133 proxy,
134 }))
135}