1use open_gpui_scheduler::Instant;
2use std::{
3 any::{TypeId, type_name},
4 cell::{BorrowMutError, Cell, Ref, RefCell, RefMut},
5 marker::PhantomData,
6 mem,
7 ops::{Deref, DerefMut},
8 path::{Path, PathBuf},
9 rc::{Rc, Weak},
10 sync::{Arc, atomic::Ordering::SeqCst},
11 time::Duration,
12};
13
14use anyhow::{Context as _, Result, anyhow};
15use derive_more::{Deref, DerefMut};
16use futures::{
17 Future, FutureExt,
18 channel::oneshot,
19 future::{LocalBoxFuture, Shared},
20};
21use itertools::Itertools;
22use parking_lot::RwLock;
23use slotmap::SlotMap;
24
25pub use async_context::*;
26#[cfg(any(test, feature = "test-support"))]
27pub use bench_context::{BenchAppContext, BenchWindowContext};
28pub use context::*;
29pub use entity_map::*;
30#[cfg(any(test, feature = "test-support"))]
31pub use headless_app_context::*;
32use open_gpui_collections::{
33 FxHashMap, FxHashSet, HashMap, TypeIdHashMap, TypeIdHashSet, VecDeque,
34};
35use open_gpui_core_util::{ResultExt, debug_panic};
36use open_gpui_http_client::{HttpClient, Url};
37use smallvec::SmallVec;
38#[cfg(any(test, feature = "test-support"))]
39pub use test_app::*;
40#[cfg(any(test, feature = "test-support"))]
41pub use test_context::*;
42#[cfg(all(target_os = "macos", any(test, feature = "test-support")))]
43pub use visual_test_context::*;
44
45#[cfg(any(feature = "inspector", debug_assertions))]
46use crate::InspectorElementRegistry;
47use crate::{
48 Action, ActionBuildError, ActionRegistry, Any, AnyView, AnyWindowHandle, AppContext, Arena,
49 ArenaBox, Asset, AssetSource, BackgroundExecutor, Bounds, ClipboardItem, CursorStyle,
50 DispatchPhase, DisplayId, EventEmitter, FocusHandle, FocusMap, ForegroundExecutor, Global,
51 KeyBinding, KeyContext, Keymap, Keystroke, LayoutId, Menu, MenuItem, MouseButton, OwnedMenu,
52 PathPromptOptions, Pixels, Platform, PlatformDisplay, PlatformFocusedWindow,
53 PlatformHoveredWindow, PlatformKeyboardLayout, PlatformKeyboardMapper,
54 PlatformViewportCapabilities, PlatformViewportFlagCapabilities, Point, Priority, PromptBuilder,
55 PromptButton, PromptHandle, PromptLevel, Render, RenderImage, RenderablePromptHandle,
56 Reservation, ScreenCaptureSource, SharedString, SubscriberSet, Subscription, SvgRenderer, Task,
57 TextRenderingMode, TextSystem, ThermalState, Window, WindowAppearance, WindowButtonLayout,
58 WindowHandle, WindowId, WindowInvalidator,
59 colors::{Colors, GlobalColors},
60 hash, init_app_menus,
61};
62
63mod async_context;
64#[cfg(any(test, feature = "test-support"))]
65mod bench_context;
66mod context;
67mod entity_map;
68#[cfg(any(test, feature = "test-support"))]
69mod headless_app_context;
70#[cfg(any(test, feature = "test-support"))]
71mod test_app;
72#[cfg(any(test, feature = "test-support"))]
73mod test_context;
74#[cfg(all(target_os = "macos", any(test, feature = "test-support")))]
75mod visual_test_context;
76
77pub const SHUTDOWN_TIMEOUT: Duration = Duration::from_millis(200);
79
80#[doc(hidden)]
83pub struct AppCell {
84 app: RefCell<App>,
85}
86
87impl AppCell {
88 #[doc(hidden)]
89 #[track_caller]
90 pub fn borrow(&self) -> AppRef<'_> {
91 if option_env!("TRACK_THREAD_BORROWS").is_some() {
92 let thread_id = std::thread::current().id();
93 eprintln!("borrowed {thread_id:?}");
94 }
95 AppRef(self.app.borrow())
96 }
97
98 #[doc(hidden)]
99 #[track_caller]
100 pub fn borrow_mut(&self) -> AppRefMut<'_> {
101 if option_env!("TRACK_THREAD_BORROWS").is_some() {
102 let thread_id = std::thread::current().id();
103 eprintln!("borrowed {thread_id:?}");
104 }
105 AppRefMut(self.app.borrow_mut())
106 }
107
108 #[doc(hidden)]
109 #[track_caller]
110 pub fn try_borrow_mut(&self) -> Result<AppRefMut<'_>, BorrowMutError> {
111 if option_env!("TRACK_THREAD_BORROWS").is_some() {
112 let thread_id = std::thread::current().id();
113 eprintln!("borrowed {thread_id:?}");
114 }
115 Ok(AppRefMut(self.app.try_borrow_mut()?))
116 }
117}
118
119#[doc(hidden)]
120#[derive(Deref, DerefMut)]
121pub struct AppRef<'a>(Ref<'a, App>);
122
123impl Drop for AppRef<'_> {
124 fn drop(&mut self) {
125 if option_env!("TRACK_THREAD_BORROWS").is_some() {
126 let thread_id = std::thread::current().id();
127 eprintln!("dropped borrow from {thread_id:?}");
128 }
129 }
130}
131
132#[doc(hidden)]
133#[derive(Deref, DerefMut)]
134pub struct AppRefMut<'a>(RefMut<'a, App>);
135
136impl Drop for AppRefMut<'_> {
137 fn drop(&mut self) {
138 if option_env!("TRACK_THREAD_BORROWS").is_some() {
139 let thread_id = std::thread::current().id();
140 eprintln!("dropped {thread_id:?}");
141 }
142 }
143}
144
145#[cfg(target_family = "wasm")]
146thread_local! {
147 static RUNNING_WEB_APPLICATIONS: RefCell<Vec<Rc<AppCell>>> = RefCell::new(Vec::new());
148}
149
150pub struct Application(Rc<AppCell>);
153
154impl Application {
157 pub fn with_platform(platform: Rc<dyn Platform>) -> Self {
159 Self(App::new_app(
160 platform,
161 Arc::new(()),
162 Arc::new(NullHttpClient),
163 ))
164 }
165
166 pub fn new_inaccessible(platform: Rc<dyn Platform>) -> Self {
176 let this = Self::with_platform(platform);
177 this.0.borrow_mut().accessibility_force_disabled = true;
178 this
179 }
180
181 pub fn with_assets(self, asset_source: impl AssetSource) -> Self {
183 let mut context_lock = self.0.borrow_mut();
184 let asset_source = Arc::new(asset_source);
185 context_lock.asset_source = asset_source.clone();
186 context_lock.svg_renderer = SvgRenderer::new(asset_source);
187 drop(context_lock);
188 self
189 }
190
191 pub fn with_http_client(self, http_client: Arc<dyn HttpClient>) -> Self {
193 let mut context_lock = self.0.borrow_mut();
194 context_lock.http_client = http_client;
195 drop(context_lock);
196 self
197 }
198
199 pub fn with_quit_mode(self, mode: QuitMode) -> Self {
202 self.0.borrow_mut().quit_mode = mode;
203 self
204 }
205
206 pub fn run<F>(self, on_finish_launching: F)
209 where
210 F: 'static + FnOnce(&mut App),
211 {
212 let this = self.0.clone();
213 let platform = self.0.borrow().platform.clone();
214 #[cfg(target_family = "wasm")]
215 let keep_alive = this.clone();
216 platform.run(Box::new(move || {
217 let cx = &mut *this.borrow_mut();
218 on_finish_launching(cx);
219 }));
220 #[cfg(target_family = "wasm")]
221 RUNNING_WEB_APPLICATIONS.with(|applications| {
222 applications.borrow_mut().push(keep_alive);
223 });
224 }
225
226 pub fn on_open_urls<F>(&self, mut callback: F) -> &Self
229 where
230 F: 'static + FnMut(Vec<String>),
231 {
232 self.0.borrow().platform.on_open_urls(Box::new(callback));
233 self
234 }
235
236 pub fn on_reopen<F>(&self, mut callback: F) -> &Self
239 where
240 F: 'static + FnMut(&mut App),
241 {
242 let this = Rc::downgrade(&self.0);
243 self.0.borrow_mut().platform.on_reopen(Box::new(move || {
244 if let Some(app) = this.upgrade() {
245 callback(&mut app.borrow_mut());
246 }
247 }));
248 self
249 }
250
251 pub fn on_system_wake<F>(&self, mut callback: F) -> &Self
253 where
254 F: 'static + FnMut(&mut App),
255 {
256 let this = Rc::downgrade(&self.0);
257 self.0
258 .borrow_mut()
259 .platform
260 .on_system_wake(Box::new(move || {
261 if let Some(app) = this.upgrade() {
262 callback(&mut app.borrow_mut());
263 }
264 }));
265 self
266 }
267
268 pub fn background_executor(&self) -> BackgroundExecutor {
270 self.0.borrow().background_executor.clone()
271 }
272
273 pub fn foreground_executor(&self) -> ForegroundExecutor {
275 self.0.borrow().foreground_executor.clone()
276 }
277
278 pub fn text_system(&self) -> Arc<TextSystem> {
280 self.0.borrow().text_system.clone()
281 }
282
283 pub fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf> {
285 self.0.borrow().path_for_auxiliary_executable(name)
286 }
287}
288
289type Handler = Box<dyn FnMut(&mut App) -> bool + 'static>;
290type Listener = Box<dyn FnMut(&dyn Any, &mut App) -> bool + 'static>;
291pub(crate) type KeystrokeObserver =
292 Box<dyn FnMut(&KeystrokeEvent, &mut Window, &mut App) -> bool + 'static>;
293type QuitHandler = Box<dyn FnOnce(&mut App) -> LocalBoxFuture<'static, ()> + 'static>;
294type WindowClosedHandler = Box<dyn FnMut(&mut App, WindowId)>;
295type ReleaseListener = Box<dyn FnOnce(&mut dyn Any, &mut App) + 'static>;
296type NewEntityListener = Box<dyn FnMut(AnyEntity, &mut Option<&mut Window>, &mut App) + 'static>;
297
298#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
300pub enum QuitMode {
301 #[default]
303 Default,
304 LastWindowClosed,
306 Explicit,
308}
309
310#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
315pub enum CursorHideMode {
316 Never,
318 OnTyping,
320 #[default]
323 OnTypingAndAction,
324}
325
326#[doc(hidden)]
327#[derive(Clone, PartialEq, Eq)]
328pub struct SystemWindowTab {
329 pub id: WindowId,
330 pub title: SharedString,
331 pub handle: AnyWindowHandle,
332 pub last_active_at: Instant,
333}
334
335impl SystemWindowTab {
336 pub fn new(title: SharedString, handle: AnyWindowHandle) -> Self {
338 Self {
339 id: handle.id,
340 title,
341 handle,
342 last_active_at: Instant::now(),
343 }
344 }
345}
346
347#[derive(Default)]
349pub struct SystemWindowTabController {
350 visible: Option<bool>,
351 tab_groups: FxHashMap<usize, Vec<SystemWindowTab>>,
352}
353
354impl Global for SystemWindowTabController {}
355
356impl SystemWindowTabController {
357 pub fn new() -> Self {
359 Self {
360 visible: None,
361 tab_groups: FxHashMap::default(),
362 }
363 }
364
365 pub fn init(cx: &mut App) {
367 cx.set_global(SystemWindowTabController::new());
368 }
369
370 pub fn tab_groups(&self) -> &FxHashMap<usize, Vec<SystemWindowTab>> {
372 &self.tab_groups
373 }
374
375 pub fn get_next_tab_group_window(cx: &mut App, id: WindowId) -> Option<&AnyWindowHandle> {
377 let controller = cx.global::<SystemWindowTabController>();
378 let current_group = controller
379 .tab_groups
380 .iter()
381 .find_map(|(group, tabs)| tabs.iter().find(|tab| tab.id == id).map(|_| group));
382
383 let current_group = current_group?;
384 let mut group_ids: Vec<_> = controller.tab_groups.keys().collect();
386 let idx = group_ids.iter().position(|g| *g == current_group)?;
387 let next_idx = (idx + 1) % group_ids.len();
388
389 controller
390 .tab_groups
391 .get(group_ids[next_idx])
392 .and_then(|tabs| {
393 tabs.iter()
394 .max_by_key(|tab| tab.last_active_at)
395 .or_else(|| tabs.first())
396 .map(|tab| &tab.handle)
397 })
398 }
399
400 pub fn get_prev_tab_group_window(cx: &mut App, id: WindowId) -> Option<&AnyWindowHandle> {
402 let controller = cx.global::<SystemWindowTabController>();
403 let current_group = controller
404 .tab_groups
405 .iter()
406 .find_map(|(group, tabs)| tabs.iter().find(|tab| tab.id == id).map(|_| group));
407
408 let current_group = current_group?;
409 let mut group_ids: Vec<_> = controller.tab_groups.keys().collect();
411 let idx = group_ids.iter().position(|g| *g == current_group)?;
412 let prev_idx = if idx == 0 {
413 group_ids.len() - 1
414 } else {
415 idx - 1
416 };
417
418 controller
419 .tab_groups
420 .get(group_ids[prev_idx])
421 .and_then(|tabs| {
422 tabs.iter()
423 .max_by_key(|tab| tab.last_active_at)
424 .or_else(|| tabs.first())
425 .map(|tab| &tab.handle)
426 })
427 }
428
429 pub fn tabs(&self, id: WindowId) -> Option<&Vec<SystemWindowTab>> {
431 self.tab_groups
432 .values()
433 .find(|tabs| tabs.iter().any(|tab| tab.id == id))
434 }
435
436 pub fn init_visible(cx: &mut App, visible: bool) {
438 let mut controller = cx.global_mut::<SystemWindowTabController>();
439 if controller.visible.is_none() {
440 controller.visible = Some(visible);
441 }
442 }
443
444 pub fn is_visible(&self) -> bool {
446 self.visible.unwrap_or(false)
447 }
448
449 pub fn set_visible(cx: &mut App, visible: bool) {
451 let mut controller = cx.global_mut::<SystemWindowTabController>();
452 controller.visible = Some(visible);
453 }
454
455 pub fn update_last_active(cx: &mut App, id: WindowId) {
457 let mut controller = cx.global_mut::<SystemWindowTabController>();
458 for windows in controller.tab_groups.values_mut() {
459 for tab in windows.iter_mut() {
460 if tab.id == id {
461 tab.last_active_at = Instant::now();
462 }
463 }
464 }
465 }
466
467 pub fn update_tab_position(cx: &mut App, id: WindowId, ix: usize) {
469 let mut controller = cx.global_mut::<SystemWindowTabController>();
470 for (_, windows) in controller.tab_groups.iter_mut() {
471 if let Some(current_pos) = windows.iter().position(|tab| tab.id == id) {
472 if ix < windows.len() && current_pos != ix {
473 let window_tab = windows.remove(current_pos);
474 windows.insert(ix, window_tab);
475 }
476 break;
477 }
478 }
479 }
480
481 pub fn update_tab_title(cx: &mut App, id: WindowId, title: SharedString) {
483 let controller = cx.global::<SystemWindowTabController>();
484 let tab = controller
485 .tab_groups
486 .values()
487 .flat_map(|windows| windows.iter())
488 .find(|tab| tab.id == id);
489
490 if tab.map_or(true, |t| t.title == title) {
491 return;
492 }
493
494 let mut controller = cx.global_mut::<SystemWindowTabController>();
495 for windows in controller.tab_groups.values_mut() {
496 for tab in windows.iter_mut() {
497 if tab.id == id {
498 tab.title = title;
499 return;
500 }
501 }
502 }
503 }
504
505 pub fn add_tab(cx: &mut App, id: WindowId, tabs: Vec<SystemWindowTab>) {
507 let mut controller = cx.global_mut::<SystemWindowTabController>();
508 let Some(tab) = tabs.iter().find(|tab| tab.id == id).cloned() else {
509 return;
510 };
511
512 let mut expected_tab_ids: Vec<_> = tabs
513 .iter()
514 .filter(|tab| tab.id != id)
515 .map(|tab| tab.id)
516 .sorted()
517 .collect();
518
519 let mut tab_group_id = None;
520 for (group_id, group_tabs) in &controller.tab_groups {
521 let tab_ids: Vec<_> = group_tabs.iter().map(|tab| tab.id).sorted().collect();
522 if tab_ids == expected_tab_ids {
523 tab_group_id = Some(*group_id);
524 break;
525 }
526 }
527
528 if let Some(tab_group_id) = tab_group_id {
529 if let Some(tabs) = controller.tab_groups.get_mut(&tab_group_id) {
530 tabs.push(tab);
531 }
532 } else {
533 let new_group_id = controller.tab_groups.len();
534 controller.tab_groups.insert(new_group_id, tabs);
535 }
536 }
537
538 pub fn remove_tab(cx: &mut App, id: WindowId) -> Option<SystemWindowTab> {
540 let mut controller = cx.global_mut::<SystemWindowTabController>();
541 let mut removed_tab = None;
542
543 controller.tab_groups.retain(|_, tabs| {
544 if let Some(pos) = tabs.iter().position(|tab| tab.id == id) {
545 removed_tab = Some(tabs.remove(pos));
546 }
547 !tabs.is_empty()
548 });
549
550 removed_tab
551 }
552
553 pub fn move_tab_to_new_window(cx: &mut App, id: WindowId) {
555 let mut removed_tab = Self::remove_tab(cx, id);
556 let mut controller = cx.global_mut::<SystemWindowTabController>();
557
558 if let Some(tab) = removed_tab {
559 let new_group_id = controller.tab_groups.keys().max().map_or(0, |k| k + 1);
560 controller.tab_groups.insert(new_group_id, vec![tab]);
561 }
562 }
563
564 pub fn merge_all_windows(cx: &mut App, id: WindowId) {
566 let mut controller = cx.global_mut::<SystemWindowTabController>();
567 let Some(initial_tabs) = controller.tabs(id) else {
568 return;
569 };
570
571 let initial_tabs_len = initial_tabs.len();
572 let mut all_tabs = initial_tabs.clone();
573
574 for (_, mut tabs) in controller.tab_groups.drain() {
575 tabs.retain(|tab| !all_tabs[..initial_tabs_len].contains(tab));
576 all_tabs.extend(tabs);
577 }
578
579 controller.tab_groups.insert(0, all_tabs);
580 }
581
582 pub fn select_next_tab(cx: &mut App, id: WindowId) {
584 let mut controller = cx.global_mut::<SystemWindowTabController>();
585 let Some(tabs) = controller.tabs(id) else {
586 return;
587 };
588
589 let current_index = tabs.iter().position(|tab| tab.id == id).unwrap();
590 let next_index = (current_index + 1) % tabs.len();
591
592 let _ = &tabs[next_index].handle.update(cx, |_, window, _| {
593 window.activate_window();
594 });
595 }
596
597 pub fn select_previous_tab(cx: &mut App, id: WindowId) {
599 let mut controller = cx.global_mut::<SystemWindowTabController>();
600 let Some(tabs) = controller.tabs(id) else {
601 return;
602 };
603
604 let current_index = tabs.iter().position(|tab| tab.id == id).unwrap();
605 let previous_index = if current_index == 0 {
606 tabs.len() - 1
607 } else {
608 current_index - 1
609 };
610
611 let _ = &tabs[previous_index].handle.update(cx, |_, window, _| {
612 window.activate_window();
613 });
614 }
615}
616
617pub(crate) enum GpuiMode {
618 #[cfg(any(test, feature = "test-support"))]
619 Test {
620 skip_drawing: bool,
621 },
622 Production,
623}
624
625impl GpuiMode {
626 #[cfg(any(test, feature = "test-support"))]
627 pub fn test() -> Self {
628 GpuiMode::Test {
629 skip_drawing: false,
630 }
631 }
632
633 #[inline]
634 pub(crate) fn skip_drawing(&self) -> bool {
635 match self {
636 #[cfg(any(test, feature = "test-support"))]
637 GpuiMode::Test { skip_drawing } => *skip_drawing,
638 GpuiMode::Production => false,
639 }
640 }
641}
642
643pub struct App {
647 pub(crate) this: Weak<AppCell>,
648 pub(crate) platform: Rc<dyn Platform>,
649 text_system: Arc<TextSystem>,
650
651 pub(crate) actions: Rc<ActionRegistry>,
652 pub(crate) active_drag: Option<AnyDrag>,
653 pub(crate) background_executor: BackgroundExecutor,
654 pub(crate) foreground_executor: ForegroundExecutor,
655 pub(crate) entities: EntityMap,
656 pub(crate) new_entity_observers: SubscriberSet<TypeId, NewEntityListener>,
657 pub(crate) windows: SlotMap<WindowId, Option<Box<Window>>>,
658 pub(crate) window_handles: FxHashMap<WindowId, AnyWindowHandle>,
659 pub(crate) focus_handles: Arc<FocusMap>,
660 pub(crate) keymap: Rc<RefCell<Keymap>>,
661 pub(crate) keyboard_layout: Box<dyn PlatformKeyboardLayout>,
662 pub(crate) keyboard_mapper: Rc<dyn PlatformKeyboardMapper>,
663 pub(crate) global_action_listeners:
664 TypeIdHashMap<Vec<Rc<dyn Fn(&dyn Any, DispatchPhase, &mut Self)>>>,
665 pending_effects: VecDeque<Effect>,
666
667 pub(crate) observers: SubscriberSet<EntityId, Handler>,
668 pub(crate) event_listeners: SubscriberSet<EntityId, (TypeId, Listener)>,
669 pub(crate) keystroke_observers: SubscriberSet<(), KeystrokeObserver>,
670 pub(crate) keystroke_interceptors: SubscriberSet<(), KeystrokeObserver>,
671 pub(crate) keyboard_layout_observers: SubscriberSet<(), Handler>,
672 pub(crate) thermal_state_observers: SubscriberSet<(), Handler>,
673 pub(crate) release_listeners: SubscriberSet<EntityId, ReleaseListener>,
674 pub(crate) global_observers: SubscriberSet<TypeId, Handler>,
675 pub(crate) quit_observers: SubscriberSet<(), QuitHandler>,
676 pub(crate) restart_observers: SubscriberSet<(), Handler>,
677 pub(crate) window_closed_observers: SubscriberSet<(), WindowClosedHandler>,
678
679 pub(crate) element_arena: RefCell<Arena>,
682 pub(crate) event_arena: Arena,
684
685 pub(crate) globals_by_type: TypeIdHashMap<Box<dyn Any>>,
690
691 pub(crate) loading_assets: FxHashMap<(TypeId, u64), Box<dyn Any>>,
693 asset_source: Arc<dyn AssetSource>,
694 pub(crate) svg_renderer: SvgRenderer,
695 http_client: Arc<dyn HttpClient>,
696
697 pub(crate) pending_notifications: FxHashSet<EntityId>,
699 pub(crate) pending_global_notifications: TypeIdHashSet,
700 pub(crate) restart_path: Option<PathBuf>,
701 pub(crate) layout_id_buffer: Vec<LayoutId>, pub(crate) propagate_event: bool,
703 pub(crate) prompt_builder: Option<PromptBuilder>,
704 pub(crate) window_invalidators_by_entity:
705 FxHashMap<EntityId, FxHashMap<WindowId, WindowInvalidator>>,
706 pub(crate) tracked_entities: FxHashMap<WindowId, FxHashSet<EntityId>>,
707 pub(crate) current_window_by_entity: FxHashMap<EntityId, WindowId>,
708 #[cfg(any(feature = "inspector", debug_assertions))]
709 pub(crate) inspector_renderer: Option<crate::InspectorRenderer>,
710 #[cfg(any(feature = "inspector", debug_assertions))]
711 pub(crate) inspector_element_registry: InspectorElementRegistry,
712 #[cfg(any(test, feature = "test-support", debug_assertions))]
713 pub(crate) name: Option<&'static str>,
714 pub(crate) text_rendering_mode: Rc<Cell<TextRenderingMode>>,
715
716 pub(crate) window_update_stack: Vec<WindowId>,
717 pub(crate) mode: GpuiMode,
718 pub(crate) cursor_hide_mode: CursorHideMode,
719 pub(crate) accessibility_force_disabled: bool,
722 flushing_effects: bool,
723 pending_updates: usize,
724 quit_mode: QuitMode,
725 quitting: bool,
726
727 #[cfg(any(test, feature = "leak-detection"))]
730 _ref_counts: Arc<RwLock<EntityRefCounts>>,
731}
732
733impl App {
734 #[allow(clippy::new_ret_no_self)]
735 pub(crate) fn new_app(
736 platform: Rc<dyn Platform>,
737 asset_source: Arc<dyn AssetSource>,
738 http_client: Arc<dyn HttpClient>,
739 ) -> Rc<AppCell> {
740 let background_executor = platform.background_executor();
741 let foreground_executor = platform.foreground_executor();
742 assert!(
743 background_executor.is_main_thread(),
744 "must construct App on main thread"
745 );
746
747 let text_system = Arc::new(TextSystem::new(platform.text_system()));
748 let entities = EntityMap::new();
749 let keyboard_layout = platform.keyboard_layout();
750 let keyboard_mapper = platform.keyboard_mapper();
751
752 #[cfg(any(test, feature = "leak-detection"))]
753 let _ref_counts = entities.ref_counts_drop_handle();
754
755 let app = Rc::new_cyclic(|this| AppCell {
756 app: RefCell::new(App {
757 this: this.clone(),
758 platform: platform.clone(),
759 text_system,
760 text_rendering_mode: Rc::new(Cell::new(TextRenderingMode::default())),
761 mode: GpuiMode::Production,
762 actions: Rc::new(ActionRegistry::default()),
763 flushing_effects: false,
764 pending_updates: 0,
765 active_drag: None,
766 background_executor,
767 foreground_executor,
768 svg_renderer: SvgRenderer::new(asset_source.clone()),
769 loading_assets: Default::default(),
770 asset_source,
771 http_client,
772 globals_by_type: Default::default(),
773 entities,
774 new_entity_observers: SubscriberSet::new(),
775 windows: SlotMap::with_key(),
776 window_update_stack: Vec::new(),
777 window_handles: FxHashMap::default(),
778 focus_handles: Arc::new(RwLock::new(SlotMap::with_key())),
779 keymap: Rc::new(RefCell::new(Keymap::default())),
780 keyboard_layout,
781 keyboard_mapper,
782 global_action_listeners: Default::default(),
783 pending_effects: VecDeque::new(),
784 pending_notifications: FxHashSet::default(),
785 pending_global_notifications: Default::default(),
786 observers: SubscriberSet::new(),
787 tracked_entities: FxHashMap::default(),
788 window_invalidators_by_entity: FxHashMap::default(),
789 current_window_by_entity: FxHashMap::default(),
790 event_listeners: SubscriberSet::new(),
791 release_listeners: SubscriberSet::new(),
792 keystroke_observers: SubscriberSet::new(),
793 keystroke_interceptors: SubscriberSet::new(),
794 keyboard_layout_observers: SubscriberSet::new(),
795 thermal_state_observers: SubscriberSet::new(),
796 global_observers: SubscriberSet::new(),
797 quit_observers: SubscriberSet::new(),
798 restart_observers: SubscriberSet::new(),
799 restart_path: None,
800 window_closed_observers: SubscriberSet::new(),
801 layout_id_buffer: Default::default(),
802 propagate_event: true,
803 prompt_builder: Some(PromptBuilder::Default),
804 #[cfg(any(feature = "inspector", debug_assertions))]
805 inspector_renderer: None,
806 #[cfg(any(feature = "inspector", debug_assertions))]
807 inspector_element_registry: InspectorElementRegistry::default(),
808 quit_mode: QuitMode::default(),
809 quitting: false,
810 cursor_hide_mode: CursorHideMode::default(),
811 accessibility_force_disabled: false,
812
813 #[cfg(any(test, feature = "test-support", debug_assertions))]
814 name: None,
815 element_arena: RefCell::new(Arena::new(1024 * 1024)),
816 event_arena: Arena::new(1024 * 1024),
817
818 #[cfg(any(test, feature = "leak-detection"))]
819 _ref_counts,
820 }),
821 });
822
823 init_app_menus(platform.as_ref(), &app.borrow());
824 SystemWindowTabController::init(&mut app.borrow_mut());
825
826 platform.on_keyboard_layout_change(Box::new({
827 let app = Rc::downgrade(&app);
828 move || {
829 if let Some(app) = app.upgrade() {
830 let cx = &mut app.borrow_mut();
831 cx.keyboard_layout = cx.platform.keyboard_layout();
832 cx.keyboard_mapper = cx.platform.keyboard_mapper();
833 cx.keyboard_layout_observers
834 .clone()
835 .retain(&(), move |callback| (callback)(cx));
836 }
837 }
838 }));
839
840 platform.on_thermal_state_change(Box::new({
841 let app = Rc::downgrade(&app);
842 move || {
843 if let Some(app) = app.upgrade() {
844 let cx = &mut app.borrow_mut();
845 cx.thermal_state_observers
846 .clone()
847 .retain(&(), move |callback| (callback)(cx));
848 }
849 }
850 }));
851
852 platform.on_quit(Box::new({
853 let cx = Rc::downgrade(&app);
854 move || {
855 if let Some(cx) = cx.upgrade() {
856 cx.borrow_mut().shutdown();
857 }
858 }
859 }));
860
861 app
862 }
863
864 #[doc(hidden)]
865 pub fn ref_counts_drop_handle(&self) -> impl Sized + use<> {
866 self.entities.ref_counts_drop_handle()
867 }
868
869 #[cfg(any(test, feature = "leak-detection"))]
875 pub fn leak_detector_snapshot(&self) -> LeakDetectorSnapshot {
876 self.entities.leak_detector_snapshot()
877 }
878
879 #[cfg(any(test, feature = "leak-detection"))]
891 pub fn assert_no_new_leaks(&self, snapshot: &LeakDetectorSnapshot) {
892 self.entities.assert_no_new_leaks(snapshot)
893 }
894
895 pub fn shutdown(&mut self) {
898 let mut futures = Vec::new();
899
900 for observer in self.quit_observers.remove(&()) {
901 futures.push(observer(self));
902 }
903
904 self.windows.clear();
905 self.window_handles.clear();
906 self.flush_effects();
907 self.quitting = true;
908
909 let futures = futures::future::join_all(futures);
910 if self
911 .foreground_executor
912 .block_with_timeout(SHUTDOWN_TIMEOUT, futures)
913 .is_err()
914 {
915 log::error!("timed out waiting on app_will_quit");
916 }
917
918 self.quitting = false;
919 }
920
921 pub fn keyboard_layout(&self) -> &dyn PlatformKeyboardLayout {
923 self.keyboard_layout.as_ref()
924 }
925
926 pub fn keyboard_mapper(&self) -> &Rc<dyn PlatformKeyboardMapper> {
928 &self.keyboard_mapper
929 }
930
931 pub fn on_keyboard_layout_change<F>(&self, mut callback: F) -> Subscription
933 where
934 F: 'static + FnMut(&mut App),
935 {
936 let (subscription, activate) = self.keyboard_layout_observers.insert(
937 (),
938 Box::new(move |cx| {
939 callback(cx);
940 true
941 }),
942 );
943 activate();
944 subscription
945 }
946
947 pub fn quit(&self) {
949 self.platform.quit();
950 }
951
952 pub fn cursor_hide_mode(&self) -> CursorHideMode {
955 self.cursor_hide_mode
956 }
957
958 pub fn set_cursor_hide_mode(&mut self, mode: CursorHideMode) {
961 self.cursor_hide_mode = mode;
962 }
963
964 pub fn is_cursor_visible(&self) -> bool {
970 self.platform.is_cursor_visible()
971 }
972
973 pub fn refresh_windows(&mut self) {
976 self.pending_effects.push_back(Effect::RefreshWindows);
977 }
978
979 pub(crate) fn update<R>(&mut self, update: impl FnOnce(&mut Self) -> R) -> R {
980 self.start_update();
981 let result = update(self);
982 self.finish_update();
983 result
984 }
985
986 pub(crate) fn start_update(&mut self) {
987 self.pending_updates += 1;
988 }
989
990 pub(crate) fn finish_update(&mut self) {
991 if !self.flushing_effects && self.pending_updates == 1 {
992 self.flushing_effects = true;
993 self.flush_effects();
994 self.flushing_effects = false;
995 }
996 self.pending_updates -= 1;
997 }
998
999 pub fn observe<W>(
1001 &mut self,
1002 entity: &Entity<W>,
1003 mut on_notify: impl FnMut(Entity<W>, &mut App) + 'static,
1004 ) -> Subscription
1005 where
1006 W: 'static,
1007 {
1008 self.observe_internal(entity, move |e, cx| {
1009 on_notify(e, cx);
1010 true
1011 })
1012 }
1013
1014 pub(crate) fn detect_accessed_entities<R>(
1015 &mut self,
1016 callback: impl FnOnce(&mut App) -> R,
1017 ) -> (R, FxHashSet<EntityId>) {
1018 let accessed_entities_start = self.entities.accessed_entities.get_mut().clone();
1019 let result = callback(self);
1020 let entities_accessed_in_callback = self
1021 .entities
1022 .accessed_entities
1023 .get_mut()
1024 .difference(&accessed_entities_start)
1025 .copied()
1026 .collect::<FxHashSet<EntityId>>();
1027 (result, entities_accessed_in_callback)
1028 }
1029
1030 pub(crate) fn record_entities_accessed(
1031 &mut self,
1032 window_handle: AnyWindowHandle,
1033 invalidator: WindowInvalidator,
1034 entities: &FxHashSet<EntityId>,
1035 ) {
1036 let mut tracked_entities =
1037 std::mem::take(self.tracked_entities.entry(window_handle.id).or_default());
1038 for entity in tracked_entities.iter() {
1039 self.window_invalidators_by_entity
1040 .entry(*entity)
1041 .and_modify(|windows| {
1042 windows.remove(&window_handle.id);
1043 });
1044 }
1045 for entity in entities.iter() {
1046 self.window_invalidators_by_entity
1047 .entry(*entity)
1048 .or_default()
1049 .insert(window_handle.id, invalidator.clone());
1050 self.current_window_by_entity
1051 .insert(*entity, window_handle.id);
1052 }
1053 tracked_entities.clear();
1054 tracked_entities.extend(entities.iter().copied());
1055 self.tracked_entities
1056 .insert(window_handle.id, tracked_entities);
1057 }
1058
1059 pub(crate) fn new_observer(&mut self, key: EntityId, value: Handler) -> Subscription {
1060 let (subscription, activate) = self.observers.insert(key, value);
1061 self.defer(move |_| activate());
1062 subscription
1063 }
1064
1065 pub(crate) fn observe_internal<W>(
1066 &mut self,
1067 entity: &Entity<W>,
1068 mut on_notify: impl FnMut(Entity<W>, &mut App) -> bool + 'static,
1069 ) -> Subscription
1070 where
1071 W: 'static,
1072 {
1073 let entity_id = entity.entity_id();
1074 let handle = entity.downgrade();
1075 self.new_observer(
1076 entity_id,
1077 Box::new(move |cx| {
1078 if let Some(entity) = handle.upgrade() {
1079 on_notify(entity, cx)
1080 } else {
1081 false
1082 }
1083 }),
1084 )
1085 }
1086
1087 pub fn subscribe<T, Event>(
1090 &mut self,
1091 entity: &Entity<T>,
1092 mut on_event: impl FnMut(Entity<T>, &Event, &mut App) + 'static,
1093 ) -> Subscription
1094 where
1095 T: 'static + EventEmitter<Event>,
1096 Event: 'static,
1097 {
1098 self.subscribe_internal(entity, move |entity, event, cx| {
1099 on_event(entity, event, cx);
1100 true
1101 })
1102 }
1103
1104 pub(crate) fn new_subscription(
1105 &mut self,
1106 key: EntityId,
1107 value: (TypeId, Listener),
1108 ) -> Subscription {
1109 let (subscription, activate) = self.event_listeners.insert(key, value);
1110 self.defer(move |_| activate());
1111 subscription
1112 }
1113 pub(crate) fn subscribe_internal<T, Evt>(
1114 &mut self,
1115 entity: &Entity<T>,
1116 mut on_event: impl FnMut(Entity<T>, &Evt, &mut App) -> bool + 'static,
1117 ) -> Subscription
1118 where
1119 T: 'static + EventEmitter<Evt>,
1120 Evt: 'static,
1121 {
1122 let entity_id = entity.entity_id();
1123 let handle = entity.downgrade();
1124 self.new_subscription(
1125 entity_id,
1126 (
1127 TypeId::of::<Evt>(),
1128 Box::new(move |event, cx| {
1129 let event: &Evt = event.downcast_ref().expect("invalid event type");
1130 if let Some(entity) = handle.upgrade() {
1131 on_event(entity, event, cx)
1132 } else {
1133 false
1134 }
1135 }),
1136 ),
1137 )
1138 }
1139
1140 pub fn windows(&self) -> Vec<AnyWindowHandle> {
1144 self.windows
1145 .keys()
1146 .flat_map(|window_id| self.window_handles.get(&window_id).copied())
1147 .collect()
1148 }
1149
1150 pub fn window_stack(&self) -> Option<Vec<AnyWindowHandle>> {
1156 self.platform.window_stack()
1157 }
1158
1159 pub fn viewport_capabilities(&self) -> PlatformViewportCapabilities {
1161 self.platform.viewport_capabilities()
1162 }
1163
1164 pub fn viewport_flag_capabilities(&self) -> PlatformViewportFlagCapabilities {
1166 self.platform.viewport_flag_capabilities()
1167 }
1168
1169 pub fn hovered_window(&self) -> PlatformHoveredWindow {
1171 self.platform.hovered_window()
1172 }
1173
1174 pub fn focused_window(&self) -> PlatformFocusedWindow {
1176 self.platform.focused_window()
1177 }
1178
1179 pub fn active_window(&self) -> Option<AnyWindowHandle> {
1181 self.platform.active_window()
1182 }
1183
1184 pub fn mouse_button_is_pressed(&self, button: MouseButton) -> Option<bool> {
1186 self.platform.mouse_button_is_pressed(button)
1187 }
1188
1189 pub fn open_window<V: 'static + Render>(
1193 &mut self,
1194 options: crate::WindowOptions,
1195 build_root_view: impl FnOnce(&mut Window, &mut App) -> Entity<V>,
1196 ) -> anyhow::Result<WindowHandle<V>> {
1197 self.update(|cx| {
1198 let id = cx.windows.insert(None);
1199 let handle = WindowHandle::new(id);
1200 match Window::new(handle.into(), options, cx) {
1201 Ok(mut window) => {
1202 cx.window_update_stack.push(id);
1203 let root_view = build_root_view(&mut window, cx);
1204 cx.window_update_stack.pop();
1205 window.root.replace(root_view.into());
1206 window.defer(cx, |window: &mut Window, cx| window.appearance_changed(cx));
1207
1208 let clear = window.draw(cx);
1213 clear.clear();
1214
1215 cx.window_handles.insert(id, window.handle);
1216 cx.windows.get_mut(id).unwrap().replace(Box::new(window));
1217 Ok(handle)
1218 }
1219 Err(e) => {
1220 cx.windows.remove(id);
1221 Err(e)
1222 }
1223 }
1224 })
1225 }
1226
1227 pub fn activate(&self, ignoring_other_apps: bool) {
1229 self.platform.activate(ignoring_other_apps);
1230 }
1231
1232 pub fn hide(&self) {
1234 self.platform.hide();
1235 }
1236
1237 pub fn hide_other_apps(&self) {
1239 self.platform.hide_other_apps();
1240 }
1241
1242 pub fn unhide_other_apps(&self) {
1244 self.platform.unhide_other_apps();
1245 }
1246
1247 pub fn displays(&self) -> Vec<Rc<dyn PlatformDisplay>> {
1249 self.platform.displays()
1250 }
1251
1252 pub fn primary_display(&self) -> Option<Rc<dyn PlatformDisplay>> {
1254 self.platform.primary_display()
1255 }
1256
1257 pub fn is_screen_capture_supported(&self) -> bool {
1259 self.platform.is_screen_capture_supported()
1260 }
1261
1262 pub fn screen_capture_sources(
1264 &self,
1265 ) -> oneshot::Receiver<Result<Vec<Rc<dyn ScreenCaptureSource>>>> {
1266 self.platform.screen_capture_sources()
1267 }
1268
1269 pub fn find_display(&self, id: DisplayId) -> Option<Rc<dyn PlatformDisplay>> {
1271 self.displays()
1272 .iter()
1273 .find(|display| display.id() == id)
1274 .cloned()
1275 }
1276
1277 pub fn thermal_state(&self) -> ThermalState {
1279 self.platform.thermal_state()
1280 }
1281
1282 pub fn on_thermal_state_change<F>(&self, mut callback: F) -> Subscription
1284 where
1285 F: 'static + FnMut(&mut App),
1286 {
1287 let (subscription, activate) = self.thermal_state_observers.insert(
1288 (),
1289 Box::new(move |cx| {
1290 callback(cx);
1291 true
1292 }),
1293 );
1294 activate();
1295 subscription
1296 }
1297
1298 pub fn window_appearance(&self) -> WindowAppearance {
1300 self.platform.window_appearance()
1301 }
1302
1303 pub fn button_layout(&self) -> Option<WindowButtonLayout> {
1305 self.platform.button_layout()
1306 }
1307
1308 pub fn read_from_clipboard(&self) -> Option<ClipboardItem> {
1310 self.platform.read_from_clipboard()
1311 }
1312
1313 pub fn set_text_rendering_mode(&mut self, mode: TextRenderingMode) {
1315 self.text_rendering_mode.set(mode);
1316 }
1317
1318 pub fn text_rendering_mode(&self) -> TextRenderingMode {
1320 self.text_rendering_mode.get()
1321 }
1322
1323 pub fn write_to_clipboard(&self, item: ClipboardItem) {
1325 self.platform.write_to_clipboard(item)
1326 }
1327
1328 #[cfg(any(target_os = "linux", target_os = "freebsd"))]
1331 pub fn read_from_primary(&self) -> Option<ClipboardItem> {
1332 self.platform.read_from_primary()
1333 }
1334
1335 #[cfg(any(target_os = "linux", target_os = "freebsd"))]
1338 pub fn write_to_primary(&self, item: ClipboardItem) {
1339 self.platform.write_to_primary(item)
1340 }
1341
1342 #[cfg(target_os = "macos")]
1348 pub fn read_from_find_pasteboard(&self) -> Option<ClipboardItem> {
1349 self.platform.read_from_find_pasteboard()
1350 }
1351
1352 #[cfg(target_os = "macos")]
1358 pub fn write_to_find_pasteboard(&self, item: ClipboardItem) {
1359 self.platform.write_to_find_pasteboard(item)
1360 }
1361
1362 pub fn write_credentials(
1364 &self,
1365 url: &str,
1366 username: &str,
1367 password: &[u8],
1368 ) -> Task<Result<()>> {
1369 self.platform.write_credentials(url, username, password)
1370 }
1371
1372 pub fn read_credentials(&self, url: &str) -> Task<Result<Option<(String, Vec<u8>)>>> {
1374 self.platform.read_credentials(url)
1375 }
1376
1377 pub fn delete_credentials(&self, url: &str) -> Task<Result<()>> {
1379 self.platform.delete_credentials(url)
1380 }
1381
1382 pub fn open_url(&self, url: &str) {
1384 self.platform.open_url(url);
1385 }
1386
1387 pub fn register_url_scheme(&self, scheme: &str) -> Task<Result<()>> {
1394 self.platform.register_url_scheme(scheme)
1395 }
1396
1397 pub fn app_path(&self) -> Result<PathBuf> {
1401 self.platform.app_path()
1402 }
1403
1404 pub fn compositor_name(&self) -> &'static str {
1408 self.platform.compositor_name()
1409 }
1410
1411 pub fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf> {
1413 self.platform.path_for_auxiliary_executable(name)
1414 }
1415
1416 pub fn prompt_for_paths(
1422 &self,
1423 options: PathPromptOptions,
1424 ) -> oneshot::Receiver<Result<Option<Vec<PathBuf>>>> {
1425 self.platform.prompt_for_paths(options)
1426 }
1427
1428 pub fn prompt_for_new_path(
1435 &self,
1436 directory: &Path,
1437 suggested_name: Option<&str>,
1438 ) -> oneshot::Receiver<Result<Option<PathBuf>>> {
1439 self.platform.prompt_for_new_path(directory, suggested_name)
1440 }
1441
1442 pub fn reveal_path(&self, path: &Path) {
1444 self.platform.reveal_path(path)
1445 }
1446
1447 pub fn open_with_system(&self, path: &Path) {
1449 self.platform.open_with_system(path)
1450 }
1451
1452 pub fn should_auto_hide_scrollbars(&self) -> bool {
1454 self.platform.should_auto_hide_scrollbars()
1455 }
1456
1457 pub fn restart(&mut self) {
1459 self.restart_observers
1460 .clone()
1461 .retain(&(), |observer| observer(self));
1462 self.platform.restart(self.restart_path.take())
1463 }
1464
1465 pub fn set_restart_path(&mut self, path: PathBuf) {
1467 self.restart_path = Some(path);
1468 }
1469
1470 pub fn http_client(&self) -> Arc<dyn HttpClient> {
1472 self.http_client.clone()
1473 }
1474
1475 pub fn set_http_client(&mut self, new_client: Arc<dyn HttpClient>) {
1477 self.http_client = new_client;
1478 }
1479
1480 pub fn set_quit_mode(&mut self, mode: QuitMode) {
1483 self.quit_mode = mode;
1484 }
1485
1486 pub fn svg_renderer(&self) -> SvgRenderer {
1488 self.svg_renderer.clone()
1489 }
1490
1491 pub(crate) fn push_effect(&mut self, effect: Effect) {
1492 match &effect {
1493 Effect::Notify { emitter } => {
1494 if !self.pending_notifications.insert(*emitter) {
1495 return;
1496 }
1497 }
1498 Effect::NotifyGlobalObservers { global_type } => {
1499 if !self.pending_global_notifications.insert(*global_type) {
1500 return;
1501 }
1502 }
1503 _ => {}
1504 };
1505
1506 self.pending_effects.push_back(effect);
1507 }
1508
1509 fn flush_effects(&mut self) {
1513 loop {
1514 self.release_dropped_entities();
1515 self.release_dropped_focus_handles();
1516 if let Some(effect) = self.pending_effects.pop_front() {
1517 match effect {
1518 Effect::Notify { emitter } => {
1519 self.apply_notify_effect(emitter);
1520 }
1521
1522 Effect::Emit {
1523 emitter,
1524 event_type,
1525 event,
1526 } => self.apply_emit_effect(emitter, event_type, &*event),
1527
1528 Effect::RefreshWindows => {
1529 self.apply_refresh_effect();
1530 }
1531
1532 Effect::NotifyGlobalObservers { global_type } => {
1533 self.apply_notify_global_observers_effect(global_type);
1534 }
1535
1536 Effect::Defer { callback } => {
1537 self.apply_defer_effect(callback);
1538 }
1539 Effect::EntityCreated {
1540 entity,
1541 tid,
1542 window,
1543 } => {
1544 self.apply_entity_created_effect(entity, tid, window);
1545 }
1546 }
1547 } else {
1548 #[cfg(any(test, feature = "test-support"))]
1549 for window in self
1550 .windows
1551 .values()
1552 .filter_map(|window| {
1553 let window = window.as_deref()?;
1554 window.invalidator.is_dirty().then_some(window.handle)
1555 })
1556 .collect::<Vec<_>>()
1557 {
1558 self.update_window(window, |_, window, cx| window.draw(cx).clear())
1559 .unwrap();
1560 }
1561
1562 if self.pending_effects.is_empty() {
1563 self.event_arena.clear();
1564 break;
1565 }
1566 }
1567 }
1568 }
1569
1570 fn release_dropped_entities(&mut self) {
1574 loop {
1575 let dropped = self.entities.take_dropped();
1576 if dropped.is_empty() {
1577 break;
1578 }
1579
1580 for (entity_id, mut entity) in dropped {
1581 self.observers.remove(&entity_id);
1582 self.event_listeners.remove(&entity_id);
1583 self.window_invalidators_by_entity.remove(&entity_id);
1584 self.current_window_by_entity.remove(&entity_id);
1585 for release_callback in self.release_listeners.remove(&entity_id) {
1586 release_callback(entity.as_mut(), self);
1587 }
1588 }
1589 }
1590 }
1591
1592 fn release_dropped_focus_handles(&mut self) {
1594 self.focus_handles
1595 .clone()
1596 .write()
1597 .retain(|handle_id, focus| {
1598 if focus.ref_count.load(SeqCst) == 0 {
1599 for window_handle in self.windows() {
1600 window_handle
1601 .update(self, |_, window, _| {
1602 if window.focus == Some(handle_id) {
1603 window.blur();
1604 }
1605 })
1606 .unwrap();
1607 }
1608 false
1609 } else {
1610 true
1611 }
1612 });
1613 }
1614
1615 fn apply_notify_effect(&mut self, emitter: EntityId) {
1616 self.pending_notifications.remove(&emitter);
1617
1618 self.observers
1619 .clone()
1620 .retain(&emitter, |handler| handler(self));
1621 }
1622
1623 fn apply_emit_effect(&mut self, emitter: EntityId, event_type: TypeId, event: &dyn Any) {
1624 self.event_listeners
1625 .clone()
1626 .retain(&emitter, |(stored_type, handler)| {
1627 if *stored_type == event_type {
1628 handler(event, self)
1629 } else {
1630 true
1631 }
1632 });
1633 }
1634
1635 fn apply_refresh_effect(&mut self) {
1636 for window in self.windows.values_mut() {
1637 if let Some(window) = window.as_deref_mut() {
1638 window.refreshing = true;
1639 window.invalidator.set_dirty(true);
1640 }
1641 }
1642 }
1643
1644 fn apply_notify_global_observers_effect(&mut self, type_id: TypeId) {
1645 self.pending_global_notifications.remove(&type_id);
1646 self.global_observers
1647 .clone()
1648 .retain(&type_id, |observer| observer(self));
1649 }
1650
1651 fn apply_defer_effect(&mut self, callback: Box<dyn FnOnce(&mut Self) + 'static>) {
1652 callback(self);
1653 }
1654
1655 fn apply_entity_created_effect(
1656 &mut self,
1657 entity: AnyEntity,
1658 tid: TypeId,
1659 window: Option<WindowId>,
1660 ) {
1661 if let Some(id) = window {
1665 self.current_window_by_entity.insert(entity.entity_id(), id);
1666 }
1667
1668 self.new_entity_observers.clone().retain(&tid, |observer| {
1669 if let Some(id) = window {
1670 self.update_window_id(id, {
1671 let entity = entity.clone();
1672 |_, window, cx| (observer)(entity, &mut Some(window), cx)
1673 })
1674 .expect("All windows should be off the stack when flushing effects");
1675 } else {
1676 (observer)(entity.clone(), &mut None, self)
1677 }
1678 true
1679 });
1680 }
1681
1682 pub fn with_window<R>(
1688 &mut self,
1689 entity_id: EntityId,
1690 f: impl FnOnce(&mut Window, &mut App) -> R,
1691 ) -> Option<R> {
1692 let window_id = *self.current_window_by_entity.get(&entity_id)?;
1693 self.update_window_id(window_id, |_, window, cx| f(window, cx))
1694 .ok()
1695 }
1696
1697 fn ensure_window(&mut self, entity_id: EntityId, window: WindowId) {
1698 self.current_window_by_entity
1699 .entry(entity_id)
1700 .or_insert(window);
1701 }
1702
1703 pub(crate) fn update_window_id<T, F>(&mut self, id: WindowId, update: F) -> Result<T>
1704 where
1705 F: FnOnce(AnyView, &mut Window, &mut App) -> T,
1706 {
1707 self.update(|cx| {
1708 let mut window = cx.windows.get_mut(id)?.take()?;
1709
1710 let root_view = window.root.clone().unwrap();
1711
1712 cx.window_update_stack.push(window.handle.id);
1713 let result = update(root_view, &mut window, cx);
1714 fn trail(id: WindowId, window: Box<Window>, cx: &mut App) -> Option<()> {
1715 cx.window_update_stack.pop();
1716
1717 if window.removed {
1718 cx.window_handles.remove(&id);
1719 cx.windows.remove(id);
1720 if let Some(tracked) = cx.tracked_entities.remove(&id) {
1721 for entity_id in tracked {
1722 if let Some(windows) =
1723 cx.window_invalidators_by_entity.get_mut(&entity_id)
1724 {
1725 windows.remove(&id);
1726 }
1727 if cx.current_window_by_entity.get(&entity_id) == Some(&id) {
1728 cx.current_window_by_entity.remove(&entity_id);
1729 }
1730 }
1731 }
1732
1733 cx.window_closed_observers.clone().retain(&(), |callback| {
1734 callback(cx, id);
1735 true
1736 });
1737
1738 let quit_on_empty = match cx.quit_mode {
1739 QuitMode::Explicit => false,
1740 QuitMode::LastWindowClosed => true,
1741 QuitMode::Default => cfg!(not(target_os = "macos")),
1742 };
1743
1744 if quit_on_empty && cx.windows.is_empty() {
1745 cx.quit();
1746 }
1747 } else {
1748 cx.windows.get_mut(id)?.replace(window);
1749 }
1750 Some(())
1751 }
1752 trail(id, window, cx)?;
1753
1754 Some(result)
1755 })
1756 .context("window not found")
1757 }
1758
1759 pub fn to_async(&self) -> AsyncApp {
1762 AsyncApp {
1763 app: self.this.clone(),
1764 background_executor: self.background_executor.clone(),
1765 foreground_executor: self.foreground_executor.clone(),
1766 }
1767 }
1768
1769 pub fn background_executor(&self) -> &BackgroundExecutor {
1771 &self.background_executor
1772 }
1773
1774 pub fn foreground_executor(&self) -> &ForegroundExecutor {
1776 if self.quitting {
1777 panic!("Can't spawn on main thread after on_app_quit")
1778 };
1779 &self.foreground_executor
1780 }
1781
1782 #[track_caller]
1785 pub fn spawn<AsyncFn, R>(&self, f: AsyncFn) -> Task<R>
1786 where
1787 AsyncFn: AsyncFnOnce(&mut AsyncApp) -> R + 'static,
1788 R: 'static,
1789 {
1790 if self.quitting {
1791 debug_panic!("Can't spawn on main thread after on_app_quit")
1792 };
1793
1794 let mut cx = self.to_async();
1795
1796 self.foreground_executor
1797 .spawn(async move { f(&mut cx).await }.boxed_local())
1798 }
1799
1800 pub fn spawn_with_priority<AsyncFn, R>(&self, priority: Priority, f: AsyncFn) -> Task<R>
1804 where
1805 AsyncFn: AsyncFnOnce(&mut AsyncApp) -> R + 'static,
1806 R: 'static,
1807 {
1808 if self.quitting {
1809 debug_panic!("Can't spawn on main thread after on_app_quit")
1810 };
1811
1812 let mut cx = self.to_async();
1813
1814 self.foreground_executor
1815 .spawn_with_priority(priority, async move { f(&mut cx).await }.boxed_local())
1816 }
1817
1818 pub fn defer(&mut self, f: impl FnOnce(&mut App) + 'static) {
1821 self.push_effect(Effect::Defer {
1822 callback: Box::new(f),
1823 });
1824 }
1825
1826 pub fn asset_source(&self) -> &Arc<dyn AssetSource> {
1828 &self.asset_source
1829 }
1830
1831 pub fn text_system(&self) -> &Arc<TextSystem> {
1833 &self.text_system
1834 }
1835
1836 pub fn has_global<G: Global>(&self) -> bool {
1838 self.globals_by_type.contains_key(&TypeId::of::<G>())
1839 }
1840
1841 #[track_caller]
1843 pub fn global<G: Global>(&self) -> &G {
1844 self.globals_by_type
1845 .get(&TypeId::of::<G>())
1846 .map(|any_state| any_state.downcast_ref::<G>().unwrap())
1847 .unwrap_or_else(|| panic!("no state of type {} exists", type_name::<G>()))
1848 }
1849
1850 pub fn try_global<G: Global>(&self) -> Option<&G> {
1852 self.globals_by_type
1853 .get(&TypeId::of::<G>())
1854 .map(|any_state| any_state.downcast_ref::<G>().unwrap())
1855 }
1856
1857 #[track_caller]
1859 pub fn global_mut<G: Global>(&mut self) -> &mut G {
1860 let global_type = TypeId::of::<G>();
1861 self.push_effect(Effect::NotifyGlobalObservers { global_type });
1862 self.globals_by_type
1863 .get_mut(&global_type)
1864 .and_then(|any_state| any_state.downcast_mut::<G>())
1865 .unwrap_or_else(|| panic!("no state of type {} exists", type_name::<G>()))
1866 }
1867
1868 pub fn default_global<G: Global + Default>(&mut self) -> &mut G {
1871 let global_type = TypeId::of::<G>();
1872 self.push_effect(Effect::NotifyGlobalObservers { global_type });
1873 self.globals_by_type
1874 .entry(global_type)
1875 .or_insert_with(|| Box::<G>::default())
1876 .downcast_mut::<G>()
1877 .unwrap()
1878 }
1879
1880 pub fn set_global<G: Global>(&mut self, global: G) {
1882 let global_type = TypeId::of::<G>();
1883 self.push_effect(Effect::NotifyGlobalObservers { global_type });
1884 self.globals_by_type.insert(global_type, Box::new(global));
1885 }
1886
1887 #[cfg(any(test, feature = "test-support"))]
1889 pub fn clear_globals(&mut self) {
1890 self.globals_by_type.drain();
1891 }
1892
1893 pub fn remove_global<G: Global>(&mut self) -> G {
1895 let global_type = TypeId::of::<G>();
1896 self.push_effect(Effect::NotifyGlobalObservers { global_type });
1897 *self
1898 .globals_by_type
1899 .remove(&global_type)
1900 .unwrap_or_else(|| panic!("no global added for {}", type_name::<G>()))
1901 .downcast()
1902 .unwrap()
1903 }
1904
1905 pub fn observe_global<G: Global>(
1907 &mut self,
1908 mut f: impl FnMut(&mut Self) + 'static,
1909 ) -> Subscription {
1910 let (subscription, activate) = self.global_observers.insert(
1911 TypeId::of::<G>(),
1912 Box::new(move |cx| {
1913 f(cx);
1914 true
1915 }),
1916 );
1917 self.defer(move |_| activate());
1918 subscription
1919 }
1920
1921 #[track_caller]
1923 pub(crate) fn lease_global<G: Global>(&mut self) -> GlobalLease<G> {
1924 GlobalLease::new(
1925 self.globals_by_type
1926 .remove(&TypeId::of::<G>())
1927 .with_context(|| format!("no global registered of type {}", type_name::<G>()))
1928 .unwrap(),
1929 )
1930 }
1931
1932 pub(crate) fn end_global_lease<G: Global>(&mut self, lease: GlobalLease<G>) {
1934 let global_type = TypeId::of::<G>();
1935
1936 self.push_effect(Effect::NotifyGlobalObservers { global_type });
1937 self.globals_by_type.insert(global_type, lease.global);
1938 }
1939
1940 pub(crate) fn new_entity_observer(
1941 &self,
1942 key: TypeId,
1943 value: NewEntityListener,
1944 ) -> Subscription {
1945 let (subscription, activate) = self.new_entity_observers.insert(key, value);
1946 activate();
1947 subscription
1948 }
1949
1950 pub fn observe_new<T: 'static>(
1953 &self,
1954 on_new: impl 'static + Fn(&mut T, Option<&mut Window>, &mut Context<T>),
1955 ) -> Subscription {
1956 self.new_entity_observer(
1957 TypeId::of::<T>(),
1958 Box::new(
1959 move |any_entity: AnyEntity, window: &mut Option<&mut Window>, cx: &mut App| {
1960 any_entity
1961 .downcast::<T>()
1962 .unwrap()
1963 .update(cx, |entity_state, cx| {
1964 on_new(entity_state, window.as_deref_mut(), cx)
1965 })
1966 },
1967 ),
1968 )
1969 }
1970
1971 pub fn observe_release<T>(
1974 &self,
1975 handle: &Entity<T>,
1976 on_release: impl FnOnce(&mut T, &mut App) + 'static,
1977 ) -> Subscription
1978 where
1979 T: 'static,
1980 {
1981 let (subscription, activate) = self.release_listeners.insert(
1982 handle.entity_id(),
1983 Box::new(move |entity, cx| {
1984 let entity = entity.downcast_mut().expect("invalid entity type");
1985 on_release(entity, cx)
1986 }),
1987 );
1988 activate();
1989 subscription
1990 }
1991
1992 pub fn observe_release_in<T>(
1995 &self,
1996 handle: &Entity<T>,
1997 window: &Window,
1998 on_release: impl FnOnce(&mut T, &mut Window, &mut App) + 'static,
1999 ) -> Subscription
2000 where
2001 T: 'static,
2002 {
2003 let window_handle = window.handle;
2004 self.observe_release(handle, move |entity, cx| {
2005 let _ = window_handle.update(cx, |_, window, cx| on_release(entity, window, cx));
2006 })
2007 }
2008
2009 pub fn observe_keystrokes(
2013 &mut self,
2014 mut f: impl FnMut(&KeystrokeEvent, &mut Window, &mut App) + 'static,
2015 ) -> Subscription {
2016 fn inner(
2017 keystroke_observers: &SubscriberSet<(), KeystrokeObserver>,
2018 handler: KeystrokeObserver,
2019 ) -> Subscription {
2020 let (subscription, activate) = keystroke_observers.insert((), handler);
2021 activate();
2022 subscription
2023 }
2024
2025 inner(
2026 &self.keystroke_observers,
2027 Box::new(move |event, window, cx| {
2028 f(event, window, cx);
2029 true
2030 }),
2031 )
2032 }
2033
2034 pub fn intercept_keystrokes(
2039 &mut self,
2040 mut f: impl FnMut(&KeystrokeEvent, &mut Window, &mut App) + 'static,
2041 ) -> Subscription {
2042 fn inner(
2043 keystroke_interceptors: &SubscriberSet<(), KeystrokeObserver>,
2044 handler: KeystrokeObserver,
2045 ) -> Subscription {
2046 let (subscription, activate) = keystroke_interceptors.insert((), handler);
2047 activate();
2048 subscription
2049 }
2050
2051 inner(
2052 &self.keystroke_interceptors,
2053 Box::new(move |event, window, cx| {
2054 f(event, window, cx);
2055 true
2056 }),
2057 )
2058 }
2059
2060 pub fn bind_keys(&mut self, bindings: impl IntoIterator<Item = KeyBinding>) {
2062 self.keymap.borrow_mut().add_bindings(bindings);
2063 self.pending_effects.push_back(Effect::RefreshWindows);
2064 }
2065
2066 pub fn clear_key_bindings(&mut self) {
2068 self.keymap.borrow_mut().clear();
2069 self.pending_effects.push_back(Effect::RefreshWindows);
2070 }
2071
2072 pub fn key_bindings(&self) -> Rc<RefCell<Keymap>> {
2074 self.keymap.clone()
2075 }
2076
2077 pub fn on_action<A: Action>(
2081 &mut self,
2082 listener: impl Fn(&A, &mut Self) + 'static,
2083 ) -> &mut Self {
2084 self.global_action_listeners
2085 .entry(TypeId::of::<A>())
2086 .or_default()
2087 .push(Rc::new(move |action, phase, cx| {
2088 if phase == DispatchPhase::Bubble {
2089 let action = action.downcast_ref().unwrap();
2090 listener(action, cx)
2091 }
2092 }));
2093 self
2094 }
2095
2096 pub fn stop_propagation(&mut self) {
2101 self.propagate_event = false;
2102 }
2103
2104 pub fn propagate(&mut self) {
2109 self.propagate_event = true;
2110 }
2111
2112 pub fn build_action(
2114 &self,
2115 name: &str,
2116 data: Option<serde_json::Value>,
2117 ) -> std::result::Result<Box<dyn Action>, ActionBuildError> {
2118 self.actions.build_action(name, data)
2119 }
2120
2121 pub fn all_action_names(&self) -> &[&'static str] {
2124 self.actions.all_action_names()
2125 }
2126
2127 pub fn all_bindings_for_input(&self, input: &[Keystroke]) -> Vec<KeyBinding> {
2131 RefCell::borrow(&self.keymap).all_bindings_for_input(input)
2132 }
2133
2134 pub fn action_schemas(
2136 &self,
2137 generator: &mut schemars::SchemaGenerator,
2138 ) -> Vec<(&'static str, Option<schemars::Schema>)> {
2139 self.actions.action_schemas(generator)
2140 }
2141
2142 pub fn action_schema_by_name(
2147 &self,
2148 name: &str,
2149 generator: &mut schemars::SchemaGenerator,
2150 ) -> Option<Option<schemars::Schema>> {
2151 self.actions.action_schema_by_name(name, generator)
2152 }
2153
2154 pub fn deprecated_actions_to_preferred_actions(&self) -> &HashMap<&'static str, &'static str> {
2156 self.actions.deprecated_aliases()
2157 }
2158
2159 pub fn action_deprecation_messages(&self) -> &HashMap<&'static str, &'static str> {
2161 self.actions.deprecation_messages()
2162 }
2163
2164 pub fn action_documentation(&self) -> &HashMap<&'static str, &'static str> {
2166 self.actions.documentation()
2167 }
2168
2169 pub fn on_app_quit<Fut>(
2172 &self,
2173 mut on_quit: impl FnMut(&mut App) -> Fut + 'static,
2174 ) -> Subscription
2175 where
2176 Fut: 'static + Future<Output = ()>,
2177 {
2178 let (subscription, activate) = self.quit_observers.insert(
2179 (),
2180 Box::new(move |cx| {
2181 let future = on_quit(cx);
2182 future.boxed_local()
2183 }),
2184 );
2185 activate();
2186 subscription
2187 }
2188
2189 pub fn on_app_restart(&self, mut on_restart: impl 'static + FnMut(&mut App)) -> Subscription {
2193 let (subscription, activate) = self.restart_observers.insert(
2194 (),
2195 Box::new(move |cx| {
2196 on_restart(cx);
2197 true
2198 }),
2199 );
2200 activate();
2201 subscription
2202 }
2203
2204 pub fn on_window_closed(
2207 &self,
2208 mut on_closed: impl FnMut(&mut App, WindowId) + 'static,
2209 ) -> Subscription {
2210 let (subscription, activate) = self.window_closed_observers.insert((), Box::new(on_closed));
2211 activate();
2212 subscription
2213 }
2214
2215 pub(crate) fn clear_pending_keystrokes(&mut self) {
2216 for window in self.windows() {
2217 window
2218 .update(self, |_, window, cx| {
2219 if window.pending_input_keystrokes().is_some() {
2220 window.clear_pending_keystrokes();
2221 window.pending_input_changed(cx);
2222 }
2223 })
2224 .ok();
2225 }
2226 }
2227
2228 pub fn is_action_available(&mut self, action: &dyn Action) -> bool {
2231 let mut action_available = false;
2232 if let Some(window) = self.focused_action_window()
2233 && let Ok(window_action_available) =
2234 window.update(self, |_, window, cx| window.is_action_available(action, cx))
2235 {
2236 action_available = window_action_available;
2237 }
2238
2239 action_available
2240 || self
2241 .global_action_listeners
2242 .contains_key(&action.as_any().type_id())
2243 }
2244
2245 pub fn set_menus(&self, menus: impl IntoIterator<Item = Menu>) {
2247 let menus: Vec<Menu> = menus.into_iter().collect();
2248 self.platform.set_menus(menus, &self.keymap.borrow());
2249 }
2250
2251 pub fn get_menus(&self) -> Option<Vec<OwnedMenu>> {
2253 self.platform.get_menus()
2254 }
2255
2256 pub fn set_dock_menu(&self, menus: Vec<MenuItem>) {
2258 self.platform.set_dock_menu(menus, &self.keymap.borrow())
2259 }
2260
2261 pub fn perform_dock_menu_action(&self, action: usize) {
2263 self.platform.perform_dock_menu_action(action);
2264 }
2265
2266 pub fn add_recent_document(&self, path: &Path) {
2271 self.platform.add_recent_document(path);
2272 }
2273
2274 pub fn update_jump_list(
2277 &self,
2278 menus: Vec<MenuItem>,
2279 entries: Vec<SmallVec<[PathBuf; 2]>>,
2280 ) -> Task<Vec<SmallVec<[PathBuf; 2]>>> {
2281 self.platform.update_jump_list(menus, entries)
2282 }
2283
2284 pub fn dispatch_action(&mut self, action: &dyn Action) {
2287 if let Some(focused_window) = self.focused_action_window() {
2288 focused_window
2289 .update(self, |_, window, cx| {
2290 window.dispatch_action(action.boxed_clone(), cx)
2291 })
2292 .log_err();
2293 } else {
2294 self.dispatch_global_action(action);
2295 }
2296 }
2297
2298 fn focused_action_window(&self) -> Option<AnyWindowHandle> {
2299 match self.focused_window() {
2300 PlatformFocusedWindow::Window(window) => Some(window),
2301 PlatformFocusedWindow::NoWindow | PlatformFocusedWindow::Unavailable => None,
2302 }
2303 }
2304
2305 fn dispatch_global_action(&mut self, action: &dyn Action) {
2306 self.propagate_event = true;
2307
2308 if let Some(mut global_listeners) = self
2309 .global_action_listeners
2310 .remove(&action.as_any().type_id())
2311 {
2312 for listener in &global_listeners {
2313 listener(action.as_any(), DispatchPhase::Capture, self);
2314 if !self.propagate_event {
2315 break;
2316 }
2317 }
2318
2319 global_listeners.extend(
2320 self.global_action_listeners
2321 .remove(&action.as_any().type_id())
2322 .unwrap_or_default(),
2323 );
2324
2325 self.global_action_listeners
2326 .insert(action.as_any().type_id(), global_listeners);
2327 }
2328
2329 if self.propagate_event
2330 && let Some(mut global_listeners) = self
2331 .global_action_listeners
2332 .remove(&action.as_any().type_id())
2333 {
2334 for listener in global_listeners.iter().rev() {
2335 listener(action.as_any(), DispatchPhase::Bubble, self);
2336 if !self.propagate_event {
2337 break;
2338 }
2339 }
2340
2341 global_listeners.extend(
2342 self.global_action_listeners
2343 .remove(&action.as_any().type_id())
2344 .unwrap_or_default(),
2345 );
2346
2347 self.global_action_listeners
2348 .insert(action.as_any().type_id(), global_listeners);
2349 }
2350 }
2351
2352 pub fn has_active_drag(&self) -> bool {
2354 self.active_drag.is_some()
2355 }
2356
2357 pub fn active_drag_value<T: 'static>(&self) -> Option<&T> {
2359 self.active_drag
2360 .as_ref()
2361 .and_then(|drag| drag.value.downcast_ref::<T>())
2362 }
2363
2364 pub fn active_drag_cursor_style(&self) -> Option<CursorStyle> {
2366 self.active_drag.as_ref().and_then(|drag| drag.cursor_style)
2367 }
2368
2369 pub fn stop_active_drag(&mut self, window: &mut Window) -> bool {
2371 if self.active_drag.is_some() {
2372 self.active_drag = None;
2373 window.refresh();
2374 true
2375 } else {
2376 false
2377 }
2378 }
2379
2380 pub fn set_active_drag_cursor_style(
2382 &mut self,
2383 cursor_style: CursorStyle,
2384 window: &mut Window,
2385 ) -> bool {
2386 if let Some(ref mut drag) = self.active_drag {
2387 drag.cursor_style = Some(cursor_style);
2388 window.refresh();
2389 true
2390 } else {
2391 false
2392 }
2393 }
2394
2395 pub fn set_prompt_builder(
2398 &mut self,
2399 renderer: impl Fn(
2400 PromptLevel,
2401 &str,
2402 Option<&str>,
2403 &[PromptButton],
2404 PromptHandle,
2405 &mut Window,
2406 &mut App,
2407 ) -> RenderablePromptHandle
2408 + 'static,
2409 ) {
2410 self.prompt_builder = Some(PromptBuilder::Custom(Box::new(renderer)));
2411 }
2412
2413 pub fn reset_prompt_builder(&mut self) {
2415 self.prompt_builder = Some(PromptBuilder::Default);
2416 }
2417
2418 pub fn remove_asset<A: Asset>(&mut self, source: &A::Source) {
2420 let asset_id = (TypeId::of::<A>(), hash(source));
2421 self.loading_assets.remove(&asset_id);
2422 }
2423
2424 pub fn fetch_asset<A: Asset>(&mut self, source: &A::Source) -> (Shared<Task<A::Output>>, bool) {
2429 let asset_id = (TypeId::of::<A>(), hash(source));
2430 let mut is_first = false;
2431 let task = self
2432 .loading_assets
2433 .remove(&asset_id)
2434 .map(|boxed_task| *boxed_task.downcast::<Shared<Task<A::Output>>>().unwrap())
2435 .unwrap_or_else(|| {
2436 is_first = true;
2437 let future = A::load(source.clone(), self);
2438
2439 self.background_executor().spawn(future).shared()
2440 });
2441
2442 self.loading_assets.insert(asset_id, Box::new(task.clone()));
2443
2444 (task, is_first)
2445 }
2446
2447 #[track_caller]
2450 pub fn focus_handle(&self) -> FocusHandle {
2451 FocusHandle::new(&self.focus_handles)
2452 }
2453
2454 pub fn notify(&mut self, entity_id: EntityId) {
2456 let window_invalidators = mem::take(
2457 self.window_invalidators_by_entity
2458 .entry(entity_id)
2459 .or_default(),
2460 );
2461
2462 let live_invalidators: SmallVec<[WindowInvalidator; 2]> = window_invalidators
2467 .iter()
2468 .filter(|(window_id, _)| {
2469 self.tracked_entities
2470 .get(window_id)
2471 .is_some_and(|set| set.contains(&entity_id))
2472 })
2473 .map(|(_, invalidator)| invalidator.clone())
2474 .collect();
2475
2476 if live_invalidators.is_empty() {
2477 if self.pending_notifications.insert(entity_id) {
2478 self.pending_effects
2479 .push_back(Effect::Notify { emitter: entity_id });
2480 }
2481 } else {
2482 for invalidator in &live_invalidators {
2483 invalidator.invalidate_view(entity_id, self);
2484 }
2485 }
2486
2487 self.window_invalidators_by_entity
2488 .insert(entity_id, window_invalidators);
2489 }
2490
2491 #[cfg(any(test, feature = "test-support", debug_assertions))]
2493 pub fn get_name(&self) -> Option<&'static str> {
2494 self.name
2495 }
2496
2497 pub fn can_select_mixed_files_and_dirs(&self) -> bool {
2499 self.platform.can_select_mixed_files_and_dirs()
2500 }
2501
2502 pub fn drop_image(&mut self, image: Arc<RenderImage>, current_window: Option<&mut Window>) {
2507 for window in self.windows.values_mut().flatten() {
2509 _ = window.drop_image(image.clone());
2510 }
2511
2512 if let Some(window) = current_window {
2514 _ = window.drop_image(image);
2515 }
2516 }
2517
2518 #[cfg(any(feature = "inspector", debug_assertions))]
2520 pub fn set_inspector_renderer(&mut self, f: crate::InspectorRenderer) {
2521 self.inspector_renderer = Some(f);
2522 }
2523
2524 #[cfg(any(feature = "inspector", debug_assertions))]
2526 pub fn register_inspector_element<T: 'static, R: crate::IntoElement>(
2527 &mut self,
2528 f: impl 'static + Fn(crate::InspectorElementId, &T, &mut Window, &mut App) -> R,
2529 ) {
2530 self.inspector_element_registry.register(f);
2531 }
2532
2533 pub fn init_colors(&mut self) {
2537 self.set_global(GlobalColors(Arc::new(Colors::default())));
2538 }
2539}
2540
2541impl AppContext for App {
2542 fn new<T: 'static>(&mut self, build_entity: impl FnOnce(&mut Context<T>) -> T) -> Entity<T> {
2547 self.update(|cx| {
2548 let slot = cx.entities.reserve();
2549 let handle = slot.clone();
2550 let entity = build_entity(&mut Context::new_context(cx, slot.downgrade()));
2551
2552 cx.push_effect(Effect::EntityCreated {
2553 entity: handle.into_any(),
2554 tid: TypeId::of::<T>(),
2555 window: cx.window_update_stack.last().cloned(),
2556 });
2557
2558 cx.entities.insert(slot, entity)
2559 })
2560 }
2561
2562 fn reserve_entity<T: 'static>(&mut self) -> Reservation<T> {
2563 Reservation(self.entities.reserve())
2564 }
2565
2566 fn insert_entity<T: 'static>(
2567 &mut self,
2568 reservation: Reservation<T>,
2569 build_entity: impl FnOnce(&mut Context<T>) -> T,
2570 ) -> Entity<T> {
2571 self.update(|cx| {
2572 let slot = reservation.0;
2573 let entity = build_entity(&mut Context::new_context(cx, slot.downgrade()));
2574 cx.entities.insert(slot, entity)
2575 })
2576 }
2577
2578 fn update_entity<T: 'static, R>(
2581 &mut self,
2582 handle: &Entity<T>,
2583 update: impl FnOnce(&mut T, &mut Context<T>) -> R,
2584 ) -> R {
2585 self.update(|cx| {
2586 let mut entity = cx.entities.lease(handle);
2587 let result = update(
2588 &mut entity,
2589 &mut Context::new_context(cx, handle.downgrade()),
2590 );
2591 cx.entities.end_lease(entity);
2592 result
2593 })
2594 }
2595
2596 fn as_mut<'a, T>(&'a mut self, handle: &Entity<T>) -> GpuiBorrow<'a, T>
2597 where
2598 T: 'static,
2599 {
2600 GpuiBorrow::new(handle.clone(), self)
2601 }
2602
2603 fn read_entity<T, R>(&self, handle: &Entity<T>, read: impl FnOnce(&T, &App) -> R) -> R
2604 where
2605 T: 'static,
2606 {
2607 let entity = self.entities.read(handle);
2608 read(entity, self)
2609 }
2610
2611 fn update_window<T, F>(&mut self, handle: AnyWindowHandle, update: F) -> Result<T>
2612 where
2613 F: FnOnce(AnyView, &mut Window, &mut App) -> T,
2614 {
2615 self.update_window_id(handle.id, update)
2616 }
2617
2618 fn with_window<R>(
2619 &mut self,
2620 entity_id: EntityId,
2621 f: impl FnOnce(&mut Window, &mut App) -> R,
2622 ) -> Option<R> {
2623 App::with_window(self, entity_id, f)
2624 }
2625
2626 fn read_window<T, R>(
2627 &self,
2628 window: &WindowHandle<T>,
2629 read: impl FnOnce(Entity<T>, &App) -> R,
2630 ) -> Result<R>
2631 where
2632 T: 'static,
2633 {
2634 let window = self
2635 .windows
2636 .get(window.id)
2637 .context("window not found")?
2638 .as_deref()
2639 .expect("attempted to read a window that is already on the stack");
2640
2641 let root_view = window.root.clone().unwrap();
2642 let view = root_view
2643 .downcast::<T>()
2644 .map_err(|_| anyhow!("root view's type has changed"))?;
2645
2646 Ok(read(view, self))
2647 }
2648
2649 fn background_spawn<R>(&self, future: impl Future<Output = R> + Send + 'static) -> Task<R>
2650 where
2651 R: Send + 'static,
2652 {
2653 self.background_executor.spawn(future)
2654 }
2655
2656 fn read_global<G, R>(&self, callback: impl FnOnce(&G, &App) -> R) -> R
2657 where
2658 G: Global,
2659 {
2660 let mut g = self.global::<G>();
2661 callback(g, self)
2662 }
2663}
2664
2665pub(crate) enum Effect {
2667 Notify {
2668 emitter: EntityId,
2669 },
2670 Emit {
2671 emitter: EntityId,
2672 event_type: TypeId,
2673 event: ArenaBox<dyn Any>,
2674 },
2675 RefreshWindows,
2676 NotifyGlobalObservers {
2677 global_type: TypeId,
2678 },
2679 Defer {
2680 callback: Box<dyn FnOnce(&mut App) + 'static>,
2681 },
2682 EntityCreated {
2683 entity: AnyEntity,
2684 tid: TypeId,
2685 window: Option<WindowId>,
2686 },
2687}
2688
2689impl std::fmt::Debug for Effect {
2690 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2691 match self {
2692 Effect::Notify { emitter } => write!(f, "Notify({})", emitter),
2693 Effect::Emit { emitter, .. } => write!(f, "Emit({:?})", emitter),
2694 Effect::RefreshWindows => write!(f, "RefreshWindows"),
2695 Effect::NotifyGlobalObservers { global_type } => {
2696 write!(f, "NotifyGlobalObservers({:?})", global_type)
2697 }
2698 Effect::Defer { .. } => write!(f, "Defer(..)"),
2699 Effect::EntityCreated { entity, .. } => write!(f, "EntityCreated({:?})", entity),
2700 }
2701 }
2702}
2703
2704pub(crate) struct GlobalLease<G: Global> {
2706 global: Box<dyn Any>,
2707 global_type: PhantomData<G>,
2708}
2709
2710impl<G: Global> GlobalLease<G> {
2711 fn new(global: Box<dyn Any>) -> Self {
2712 GlobalLease {
2713 global,
2714 global_type: PhantomData,
2715 }
2716 }
2717}
2718
2719impl<G: Global> Deref for GlobalLease<G> {
2720 type Target = G;
2721
2722 fn deref(&self) -> &Self::Target {
2723 self.global.downcast_ref().unwrap()
2724 }
2725}
2726
2727impl<G: Global> DerefMut for GlobalLease<G> {
2728 fn deref_mut(&mut self) -> &mut Self::Target {
2729 self.global.downcast_mut().unwrap()
2730 }
2731}
2732
2733pub struct AnyDrag {
2736 pub view: AnyView,
2738
2739 pub value: Arc<dyn Any>,
2741
2742 pub cursor_offset: Point<Pixels>,
2745
2746 pub cursor_style: Option<CursorStyle>,
2748}
2749
2750#[derive(Clone)]
2753pub struct AnyTooltip {
2754 pub view: AnyView,
2756
2757 pub mouse_position: Point<Pixels>,
2759
2760 pub check_visible_and_update: Rc<dyn Fn(Bounds<Pixels>, &mut Window, &mut App) -> bool>,
2764}
2765
2766#[derive(Debug)]
2768pub struct KeystrokeEvent {
2769 pub keystroke: Keystroke,
2771
2772 pub action: Option<Box<dyn Action>>,
2774
2775 pub context_stack: Vec<KeyContext>,
2777}
2778
2779struct NullHttpClient;
2780
2781impl HttpClient for NullHttpClient {
2782 fn send(
2783 &self,
2784 _req: open_gpui_http_client::Request<open_gpui_http_client::AsyncBody>,
2785 ) -> futures::future::BoxFuture<
2786 'static,
2787 anyhow::Result<open_gpui_http_client::Response<open_gpui_http_client::AsyncBody>>,
2788 > {
2789 async move {
2790 anyhow::bail!("No HttpClient available");
2791 }
2792 .boxed()
2793 }
2794
2795 fn user_agent(&self) -> Option<&open_gpui_http_client::http::HeaderValue> {
2796 None
2797 }
2798
2799 fn proxy(&self) -> Option<&Url> {
2800 None
2801 }
2802}
2803
2804pub struct GpuiBorrow<'a, T> {
2806 inner: Option<Lease<T>>,
2807 app: &'a mut App,
2808}
2809
2810impl<'a, T: 'static> GpuiBorrow<'a, T> {
2811 fn new(inner: Entity<T>, app: &'a mut App) -> Self {
2812 app.start_update();
2813 let lease = app.entities.lease(&inner);
2814 Self {
2815 inner: Some(lease),
2816 app,
2817 }
2818 }
2819}
2820
2821impl<'a, T: 'static> std::borrow::Borrow<T> for GpuiBorrow<'a, T> {
2822 fn borrow(&self) -> &T {
2823 self.inner.as_ref().unwrap().borrow()
2824 }
2825}
2826
2827impl<'a, T: 'static> std::borrow::BorrowMut<T> for GpuiBorrow<'a, T> {
2828 fn borrow_mut(&mut self) -> &mut T {
2829 self.inner.as_mut().unwrap().borrow_mut()
2830 }
2831}
2832
2833impl<'a, T: 'static> std::ops::Deref for GpuiBorrow<'a, T> {
2834 type Target = T;
2835
2836 fn deref(&self) -> &Self::Target {
2837 self.inner.as_ref().unwrap()
2838 }
2839}
2840
2841impl<'a, T: 'static> std::ops::DerefMut for GpuiBorrow<'a, T> {
2842 fn deref_mut(&mut self) -> &mut T {
2843 self.inner.as_mut().unwrap()
2844 }
2845}
2846
2847impl<'a, T> Drop for GpuiBorrow<'a, T> {
2848 fn drop(&mut self) {
2849 let lease = self.inner.take().unwrap();
2850 self.app.notify(lease.id);
2851 self.app.entities.end_lease(lease);
2852 self.app.finish_update();
2853 }
2854}
2855
2856#[cfg(test)]
2857mod test {
2858 use std::{
2859 cell::{Cell, RefCell},
2860 rc::Rc,
2861 };
2862
2863 use crate::{AppContext, Empty, TestAppContext, px, size};
2864
2865 actions!(app_focus_tests, [DispatchProbe]);
2866
2867 #[test]
2868 fn test_gpui_borrow() {
2869 let cx = TestAppContext::single();
2870 let observation_count = Rc::new(RefCell::new(0));
2871
2872 let state = cx.update(|cx| {
2873 let state = cx.new(|_| false);
2874 cx.observe(&state, {
2875 let observation_count = observation_count.clone();
2876 move |_, _| {
2877 let mut count = observation_count.borrow_mut();
2878 *count += 1;
2879 }
2880 })
2881 .detach();
2882
2883 state
2884 });
2885
2886 cx.update(|cx| {
2887 *std::borrow::BorrowMut::borrow_mut(&mut state.as_mut(cx)) = true;
2889 });
2890
2891 cx.update(|cx| {
2892 state.write(cx, false);
2893 });
2894
2895 assert_eq!(*observation_count.borrow(), 2);
2896 }
2897
2898 #[crate::test]
2899 fn application_on_system_wake_runs_callback(cx: &mut TestAppContext) {
2900 let wake_count = Rc::new(Cell::new(0));
2901 super::Application(cx.app.clone()).on_system_wake({
2902 let wake_count = wake_count.clone();
2903 move |_| wake_count.set(wake_count.get() + 1)
2904 });
2905
2906 cx.simulate_system_wake();
2907 cx.simulate_system_wake();
2908
2909 assert_eq!(wake_count.get(), 2);
2910 }
2911
2912 #[crate::test]
2913 fn app_dispatch_action_uses_focused_window_authority(cx: &mut TestAppContext) {
2914 let window = cx.open_window(size(px(320.0), px(200.0)), |_, _| Empty);
2915 window
2916 .update(cx, |_, window, _| window.activate_window())
2917 .expect("test window should be activatable");
2918 cx.run_until_parked();
2919 assert_eq!(
2920 cx.update(|app| app.active_window()),
2921 Some(window.into()),
2922 "setup should leave an active application window"
2923 );
2924
2925 let global_dispatch_count = Rc::new(RefCell::new(0));
2926 cx.update(|app| {
2927 let global_dispatch_count = global_dispatch_count.clone();
2928 app.on_action(move |_: &DispatchProbe, _| {
2929 *global_dispatch_count.borrow_mut() += 1;
2930 });
2931 });
2932
2933 cx.set_platform_focused_window_available(false);
2934 cx.update(|app| app.dispatch_action(&DispatchProbe));
2935
2936 assert_eq!(
2937 *global_dispatch_count.borrow(),
2938 1,
2939 "when backend focus authority is unavailable, app dispatch must not target active_window"
2940 );
2941 }
2942}