1use super::Composition;
16use super::composer::{Composer, EventCallback, ROOT};
17use super::seam::{Batch, Runtime};
18use super::{drain_graveyard, effects, state, with_composer};
19use crate::boundary::{Host, request_frame_from_worker};
20use crate::protocol::{HostEvent, ProtocolError};
21use crate::schema::{EventPayload, Theme};
22use crate::{KeyEvent, RangeRequest};
23use std::any::Any;
24use std::rc::Rc;
25use std::sync::Arc;
26
27pub struct Recomposer {
33 content: Rc<dyn Fn()>,
34 composition: Rc<Composition>,
35 _subscriptions: Vec<Box<dyn Any>>,
38}
39
40impl Recomposer {
41 pub fn new(content: impl Fn() + 'static) -> Self {
43 let composition = Composition::new();
44 let (window, design, permission) = {
45 let composer = composition.composer.borrow();
46 (
47 composer.ambient.window.clone(),
48 composer.ambient.design.clone(),
49 composer.ambient.permission.clone(),
50 )
51 };
52 let subscriptions: Vec<Box<dyn Any>> = vec![
56 Box::new(crate::window::subscribe(Arc::new(move || {
57 window.set(crate::window::window_size())
58 }))),
59 Box::new(crate::design::subscribe(Arc::new(move || {
60 design.set(crate::design::design_system())
61 }))),
62 Box::new(crate::notification::subscribe_permission(Arc::new(
63 move || permission.set(crate::notification::notification_permission()),
64 ))),
65 ];
66 Self {
67 content: Rc::new(content),
68 composition,
69 _subscriptions: subscriptions,
70 }
71 }
72
73 pub fn arena(&self) -> (*const u8, usize) {
75 self.composition.composer.borrow().writer.arena()
76 }
77
78 pub fn is_window(&self, node_id: u32) -> bool {
80 self.composition.composer.borrow().writer.is_window(node_id)
81 }
82
83 pub fn size_token(&self, node_id: u32) -> Option<u32> {
85 self.composition
86 .composer
87 .borrow()
88 .writer
89 .size_token(node_id)
90 }
91
92 pub fn rebuild(&mut self) {
94 let _composition = self.composition.enter();
95 with_composer(|composer| {
96 composer.abandon_composition();
97 composer.begin_root();
98 });
99 (self.content)();
100 with_composer(Composer::end_root);
101 self.after_composition();
102 }
103
104 pub fn render(&mut self, frame_time_nanos: Option<u64>) {
107 let _composition = self.composition.enter();
108 if let Some(now) = frame_time_nanos {
109 with_composer(|composer| composer.executor.deliver_frame(now));
110 }
111 effects::poll_woken();
112 self.recompose();
113 }
114
115 pub fn handle_event(&mut self, event: &HostEvent<'_>) -> Result<i64, ProtocolError> {
121 let _composition = self.composition.enter();
122 let Some((node, callback)) = with_composer(|composer| {
123 composer
124 .handlers
125 .get(&event.handler_id)
126 .map(|entry| (entry.node, entry.callback.clone()))
127 })
128 .flatten() else {
129 return Err(ProtocolError::InvalidValueKind(0));
130 };
131 if node != event.node_id {
132 return Err(ProtocolError::InvalidValueKind(0));
133 }
134 let window = with_composer(|composer| composer.writer.window_of(node)).unwrap_or(0);
137 let _window = crate::windows::DispatchWindow::enter(window);
138 deliver(&callback, &event.payload)
139 }
140
141 pub fn run_in_context(&mut self, action: &mut dyn FnMut()) {
145 let _composition = self.composition.enter();
146 action();
147 }
148
149 fn recompose(&mut self) {
156 with_composer(Composer::abandon_composition);
157 state::apply_state_changes();
158 let root = with_composer(|composer| composer.root_invalid()).unwrap_or(false);
159 if root {
160 with_composer(Composer::begin_root);
161 (self.content)();
162 with_composer(Composer::end_root);
163 }
164 let invalid = with_composer(Composer::take_invalid).unwrap_or_default();
165 for group in invalid {
166 if group == ROOT {
167 continue;
168 }
169 let restart = with_composer(|composer| composer.prepare_restart(group)).flatten();
170 if let Some(restart) = restart {
171 restart();
172 with_composer(Composer::finish_restart);
173 }
174 }
175 self.after_composition();
176 }
177
178 fn after_composition(&mut self) {
179 with_composer(|composer| {
182 for window in composer.writer.take_forgotten_windows() {
183 if let Some(entry) = composer.ambient.windows.remove(&window) {
184 composer.graveyard.push(Box::new(entry));
185 }
186 }
187 });
188 drain_graveyard();
189 effects::apply_effects();
190 drain_graveyard();
191 effects::poll_woken();
192 let pending = with_composer(|composer| {
195 !composer
196 .signal
197 .dirty
198 .lock()
199 .unwrap_or_else(|poison| poison.into_inner())
200 .is_empty()
201 || !composer.invalid.is_empty()
202 })
203 .unwrap_or(false);
204 if pending {
205 request_frame_from_worker();
206 }
207 }
208}
209
210pub struct ComposeHost(Host);
217
218impl ComposeHost {
219 pub fn new(content: fn()) -> Self {
221 Self(Host::new(recomposer_for(content)))
222 }
223
224 pub fn with_theme(content: fn(), theme: Theme) -> Self {
226 Self(Host::with_theme(recomposer_for(content), theme))
227 }
228
229 pub fn with_window(mut self, window: crate::schema::Window) -> Self {
232 self.0.set_window(window);
233 self
234 }
235
236 pub fn with_content(content: impl Fn() + Send + Sync + 'static) -> Self {
240 let content = Arc::new(content);
241 Self(Host::new(move || {
242 let content = Arc::clone(&content);
243 Box::new(Recomposer::new(move || content())) as Box<dyn Runtime>
244 }))
245 }
246}
247
248impl std::ops::Deref for ComposeHost {
249 type Target = Host;
250
251 fn deref(&self) -> &Host {
252 &self.0
253 }
254}
255
256impl std::ops::DerefMut for ComposeHost {
257 fn deref_mut(&mut self) -> &mut Host {
258 &mut self.0
259 }
260}
261
262pub fn recomposer_for(content: fn()) -> impl Fn() -> Box<dyn Runtime> + Send + Sync + 'static {
265 move || Box::new(Recomposer::new(content)) as Box<dyn Runtime>
266}
267
268impl crate::LaunchBuilder {
269 pub fn launch(self, content: fn()) {
283 self.launch_runtime(recomposer_for(content));
284 }
285
286 pub fn try_launch(self, content: fn()) -> i32 {
289 self.try_launch_runtime(recomposer_for(content))
290 }
291
292 pub fn application(self, content: fn()) {
294 self.launch(content);
295 }
296}
297
298pub fn launch(content: fn()) {
313 crate::LaunchBuilder::new().launch(content);
314}
315
316pub fn application(content: fn()) {
318 launch(content);
319}
320
321fn deliver(callback: &EventCallback, payload: &EventPayload<'_>) -> Result<i64, ProtocolError> {
323 match (callback, payload) {
324 (
325 EventCallback::Unit(handler),
326 EventPayload::Clicked | EventPayload::FocusLost | EventPayload::FilesEntered,
327 ) => (*handler.borrow_mut())(),
328 (EventCallback::Text(handler), EventPayload::TextChanged(text))
329 | (EventCallback::Text(handler), EventPayload::TextSubmitted(text)) => {
330 (*handler.borrow_mut())((*text).to_owned())
331 }
332 (
333 EventCallback::Key(handler),
334 EventPayload::KeyDown {
335 key,
336 shift_key,
337 ctrl_key,
338 alt_key,
339 meta_key,
340 },
341 ) => {
342 let event = KeyEvent::new(*key, *shift_key, *ctrl_key, *alt_key, *meta_key);
343 (*handler.borrow_mut())(event.clone());
344 return Ok(i64::from(event.consumed()));
345 }
346 (
347 EventCallback::Pointer(handler),
348 EventPayload::Pointer {
349 kind,
350 pointer_id,
351 pointer_type,
352 x,
353 y,
354 buttons,
355 button,
356 modifiers,
357 click_count,
358 delta_x,
359 delta_y,
360 delta_mode,
361 timestamp_nanos,
362 },
363 ) => {
364 let event = crate::PointerEvent::new(
365 *kind,
366 *pointer_id,
367 *pointer_type,
368 *x,
369 *y,
370 *buttons,
371 *button,
372 *modifiers,
373 *click_count,
374 *delta_x,
375 *delta_y,
376 *delta_mode,
377 *timestamp_nanos,
378 );
379 (*handler.borrow_mut())(event.clone());
380 return Ok(i64::from(event.consumed()));
381 }
382 (EventCallback::Value(handler), EventPayload::ValueChanged(value)) => {
383 (*handler.borrow_mut())(*value)
384 }
385 (EventCallback::Range(handler), EventPayload::RangeRequested { start, count }) => {
386 (*handler.borrow_mut())(RangeRequest::new(*start, *count))
387 }
388 (EventCallback::Files(handler), EventPayload::FilesDropped(paths)) => {
389 (*handler.borrow_mut())(crate::FileDrop::new(paths))
390 }
391 (EventCallback::Window(handler), payload) => {
392 let Some(event) = crate::windows::WindowEvent::from_payload(payload) else {
393 return Err(ProtocolError::InvalidValueKind(0));
394 };
395 (*handler.borrow_mut())(event)
396 }
397 _ => return Err(ProtocolError::InvalidValueKind(0)),
398 }
399 Ok(0)
400}
401
402impl Composer {
403 pub(crate) fn abandon_composition(&mut self) {
405 self.clear_walk();
406 }
407}
408
409impl Runtime for Recomposer {
410 fn batch(&self) -> &Batch {
411 let composer = self.composition.composer.as_ptr();
412 unsafe { (*composer).writer.batch() }
416 }
417
418 fn batch_mut(&mut self) -> &mut Batch {
419 let composer = self.composition.composer.as_ptr();
420 unsafe { (*composer).writer.batch_mut() }
422 }
423
424 fn rebuild(&mut self) {
425 Recomposer::rebuild(self);
426 }
427
428 fn render(&mut self, frame_time_nanos: Option<u64>) {
429 Recomposer::render(self, frame_time_nanos);
430 }
431
432 fn handle_event(&mut self, event: &HostEvent<'_>) -> Result<i64, ProtocolError> {
433 Recomposer::handle_event(self, event)
434 }
435
436 fn size_token(&self, node_id: u32) -> Option<u32> {
437 Recomposer::size_token(self, node_id)
438 }
439
440 fn is_window(&self, node_id: u32) -> bool {
441 Recomposer::is_window(self, node_id)
442 }
443
444 fn run_in_context(&mut self, action: &mut dyn FnMut()) {
445 Recomposer::run_in_context(self, action);
446 }
447}