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,
48 composer.ambient.design,
49 composer.ambient.permission,
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 with_composer(Composer::flush_focus_requests);
195 let pending = with_composer(|composer| {
198 !composer
199 .signal
200 .dirty
201 .lock()
202 .unwrap_or_else(|poison| poison.into_inner())
203 .is_empty()
204 || !composer.invalid.is_empty()
205 })
206 .unwrap_or(false);
207 if pending {
208 request_frame_from_worker();
209 }
210 }
211}
212
213pub struct ComposeHost(Host);
220
221impl ComposeHost {
222 pub fn new(content: fn()) -> Self {
224 Self(Host::new(recomposer_for(content)))
225 }
226
227 pub fn with_theme(content: fn(), theme: Theme) -> Self {
229 Self(Host::with_theme(recomposer_for(content), theme))
230 }
231
232 pub fn with_window(mut self, window: crate::schema::Window) -> Self {
235 self.0.set_window(window);
236 self
237 }
238
239 pub fn with_content(content: impl Fn() + Send + Sync + 'static) -> Self {
243 let content = Arc::new(content);
244 Self(Host::new(move || {
245 let content = Arc::clone(&content);
246 Box::new(Recomposer::new(move || content())) as Box<dyn Runtime>
247 }))
248 }
249}
250
251impl std::ops::Deref for ComposeHost {
252 type Target = Host;
253
254 fn deref(&self) -> &Host {
255 &self.0
256 }
257}
258
259impl std::ops::DerefMut for ComposeHost {
260 fn deref_mut(&mut self) -> &mut Host {
261 &mut self.0
262 }
263}
264
265pub fn recomposer_for(content: fn()) -> impl Fn() -> Box<dyn Runtime> + Send + Sync + 'static {
268 move || Box::new(Recomposer::new(content)) as Box<dyn Runtime>
269}
270
271impl crate::LaunchBuilder {
272 pub fn launch(self, content: fn()) {
286 self.launch_runtime(recomposer_for(content));
287 }
288
289 pub fn try_launch(self, content: fn()) -> i32 {
292 self.try_launch_runtime(recomposer_for(content))
293 }
294
295 pub fn application(self, content: fn()) {
297 self.launch(content);
298 }
299}
300
301pub fn launch(content: fn()) {
316 crate::LaunchBuilder::new().launch(content);
317}
318
319pub fn application(content: fn()) {
321 launch(content);
322}
323
324fn deliver(callback: &EventCallback, payload: &EventPayload<'_>) -> Result<i64, ProtocolError> {
326 match (callback, payload) {
327 (
328 EventCallback::Unit(handler),
329 EventPayload::Clicked
330 | EventPayload::FocusLost
331 | EventPayload::FocusGained
332 | EventPayload::FilesEntered,
333 ) => (*handler.borrow_mut())(),
334 (EventCallback::Text(handler), EventPayload::TextChanged(text))
335 | (EventCallback::Text(handler), EventPayload::TextSubmitted(text)) => {
336 (*handler.borrow_mut())((*text).to_owned())
337 }
338 (
339 EventCallback::Key(handler),
340 EventPayload::KeyDown {
341 key,
342 shift_key,
343 ctrl_key,
344 alt_key,
345 meta_key,
346 repeat,
347 code,
348 text,
349 }
350 | EventPayload::KeyUp {
351 key,
352 shift_key,
353 ctrl_key,
354 alt_key,
355 meta_key,
356 repeat,
357 code,
358 text,
359 },
360 ) => {
361 let event = KeyEvent::new(*key, *shift_key, *ctrl_key, *alt_key, *meta_key)
362 .with_details(*repeat, *code, text);
363 (*handler.borrow_mut())(event.clone());
364 return Ok(i64::from(event.consumed()));
365 }
366 (
367 EventCallback::Pointer(handler),
368 EventPayload::Pointer {
369 kind,
370 pointer_id,
371 pointer_type,
372 x,
373 y,
374 buttons,
375 button,
376 modifiers,
377 click_count,
378 delta_x,
379 delta_y,
380 delta_mode,
381 timestamp_nanos,
382 },
383 ) => {
384 let event = crate::PointerEvent::new(
385 *kind,
386 *pointer_id,
387 *pointer_type,
388 *x,
389 *y,
390 *buttons,
391 *button,
392 *modifiers,
393 *click_count,
394 *delta_x,
395 *delta_y,
396 *delta_mode,
397 *timestamp_nanos,
398 );
399 (*handler.borrow_mut())(event.clone());
400 return Ok(i64::from(event.consumed()));
401 }
402 (EventCallback::Value(handler), EventPayload::ValueChanged(value)) => {
403 (*handler.borrow_mut())(*value)
404 }
405 (EventCallback::Value(handler), EventPayload::CompositionChanged { composing }) => {
406 (*handler.borrow_mut())(if *composing { 1.0 } else { 0.0 })
407 }
408 (EventCallback::Range(handler), EventPayload::RangeRequested { start, count }) => {
409 (*handler.borrow_mut())(RangeRequest::new(*start, *count))
410 }
411 (EventCallback::Files(handler), EventPayload::FilesDropped(paths)) => {
412 (*handler.borrow_mut())(crate::FileDrop::new(paths))
413 }
414 (EventCallback::Window(handler), payload) => {
415 let Some(event) = crate::windows::WindowEvent::from_payload(payload) else {
416 return Err(ProtocolError::InvalidValueKind(0));
417 };
418 (*handler.borrow_mut())(event)
419 }
420 _ => return Err(ProtocolError::InvalidValueKind(0)),
421 }
422 Ok(0)
423}
424
425impl Composer {
426 pub(crate) fn abandon_composition(&mut self) {
428 self.clear_walk();
429 }
430}
431
432impl Runtime for Recomposer {
433 fn batch(&self) -> &Batch {
434 let composer = self.composition.composer.as_ptr();
435 unsafe { (*composer).writer.batch() }
439 }
440
441 fn batch_mut(&mut self) -> &mut Batch {
442 let composer = self.composition.composer.as_ptr();
443 unsafe { (*composer).writer.batch_mut() }
445 }
446
447 fn rebuild(&mut self) {
448 Recomposer::rebuild(self);
449 }
450
451 fn render(&mut self, frame_time_nanos: Option<u64>) {
452 Recomposer::render(self, frame_time_nanos);
453 }
454
455 fn handle_event(&mut self, event: &HostEvent<'_>) -> Result<i64, ProtocolError> {
456 Recomposer::handle_event(self, event)
457 }
458
459 fn size_token(&self, node_id: u32) -> Option<u32> {
460 Recomposer::size_token(self, node_id)
461 }
462
463 fn is_window(&self, node_id: u32) -> bool {
464 Recomposer::is_window(self, node_id)
465 }
466
467 fn run_in_context(&mut self, action: &mut dyn FnMut()) {
468 Recomposer::run_in_context(self, action);
469 }
470}