1use blitz_traits::navigation::NavigationOptions;
2use blitz_traits::net::NetWaker;
3use futures_util::task::ArcWake;
4use std::sync::mpsc::{Receiver, Sender, channel};
5use std::{any::Any, sync::Arc};
6use winit::{event_loop::EventLoopProxy, window::WindowId};
7
8#[cfg(feature = "accessibility")]
9use accesskit_xplat::WindowEvent as AccessKitEvent;
10
11#[derive(Debug, Clone)]
12pub enum BlitzShellEvent {
13 Poll {
14 window_id: WindowId,
15 },
16
17 RequestRedraw {
18 doc_id: usize,
19 },
20
21 #[cfg(feature = "accessibility")]
23 Accessibility {
24 window_id: WindowId,
25 data: Arc<AccessKitEvent>,
26 },
27
28 Embedder(Arc<dyn Any + Send + Sync>),
30
31 Navigate(Box<NavigationOptions>),
33
34 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}
48
49#[derive(Clone)]
50pub struct BlitzShellProxy(Arc<BlitzShellProxyInner>);
51pub struct BlitzShellProxyInner {
52 winit_proxy: EventLoopProxy,
53 sender: Sender<BlitzShellEvent>,
54}
55
56impl BlitzShellProxy {
57 pub fn new(winit_proxy: EventLoopProxy) -> (Self, Receiver<BlitzShellEvent>) {
58 let (sender, receiver) = channel();
59 let proxy = Self(Arc::new(BlitzShellProxyInner {
60 winit_proxy,
61 sender,
62 }));
63 (proxy, receiver)
64 }
65
66 pub fn wake_up(&self) {
67 self.0.winit_proxy.wake_up();
68 }
69 pub fn send_event(&self, event: impl Into<BlitzShellEvent>) {
70 self.send_event_impl(event.into());
71 }
72 fn send_event_impl(&self, event: BlitzShellEvent) {
73 let _ = self.0.sender.send(event);
74 self.wake_up();
75 }
76}
77
78impl NetWaker for BlitzShellProxy {
79 fn wake(&self, client_id: usize) {
80 self.send_event_impl(BlitzShellEvent::RequestRedraw { doc_id: client_id })
81 }
82}
83
84pub fn create_waker(proxy: &BlitzShellProxy, id: WindowId) -> std::task::Waker {
90 struct DomHandle {
91 proxy: BlitzShellProxy,
92 id: WindowId,
93 }
94 impl ArcWake for DomHandle {
95 fn wake_by_ref(arc_self: &Arc<Self>) {
96 let event = BlitzShellEvent::Poll {
97 window_id: arc_self.id,
98 };
99 arc_self.proxy.send_event(event)
100 }
101 }
102
103 let proxy = proxy.clone();
104 futures_util::task::waker(Arc::new(DomHandle { id, proxy }))
105}