dioxus_native/
dioxus_application.rs1use blitz_shell::{BlitzApplication, View};
2use dioxus_core::{provide_context, ScopeId};
3use dioxus_history::{History, MemoryHistory};
4use std::rc::Rc;
5use winit::application::ApplicationHandler;
6use winit::event::{StartCause, WindowEvent};
7use winit::event_loop::{ActiveEventLoop, EventLoopProxy};
8use winit::window::WindowId;
9
10use crate::DioxusNativeWindowRenderer;
11use crate::{contexts::DioxusNativeDocument, BlitzShellEvent, DioxusDocument, WindowConfig};
12
13pub enum DioxusNativeEvent {
15 #[cfg(all(
17 feature = "hot-reload",
18 debug_assertions,
19 not(target_os = "android"),
20 not(target_os = "ios")
21 ))]
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 proxy: EventLoopProxy<BlitzShellEvent>,
39}
40
41impl DioxusNativeApplication {
42 pub fn new(
43 proxy: EventLoopProxy<BlitzShellEvent>,
44 config: WindowConfig<DioxusNativeWindowRenderer>,
45 ) -> Self {
46 Self {
47 pending_window: Some(config),
48 inner: BlitzApplication::new(proxy.clone()),
49 proxy,
50 }
51 }
52
53 pub fn add_window(&mut self, window_config: WindowConfig<DioxusNativeWindowRenderer>) {
54 self.inner.add_window(window_config);
55 }
56
57 fn handle_blitz_shell_event(
58 &mut self,
59 event_loop: &ActiveEventLoop,
60 event: &DioxusNativeEvent,
61 ) {
62 match event {
63 #[cfg(all(
64 feature = "hot-reload",
65 debug_assertions,
66 not(target_os = "android"),
67 not(target_os = "ios")
68 ))]
69 DioxusNativeEvent::DevserverEvent(event) => match event {
70 dioxus_devtools::DevserverMsg::HotReload(hotreload_message) => {
71 for window in self.inner.windows.values_mut() {
72 let doc = window.downcast_doc_mut::<DioxusDocument>();
73
74 dioxus_devtools::apply_changes(&doc.vdom, hotreload_message);
76
77 for asset_path in &hotreload_message.assets {
79 if let Some(url) = asset_path.to_str() {
80 doc.reload_resource_by_href(url);
81 }
82 }
83
84 window.poll();
85 }
86 }
87 dioxus_devtools::DevserverMsg::Shutdown => event_loop.exit(),
88 dioxus_devtools::DevserverMsg::FullReloadStart => {}
89 dioxus_devtools::DevserverMsg::FullReloadFailed => {}
90 dioxus_devtools::DevserverMsg::FullReloadCommand => {}
91 _ => {}
92 },
93
94 DioxusNativeEvent::CreateHeadElement {
95 name,
96 attributes,
97 contents,
98 window,
99 } => {
100 if let Some(window) = self.inner.windows.get_mut(window) {
101 let doc = window.downcast_doc_mut::<DioxusDocument>();
102 doc.create_head_element(name, attributes, contents);
103 window.poll();
104 }
105 }
106
107 #[cfg(not(all(
109 feature = "hot-reload",
110 debug_assertions,
111 not(target_os = "android"),
112 not(target_os = "ios")
113 )))]
114 _ => {
115 let _ = event_loop;
116 let _ = event;
117 }
118 }
119 }
120}
121
122impl ApplicationHandler<BlitzShellEvent> for DioxusNativeApplication {
123 fn resumed(&mut self, event_loop: &ActiveEventLoop) {
124 #[cfg(feature = "tracing")]
125 tracing::debug!("Injecting document provider into all windows");
126
127 if let Some(config) = self.pending_window.take() {
128 let mut window = View::init(config, event_loop, &self.proxy);
129 let renderer = window.renderer.clone();
130 let window_id = window.window_id();
131 let doc = window.downcast_doc_mut::<DioxusDocument>();
132
133 doc.vdom.in_scope(ScopeId::ROOT, || {
134 let shared: Rc<dyn dioxus_document::Document> =
135 Rc::new(DioxusNativeDocument::new(self.proxy.clone(), window_id));
136 provide_context(shared);
137 });
138
139 let history_provider: Rc<dyn History> = Rc::new(MemoryHistory::default());
141 doc.vdom
142 .in_scope(ScopeId::ROOT, move || provide_context(history_provider));
143
144 doc.vdom
146 .in_scope(ScopeId::ROOT, move || provide_context(renderer));
147
148 doc.initial_build();
150
151 window.request_redraw();
153
154 self.inner.windows.insert(window_id, window);
156 }
157
158 self.inner.resumed(event_loop);
159 }
160
161 fn suspended(&mut self, event_loop: &ActiveEventLoop) {
162 self.inner.suspended(event_loop);
163 }
164
165 fn new_events(&mut self, event_loop: &ActiveEventLoop, cause: StartCause) {
166 self.inner.new_events(event_loop, cause);
167 }
168
169 fn window_event(
170 &mut self,
171 event_loop: &ActiveEventLoop,
172 window_id: WindowId,
173 event: WindowEvent,
174 ) {
175 self.inner.window_event(event_loop, window_id, event);
176 }
177
178 fn user_event(&mut self, event_loop: &ActiveEventLoop, event: BlitzShellEvent) {
179 match event {
180 BlitzShellEvent::Embedder(event) => {
181 if let Some(event) = event.downcast_ref::<DioxusNativeEvent>() {
182 self.handle_blitz_shell_event(event_loop, event);
183 }
184 }
185 event => self.inner.user_event(event_loop, event),
186 }
187 }
188}