actuate_winit/
lib.rs

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        // TODO react to more attributes
187
188        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        // Safety: The pointer to `me.content` is guranteed to remain constant.
201        Ref::map(cx.me(), |me| &me.content)
202    }
203}