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