1use blitz_traits::navigation::NavigationOptions;
2use blitz_traits::net::NetWaker;
3use futures_util::task::ArcWake;
4use std::sync::atomic::{AtomicBool, Ordering};
5use std::sync::mpsc::{Receiver, Sender, channel};
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
71#[derive(Clone)]
72pub struct BlitzShellProxy(Arc<BlitzShellProxyInner>);
73pub struct BlitzShellProxyInner {
74 winit_proxy: EventLoopProxy,
75 sender: Sender<BlitzShellEvent>,
76}
77
78impl BlitzShellProxy {
79 pub fn new(winit_proxy: EventLoopProxy) -> (Self, Receiver<BlitzShellEvent>) {
80 let (sender, receiver) = channel();
81 let proxy = Self(Arc::new(BlitzShellProxyInner {
82 winit_proxy,
83 sender,
84 }));
85 (proxy, receiver)
86 }
87
88 pub fn wake_up(&self) {
89 self.0.winit_proxy.wake_up();
90 }
91 pub fn send_event(&self, event: impl Into<BlitzShellEvent>) {
92 self.send_event_impl(event.into());
93 }
94 fn send_event_impl(&self, event: BlitzShellEvent) {
95 let _ = self.0.sender.send(event);
96 self.wake_up();
97 }
98}
99
100impl NetWaker for BlitzShellProxy {
101 fn wake(&self, client_id: usize) {
102 self.send_event_impl(BlitzShellEvent::RequestRedraw { doc_id: client_id })
103 }
104}
105
106pub fn create_waker(proxy: &BlitzShellProxy, poll_requested: Arc<AtomicBool>) -> std::task::Waker {
117 struct DomHandle {
118 proxy: BlitzShellProxy,
119 poll_requested: Arc<AtomicBool>,
120 }
121 impl ArcWake for DomHandle {
122 fn wake_by_ref(arc_self: &Arc<Self>) {
123 arc_self.poll_requested.store(true, Ordering::Release);
124 arc_self.proxy.wake_up();
125 }
126 }
127
128 let proxy = proxy.clone();
129 futures_util::task::waker(Arc::new(DomHandle {
130 poll_requested,
131 proxy,
132 }))
133}