dioxus_native/
dioxus_application.rs1use blitz_shell::{BlitzApplication, BlitzShellProxy, View};
2use dioxus_core::{ScopeId, provide_context};
3use dioxus_history::{History, MemoryHistory};
4use std::rc::Rc;
5use std::sync::Arc;
6use winit::application::ApplicationHandler;
7use winit::event::{StartCause, WindowEvent};
8use winit::event_loop::ActiveEventLoop;
9use winit::window::WindowId;
10
11#[cfg(target_os = "macos")]
12use winit::platform::macos::ApplicationHandlerExtMacOS;
13
14use crate::DioxusNativeWindowRenderer;
15use crate::event_handlers::WindowEventHandlers;
16use crate::{BlitzShellEvent, DioxusDocument, WindowConfig, contexts::DioxusNativeDocument};
17
18pub enum DioxusNativeEvent {
20 #[cfg(all(feature = "hot-reload", debug_assertions))]
22 DevserverEvent(dioxus_devtools::DevserverMsg),
23
24 CreateHeadElement {
28 window: WindowId,
29 name: String,
30 attributes: Vec<(String, String)>,
31 contents: Option<String>,
32 },
33}
34
35pub struct DioxusNativeApplication {
36 pending_window: Option<WindowConfig<DioxusNativeWindowRenderer>>,
37 inner: BlitzApplication<DioxusNativeWindowRenderer>,
38 event_handlers: Rc<WindowEventHandlers>,
39}
40
41impl DioxusNativeApplication {
42 pub fn new(
43 proxy: BlitzShellProxy,
44 event_queue: std::sync::mpsc::Receiver<BlitzShellEvent>,
45 config: WindowConfig<DioxusNativeWindowRenderer>,
46 ) -> Self {
47 Self {
48 pending_window: Some(config),
49 inner: BlitzApplication::new(proxy, event_queue),
50 event_handlers: Rc::new(WindowEventHandlers::default()),
51 }
52 }
53
54 pub fn add_window(&mut self, window_config: WindowConfig<DioxusNativeWindowRenderer>) {
55 self.inner.add_window(window_config);
56 }
57
58 fn handle_dioxus_native_event(
59 &mut self,
60 event_loop: &dyn ActiveEventLoop,
61 event: &DioxusNativeEvent,
62 ) {
63 match event {
64 #[cfg(all(feature = "hot-reload", debug_assertions))]
65 DioxusNativeEvent::DevserverEvent(event) => match event {
66 dioxus_devtools::DevserverMsg::HotReload(hotreload_message) => {
67 for window in self.inner.windows.values_mut() {
68 let doc = window.downcast_doc_mut::<DioxusDocument>();
69
70 dioxus_devtools::apply_changes(&doc.vdom, hotreload_message);
72
73 for asset_path in &hotreload_message.assets {
75 if let Some(url) = asset_path.to_str() {
76 doc.inner.borrow_mut().reload_resource_by_href(url);
77 }
78 }
79
80 window.poll();
81 }
82 }
83 dioxus_devtools::DevserverMsg::Shutdown => event_loop.exit(),
84 dioxus_devtools::DevserverMsg::FullReloadStart => {}
85 dioxus_devtools::DevserverMsg::FullReloadFailed => {}
86 dioxus_devtools::DevserverMsg::FullReloadCommand => {}
87 _ => {}
88 },
89
90 DioxusNativeEvent::CreateHeadElement {
91 name,
92 attributes,
93 contents,
94 window,
95 } => {
96 if let Some(window) = self.inner.windows.get_mut(window) {
97 let doc = window.downcast_doc_mut::<DioxusDocument>();
98 doc.create_head_element(name, attributes, contents);
99 window.poll();
100 }
101 }
102
103 #[cfg(not(all(feature = "hot-reload", debug_assertions)))]
105 #[allow(unreachable_patterns)]
106 _ => {
107 let _ = event_loop;
108 let _ = event;
109 }
110 }
111 }
112}
113
114impl ApplicationHandler for DioxusNativeApplication {
115 #[cfg(target_os = "macos")]
116 fn macos_handler(&mut self) -> Option<&mut dyn ApplicationHandlerExtMacOS> {
117 self.inner.macos_handler()
118 }
119
120 fn resumed(&mut self, event_loop: &dyn ActiveEventLoop) {
121 self.inner.resumed(event_loop);
122 }
123
124 fn suspended(&mut self, event_loop: &dyn ActiveEventLoop) {
125 self.inner.suspended(event_loop);
126 }
127
128 fn destroy_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) {
129 self.inner.destroy_surfaces(event_loop);
130 }
131
132 fn about_to_wait(&mut self, event_loop: &dyn ActiveEventLoop) {
133 self.inner.about_to_wait(event_loop);
134 }
135
136 fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) {
137 #[cfg(feature = "tracing")]
138 tracing::debug!("Injecting document provider into all windows");
139
140 if let Some(config) = self.pending_window.take() {
141 let mut window = View::init(config, event_loop, &self.inner.proxy);
142 let winit_window = Arc::clone(&window.window);
143 let renderer = window.renderer.clone();
144 let window_id = window.window_id();
145 let doc = window.downcast_doc_mut::<DioxusDocument>();
146
147 doc.vdom.in_scope(ScopeId::ROOT, || {
148 let shared: Rc<dyn dioxus_document::Document> = Rc::new(DioxusNativeDocument::new(
149 self.inner.proxy.clone(),
150 window_id,
151 ));
152 provide_context(shared);
153 provide_context(self.event_handlers.clone());
154 });
155
156 let shell_provider = doc.inner.borrow().shell_provider.clone();
158 doc.vdom
159 .in_scope(ScopeId::ROOT, move || provide_context(shell_provider));
160
161 let history_provider: Rc<dyn History> = Rc::new(MemoryHistory::default());
163 doc.vdom
164 .in_scope(ScopeId::ROOT, move || provide_context(history_provider));
165
166 doc.vdom
168 .in_scope(ScopeId::ROOT, move || provide_context(renderer));
169
170 doc.vdom
172 .in_scope(ScopeId::ROOT, move || provide_context(winit_window));
173
174 doc.initial_build();
176
177 window.request_redraw();
179
180 self.inner.windows.insert(window_id, window);
182 }
183
184 self.inner.can_create_surfaces(event_loop);
185 }
186
187 fn new_events(&mut self, event_loop: &dyn ActiveEventLoop, cause: StartCause) {
188 self.inner.new_events(event_loop, cause);
189 }
190
191 fn window_event(
192 &mut self,
193 event_loop: &dyn ActiveEventLoop,
194 window_id: WindowId,
195 event: WindowEvent,
196 ) {
197 self.event_handlers
198 .apply_event(window_id, &event, event_loop);
199 self.inner.window_event(event_loop, window_id, event);
200 }
201
202 fn proxy_wake_up(&mut self, event_loop: &dyn ActiveEventLoop) {
203 while let Ok(event) = self.inner.event_queue.try_recv() {
204 match event {
205 BlitzShellEvent::Embedder(event) => {
206 if let Some(event) = event.downcast_ref::<DioxusNativeEvent>() {
207 self.handle_dioxus_native_event(event_loop, event);
208 }
209 }
210 event => self.inner.handle_blitz_shell_event(event_loop, event),
211 }
212 }
213 }
214}