Seregon/StratoSDK

StratoSDK is a framework with a declarative approach similar to Flutter/React, written and designed entirely for Rust.

Rust/27.3 KB/No license
crates/strato-ui-core/src/core/app.rs
1use crate::{
2 assets::{
3 asset_cache::{AssetCache, AssetHandle, AssetSource, AssetState},
4 AssetProvider,
5 },
6 event::KeyState,
7 fonts::FallbackFontModel,
8 image_cache::{self, ImageCache},
9 modals::{
10 AlertDialog, AlertDialogWithCallbacks, AppModalCallback, ModalId, PlatformModalResponseData,
11 },
12 platform::{
13 app::TerminationResult,
14 file_picker::{FilePickerConfiguration, FilePickerError},
15 keyboard::KeyCode,
16 FullscreenState, MicrophoneAccessState, SaveFilePickerConfiguration, SystemTheme,
17 TerminationMode, WindowContext,
18 },
19 r#async::{block_on, SpawnableOutput, Timer},
20 windowing::{self, WindowCallbacks, WindowManager},
21 AccessibilityData, AddSingletonModel, Clipboard, Scene, ZoomFactor,
22};
23use anyhow::{anyhow, Result};
24use chrono::Utc;
25use futures::{future::join_all, prelude::*};
26use instant::Instant;
27use itertools::Itertools;
28use lazy_static::lazy_static;
29use parking_lot::Mutex;
30use pathfinder_geometry::{rect::RectF, vector::Vector2F};
31use rustc_hash::FxHashMap;
32use std::{
33 any::{Any, TypeId},
34 cell::{RefCell, RefMut},
35 collections::{HashMap, HashSet, VecDeque},
36 fmt::Debug,
37 path::Path,
38 pin::pin,
39 rc::{self, Rc},
40 sync::{
41 atomic::{AtomicI64, Ordering},
42 Arc, OnceLock,
43 },
44};
45 
46use crate::{
47 accessibility::{AccessibilityVerbosity, ActionAccessibilityContent},
48 actions::StandardAction,
49 app_focus_telemetry::AppFocusInfo,
50 assets,
51 core::{ActionType, Window},
52 fonts::{self, ExternalFontFamily, RequestedFallbackFontSource},
53 keymap::{
54 BindingLens, Context, CustomTag, DescriptionContext, EditableBinding, EditableBindingLens,
55 FixedBinding, IsBindingValid, Keystroke, MatchResult, Matcher, Trigger,
56 },
57 notification::{NotificationSendError, RequestPermissionsOutcome, UserNotification},
58 platform::{self, Cursor, WindowBounds, WindowOptions, WindowStyle},
59 presenter::{CursorUpdate, DispatchedActionKind},
60 r#async::{
61 executor::{self, Background, Foreground, ForegroundTask},
62 FutureId,
63 },
64 rendering,
65 util::post_inc,
66 Action, AddWindowOptions, AnyModel, AnyModelHandle, AnyView, ApplicationBundleInfo, CursorInfo,
67 Effect, Element, Entity, EntityId, Event, GetSingletonModelHandle, ModelAsRef, ModelContext,
68 ModelHandle, NextNewWindowsHasThisWindowsBoundsUponClose, Presenter, ReadModel, ReadView,
69 SingletonEntity, SpawnedFuture, TaskId, TypedActionView, UpdateModel, UpdateView, View,
70 ViewAsRef, ViewContext, ViewHandle, WindowId, WindowInvalidation,
71};
72 
73use super::{
74 autotracking, ActionCallback, BlurContext, FocusContext, GlobalActionCallback, GlobalShortcut,
75 InvalidationCallback, Observation, PendingUnsubscribes, RefCounts, Subscription, TaskCallback,
76 TypedActionCallback, ViewType,
77};
78 
79lazy_static! {
80 static ref LAST_USER_ACTION_UNIX_TIMESTAMP: AtomicI64 = AtomicI64::new(0);
81}
82 
83#[derive(Clone)]
84pub struct App(Rc<RefCell<AppContext>>);
85 
86impl App {
87 pub fn test<A: assets::AssetProvider, T: 'static, F: Future<Output = T> + 'static>(
88 asset_provider: A,
89 f: impl FnOnce(App) -> F,
90 ) -> T {
91 log::info!("Starting test app...");
92 let platform = Box::new(platform::test::AppDelegate::new().unwrap());
93 let window_manager = Box::new(platform::test::WindowManager::new());
94 let font_cache = Box::new(platform::test::FontDB);
95 let executor = Rc::new(executor::Foreground::test());
96 let app = Self(Rc::new(RefCell::new(AppContext::with_foreground_executor(
97 executor.clone(),
98 platform,
99 window_manager,
100 font_cache,
101 Box::new(asset_provider),
102 true, /* is_unit_test */
103 ))));
104 {
105 let mut app_mut = app.0.borrow_mut();
106 app_mut.weak_self = Rc::downgrade(&app.0);
107 }
108 log::info!("Executing test...");
109 let result = block_on(executor.run(f(app)));
110 log::info!("Test complete; terminating application...");
111 result
112 }
113 
114 pub fn new(
115 platform_delegate: Box<dyn platform::Delegate>,
116 window_manager: Box<dyn platform::WindowManager>,
117 font_db: Box<dyn platform::FontDB>,
118 asset_provider: Box<dyn AssetProvider>,
119 ) -> Result<Self> {
120 let app = Self(Rc::new(RefCell::new(AppContext::new(
121 platform_delegate,
122 window_manager,
123 font_db,
124 asset_provider,
125 )?)));
126 app.0.borrow_mut().weak_self = Rc::downgrade(&app.0);
127 Ok(app)
128 }
129 
130 pub(crate) fn can_borrow_mut(&self) -> bool {
131 self.0.try_borrow_mut().is_ok()
132 }
133 
134 pub fn has_window_invalidations(&self, window_id: WindowId) -> bool {
135 self.0.borrow().has_window_invalidations(window_id)
136 }
137 
138 pub fn window_bounds(&self, window_id: &WindowId) -> Option<RectF> {
139 self.0.borrow().window_bounds(window_id)
140 }
141 
142 pub fn next_window_bounds_and_style(&self) -> (WindowBounds, WindowStyle) {
143 self.0.borrow().next_window_bounds_and_style()
144 }
145 
146 pub fn focused_view_id(&self, window_id: WindowId) -> Option<EntityId> {
147 self.0.borrow().focused_view_id(window_id)
148 }
149 
150 pub fn presenter(&self, window_id: WindowId) -> Option<Rc<RefCell<Presenter>>> {
151 self.0.borrow().presenter(window_id)
152 }
153 
154 pub fn is_window_open(&self, window_id: WindowId) -> bool {
155 self.0.borrow().is_window_open(window_id)
156 }
157 
158 pub fn foreground_executor(&self) -> Rc<Foreground> {
159 self.0.borrow().foreground.clone()
160 }
161 
162 pub fn background_executor(&self) -> Arc<Background> {
163 self.0.borrow().background.clone()
164 }
165 
166 pub fn set_a11y_verbosity(&mut self, verbosity: AccessibilityVerbosity) {
167 self.0.borrow_mut().set_a11y_verbosity(verbosity);
168 }
169 
170 pub fn on_window_invalidated<F: 'static + FnMut(WindowId, &mut AppContext)>(
171 &self,
172 window_id: WindowId,
173 callback: F,
174 ) {
175 self.0
176 .borrow_mut()
177 .on_window_invalidated(window_id, callback);
178 }
179 
180 /// Adds an action with a given handler that is executed when the action is dispatched. The
181 /// action handler should return whether the action was handled. If it returns false this means
182 /// a parent view that listens on the same action name will receive the action.
183 pub fn add_action<S, V, T, F>(&self, name: S, handler: F)
184 where
185 S: Into<String>,
186 V: View,
187 T: Any,
188 F: 'static + FnMut(&mut V, &T, &mut ViewContext<V>) -> bool,
189 {
190 self.0.borrow_mut().add_action(name, handler);
191 }
192 
193 pub fn add_global_action<S, T, F>(&self, name: S, handler: F)
194 where
195 S: Into<String>,
196 T: 'static + Any,
197 F: 'static + FnMut(&T, &mut AppContext),
198 {
199 self.0.borrow_mut().add_global_action(name, handler);
200 }
201 
202 pub fn dispatch_action<T: 'static + Any>(
203 &self,
204 window_id: WindowId,
205 responder_chain: &[EntityId],
206 name: &str,
207 arg: T,
208 ) {
209 self.0.borrow_mut().dispatch_action(
210 window_id,
211 responder_chain,
212 name,
213 &arg,
214 log::Level::Info,
215 );
216 }
217 
218 pub fn dispatch_typed_action(
219 &self,
220 window_id: WindowId,
221 responder_chain: &[EntityId],
222 action: &dyn Action,
223 ) {
224 self.0.borrow_mut().dispatch_typed_action(
225 window_id,
226 responder_chain,
227 action,
228 log::Level::Info,
229 );
230 }
231 
232 pub fn last_active_timestamp() -> i64 {
233 LAST_USER_ACTION_UNIX_TIMESTAMP.load(Ordering::SeqCst)
234 }
235 
236 pub fn record_last_active_timestamp() {
237 LAST_USER_ACTION_UNIX_TIMESTAMP.fetch_max(Utc::now().timestamp(), Ordering::SeqCst);
238 }
239 
240 pub fn dispatch_global_action<T: 'static + Any>(&self, name: &str, arg: T) {
241 self.0.borrow_mut().dispatch_global_action(name, &arg);
242 }
243 
244 pub fn dispatch_standard_action(&mut self, window_id: WindowId, action: StandardAction) {
245 log::info!("Dispatching standard action {action:?}");
246 self.update(move |ctx| {
247 let responder_chain = ctx.get_responder_chain(window_id);
248 let res = ctx.dispatch_standard_action(action, window_id, &responder_chain);
249 if let Err(error) = res {
250 log::error!("error dispatching standard action: {error}");
251 }
252 });
253 }
254 
255 pub fn dispatch_custom_action<Action>(&mut self, action: Action, window_id: WindowId)
256 where
257 Action: Into<CustomTag> + Debug + Copy,
258 {
259 self.0
260 .borrow_mut()
261 .dispatch_custom_action(action, window_id);
262 }
263 
264 pub fn key_bindings_dispatching_enabled(&mut self, window_id: WindowId) -> bool {
265 self.0.borrow_mut().key_bindings_enabled(window_id)
266 }
267 
268 pub fn dispatch_keystroke(
269 &self,
270 window_id: WindowId,
271 responder_chain: &[EntityId],
272 keystroke: &Keystroke,
273 is_composing: bool,
274 ) -> Result<bool> {
275 let mut state = self.0.borrow_mut();
276 state.dispatch_keystroke(window_id, responder_chain, keystroke, is_composing)
277 }
278 
279 pub fn add_model<T, F>(&mut self, build_model: F) -> ModelHandle<T>
280 where
281 T: Entity,
282 F: FnOnce(&mut ModelContext<T>) -> T,
283 {
284 let mut state = self.0.borrow_mut();
285 state.pending_flushes += 1;
286 let handle = state.add_model(build_model);
287 state.flush_effects();
288 handle
289 }
290 
291 pub fn add_singleton_model<T, F>(&self, build_model: F) -> ModelHandle<T>
292 where
293 T: SingletonEntity,
294 F: FnOnce(&mut ModelContext<T>) -> T,
295 {
296 let mut state = self.0.borrow_mut();
297 state.pending_flushes += 1;
298 let handle = state.add_singleton_model(build_model);
299 state.flush_effects();
300 handle
301 }
302 
303 pub fn get_singleton_model_handle<T>(&self) -> ModelHandle<T>
304 where
305 T: SingletonEntity,
306 {
307 self.0.borrow().get_singleton_model_handle()
308 }
309 
310 pub fn add_window_with_bounds<T, F>(
311 &mut self,
312 style: WindowStyle,
313 bounds: WindowBounds,
314 build_root_view: F,
315 ) -> (WindowId, ViewHandle<T>)
316 where
317 T: View + TypedActionView,
318 F: FnOnce(&mut ViewContext<T>) -> T,
319 {
320 self.0.borrow_mut().add_window(
321 AddWindowOptions {
322 window_style: style,
323 window_bounds: bounds,
324 ..Default::default()
325 },
326 build_root_view,
327 )
328 }
329 
330 pub fn add_window<T, F>(
331 &mut self,
332 style: WindowStyle,
333 build_root_view: F,
334 ) -> (WindowId, ViewHandle<T>)
335 where
336 T: View + TypedActionView,
337 F: FnOnce(&mut ViewContext<T>) -> T,
338 {
339 self.add_window_with_bounds(style, WindowBounds::Default, build_root_view)
340 }
341 
342 pub fn window_ids(&self) -> Vec<WindowId> {
343 self.0.borrow().window_ids().collect()
344 }
345 
346 pub fn root_view<T: View>(&self, window_id: WindowId) -> Option<ViewHandle<T>> {
347 self.0.borrow().root_view(window_id)
348 }
349 
350 pub fn root_view_id(&self, window_id: WindowId) -> Option<EntityId> {
351 self.0.borrow().root_view_id(window_id)
352 }
353 
354 pub fn add_view<T, F>(&mut self, window_id: WindowId, build_view: F) -> ViewHandle<T>
355 where
356 T: View,
357 F: FnOnce(&mut ViewContext<T>) -> T,
358 {
359 let mut state = self.0.borrow_mut();
360 state.pending_flushes += 1;
361 let handle = state.add_view(window_id, build_view);
362 state.flush_effects();
363 handle
364 }
365 
366 pub fn add_typed_action_view<V, F>(
367 &mut self,
368 window_id: WindowId,
369 build_view: F,
370 ) -> ViewHandle<V>
371 where
372 V: TypedActionView + View,
373 F: FnOnce(&mut ViewContext<V>) -> V,
374 {
375 self.0
376 .borrow_mut()
377 .add_typed_action_view(window_id, build_view)
378 }
379 
380 pub fn add_option_view<T, F>(
381 &mut self,
382 window_id: WindowId,
383 build_view: F,
384 ) -> Option<ViewHandle<T>>
385 where
386 T: View,
387 F: FnOnce(&mut ViewContext<T>) -> Option<T>,
388 {
389 let mut state = self.0.borrow_mut();
390 state.pending_flushes += 1;
391 let handle = state.add_option_view(window_id, build_view);
392 state.flush_effects();
393 handle
394 }
395 
396 pub fn read<T, F: FnOnce(&AppContext) -> T>(&self, callback: F) -> T {
397 callback(&self.0.borrow())
398 }
399 
400 pub fn update<T, F: FnOnce(&mut AppContext) -> T>(&mut self, callback: F) -> T {
401 let mut state = self.0.borrow_mut();
402 state.pending_flushes += 1;
403 let result = callback(&mut state);
404 state.flush_effects();
405 result
406 }
407 
408 // Returns objects in the order they were added
409 pub fn views_of_type<T: View>(&self, window_id: WindowId) -> Option<Vec<ViewHandle<T>>> {
410 let views = self.0.borrow().views_of_type(window_id);
411 // Since iter yields arbitrary order, sort by id
412 match views {
413 Some(mut views) => {
414 views.sort_by_key(|view| view.id());
415 Some(views)
416 }
417 None => None,
418 }
419 }
420 
421 // Returns objects in the order they were added
422 pub fn models_of_type<M: Entity>(&self) -> Vec<ModelHandle<M>> {
423 let mut models = self.0.borrow().models_of_type();
424 // Since iter yields arbitrary order, sort by id
425 models.sort_by_key(|models| models.id());
426 models
427 }
428 
429 #[cfg(test)]
430 pub fn finish_pending_tasks(&self) -> impl Future<Output = ()> {
431 self.0.borrow().finish_pending_tasks()
432 }
433 
434 pub(crate) fn as_mut(&mut self) -> AppContextRefMut<'_> {
435 AppContextRefMut::new(self.0.as_ref().borrow_mut())
436 }
437 
438 pub fn termination_result(self) -> Option<TerminationResult> {
439 self.0.borrow_mut().termination_result.take()
440 }
441}
442 
443impl ModelAsRef for App {
444 // Unsupported for the same reasons as [`ViewAsRef`] being
445 // unsupported for [`App`].
446 fn model<T: Entity>(&self, _: &ModelHandle<T>) -> &T {
447 unimplemented!("Read from [`App::read_model`] instead");
448 }
449}
450 
451impl ReadModel for App {
452 fn read_model<T, F, S>(&self, handle: &ModelHandle<T>, read: F) -> S
453 where
454 T: Entity,
455 F: FnOnce(&T, &AppContext) -> S,
456 {
457 let state = self.0.borrow();
458 state.read_model(handle, read)
459 }
460}
461 
462impl UpdateModel for App {
463 fn update_model<T, F, S>(&mut self, handle: &ModelHandle<T>, update: F) -> S
464 where
465 T: Entity,
466 F: FnOnce(&mut T, &mut ModelContext<T>) -> S,
467 {
468 self.as_mut().update_model(handle, update)
469 }
470}
471 
472impl UpdateView for App {
473 fn update_view<T, F, S>(&mut self, handle: &ViewHandle<T>, update: F) -> S
474 where
475 T: View,
476 F: FnOnce(&mut T, &mut ViewContext<T>) -> S,
477 {
478 self.as_mut().update_view(handle, update)
479 }
480}
481 
482impl ReadView for App {
483 fn read_view<T, F, S>(&self, handle: &ViewHandle<T>, read: F) -> S
484 where
485 T: View,
486 F: FnOnce(&T, &AppContext) -> S,
487 {
488 let state = self.0.borrow();
489 state.read_view(handle, read)
490 }
491}
492 
493impl ViewAsRef for App {
494 // This is unimplemented because we would need to do
495 // some borrow-gymnastics, like returning a wrapper type
496 // that internally holds the reference, to get around a
497 // "returned reference to temporary value" error.
498 //
499 // That effort is currently unjustified because we want
500 // to ideally strip the *AsRef, Read* and Update* implementations
501 // from [`App`].
502 fn view<T: View>(&self, _handle: &ViewHandle<T>) -> &T {
503 unimplemented!("Read from [`App::read_view`] instead");
504 }
505 
506 fn try_view<T: View>(&self, _handle: &ViewHandle<T>) -> Option<&T> {
507 unimplemented!("Read from [`App::read_view`] instead");
508 }
509}
510 
511impl AddSingletonModel for App {
512 fn add_singleton_model<T, F>(&mut self, build_model: F) -> ModelHandle<T>
513 where
514 T: SingletonEntity,
515 F: FnOnce(&mut super::ModelContext<T>) -> T,
516 {
517 self.0.borrow_mut().add_singleton_model(build_model)
518 }
519}
520 
521impl GetSingletonModelHandle for App {
522 fn get_singleton_model_handle<T: SingletonEntity>(&self) -> ModelHandle<T> {
523 self.0.borrow_mut().get_singleton_model_handle()
524 }
525}
526 
527/// A wrapper around a mutably-borrowed app context.
528///
529/// This is necessary in order to ensure that all pending effects are flushed
530/// before we return the mutable borrow.
531pub(crate) struct AppContextRefMut<'a>(RefMut<'a, AppContext>);
532 
533impl<'a> AppContextRefMut<'a> {
534 fn new(mut inner: RefMut<'a, AppContext>) -> Self {
535 inner.pending_flushes += 1;
536 Self(inner)
537 }
538}
539 
540impl std::ops::Drop for AppContextRefMut<'_> {
541 fn drop(&mut self) {
542 self.0.flush_effects();
543 }
544}
545 
546impl<'a> std::ops::Deref for AppContextRefMut<'a> {
547 type Target = RefMut<'a, AppContext>;
548 
549 fn deref(&self) -> &Self::Target {
550 &self.0
551 }
552}
553 
554impl std::ops::DerefMut for AppContextRefMut<'_> {
555 fn deref_mut(&mut self) -> &mut Self::Target {
556 &mut self.0
557 }
558}
559 
560pub struct RepaintTask {
561 pub task: ForegroundTask,
562 
563 /// The window from which this comes
564 pub window_id: WindowId,
565 
566 pub repaint_trigger: RepaintTrigger,
567}
568 
569pub enum RepaintTrigger {
570 Timer { instant: Instant },
571 AssetLoaded { asset_handle: AssetHandle },
572}
573 
574type EventMunger = dyn Fn(&mut Event, &mut AppContext);
575 
576pub type DrawFrameErrorCallback = dyn Fn(&mut AppContext, WindowId);
577 
578pub type FrameDrawnCallback = dyn Fn(&mut AppContext, WindowId);
579 
580pub type BeforeOpenUrlCallback = dyn Fn(&str, &AppContext) -> String;
581 
582pub struct AppContext {
583 /////////////////////////
584 // Fields from AppContext
585 /////////////////////////
586 pub(super) models: HashMap<EntityId, Box<dyn AnyModel>>,
587 /// A mapping from type ID -> handle to the single global model of that
588 /// type. The handle is a strong reference, ensuring the model will not be
589 /// dropped during the lifetime of the application.
590 ///
591 /// We use an FxHashMap here because `TypeId` hashes as a u64, and FxHasher
592 /// is the fastest commonly-used hasher for this type.
593 singleton_models: FxHashMap<TypeId, AnyModelHandle>,
594 last_frame_position_cache: HashMap<WindowId, crate::presenter::PositionCache>,
595 pub(super) windows: HashMap<WindowId, Window>,
596 pub(super) ref_counts: Arc<Mutex<RefCounts>>,
597 pub(super) platform_delegate: Box<dyn platform::Delegate>,
598 
599 ////////////////////////////////
600 // Fields from MutableAppContext
601 ////////////////////////////////
602 actions: HashMap<TypeId, HashMap<String, Vec<Box<ActionCallback>>>>,
603 /// Map of typed actions to their internal handler functions
604 ///
605 /// We use a nested HashMap to key on both the ActionType and the ViewType, which allows us to
606 /// efficiently look up the appropriate handler while iterating the responder_chain on dispatch
607 ///
608 /// Safety Note: The `TypedActionCallback` must only be called with parameters that match the
609 /// type keys, as it requires the values to appropriately downcast.
610 typed_actions: HashMap<ActionType, HashMap<ViewType, Box<TypedActionCallback>>>,
611 presenters: HashMap<WindowId, Rc<RefCell<Presenter>>>,
612 /// Configuration options related to rendering of the application.
613 rendering_config: rendering::Config,
614 global_actions: HashMap<String, Vec<Box<GlobalActionCallback>>>,
615 keystroke_matcher: Matcher,
616 next_task_id: usize,
617 weak_self: rc::Weak<RefCell<Self>>,
618 pub(super) subscriptions: HashMap<EntityId, Vec<Subscription>>,
619 pub(super) observations: HashMap<EntityId, Vec<Observation>>,
620 /// Tracks pending unsubscribes during event emission.
621 /// When `emit_event` is processing callbacks, unsubscribes are deferred here to avoid
622 /// O(N²) tombstone scanning. The unsubscribes are processed at the end of event emission.
623 pub(super) pending_unsubscribes: Option<PendingUnsubscribes>,
624 window_invalidations: HashMap<WindowId, WindowInvalidation>,
625 invalidation_callbacks: HashMap<WindowId, Box<InvalidationCallback>>,
626 disabled_key_bindings_windows: HashSet<WindowId>,
627 window_bounds: HashMap<WindowId, Option<RectF>>,
628 next_window_bounds_map: HashMap<WindowId, NextNewWindowsHasThisWindowsBoundsUponClose>,
629 
630 /// The bounds of the next window to open. Typically this is set
631 /// using the position of the last window that was closed.
632 next_window_bounds: Option<RectF>,
633 
634 /// Map of window id to the last mouse moved event on that window. Used
635 /// for dispatch of synthetic mouse moved events to trigger hover behavior.
636 window_last_mouse_moved_event: HashMap<WindowId, Rc<RefCell<Option<Event>>>>,
637 foreground: Rc<executor::Foreground>,
638 background: Arc<executor::Background>,
639 pub(super) task_callbacks: HashMap<usize, TaskCallback>,
640 /// Callbacks that trigger a view redraw on a delay
641 /// We store references in case we need to cancel them.
642 /// The map key is the timer id returned by EventContext.notify_after
643 notify_tasks: HashMap<TaskId, ForegroundTask>,
644 repaint_tasks: HashMap<TaskId, RepaintTask>,
645 
646 /// A channel used in tests that receives messages whenever a task
647 /// completes.
648 #[cfg(test)]
649 task_done: (async_channel::Sender<usize>, async_channel::Receiver<usize>),
650 pub(super) pending_effects: VecDeque<Effect>,
651 pending_flushes: usize,
652 flushing_effects: bool,
653 app_focus_info: AppFocusInfo,
654 #[allow(clippy::type_complexity)]
655 first_frame_callback: Option<Box<dyn Fn(&mut AppContext)>>,
656 frame_drawn_callback: Option<Box<FrameDrawnCallback>>,
657 global_shortcuts: HashMap<Keystroke, GlobalShortcut>,
658 next_frame_callbacks: HashMap<WindowId, Vec<Box<dyn Fn()>>>,
659 on_draw_frame_error_callback: Option<Box<DrawFrameErrorCallback>>,
660 
661 /// The "event munger" allows for clients to hook into events and modify them
662 /// before they are dispatched.
663 event_munger: Box<EventMunger>,
664 
665 /// Callback invoked before opening any URL.
666 before_open_url_callback: Box<BeforeOpenUrlCallback>,
667 
668 pub(super) a11y_verbosity: AccessibilityVerbosity,
669 
670 #[allow(dead_code)]
671 spawned_futures: HashMap<FutureId, SpawnedFuture>,
672 
673 /// This maps modal IDs to the struct of data needed to send the response back to the context
674 /// which requested a platform native modal. This is needed because these modals are opened
675 /// asynchronously in platform code. Only the ID is propagated to/from platform code. Once we
676 /// have the modal response, we only have its ID, and so we look up the data in this map from
677 /// that ID.
678 platform_modal_data_map: HashMap<ModalId, PlatformModalResponseData>,
679 
680 /// If the cursor shape was changed by a view, keep track of that so that we can reset the
681 /// cursor if that view goes away.
682 pub(crate) cursor_updated_for_view: Option<(WindowId, EntityId)>,
683 is_unit_test: bool,
684 
685 termination_result: OnceLock<TerminationResult>,
686 
687 /// The current zoom (magnification) factor of the application.
688 zoom_factor: ZoomFactor,
689 
690 /// Maps view entity IDs to their containing window.
691 /// This is the source of truth for which window a view belongs to,
692 /// enabling views to be transferred between windows.
693 ///
694 /// Visibility is `pub(super)` because the `view::handle` module needs to access
695 /// this field for dynamic window lookup in `ViewHandle::window_id()`,
696 /// `WeakViewHandle::upgrade()`, and `WeakViewHandle::window_id()`.
697 pub(super) view_to_window: HashMap<EntityId, WindowId>,
698 
699 /// Maps child view → parent view for views created via `add_typed_action_view_with_parent`.
700 /// Unlike the presenter's layout-time parent map, this persists across renders and
701 /// includes views that are conditionally rendered. Used by `transfer_view_tree_to_window`
702 /// to discover non-rendered child views that must move with their parent.
703 ///
704 /// Populated by `add_typed_action_view_internal` when a parent_view_id is provided,
705 /// and cleaned up in `remove_dropped_items` when views are dropped.
706 structural_child_to_parent: HashMap<EntityId, EntityId>,
707 
708 /// Reverse of `structural_child_to_parent`: maps parent view → set of child views.
709 /// Enables efficient traversal in `transfer_structural_children` without iterating
710 /// all views in the source window.
711 structural_parent_to_children: HashMap<EntityId, HashSet<EntityId>>,
712 
713 /// When set, all focus changes to this window are suppressed.
714 /// Used during tab drag to prevent the new window from stealing focus.
715 suppress_focus_for_window: Option<WindowId>,
716 
717 /// An optional provider that creates an [`AssetSource`] for loading a
718 /// fallback font from a URL string. Injected by the application layer so
719 /// that `strato_ui_core` does not depend on `reqwest`.
720 #[allow(clippy::type_complexity)]
721 fallback_font_source_provider: Option<Box<dyn Fn(&str) -> AssetSource>>,
722}
723 
724impl AppContext {
725 pub(crate) fn new(
726 platform_delegate: Box<dyn platform::Delegate>,
727 window_manager: Box<dyn platform::WindowManager>,
728 font_db: Box<dyn platform::FontDB>,
729 asset_provider: Box<dyn AssetProvider>,
730 ) -> Result<Self> {
731 Ok(Self::with_foreground_executor(
732 Rc::new(executor::Foreground::platform(
733 platform_delegate.dispatch_delegate(),
734 )?),
735 platform_delegate,
736 window_manager,
737 font_db,
738 asset_provider,
739 false, /* is_unit_test */
740 ))
741 }
742 
743 pub fn is_window_open(&self, window_id: WindowId) -> bool {
744 self.windows.contains_key(&window_id)
745 }
746 
747 /// Sets or clears the window for which focus changes should be suppressed.
748 /// When set, all `ctx.focus()` calls targeting this window will be ignored.
749 pub fn set_suppress_focus_for_window(&mut self, window_id: Option<WindowId>) {
750 self.suppress_focus_for_window = window_id;
751 }
752 
753 fn with_foreground_executor(
754 foreground: Rc<executor::Foreground>,
755 platform_delegate: Box<dyn platform::Delegate>,
756 window_manager: Box<dyn platform::WindowManager>,
757 font_db: Box<dyn platform::FontDB>,
758 asset_provider: Box<dyn assets::AssetProvider>,
759 is_unit_test: bool,
760 ) -> Self {
761 let mut ctx = Self {
762 // AppContext fields
763 models: Default::default(),
764 singleton_models: Default::default(),
765 windows: Default::default(),
766 ref_counts: Arc::new(Mutex::new(RefCounts::default())),
767 last_frame_position_cache: Default::default(),
768 platform_delegate,
769 // AppContext fields
770 actions: Default::default(),
771 typed_actions: Default::default(),
772 global_actions: Default::default(),
773 presenters: Default::default(),
774 rendering_config: Default::default(),
775 keystroke_matcher: Default::default(),
776 disabled_key_bindings_windows: Default::default(),
777 next_task_id: 0,
778 weak_self: rc::Weak::default(),
779 subscriptions: Default::default(),
780 next_window_bounds: None,
781 next_window_bounds_map: Default::default(),
782 observations: Default::default(),
783 pending_unsubscribes: None,
784 window_invalidations: Default::default(),
785 invalidation_callbacks: Default::default(),
786 window_bounds: Default::default(),
787 window_last_mouse_moved_event: Default::default(),
788 foreground: foreground.clone(),
789 background: Default::default(),
790 task_callbacks: Default::default(),
791 notify_tasks: Default::default(),
792 repaint_tasks: Default::default(),
793 spawned_futures: Default::default(),
794 #[cfg(test)]
795 task_done: async_channel::unbounded(),
796 pending_effects: VecDeque::new(),
797 pending_flushes: 0,
798 flushing_effects: false,
799 app_focus_info: AppFocusInfo::new(),
800 first_frame_callback: None,
801 frame_drawn_callback: None,
802 global_shortcuts: Default::default(),
803 next_frame_callbacks: Default::default(),
804 event_munger: Box::new(|_evt, _ctx| {}),
805 before_open_url_callback: Box::new(|url, _ctx| url.to_owned()),
806 a11y_verbosity: Default::default(),
807 platform_modal_data_map: Default::default(),
808 on_draw_frame_error_callback: None,
809 cursor_updated_for_view: None,
810 is_unit_test,
811 termination_result: Default::default(),
812 zoom_factor: ZoomFactor::default(),
813 view_to_window: Default::default(),
814 structural_child_to_parent: Default::default(),
815 structural_parent_to_children: Default::default(),
816 suppress_focus_for_window: None,
817 fallback_font_source_provider: None,
818 };
819 
820 // Register a variety of required/core singleton models.
821 ctx.add_singleton_model(|_| fonts::Cache::new(font_db));
822 ctx.add_singleton_model(|_| WindowManager::new(window_manager));
823 ctx.add_singleton_model(|ctx| {
824 AssetCache::new(asset_provider, foreground, ctx.background_executor())
825 });
826 ctx.add_singleton_model(|_| ImageCache::new());
827 ctx.add_singleton_model(|_| FallbackFontModel::new());
828 
829 if !is_unit_test {
830 ctx.background_executor()
831 .spawn(async {
832 image_cache::prewarm_svg_font_db();
833 })
834 .detach();
835 }
836 
837 ctx
838 }
839 
840 /// Registers a provider that creates an [`AssetSource`] for a given URL.
841 /// Used to load fallback fonts without pulling `reqwest` into `strato_ui_core`.
842 pub fn set_fallback_font_source_provider(
843 &mut self,
844 provider: impl Fn(&str) -> AssetSource + 'static,
845 ) {
846 self.fallback_font_source_provider = Some(Box::new(provider));
847 }
848 
849 pub fn foreground_executor(&self) -> &Rc<executor::Foreground> {
850 &self.foreground
851 }
852 
853 pub fn background_executor(&self) -> &Arc<executor::Background> {
854 &self.background
855 }
856 
857 pub fn window_bounds(&self, window_id: &WindowId) -> Option<RectF> {
858 *self.window_bounds.get(window_id)?
859 }
860 
861 pub fn update_window_bounds(&mut self, window_id: WindowId, bounds: RectF) {
862 self.window_bounds.insert(window_id, Some(bounds));
863 }
864 
865 fn matches_any_window_bounds(&self, r: RectF) -> bool {
866 self.window_bounds.values().any(|b| *b == Some(r))
867 }
868 
869 /// Create a window showing a modal dialog native to the platform. The modal will synchronously
870 /// block all other interactions with the app until dismissed. Each button can have a callback
871 /// attached to it in the [`crate::modals::ModalButton`] struct.
872 pub fn show_native_platform_modal(
873 &mut self,
874 alert_data: AlertDialogWithCallbacks<AppModalCallback>,
875 ) {
876 let id = ModalId::new();
877 let (button_titles, button_callbacks) = alert_data
878 .button_data
879 .into_iter()
880 .map(|button| (button.title, button.on_click))
881 .unzip();
882 let dialog = AlertDialog {
883 message_text: alert_data.message_text,
884 info_text: alert_data.info_text,
885 buttons: button_titles,
886 };
887 
888 let response_data = PlatformModalResponseData {
889 button_callbacks,
890 disable_callback: alert_data.on_disable,
891 };
892 self.platform_modal_data_map.insert(id, response_data);
893 self.platform_delegate
894 .show_native_platform_modal(id, dialog);
895 }
896 
897 /// When a native platform modal which was requested by an app/view context returns a response,
898 /// this method handles dispatching the right handler for the button clicked. The response is
899 /// encoded as a 0-based index into the list of buttons on the modal, and the callback will be
900 /// at the same index in the Vec of callbacks.
901 /// TODO(CORE-2323): Implement native Windows OS modal
902 #[cfg_attr(target_os = "windows", allow(dead_code))]
903 pub(crate) fn process_platform_modal_response(
904 &mut self,
905 modal_id: ModalId,
906 response_button_index: usize,
907 disable_modal: bool,
908 ) {
909 if let Some(mut response_data) = self.platform_modal_data_map.remove(&modal_id) {
910 if disable_modal {
911 (response_data.disable_callback)(self);
912 }
913 response_data.button_callbacks.remove(response_button_index)(self);
914 }
915 }
916 
917 pub fn zoom_factor(&self) -> ZoomFactor {
918 self.zoom_factor
919 }
920 
921 pub fn report_active_cursor_position_update(&self) {
922 self.windows().active_cursor_position_updated();
923 }
924 
925 pub fn rendering_config(&self) -> rendering::Config {
926 self.rendering_config
927 }
928 
929 pub fn update_rendering_config<U>(&mut self, update_fn: U)
930 where
931 U: FnOnce(&mut rendering::Config),
932 {
933 update_fn(&mut self.rendering_config)
934 }
935 
936 pub fn has_window_invalidations(&self, window_id: WindowId) -> bool {
937 self.window_invalidations
938 .get(&window_id)
939 .is_some_and(|invalidation| {
940 !invalidation.updated.is_empty() || !invalidation.removed.is_empty()
941 })
942 }
943 
944 pub fn presenter(&self, window_id: WindowId) -> Option<Rc<RefCell<Presenter>>> {
945 // The presenter may not exist if there is a race condition where a window event comes in
946 // after the window is closed (for example, if a fullscreen window is closed, a resize event
947 // comes in after the window is closed.
948 self.presenters.get(&window_id).cloned()
949 }
950 
951 fn invalidate_all_views_for_window(&mut self, window_id: WindowId) {
952 let Some(window) = self.windows.get(&window_id) else {
953 return;
954 };
955 self.window_invalidations
956 .entry(window_id)
957 .or_default()
958 .updated = window.views.keys().cloned().collect();
959 }
960 
961 pub fn invalidate_all_views(&mut self) {
962 // Mark all views in all windows as invalid.
963 for window_id in self.windows.keys().cloned().collect_vec() {
964 self.invalidate_all_views_for_window(window_id)
965 }
966 }
967 
968 pub(crate) fn on_global_shortcut_triggered(&mut self, shortcut: Keystroke) {
969 if let Some(global_action) = self.global_shortcuts.remove(&shortcut) {
970 self.dispatch_global_action(global_action.action, global_action.args.as_ref());
971 self.global_shortcuts.insert(shortcut, global_action);
972 }
973 }
974 
975 pub fn on_window_invalidated<F: 'static + FnMut(WindowId, &mut AppContext)>(
976 &mut self,
977 window_id: WindowId,
978 callback: F,
979 ) {
980 self.invalidation_callbacks
981 .insert(window_id, Box::new(callback));
982 }
983 
984 /// Observes a [`ModelHandle`] for changes, calling `callback` whenever the model is invalidated.
985 pub fn observe_model<S, F>(&mut self, handle: &ModelHandle<S>, mut callback: F)
986 where
987 S: Entity,
988 F: 'static + FnMut(ModelHandle<S>, &mut AppContext),
989 {
990 self.observations
991 .entry(handle.id())
992 .or_default()
993 .push(Observation::FromApp {
994 callback: Box::new(move |observed_id, app| {
995 let model = ModelHandle::new(observed_id, &app.ref_counts);
996 callback(model, app)
997 }),
998 });
999 }
1000 
1001 /// Subscribes to a [`ModelHandle`] for changes, calling `callback` with the emitted event whenever the model is invalidated.
1002 pub fn subscribe_to_model<S, F>(&mut self, handle: &ModelHandle<S>, mut callback: F)
1003 where
1004 S: Entity,
1005 S::Event: 'static,
1006 F: 'static + FnMut(ModelHandle<S>, &S::Event, &mut AppContext),
1007 {
1008 self.subscriptions
1009 .entry(handle.id())
1010 .or_default()
1011 .push(Subscription::FromApp {
1012 callback: Box::new(move |payload, app, entity_id| {
1013 let model = ModelHandle::new(entity_id, &app.ref_counts);
1014 let payload: &<S as Entity>::Event =
1015 payload.downcast_ref().expect("downcast is type safe");
1016 callback(model, payload, app);
1017 }),
1018 });
1019 }
1020 
1021 /// Subscribes to a [`ViewHandle`] for changes, calling `callback` with the emitted event whenever the view is invalidated.
1022 pub fn subscribe_to_view<S, F>(&mut self, handle: &ViewHandle<S>, mut callback: F)
1023 where
1024 S: View,
1025 S::Event: 'static,
1026 F: 'static + FnMut(ViewHandle<S>, &S::Event, &mut AppContext),
1027 {
1028 self.subscriptions
1029 .entry(handle.id())
1030 .or_default()
1031 .push(Subscription::FromApp {
1032 callback: Box::new(move |payload, app, entity_id| {
1033 let Some(current_window_id) = app.view_to_window.get(&entity_id).copied()
1034 else {
1035 log::warn!("subscribe_to_view callback: view {entity_id:?} not found in view_to_window");
1036 return;
1037 };
1038 if !app.windows.contains_key(&current_window_id) {
1039 log::warn!("subscribe_to_view callback: window {current_window_id:?} not found for view {entity_id:?}");
1040 return;
1041 }
1042 
1043 let view = ViewHandle::new(current_window_id, entity_id, &app.ref_counts);
1044 let payload: &<S as Entity>::Event =
1045 payload.downcast_ref().expect("downcast is type safe");
1046 callback(view, payload, app);
1047 }),
1048 });
1049 }
1050 
1051 #[cfg(feature = "test-util")]
1052 pub(crate) fn register_spawned_future(&mut self, future: SpawnedFuture) -> FutureId {
1053 let future_id = FutureId::new();
1054 self.spawned_futures.insert(future_id, future);
1055 
1056 future_id
1057 }
1058 
1059 #[cfg(not(feature = "test-util"))]
1060 pub(crate) fn register_spawned_future(&mut self, _future: SpawnedFuture) -> FutureId {
1061 FutureId::new()
1062 }
1063 
1064 /// Returns a future that can be awaited to ensure the spawned background future identified by
1065 /// `future_id` has finished. If no spawned future exists with `future_id` a future that
1066 /// immediately resolves to the unit type is returned.
1067 ///
1068 /// This is useful for tests to ensure that calls to `ctx#spawn` have
1069 /// completed before asserting correct state.
1070 #[cfg(feature = "test-util")]
1071 pub fn await_spawned_future(&mut self, future_id: FutureId) -> future::BoxFuture<'static, ()> {
1072 match self.spawned_futures.remove(&future_id) {
1073 None => futures::future::ready(()).boxed(),
1074 Some(future) => future,
1075 }
1076 }
1077 
1078 /// This callback will be invoked immediately after the very first frame in the app is drawn.
1079 /// After that, the callback will be removed.
1080 pub fn on_first_frame_drawn<F: 'static + Fn(&mut AppContext)>(&mut self, callback: F) {
1081 self.first_frame_callback = Some(Box::new(callback));
1082 }
1083 
1084 /// Callback that is called whenever a frame is successfully drawn.
1085 pub fn on_frame_drawn<F: 'static + Fn(&mut AppContext, WindowId)>(&mut self, callback: F) {
1086 self.frame_drawn_callback = Some(Box::new(callback));
1087 }
1088 
1089 /// Callback invoked whenever a frame fails to render in a given [`WindowId`].
1090 pub fn on_draw_frame_error<F: 'static + Fn(&mut AppContext, WindowId)>(&mut self, callback: F) {
1091 self.on_draw_frame_error_callback = Some(Box::new(callback));
1092 }
1093 
1094 pub fn unregister_global_shortcut(&mut self, shortcut: &Keystroke) {
1095 if self.is_wayland() {
1096 return;
1097 }
1098 self.global_shortcuts.remove(shortcut);
1099 self.platform_delegate.unregister_global_shortcut(shortcut);
1100 }
1101 
1102 pub fn register_global_shortcut<T: 'static + Any>(
1103 &mut self,
1104 mut shortcut: Keystroke,
1105 action: &'static str,
1106 arg: T,
1107 ) {
1108 if self.is_wayland() {
1109 return;
1110 }
1111 // Note that for global hotkey we don't support registering the meta key so
1112 // we will treat meta key as alt.
1113 if shortcut.meta {
1114 shortcut.meta = false;
1115 shortcut.alt = true;
1116 }
1117 
1118 self.global_shortcuts.insert(
1119 shortcut.clone(),
1120 GlobalShortcut {
1121 action,
1122 args: Box::new(arg),
1123 },
1124 );
1125 
1126 self.platform_delegate.register_global_shortcut(shortcut);
1127 }
1128 
1129 fn dispatch_draw_frame_error_callback(&mut self, window_id: WindowId) {
1130 let callback = self.on_draw_frame_error_callback.take();
1131 if let Some(callback) = &callback {
1132 callback(self, window_id);
1133 }
1134 
1135 self.on_draw_frame_error_callback = callback;
1136 }
1137 
1138 fn trigger_on_frame_drawn_callbacks(&mut self, window_id: WindowId) {
1139 if let Some(callback) = self.first_frame_callback.take() {
1140 callback(self);
1141 }
1142 
1143 let frame_drawn_callback = self.frame_drawn_callback.take();
1144 if let Some(callback) = &frame_drawn_callback {
1145 callback(self, window_id);
1146 }
1147 self.frame_drawn_callback = frame_drawn_callback;
1148 
1149 if let Some(callbacks) = self.next_frame_callbacks.remove(&window_id) {
1150 for callback in callbacks {
1151 callback();
1152 }
1153 }
1154 }
1155 
1156 /// Installs the callback so that it'll be invoked after the next frame for the window is
1157 /// drawn.
1158 pub fn on_next_frame_drawn<F: 'static + Fn()>(&mut self, window_id: WindowId, callback: F) {
1159 let entry = self.next_frame_callbacks.entry(window_id).or_default();
1160 entry.push(Box::new(callback));
1161 }
1162 
1163 /// Sets a function which gets to inspect and modify events before they are dispatched.
1164 pub fn set_event_munger<F>(&mut self, handler: F)
1165 where
1166 F: 'static + Fn(&mut Event, &mut AppContext),
1167 {
1168 self.event_munger = Box::new(handler)
1169 }
1170 
1171 /// Sets the zoom factor for the application. Changing the zoom factor adjusts
1172 /// the magnification of every element rendered within the application.
1173 ///
1174 /// All views in every window are invalidated when this is invoked.
1175 ///
1176 /// ## Validation
1177 /// The zoom factor is clamped to the range [0.5, 4.0].
1178 pub fn set_zoom_factor(&mut self, zoom_factor: f32) {
1179 let zoom_factor = ZoomFactor::new(zoom_factor.clamp(0.5, 4.0));
1180 self.zoom_factor = zoom_factor;
1181 self.invalidate_all_views();
1182 }
1183 
1184 /// Sets the callback invoked before opening a URL.
1185 pub fn set_before_open_url<F>(&mut self, handler: F)
1186 where
1187 F: 'static + Fn(&str, &AppContext) -> String,
1188 {
1189 self.before_open_url_callback = Box::new(handler);
1190 }
1191 
1192 /// Internal helper method to store the handler for a `TypedActionView` being registered
1193 ///
1194 /// Creates a handler which will dispatch to `TypedActionView::handle_action` for the given
1195 /// View + Action combination.
1196 fn add_typed_action<V>(&mut self)
1197 where
1198 V: TypedActionView + View,
1199 {
1200 let handler = Box::new(
1201 |view: &mut dyn AnyView,
1202 action: &dyn Any,
1203 app: &mut AppContext,
1204 window_id: WindowId,
1205 view_id: EntityId| {
1206 let is_screen_reader_enabled = app
1207 .platform_delegate
1208 .is_screen_reader_enabled()
1209 .unwrap_or(false);
1210 // Safety: The handler is stored in a map keyed on both the ActionType and the
1211 // ViewType, so we will only call it if both match, making the downcasts safe
1212 let action = action
1213 .downcast_ref()
1214 .expect("Handlers are hashed by action type");
1215 let view = view
1216 .as_any_mut()
1217 .downcast_mut()
1218 .expect("Handlers are hashed by view type");
1219 let mut ctx = ViewContext::new(app, window_id, view_id);
1220 V::handle_action(view, action, &mut ctx);
1221 if is_screen_reader_enabled {
1222 match V::action_accessibility_contents(view, action, &mut ctx) {
1223 ActionAccessibilityContent::CustomFn(f) => {
1224 app.platform_delegate.set_accessibility_contents(
1225 f(action).with_verbosity(app.a11y_verbosity),
1226 );
1227 }
1228 ActionAccessibilityContent::Custom(content) => {
1229 app.platform_delegate.set_accessibility_contents(
1230 content.with_verbosity(app.a11y_verbosity),
1231 );
1232 }
1233 ActionAccessibilityContent::Empty => {}
1234 };
1235 }
1236 },
1237 );
1238 
1239 // Insert the action handler for this view into the `typed_actions` hash
1240 // We only need to do this once per View type, since the handler is the same for every
1241 // instance.
1242 self.typed_actions
1243 .entry(ActionType::of::<V::Action>())
1244 .or_default()
1245 .entry(ViewType::of::<V>())
1246 .or_insert(handler);
1247 }
1248 
1249 pub fn add_action<S, V, T, F>(&mut self, name: S, mut handler: F)
1250 where
1251 S: Into<String>,
1252 V: View,
1253 T: Any,
1254 F: 'static + FnMut(&mut V, &T, &mut ViewContext<V>) -> bool,
1255 {
1256 let name = name.into();
1257 let name_clone = name.clone();
1258 let handler = Box::new(
1259 move |view: &mut dyn AnyView,
1260 arg: &dyn Any,
1261 app: &mut AppContext,
1262 window_id: WindowId,
1263 view_id: EntityId| {
1264 match arg.downcast_ref() {
1265 Some(arg) => {
1266 let mut ctx = ViewContext::new(app, window_id, view_id);
1267 handler(
1268 view.as_any_mut()
1269 .downcast_mut()
1270 .expect("downcast is type safe"),
1271 arg,
1272 &mut ctx,
1273 )
1274 }
1275 None => {
1276 log::error!("Could not downcast argument for action {name_clone}");
1277 false
1278 }
1279 }
1280 },
1281 );
1282 
1283 self.actions
1284 .entry(TypeId::of::<V>())
1285 .or_default()
1286 .entry(name)
1287 .or_default()
1288 .push(handler);
1289 }
1290 
1291 pub fn add_global_action<S, T, F>(&mut self, name: S, mut handler: F)
1292 where
1293 S: Into<String>,
1294 T: 'static + Any,
1295 F: 'static + FnMut(&T, &mut AppContext),
1296 {
1297 let name = name.into();
1298 let name_clone = name.clone();
1299 let handler = Box::new(
1300 move |arg: &dyn Any,
1301 location: &'static std::panic::Location<'static>,
1302 app: &mut AppContext| {
1303 if let Some(arg) = arg.downcast_ref() {
1304 handler(arg, app);
1305 } else {
1306 debug_assert!(
1307 false,
1308 "Could not downcast argument for action {name_clone}: {location:?}"
1309 );
1310 log::error!("Could not downcast argument for action {name_clone}");
1311 }
1312 },
1313 );
1314 
1315 self.global_actions.entry(name).or_default().push(handler);
1316 }
1317 
1318 pub fn pending_flushes(&self) -> usize {
1319 self.pending_flushes
1320 }
1321 
1322 pub fn models_of_type<M: Entity>(&self) -> Vec<ModelHandle<M>> {
1323 let ref_counts = &self.ref_counts;
1324 self.models
1325 .iter()
1326 .filter(|(_, m)| (*m).as_any().type_id() == TypeId::of::<M>())
1327 .map(|(model_id, _)| ModelHandle::new(*model_id, ref_counts))
1328 .collect::<Vec<ModelHandle<M>>>()
1329 }
1330 
1331 pub fn root_view<T: View>(&self, window_id: WindowId) -> Option<ViewHandle<T>> {
1332 self.windows
1333 .get(&window_id)
1334 .and_then(|window| window.root_view.as_ref())
1335 .and_then(|root_view| root_view.clone().downcast::<T>())
1336 }
1337 
1338 /// Returns the [`AccessibilityData`] of the focused view, or a parent of that view in its
1339 /// responder chain.
1340 #[cfg_attr(not(target_os = "macos"), allow(dead_code))]
1341 pub fn focused_view_accessibility_data(
1342 &mut self,
1343 window_id: WindowId,
1344 ) -> Option<AccessibilityData> {
1345 let responder_chain = self.get_responder_chain(window_id);
1346 for view_id in responder_chain {
1347 let window = self.windows.get_mut(&window_id)?;
1348 let view = window.views.remove(&view_id)?;
1349 let accessibility_data = view.accessibility_data(self, window_id, view_id);
1350 
1351 if let Some(window) = self.windows.get_mut(&window_id) {
1352 window.views.insert(view_id, view);
1353 }
1354 
1355 if let Some(accessibility_data) = accessibility_data {
1356 return Some(accessibility_data);
1357 }
1358 }
1359 None
1360 }
1361 
1362 pub fn dispatch_action_for_view(
1363 &mut self,
1364 window_id: WindowId,
1365 view_id: EntityId,
1366 name: &str,
1367 arg: &dyn Any,
1368 ) -> bool {
1369 if let Some(presenter) = self.presenter(window_id) {
1370 let responder_chain = presenter.borrow().ancestors(view_id);
1371 self.dispatch_action(window_id, &responder_chain, name, arg, log::Level::Info)
1372 } else {
1373 false
1374 }
1375 }
1376 
1377 /// Dispatch a typed action using the given view as the base of the responder_chain
1378 pub fn dispatch_typed_action_for_view(
1379 &mut self,
1380 window_id: WindowId,
1381 view_id: EntityId,
1382 action: &dyn Action,
1383 ) {
1384 if let Some(presenter) = self.presenter(window_id) {
1385 let responder_chain = presenter.borrow().ancestors(view_id);
1386 self.dispatch_typed_action(window_id, &responder_chain, action, log::Level::Info);
1387 }
1388 }
1389 
1390 pub fn dispatch_action(
1391 &mut self,
1392 window_id: WindowId,
1393 responder_chain: &[EntityId],
1394 name: &str,
1395 arg: &dyn Any,
1396 log_level: log::Level,
1397 ) -> bool {
1398 log::log!(log_level, "dispatching action for {name:?}");
1399 self.pending_flushes += 1;
1400 
1401 let mut any_action_handled = false;
1402 let mut dispatched_actions = HashSet::<String>::new();
1403 
1404 for view_id in responder_chain.iter().rev() {
1405 if let Some(mut view) = self
1406 .windows
1407 .get_mut(&window_id)
1408 .and_then(|w| w.views.remove(view_id))
1409 {
1410 let type_id = view.as_any().type_id();
1411 
1412 if let Some((name, mut handlers)) = self
1413 .actions
1414 .get_mut(&type_id)
1415 .and_then(|h| h.remove_entry(name))
1416 {
1417 // Only dispatch the action if a previous view hasn't already handled it or the
1418 // child view determined it should be propagated to the parent view.
1419 if !dispatched_actions.contains(name.as_str()) {
1420 for handler in handlers.iter_mut().rev() {
1421 let handled = handler(view.as_mut(), arg, self, window_id, *view_id);
1422 any_action_handled |= handled;
1423 if handled {
1424 dispatched_actions.insert(name.clone());
1425 }
1426 }
1427 } else {
1428 log::log!(log_level, "not propagating action {name:?} to parent view");
1429 }
1430 self.actions
1431 .get_mut(&type_id)
1432 .unwrap()
1433 .insert(name, handlers);
1434 }
1435 
1436 if let Some(window) = self.windows.get_mut(&window_id) {
1437 window.views.insert(*view_id, view);
1438 }
1439 }
1440 }
1441 
1442 if !any_action_handled {
1443 log::warn!("Action {name:?} was dispatched, but no view handled it");
1444 }
1445 
1446 self.dispatch_global_action(name, arg);
1447 
1448 self.flush_effects();
1449 any_action_handled
1450 }
1451 
1452 /// Dispatch a typed action to a view that was registered with `add_typed_action_view`
1453 ///
1454 /// The action will be dispatched to deepest view in the `responder_chain` that registered a
1455 /// handler for the action's type
1456 pub fn dispatch_typed_action(
1457 &mut self,
1458 window_id: WindowId,
1459 responder_chain: &[EntityId],
1460 action: &dyn Action,
1461 log_level: log::Level,
1462 ) -> bool {
1463 log::log!(
1464 log_level,
1465 "dispatching typed action: {}::{action:?}",
1466 action.type_name()
1467 );
1468 
1469 let action_type: ActionType = action.into();
1470 // If there are no handlers registered for the given action, then we can return early
1471 // without needing to look at the responder chain at all, since no views will handle it
1472 let Some(mut handlers) = self.typed_actions.remove(&action_type) else {
1473 log::warn!("Dispatched action has no handlers: {:?}", &action);
1474 return false;
1475 };
1476 
1477 // Increment pending flushes only after we know there is a handler for the action.
1478 self.pending_flushes += 1;
1479 
1480 // Traverse the responder chain from the leaf view to see if any views handle the action
1481 // We stop on the first View that handles the action, we explicitly do not propagate to
1482 // parent views
1483 let handled = responder_chain.iter().rev().any(|view_id| {
1484 let mut view = match self
1485 .windows
1486 .get_mut(&window_id)
1487 .and_then(|w| w.views.remove(view_id))
1488 {
1489 Some(view) => view,
1490 None => return false,
1491 };
1492 
1493 // Check to see if we have a handler for this action on the view
1494 let view_type = ViewType(view.as_any().type_id());
1495 let found = match handlers.get_mut(&view_type) {
1496 Some(handler) => {
1497 handler(view.as_mut(), action.as_any(), self, window_id, *view_id);
1498 true
1499 }
1500 None => false,
1501 };
1502 
1503 // Reinsert the view before moving on to the next link in the responder chain
1504 if let Some(window) = self.windows.get_mut(&window_id) {
1505 window.views.insert(*view_id, view);
1506 }
1507 
1508 found
1509 });
1510 
1511 // Reinsert the action handlers for this action type
1512 self.typed_actions.insert(action_type, handlers);
1513 
1514 if !handled {
1515 log::warn!("Action {action:?} was dispatched, but no view handled it");
1516 }
1517 
1518 self.flush_effects();
1519 handled
1520 }
1521 
1522 /// Global actions are being phased out. Prefer dispatching typed actions instead of global actions.
1523 #[track_caller]
1524 pub fn dispatch_global_action(&mut self, name: &str, arg: &dyn Any) {
1525 let location = std::panic::Location::caller();
1526 self.dispatch_global_action_internal(name, location, arg);
1527 }
1528 
1529 fn dispatch_global_action_internal(
1530 &mut self,
1531 name: &str,
1532 location: &'static std::panic::Location<'static>,
1533 arg: &dyn Any,
1534 ) {
1535 if let Some((name, mut handlers)) = self.global_actions.remove_entry(name) {
1536 log::info!("dispatching global action for {}", &name);
1537 self.pending_flushes += 1;
1538 for handler in handlers.iter_mut().rev() {
1539 handler(arg, location, self);
1540 }
1541 self.global_actions.insert(name, handlers);
1542 self.flush_effects();
1543 }
1544 }
1545 /// Registers a validator that validates every binding that matches the given view's default
1546 /// [`Context`].
1547 /// After the app is initialized, the provided `binding_validator` function is called for every
1548 /// binding that matches the View's default context. If the binding is invalid (indicated by
1549 /// [`IsBindingValid::No`]), the app will panic if `debug_assertions` are enabled.
1550 #[cfg(debug_assertions)]
1551 pub fn register_binding_validator<T: View>(
1552 &mut self,
1553 binding_validator: impl Fn(BindingLens) -> IsBindingValid + 'static,
1554 ) {
1555 let context = T::default_keymap_context();
1556 self.keystroke_matcher
1557 .register_binding_validator(context, binding_validator)
1558 }
1559 
1560 #[cfg(not(debug_assertions))]
1561 pub fn register_binding_validator<T: View>(
1562 &mut self,
1563 binding_validator: impl Fn(BindingLens) -> IsBindingValid + 'static,
1564 ) {
1565 }
1566 
1567 /// Sets a default binding validator that runs on _every_ binding that is registered by the
1568 /// application.
1569 /// Noops if `debug_assertions` are disabled.
1570 #[cfg(debug_assertions)]
1571 pub fn set_default_binding_validator(
1572 &mut self,
1573 binding_validator: impl Fn(BindingLens) -> IsBindingValid + 'static,
1574 ) {
1575 self.keystroke_matcher
1576 .set_default_binding_validator(binding_validator)
1577 }
1578 
1579 /// Sets a default binding validator that runs on _every_ binding that is registered by the
1580 /// application.
1581 /// Noops if `debug_assertions` are disabled.
1582 #[cfg(not(debug_assertions))]
1583 pub fn set_default_binding_validator(
1584 &mut self,
1585 binding_validator: impl Fn(BindingLens) -> IsBindingValid + 'static,
1586 ) {
1587 }
1588 
1589 /// Runs through each registered binding validator, asserting that each matching binding is
1590 /// valid. Noop if debug assertions are not enabled.
1591 #[cfg(debug_assertions)]
1592 pub(crate) fn validate_bindings(&mut self) {
1593 self.keystroke_matcher.validate_bindings();
1594 }
1595 
1596 /// Runs through each registered binding validator, asserting that each matching binding is
1597 /// valid. Noop if debug assertions are not enabled.
1598 #[cfg(not(debug_assertions))]
1599 pub(crate) fn validate_bindings(&mut self) {}
1600 
1601 /// Add new fixed (immutable) key bindings to the app
1602 pub fn register_fixed_bindings<T: IntoIterator<Item = FixedBinding>>(&mut self, bindings: T) {
1603 self.keystroke_matcher.register_fixed_bindings(bindings);
1604 }
1605 
1606 /// Register new actions with the app
1607 ///
1608 /// Editable Bindings have a name identifier which can be used to override their key bindings
1609 /// via the `set_custom_trigger` method.
1610 pub fn register_editable_bindings<A: IntoIterator<Item = EditableBinding>>(
1611 &mut self,
1612 actions: A,
1613 ) {
1614 self.keystroke_matcher.register_editable_bindings(actions);
1615 }
1616 
1617 /// Set a custom trigger for a given editable binding name
1618 ///
1619 /// This will override the default trigger for that action
1620 pub fn set_custom_trigger(&mut self, name: String, trigger: Trigger) {
1621 self.keystroke_matcher.set_custom_trigger(name, trigger);
1622 }
1623 
1624 pub(super) fn disable_key_bindings(&mut self, window_id: WindowId) {
1625 self.disabled_key_bindings_windows.insert(window_id);
1626 }
1627 
1628 pub(super) fn enable_key_bindings(&mut self, window_id: WindowId) {
1629 self.disabled_key_bindings_windows.remove(&window_id);
1630 }
1631 
1632 pub fn key_bindings_enabled(&self, window_id: WindowId) -> bool {
1633 !self.disabled_key_bindings_windows.contains(&window_id)
1634 }
1635 
1636 /// Remove any custom trigger associated with a given action
1637 ///
1638 /// This will return the trigger to its default state (if any)
1639 pub fn remove_custom_trigger<N>(&mut self, name: N)
1640 where
1641 N: AsRef<str>,
1642 {
1643 self.keystroke_matcher.remove_custom_trigger(name);
1644 }
1645 
1646 /// Fetch the key bindings that apply to the given window / view
1647 ///
1648 /// This will look at key bindings in precedence order (closest to the view) first and only
1649 /// return the _first_ binding for a given trigger condition. That binding is the one that
1650 /// would run if the keys were pressed, so it matches what bindings are "available" from that
1651 /// view.
1652 pub fn key_bindings_for_view(
1653 &self,
1654 window_id: WindowId,
1655 view_id: EntityId,
1656 ) -> Vec<BindingLens<'_>> {
1657 let contexts = self.contexts_for_window_and_view(window_id, view_id);
1658 let mut triggers = HashSet::with_capacity(contexts.len());
1659 let mut results = Vec::with_capacity(contexts.len());
1660 
1661 for binding in contexts
1662 .into_iter()
1663 // The contexts are ordered top-down (from the root view down to the current view),
1664 // however the precedence order is bottom-up, so we need to reverse the iteration order
1665 .rev()
1666 .flat_map(|c| self.keystroke_matcher.bindings_for_context(c))
1667 {
1668 // Include all empty triggers, since they can't "overlap"
1669 if binding.trigger.is_empty() || triggers.insert(binding.trigger) {
1670 results.push(binding);
1671 }
1672 }
1673 
1674 results
1675 }
1676 
1677 /// Fetch an iterator of `BindingLens` objects, with the editable key bindings
1678 /// modified by the custom bindings, where appropriate.
1679 ///
1680 /// Editable bindings will be returned first, followed by any fixed bindings in the reverse
1681 /// order they were added.
1682 pub fn get_key_bindings(&self) -> impl Iterator<Item = BindingLens<'_>> {
1683 self.keystroke_matcher.get_bindings()
1684 }
1685 
1686 /// Returns the first registered binding with the given name, if one exists.
1687 pub fn get_binding_by_name(&self, name: &str) -> Option<BindingLens<'_>> {
1688 self.keystroke_matcher.get_binding_by_name(name)
1689 }
1690 
1691 /// Executes an updater callback against the current binding for
1692 /// a custom action. A typical use of an updater is to update menu
1693 /// state based on the current contextual binding for a given custom action.
1694 pub fn update_custom_action_binding<F>(&self, custom_tag: CustomTag, mut updater: F)
1695 where
1696 F: FnMut(Option<BindingLens<'_>>),
1697 {
1698 updater(self.active_binding_for_custom_action(custom_tag));
1699 }
1700 
1701 /// Returns an optional binding for a custom action in the context of
1702 /// the currently focused window and view, if there is one.
1703 fn active_binding_for_custom_action(&self, custom_tag: CustomTag) -> Option<BindingLens<'_>> {
1704 let window_id = self.windows().active_window()?;
1705 let view_id = self.focused_view_id(window_id)?;
1706 let contexts = self.contexts_for_window_and_view(window_id, view_id);
1707 self.binding_for_custom_action(custom_tag, contexts)
1708 }
1709 
1710 pub fn default_binding_for_custom_action(
1711 &self,
1712 custom_tag: CustomTag,
1713 ) -> Option<BindingLens<'_>> {
1714 self.keystroke_matcher
1715 .default_binding_for_custom_action(custom_tag)
1716 }
1717 
1718 pub fn description_for_custom_action(
1719 &self,
1720 custom_tag: CustomTag,
1721 description_for: DescriptionContext,
1722 ) -> Option<String> {
1723 // Resolve via the dynamic override (if any) so menu-bar callers pick
1724 // up state-dependent labels automatically. `in_context` would skip
1725 // the override and return the static fallback.
1726 self.default_binding_for_custom_action(custom_tag)
1727 .and_then(|binding| binding.description)
1728 .map(|s| s.resolve(self, description_for).into_owned())
1729 }
1730 
1731 /// Returns an optional binding for a custom action in any of the given contexts.
1732 /// Expects contexts to be ordered from more general (root view) to more specific (leafs)
1733 /// and uses the first context that matches.
1734 pub fn binding_for_custom_action(
1735 &self,
1736 custom_tag: CustomTag,
1737 contexts: Vec<Context>,
1738 ) -> Option<BindingLens<'_>> {
1739 contexts
1740 .into_iter()
1741 // The contexts are ordered top-down (from the root view down to the current view),
1742 // however the precedence order is bottom-up, so we need to reverse the iteration order
1743 .rev()
1744 .find_map(|context| {
1745 self.keystroke_matcher
1746 .binding_for_custom_action_in_context(custom_tag, &context)
1747 })
1748 }
1749 
1750 fn contexts_for_window_and_view(&self, window_id: WindowId, view_id: EntityId) -> Vec<Context> {
1751 let responder_chain = self
1752 .presenter(window_id)
1753 .expect("Invalid window id")
1754 .borrow()
1755 .ancestors(view_id);
1756 match self.contexts_from_responder_chain(window_id, &responder_chain) {
1757 Ok(ctxs) => ctxs,
1758 Err(error) => {
1759 log::error!("Unable to fetch Key Bindings for View: {error}");
1760 Vec::new()
1761 }
1762 }
1763 }
1764 
1765 /// Fetch an iterator of editable bindings
1766 ///
1767 /// The triggers for those actions will be overwritten by any custom triggers
1768 ///
1769 /// Items will be returned in the reverse order they were registered, the most recently
1770 /// registered editable binding will have the highest precedence
1771 pub fn editable_bindings(&self) -> impl Iterator<Item = EditableBindingLens<'_>> {
1772 self.keystroke_matcher.editable_bindings()
1773 }
1774 
1775 /// Overrides any registered binding with has a [`Trigger::Custom`] to one that is keystroke
1776 /// based ([`Trigger::Keystrokes`]) using the provided `custom_to_keystroke` fn.
1777 pub fn convert_custom_triggers_to_keystroke_triggers(
1778 &mut self,
1779 custom_to_keystroke_fn: impl Fn(CustomTag) -> Option<Keystroke> + 'static,
1780 ) {
1781 self.keystroke_matcher
1782 .convert_custom_triggers_to_keystroke_triggers(custom_to_keystroke_fn);
1783 }
1784 
1785 pub fn register_default_keystroke_triggers_for_custom_actions(
1786 &mut self,
1787 custom_to_keystroke_fn: impl Fn(CustomTag) -> Option<Keystroke> + 'static,
1788 ) {
1789 self.keystroke_matcher
1790 .register_default_keystroke_triggers_for_custom_actions(custom_to_keystroke_fn);
1791 }
1792 
1793 /// Fetch an iterator of editable bindings that apply in a given window / view
1794 ///
1795 /// This will return all editable bindings, regardless of whether or not they have
1796 /// associated key bindings
1797 pub fn editable_bindings_for_view(
1798 &self,
1799 window_id: WindowId,
1800 view_id: EntityId,
1801 ) -> Vec<EditableBindingLens<'_>> {
1802 let responder_chain = self
1803 .presenter(window_id)
1804 .expect("Invalid window id")
1805 .borrow()
1806 .ancestors(view_id);
1807 let contexts = match self.contexts_from_responder_chain(window_id, &responder_chain) {
1808 Ok(ctxs) => ctxs,
1809 Err(error) => {
1810 log::error!("Unable to fetch Key Bindings for View: {error}");
1811 return Vec::new();
1812 }
1813 };
1814 
1815 self.keystroke_matcher
1816 .editable_bindings()
1817 .filter(|action| contexts.iter().any(|ctx| action.in_context(ctx)))
1818 .collect()
1819 }
1820 
1821 /// return a list of contexts corresponding to a responder chain.
1822 fn contexts_from_responder_chain(
1823 &self,
1824 window_id: WindowId,
1825 responder_chain: &[EntityId],
1826 ) -> Result<Vec<Context>> {
1827 let mut context_chain = Vec::new();
1828 for view_id in responder_chain {
1829 if let Some(view) = self
1830 .windows
1831 .get(&window_id)
1832 .and_then(|w| w.views.get(view_id))
1833 {
1834 let mut context = view.keymap_context(self);
1835 if self.platform_delegate.is_ime_open() {
1836 context.set.insert("IMEOpen");
1837 }
1838 context_chain.push(context);
1839 } else {
1840 return Err(anyhow!(
1841 "View {} in responder chain does not exist",
1842 view_id
1843 ));
1844 }
1845 }
1846 Ok(context_chain)
1847 }
1848 
1849 fn dispatch_standard_action(
1850 &mut self,
1851 action: StandardAction,
1852 window_id: WindowId,
1853 responder_chain: &[EntityId],
1854 ) -> Result<bool> {
1855 let mut context_chain = self.contexts_from_responder_chain(window_id, responder_chain)?;
1856 for (i, ctx) in context_chain.iter_mut().enumerate().rev() {
1857 let handled = match self.keystroke_matcher.match_standard(action, ctx) {
1858 MatchResult::Action(action) => self.dispatch_typed_action(
1859 window_id,
1860 &responder_chain[0..=i],
1861 action.as_ref(),
1862 log::Level::Info,
1863 ),
1864 _ => false,
1865 };
1866 // In this case, paste is the only valid interaction
1867 if handled && matches!(action, StandardAction::Paste) {
1868 self.dispatch_self_or_child_interacted_with(window_id, responder_chain);
1869 return Ok(true);
1870 }
1871 }
1872 Ok(false)
1873 }
1874 
1875 /// Returns the responder chain for a given context and window ID.
1876 ///
1877 /// The "responder chain" is the view hierarchy to match against with bindings.
1878 /// This prefers the focused view and its ancestors; if no view is focused it
1879 /// dispatches to the root view.
1880 fn get_responder_chain(&self, window_id: WindowId) -> Vec<EntityId> {
1881 if let Some(focused) = self.focused_view_id(window_id) {
1882 if let Some(presenter) = self.presenter(window_id) {
1883 presenter.borrow().ancestors(focused)
1884 } else {
1885 vec![]
1886 }
1887 } else if let Some(root) = self.root_view_id(window_id) {
1888 vec![root]
1889 } else {
1890 vec![]
1891 }
1892 }
1893 
1894 pub fn custom_action_bindings(&self) -> impl Iterator<Item = BindingLens<'_>> {
1895 self.keystroke_matcher.custom_action_bindings()
1896 }
1897 
1898 pub fn dispatch_custom_action<Action>(&mut self, action: Action, window_id: WindowId)
1899 where
1900 Action: Into<CustomTag> + Debug + Copy,
1901 {
1902 if self.key_bindings_enabled(window_id) {
1903 log::info!("Dispatching custom action {action:?}");
1904 let responder_chain = self.get_responder_chain(window_id);
1905 let res =
1906 self.dispatch_custom_action_internal(action.into(), window_id, &responder_chain);
1907 
1908 if let Ok(true) = res {
1909 self.dispatch_self_or_child_interacted_with(window_id, &responder_chain);
1910 }
1911 
1912 if let Err(error) = res {
1913 log::error!("error dispatching custom action: {error}");
1914 }
1915 } else {
1916 // We hit this case when the user is in the course of editing their keybindings.
1917 self.dispatch_custom_action_keystroke(action, window_id);
1918 }
1919 }
1920 
1921 /// Figures out what keystroke (if any) is bound to a custom action and dispatches it as a key event.
1922 /// This is used when the user is in the course of editing their keybindings and we need
1923 /// to get the raw keystroke for something that is currently bound to a custom action.
1924 ///
1925 /// This happens commonly with actions that are defined through Mac menu items (e.g. cmd-p for
1926 /// the command palette). If we want to map another keybinding to cmd-p while cmd-p is
1927 /// currently mapped to the command palette through a mac menu item, the only way to do it
1928 /// is by first handling the custom action, and then looking up the keystroke for the
1929 /// action, and then handling that as a raw key event.
1930 fn dispatch_custom_action_keystroke<Action>(
1931 &mut self,
1932 action: Action,
1933 window_id: WindowId,
1934 ) -> bool
1935 where
1936 Action: Into<CustomTag> + Debug + Clone + Copy,
1937 {
1938 self.contexts_from_responder_chain(window_id, &self.get_responder_chain(window_id))
1939 .ok()
1940 .and_then(|contexts| self.binding_for_custom_action(action.into(), contexts))
1941 .and_then(|binding| match binding.trigger {
1942 Trigger::Keystrokes(keys) => keys.first().cloned(),
1943 Trigger::Custom(custom_tag) => self
1944 .keystroke_matcher
1945 .default_keystroke_trigger_for_custom_action(*custom_tag),
1946 _ => None,
1947 })
1948 .map(|keystroke| Event::KeyDown {
1949 keystroke: keystroke.clone(),
1950 chars: keystroke.key,
1951 details: Default::default(),
1952 is_composing: false,
1953 })
1954 .and_then(|key_event| {
1955 self.presenter(window_id).map(|presenter| {
1956 log::info!("Dispatching key event {key_event:?} for custom action {action:?}");
1957 self.handle_non_keybound_event(key_event, window_id, presenter.clone())
1958 .handled
1959 })
1960 })
1961 .unwrap_or_default()
1962 }
1963 
1964 fn dispatch_custom_action_internal(
1965 &mut self,
1966 action: CustomTag,
1967 window_id: WindowId,
1968 responder_chain: &[EntityId],
1969 ) -> Result<bool> {
1970 let mut context_chain = self.contexts_from_responder_chain(window_id, responder_chain)?;
1971 for (i, ctx) in context_chain.iter_mut().enumerate().rev() {
1972 let handled = match self.keystroke_matcher.match_custom(action, ctx) {
1973 MatchResult::Action(action) => self.dispatch_typed_action(
1974 window_id,
1975 &responder_chain[0..=i],
1976 action.as_ref(),
1977 log::Level::Info,
1978 ),
1979 _ => false,
1980 };
1981 if handled {
1982 return Ok(true);
1983 }
1984 }
1985 Ok(false)
1986 }
1987 
1988 pub fn dispatch_keystroke(
1989 &mut self,
1990 window_id: WindowId,
1991 responder_chain: &[EntityId],
1992 keystroke: &Keystroke,
1993 is_composing: bool,
1994 ) -> Result<bool> {
1995 let mut context_chain = self.contexts_from_responder_chain(window_id, responder_chain)?;
1996 let mut pending = false;
1997 for (i, ctx) in context_chain.iter_mut().enumerate().rev() {
1998 if is_composing {
1999 ctx.set.insert("IMEOpen");
2000 }
2001 let handled = match self.keystroke_matcher.push_keystroke(
2002 keystroke.clone(),
2003 responder_chain[i],
2004 ctx,
2005 ) {
2006 MatchResult::None => false,
2007 MatchResult::Pending => {
2008 pending = true;
2009 false
2010 }
2011 MatchResult::Action(action) => self.dispatch_typed_action(
2012 window_id,
2013 &responder_chain[0..=i],
2014 action.as_ref(),
2015 log::Level::Info,
2016 ),
2017 };
2018 
2019 if handled {
2020 return Ok(true);
2021 }
2022 }
2023 Ok(pending)
2024 }
2025 
2026 /// Dispatches `self_or_child_interacted_with` on every view in the responder chain,
2027 /// and should only be called if the event was handled by a view in the chain.
2028 fn dispatch_self_or_child_interacted_with(
2029 &mut self,
2030 window_id: WindowId,
2031 responder_chain: &[EntityId],
2032 ) {
2033 for view_id in responder_chain {
2034 if let Some(view) = self
2035 .windows
2036 .get_mut(&window_id)
2037 .and_then(|w| w.views.remove(view_id))
2038 {
2039 view.self_or_child_interacted_with(self, window_id, *view_id);
2040 
2041 // Reinsert the view before moving on to the next link in the responder chain
2042 if let Some(window) = self.windows.get_mut(&window_id) {
2043 window.views.insert(*view_id, view);
2044 }
2045 }
2046 }
2047 }
2048 
2049 pub fn default_keystroke_trigger_for_custom_action(
2050 &self,
2051 custom_tag: CustomTag,
2052 ) -> Option<Keystroke> {
2053 self.keystroke_matcher
2054 .default_keystroke_trigger_for_custom_action(custom_tag)
2055 }
2056 
2057 pub fn add_model<T, F>(&mut self, build_model: F) -> ModelHandle<T>
2058 where
2059 T: Entity,
2060 F: FnOnce(&mut ModelContext<T>) -> T,
2061 {
2062 self.pending_flushes += 1;
2063 let model_id = EntityId::new();
2064 let mut ctx = ModelContext::new(self, model_id);
2065 let model = build_model(&mut ctx);
2066 self.models.insert(model_id, Box::new(model));
2067 self.flush_effects();
2068 ModelHandle::new(model_id, &self.ref_counts)
2069 }
2070 
2071 pub fn add_singleton_model<T, F>(&mut self, build_model: F) -> ModelHandle<T>
2072 where
2073 T: SingletonEntity,
2074 F: FnOnce(&mut ModelContext<T>) -> T,
2075 {
2076 let model_handle = self.add_model(build_model);
2077 let prev_value = self
2078 .singleton_models
2079 .insert(std::any::TypeId::of::<T>(), model_handle.clone().into());
2080 // Panic in debug mode if this is the second time a singleton model was
2081 // registered for type T.
2082 debug_assert!(
2083 prev_value.is_none(),
2084 "add_singleton_model() was called twice for {:?}",
2085 std::any::type_name::<T>()
2086 );
2087 model_handle
2088 }
2089 
2090 /// Delegates to the OS to request the user attention within the app. For mac this bounces the
2091 /// icon in the dock.
2092 pub(super) fn request_user_attention(&self, window_id: WindowId) {
2093 self.platform_delegate.request_user_attention(window_id);
2094 }
2095 
2096 /// Delegates to the OS to show the system character palette.
2097 pub fn open_character_palette(&mut self) {
2098 self.platform_delegate.open_character_palette();
2099 }
2100 
2101 /// Delegates to the OS to request permissions for sending desktop notifications.
2102 ///
2103 /// ## Platform-Specific
2104 /// * Linux: Always calls the `on_completion_callback` with a value of [`RequestPermissionsOutcome::Accepted`].
2105 pub(super) fn request_desktop_notification_permissions<F, T>(
2106 &mut self,
2107 view_id: EntityId,
2108 window_id: WindowId,
2109 on_completion_callback: F,
2110 ) where
2111 F: 'static + Send + Sync + FnOnce(&mut T, RequestPermissionsOutcome, &mut ViewContext<T>),
2112 T: View,
2113 {
2114 self.platform_delegate
2115 .request_desktop_notification_permissions(Box::new(
2116 move |request_permissions_outcome, ctx| {
2117 if let Some(mut view) = ctx
2118 .windows
2119 .get_mut(&window_id)
2120 .and_then(|w| w.views.remove(&view_id))
2121 {
2122 let mut view_context = ViewContext::new(ctx, window_id, view_id);
2123 on_completion_callback(
2124 view.as_mut()
2125 .as_any_mut()
2126 .downcast_mut()
2127 .expect("Should be able to downcast to mutable view."),
2128 request_permissions_outcome,
2129 &mut view_context,
2130 );
2131 ctx.windows
2132 .get_mut(&window_id)
2133 .expect("Should be able to retrieve window.")
2134 .views
2135 .insert(view_id, view);
2136 }
2137 },
2138 ))
2139 }
2140 
2141 pub fn reset_cursor(&mut self) {
2142 self.cursor_updated_for_view = None;
2143 self.platform_delegate.set_cursor_shape(Cursor::Arrow)
2144 }
2145 
2146 pub(crate) fn set_cursor_shape(
2147 &mut self,
2148 cursor: Cursor,
2149 window_id: WindowId,
2150 view_id: EntityId,
2151 ) {
2152 self.cursor_updated_for_view = Some((window_id, view_id));
2153 self.platform_delegate.set_cursor_shape(cursor)
2154 }
2155 
2156 #[cfg(test)]
2157 pub fn get_cursor_shape(&self) -> Cursor {
2158 self.platform_delegate.get_cursor_shape()
2159 }
2160 
2161 /// Delegates to the OS to send a desktop notification.
2162 pub(super) fn send_desktop_notification<F, T>(
2163 &mut self,
2164 content: UserNotification,
2165 view_id: EntityId,
2166 window_id: WindowId,
2167 on_error_callback: F,
2168 ) where
2169 F: 'static + Send + Sync + FnOnce(&mut T, NotificationSendError, &mut ViewContext<T>),
2170 T: View,
2171 {
2172 self.platform_delegate.send_desktop_notification(
2173 content,
2174 window_id,
2175 Box::new(move |notification_error, ctx| {
2176 if let Some(mut view) = ctx
2177 .windows
2178 .get_mut(&window_id)
2179 .and_then(|w| w.views.remove(&view_id))
2180 {
2181 let mut view_context = ViewContext::new(ctx, window_id, view_id);
2182 on_error_callback(
2183 view.as_mut()
2184 .as_any_mut()
2185 .downcast_mut()
2186 .expect("Should be able to downcast to mutable view."),
2187 notification_error,
2188 &mut view_context,
2189 );
2190 ctx.windows
2191 .get_mut(&window_id)
2192 .expect("Should be able to retrieve window.")
2193 .views
2194 .insert(view_id, view);
2195 }
2196 }),
2197 )
2198 }
2199 
2200 fn active_cursor_position(&mut self, window_id: WindowId) -> Option<CursorInfo> {
2201 let focused_view_id = self.focused_view_id(window_id)?;
2202 let view = self
2203 .windows
2204 .get_mut(&window_id)?
2205 .views
2206 .remove(&focused_view_id)?;
2207 let position = view.active_cursor_position(self, window_id, focused_view_id);
2208 
2209 if let Some(window) = self.windows.get_mut(&window_id) {
2210 window.views.insert(focused_view_id, view);
2211 }
2212 
2213 position
2214 }
2215 
2216 pub fn clipboard(&mut self) -> &mut dyn Clipboard {
2217 self.platform_delegate.clipboard()
2218 }
2219 
2220 pub fn set_last_mouse_move_event(&mut self, window_id: WindowId, event: Event) {
2221 match event {
2222 Event::MouseMoved { .. } => {
2223 let last_mouse_moved_event = self.get_last_mouse_moved_event(window_id);
2224 *last_mouse_moved_event.borrow_mut() = Some(event);
2225 }
2226 _ => {
2227 panic!("not a mouse move event")
2228 }
2229 }
2230 }
2231 
2232 fn get_last_mouse_moved_event(&mut self, window_id: WindowId) -> Rc<RefCell<Option<Event>>> {
2233 self.window_last_mouse_moved_event
2234 .entry(window_id)
2235 .or_default()
2236 .clone()
2237 }
2238 
2239 /// Creates a new window with the view returned by the `build_root_view` function as its root
2240 /// view.
2241 pub fn add_window<T, F>(
2242 &mut self,
2243 options: AddWindowOptions,
2244 build_root_view: F,
2245 ) -> (WindowId, ViewHandle<T>)
2246 where
2247 T: View + TypedActionView,
2248 F: FnOnce(&mut ViewContext<T>) -> T,
2249 {
2250 self.insert_window(options, build_root_view)
2251 }
2252 
2253 fn insert_window<T, F>(
2254 &mut self,
2255 add_window_options: AddWindowOptions,
2256 build_root_view: F,
2257 ) -> (WindowId, ViewHandle<T>)
2258 where
2259 T: View + TypedActionView,
2260 F: FnOnce(&mut ViewContext<T>) -> T,
2261 {
2262 let (window_id, _root_view_id) =
2263 self.insert_window_internal(None, add_window_options, |window_id, ctx| {
2264 ctx.windows.insert(window_id, Window::default());
2265 let root_handle = ctx.add_typed_action_view(window_id, build_root_view);
2266 let root_view_id = root_handle.id();
2267 ctx.windows
2268 .get_mut(&window_id)
2269 .expect("this window was just inserted and should still exist")
2270 .root_view = Some(root_handle.into());
2271 root_view_id
2272 });
2273 (
2274 window_id,
2275 self.root_view(window_id)
2276 .expect("should have just inserted a window and root view"),
2277 )
2278 }
2279 
2280 fn insert_window_internal<F>(
2281 &mut self,
2282 window_id: Option<WindowId>,
2283 add_window_options: AddWindowOptions,
2284 build_window_data: F,
2285 ) -> (WindowId, EntityId)
2286 where
2287 F: FnOnce(WindowId, &mut AppContext) -> EntityId,
2288 {
2289 let AddWindowOptions {
2290 window_style,
2291 window_bounds,
2292 title,
2293 fullscreen_state,
2294 background_blur_radius_pixels,
2295 background_blur_texture,
2296 anchor_new_windows_from_closed_position,
2297 on_gpu_driver_selected: on_gpu_driver_reported,
2298 window_instance,
2299 } = add_window_options;
2300 
2301 let window_id = window_id.unwrap_or_else(WindowId::new);
2302 
2303 // Make sure we store the window bounds before we create the root view,
2304 // in case it uses this value.
2305 self.window_bounds.insert(window_id, window_bounds.bounds());
2306 self.next_window_bounds_map
2307 .insert(window_id, anchor_new_windows_from_closed_position);
2308 
2309 // Clear the next window bounds if they were set - we don't want to start
2310 // from the last closed position after a new window has been created.
2311 self.next_window_bounds = None;
2312 
2313 self.presenters
2314 .insert(window_id, Rc::new(RefCell::new(Presenter::new(window_id))));
2315 
2316 let window_options = WindowOptions {
2317 bounds: window_bounds,
2318 fullscreen_state,
2319 hide_title_bar: true,
2320 title,
2321 style: window_style,
2322 background_blur_radius_pixels,
2323 background_blur_texture,
2324 gpu_power_preference: self.rendering_config.gpu_power_preference,
2325 backend_preference: self.rendering_config.backend_preference,
2326 on_gpu_device_info_reported: on_gpu_driver_reported.unwrap_or(Box::new(|_| {})),
2327 window_instance,
2328 };
2329 
2330 let callbacks = WindowCallbacks {
2331 standard_action_callback: Box::new(move |action, ctx| {
2332 log::info!("Dispatching standard action {action:?}");
2333 let responder_chain = ctx.get_responder_chain(window_id);
2334 let res = ctx.dispatch_standard_action(action, window_id, &responder_chain);
2335 if let Err(error) = res {
2336 log::error!("error dispatching standard action: {error}");
2337 }
2338 }),
2339 event_callback: Box::new(move |event, ctx| {
2340 let last_mouse_moved_event: Rc<RefCell<Option<Event>>> =
2341 ctx.get_last_mouse_moved_event(window_id);
2342 match event {
2343 Event::MouseMoved { .. } => {
2344 *last_mouse_moved_event.borrow_mut() = Some(event.clone())
2345 }
2346 // Update the last mouse moved event with the current state of the modifiers
2347 // so we don't dispatch a synthetic moused moved event with an incorrect modifier state.
2348 Event::ModifierStateChanged {
2349 modifiers,
2350 key_code,
2351 ..
2352 } => {
2353 if let Some(Event::MouseMoved { cmd, shift, .. }) =
2354 &mut (*last_mouse_moved_event.borrow_mut())
2355 {
2356 *cmd = modifiers.cmd;
2357 *shift = modifiers.shift;
2358 }
2359 
2360 if let Some(presenter) = ctx.presenter(window_id) {
2361 if let Some(key_code) = key_code {
2362 // Based on the key code in question and the new state of the modifier key,
2363 // we can infer whether it was pressed or released.
2364 let key_pressed = match key_code {
2365 KeyCode::ShiftLeft | KeyCode::ShiftRight => {
2366 Some(modifiers.shift)
2367 }
2368 KeyCode::ControlLeft | KeyCode::ControlRight => {
2369 Some(modifiers.ctrl)
2370 }
2371 KeyCode::AltLeft | KeyCode::AltRight => Some(modifiers.alt),
2372 KeyCode::SuperLeft | KeyCode::SuperRight => Some(modifiers.cmd),
2373 KeyCode::Fn => Some(modifiers.func),
2374 _ => None,
2375 };
2376 if let Some(key_pressed) = key_pressed {
2377 // Note: this can be slightly incorrect in a particular edge case where the user
2378 // uses 2 physical keys corresponding to the same logical modifer. For example:
2379 // 1. The user holds down right-alt - we fire the right-alt pressed event
2380 // 2. The user then holds down left-alt - we fire the left-alt pressed event
2381 // 3. The user lets go of left-alt - we would incorrectly fire the left-alt pressed event (since the logical state is still true)
2382 // 4. The user lets go of right-alt - we correctly fire the right-alt released event
2383 // This is a known limitation due to the underlying APIs being limited (we must use lower-level Apple
2384 // APIs to get the exact physical key states, which we currently don't do).
2385 let key_state = if key_pressed {
2386 KeyState::Pressed
2387 } else {
2388 KeyState::Released
2389 };
2390 
2391 ctx.handle_window_event(
2392 Event::ModifierKeyChanged {
2393 key_code,
2394 state: key_state,
2395 },
2396 window_id,
2397 presenter.clone(),
2398 );
2399 }
2400 }
2401 }
2402 }
2403 // Update the last mouse moved event on mouse up with the new position.
2404 // This makes sure that hoverables are updated to the proper mouse
2405 // position after a click-and-drag, as we don't update the cached event
2406 // on a LeftMouseDragged event.
2407 Event::LeftMouseUp {
2408 position: new_position,
2409 modifiers,
2410 } => {
2411 if let Some(Event::MouseMoved {
2412 cmd,
2413 shift,
2414 position,
2415 is_synthetic: _,
2416 }) = &mut (*last_mouse_moved_event.borrow_mut())
2417 {
2418 *position = new_position;
2419 *cmd = modifiers.cmd;
2420 *shift = modifiers.shift;
2421 }
2422 }
2423 _ => (),
2424 };
2425 
2426 if let Some(presenter) = ctx.presenter(window_id) {
2427 ctx.handle_window_event(event, window_id, presenter)
2428 } else {
2429 crate::windowing::EventDispatchResult::default()
2430 }
2431 }),
2432 resize_callback: Box::new(move |window, ctx| {
2433 let origin = window.origin();
2434 let size = window.size();
2435 ctx.window_bounds
2436 .insert(window_id, Some(RectF::new(origin, size)));
2437 
2438 window.request_redraw();
2439 
2440 // On Linux and Windows, we don't have a direct way to react to
2441 // window fullscreen state changes, so instead we're using a
2442 // resize event as a signal that the fullscreen state _may_ have
2443 // changed.
2444 #[cfg(any(target_os = "linux", windows))]
2445 crate::windowing::WindowManager::handle(ctx).update(ctx, |manager, ctx| {
2446 manager.update_is_active_window_fullscreen(ctx);
2447 });
2448 
2449 ctx.report_active_cursor_position_update();
2450 }),
2451 build_scene_callback: Box::new(move |window, ctx| ctx.build_scene(window_id, window)),
2452 frame_callback: Box::new(move |ctx| {
2453 ctx.trigger_on_frame_drawn_callbacks(window_id);
2454 }),
2455 draw_frame_error_callback: Box::new(move |ctx| {
2456 ctx.dispatch_draw_frame_error_callback(window_id);
2457 }),
2458 move_callback: Box::new(move |bound, ctx| {
2459 ctx.window_bounds.insert(window_id, Some(bound));
2460 ctx.report_active_cursor_position_update();
2461 }),
2462 active_cursor_position_callback: Box::new(move |ctx| {
2463 ctx.active_cursor_position(window_id)
2464 }),
2465 };
2466 
2467 let window_result = WindowManager::handle(self).update(self, |windowing_state, _ctx| {
2468 windowing_state.open_window(window_id, window_options, callbacks)
2469 });
2470 
2471 // Create the root view after adding the window but before registering an invalidation callback.
2472 // This ensures that a platform window is always available to user view code.
2473 let root_view_id = build_window_data(window_id, self);
2474 self.focus(window_id, root_view_id);
2475 
2476 match window_result {
2477 Err(err) => {
2478 log::error!("error opening window: {err}");
2479 }
2480 Ok(_) => {
2481 self.on_window_invalidated(window_id, move |window_id, ctx| {
2482 if let Some(window) = ctx.windows().platform_window(window_id) {
2483 // All we need to do when a window is invalidated is
2484 // request from the OS that it be redrawn. We'll do all
2485 // of the actual work later.
2486 window.request_redraw();
2487 
2488 // In tests, however, there's no real event loop, so we need to do the work now.
2489 // While this _shouldn't_ be necessary in integration tests, it currently is.
2490 if ctx.is_unit_test || cfg!(feature = "integration_tests") {
2491 ctx.build_scene(window_id, window.as_ctx());
2492 }
2493 }
2494 });
2495 }
2496 };
2497 
2498 (window_id, root_view_id)
2499 }
2500 
2501 #[allow(clippy::unwrap_in_result)]
2502 pub(crate) fn handle_window_closed(&mut self, window_id: WindowId) -> Option<ClosedWindowData> {
2503 // Defer ALL effect flushes until the window is fully removed from
2504 // self.windows. Without this guard, the flush that used to happen during
2505 // build_scene (in the test-only code path in on_window_invalidated) would
2506 // fire cascading effects (save_app, active_window_changed,
2507 // ClearMarkedText, etc.) while the window is still registered. Those
2508 // effects can trigger nested update_view calls on views in the
2509 // half-dead window, causing "circular view reference" panics.
2510 self.pending_flushes += 1;
2511 
2512 let view_ids = self
2513 .windows
2514 .get(&window_id)
2515 .map(|window| window.views.keys().copied().collect_vec());
2516 
2517 if let Some(view_ids) = &view_ids {
2518 for view_id in view_ids {
2519 // We're using .expect here even though the function returns an Option because we
2520 // know that the window exists at this point.
2521 if let Some(mut view) = self
2522 .windows
2523 .get_mut(&window_id)
2524 .expect("Window exists")
2525 .views
2526 .remove(view_id)
2527 {
2528 view.on_window_closed(self, window_id, *view_id);
2529 
2530 self.windows
2531 .get_mut(&window_id)
2532 .expect("Window exists")
2533 .views
2534 .insert(*view_id, view);
2535 }
2536 }
2537 }
2538 
2539 let fullscreen_state = self
2540 .windows()
2541 .platform_window(window_id)
2542 .map(|window| window.fullscreen_state())
2543 .unwrap_or_default();
2544 
2545 if let (Some(bounds), Some(NextNewWindowsHasThisWindowsBoundsUponClose::Yes)) = (
2546 self.window_bounds.get(&window_id),
2547 self.next_window_bounds_map.get(&window_id),
2548 ) {
2549 // Store the bounds of the window that was closed so that the next window
2550 // we reopen is positioned there.
2551 self.next_window_bounds = *bounds;
2552 }
2553 WindowManager::handle(self).update(self, |windowing_state, ctx| {
2554 windowing_state.remove_window(window_id, ctx);
2555 });
2556 self.presenters.remove(&window_id);
2557 self.invalidation_callbacks.remove(&window_id);
2558 self.window_invalidations.remove(&window_id);
2559 autotracking::close_window(window_id);
2560 
2561 let mut subscriptions = HashMap::new();
2562 let mut observations = HashMap::new();
2563 // Back up view_to_window mappings so they can be restored if the window is reopened
2564 // via reopen_closed_window(). This preserves the view-to-window associations.
2565 let mut view_to_window_backup = HashMap::new();
2566 for view_id in view_ids.into_iter().flatten() {
2567 if let Some(subs) = self.subscriptions.remove(&view_id) {
2568 subscriptions.insert(view_id, subs);
2569 }
2570 if let Some(obs) = self.observations.remove(&view_id) {
2571 observations.insert(view_id, obs);
2572 }
2573 if let Some(view_window_id) = self.view_to_window.remove(&view_id) {
2574 debug_assert_eq!(
2575 view_window_id, window_id,
2576 "View {view_id:?} was in window {view_window_id:?} but expected {window_id:?} - was it transferred during close?"
2577 );
2578 view_to_window_backup.insert(view_id, view_window_id);
2579 }
2580 }
2581 
2582 if !self.window_bounds.contains_key(&window_id) {
2583 log::info!("missing window bounds!");
2584 }
2585 if !self.windows.contains_key(&window_id) {
2586 log::info!("missing core window data!");
2587 }
2588 let (Some(window), Some(bounds)) = (
2589 self.windows.remove(&window_id),
2590 self.window_bounds.remove(&window_id),
2591 ) else {
2592 log::error!("Closed a window that was missing underlying window data!");
2593 self.flush_effects();
2594 return None;
2595 };
2596 
2597 let result = Some(ClosedWindowData {
2598 window_id,
2599 window,
2600 subscriptions,
2601 observations,
2602 view_to_window: view_to_window_backup,
2603 bounds,
2604 fullscreen_state,
2605 });
2606 
2607 self.flush_effects();
2608 result
2609 }
2610 
2611 pub fn reopen_closed_window(&mut self, data: ClosedWindowData) {
2612 let ClosedWindowData {
2613 window_id,
2614 window,
2615 subscriptions,
2616 observations,
2617 view_to_window,
2618 bounds,
2619 fullscreen_state,
2620 } = data;
2621 
2622 let Some(bounds) = bounds else {
2623 log::error!("Had no bounds for cached closed window!");
2624 return;
2625 };
2626 
2627 for (entity_id, subs) in subscriptions {
2628 self.subscriptions.insert(entity_id, subs);
2629 }
2630 for (entity_id, obs) in observations {
2631 self.observations.insert(entity_id, obs);
2632 }
2633 for (entity_id, win_id) in view_to_window {
2634 self.view_to_window.insert(entity_id, win_id);
2635 }
2636 
2637 let add_window_options = AddWindowOptions {
2638 // TODO(vorporeal): what's the right value here?
2639 background_blur_radius_pixels: None,
2640 background_blur_texture: false,
2641 window_bounds: WindowBounds::ExactPosition(bounds),
2642 // TODO(alokedesai): Determine if, and how, we want to pass the on_gpu_driver_reported
2643 // callback from the original window back to this window.
2644 on_gpu_driver_selected: None,
2645 fullscreen_state,
2646 ..Default::default()
2647 };
2648 let root_view_id = window
2649 .root_view
2650 .as_ref()
2651 .expect("should have root view")
2652 .id();
2653 self.insert_window_internal(
2654 Some(window_id),
2655 add_window_options,
2656 move |window_id, ctx| {
2657 ctx.windows.insert(window_id, window);
2658 root_view_id
2659 },
2660 );
2661 
2662 self.invalidate_all_views_for_window(window_id);
2663 }
2664 
2665 /// Returns the bounds and window style for the next window to create.
2666 /// This is a function of what window was last closed plus the positions
2667 /// of all current windows.
2668 pub fn next_window_bounds_and_style(&self) -> (WindowBounds, WindowStyle) {
2669 let active_window_id = self.windows().active_window();
2670 match (
2671 self.next_window_bounds,
2672 active_window_id.and_then(|id| self.window_bounds(&id)),
2673 ) {
2674 // If the last closed window position exactly overlays any current
2675 // window, then do a cascade from the active window instead of
2676 // using the last closed window position
2677 (Some(last_closed_rect), Some(active_window_rect))
2678 if self.matches_any_window_bounds(last_closed_rect) =>
2679 {
2680 (
2681 WindowBounds::ExactPosition(active_window_rect),
2682 WindowStyle::Cascade,
2683 )
2684 }
2685 // Otherwise, use the last closed window position and size as the spot
2686 // for launching the new window.
2687 (Some(last_closed_rect), _) => (
2688 WindowBounds::ExactPosition(last_closed_rect),
2689 WindowStyle::Normal,
2690 ),
2691 // If there is no last closed window but there is an active window,
2692 // cascade from the active window.
2693 (_, Some(active_window_rect)) => (
2694 WindowBounds::ExactPosition(active_window_rect),
2695 WindowStyle::Cascade,
2696 ),
2697 // And finally fall back to using the default window position.
2698 (_, _) => (WindowBounds::Default, WindowStyle::Normal),
2699 }
2700 }
2701 
2702 /// Builds a new scene for the given window.
2703 fn build_scene(&mut self, window_id: WindowId, window: &dyn WindowContext) -> Rc<Scene> {
2704 let mut scene = Rc::new(Scene::new(
2705 window.backing_scale_factor(),
2706 self.rendering_config(),
2707 ));
2708 let Some(presenter) = self.presenter(window_id) else {
2709 return scene;
2710 };
2711 
2712 // This outer loop exists because after redrawing a scene, we will sometimes emit an
2713 // artificial `MouseMoved` event to ensure that `Hoverable` elements are properly updated
2714 // if the layout changes. However, to prevent an infinite loop hanging the app, we limit
2715 // to a maximum of three iterations. If more invalidations are created, then those will be
2716 // handled on the next call to `update_windows`.
2717 for iter in 1..=3 {
2718 let invalidation = self.take_all_invalidations_for_window(window_id);
2719 
2720 // Always build the scene at least once, even if there
2721 // are no updated views.
2722 if invalidation.updated.is_empty() && !invalidation.redraw_requested && iter > 1 {
2723 break;
2724 }
2725 
2726 {
2727 let mut presenter = presenter.borrow_mut();
2728 presenter.invalidate(invalidation, self);
2729 
2730 // Skip rendering if a dimension is 0. This must happen after
2731 // invalidation to ensure the proper views are still invalidated.
2732 let size = window.size();
2733 if size.x() == 0. || size.y() == 0. {
2734 log::debug!(
2735 "Received window_id={window_id:?} with window size {size:?}. Skipping render"
2736 );
2737 break;
2738 }
2739 
2740 // Build the scene. As part of this process, we compute element
2741 // origins and bounding boxes.
2742 //
2743 // In the future, we should separate out position computation from
2744 // scene building, as we don't need to do the latter on each
2745 // iteration of this loop.
2746 scene = presenter.build_scene(
2747 size,
2748 window.backing_scale_factor(),
2749 window.max_texture_dimension_2d(),
2750 self,
2751 );
2752 
2753 // Cache the last position cache after rendering.
2754 self.last_frame_position_cache
2755 .insert(window_id, presenter.position_cache().clone());
2756 }
2757 
2758 // Synthesize a MouseMoved event in case any elements
2759 // are now hovered due to being in a different location.
2760 let last_mouse_moved_event: Rc<RefCell<Option<Event>>> =
2761 self.get_last_mouse_moved_event(window_id);
2762 let event = last_mouse_moved_event.borrow();
2763 if let Some(event) = event
2764 .as_ref()
2765 .and_then(Event::to_synthetic_mouse_move_event)
2766 {
2767 self.handle_window_event(event, window_id, presenter.clone());
2768 }
2769 }
2770 
2771 scene
2772 }
2773 
2774 /// Simulates rendering a frame for the given window.
2775 #[cfg(test)]
2776 pub fn simulate_render_frame(&mut self, window_id: WindowId) {
2777 let Some(window) = self.windows().platform_window(window_id) else {
2778 return;
2779 };
2780 self.build_scene(window_id, window.as_ctx());
2781 }
2782 
2783 pub fn add_view<T, F>(&mut self, window_id: WindowId, build_view: F) -> ViewHandle<T>
2784 where
2785 T: View,
2786 F: FnOnce(&mut ViewContext<T>) -> T,
2787 {
2788 self.add_option_view(window_id, |ctx| Some(build_view(ctx)))
2789 .unwrap()
2790 }
2791 
2792 pub fn add_option_view<T, F>(
2793 &mut self,
2794 window_id: WindowId,
2795 build_view: F,
2796 ) -> Option<ViewHandle<T>>
2797 where
2798 T: View,
2799 F: FnOnce(&mut ViewContext<T>) -> Option<T>,
2800 {
2801 let view_id = EntityId::new();
2802 self.pending_flushes += 1;
2803 let mut ctx = ViewContext::new(self, window_id, view_id);
2804 let handle = if let Some(view) = build_view(&mut ctx) {
2805 if let Some(window) = self.windows.get_mut(&window_id) {
2806 window.views.insert(view_id, Box::new(view));
2807 } else {
2808 panic!("Window does not exist");
2809 }
2810 self.view_to_window.insert(view_id, window_id);
2811 self.window_invalidations
2812 .entry(window_id)
2813 .or_default()
2814 .updated
2815 .insert(view_id);
2816 Some(ViewHandle::new(window_id, view_id, &self.ref_counts))
2817 } else {
2818 None
2819 };
2820 self.flush_effects();
2821 handle
2822 }
2823 
2824 /// Add a view that implements the `TypedAction` trait, including the default parent view
2825 ///
2826 /// This will create the view as normal as well as register it's `handle_action` method in the
2827 /// typed_actions hash.
2828 ///
2829 /// Note: This is intended to be the replacement for `add_view` with the conversion to typed
2830 /// actions (and will subsequently be renamed to `add_view` once that is complete)
2831 pub(crate) fn add_typed_action_view_with_parent<V, F>(
2832 &mut self,
2833 window_id: WindowId,
2834 build_view: F,
2835 parent_view_id: EntityId,
2836 ) -> ViewHandle<V>
2837 where
2838 V: TypedActionView + View,
2839 F: FnOnce(&mut ViewContext<V>) -> V,
2840 {
2841 self.add_typed_action_view_internal(window_id, build_view, Some(parent_view_id))
2842 }
2843 
2844 /// Add a view that implements the `TypedAction` trait
2845 ///
2846 /// This will create the view as normal as well as register it's `handle_action` method in the
2847 /// typed_actions hash.
2848 ///
2849 /// Note: This is intended to be the replacement for `add_view` with the conversion to typed
2850 /// actions (and will subsequently be renamed to `add_view` once that is complete)
2851 pub fn add_typed_action_view<V, F>(
2852 &mut self,
2853 window_id: WindowId,
2854 build_view: F,
2855 ) -> ViewHandle<V>
2856 where
2857 V: TypedActionView + View,
2858 F: FnOnce(&mut ViewContext<V>) -> V,
2859 {
2860 self.add_typed_action_view_internal(window_id, build_view, None)
2861 }
2862 
2863 fn add_typed_action_view_internal<V, F>(
2864 &mut self,
2865 window_id: WindowId,
2866 build_view: F,
2867 parent_view_id: Option<EntityId>,
2868 ) -> ViewHandle<V>
2869 where
2870 V: TypedActionView + View,
2871 F: FnOnce(&mut ViewContext<V>) -> V,
2872 {
2873 self.pending_flushes += 1;
2874 
2875 // Build the view and insert it into the window `views` map
2876 let view_id = EntityId::new();
2877 let mut ctx = ViewContext::new(self, window_id, view_id);
2878 let view = build_view(&mut ctx);
2879 let window = self
2880 .windows
2881 .get_mut(&window_id)
2882 .expect("Window does not exist");
2883 window.views.insert(view_id, Box::new(view));
2884 
2885 // Register in view_to_window mapping
2886 self.view_to_window.insert(view_id, window_id);
2887 
2888 // If a parent view ID was provided, add the view as a child of the parent
2889 if let Some(parent_view_id) = parent_view_id {
2890 if let Some(presenter) = self.presenter(window_id) {
2891 presenter.borrow_mut().set_parent(view_id, parent_view_id);
2892 }
2893 self.structural_child_to_parent
2894 .insert(view_id, parent_view_id);
2895 self.structural_parent_to_children
2896 .entry(parent_view_id)
2897 .or_default()
2898 .insert(view_id);
2899 }
2900 
2901 // Register the action handler for this view type (if it hasn't already been added)
2902 self.add_typed_action::<V>();
2903 // Mark the view as needing to be drawn
2904 self.window_invalidations
2905 .entry(window_id)
2906 .or_default()
2907 .updated
2908 .insert(view_id);
2909 
2910 // Create the handle for managing the view lifetime
2911 let handle = ViewHandle::new(window_id, view_id, &self.ref_counts);
2912 self.flush_effects();
2913 handle
2914 }
2915 
2916 /// Transfers a single view from one window to another.
2917 ///
2918 /// This moves the view to the target window and updates all internal mappings.
2919 /// The view's subscriptions and observations will continue to work correctly
2920 /// because they now use dynamic window lookup.
2921 ///
2922 /// Returns `true` if the transfer was successful, `false` if the view doesn't exist.
2923 pub fn transfer_view_to_window(
2924 &mut self,
2925 view_id: EntityId,
2926 source_window_id: WindowId,
2927 target_window_id: WindowId,
2928 ) -> bool {
2929 if source_window_id == target_window_id {
2930 return true;
2931 }
2932 
2933 let Some(source_window) = self.windows.get_mut(&source_window_id) else {
2934 return false;
2935 };
2936 
2937 let Some(view) = source_window.views.remove(&view_id) else {
2938 return false;
2939 };
2940 
2941 // Mark the view as removed from the source window's invalidation set.
2942 // This tells the renderer to stop tracking this view in the source window.
2943 self.window_invalidations
2944 .entry(source_window_id)
2945 .or_default()
2946 .removed
2947 .insert(view_id);
2948 
2949 let Some(target_window) = self.windows.get_mut(&target_window_id) else {
2950 // Target window doesn't exist - roll back by putting the view back in source window
2951 if let Some(source_window) = self.windows.get_mut(&source_window_id) {
2952 source_window.views.insert(view_id, view);
2953 }
2954 return false;
2955 };
2956 
2957 target_window.views.insert(view_id, view);
2958 self.view_to_window.insert(view_id, target_window_id);
2959 
2960 self.window_invalidations
2961 .entry(target_window_id)
2962 .or_default()
2963 .updated
2964 .insert(view_id);
2965 
2966 // Remove from autotracking in the old window. The view will be automatically
2967 // added to autotracking in the new window when it renders, since render_view()
2968 // tracks dependencies based on the current window_id.
2969 autotracking::remove_view(source_window_id, view_id);
2970 
2971 if let Some(mut view) = self
2972 .windows
2973 .get_mut(&target_window_id)
2974 .and_then(|w| w.views.remove(&view_id))
2975 {
2976 view.on_window_transferred(source_window_id, target_window_id, self, view_id);
2977 if let Some(window) = self.windows.get_mut(&target_window_id) {
2978 window.views.insert(view_id, view);
2979 }
2980 }
2981 
2982 true
2983 }
2984 
2985 /// Transfers a view and all its descendant views from one window to another.
2986 ///
2987 /// This is useful when transferring a component like a tab that contains
2988 /// multiple nested views. The view tree is determined by the presenter's
2989 /// parent-child relationships.
2990 ///
2991 /// Returns the list of view IDs that were transferred.
2992 pub fn transfer_view_tree_to_window(
2993 &mut self,
2994 root_view_id: EntityId,
2995 source_window_id: WindowId,
2996 target_window_id: WindowId,
2997 ) -> Vec<EntityId> {
2998 if source_window_id == target_window_id {
2999 return vec![root_view_id];
3000 }
3001 
3002 let descendants = self
3003 .presenter(source_window_id)
3004 .map(|presenter| presenter.borrow().descendants(root_view_id))
3005 .unwrap_or_default();
3006 
3007 let mut transferred = Vec::with_capacity(descendants.len() + 1);
3008 
3009 if self.transfer_view_to_window(root_view_id, source_window_id, target_window_id) {
3010 transferred.push(root_view_id);
3011 }
3012 
3013 for view_id in descendants {
3014 if self.transfer_view_to_window(view_id, source_window_id, target_window_id) {
3015 transferred.push(view_id);
3016 }
3017 }
3018 
3019 self.transfer_structural_children(source_window_id, target_window_id, &mut transferred);
3020 
3021 transferred
3022 }
3023 
3024 /// Transfers structural children of already-transferred views.
3025 ///
3026 /// Uses `structural_parent_to_children` to walk from transferred parents
3027 /// to their children, avoiding iteration over all views in the source window.
3028 fn transfer_structural_children(
3029 &mut self,
3030 source_window_id: WindowId,
3031 target_window_id: WindowId,
3032 transferred: &mut Vec<EntityId>,
3033 ) {
3034 let mut transferred_set: HashSet<EntityId> = transferred.iter().copied().collect();
3035 let mut to_process: Vec<EntityId> = transferred.clone();
3036 
3037 while let Some(parent_id) = to_process.pop() {
3038 let children: Vec<EntityId> = self
3039 .structural_parent_to_children
3040 .get(&parent_id)
3041 .map(|s| s.iter().copied().collect())
3042 .unwrap_or_default();
3043 
3044 for child_id in children {
3045 if transferred_set.contains(&child_id) {
3046 continue;
3047 }
3048 if self.transfer_view_to_window(child_id, source_window_id, target_window_id) {
3049 transferred.push(child_id);
3050 transferred_set.insert(child_id);
3051 to_process.push(child_id);
3052 }
3053 }
3054 }
3055 }
3056 
3057 fn remove_dropped_items(&mut self) {
3058 loop {
3059 let dropped_items = self.ref_counts.lock().take_dropped();
3060 if dropped_items.is_empty() {
3061 break;
3062 }
3063 
3064 for model_id in dropped_items.models {
3065 self.models.remove(&model_id);
3066 self.subscriptions.remove(&model_id);
3067 self.observations.remove(&model_id);
3068 }
3069 
3070 for (handle_window_id, view_id) in dropped_items.views {
3071 // Look up the current window from view_to_window mapping, which may differ
3072 // from handle_window_id if the view was transferred between windows.
3073 //
3074 // The entry may be missing when handle_window_closed() eagerly removes
3075 // view_to_window entries while the views are still alive in ClosedWindowData.
3076 // When those views' handles are later dropped, we correctly fall back to
3077 // handle_window_id.
3078 let current_window_id = self
3079 .view_to_window
3080 .remove(&view_id)
3081 .unwrap_or(handle_window_id);
3082 
3083 // Focus the root view if the view being removed is focused
3084 if let Some(focused_view_id) = self.focused_view_id(current_window_id) {
3085 if view_id == focused_view_id {
3086 if let Some(root_view_id) = self.root_view_id(current_window_id) {
3087 self.focus(current_window_id, root_view_id);
3088 }
3089 }
3090 }
3091 
3092 self.subscriptions.remove(&view_id);
3093 self.observations.remove(&view_id);
3094 if let Some(parent_id) = self.structural_child_to_parent.remove(&view_id) {
3095 if let Some(children) = self.structural_parent_to_children.get_mut(&parent_id) {
3096 children.remove(&view_id);
3097 if children.is_empty() {
3098 self.structural_parent_to_children.remove(&parent_id);
3099 }
3100 }
3101 }
3102 self.structural_parent_to_children.remove(&view_id);
3103 
3104 if let Some(window) = self.windows.get_mut(&current_window_id) {
3105 self.window_invalidations
3106 .entry(current_window_id)
3107 .or_default()
3108 .removed
3109 .insert(view_id);
3110 window.views.remove(&view_id);
3111 }
3112 
3113 autotracking::remove_view(current_window_id, view_id);
3114 }
3115 }
3116 }
3117 
3118 fn flush_effects(&mut self) {
3119 self.pending_flushes -= 1;
3120 
3121 if !self.flushing_effects && self.pending_flushes == 0 {
3122 self.flushing_effects = true;
3123 
3124 self.remove_dropped_items();
3125 
3126 while let Some(effect) = self.pending_effects.pop_front() {
3127 match effect {
3128 Effect::Event { entity_id, payload } => self.emit_event(entity_id, payload),
3129 Effect::ModelNotification { model_id } => self.notify_model_observers(model_id),
3130 Effect::ViewNotification { window_id, view_id } => {
3131 self.notify_view_observers(window_id, view_id)
3132 }
3133 Effect::Focus { window_id, view_id } => {
3134 self.focus(window_id, view_id);
3135 }
3136 Effect::TypedAction {
3137 window_id,
3138 view_id,
3139 action,
3140 } => {
3141 self.dispatch_typed_action_for_view(window_id, view_id, action.as_ref());
3142 }
3143 Effect::GlobalAction {
3144 name,
3145 location,
3146 arg,
3147 } => {
3148 self.dispatch_global_action_internal(name, location, arg.as_ref());
3149 }
3150 }
3151 
3152 self.remove_dropped_items();
3153 }
3154 
3155 self.flushing_effects = false;
3156 self.update_windows();
3157 }
3158 }
3159 
3160 fn update_windows(&mut self) {
3161 let invalidated_window_ids = self
3162 .window_invalidations
3163 .keys()
3164 .chain(autotracking::windows_with_invalidations().iter())
3165 .unique()
3166 .cloned()
3167 .collect_vec();
3168 for window_id in invalidated_window_ids {
3169 if let Some(mut callback) = self.invalidation_callbacks.remove(&window_id) {
3170 callback(window_id, self);
3171 self.invalidation_callbacks.insert(window_id, callback);
3172 }
3173 }
3174 }
3175 
3176 /// Collects invalidations for the given window from all sources: manual
3177 /// and autotracking.
3178 ///
3179 /// This operation is destructive: It will clear the caches for both manual and autotracked
3180 /// invalidations.
3181 pub(super) fn take_all_invalidations_for_window(
3182 &mut self,
3183 window_id: WindowId,
3184 ) -> WindowInvalidation {
3185 let mut invalidations = self
3186 .window_invalidations
3187 .remove(&window_id)
3188 .unwrap_or_default();
3189 invalidations
3190 .updated
3191 .extend(autotracking::take_invalidations_for_window(window_id));
3192 invalidations
3193 }
3194 
3195 #[cfg(any(test, feature = "test-util"))]
3196 pub fn simulate_window_event(
3197 &mut self,
3198 event: Event,
3199 window_id: WindowId,
3200 presenter: Rc<RefCell<Presenter>>,
3201 ) -> bool {
3202 self.handle_window_event(event, window_id, presenter)
3203 .handled
3204 }
3205 
3206 fn handle_window_event(
3207 &mut self,
3208 mut event: Event,
3209 window_id: WindowId,
3210 presenter: Rc<RefCell<Presenter>>,
3211 ) -> crate::windowing::EventDispatchResult {
3212 let mut event_munger: Box<EventMunger> = Box::new(|_, _| {});
3213 std::mem::swap(&mut event_munger, &mut self.event_munger);
3214 // Give the app a chance to modify the event first. The closure had to be moved out of
3215 // `self.event_munger` to avoid a double-borrow error, so swapped it into `event_munger`
3216 // local variable, then swap it back after.
3217 event_munger(&mut event, self);
3218 std::mem::swap(&mut event_munger, &mut self.event_munger);
3219 
3220 let mut keystroke_handled = false;
3221 if self.key_bindings_enabled(window_id) {
3222 // Checks (and possibly dispatches) for actions with a matching keybinding
3223 if let Event::KeyDown {
3224 keystroke,
3225 is_composing,
3226 ..
3227 } = &event
3228 {
3229 if let Some(focused_view_id) = self.focused_view_id(window_id) {
3230 let responder_chain = presenter.borrow().ancestors(focused_view_id);
3231 match self.dispatch_keystroke(
3232 window_id,
3233 &responder_chain,
3234 keystroke,
3235 *is_composing,
3236 ) {
3237 Ok(handled) => {
3238 keystroke_handled = handled;
3239 }
3240 Err(error) => {
3241 log::error!("error dispatching keystroke: {error}");
3242 }
3243 }
3244 }
3245 }
3246 }
3247 
3248 let mut result = crate::windowing::EventDispatchResult::default();
3249 if !keystroke_handled {
3250 result = self.handle_non_keybound_event(event.clone(), window_id, presenter.clone());
3251 }
3252 
3253 let handled = keystroke_handled || result.handled;
3254 
3255 // Only dispatch `self_or_child_interacted_with` if:
3256 // (1) the event was handled by a view in the responder chain, and
3257 // (2) the event is a valid interaction (we exclude mouse and scroll movements to reduce noise)
3258 if handled && !matches!(event, Event::MouseMoved { .. } | Event::ScrollWheel { .. }) {
3259 if let Some(focused_view_id) = self.focused_view_id(window_id) {
3260 let responder_chain = presenter.borrow().ancestors(focused_view_id);
3261 self.dispatch_self_or_child_interacted_with(window_id, &responder_chain);
3262 }
3263 }
3264 
3265 crate::windowing::EventDispatchResult {
3266 handled,
3267 soft_keyboard_requested: result.soft_keyboard_requested,
3268 }
3269 }
3270 
3271 /// Schedules an asynchronous task for each delayed notify. Removes any existing notify jobs that've been cancelled.
3272 pub fn manage_delayed_repaint_timers(&mut self, window_id: WindowId, repaint_at: Instant) {
3273 // Avoid creating new timers if a timer with a closer repaint time for
3274 // the same window already exists.
3275 if self.repaint_tasks.iter().any(|(_, task)| {
3276 task.window_id == window_id &&
3277 matches!(task.repaint_trigger, RepaintTrigger::Timer { instant } if instant <= repaint_at)
3278 }) {
3279 return;
3280 }
3281 
3282 let weak_app = self.weak_self.clone();
3283 
3284 let task_id = TaskId::new();
3285 let task = self.foreground.spawn(async move {
3286 Timer::after(repaint_at.saturating_duration_since(Instant::now())).await;
3287 if let Some(app) = weak_app.upgrade() {
3288 let mut app = app.borrow_mut();
3289 
3290 // If the timer is no longer in repaint_tasks, it was cancelled.
3291 if app.repaint_tasks.remove(&task_id).is_some() {
3292 app.window_invalidations
3293 .entry(window_id)
3294 .or_default()
3295 .redraw_requested = true;
3296 app.update_windows();
3297 }
3298 }
3299 });
3300 
3301 self.repaint_tasks.insert(
3302 task_id,
3303 RepaintTask {
3304 task,
3305 window_id,
3306 repaint_trigger: RepaintTrigger::Timer {
3307 instant: repaint_at,
3308 },
3309 },
3310 );
3311 }
3312 
3313 /// Schedules an asynchronous task for each delayed notify. Removes any existing notify jobs that've been cancelled.
3314 pub fn manage_pending_assets(
3315 &mut self,
3316 window_id: WindowId,
3317 pending_assets: HashSet<AssetHandle>,
3318 ) {
3319 pending_assets.into_iter().for_each(|pending_asset| {
3320 // Avoid creating new repaint tasks if this (window, asset) pairing already has a future.
3321 if self.repaint_tasks.iter().any(|(_, task)| {
3322 task.window_id == window_id && matches!(&task.repaint_trigger, RepaintTrigger::AssetLoaded { asset_handle } if asset_handle == &pending_asset)
3323 }) {
3324 return;
3325 }
3326 
3327 let asset_cache = AssetCache::as_ref(self);
3328 let Some(asset_loaded_future) = pending_asset.when_loaded(asset_cache) else {
3329 return;
3330 };
3331 let weak_app = self
3332 .weak_self
3333 .clone();
3334 
3335 let task_id = TaskId::new();
3336 
3337 let task = self.foreground.spawn(async move {
3338 asset_loaded_future.await;
3339 
3340 let Some(app) = weak_app.upgrade() else {
3341 return;
3342 };
3343 let mut app = app.borrow_mut();
3344 
3345 // If the timer is no longer in repaint_tasks, it was cancelled.
3346 if app.repaint_tasks.remove(&task_id).is_some() {
3347 app.window_invalidations
3348 .entry(window_id)
3349 .or_default()
3350 .redraw_requested = true;
3351 app.update_windows();
3352 }
3353 });
3354 
3355 self.repaint_tasks.insert(
3356 task_id,
3357 RepaintTask {
3358 task,
3359 window_id,
3360 repaint_trigger: RepaintTrigger::AssetLoaded {
3361 asset_handle: pending_asset,
3362 },
3363 },
3364 );
3365 })
3366 }
3367 
3368 fn load_fallback_family_and_redraw(
3369 &mut self,
3370 window_id: WindowId,
3371 fallback_family: ExternalFontFamily,
3372 request_sources: Vec<RequestedFallbackFontSource>,
3373 asset_sources: Vec<AssetSource>,
3374 ) {
3375 let asset_cache = AssetCache::as_ref(self);
3376 
3377 let mut font_family_bytes: Vec<Vec<u8>> = Vec::new();
3378 // Get the raw font bytes from the loaded assets.
3379 for asset in asset_sources
3380 .into_iter()
3381 .map(|source| asset_cache.load_asset::<fonts::FontBytes>(source))
3382 {
3383 match asset {
3384 AssetState::Loaded { data } => {
3385 // TODO(PLAT-746): Update API for loading a font family to
3386 // take an `Rc`, so we don't have to clone the font data.
3387 font_family_bytes.push(data.0.clone());
3388 }
3389 AssetState::Evicted => {
3390 log::warn!("Unable to load requested fallback font because it was evicted");
3391 }
3392 AssetState::FailedToLoad(e) => {
3393 log::warn!("Unable to load requested fallback font: {e:?}");
3394 }
3395 AssetState::Loading { .. } => {
3396 log::error!("Fallback font asset should not be in a loading state");
3397 }
3398 }
3399 }
3400 
3401 // Early return if we were not able to load any of the font assets for
3402 // this family.
3403 // TODO(PLAT-760): Implement a retry mechanism if we load some but not
3404 // all of the font assets for the family. Currently we will load the
3405 // partial font family into the cache and will not try loading again.
3406 if font_family_bytes.is_empty() {
3407 log::warn!(
3408 "Failed to load any fonts for the family {}",
3409 &fallback_family.name
3410 );
3411 return;
3412 }
3413 
3414 // Insert the family into the font cache.
3415 if !self
3416 .font_cache()
3417 .is_fallback_family_loaded(fallback_family.name)
3418 {
3419 if let Err(e) = fonts::Cache::handle(self).update(self, |cache, _| {
3420 cache.load_fallback_family_from_bytes(fallback_family, font_family_bytes)
3421 }) {
3422 log::warn!("Unable to load fallback family from bytes: {e:?}");
3423 return;
3424 }
3425 
3426 // TODO(PLAT-747): Ideally the font cache itself is a model and can
3427 // handle emitting these events.
3428 FallbackFontModel::handle(self).update(self, |model, ctx| {
3429 model.loaded_fallback_font(ctx);
3430 });
3431 }
3432 
3433 // Clear the glyph/layout caches before redrawing. These caches must
3434 // be cleared even if the fallback family has previously been loaded.
3435 for source in request_sources {
3436 match source {
3437 RequestedFallbackFontSource::GlyphForChar(key) => {
3438 fonts::Cache::handle(self).update(self, |cache, _| {
3439 cache.remove_glyphs_by_char_entry(key);
3440 });
3441 }
3442 RequestedFallbackFontSource::Line(key) => {
3443 if let Some(presenter) = self.presenter(window_id) {
3444 presenter.borrow().text_layout_cache().remove_line(&key);
3445 }
3446 }
3447 RequestedFallbackFontSource::TextFrame(key) => {
3448 if let Some(presenter) = self.presenter(window_id) {
3449 presenter
3450 .borrow()
3451 .text_layout_cache()
3452 .remove_text_frame(&key);
3453 }
3454 }
3455 }
3456 }
3457 
3458 // Trigger a redraw on the window.
3459 self.window_invalidations
3460 .entry(window_id)
3461 .or_default()
3462 .redraw_requested = true;
3463 self.update_windows();
3464 }
3465 
3466 pub(crate) fn load_requested_fallback_families(&mut self, window_id: WindowId) {
3467 let Some(fallback_font_source_provider) = self.fallback_font_source_provider.as_ref()
3468 else {
3469 static ONCE: std::sync::Once = std::sync::Once::new();
3470 ONCE.call_once(|| {
3471 log::warn!(
3472 "No fallback_font_source_provider registered; cannot load fallback fonts"
3473 );
3474 });
3475 
3476 return;
3477 };
3478 
3479 let requested_fallback_families =
3480 fonts::Cache::as_ref(self).take_requested_fallback_families();
3481 let asset_cache = AssetCache::as_ref(self);
3482 
3483 for (fallback_family, request_sources) in requested_fallback_families {
3484 let mut asset_sources = Vec::with_capacity(fallback_family.font_urls.len());
3485 let mut futures = Vec::with_capacity(fallback_family.font_urls.len());
3486 for fallback_font in fallback_family.font_urls.as_ref() {
3487 let asset_source = fallback_font_source_provider(fallback_font);
3488 let asset = asset_cache.load_asset::<fonts::FontBytes>(asset_source.clone());
3489 
3490 // If the font is loading, collect the future so we can wait
3491 // for it to resolve.
3492 if let AssetState::Loading { ref handle } = asset {
3493 if let Some(future) = handle.when_loaded(asset_cache) {
3494 futures.push(future);
3495 }
3496 }
3497 // We need to load the asset again once the future has resolved,
3498 // so collect the asset source.
3499 asset_sources.push(asset_source);
3500 }
3501 
3502 let weak_self_clone = self.weak_self.clone();
3503 self.foreground
3504 .spawn(async move {
3505 join_all(futures).await;
3506 
3507 let Some(app) = weak_self_clone.upgrade() else {
3508 return;
3509 };
3510 let mut app = app.borrow_mut();
3511 
3512 app.load_fallback_family_and_redraw(
3513 window_id,
3514 fallback_family,
3515 request_sources,
3516 asset_sources,
3517 );
3518 })
3519 .detach();
3520 }
3521 }
3522 
3523 fn handle_non_keybound_event(
3524 &mut self,
3525 event: Event,
3526 window_id: WindowId,
3527 presenter: Rc<RefCell<Presenter>>,
3528 ) -> crate::windowing::EventDispatchResult {
3529 let log_level = match &event {
3530 // If the action comes from the MouseMoved or ScrollWheel events,
3531 // dispatch it at the `trace` log level so it doesn't clutter the
3532 // logs by default.
3533 Event::MouseMoved { .. } | Event::ScrollWheel { .. } => log::Level::Trace,
3534 _ => {
3535 // Update last user action timestamp for non-hover events
3536 App::record_last_active_timestamp();
3537 log::Level::Info
3538 }
3539 };
3540 let dispatch_result = presenter.borrow_mut().dispatch_event(event, self);
3541 
3542 // Iterate through all timers, and put a task onto the main thread for each
3543 // to call back and notify the view when the timer triggers.
3544 for (timer_id, view_to_notify) in dispatch_result.notify_timers_to_set.iter() {
3545 let (timer_id, view_to_notify) = (*timer_id, *view_to_notify);
3546 let weak_app = self.weak_self.clone();
3547 let task = self.foreground.spawn(async move {
3548 Timer::after(view_to_notify.notify_at - Instant::now()).await;
3549 if let Some(app) = weak_app.upgrade() {
3550 let mut app = app.borrow_mut();
3551 if app.notify_tasks.remove(&timer_id).is_some() {
3552 log::info!(
3553 "notifying view observers and updating windows for timer id {timer_id}"
3554 );
3555 app.notify_view_observers(window_id, view_to_notify.view_id);
3556 // Note that for the hoverable delay this triggers the appropriate
3557 // behavior because the window stores the last mouse moved event and
3558 // dispatches it on every window redraw.
3559 // See the on_window_invalidated callback
3560 app.update_windows();
3561 }
3562 }
3563 });
3564 self.notify_tasks.insert(timer_id, task);
3565 }
3566 
3567 for timer_id in dispatch_result.notify_timers_to_clear {
3568 // Dropping the task should be sufficient to cancel it.
3569 self.notify_tasks.remove(&timer_id);
3570 }
3571 
3572 for view_id in dispatch_result.notified {
3573 self.notify_view_observers(window_id, view_id)
3574 }
3575 
3576 for action in dispatch_result.actions.into_iter().rev() {
3577 let responder_chain = presenter.borrow().ancestors(action.view_id);
3578 match action.kind {
3579 DispatchedActionKind::Legacy { name, arg } => {
3580 self.dispatch_action(
3581 window_id,
3582 &responder_chain,
3583 name,
3584 arg.as_ref(),
3585 log_level,
3586 );
3587 }
3588 DispatchedActionKind::Typed(action) => {
3589 self.dispatch_typed_action(
3590 window_id,
3591 &responder_chain,
3592 action.as_ref(),
3593 log_level,
3594 );
3595 }
3596 }
3597 }
3598 
3599 match dispatch_result.cursor_update {
3600 Some(CursorUpdate::Set {
3601 cursor, view_id, ..
3602 }) => self.set_cursor_shape(cursor, window_id, view_id),
3603 Some(CursorUpdate::Reset) => self.reset_cursor(),
3604 _ => {}
3605 }
3606 
3607 crate::windowing::EventDispatchResult {
3608 handled: dispatch_result.handled,
3609 soft_keyboard_requested: dispatch_result.soft_keyboard_requested,
3610 }
3611 }
3612 
3613 fn emit_event(&mut self, entity_id: EntityId, payload: Box<dyn Any>) {
3614 if let Some(subscriptions) = self.subscriptions.remove(&entity_id) {
3615 // Start tracking unsubscribes for this entity. Unsubscribes called from inside
3616 // callbacks are deferred and processed at the end, avoiding O(N²) tombstone scanning.
3617 //
3618 // Note: All callbacks that existed when the event started processing will be called.
3619 // Unsubscribe only prevents re-insertion (i.e., it affects future events, not the
3620 // current one).
3621 debug_assert!(
3622 self.pending_unsubscribes.is_none(),
3623 "pending_unsubscribes should be None at start of emit_event"
3624 );
3625 self.pending_unsubscribes = Some(PendingUnsubscribes {
3626 entity_id,
3627 keys: HashSet::new(),
3628 });
3629 
3630 let mut to_reinsert = Vec::new();
3631 
3632 for mut subscription in subscriptions {
3633 let alive = match &mut subscription {
3634 Subscription::FromModel { model_id, callback } => {
3635 if let Some(mut model) = self.models.remove(model_id) {
3636 callback(model.as_any_mut(), payload.as_ref(), self, *model_id);
3637 self.models.insert(*model_id, model);
3638 true
3639 } else {
3640 false
3641 }
3642 }
3643 Subscription::FromView {
3644 window_id: stored_window_id,
3645 view_id,
3646 callback,
3647 } => {
3648 let current_window_id = self
3649 .view_to_window
3650 .get(view_id)
3651 .copied()
3652 .unwrap_or(*stored_window_id);
3653 if let Some(mut view) = self
3654 .windows
3655 .get_mut(&current_window_id)
3656 .and_then(|window| window.views.remove(view_id))
3657 {
3658 callback(
3659 view.as_any_mut(),
3660 payload.as_ref(),
3661 self,
3662 current_window_id,
3663 *view_id,
3664 );
3665 
3666 // XXX We need to check whether window is None
3667 // once again because callback could
3668 // potentially erase the window (i.e. if we
3669 // handle the Terminal exit event)
3670 if let Some(window) = self.windows.get_mut(&current_window_id) {
3671 window.views.insert(*view_id, view);
3672 true
3673 } else {
3674 false
3675 }
3676 } else {
3677 false
3678 }
3679 }
3680 Subscription::FromApp { callback } => {
3681 callback(payload.as_ref(), self, entity_id);
3682 true
3683 }
3684 };
3685 
3686 if alive {
3687 to_reinsert.push(subscription);
3688 }
3689 }
3690 
3691 // Process any pending unsubscribes collected during callback execution.
3692 let pending = self.pending_unsubscribes.take().unwrap();
3693 
3694 // Remove unsubscribed entries from the subscriptions that existed when this event started.
3695 if !pending.keys.is_empty() {
3696 to_reinsert.retain(|sub| {
3697 sub.subscription_key()
3698 .is_none_or(|key| !pending.keys.contains(&key))
3699 });
3700 }
3701 
3702 // Collect any new subscriptions added during callback execution (e.g., a callback
3703 // that subscribes a new handler to this same entity).
3704 let mut final_subs = self.subscriptions.remove(&entity_id).unwrap_or_default();
3705 final_subs.extend(to_reinsert);
3706 
3707 // Re-insert surviving subscriptions.
3708 if !final_subs.is_empty() {
3709 self.subscriptions.insert(entity_id, final_subs);
3710 }
3711 }
3712 }
3713 
3714 fn notify_model_observers(&mut self, observed_id: EntityId) {
3715 // TODO: Apply the same deferred unsubscribe pattern used in `emit_event` to support
3716 // unobserving from inside an observation callback.
3717 if let Some(observations) = self.observations.remove(&observed_id) {
3718 if self.models.contains_key(&observed_id) {
3719 for mut observation in observations {
3720 let alive = match &mut observation {
3721 Observation::FromModel { model_id, callback } => {
3722 if let Some(mut model) = self.models.remove(model_id) {
3723 callback(model.as_any_mut(), observed_id, self, *model_id);
3724 self.models.insert(*model_id, model);
3725 true
3726 } else {
3727 false
3728 }
3729 }
3730 Observation::FromView {
3731 window_id: stored_window_id,
3732 view_id,
3733 callback,
3734 } => {
3735 let current_window_id = self
3736 .view_to_window
3737 .get(view_id)
3738 .copied()
3739 .unwrap_or(*stored_window_id);
3740 if let Some(mut view) = self
3741 .windows
3742 .get_mut(&current_window_id)
3743 .and_then(|w| w.views.remove(view_id))
3744 {
3745 callback(
3746 view.as_any_mut(),
3747 observed_id,
3748 self,
3749 current_window_id,
3750 *view_id,
3751 );
3752 if let Some(window) = self.windows.get_mut(&current_window_id) {
3753 window.views.insert(*view_id, view);
3754 }
3755 true
3756 } else {
3757 false
3758 }
3759 }
3760 Observation::FromApp { callback } => {
3761 callback(observed_id, self);
3762 true
3763 }
3764 };
3765 
3766 if alive {
3767 self.observations
3768 .entry(observed_id)
3769 .or_default()
3770 .push(observation);
3771 }
3772 }
3773 }
3774 }
3775 }
3776 
3777 fn notify_view_observers(&mut self, window_id: WindowId, view_id: EntityId) {
3778 self.window_invalidations
3779 .entry(window_id)
3780 .or_default()
3781 .updated
3782 .insert(view_id);
3783 }
3784 
3785 fn focus(&mut self, window_id: WindowId, focused_id: EntityId) {
3786 if self.windows.get(&window_id).and_then(|w| w.focused_view) == Some(focused_id) {
3787 return;
3788 }
3789 
3790 if self.suppress_focus_for_window == Some(window_id) {
3791 return;
3792 }
3793 self.pending_flushes += 1;
3794 
3795 if let Some((blurred_id, mut blurred)) = self.windows.get_mut(&window_id).and_then(|w| {
3796 let blurred_view = w.focused_view;
3797 w.focused_view = Some(focused_id);
3798 blurred_view.and_then(|id| w.views.remove(&id).map(|view| (id, view)))
3799 }) {
3800 blurred.on_blur(&BlurContext::SelfBlurred, self, window_id, blurred_id);
3801 self.windows
3802 .get_mut(&window_id)
3803 .unwrap()
3804 .views
3805 .insert(blurred_id, blurred);
3806 
3807 if let Some(presenter) = self.presenter(window_id) {
3808 let blur_ctx = BlurContext::DescendentBlurred(blurred_id);
3809 // Skip the last entry, it is the blurred view itself.
3810 for view_id in presenter
3811 .borrow()
3812 .ancestors(blurred_id)
3813 .into_iter()
3814 .rev()
3815 .skip(1)
3816 {
3817 if let Some(mut view) = self
3818 .windows
3819 .get_mut(&window_id)
3820 .and_then(|w| w.views.remove(&view_id))
3821 {
3822 view.on_blur(&blur_ctx, self, window_id, view_id);
3823 self.windows
3824 .get_mut(&window_id)
3825 .and_then(|w| w.views.insert(view_id, view));
3826 }
3827 }
3828 }
3829 }
3830 
3831 // Close the IME if it was open since the view that was focused has changed.
3832 // It's important for us to do this asynchronously: since we are in a method
3833 // that's called from UI framework code, we don't want to trigger platform
3834 // side effects that could cause the AppContext to be borrowed in
3835 // the same callstack.
3836 self.platform_delegate.close_ime_async(window_id);
3837 
3838 if let Some(mut focused) = self
3839 .windows
3840 .get_mut(&window_id)
3841 .and_then(|w| w.views.remove(&focused_id))
3842 {
3843 focused.on_focus(&FocusContext::SelfFocused, self, window_id, focused_id);
3844 self.windows
3845 .get_mut(&window_id)
3846 .unwrap()
3847 .views
3848 .insert(focused_id, focused);
3849 
3850 if let Some(presenter) = self.presenter(window_id) {
3851 let focus_ctx = FocusContext::DescendentFocused(focused_id);
3852 // Skip the last entry, it is the focused view itself.
3853 for view_id in presenter
3854 .borrow()
3855 .ancestors(focused_id)
3856 .into_iter()
3857 .rev()
3858 .skip(1)
3859 {
3860 if let Some(mut view) = self
3861 .windows
3862 .get_mut(&window_id)
3863 .and_then(|w| w.views.remove(&view_id))
3864 {
3865 view.on_focus(&focus_ctx, self, window_id, view_id);
3866 self.windows
3867 .get_mut(&window_id)
3868 .and_then(|w| w.views.insert(view_id, view));
3869 }
3870 }
3871 }
3872 }
3873 
3874 self.flush_effects();
3875 }
3876 
3877 pub(super) fn spawn_local<F>(&mut self, future: F) -> usize
3878 where
3879 F: 'static + Future,
3880 {
3881 let task_id = post_inc(&mut self.next_task_id);
3882 let app = self.weak_self.clone();
3883 self.foreground
3884 .spawn_boxed(
3885 async move {
3886 let output = future.await;
3887 if let Some(app) = app.upgrade() {
3888 // Ignore any errors that may occur when relaying task output,
3889 // as there's nothing we can do about the entity no longer
3890 // existing.
3891 let _ = app
3892 .borrow_mut()
3893 .relay_task_output(task_id, Box::new(output));
3894 }
3895 }
3896 .boxed_local(),
3897 )
3898 .detach();
3899 task_id
3900 }
3901 
3902 pub(super) fn spawn_stream_local<F>(
3903 &mut self,
3904 stream: F,
3905 done_tx: futures::channel::oneshot::Sender<()>,
3906 ) -> usize
3907 where
3908 F: 'static + crate::r#async::Stream,
3909 F::Item: SpawnableOutput,
3910 {
3911 // Spawn a background task to poll the stream, and forward items to the
3912 // main thread (foreground executor).
3913 let (tx, rx) = async_channel::unbounded();
3914 self.background
3915 .spawn(async move {
3916 let mut stream = pin!(stream);
3917 while let Some(item) = stream.next().await {
3918 // If we fail to send the item, the foreground task has dropped the receiver,
3919 // meaning the entity that spawned the stream no longer exists, and we can
3920 // stop polling the stream.
3921 if tx.send(item).await.is_err() {
3922 break;
3923 }
3924 }
3925 })
3926 .detach();
3927 
3928 // Spawn a task on the foreground executor to invoke the provided on_item and on_done
3929 // callbacks on the main thread.
3930 let task_id = post_inc(&mut self.next_task_id);
3931 let app = self.weak_self.clone();
3932 self.foreground
3933 .spawn(async move {
3934 let mut stream = pin!(rx);
3935 loop {
3936 match stream.next().await {
3937 Some(item) => {
3938 if let Some(app) = app.upgrade() {
3939 let mut app = app.borrow_mut();
3940 
3941 // If the entity that spawned the stream no longer exists, terminate
3942 // the stream.
3943 if app.relay_task_output(task_id, Box::new(item)).is_err() {
3944 app.stream_completed(task_id);
3945 break;
3946 }
3947 } else {
3948 break;
3949 }
3950 }
3951 None => {
3952 if let Some(app) = app.upgrade() {
3953 let mut app = app.borrow_mut();
3954 app.stream_completed(task_id);
3955 }
3956 let _ = done_tx.send(());
3957 break;
3958 }
3959 }
3960 }
3961 })
3962 .detach();
3963 task_id
3964 }
3965 
3966 /// Opens the file path using the default application configured to handle the given filetype.
3967 pub fn open_file_path(&mut self, path: &Path) {
3968 self.platform_delegate.open_file_path(path);
3969 }
3970 
3971 /// Opens the given file path in an explorer view. On MacOS this will open the file in finder.
3972 pub fn open_file_path_in_explorer(&mut self, path: &Path) {
3973 self.platform_delegate.open_file_path_in_explorer(path);
3974 }
3975 
3976 /// Prompt the user to pick file path(s) in the OS native file picker.
3977 pub fn open_file_picker(
3978 &mut self,
3979 callback: impl FnOnce(Result<Vec<String>, FilePickerError>, &mut AppContext)
3980 + Send
3981 + Sync
3982 + 'static,
3983 config: FilePickerConfiguration,
3984 ) {
3985 self.platform_delegate
3986 .open_file_picker(Box::new(callback), config)
3987 }
3988 
3989 /// Prompt the user to save a file with the OS native save file dialog.
3990 pub fn open_save_file_picker(
3991 &mut self,
3992 callback: impl FnOnce(Option<String>, &mut AppContext) + Send + Sync + 'static,
3993 config: SaveFilePickerConfiguration,
3994 ) {
3995 self.platform_delegate
3996 .open_save_file_picker(Box::new(callback), config)
3997 }
3998 
3999 pub fn application_bundle_info(
4000 &self,
4001 bundle_identifier: &str,
4002 ) -> Option<ApplicationBundleInfo<'_>> {
4003 self.platform_delegate
4004 .application_bundle_info(bundle_identifier)
4005 }
4006 
4007 /// Triggers termination of the app and optionally takes in a TerminationResult, which will be
4008 /// printed when the program exits.
4009 pub fn terminate_app(
4010 &mut self,
4011 termination_mode: TerminationMode,
4012 termination_result: Option<TerminationResult>,
4013 ) {
4014 if let Some(termination_result) = termination_result {
4015 #[cfg(debug_assertions)]
4016 self.termination_result
4017 .set(termination_result)
4018 .expect("Termination result should not have been set already");
4019 #[cfg(not(debug_assertions))]
4020 let _ = self.termination_result.set(termination_result);
4021 }
4022 self.platform_delegate.terminate_app(termination_mode);
4023 }
4024 
4025 pub fn check_view_focused(&self, window_id: WindowId, view_id: &EntityId) -> bool {
4026 let focused_view_id = match self.focused_view_id(window_id) {
4027 Some(id) => id,
4028 None => return false,
4029 };
4030 focused_view_id == *view_id
4031 }
4032 
4033 pub fn check_view_or_child_focused(&self, window_id: WindowId, view_id: &EntityId) -> bool {
4034 let focused_view_id = match self.focused_view_id(window_id) {
4035 Some(id) => id,
4036 None => return false,
4037 };
4038 let presenter = match self.presenter(window_id) {
4039 Some(p) => p,
4040 None => return false,
4041 };
4042 
4043 let borrowed_presenter = presenter.borrow();
4044 borrowed_presenter
4045 .ancestors(focused_view_id)
4046 .contains(view_id)
4047 }
4048 
4049 fn relay_task_output(&mut self, task_id: usize, output: Box<dyn Any>) -> Result<()> {
4050 self.pending_flushes += 1;
4051 let Some(task_callback) = self.task_callbacks.remove(&task_id) else {
4052 return Err(anyhow!("Unable to retrieve task callback."));
4053 };
4054 
4055 let mut result = Ok(());
4056 
4057 match task_callback {
4058 TaskCallback::ModelFromFuture { model_id, callback } => {
4059 if let Some(mut model) = self.models.remove(&model_id) {
4060 callback(model.as_any_mut(), output, self, model_id);
4061 self.models.insert(model_id, model);
4062 }
4063 self.task_done(task_id);
4064 }
4065 TaskCallback::ModelFromStream {
4066 model_id,
4067 mut on_item,
4068 on_done,
4069 } => {
4070 if let Some(mut model) = self.models.remove(&model_id) {
4071 on_item(model.as_any_mut(), output, self, model_id);
4072 self.models.insert(model_id, model);
4073 } else {
4074 result = Err(anyhow!(
4075 "Unable to retrieve model when relaying task output from stream"
4076 ));
4077 }
4078 // Streams go through different code paths compared to Futures.
4079 // Even if the stream halts after this call, we still need to
4080 // refer to the task callback in stream completed.
4081 self.task_callbacks.insert(
4082 task_id,
4083 TaskCallback::ModelFromStream {
4084 model_id,
4085 on_item,
4086 on_done,
4087 },
4088 );
4089 }
4090 TaskCallback::ViewFromFuture {
4091 window_id,
4092 view_id,
4093 callback,
4094 } => {
4095 if let Some(mut view) = self
4096 .windows
4097 .get_mut(&window_id)
4098 .and_then(|w| w.views.remove(&view_id))
4099 {
4100 callback(view.as_mut(), output, self, window_id, view_id);
4101 self.windows
4102 .get_mut(&window_id)
4103 .ok_or_else(|| anyhow!("Unable to retrieve window for view"))?
4104 .views
4105 .insert(view_id, view);
4106 }
4107 self.task_done(task_id);
4108 }
4109 TaskCallback::ViewFromStream {
4110 window_id,
4111 view_id,
4112 mut on_item,
4113 on_done,
4114 } => {
4115 if let Some(mut view) = self
4116 .windows
4117 .get_mut(&window_id)
4118 .and_then(|w| w.views.remove(&view_id))
4119 {
4120 on_item(view.as_mut(), output, self, window_id, view_id);
4121 self.windows
4122 .get_mut(&window_id)
4123 .ok_or_else(|| anyhow!("Unable to retrieve window for view"))?
4124 .views
4125 .insert(view_id, view);
4126 } else {
4127 result = Err(anyhow!(
4128 "Unable to retrieve view when relaying task output from stream"
4129 ));
4130 }
4131 // Streams go through different code paths compared to Futures.
4132 // Even if the stream halts after this call, we still need to
4133 // refer to the task callback in stream completed.
4134 self.task_callbacks.insert(
4135 task_id,
4136 TaskCallback::ViewFromStream {
4137 window_id,
4138 view_id,
4139 on_item,
4140 on_done,
4141 },
4142 );
4143 }
4144 };
4145 self.flush_effects();
4146 result
4147 }
4148 
4149 fn stream_completed(&mut self, task_id: usize) {
4150 self.pending_flushes += 1;
4151 let Some(task_callback) = self.task_callbacks.remove(&task_id) else {
4152 return;
4153 };
4154 match task_callback {
4155 TaskCallback::ModelFromStream {
4156 model_id, on_done, ..
4157 } => {
4158 if let Some(mut model) = self.models.remove(&model_id) {
4159 on_done(model.as_any_mut(), self, model_id);
4160 self.models.insert(model_id, model);
4161 }
4162 }
4163 TaskCallback::ViewFromStream {
4164 window_id,
4165 view_id,
4166 on_done: callback,
4167 ..
4168 } => {
4169 if let Some(mut view) = self
4170 .windows
4171 .get_mut(&window_id)
4172 .and_then(|w| w.views.remove(&view_id))
4173 {
4174 callback(view.as_mut(), self, window_id, view_id);
4175 self.windows
4176 .get_mut(&window_id)
4177 .expect("Window should exist.")
4178 .views
4179 .insert(view_id, view);
4180 }
4181 }
4182 _ => {}
4183 };
4184 self.flush_effects();
4185 self.task_done(task_id);
4186 }
4187 
4188 fn task_done(&self, _task_id: usize) {
4189 // If the receiver has been dropped, the app is likely terminating,
4190 // so ignore the error. Additionally, we only ever consume items
4191 // from this queue in tests, so if this isn't a test, don't stick
4192 // things into the channel, otherwise it will grow forever without
4193 // bound.
4194 #[cfg(test)]
4195 let _ = block_on(self.task_done.0.send(_task_id));
4196 }
4197 
4198 pub fn set_a11y_verbosity(&mut self, verbosity: AccessibilityVerbosity) {
4199 self.a11y_verbosity = verbosity;
4200 }
4201 
4202 #[cfg(test)]
4203 pub fn finish_pending_tasks(&self) -> impl Future<Output = ()> {
4204 let mut pending_tasks = self.task_callbacks.keys().cloned().collect::<HashSet<_>>();
4205 let task_done = self.task_done.1.clone();
4206 
4207 async move {
4208 while !pending_tasks.is_empty() {
4209 if let Ok(task_id) = task_done.recv().await {
4210 pending_tasks.remove(&task_id);
4211 } else {
4212 break;
4213 }
4214 }
4215 }
4216 }
4217 
4218 pub fn open_view_tree_debug_window(&mut self, target_window_id: WindowId) {
4219 let Some(presenter) = self.presenter(target_window_id) else {
4220 return;
4221 };
4222 let Some(root_view_id) = self.root_view_id(target_window_id) else {
4223 return;
4224 };
4225 
4226 let Some(current_bounds) = self.window_bounds(&target_window_id) else {
4227 return;
4228 };
4229 let size = Vector2F::new(340., 540.);
4230 let origin = Vector2F::new(
4231 current_bounds.origin().x() + current_bounds.width() - size.x() - 20.,
4232 current_bounds.origin().y() + 20.,
4233 );
4234 
4235 let options = AddWindowOptions {
4236 window_bounds: WindowBounds::ExactPosition(RectF::new(origin, size)),
4237 anchor_new_windows_from_closed_position:
4238 NextNewWindowsHasThisWindowsBoundsUponClose::No,
4239 window_instance: Some("dev.warp.strato_ui-debug".to_owned()),
4240 title: Some("View Tree Debugger".to_owned()),
4241 ..Default::default()
4242 };
4243 self.add_window(options, |ctx| {
4244 crate::debug::DebugRootView::new(
4245 target_window_id,
4246 presenter.borrow().parents(),
4247 root_view_id,
4248 ctx,
4249 )
4250 });
4251 }
4252 
4253 pub fn record_app_focus(&mut self, user_id: Option<String>, anonymous_id: String) {
4254 self.app_focus_info.record_app_focus(user_id, anonymous_id);
4255 }
4256 
4257 pub fn record_app_blur(&mut self, user_id: Option<String>, anonymous_id: String) {
4258 self.app_focus_info.record_app_blur(user_id, anonymous_id);
4259 }
4260 
4261 pub fn try_record_daily_app_focus_duration(
4262 &mut self,
4263 user_id: Option<String>,
4264 anonymous_id: String,
4265 ) {
4266 self.app_focus_info
4267 .try_record_daily_app_focus_duration(user_id, anonymous_id);
4268 }
4269 
4270 pub fn is_screen_reader_enabled(&self) -> Option<bool> {
4271 self.platform_delegate.is_screen_reader_enabled()
4272 }
4273 
4274 /// A way for applications to specify custom fallback fonts.
4275 ///
4276 /// Takes a function that maps characters to external font families, each
4277 /// containing URLs to the font files for that family.
4278 ///
4279 /// If a character cannot be rendered using the existing loaded fonts, and
4280 /// the fallback font function specifies a fallback font family, the font
4281 /// family will be lazy-loaded and the character will be re-rendered with
4282 /// the specified font.
4283 pub fn set_fallback_font_fn(
4284 &mut self,
4285 f: impl Fn(char) -> Option<fonts::ExternalFontFamily> + Send + Sync + 'static,
4286 ) {
4287 fonts::Cache::handle(self).update(self, |cache, _| {
4288 cache.set_fallback_font_fn(Box::new(f));
4289 });
4290 }
4291}
4292 
4293impl UpdateModel for AppContext {
4294 fn update_model<T, F, S>(&mut self, handle: &ModelHandle<T>, update: F) -> S
4295 where
4296 T: Entity,
4297 F: FnOnce(&mut T, &mut ModelContext<T>) -> S,
4298 {
4299 if let Some(mut model) = self.models.remove(&handle.id()) {
4300 self.pending_flushes += 1;
4301 let mut ctx = ModelContext::new(self, handle.id());
4302 let result = update(
4303 model
4304 .as_any_mut()
4305 .downcast_mut()
4306 .expect("Downcast is type safe"),
4307 &mut ctx,
4308 );
4309 self.models.insert(handle.id(), model);
4310 self.flush_effects();
4311 result
4312 } else {
4313 panic!("Circular model update");
4314 }
4315 }
4316}
4317 
4318impl UpdateView for AppContext {
4319 fn update_view<T, F, S>(&mut self, handle: &ViewHandle<T>, update: F) -> S
4320 where
4321 T: View,
4322 F: FnOnce(&mut T, &mut ViewContext<T>) -> S,
4323 {
4324 self.pending_flushes += 1;
4325 let window_id = handle.window_id(self);
4326 let mut view = if let Some(window) = self.windows.get_mut(&window_id) {
4327 if let Some(view) = window.views.remove(&handle.id()) {
4328 view
4329 } else {
4330 panic!("Circular view update");
4331 }
4332 } else {
4333 panic!("Window does not exist");
4334 };
4335 
4336 let mut ctx = ViewContext::new(self, window_id, handle.id());
4337 let result = update(
4338 view.as_any_mut()
4339 .downcast_mut()
4340 .expect("Downcast is type safe"),
4341 &mut ctx,
4342 );
4343 if let Some(window) = self.windows.get_mut(&window_id) {
4344 window.views.insert(handle.id(), view);
4345 }
4346 self.flush_effects();
4347 result
4348 }
4349}
4350 
4351impl AddSingletonModel for AppContext {
4352 fn add_singleton_model<T, F>(&mut self, build_model: F) -> ModelHandle<T>
4353 where
4354 T: SingletonEntity,
4355 F: FnOnce(&mut super::ModelContext<T>) -> T,
4356 {
4357 AppContext::add_singleton_model(self, build_model)
4358 }
4359}
4360 
4361pub struct ClosedWindowData {
4362 pub window_id: WindowId,
4363 window: Window,
4364 subscriptions: HashMap<EntityId, Vec<Subscription>>,
4365 observations: HashMap<EntityId, Vec<Observation>>,
4366 view_to_window: HashMap<EntityId, WindowId>,
4367 // TODO(vorporeal): why is AppContext.window_bounds holding an option?
4368 bounds: Option<RectF>,
4369 fullscreen_state: FullscreenState,
4370}
4371 
4372impl AppContext {
4373 pub fn font_cache(&self) -> &fonts::Cache {
4374 fonts::Cache::as_ref(self)
4375 }
4376 
4377 pub fn root_view_id(&self, window_id: WindowId) -> Option<EntityId> {
4378 self.windows
4379 .get(&window_id)
4380 .and_then(|window| window.root_view.as_ref().map(|v| v.id()))
4381 }
4382 
4383 pub fn focused_view_id(&self, window_id: WindowId) -> Option<EntityId> {
4384 self.windows
4385 .get(&window_id)
4386 .and_then(|window| window.focused_view)
4387 }
4388 
4389 pub fn view_name(&self, window_id: WindowId, view_id: EntityId) -> Option<&str> {
4390 self.windows
4391 .get(&window_id)
4392 .and_then(|window| window.views.get(&view_id))
4393 .map(|view| view.ui_name())
4394 }
4395 
4396 /// Returns all the views of type `T` within `window_id`.
4397 pub fn views_of_type<T: View>(&self, window_id: WindowId) -> Option<Vec<ViewHandle<T>>> {
4398 let ref_counts = &self.ref_counts;
4399 self.windows.get(&window_id).map(|window| {
4400 window
4401 .views
4402 .iter()
4403 .filter(|(_, v)| (*v).as_any().type_id() == TypeId::of::<T>())
4404 .map(|(view_id, _)| ViewHandle::new(window_id, *view_id, ref_counts))
4405 .collect::<Vec<ViewHandle<T>>>()
4406 })
4407 }
4408 
4409 /// Returns the view of type `T` within `window_id` with the given `entity_id`.
4410 pub fn view_with_id<T: View>(
4411 &self,
4412 window_id: WindowId,
4413 entity_id: EntityId,
4414 ) -> Option<ViewHandle<T>> {
4415 let ref_counts = &self.ref_counts;
4416 self.windows.get(&window_id).and_then(|window| {
4417 window
4418 .views
4419 .get(&entity_id)
4420 .filter(|view| (*view).as_any().type_id() == TypeId::of::<T>())
4421 .map(|_| ViewHandle::new(window_id, entity_id, ref_counts))
4422 })
4423 }
4424 
4425 /// Opens the given URL in the default application configured to handle the URL.
4426 pub fn open_url(&self, url: &str) {
4427 let effective_url = (self.before_open_url_callback)(url, self);
4428 self.platform_delegate.open_url(&effective_url);
4429 }
4430 
4431 pub fn system_theme(&self) -> SystemTheme {
4432 self.platform_delegate.system_theme()
4433 }
4434 
4435 pub fn is_headless(&self) -> bool {
4436 self.platform_delegate.is_headless()
4437 }
4438 
4439 pub fn microphone_access_state(&self) -> MicrophoneAccessState {
4440 self.platform_delegate.microphone_access_state()
4441 }
4442 
4443 pub fn windows(&self) -> &WindowManager {
4444 WindowManager::as_ref(self)
4445 }
4446 
4447 pub fn window_ids(&self) -> impl Iterator<Item = WindowId> + '_ {
4448 self.windows.keys().cloned()
4449 }
4450 
4451 pub fn is_wayland(&self) -> bool {
4452 matches!(
4453 self.windows().windowing_system(),
4454 Some(windowing::System::Wayland)
4455 )
4456 }
4457 
4458 /// Returns all view IDs registered in the given window.
4459 pub fn view_ids_for_window(&self, window_id: WindowId) -> Vec<EntityId> {
4460 self.windows
4461 .get(&window_id)
4462 .map(|window| window.views.keys().copied().collect())
4463 .unwrap_or_default()
4464 }
4465 
4466 pub fn render_view(&self, window_id: WindowId, view_id: EntityId) -> Result<Box<dyn Element>> {
4467 // surfacing the error of a missing window earlier
4468 let window = self
4469 .windows
4470 .get(&window_id)
4471 .ok_or_else(|| anyhow!("window not found"))?;
4472 window
4473 .views
4474 .get(&view_id)
4475 .map(|view| autotracking::render_view(window_id, view_id, || view.render(self)))
4476 .ok_or_else(|| anyhow!("view not found"))
4477 }
4478 
4479 pub fn render_views(&self, window_id: WindowId) -> Result<HashMap<EntityId, Box<dyn Element>>> {
4480 self.windows
4481 .get(&window_id)
4482 .map(|w| {
4483 w.views
4484 .iter()
4485 .map(|(id, view)| (*id, view.render(self)))
4486 .collect::<HashMap<_, _>>()
4487 })
4488 .ok_or_else(|| anyhow!("window not found"))
4489 }
4490 
4491 /// Returns the cached element position from the last rendered frame, if there is one.
4492 pub fn element_position_by_id_at_last_frame<S>(
4493 &self,
4494 window_id: WindowId,
4495 id: S,
4496 ) -> Option<RectF>
4497 where
4498 S: AsRef<str>,
4499 {
4500 self.last_frame_position_cache
4501 .get(&window_id)
4502 .and_then(|position_cache| position_cache.get_position(id))
4503 }
4504}
4505 
4506impl AsRef<AppContext> for AppContext {
4507 fn as_ref(&self) -> &AppContext {
4508 self
4509 }
4510}
4511 
4512impl ModelAsRef for AppContext {
4513 fn model<T: Entity>(&self, handle: &ModelHandle<T>) -> &T {
4514 if let Some(model) = self.models.get(&handle.id()) {
4515 model
4516 .as_any()
4517 .downcast_ref()
4518 .expect("downcast should be type safe")
4519 } else {
4520 panic!(
4521 "circular model reference for model type {}",
4522 std::any::type_name::<T>()
4523 );
4524 }
4525 }
4526}
4527 
4528impl ReadModel for AppContext {
4529 fn read_model<T, F, S>(&self, handle: &ModelHandle<T>, read: F) -> S
4530 where
4531 T: Entity,
4532 F: FnOnce(&T, &AppContext) -> S,
4533 {
4534 read(self.model(handle), self)
4535 }
4536}
4537 
4538impl ViewAsRef for AppContext {
4539 fn view<T: View>(&self, handle: &ViewHandle<T>) -> &T {
4540 let window_id = handle.window_id(self);
4541 if let Some(window) = self.windows.get(&window_id) {
4542 if let Some(view) = window.views.get(&handle.id()) {
4543 view.as_any()
4544 .downcast_ref()
4545 .expect("downcast should be type safe")
4546 } else {
4547 panic!(
4548 "circular view reference for view type {}",
4549 std::any::type_name::<T>()
4550 );
4551 }
4552 } else {
4553 panic!("window does not exist");
4554 }
4555 }
4556 
4557 /// Returns the backing view, or None if materializing the view would
4558 /// otherwise produce a circular view reference.
4559 fn try_view<T: View>(&self, handle: &ViewHandle<T>) -> Option<&T> {
4560 let window_id = handle.window_id(self);
4561 self.windows
4562 .get(&window_id)?
4563 .views
4564 .get(&handle.id())?
4565 .as_any()
4566 .downcast_ref()
4567 }
4568}
4569 
4570impl ReadView for AppContext {
4571 fn read_view<T, F, S>(&self, handle: &ViewHandle<T>, read: F) -> S
4572 where
4573 T: View,
4574 F: FnOnce(&T, &AppContext) -> S,
4575 {
4576 read(self.view(handle), self)
4577 }
4578}
4579 
4580impl GetSingletonModelHandle for AppContext {
4581 fn get_singleton_model_handle<T: SingletonEntity>(&self) -> ModelHandle<T> {
4582 match self.singleton_models.get(&std::any::TypeId::of::<T>()) {
4583 Some(model_handle) => model_handle
4584 .clone()
4585 .downcast()
4586 .expect("a registered singleton model should never have a refcount of 0"),
4587 None => {
4588 panic!(
4589 "Cannot get singleton model of type {:?} that was never registered",
4590 std::any::type_name::<T>()
4591 );
4592 }
4593 }
4594 }
4595}
4596 
4597impl AppContext {
4598 pub(super) fn get_singleton_model_as_ref<T: SingletonEntity>(&self) -> &T {
4599 match self.singleton_models.get(&std::any::TypeId::of::<T>()) {
4600 Some(model_handle) => model_handle
4601 .downcast_ref(self)
4602 .expect("downcast should be type safe"),
4603 None => {
4604 panic!(
4605 "Cannot get singleton model of type {:?} that was never registered",
4606 std::any::type_name::<T>()
4607 );
4608 }
4609 }
4610 }
4611}
4612