1use actuate_core::{prelude::*, Composer, Update, Updater};
2use std::{cell::RefCell, collections::HashMap, mem, rc::Rc, sync::mpsc, thread};
3use winit::{
4 application::ApplicationHandler,
5 event::{Event, WindowEvent},
6 event_loop::{ActiveEventLoop, EventLoop},
7 window::{Window as RawWindow, WindowAttributes, WindowId},
8};
9
10struct UnsafeUpdate(Update);
11
12unsafe impl Send for UnsafeUpdate {}
13
14struct EventLoopUpdater {
15 tx: mpsc::Sender<UnsafeUpdate>,
16}
17
18impl Updater for EventLoopUpdater {
19 fn update(&self, update: Update) {
20 if self.tx.send(UnsafeUpdate(update)).is_err() {
21 panic!("Failed to send update to event loop.");
22 }
23 }
24}
25
26struct HandlerRoot<C> {
27 content: C,
28 event_loop_cx: EventLoopContext,
29}
30
31unsafe impl<C: Data> Data for HandlerRoot<C> {
32 type Id = HandlerRoot<C::Id>;
33}
34
35impl<C: Compose> Compose for HandlerRoot<C> {
36 fn compose(cx: Scope<Self>) -> impl Compose {
37 use_provider(&cx, || cx.me().event_loop_cx.clone());
38
39 Ref::map(cx.me(), |me| &me.content)
40 }
41}
42
43struct Handler {
44 composer: Composer,
45 cx: EventLoopContext,
46}
47
48impl Handler {
49 fn compose(&mut self, event_loop: &ActiveEventLoop) {
50 self.cx.inner.borrow_mut().event_loop = Some(unsafe { mem::transmute(event_loop) });
51
52 self.composer.compose();
53
54 self.cx.inner.borrow_mut().event_loop = None;
55 }
56}
57
58impl ApplicationHandler<Vec<UnsafeUpdate>> for Handler {
59 fn resumed(&mut self, event_loop: &ActiveEventLoop) {
60 #[cfg(feature = "tracing")]
61 tracing::trace!("Resumed");
62
63 self.compose(event_loop);
64
65 for f in self.cx.inner.borrow_mut().handler_fns.values_mut() {
66 f(&Event::Resumed)
67 }
68 }
69
70 fn user_event(&mut self, event_loop: &ActiveEventLoop, events: Vec<UnsafeUpdate>) {
71 #[cfg(feature = "tracing")]
72 tracing::trace!("Update");
73
74 for event in events {
75 unsafe { event.0.apply() };
76 }
77
78 self.compose(event_loop);
79
80 for f in self.cx.inner.borrow_mut().handler_fns.values_mut() {
81 f(&Event::UserEvent(()))
82 }
83 }
84
85 fn window_event(
86 &mut self,
87 event_loop: &ActiveEventLoop,
88 window_id: WindowId,
89 event: WindowEvent,
90 ) {
91 self.compose(event_loop);
92
93 self.cx
94 .inner
95 .borrow_mut()
96 .handler_fns
97 .get_mut(&window_id)
98 .unwrap()(&Event::WindowEvent { window_id, event });
99 }
100}
101
102pub fn run(content: impl Compose + 'static) {
103 let event_loop = EventLoop::with_user_event().build().unwrap();
104
105 let proxy = event_loop.create_proxy();
106 let (tx, rx) = mpsc::channel();
107 thread::spawn(move || {
108 while let Ok(update) = rx.recv() {
109 let mut updates = vec![update];
110 while let Ok(next_update) = rx.try_recv() {
111 updates.push(next_update);
112 }
113
114 if proxy.send_event(updates).is_err() {
115 panic!("Failed to send update to event loop.");
116 }
117 }
118 });
119
120 let cx = EventLoopContext::default();
121
122 let mut handler = Handler {
123 composer: Composer::with_updater(
124 HandlerRoot {
125 content,
126 event_loop_cx: cx.clone(),
127 },
128 EventLoopUpdater { tx },
129 ),
130 cx,
131 };
132
133 event_loop.run_app(&mut handler).unwrap();
134}
135
136#[derive(Default)]
137struct Inner {
138 handler_fns: HashMap<WindowId, Rc<dyn Fn(&Event<()>)>>,
139 event_loop: Option<&'static ActiveEventLoop>,
140}
141
142#[derive(Clone, Default)]
143pub struct EventLoopContext {
144 inner: Rc<RefCell<Inner>>,
145}
146
147#[derive(Data)]
148pub struct Window<'a, C> {
149 window_attributes: WindowAttributes,
150 on_event: Box<dyn Fn(&RawWindow, &Event<()>) + 'a>,
151 content: C,
152}
153
154impl<'a, C> Window<'a, C> {
155 pub fn new(
156 window_attributes: WindowAttributes,
157 on_event: impl Fn(&RawWindow, &Event<()>) + 'a,
158 content: C,
159 ) -> Self {
160 Self {
161 window_attributes,
162 on_event: Box::new(on_event),
163 content,
164 }
165 }
166}
167
168impl<C: Compose> Compose for Window<'_, C> {
169 fn compose(cx: Scope<Self>) -> impl Compose {
170 let event_loop_cx = use_context::<EventLoopContext>(&cx).unwrap();
171 let mut inner = event_loop_cx.inner.borrow_mut();
172
173 let window = use_ref(&cx, || {
174 inner
175 .event_loop
176 .as_ref()
177 .unwrap()
178 .create_window(cx.me().window_attributes.clone())
179 .unwrap()
180 });
181
182 use_memo(&cx, cx.me().window_attributes.title.clone(), || {
183 window.set_title(&cx.me().window_attributes.title);
184 });
185
186 let drop_inner = event_loop_cx.inner.clone();
189 let id = window.id();
190 use_drop(&cx, move || {
191 drop_inner.borrow_mut().handler_fns.remove(&id);
192 });
193
194 let on_event = &*cx.me().on_event;
195 let on_event: Rc<dyn Fn(&Event<()>)> = Rc::new(move |event| on_event(window, event));
196 let on_event: Rc<dyn Fn(&Event<()>)> = unsafe { mem::transmute(on_event) };
197
198 inner.handler_fns.insert(id, on_event);
199
200 Ref::map(cx.me(), |me| &me.content)
202 }
203}