1use crate::{
2 Action, ActionBuildError, ActionRegistry, ActivationPolicy, ActivityGuard, Any, AnyView,
3 AnyWindowHandle, AppContext, AppLifecyclePhase, Arena, ArenaBox, Asset, AssetRegistry,
4 BackgroundExecutor, Bounds, ClipboardItem, ClipboardReadError, CursorStyle, DispatchPhase,
5 DisplayChanges, DisplayEvent, DisplayId, EventEmitter, ExternalDragPayload, FocusHandle,
6 FocusMap, ForegroundExecutor, Global, HapticFeedbackStyle, KeyBinding, KeyContext, Keymap,
7 Keystroke, LayoutId, Menu, MenuItem, OwnedMenu, PathPromptOptions, Pixels, Platform,
8 PlatformDisplay, PlatformKeyboardLayout, PlatformKeyboardMapper, Point, Priority,
9 PromptBuilder, PromptButton, PromptHandle, PromptLevel, Render, RenderImage,
10 RenderablePromptHandle, Reservation, ScreenCaptureSource, SharedString, SubscriberSet,
11 Subscription, SvgRenderer, SystemNotification, SystemNotificationResponse, Task,
12 TextRenderingMode, TextSystem, ThermalState, Window, WindowAppearance, WindowButtonLayout,
13 WindowHandle, WindowId, WindowInvalidator, WindowingRequest,
14 colors::{Colors, GlobalColors},
15 hash,
16 http_client::{HttpClient, NullHttpClient},
17 init_app_menus,
18};
19use anyhow::{Context as _, Result, anyhow};
20use collections::{FxHashMap, FxHashSet, HashMap, TypeIdHashMap, TypeIdHashSet, VecDeque};
21use derive_more::{Deref, DerefMut};
22use futures::{Future, FutureExt, channel::oneshot, future::LocalBoxFuture};
23use gpui_util::{ResultExt, debug_panic};
24use itertools::Itertools;
25use parking_lot::RwLock;
26use scheduler::Instant;
27use slotmap::SlotMap;
28use smallvec::SmallVec;
29use std::{
30 any::{TypeId, type_name},
31 cell::{BorrowMutError, Cell, Ref, RefCell, RefMut},
32 ffi::OsString,
33 marker::PhantomData,
34 mem,
35 ops::{Deref, DerefMut},
36 path::{Path, PathBuf},
37 rc::{Rc, Weak},
38 sync::Arc,
39 time::Duration,
40};
41
42#[cfg(any(feature = "inspector", debug_assertions))]
43use crate::InspectorElementRegistry;
44use crate::asset_cache::CachedLoad;
45pub use async_context::*;
46#[cfg(feature = "bench-support")]
47pub use bench_context::{
48 BenchAppContext, BenchMeasurement, BenchReport, BenchWindowContext, CountingAllocator,
49 MetricReport, bench_platform,
50};
51
52mod async_context;
53#[cfg(feature = "bench-support")]
54mod bench_context;
55mod context;
56mod entity_map;
57#[cfg(any(test, feature = "test-support"))]
58mod headless_app_context;
59#[cfg(any(test, feature = "test-support"))]
60mod test_app;
61#[cfg(any(test, feature = "test-support"))]
62mod test_context;
63#[cfg(all(target_os = "macos", any(test, feature = "test-support")))]
64mod visual_test_context;
65
66pub use context::*;
67pub use entity_map::*;
68#[cfg(any(test, feature = "test-support"))]
69pub use headless_app_context::*;
70#[cfg(any(test, feature = "test-support"))]
71pub use test_app::*;
72#[cfg(any(test, feature = "test-support"))]
73pub use test_context::*;
74#[cfg(all(target_os = "macos", any(test, feature = "test-support")))]
75pub use visual_test_context::*;
76
77pub const SHUTDOWN_TIMEOUT: Duration = Duration::from_millis(200);
80
81#[doc(hidden)]
84pub struct AppCell {
85 app: RefCell<App>,
86}
87
88impl AppCell {
89 #[doc(hidden)]
90 #[track_caller]
91 pub fn borrow(&self) -> AppRef<'_> {
92 if option_env!("TRACK_THREAD_BORROWS").is_some() {
93 let thread_id = std::thread::current().id();
94 eprintln!("borrowed {thread_id:?}");
95 }
96 AppRef(self.app.borrow())
97 }
98
99 #[doc(hidden)]
100 #[track_caller]
101 pub fn borrow_mut(&self) -> AppRefMut<'_> {
102 if option_env!("TRACK_THREAD_BORROWS").is_some() {
103 let thread_id = std::thread::current().id();
104 eprintln!("borrowed {thread_id:?}");
105 }
106 AppRefMut(self.app.borrow_mut())
107 }
108
109 #[doc(hidden)]
110 #[track_caller]
111 pub fn try_borrow_mut(&self) -> Result<AppRefMut<'_>, BorrowMutError> {
112 if option_env!("TRACK_THREAD_BORROWS").is_some() {
113 let thread_id = std::thread::current().id();
114 eprintln!("borrowed {thread_id:?}");
115 }
116 Ok(AppRefMut(self.app.try_borrow_mut()?))
117 }
118}
119
120#[doc(hidden)]
121#[derive(Deref, DerefMut)]
122pub struct AppRef<'a>(Ref<'a, App>);
123
124impl Drop for AppRef<'_> {
125 fn drop(&mut self) {
126 if option_env!("TRACK_THREAD_BORROWS").is_some() {
127 let thread_id = std::thread::current().id();
128 eprintln!("dropped borrow from {thread_id:?}");
129 }
130 }
131}
132
133#[doc(hidden)]
134#[derive(Deref, DerefMut)]
135pub struct AppRefMut<'a>(RefMut<'a, App>);
136
137impl Drop for AppRefMut<'_> {
138 fn drop(&mut self) {
139 if option_env!("TRACK_THREAD_BORROWS").is_some() {
140 let thread_id = std::thread::current().id();
141 eprintln!("dropped {thread_id:?}");
142 }
143 }
144}
145
146pub struct Application(Rc<AppCell>);
186
187pub struct ApplicationHandle {
193 app: Rc<AppCell>,
194}
195
196impl ApplicationHandle {
197 pub fn update<R>(&self, f: impl FnOnce(&mut App) -> R) -> R {
204 let cx = &mut *self.app.borrow_mut();
205 cx.update(f)
206 }
207
208 pub fn to_async(&self) -> AsyncApp {
213 self.update(|cx| cx.to_async())
214 }
215}
216
217impl Application {
218 pub fn with_platform(platform: Rc<dyn Platform>) -> Self {
229 Self(App::new_app(
230 platform,
231 AssetRegistry::default().into(),
232 Arc::new(NullHttpClient),
233 ))
234 }
235
236 pub fn new_inaccessible(platform: Rc<dyn Platform>) -> Self {
246 let this = Self::with_platform(platform);
247 this.0.borrow_mut().accessibility_force_disabled = true;
248 this
249 }
250
251 pub fn with_accessibility_forced(self) -> Self {
258 self.0.borrow_mut().accessibility_forced = true;
259 self
260 }
261
262 pub fn with_assets(self, assets: impl Into<AssetRegistry>) -> Self {
267 let mut context_lock = self.0.borrow_mut();
268 let asset_registry = Arc::new(assets.into());
269 context_lock.asset_registry = asset_registry.clone();
270 context_lock.svg_renderer = SvgRenderer::new(asset_registry);
271 drop(context_lock);
272 self
273 }
274
275 pub fn with_restart_arguments(self, arguments: Vec<OsString>) -> Self {
277 self.0.borrow_mut().restart_arguments = arguments;
278 self
279 }
280
281 pub fn with_http_client(self, http_client: Arc<dyn HttpClient>) -> Self {
286 let mut context_lock = self.0.borrow_mut();
287 context_lock.http_client = http_client;
288 drop(context_lock);
289 self
290 }
291
292 pub fn with_quit_mode(self, mode: QuitMode) -> Self {
297 self.0.borrow_mut().quit_mode = mode;
298 self
299 }
300
301 #[cfg(target_os = "macos")]
312 pub fn with_activation_policy(self, policy: ActivationPolicy) -> Self {
313 self.0.borrow().platform.set_activation_policy(policy);
314 self
315 }
316
317 pub fn with_windowing(self, request: WindowingRequest) -> Self {
332 self.0.borrow().platform.set_initial_windowing(request);
333 self
334 }
335
336 pub fn run<F>(self, on_finish_launching: F)
342 where
343 F: 'static + FnOnce(&mut App),
344 {
345 #[cfg(all(
346 feature = "hot-patching",
347 debug_assertions,
348 not(target_family = "wasm")
349 ))]
350 dioxus_devtools::connect_subsecond();
351
352 let this = self.0.clone();
353 let platform = self.0.borrow().platform.clone();
354 platform.run(Box::new(move || {
355 let cx = &mut *this.borrow_mut();
356 cx.displays_changed();
358 on_finish_launching(cx);
359 }));
360
361 #[cfg(target_family = "wasm")]
365 std::mem::forget(self);
366 }
367
368 pub fn run_embedded<F>(self, on_finish_launching: F) -> ApplicationHandle
378 where
379 F: 'static + FnOnce(&mut App),
380 {
381 let this = self.0.clone();
382 let platform = self.0.borrow().platform.clone();
383 platform.run(Box::new(move || {
384 let cx = &mut *this.borrow_mut();
385 cx.displays_changed();
387 on_finish_launching(cx);
388 }));
389 ApplicationHandle { app: self.0 }
390 }
391
392 pub fn on_open_urls<F>(&self, mut callback: F) -> &Self
398 where
399 F: 'static + FnMut(Vec<String>),
400 {
401 self.0.borrow().platform.on_open_urls(Box::new(callback));
402 self
403 }
404
405 pub fn on_reopen<F>(&self, mut callback: F) -> &Self
411 where
412 F: 'static + FnMut(&mut App),
413 {
414 let this = Rc::downgrade(&self.0);
415 self.0.borrow_mut().platform.on_reopen(Box::new(move || {
416 if let Some(app) = this.upgrade() {
417 callback(&mut app.borrow_mut());
418 }
419 }));
420 self
421 }
422
423 pub fn background_executor(&self) -> BackgroundExecutor {
425 self.0.borrow().background_executor.clone()
426 }
427
428 pub fn foreground_executor(&self) -> ForegroundExecutor {
430 self.0.borrow().foreground_executor.clone()
431 }
432
433 pub fn text_system(&self) -> Arc<TextSystem> {
435 self.0.borrow().text_system.clone()
436 }
437
438 pub fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf> {
443 self.0.borrow().path_for_auxiliary_executable(name)
444 }
445}
446
447type Handler = Box<dyn FnMut(&mut App) -> bool + 'static>;
448type AppLifecycleHandler = Box<dyn FnMut(AppLifecyclePhase, &mut App) -> bool + 'static>;
449type DisplayHandler = Box<dyn FnMut(DisplayEvent, &mut App) -> bool + 'static>;
450
451#[derive(Clone, Copy, PartialEq)]
453struct DisplayState {
454 bounds: Bounds<Pixels>,
455 refresh_interval: Option<Duration>,
456}
457
458impl DisplayState {
459 fn changes_from(&self, previous: &DisplayState) -> DisplayChanges {
460 let mut changes = DisplayChanges::empty();
461 changes.set(DisplayChanges::BOUNDS, self.bounds != previous.bounds);
462 changes.set(
463 DisplayChanges::REFRESH_INTERVAL,
464 self.refresh_interval != previous.refresh_interval,
465 );
466 changes
467 }
468}
469
470fn read_displays(platform: &dyn Platform) -> HashMap<DisplayId, DisplayState> {
471 platform
472 .displays()
473 .into_iter()
474 .map(|display| {
475 let state = DisplayState {
476 bounds: display.bounds(),
477 refresh_interval: display.refresh_interval(),
478 };
479 (display.id(), state)
480 })
481 .collect()
482}
483
484fn display_events(
486 previous: &HashMap<DisplayId, DisplayState>,
487 current: &HashMap<DisplayId, DisplayState>,
488) -> Vec<DisplayEvent> {
489 let removed = previous
490 .keys()
491 .filter(|id| !current.contains_key(id))
492 .map(|id| DisplayEvent::Removed(*id));
493 let added_or_changed = current.iter().filter_map(|(id, state)| {
494 let Some(previous_state) = previous.get(id) else {
495 return Some(DisplayEvent::Added(*id));
496 };
497 let changes = state.changes_from(previous_state);
498 (!changes.is_empty()).then_some(DisplayEvent::Changed { id: *id, changes })
499 });
500 removed.chain(added_or_changed).collect()
501}
502type Listener = Box<dyn FnMut(&dyn Any, &mut App) -> bool + 'static>;
503pub(crate) type KeystrokeObserver =
504 Box<dyn FnMut(&KeystrokeEvent, &mut Window, &mut App) -> bool + 'static>;
505type QuitHandler = Box<dyn FnOnce(&mut App) -> LocalBoxFuture<'static, ()> + 'static>;
506type WindowClosedHandler = Box<dyn FnMut(&mut App, WindowId)>;
507type ReleaseListener = Box<dyn FnOnce(&mut dyn Any, &mut App) + 'static>;
508type NewEntityListener = Box<dyn FnMut(AnyEntity, &mut Option<&mut Window>, &mut App) + 'static>;
509
510#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
523pub enum QuitMode {
524 #[default]
527 Default,
528 LastWindowClosed,
530 Explicit,
532}
533
534#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
539pub enum CursorHideMode {
540 Never,
542 OnTyping,
544 #[default]
547 OnTypingAndAction,
548}
549
550#[doc(hidden)]
552#[derive(Clone, PartialEq, Eq)]
553pub struct SystemWindowTab {
554 pub id: WindowId,
556 pub title: SharedString,
558 pub handle: AnyWindowHandle,
560 pub last_active_at: Instant,
562}
563
564impl SystemWindowTab {
565 pub fn new(title: SharedString, handle: AnyWindowHandle) -> Self {
567 Self {
568 id: handle.id,
569 title,
570 handle,
571 last_active_at: Instant::now(),
572 }
573 }
574}
575
576#[derive(Default)]
581pub struct SystemWindowTabController {
582 visible: Option<bool>,
583 tab_groups: FxHashMap<usize, Vec<SystemWindowTab>>,
584}
585
586impl Global for SystemWindowTabController {}
587
588impl SystemWindowTabController {
589 pub fn new() -> Self {
591 Self {
592 visible: None,
593 tab_groups: FxHashMap::default(),
594 }
595 }
596
597 pub fn init(cx: &mut App) {
599 cx.set_global(SystemWindowTabController::new());
600 }
601
602 pub fn tab_groups(&self) -> &FxHashMap<usize, Vec<SystemWindowTab>> {
604 &self.tab_groups
605 }
606
607 pub fn get_next_tab_group_window(cx: &mut App, id: WindowId) -> Option<&AnyWindowHandle> {
613 let controller = cx.global::<SystemWindowTabController>();
614 let current_group = controller
615 .tab_groups
616 .iter()
617 .find_map(|(group, tabs)| tabs.iter().find(|tab| tab.id == id).map(|_| group));
618
619 let current_group = current_group?;
620 let mut group_ids: Vec<_> = controller.tab_groups.keys().collect();
622 let idx = group_ids.iter().position(|g| *g == current_group)?;
623 let next_idx = (idx + 1) % group_ids.len();
624
625 controller
626 .tab_groups
627 .get(group_ids[next_idx])
628 .and_then(|tabs| {
629 tabs.iter()
630 .max_by_key(|tab| tab.last_active_at)
631 .or_else(|| tabs.first())
632 .map(|tab| &tab.handle)
633 })
634 }
635
636 pub fn get_prev_tab_group_window(cx: &mut App, id: WindowId) -> Option<&AnyWindowHandle> {
642 let controller = cx.global::<SystemWindowTabController>();
643 let current_group = controller
644 .tab_groups
645 .iter()
646 .find_map(|(group, tabs)| tabs.iter().find(|tab| tab.id == id).map(|_| group));
647
648 let current_group = current_group?;
649 let mut group_ids: Vec<_> = controller.tab_groups.keys().collect();
651 let idx = group_ids.iter().position(|g| *g == current_group)?;
652 let prev_idx = if idx == 0 {
653 group_ids.len() - 1
654 } else {
655 idx - 1
656 };
657
658 controller
659 .tab_groups
660 .get(group_ids[prev_idx])
661 .and_then(|tabs| {
662 tabs.iter()
663 .max_by_key(|tab| tab.last_active_at)
664 .or_else(|| tabs.first())
665 .map(|tab| &tab.handle)
666 })
667 }
668
669 pub fn tabs(&self, id: WindowId) -> Option<&Vec<SystemWindowTab>> {
671 self.tab_groups
672 .values()
673 .find(|tabs| tabs.iter().any(|tab| tab.id == id))
674 }
675
676 pub fn init_visible(cx: &mut App, visible: bool) {
678 let mut controller = cx.global_mut::<SystemWindowTabController>();
679 if controller.visible.is_none() {
680 controller.visible = Some(visible);
681 }
682 }
683
684 pub fn is_visible(&self) -> bool {
686 self.visible.unwrap_or(false)
687 }
688
689 pub fn set_visible(cx: &mut App, visible: bool) {
691 let mut controller = cx.global_mut::<SystemWindowTabController>();
692 controller.visible = Some(visible);
693 }
694
695 pub fn update_last_active(cx: &mut App, id: WindowId) {
697 let mut controller = cx.global_mut::<SystemWindowTabController>();
698 for windows in controller.tab_groups.values_mut() {
699 for tab in windows.iter_mut() {
700 if tab.id == id {
701 tab.last_active_at = Instant::now();
702 }
703 }
704 }
705 }
706
707 pub fn update_tab_position(cx: &mut App, id: WindowId, ix: usize) {
711 let mut controller = cx.global_mut::<SystemWindowTabController>();
712 for (_, windows) in controller.tab_groups.iter_mut() {
713 if let Some(current_pos) = windows.iter().position(|tab| tab.id == id) {
714 if ix < windows.len() && current_pos != ix {
715 let window_tab = windows.remove(current_pos);
716 windows.insert(ix, window_tab);
717 }
718 break;
719 }
720 }
721 }
722
723 pub fn update_tab_title(cx: &mut App, id: WindowId, title: SharedString) {
725 let controller = cx.global::<SystemWindowTabController>();
726 let tab = controller
727 .tab_groups
728 .values()
729 .flat_map(|windows| windows.iter())
730 .find(|tab| tab.id == id);
731
732 if tab.map_or(true, |t| t.title == title) {
733 return;
734 }
735
736 let mut controller = cx.global_mut::<SystemWindowTabController>();
737 for windows in controller.tab_groups.values_mut() {
738 for tab in windows.iter_mut() {
739 if tab.id == id {
740 tab.title = title;
741 return;
742 }
743 }
744 }
745 }
746
747 pub fn add_tab(cx: &mut App, id: WindowId, tabs: Vec<SystemWindowTab>) {
752 let mut controller = cx.global_mut::<SystemWindowTabController>();
753 let Some(tab) = tabs.iter().find(|tab| tab.id == id).cloned() else {
754 return;
755 };
756
757 let mut expected_tab_ids: Vec<_> = tabs
758 .iter()
759 .filter(|tab| tab.id != id)
760 .map(|tab| tab.id)
761 .sorted()
762 .collect();
763
764 let mut tab_group_id = None;
765 for (group_id, group_tabs) in &controller.tab_groups {
766 let tab_ids: Vec<_> = group_tabs.iter().map(|tab| tab.id).sorted().collect();
767 if tab_ids == expected_tab_ids {
768 tab_group_id = Some(*group_id);
769 break;
770 }
771 }
772
773 if let Some(tab_group_id) = tab_group_id {
774 if let Some(tabs) = controller.tab_groups.get_mut(&tab_group_id) {
775 tabs.push(tab);
776 }
777 } else {
778 let new_group_id = controller.tab_groups.keys().max().map_or(0, |id| id + 1);
779 controller.tab_groups.insert(new_group_id, tabs);
780 }
781 }
782
783 pub fn remove_tab(cx: &mut App, id: WindowId) -> Option<SystemWindowTab> {
787 let mut controller = cx.global_mut::<SystemWindowTabController>();
788 let mut removed_tab = None;
789
790 controller.tab_groups.retain(|_, tabs| {
791 if let Some(pos) = tabs.iter().position(|tab| tab.id == id) {
792 removed_tab = Some(tabs.remove(pos));
793 }
794 !tabs.is_empty()
795 });
796
797 removed_tab
798 }
799
800 pub fn move_tab_to_new_window(cx: &mut App, id: WindowId) {
802 let mut removed_tab = Self::remove_tab(cx, id);
803 let mut controller = cx.global_mut::<SystemWindowTabController>();
804
805 if let Some(tab) = removed_tab {
806 let new_group_id = controller.tab_groups.keys().max().map_or(0, |k| k + 1);
807 controller.tab_groups.insert(new_group_id, vec![tab]);
808 }
809 }
810
811 pub fn merge_all_windows(cx: &mut App, id: WindowId) {
813 let mut controller = cx.global_mut::<SystemWindowTabController>();
814 let Some(initial_tabs) = controller.tabs(id) else {
815 return;
816 };
817
818 let initial_tabs_len = initial_tabs.len();
819 let mut all_tabs = initial_tabs.clone();
820
821 for (_, mut tabs) in controller.tab_groups.drain() {
822 tabs.retain(|tab| !all_tabs[..initial_tabs_len].contains(tab));
823 all_tabs.extend(tabs);
824 }
825
826 controller.tab_groups.insert(0, all_tabs);
827 }
828
829 pub fn select_next_tab(cx: &mut App, id: WindowId) {
831 let mut controller = cx.global_mut::<SystemWindowTabController>();
832 let Some(tabs) = controller.tabs(id) else {
833 return;
834 };
835
836 let current_index = tabs.iter().position(|tab| tab.id == id).unwrap();
837 let next_index = (current_index + 1) % tabs.len();
838
839 let _ = &tabs[next_index].handle.update(cx, |_, window, _| {
840 window.activate();
841 });
842 }
843
844 pub fn select_previous_tab(cx: &mut App, id: WindowId) {
846 let mut controller = cx.global_mut::<SystemWindowTabController>();
847 let Some(tabs) = controller.tabs(id) else {
848 return;
849 };
850
851 let current_index = tabs.iter().position(|tab| tab.id == id).unwrap();
852 let previous_index = if current_index == 0 {
853 tabs.len() - 1
854 } else {
855 current_index - 1
856 };
857
858 let _ = &tabs[previous_index].handle.update(cx, |_, window, _| {
859 window.activate();
860 });
861 }
862}
863
864pub(crate) enum GpuiMode {
865 #[cfg(any(test, feature = "test-support"))]
866 Test {
867 skip_drawing: bool,
868 },
869 Production,
870}
871
872impl GpuiMode {
873 #[cfg(any(test, feature = "test-support"))]
874 pub fn test() -> Self {
875 GpuiMode::Test {
876 skip_drawing: false,
877 }
878 }
879
880 #[inline]
881 pub(crate) fn skip_drawing(&self) -> bool {
882 match self {
883 #[cfg(any(test, feature = "test-support"))]
884 GpuiMode::Test { skip_drawing } => *skip_drawing,
885 GpuiMode::Production => false,
886 }
887 }
888}
889
890struct PlatformOwnedDrag {
891 source_window: WindowId,
892 state: PlatformOwnedDragState,
893}
894
895enum PlatformOwnedDragState {
896 Suspended(AnyDrag),
897 RestoredInSourceWindow,
900}
901
902#[derive(Default)]
905pub(crate) struct Dependencies {
906 entities: Vec<EntityId>,
907 globals: Vec<(TypeId, u64)>,
908 revisions: Vec<(Revision, u64)>,
909}
910
911impl Dependencies {
912 pub(crate) fn extend(&mut self, other: Dependencies) {
913 self.entities.extend(other.entities);
914 self.entities.sort_unstable();
915 self.entities.dedup();
916 self.globals.extend(other.globals);
917 self.globals.sort_unstable();
918 self.globals.dedup_by_key(|(global_type, _)| *global_type);
919 for (revision, seen) in other.revisions {
921 match self
922 .revisions
923 .iter_mut()
924 .find(|(known, _)| known.same(&revision))
925 {
926 Some(entry) => entry.1 = seen,
927 None => self.revisions.push((revision, seen)),
928 }
929 }
930 }
931}
932
933#[derive(Clone, Debug, Default)]
936pub(crate) struct Revision(Rc<Cell<u64>>);
937
938impl Revision {
939 pub(crate) fn bump(&self) {
940 self.0.set(self.0.get().wrapping_add(1));
941 }
942
943 fn same(&self, other: &Self) -> bool {
944 Rc::ptr_eq(&self.0, &other.0)
945 }
946}
947
948pub struct App {
970 pub(crate) this: Weak<AppCell>,
971 pub(crate) platform: Rc<dyn Platform>,
972 text_system: Arc<TextSystem>,
973
974 pub(crate) actions: Rc<ActionRegistry>,
975 pub(crate) active_drag: Option<AnyDrag>,
976 platform_owned_drag: Option<PlatformOwnedDrag>,
977 pub(crate) background_executor: BackgroundExecutor,
978 pub(crate) foreground_executor: ForegroundExecutor,
979 #[cfg(feature = "profiler")]
980 foreground_journal: crate::profiler::journal::ForegroundJournal,
981 #[cfg(all(feature = "profiler", not(target_family = "wasm")))]
982 hang_monitor: Option<crate::profiler::hang::HangMonitor>,
983 pub(crate) entities: EntityMap,
984 pub(crate) new_entity_observers: SubscriberSet<TypeId, NewEntityListener>,
985 pub(crate) windows: SlotMap<WindowId, Option<Box<Window>>>,
986 pub(crate) window_handles: FxHashMap<WindowId, AnyWindowHandle>,
987 pub(crate) focus_handles: Arc<RwLock<FocusMap>>,
988 pub(crate) keymap: Rc<RefCell<Keymap>>,
989 pub(crate) keyboard_layout: Box<dyn PlatformKeyboardLayout>,
990 pub(crate) keyboard_mapper: Rc<dyn PlatformKeyboardMapper>,
991 pub(crate) global_action_listeners:
992 TypeIdHashMap<Vec<Rc<dyn Fn(&dyn Any, DispatchPhase, &mut Self)>>>,
993 pending_effects: VecDeque<Effect>,
994
995 pub(crate) observers: SubscriberSet<EntityId, Handler>,
996 pub(crate) event_listeners: SubscriberSet<EntityId, (TypeId, Listener)>,
997 pub(crate) keystroke_observers: SubscriberSet<(), KeystrokeObserver>,
998 pub(crate) keystroke_interceptors: SubscriberSet<(), KeystrokeObserver>,
999 pub(crate) keyboard_layout_observers: SubscriberSet<(), Handler>,
1000 pub(crate) thermal_state_observers: SubscriberSet<(), Handler>,
1001 pub(crate) display_observers: SubscriberSet<(), DisplayHandler>,
1002 displays: HashMap<DisplayId, DisplayState>,
1005 pub(crate) system_sleep_observers: SubscriberSet<(), Handler>,
1006 pub(crate) system_wake_observers: SubscriberSet<(), Handler>,
1007 app_lifecycle_observers: SubscriberSet<(), AppLifecycleHandler>,
1008 memory_warning_observers: SubscriberSet<(), Handler>,
1009 pub(crate) release_listeners: SubscriberSet<EntityId, ReleaseListener>,
1010 pub(crate) global_observers: SubscriberSet<TypeId, Handler>,
1011 pub(crate) quit_observers: SubscriberSet<(), QuitHandler>,
1012 pub(crate) restart_observers: SubscriberSet<(), Handler>,
1013 pub(crate) window_closed_observers: SubscriberSet<(), WindowClosedHandler>,
1014
1015 pub(crate) element_arena: RefCell<Arena>,
1018 pub(crate) event_arena: Arena,
1020
1021 pub(crate) globals_by_type: TypeIdHashMap<Box<dyn Any>>,
1026 global_revisions: TypeIdHashMap<u64>,
1027 global_reads: RefCell<Vec<TypeId>>,
1028 revision_reads: RefCell<Vec<Revision>>,
1029 global_entities: Vec<AnyEntity>,
1033
1034 pub(crate) loading_assets: FxHashMap<(TypeId, u64), Box<dyn Any>>,
1036 asset_registry: Arc<AssetRegistry>,
1037 pub(crate) svg_renderer: SvgRenderer,
1038 http_client: Arc<dyn HttpClient>,
1039
1040 pub(crate) pending_notifications: FxHashSet<EntityId>,
1042 pub(crate) pending_global_notifications: TypeIdHashSet,
1043 pub(crate) restart_path: Option<PathBuf>,
1044 pub(crate) restart_arguments: Vec<OsString>,
1045 pub(crate) layout_id_buffer: Vec<LayoutId>, pub(crate) propagate_event: bool,
1047 pub(crate) prompt_builder: Option<PromptBuilder>,
1048 pub(crate) window_invalidators_by_entity:
1049 FxHashMap<EntityId, FxHashMap<WindowId, WindowInvalidator>>,
1050 pub(crate) tracked_entities: FxHashMap<WindowId, FxHashSet<EntityId>>,
1051 pub(crate) current_window_by_entity: FxHashMap<EntityId, WindowId>,
1052 #[cfg(any(feature = "inspector", debug_assertions))]
1053 pub(crate) inspector_renderer: Option<crate::InspectorRenderer>,
1054 #[cfg(any(feature = "inspector", debug_assertions))]
1055 pub(crate) inspector_element_registry: InspectorElementRegistry,
1056 #[cfg(any(test, feature = "test-support", debug_assertions))]
1057 pub(crate) name: Option<&'static str>,
1058 pub(crate) text_rendering_mode: Rc<Cell<TextRenderingMode>>,
1059
1060 pub(crate) window_update_stack: Vec<WindowId>,
1061 pub(crate) mode: GpuiMode,
1062 pub(crate) cursor_hide_mode: CursorHideMode,
1063 pub(crate) reduce_motion: bool,
1064 pub(crate) synced_animation_epoch: Instant,
1066 pub(crate) accessibility_force_disabled: bool,
1069 pub(crate) accessibility_forced: bool,
1072 pending_updates: usize,
1073 quit_mode: QuitMode,
1074 quitting: bool,
1075
1076 #[cfg(any(test, gpui_leak_detection))]
1079 _ref_counts: Arc<RwLock<EntityRefCounts>>,
1080}
1081
1082impl App {
1083 #[allow(clippy::new_ret_no_self)]
1084 pub(crate) fn new_app(
1085 platform: Rc<dyn Platform>,
1086 asset_registry: Arc<AssetRegistry>,
1087 http_client: Arc<dyn HttpClient>,
1088 ) -> Rc<AppCell> {
1089 let background_executor = platform.background_executor();
1090 let foreground_executor = platform.foreground_executor();
1091 assert!(
1092 background_executor.is_main_thread(),
1093 "must construct App on main thread"
1094 );
1095 #[cfg(feature = "profiler")]
1096 let foreground_journal = crate::profiler::journal::install_foreground_journal();
1097 let synced_animation_epoch = background_executor.now();
1098
1099 let text_system = Arc::new(TextSystem::new(platform.text_system()));
1100 let entities = EntityMap::new();
1101 let keyboard_layout = platform.keyboard_layout();
1102 let keyboard_mapper = platform.keyboard_mapper();
1103
1104 #[cfg(any(test, gpui_leak_detection))]
1105 let _ref_counts = entities.ref_counts_drop_handle();
1106
1107 let app = Rc::new_cyclic(|this| AppCell {
1108 app: RefCell::new(App {
1109 this: this.clone(),
1110 platform: platform.clone(),
1111 text_system,
1112 text_rendering_mode: Rc::new(Cell::new(TextRenderingMode::default())),
1113 mode: GpuiMode::Production,
1114 actions: Rc::new(ActionRegistry::default()),
1115 pending_updates: 0,
1116 active_drag: None,
1117 platform_owned_drag: None,
1118 background_executor,
1119 foreground_executor,
1120 #[cfg(feature = "profiler")]
1121 foreground_journal,
1122 #[cfg(all(feature = "profiler", not(target_family = "wasm")))]
1123 hang_monitor: None,
1124 svg_renderer: SvgRenderer::new(asset_registry.clone()),
1125 loading_assets: Default::default(),
1126 asset_registry,
1127 http_client,
1128 globals_by_type: Default::default(),
1129 global_revisions: Default::default(),
1130 global_reads: Default::default(),
1131 revision_reads: Default::default(),
1132 global_entities: Default::default(),
1133 entities,
1134 new_entity_observers: SubscriberSet::new(),
1135 windows: SlotMap::with_key(),
1136 window_update_stack: Vec::new(),
1137 window_handles: FxHashMap::default(),
1138 focus_handles: Arc::new(RwLock::new(FocusMap::default())),
1139 keymap: Rc::new(RefCell::new(Keymap::default())),
1140 keyboard_layout,
1141 keyboard_mapper,
1142 global_action_listeners: Default::default(),
1143 pending_effects: VecDeque::new(),
1144 pending_notifications: FxHashSet::default(),
1145 pending_global_notifications: Default::default(),
1146 observers: SubscriberSet::new(),
1147 tracked_entities: FxHashMap::default(),
1148 window_invalidators_by_entity: FxHashMap::default(),
1149 current_window_by_entity: FxHashMap::default(),
1150 event_listeners: SubscriberSet::new(),
1151 release_listeners: SubscriberSet::new(),
1152 keystroke_observers: SubscriberSet::new(),
1153 keystroke_interceptors: SubscriberSet::new(),
1154 keyboard_layout_observers: SubscriberSet::new(),
1155 thermal_state_observers: SubscriberSet::new(),
1156 display_observers: SubscriberSet::new(),
1157 displays: read_displays(platform.as_ref()),
1158 system_sleep_observers: SubscriberSet::new(),
1159 system_wake_observers: SubscriberSet::new(),
1160 app_lifecycle_observers: SubscriberSet::new(),
1161 memory_warning_observers: SubscriberSet::new(),
1162 global_observers: SubscriberSet::new(),
1163 quit_observers: SubscriberSet::new(),
1164 restart_observers: SubscriberSet::new(),
1165 restart_path: None,
1166 restart_arguments: Vec::new(),
1167 window_closed_observers: SubscriberSet::new(),
1168 layout_id_buffer: Default::default(),
1169 propagate_event: true,
1170 prompt_builder: Some(PromptBuilder::Default),
1171 #[cfg(any(feature = "inspector", debug_assertions))]
1172 inspector_renderer: None,
1173 #[cfg(any(feature = "inspector", debug_assertions))]
1174 inspector_element_registry: InspectorElementRegistry::default(),
1175 quit_mode: QuitMode::default(),
1176 quitting: false,
1177 cursor_hide_mode: CursorHideMode::default(),
1178 reduce_motion: false,
1179 synced_animation_epoch,
1180 accessibility_force_disabled: false,
1181 accessibility_forced: false,
1182
1183 #[cfg(any(test, feature = "test-support", debug_assertions))]
1184 name: None,
1185 element_arena: RefCell::new(Arena::new(1024 * 1024)),
1186 event_arena: Arena::new(1024 * 1024),
1187
1188 #[cfg(any(test, gpui_leak_detection))]
1189 _ref_counts,
1190 }),
1191 });
1192
1193 init_app_menus(platform.as_ref(), &app.borrow());
1194 SystemWindowTabController::init(&mut app.borrow_mut());
1195 #[cfg(feature = "profiler")]
1196 crate::profiler::journal::observe_power(&app.borrow());
1197
1198 platform.on_keyboard_layout_change(Box::new({
1199 let app = Rc::downgrade(&app);
1200 move || {
1201 if let Some(app) = app.upgrade() {
1202 let cx = &mut app.borrow_mut();
1203 cx.keyboard_layout = cx.platform.keyboard_layout();
1204 cx.keyboard_mapper = cx.platform.keyboard_mapper();
1205 cx.keyboard_layout_observers
1206 .clone()
1207 .retain(&(), move |callback| (callback)(cx));
1208 }
1209 }
1210 }));
1211
1212 platform.on_thermal_state_change(Box::new({
1213 let app = Rc::downgrade(&app);
1214 move || {
1215 if let Some(app) = app.upgrade() {
1216 let cx = &mut app.borrow_mut();
1217 cx.thermal_state_observers
1218 .clone()
1219 .retain(&(), move |callback| (callback)(cx));
1220 }
1221 }
1222 }));
1223
1224 platform.on_displays_changed(Box::new({
1225 let app = Rc::downgrade(&app);
1226 move || {
1227 if let Some(app) = app.upgrade() {
1228 app.borrow_mut().displays_changed();
1229 }
1230 }
1231 }));
1232
1233 platform.on_system_sleep(Box::new({
1234 let app = Rc::downgrade(&app);
1235 move || {
1236 if let Some(app) = app.upgrade() {
1237 let cx = &mut app.borrow_mut();
1238 cx.system_sleep_observers
1239 .clone()
1240 .retain(&(), move |callback| (callback)(cx));
1241 }
1242 }
1243 }));
1244
1245 platform.on_system_wake(Box::new({
1246 let app = Rc::downgrade(&app);
1247 move || {
1248 if let Some(app) = app.upgrade() {
1249 let cx = &mut app.borrow_mut();
1250 cx.system_wake_observers
1251 .clone()
1252 .retain(&(), move |callback| (callback)(cx));
1253 }
1254 }
1255 }));
1256
1257 platform.on_app_lifecycle(Box::new({
1258 let app = Rc::downgrade(&app);
1259 move |phase| {
1260 if let Some(app) = app.upgrade() {
1261 app.borrow_mut().update(|cx| {
1262 cx.app_lifecycle_observers
1263 .clone()
1264 .retain(&(), |callback| callback(phase, cx));
1265 });
1266 }
1267 }
1268 }));
1269
1270 platform.on_memory_warning(Box::new({
1271 let app = Rc::downgrade(&app);
1272 move || {
1273 if let Some(app) = app.upgrade() {
1274 app.borrow_mut().update(|cx| {
1275 cx.memory_warning_observers
1276 .clone()
1277 .retain(&(), |callback| callback(cx));
1278 });
1279 }
1280 }
1281 }));
1282
1283 platform.on_quit(Box::new({
1284 let cx = Rc::downgrade(&app);
1285 move || {
1286 let Some(cx) = cx.upgrade() else {
1287 return true;
1288 };
1289 match cx.try_borrow_mut() {
1290 Ok(mut cx) => {
1291 cx.shutdown();
1292 true
1293 }
1294 Err(_) => {
1295 false
1298 }
1299 }
1300 }
1301 }));
1302
1303 app
1304 }
1305
1306 #[doc(hidden)]
1307 pub fn ref_counts_drop_handle(&self) -> impl Sized + use<> {
1308 self.entities.ref_counts_drop_handle()
1309 }
1310
1311 #[cfg(any(test, gpui_leak_detection))]
1317 pub fn leak_detector_snapshot(&self) -> LeakDetectorSnapshot {
1318 self.entities.leak_detector_snapshot()
1319 }
1320
1321 #[cfg(any(test, gpui_leak_detection))]
1333 pub fn assert_no_new_leaks(&self, snapshot: &LeakDetectorSnapshot) {
1334 self.entities.assert_no_new_leaks(snapshot)
1335 }
1336
1337 #[cfg(all(feature = "test-support", not(any(test, gpui_leak_detection))))]
1339 pub fn leak_detector_snapshot(&self) -> LeakDetectorSnapshot {
1340 LeakDetectorSnapshot::default()
1341 }
1342
1343 #[cfg(all(feature = "test-support", not(any(test, gpui_leak_detection))))]
1346 pub fn assert_no_new_leaks(&self, _snapshot: &LeakDetectorSnapshot) {}
1347
1348 pub fn shutdown(&mut self) {
1357 #[cfg(all(feature = "profiler", not(target_family = "wasm")))]
1360 let hang_monitor_flush = self
1361 .hang_monitor
1362 .as_ref()
1363 .and_then(|hang_monitor| hang_monitor.request_flush());
1364
1365 let mut futures: Vec<LocalBoxFuture<'static, ()>> = Vec::new();
1366
1367 for observer in self.quit_observers.remove(&()) {
1368 futures.push(observer(self));
1369 }
1370
1371 #[cfg(all(feature = "profiler", not(target_family = "wasm")))]
1372 if let Some(flushed) = hang_monitor_flush {
1373 futures.push(
1374 async move {
1375 if flushed.await.is_err() {
1376 log::warn!("hang monitor exited before flushing");
1377 }
1378 }
1379 .boxed_local(),
1380 );
1381 }
1382
1383 self.windows.clear();
1384 self.window_handles.clear();
1385 self.flush_effects();
1386 self.quitting = true;
1387
1388 let futures = futures::future::join_all(futures);
1389 #[cfg(not(target_family = "wasm"))]
1390 if self
1391 .foreground_executor
1392 .block_with_timeout(SHUTDOWN_TIMEOUT, futures)
1393 .is_err()
1394 {
1395 log::error!("timed out waiting on app_will_quit");
1396 }
1397 #[cfg(target_family = "wasm")]
1398 self.foreground_executor.spawn(futures).detach();
1399
1400 self.quitting = false;
1401 }
1402
1403 pub fn keyboard_layout(&self) -> &dyn PlatformKeyboardLayout {
1409 self.keyboard_layout.as_ref()
1410 }
1411
1412 pub fn keyboard_mapper(&self) -> &Rc<dyn PlatformKeyboardMapper> {
1414 &self.keyboard_mapper
1415 }
1416
1417 pub fn on_keyboard_layout_change<F>(&self, mut callback: F) -> Subscription
1423 where
1424 F: 'static + FnMut(&mut App),
1425 {
1426 let (subscription, activate) = self.keyboard_layout_observers.insert(
1427 (),
1428 Box::new(move |cx| {
1429 callback(cx);
1430 true
1431 }),
1432 );
1433 activate();
1434 subscription
1435 }
1436
1437 pub fn quit(&self) {
1444 self.platform.quit();
1445 }
1446
1447 pub fn request_windowing(&self, request: WindowingRequest) -> Task<anyhow::Result<()>> {
1461 if !self.windows.is_empty() {
1462 return Task::ready(Err(anyhow::anyhow!(
1463 "cannot switch windowing modes while windows are open"
1464 )));
1465 }
1466 self.platform.request_windowing(request)
1467 }
1468
1469 pub fn graphical_environment(&self) -> Option<crate::GraphicalEnvironment> {
1479 self.platform.graphical_environment()
1480 }
1481
1482 pub fn cursor_hide_mode(&self) -> CursorHideMode {
1486 self.cursor_hide_mode
1487 }
1488
1489 pub fn set_cursor_hide_mode(&mut self, mode: CursorHideMode) {
1493 self.cursor_hide_mode = mode;
1494 }
1495
1496 pub fn is_cursor_visible(&self) -> bool {
1502 self.platform.is_cursor_visible()
1503 }
1504
1505 pub fn reduce_motion(&self) -> bool {
1510 self.reduce_motion
1511 }
1512
1513 pub fn set_reduce_motion(&mut self, reduce_motion: bool) {
1518 if self.reduce_motion != reduce_motion {
1519 self.reduce_motion = reduce_motion;
1520 self.refresh_windows();
1521 }
1522 }
1523
1524 pub fn refresh_windows(&mut self) {
1530 self.pending_effects.push_back(Effect::RefreshWindows);
1531 }
1532
1533 #[inline(always)]
1534 pub(crate) fn update<R>(&mut self, update: impl FnOnce(&mut Self) -> R) -> R {
1535 self.start_update();
1536 let result = update(self);
1537 self.finish_update();
1538 result
1539 }
1540
1541 pub(crate) fn start_update(&mut self) {
1542 self.pending_updates += 1;
1543 }
1544
1545 #[inline(never)]
1546 pub(crate) fn finish_update(&mut self) {
1547 if self.pending_updates == 1 {
1548 self.flush_effects();
1549 }
1550 self.pending_updates -= 1;
1551 }
1552
1553 pub fn observe<W>(
1584 &mut self,
1585 entity: &Entity<W>,
1586 mut on_notify: impl FnMut(Entity<W>, &mut App) + 'static,
1587 ) -> Subscription
1588 where
1589 W: 'static,
1590 {
1591 self.observe_internal(entity, move |e, cx| {
1592 on_notify(e, cx);
1593 true
1594 })
1595 }
1596
1597 pub(crate) fn record_dependencies<R>(
1600 &mut self,
1601 callback: impl FnOnce(&mut App) -> R,
1602 ) -> (R, Dependencies) {
1603 let entities_start = self.entities.access_log.get_mut().len();
1604 let globals_start = self.global_reads.get_mut().len();
1605 let revisions_start = self.revision_reads.get_mut().len();
1606 *self.entities.recordings.get_mut() += 1;
1607 let result = callback(self);
1608 let recordings = self.entities.recordings.get_mut();
1609 *recordings -= 1;
1610 let outermost = *recordings == 0;
1611
1612 let log = self.entities.access_log.get_mut();
1613 let mut entities = log[entities_start..].to_vec();
1614 entities.sort_unstable();
1615 entities.dedup();
1616 let reads = self.global_reads.get_mut();
1617 let mut globals: Vec<(TypeId, u64)> = reads[globals_start..]
1618 .iter()
1619 .map(|global_type| (*global_type, 0))
1620 .collect();
1621 let revision_reads = self.revision_reads.get_mut();
1622 let mut revisions: Vec<(Revision, u64)> = Vec::new();
1623 for revision in revision_reads.drain(revisions_start..) {
1624 if !revisions.iter().any(|(known, _)| known.same(&revision)) {
1625 let seen = revision.0.get();
1626 revisions.push((revision, seen));
1627 }
1628 }
1629 if !outermost {
1630 revision_reads.extend(revisions.iter().map(|(revision, _)| revision.clone()));
1632 }
1633 if outermost {
1634 log.clear();
1635 reads.clear();
1636 }
1637 globals.sort_unstable();
1638 globals.dedup();
1639 for (global_type, revision) in &mut globals {
1640 *revision = self.global_revision(*global_type);
1641 }
1642 (
1643 result,
1644 Dependencies {
1645 entities,
1646 globals,
1647 revisions,
1648 },
1649 )
1650 }
1651
1652 pub(crate) fn replay_dependencies(&mut self, dependencies: &Dependencies) {
1654 for entity_id in &dependencies.entities {
1655 self.entities.note_access(*entity_id);
1656 }
1657 for (global_type, _) in &dependencies.globals {
1658 self.note_global_read(*global_type);
1659 }
1660 for (revision, _) in &dependencies.revisions {
1661 self.note_revision(revision);
1662 }
1663 }
1664
1665 pub(crate) fn note_revision(&self, revision: &Revision) {
1667 if self.entities.recordings.get() > 0 {
1668 self.revision_reads.borrow_mut().push(revision.clone());
1669 }
1670 }
1671
1672 pub(crate) fn dependencies_changed(
1675 &self,
1676 dependencies: &Dependencies,
1677 dirty: &FxHashSet<EntityId>,
1678 ) -> bool {
1679 dependencies.entities.iter().any(|id| dirty.contains(id))
1680 || dependencies
1681 .globals
1682 .iter()
1683 .any(|(global_type, revision)| self.global_revision(*global_type) != *revision)
1684 || dependencies
1685 .revisions
1686 .iter()
1687 .any(|(revision, seen)| revision.0.get() != *seen)
1688 }
1689
1690 fn note_global_read(&self, global_type: TypeId) {
1691 if self.entities.recordings.get() > 0 {
1692 self.global_reads.borrow_mut().push(global_type);
1693 }
1694 }
1695
1696 fn global_revision(&self, global_type: TypeId) -> u64 {
1697 self.global_revisions
1698 .get(&global_type)
1699 .copied()
1700 .unwrap_or(0)
1701 }
1702
1703 fn global_changed(&mut self, global_type: TypeId) {
1704 *self.global_revisions.entry(global_type).or_default() += 1;
1705 self.push_effect(Effect::NotifyGlobalObservers { global_type });
1706 }
1707
1708 pub(crate) fn record_entities_accessed(
1709 &mut self,
1710 window_handle: AnyWindowHandle,
1711 invalidator: WindowInvalidator,
1712 entities: &FxHashSet<EntityId>,
1713 ) {
1714 let mut tracked_entities =
1715 std::mem::take(self.tracked_entities.entry(window_handle.id).or_default());
1716 for entity in tracked_entities.iter() {
1717 self.window_invalidators_by_entity
1718 .entry(*entity)
1719 .and_modify(|windows| {
1720 windows.remove(&window_handle.id);
1721 });
1722 }
1723 for entity in entities.iter() {
1724 self.window_invalidators_by_entity
1725 .entry(*entity)
1726 .or_default()
1727 .insert(window_handle.id, invalidator.clone());
1728 self.current_window_by_entity
1729 .insert(*entity, window_handle.id);
1730 }
1731 tracked_entities.clear();
1732 tracked_entities.extend(entities.iter().copied());
1733 self.tracked_entities
1734 .insert(window_handle.id, tracked_entities);
1735 }
1736
1737 pub(crate) fn new_observer(&mut self, key: EntityId, value: Handler) -> Subscription {
1738 let (subscription, activate) = self.observers.insert(key, value);
1739 self.defer(move |_| activate());
1740 subscription
1741 }
1742
1743 pub(crate) fn observe_internal<W>(
1744 &mut self,
1745 entity: &Entity<W>,
1746 mut on_notify: impl FnMut(Entity<W>, &mut App) -> bool + 'static,
1747 ) -> Subscription
1748 where
1749 W: 'static,
1750 {
1751 let entity_id = entity.entity_id();
1752 let handle = entity.downgrade();
1753 self.new_observer(
1754 entity_id,
1755 Box::new(move |cx| {
1756 if let Some(entity) = handle.upgrade() {
1757 on_notify(entity, cx)
1758 } else {
1759 false
1760 }
1761 }),
1762 )
1763 }
1764
1765 pub fn subscribe<T, Event>(
1795 &mut self,
1796 entity: &Entity<T>,
1797 mut on_event: impl FnMut(Entity<T>, &Event, &mut App) + 'static,
1798 ) -> Subscription
1799 where
1800 T: 'static + EventEmitter<Event>,
1801 Event: 'static,
1802 {
1803 self.subscribe_internal(entity, move |entity, event, cx| {
1804 on_event(entity, event, cx);
1805 true
1806 })
1807 }
1808
1809 pub(crate) fn new_subscription(
1810 &mut self,
1811 key: EntityId,
1812 value: (TypeId, Listener),
1813 ) -> Subscription {
1814 let (subscription, activate) = self.event_listeners.insert(key, value);
1815 self.defer(move |_| activate());
1816 subscription
1817 }
1818 pub(crate) fn subscribe_internal<T, Evt>(
1819 &mut self,
1820 entity: &Entity<T>,
1821 mut on_event: impl FnMut(Entity<T>, &Evt, &mut App) -> bool + 'static,
1822 ) -> Subscription
1823 where
1824 T: 'static + EventEmitter<Evt>,
1825 Evt: 'static,
1826 {
1827 let entity_id = entity.entity_id();
1828 let handle = entity.downgrade();
1829 self.new_subscription(
1830 entity_id,
1831 (
1832 TypeId::of::<Evt>(),
1833 Box::new(move |event, cx| {
1834 let event: &Evt = event.downcast_ref().expect("invalid event type");
1835 if let Some(entity) = handle.upgrade() {
1836 on_event(entity, event, cx)
1837 } else {
1838 false
1839 }
1840 }),
1841 ),
1842 )
1843 }
1844
1845 pub fn windows(&self) -> Vec<AnyWindowHandle> {
1851 self.windows
1852 .keys()
1853 .flat_map(|window_id| self.window_handles.get(&window_id).copied())
1854 .collect()
1855 }
1856
1857 pub fn window_stack(&self) -> Option<Vec<AnyWindowHandle>> {
1863 self.platform.window_stack()
1864 }
1865
1866 pub fn set_gpu_requirements(&self, requirements: Box<dyn std::any::Any>) {
1872 self.platform.set_gpu_requirements(requirements);
1873 }
1874
1875 pub fn set_keyring_label(&self, label: impl Into<SharedString>) {
1878 self.platform.set_keyring_label(label.into());
1879 }
1880
1881 pub fn active_window(&self) -> Option<AnyWindowHandle> {
1886 self.platform.active_window()
1887 }
1888
1889 pub fn open_window<V: 'static + Render>(
1923 &mut self,
1924 options: crate::WindowOptions,
1925 build_root_view: impl FnOnce(&mut Window, &mut App) -> Entity<V>,
1926 ) -> anyhow::Result<WindowHandle<V>> {
1927 self.update(|cx| {
1928 let id = cx.windows.insert(None);
1929 let handle = WindowHandle::new(id);
1930 match Window::new(handle.into(), options, cx) {
1931 Ok(mut window) => {
1932 cx.window_update_stack.push(id);
1933 let root_view = build_root_view(&mut window, cx);
1934 cx.window_update_stack.pop();
1935 window.root.replace(root_view.into());
1936 window.defer(cx, |window: &mut Window, cx| window.appearance_changed(cx));
1937
1938 let clear = window.draw(cx);
1943 clear.clear(cx);
1944
1945 cx.window_handles.insert(id, window.handle);
1946 cx.windows.get_mut(id).unwrap().replace(Box::new(window));
1947 Ok(handle)
1948 }
1949 Err(e) => {
1950 cx.windows.remove(id);
1951 Err(e)
1952 }
1953 }
1954 })
1955 }
1956
1957 pub fn activate(&self, ignoring_other_apps: bool) {
1962 self.platform.activate(ignoring_other_apps);
1963 }
1964
1965 pub fn hide(&self) {
1967 self.platform.hide();
1968 }
1969
1970 pub fn hide_other_apps(&self) {
1972 self.platform.hide_other_apps();
1973 }
1974
1975 pub fn unhide_other_apps(&self) {
1977 self.platform.unhide_other_apps();
1978 }
1979
1980 pub fn displays(&self) -> Vec<Rc<dyn PlatformDisplay>> {
1982 self.platform.displays()
1983 }
1984
1985 pub fn primary_display(&self) -> Option<Rc<dyn PlatformDisplay>> {
1987 self.platform.primary_display()
1988 }
1989
1990 pub fn is_screen_capture_supported(&self) -> bool {
1992 self.platform.is_screen_capture_supported()
1993 }
1994
1995 pub fn screen_capture_sources(
2001 &self,
2002 ) -> oneshot::Receiver<Result<Vec<Rc<dyn ScreenCaptureSource>>>> {
2003 self.platform.screen_capture_sources()
2004 }
2005
2006 pub fn find_display(&self, id: DisplayId) -> Option<Rc<dyn PlatformDisplay>> {
2008 self.displays()
2009 .iter()
2010 .find(|display| display.id() == id)
2011 .cloned()
2012 }
2013
2014 pub fn thermal_state(&self) -> ThermalState {
2019 self.platform.thermal_state()
2020 }
2021
2022 pub fn prevent_idle_sleep(&self, reason: &str) -> Task<Result<ActivityGuard>> {
2024 self.platform.prevent_idle_sleep(reason)
2025 }
2026
2027 pub fn on_thermal_state_change<F>(&self, mut callback: F) -> Subscription
2031 where
2032 F: 'static + FnMut(&mut App),
2033 {
2034 let (subscription, activate) = self.thermal_state_observers.insert(
2035 (),
2036 Box::new(move |cx| {
2037 callback(cx);
2038 true
2039 }),
2040 );
2041 activate();
2042 subscription
2043 }
2044
2045 pub fn on_system_sleep<F>(&self, mut callback: F) -> Subscription
2050 where
2051 F: 'static + FnMut(&mut App),
2052 {
2053 let (subscription, activate) = self.system_sleep_observers.insert(
2054 (),
2055 Box::new(move |cx| {
2056 callback(cx);
2057 true
2058 }),
2059 );
2060 activate();
2061 subscription
2062 }
2063
2064 pub(crate) fn displays_changed(&mut self) {
2065 let current = read_displays(self.platform.as_ref());
2066 let events = display_events(&self.displays, ¤t);
2067 self.displays = current;
2068 for event in &events {
2069 let DisplayEvent::Changed { id, .. } = *event else {
2070 continue;
2071 };
2072 for handle in self.windows() {
2073 self.update_window(handle, |_, window, cx| {
2074 if window.display_id == Some(id) {
2075 window.notify_display_observers(cx);
2076 }
2077 })
2078 .log_err();
2079 }
2080 }
2081 for event in events {
2082 self.display_observers
2083 .clone()
2084 .retain(&(), |callback| (callback)(event, self));
2085 }
2086 }
2087
2088 pub(crate) fn knows_display(&self, id: DisplayId) -> bool {
2089 self.displays.contains_key(&id)
2090 }
2091
2092 pub(crate) fn display_refresh_interval(&self, id: DisplayId) -> Option<Duration> {
2095 self.displays.get(&id)?.refresh_interval
2096 }
2097
2098 pub fn observe_displays<F>(&self, mut callback: F) -> Subscription
2101 where
2102 F: 'static + FnMut(DisplayEvent, &mut App),
2103 {
2104 let (subscription, activate) = self.display_observers.insert(
2105 (),
2106 Box::new(move |event, cx| {
2107 callback(event, cx);
2108 true
2109 }),
2110 );
2111 activate();
2112 subscription
2113 }
2114
2115 pub fn on_system_wake<F>(&self, mut callback: F) -> Subscription
2120 where
2121 F: 'static + FnMut(&mut App),
2122 {
2123 let (subscription, activate) = self.system_wake_observers.insert(
2124 (),
2125 Box::new(move |cx| {
2126 callback(cx);
2127 true
2128 }),
2129 );
2130 activate();
2131 subscription
2132 }
2133
2134 pub fn on_app_lifecycle(
2142 &self,
2143 mut callback: impl FnMut(AppLifecyclePhase, &mut App) + 'static,
2144 ) -> Subscription {
2145 let (subscription, activate) = self.app_lifecycle_observers.insert(
2146 (),
2147 Box::new(move |phase, cx| {
2148 callback(phase, cx);
2149 true
2150 }),
2151 );
2152 activate();
2153 subscription
2154 }
2155
2156 pub fn on_memory_warning(&self, mut callback: impl FnMut(&mut App) + 'static) -> Subscription {
2159 let (subscription, activate) = self.memory_warning_observers.insert(
2160 (),
2161 Box::new(move |cx| {
2162 callback(cx);
2163 true
2164 }),
2165 );
2166 activate();
2167 subscription
2168 }
2169
2170 pub fn window_appearance(&self) -> WindowAppearance {
2174 self.platform.window_appearance()
2175 }
2176
2177 pub fn set_window_appearance(&self, appearance: Option<WindowAppearance>) {
2188 self.platform.set_window_appearance(appearance);
2189 }
2190
2191 pub fn supports_haptic_feedback(&self) -> bool {
2193 self.platform.supports_haptic_feedback()
2194 }
2195
2196 pub fn play_haptic_feedback(&self, style: HapticFeedbackStyle) {
2205 self.platform.play_haptic_feedback(style)
2206 }
2207
2208 pub fn button_layout(&self) -> Option<WindowButtonLayout> {
2213 self.platform.button_layout()
2214 }
2215
2216 pub fn read_from_clipboard(&self) -> Option<ClipboardItem> {
2222 self.platform.read_from_clipboard()
2223 }
2224
2225 pub fn read_from_clipboard_async(
2232 &self,
2233 ) -> Task<Result<Option<ClipboardItem>, ClipboardReadError>> {
2234 self.platform.read_from_clipboard_async()
2235 }
2236
2237 pub fn set_text_rendering_mode(&mut self, mode: TextRenderingMode) {
2242 self.text_rendering_mode.set(mode);
2243 }
2244
2245 pub fn text_rendering_mode(&self) -> TextRenderingMode {
2247 self.text_rendering_mode.get()
2248 }
2249
2250 pub fn write_to_clipboard(&self, item: ClipboardItem) {
2264 self.platform.write_to_clipboard(item)
2265 }
2266
2267 #[cfg(any(target_os = "linux", target_os = "freebsd"))]
2270 pub fn read_from_primary(&self) -> Option<ClipboardItem> {
2271 self.platform.read_from_primary()
2272 }
2273
2274 #[cfg(any(target_os = "linux", target_os = "freebsd"))]
2277 pub fn write_to_primary(&self, item: ClipboardItem) {
2278 self.platform.write_to_primary(item)
2279 }
2280
2281 #[cfg(target_os = "macos")]
2287 pub fn read_from_find_pasteboard(&self) -> Option<ClipboardItem> {
2288 self.platform.read_from_find_pasteboard()
2289 }
2290
2291 #[cfg(target_os = "macos")]
2297 pub fn write_to_find_pasteboard(&self, item: ClipboardItem) {
2298 self.platform.write_to_find_pasteboard(item)
2299 }
2300
2301 pub fn write_credentials(
2306 &self,
2307 url: &str,
2308 username: &str,
2309 password: &[u8],
2310 ) -> Task<Result<()>> {
2311 self.platform.write_credentials(url, username, password)
2312 }
2313
2314 pub fn read_credentials(&self, url: &str) -> Task<Result<Option<(String, Vec<u8>)>>> {
2319 self.platform.read_credentials(url)
2320 }
2321
2322 pub fn delete_credentials(&self, url: &str) -> Task<Result<()>> {
2324 self.platform.delete_credentials(url)
2325 }
2326
2327 pub fn open_url(&self, url: &str) {
2332 self.platform.open_url(url);
2333 }
2334
2335 pub fn register_url_scheme(&self, scheme: &str) -> Task<Result<()>> {
2340 self.platform.register_url_scheme(scheme)
2341 }
2342
2343 pub fn set_app_identity(&self, identifier: &str, name: &str) {
2348 self.platform.set_app_identity(identifier, name);
2349 }
2350
2351 pub fn show_system_notification(&self, notification: SystemNotification) {
2358 self.platform.show_system_notification(notification);
2359 }
2360
2361 pub fn dismiss_system_notification(&self, tag: &str) {
2366 self.platform.dismiss_system_notification(tag);
2367 }
2368
2369 pub fn on_system_notification_response<F>(&self, mut callback: F)
2373 where
2374 F: 'static + FnMut(SystemNotificationResponse, &mut App),
2375 {
2376 let this = self.this.clone();
2377 self.platform
2378 .on_system_notification_response(Box::new(move |response| {
2379 if let Some(app) = this.upgrade() {
2380 callback(response, &mut app.borrow_mut());
2381 }
2382 }));
2383 }
2384
2385 pub fn app_path(&self) -> Result<PathBuf> {
2389 self.platform.app_path()
2390 }
2391
2392 pub fn compositor_name(&self) -> &'static str {
2396 self.platform.compositor_name()
2397 }
2398
2399 pub fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf> {
2403 self.platform.path_for_auxiliary_executable(name)
2404 }
2405
2406 pub fn prompt_for_paths(
2412 &self,
2413 options: PathPromptOptions,
2414 ) -> oneshot::Receiver<Result<Option<Vec<PathBuf>>>> {
2415 self.platform.prompt_for_paths(options)
2416 }
2417
2418 pub fn prompt_for_new_path(
2424 &self,
2425 directory: &Path,
2426 suggested_name: Option<&str>,
2427 ) -> oneshot::Receiver<Result<Option<PathBuf>>> {
2428 self.platform.prompt_for_new_path(directory, suggested_name)
2429 }
2430
2431 pub fn reveal_path(&self, path: &Path) {
2433 self.platform.reveal_path(path)
2434 }
2435
2436 pub fn open_with_system(&self, path: &Path) {
2438 self.platform.open_with_system(path)
2439 }
2440
2441 pub fn should_auto_hide_scrollbars(&self) -> bool {
2443 self.platform.should_auto_hide_scrollbars()
2444 }
2445
2446 pub fn restart(&mut self) {
2452 self.restart_observers
2453 .clone()
2454 .retain(&(), |observer| observer(self));
2455 self.platform.restart(
2456 self.restart_path.take(),
2457 std::mem::take(&mut self.restart_arguments),
2458 )
2459 }
2460
2461 pub fn set_restart_path(&mut self, path: PathBuf) {
2463 self.restart_path = Some(path);
2464 }
2465
2466 pub fn http_client(&self) -> Arc<dyn HttpClient> {
2468 self.http_client.clone()
2469 }
2470
2471 pub fn set_http_client(&mut self, new_client: Arc<dyn HttpClient>) {
2473 self.http_client = new_client;
2474 }
2475
2476 pub fn set_quit_mode(&mut self, mode: QuitMode) {
2480 self.quit_mode = mode;
2481 }
2482
2483 pub fn set_activation_policy(&mut self, policy: ActivationPolicy) {
2492 self.platform.set_activation_policy(policy);
2493 }
2494
2495 pub fn svg_renderer(&self) -> SvgRenderer {
2497 self.svg_renderer.clone()
2498 }
2499
2500 pub(crate) fn push_effect(&mut self, effect: Effect) {
2501 match &effect {
2502 Effect::Notify { emitter } => {
2503 if !self.pending_notifications.insert(*emitter) {
2504 return;
2505 }
2506 }
2507 Effect::NotifyGlobalObservers { global_type } => {
2508 if !self.pending_global_notifications.insert(*global_type) {
2509 return;
2510 }
2511 }
2512 _ => {}
2513 };
2514
2515 self.pending_effects.push_back(effect);
2516 }
2517
2518 fn flush_effects(&mut self) {
2522 loop {
2523 self.release_dropped_entities();
2524 self.release_dropped_focus_handles();
2525 if let Some(effect) = self.pending_effects.pop_front() {
2526 match effect {
2527 Effect::Notify { emitter } => {
2528 self.apply_notify_effect(emitter);
2529 }
2530
2531 Effect::Emit {
2532 emitter,
2533 event_type,
2534 event,
2535 } => self.apply_emit_effect(emitter, event_type, &*event),
2536
2537 Effect::RefreshWindows => {
2538 self.apply_refresh_effect();
2539 }
2540
2541 Effect::NotifyGlobalObservers { global_type } => {
2542 self.apply_notify_global_observers_effect(global_type);
2543 }
2544
2545 Effect::Defer { callback } => {
2546 self.apply_defer_effect(callback);
2547 }
2548 Effect::EntityCreated {
2549 entity,
2550 tid,
2551 window,
2552 } => {
2553 self.apply_entity_created_effect(entity, tid, window);
2554 }
2555 }
2556 } else {
2557 #[cfg(any(test, feature = "test-support"))]
2558 if matches!(self.mode, GpuiMode::Test { .. }) {
2559 for window in self
2560 .windows
2561 .values()
2562 .filter_map(|window| {
2563 let window = window.as_deref()?;
2564 window.invalidator.is_dirty().then_some(window.handle)
2565 })
2566 .collect::<Vec<_>>()
2567 {
2568 self.update_window(window, |_, window, cx| window.draw(cx).clear(cx))
2569 .unwrap();
2570 }
2571 }
2572
2573 if self.pending_effects.is_empty() {
2574 for window in self.windows.values().filter_map(|window| window.as_deref()) {
2575 if window.invalidator.is_dirty()
2576 || window.needs_present.get()
2577 || !window.next_frame_callbacks.borrow().is_empty()
2578 {
2579 window.platform_window.schedule_frame();
2580 }
2581 }
2582
2583 self.event_arena.clear();
2584 break;
2585 }
2586 }
2587 }
2588 }
2589
2590 fn release_dropped_entities(&mut self) {
2594 loop {
2595 let dropped = self.entities.take_dropped();
2596 if dropped.is_empty() {
2597 break;
2598 }
2599
2600 for (entity_id, mut entity) in dropped {
2601 self.observers.remove(&entity_id);
2602 self.event_listeners.remove(&entity_id);
2603 self.window_invalidators_by_entity.remove(&entity_id);
2604 self.current_window_by_entity.remove(&entity_id);
2605 for release_callback in self.release_listeners.remove(&entity_id) {
2606 release_callback(entity.as_mut(), self);
2607 }
2608 }
2609 }
2610 }
2611
2612 fn release_dropped_focus_handles(&mut self) {
2614 let focus_handles = self.focus_handles.clone();
2615 let mut focus_handles = focus_handles.write();
2616 let FocusMap {
2617 handles,
2618 dropped_handles,
2619 } = &mut *focus_handles;
2620 if dropped_handles.is_empty() {
2621 return;
2622 }
2623
2624 let windows = self
2625 .windows
2626 .values()
2627 .filter_map(|window| {
2628 let window = window.as_ref()?;
2629 dropped_handles
2630 .contains(&window.focus?)
2631 .then_some(window.handle)
2632 })
2633 .collect::<SmallVec<[_; 1]>>();
2634 for handle_id in dropped_handles.drain(..) {
2635 handles.remove(handle_id);
2636 }
2637 drop(focus_handles);
2638
2639 for window_handle in windows {
2640 window_handle
2641 .update(self, |_, window, cx| window.blur(cx))
2642 .ok();
2643 }
2644 }
2645
2646 fn apply_notify_effect(&mut self, emitter: EntityId) {
2647 self.pending_notifications.remove(&emitter);
2648
2649 self.observers
2650 .clone()
2651 .retain(&emitter, |handler| handler(self));
2652 }
2653
2654 fn apply_emit_effect(&mut self, emitter: EntityId, event_type: TypeId, event: &dyn Any) {
2655 self.event_listeners
2656 .clone()
2657 .retain(&emitter, |(stored_type, handler)| {
2658 if *stored_type == event_type {
2659 handler(event, self)
2660 } else {
2661 true
2662 }
2663 });
2664 }
2665
2666 fn apply_refresh_effect(&mut self) {
2667 for window in self.windows.values_mut() {
2668 if let Some(window) = window.as_deref_mut() {
2669 window.refreshing = true;
2670 window.invalidator.set_dirty(true);
2671 }
2672 }
2673 }
2674
2675 fn apply_notify_global_observers_effect(&mut self, type_id: TypeId) {
2676 self.pending_global_notifications.remove(&type_id);
2677 self.global_observers
2678 .clone()
2679 .retain(&type_id, |observer| observer(self));
2680 }
2681
2682 fn apply_defer_effect(&mut self, callback: Box<dyn FnOnce(&mut Self) + 'static>) {
2683 callback(self);
2684 }
2685
2686 fn apply_entity_created_effect(
2687 &mut self,
2688 entity: AnyEntity,
2689 tid: TypeId,
2690 window: Option<WindowId>,
2691 ) {
2692 if let Some(id) = window {
2696 self.current_window_by_entity.insert(entity.entity_id(), id);
2697 }
2698
2699 self.new_entity_observers.clone().retain(&tid, |observer| {
2700 if let Some(id) = window {
2701 self.update_window_id(id, {
2702 let entity = entity.clone();
2703 |_, window, cx| (observer)(entity, &mut Some(window), cx)
2704 })
2705 .expect("All windows should be off the stack when flushing effects");
2706 } else {
2707 (observer)(entity.clone(), &mut None, self)
2708 }
2709 true
2710 });
2711 }
2712
2713 #[inline(always)]
2720 pub fn with_window<R>(
2721 &mut self,
2722 entity_id: EntityId,
2723 f: impl FnOnce(&mut Window, &mut App) -> R,
2724 ) -> Option<R> {
2725 let window_id = *self.current_window_by_entity.get(&entity_id)?;
2726 self.update_window_id(window_id, |_, window, cx| f(window, cx))
2727 .ok()
2728 }
2729
2730 fn ensure_window(&mut self, entity_id: EntityId, window: WindowId) {
2731 self.current_window_by_entity
2732 .entry(entity_id)
2733 .or_insert(window);
2734 }
2735
2736 #[inline(always)]
2737 pub(crate) fn update_window_id<T, F>(&mut self, id: WindowId, update: F) -> Result<T>
2738 where
2739 F: FnOnce(AnyView, &mut Window, &mut App) -> T,
2740 {
2741 let mut update = Some(update);
2742 let mut result = None;
2743 self.update_window_erased(id, &mut |arguments| {
2744 if let Some((root_view, window, cx)) = arguments {
2745 result = Some(update.take().unwrap()(root_view, window, cx));
2746 } else {
2747 drop(update.take());
2748 drop(result.take());
2749 }
2750 });
2751 result.context("window not found")
2752 }
2753
2754 pub fn to_async(&self) -> AsyncApp {
2759 AsyncApp {
2760 app: self.this.clone(),
2761 background_executor: self.background_executor.clone(),
2762 foreground_executor: self.foreground_executor.clone(),
2763 }
2764 }
2765
2766 pub fn background_executor(&self) -> &BackgroundExecutor {
2770 &self.background_executor
2771 }
2772
2773 pub fn is_test(&self) -> bool {
2776 self.background_executor.is_test()
2777 }
2778
2779 pub fn foreground_executor(&self) -> &ForegroundExecutor {
2786 if self.quitting {
2787 panic!("Can't spawn on main thread after on_app_quit")
2788 };
2789 &self.foreground_executor
2790 }
2791
2792 #[cfg(feature = "profiler")]
2795 pub fn foreground_journal(&self) -> crate::profiler::journal::ForegroundJournal {
2796 self.foreground_journal.clone()
2797 }
2798
2799 #[cfg(all(feature = "profiler", not(target_family = "wasm")))]
2816 pub fn start_hang_monitor(
2817 &mut self,
2818 config: crate::profiler::hang::HangMonitorConfig,
2819 on_poll: impl FnMut(crate::profiler::hang::HangMonitorPoll) + Send + 'static,
2820 ) -> Result<(), crate::profiler::hang::HangMonitorError> {
2821 use crate::profiler::hang::{HangDetector, HangMonitor, HangMonitorError};
2822
2823 if self.hang_monitor.is_some() {
2824 debug_assert!(false, "the hang monitor was started twice");
2825 return Err(HangMonitorError::AlreadyStarted);
2826 }
2827 let detector = HangDetector::new(
2828 self.foreground_journal(),
2829 config.threshold,
2830 config.frame_budget,
2831 );
2832 let monitor = HangMonitor::spawn(detector, config.interval, on_poll)
2833 .map_err(HangMonitorError::Spawn)?;
2834 self.hang_monitor = Some(monitor);
2835 Ok(())
2836 }
2837
2838 #[track_caller]
2870 #[inline(always)]
2871 pub fn spawn<AsyncFn, R>(&self, f: AsyncFn) -> Task<R>
2872 where
2873 AsyncFn: AsyncFnOnce(&mut AsyncApp) -> R + 'static,
2874 R: 'static,
2875 {
2876 let mut cx = self.prepare_spawn();
2877
2878 self.foreground_executor
2879 .spawn(async move { f(&mut cx).await }.boxed_local())
2880 }
2881
2882 pub fn spawn_with_priority<AsyncFn, R>(&self, priority: Priority, f: AsyncFn) -> Task<R>
2884 where
2885 AsyncFn: AsyncFnOnce(&mut AsyncApp) -> R + 'static,
2886 R: 'static,
2887 {
2888 if self.quitting {
2889 debug_panic!("Can't spawn on main thread after on_app_quit")
2890 };
2891
2892 let mut cx = self.to_async();
2893
2894 self.foreground_executor
2895 .spawn_with_priority(priority, async move { f(&mut cx).await }.boxed_local())
2896 }
2897
2898 pub fn defer(&mut self, f: impl FnOnce(&mut App) + 'static) {
2917 self.push_effect(Effect::Defer {
2918 callback: Box::new(f),
2919 });
2920 }
2921
2922 pub fn assets(&self) -> &Arc<AssetRegistry> {
2924 &self.asset_registry
2925 }
2926
2927 pub fn text_system(&self) -> &Arc<TextSystem> {
2929 &self.text_system
2930 }
2931
2932 pub fn has_global<G: Global>(&self) -> bool {
2934 self.note_global_read(TypeId::of::<G>());
2935 self.globals_by_type.contains_key(&TypeId::of::<G>())
2936 }
2937
2938 #[track_caller]
2945 pub fn global<G: Global>(&self) -> &G {
2946 self.note_global_read(TypeId::of::<G>());
2947 self.globals_by_type
2948 .get(&TypeId::of::<G>())
2949 .map(|any_state| any_state.downcast_ref::<G>().unwrap())
2950 .unwrap_or_else(|| panic!("no state of type {} exists", type_name::<G>()))
2951 }
2952
2953 pub fn try_global<G: Global>(&self) -> Option<&G> {
2955 self.note_global_read(TypeId::of::<G>());
2956 self.globals_by_type
2957 .get(&TypeId::of::<G>())
2958 .map(|any_state| any_state.downcast_ref::<G>().unwrap())
2959 }
2960
2961 #[track_caller]
2972 pub fn global_mut<G: Global>(&mut self) -> &mut G {
2973 let global_type = TypeId::of::<G>();
2974 self.global_changed(global_type);
2975 self.globals_by_type
2976 .get_mut(&global_type)
2977 .and_then(|any_state| any_state.downcast_mut::<G>())
2978 .unwrap_or_else(|| panic!("no state of type {} exists", type_name::<G>()))
2979 }
2980
2981 pub fn default_global<G: Global + Default>(&mut self) -> &mut G {
2985 let global_type = TypeId::of::<G>();
2986 self.global_changed(global_type);
2987 self.globals_by_type
2988 .entry(global_type)
2989 .or_insert_with(|| Box::<G>::default())
2990 .downcast_mut::<G>()
2991 .unwrap()
2992 }
2993
2994 pub fn set_global<G: Global>(&mut self, global: G) {
3012 let global_type = TypeId::of::<G>();
3013 self.global_changed(global_type);
3014 self.globals_by_type.insert(global_type, Box::new(global));
3015 }
3016
3017 #[cfg(any(test, feature = "test-support"))]
3019 pub fn clear_globals(&mut self) {
3020 self.globals_by_type.drain();
3021 }
3022
3023 pub fn remove_global<G: Global>(&mut self) -> G {
3031 let global_type = TypeId::of::<G>();
3032 self.global_changed(global_type);
3033 *self
3034 .globals_by_type
3035 .remove(&global_type)
3036 .unwrap_or_else(|| panic!("no global added for {}", type_name::<G>()))
3037 .downcast()
3038 .unwrap()
3039 }
3040
3041 pub fn observe_global<G: Global>(
3067 &mut self,
3068 mut f: impl FnMut(&mut Self) + 'static,
3069 ) -> Subscription {
3070 let (subscription, activate) = self.global_observers.insert(
3071 TypeId::of::<G>(),
3072 Box::new(move |cx| {
3073 f(cx);
3074 true
3075 }),
3076 );
3077 self.defer(move |_| activate());
3078 subscription
3079 }
3080
3081 #[track_caller]
3083 pub(crate) fn lease_global<G: Global>(&mut self) -> GlobalLease<G> {
3084 GlobalLease::new(
3085 self.globals_by_type
3086 .remove(&TypeId::of::<G>())
3087 .with_context(|| format!("no global registered of type {}", type_name::<G>()))
3088 .unwrap(),
3089 )
3090 }
3091
3092 pub(crate) fn end_global_lease<G: Global>(&mut self, lease: GlobalLease<G>) {
3094 let global_type = TypeId::of::<G>();
3095
3096 self.global_changed(global_type);
3097 self.globals_by_type.insert(global_type, lease.global);
3098 }
3099
3100 pub(crate) fn new_entity_observer(
3101 &self,
3102 key: TypeId,
3103 value: NewEntityListener,
3104 ) -> Subscription {
3105 let (subscription, activate) = self.new_entity_observers.insert(key, value);
3106 activate();
3107 subscription
3108 }
3109
3110 pub fn observe_new<T: 'static>(
3117 &self,
3118 on_new: impl 'static + Fn(&mut T, Option<&mut Window>, &mut Context<T>),
3119 ) -> Subscription {
3120 self.new_entity_observer(
3121 TypeId::of::<T>(),
3122 Box::new(
3123 move |any_entity: AnyEntity, window: &mut Option<&mut Window>, cx: &mut App| {
3124 any_entity
3125 .downcast::<T>()
3126 .unwrap()
3127 .update(cx, |entity_state, cx| {
3128 on_new(entity_state, window.as_deref_mut(), cx)
3129 })
3130 },
3131 ),
3132 )
3133 }
3134
3135 pub fn observe_release<T>(
3141 &self,
3142 handle: &Entity<T>,
3143 on_release: impl FnOnce(&mut T, &mut App) + 'static,
3144 ) -> Subscription
3145 where
3146 T: 'static,
3147 {
3148 let (subscription, activate) = self.release_listeners.insert(
3149 handle.entity_id(),
3150 Box::new(move |entity, cx| {
3151 let entity = entity.downcast_mut().expect("invalid entity type");
3152 on_release(entity, cx)
3153 }),
3154 );
3155 activate();
3156 subscription
3157 }
3158
3159 pub fn observe_release_in<T>(
3164 &self,
3165 handle: &Entity<T>,
3166 window: &Window,
3167 on_release: impl FnOnce(&mut T, &mut Window, &mut App) + 'static,
3168 ) -> Subscription
3169 where
3170 T: 'static,
3171 {
3172 let window_handle = window.handle;
3173 self.observe_release(handle, move |entity, cx| {
3174 let _ = window_handle.update(cx, |_, window, cx| on_release(entity, window, cx));
3175 })
3176 }
3177
3178 pub fn observe_keystrokes(
3187 &mut self,
3188 mut f: impl FnMut(&KeystrokeEvent, &mut Window, &mut App) + 'static,
3189 ) -> Subscription {
3190 fn inner(
3191 keystroke_observers: &SubscriberSet<(), KeystrokeObserver>,
3192 handler: KeystrokeObserver,
3193 ) -> Subscription {
3194 let (subscription, activate) = keystroke_observers.insert((), handler);
3195 activate();
3196 subscription
3197 }
3198
3199 inner(
3200 &self.keystroke_observers,
3201 Box::new(move |event, window, cx| {
3202 f(event, window, cx);
3203 true
3204 }),
3205 )
3206 }
3207
3208 pub fn intercept_keystrokes(
3214 &mut self,
3215 mut f: impl FnMut(&KeystrokeEvent, &mut Window, &mut App) + 'static,
3216 ) -> Subscription {
3217 fn inner(
3218 keystroke_interceptors: &SubscriberSet<(), KeystrokeObserver>,
3219 handler: KeystrokeObserver,
3220 ) -> Subscription {
3221 let (subscription, activate) = keystroke_interceptors.insert((), handler);
3222 activate();
3223 subscription
3224 }
3225
3226 inner(
3227 &self.keystroke_interceptors,
3228 Box::new(move |event, window, cx| {
3229 f(event, window, cx);
3230 true
3231 }),
3232 )
3233 }
3234
3235 pub fn bind_keys(&mut self, bindings: impl IntoIterator<Item = KeyBinding>) {
3261 self.keymap.borrow_mut().add_bindings(bindings);
3262 self.pending_effects.push_back(Effect::RefreshWindows);
3263 }
3264
3265 pub fn clear_key_bindings(&mut self) {
3267 self.keymap.borrow_mut().clear();
3268 self.pending_effects.push_back(Effect::RefreshWindows);
3269 }
3270
3271 pub fn key_bindings(&self) -> Rc<RefCell<Keymap>> {
3276 self.keymap.clone()
3277 }
3278
3279 pub fn on_action<A: Action>(
3303 &mut self,
3304 listener: impl Fn(&A, &mut Self) + 'static,
3305 ) -> &mut Self {
3306 self.global_action_listeners
3307 .entry(TypeId::of::<A>())
3308 .or_default()
3309 .push(Rc::new(move |action, phase, cx| {
3310 if phase == DispatchPhase::Bubble {
3311 let action = action.downcast_ref().unwrap();
3312 listener(action, cx)
3313 }
3314 }));
3315 self
3316 }
3317
3318 pub fn stop_propagation(&mut self) {
3324 self.propagate_event = false;
3325 }
3326
3327 pub fn propagate(&mut self) {
3333 self.propagate_event = true;
3334 }
3335
3336 pub fn build_action(
3342 &self,
3343 name: &str,
3344 data: Option<serde_json::Value>,
3345 ) -> std::result::Result<Box<dyn Action>, ActionBuildError> {
3346 self.actions.build_action(name, data)
3347 }
3348
3349 pub fn all_action_names(&self) -> &[&'static str] {
3355 self.actions.all_action_names()
3356 }
3357
3358 pub fn all_bindings_for_input(&self, input: &[Keystroke]) -> Vec<KeyBinding> {
3363 RefCell::borrow(&self.keymap).all_bindings_for_input(input)
3364 }
3365
3366 pub fn action_schemas(
3370 &self,
3371 generator: &mut schemars::SchemaGenerator,
3372 ) -> Vec<(&'static str, Option<schemars::Schema>)> {
3373 self.actions.action_schemas(generator)
3374 }
3375
3376 pub fn action_schema_by_name(
3381 &self,
3382 name: &str,
3383 generator: &mut schemars::SchemaGenerator,
3384 ) -> Option<Option<schemars::Schema>> {
3385 self.actions.action_schema_by_name(name, generator)
3386 }
3387
3388 pub fn deprecated_actions_to_preferred_actions(&self) -> &HashMap<&'static str, &'static str> {
3390 self.actions.deprecated_aliases()
3391 }
3392
3393 pub fn action_deprecation_messages(&self) -> &HashMap<&'static str, &'static str> {
3395 self.actions.deprecation_messages()
3396 }
3397
3398 pub fn action_documentation(&self) -> &HashMap<&'static str, &'static str> {
3400 self.actions.documentation()
3401 }
3402
3403 pub fn on_app_quit<Fut>(
3410 &self,
3411 mut on_quit: impl FnMut(&mut App) -> Fut + 'static,
3412 ) -> Subscription
3413 where
3414 Fut: 'static + Future<Output = ()>,
3415 {
3416 let (subscription, activate) = self.quit_observers.insert(
3417 (),
3418 Box::new(move |cx| {
3419 let future = on_quit(cx);
3420 future.boxed_local()
3421 }),
3422 );
3423 activate();
3424 subscription
3425 }
3426
3427 pub fn on_app_restart(&self, mut on_restart: impl 'static + FnMut(&mut App)) -> Subscription {
3431 let (subscription, activate) = self.restart_observers.insert(
3432 (),
3433 Box::new(move |cx| {
3434 on_restart(cx);
3435 true
3436 }),
3437 );
3438 activate();
3439 subscription
3440 }
3441
3442 pub fn on_window_closed(
3447 &self,
3448 mut on_closed: impl FnMut(&mut App, WindowId) + 'static,
3449 ) -> Subscription {
3450 let (subscription, activate) = self.window_closed_observers.insert((), Box::new(on_closed));
3451 activate();
3452 subscription
3453 }
3454
3455 pub(crate) fn clear_pending_keystrokes(&mut self) {
3456 for window in self.windows() {
3457 window
3458 .update(self, |_, window, cx| {
3459 window.clear_pending_keystrokes(cx);
3460 })
3461 .ok();
3462 }
3463 }
3464
3465 pub fn is_action_available(&mut self, action: &dyn Action) -> bool {
3470 let mut action_available = false;
3471 if let Some(window) = self.active_window()
3472 && let Ok(window_action_available) =
3473 window.update(self, |_, window, cx| window.is_action_available(action, cx))
3474 {
3475 action_available = window_action_available;
3476 }
3477
3478 action_available
3479 || self
3480 .global_action_listeners
3481 .contains_key(&action.as_any().type_id())
3482 }
3483
3484 pub fn set_menus(&self, menus: impl IntoIterator<Item = Menu>) {
3488 let menus: Vec<Menu> = menus.into_iter().collect();
3489 self.platform.set_menus(menus, &self.keymap.borrow());
3490 }
3491
3492 pub fn get_menus(&self) -> Option<Vec<OwnedMenu>> {
3494 self.platform.get_menus()
3495 }
3496
3497 pub fn set_dock_menu(&self, menus: Vec<MenuItem>) {
3499 self.platform.set_dock_menu(menus, &self.keymap.borrow())
3500 }
3501
3502 pub fn perform_dock_menu_action(&self, action: usize) {
3506 self.platform.perform_dock_menu_action(action);
3507 }
3508
3509 pub fn add_recent_document(&self, path: &Path) {
3514 self.platform.add_recent_document(path);
3515 }
3516
3517 pub fn update_jump_list(
3521 &self,
3522 menus: Vec<MenuItem>,
3523 entries: Vec<SmallVec<[PathBuf; 2]>>,
3524 ) -> Task<Vec<SmallVec<[PathBuf; 2]>>> {
3525 self.platform.update_jump_list(menus, entries)
3526 }
3527
3528 pub fn dispatch_action(&mut self, action: &dyn Action) {
3534 if let Some(active_window) = self.active_window() {
3535 active_window
3536 .update(self, |_, window, cx| {
3537 window.dispatch_action(action.boxed_clone(), cx)
3538 })
3539 .log_err();
3540 } else {
3541 self.dispatch_global_action(action);
3542 }
3543 }
3544
3545 fn dispatch_global_action(&mut self, action: &dyn Action) {
3546 self.propagate_event = true;
3547
3548 if let Some(mut global_listeners) = self
3549 .global_action_listeners
3550 .remove(&action.as_any().type_id())
3551 {
3552 for listener in &global_listeners {
3553 listener(action.as_any(), DispatchPhase::Capture, self);
3554 if !self.propagate_event {
3555 break;
3556 }
3557 }
3558
3559 global_listeners.extend(
3560 self.global_action_listeners
3561 .remove(&action.as_any().type_id())
3562 .unwrap_or_default(),
3563 );
3564
3565 self.global_action_listeners
3566 .insert(action.as_any().type_id(), global_listeners);
3567 }
3568
3569 if self.propagate_event
3570 && let Some(mut global_listeners) = self
3571 .global_action_listeners
3572 .remove(&action.as_any().type_id())
3573 {
3574 for listener in global_listeners.iter().rev() {
3575 listener(action.as_any(), DispatchPhase::Bubble, self);
3576 if !self.propagate_event {
3577 break;
3578 }
3579 }
3580
3581 global_listeners.extend(
3582 self.global_action_listeners
3583 .remove(&action.as_any().type_id())
3584 .unwrap_or_default(),
3585 );
3586
3587 self.global_action_listeners
3588 .insert(action.as_any().type_id(), global_listeners);
3589 }
3590 }
3591
3592 pub fn has_active_drag(&self) -> bool {
3594 self.active_drag.is_some()
3595 }
3596
3597 pub fn active_drag(&self) -> Option<&AnyDrag> {
3599 self.active_drag.as_ref()
3600 }
3601
3602 pub fn active_drag_cursor_style(&self) -> Option<CursorStyle> {
3604 self.active_drag.as_ref().and_then(|drag| drag.cursor_style)
3605 }
3606
3607 pub fn start_drag(&mut self, drag: AnyDrag) {
3613 debug_assert!(self.active_drag.is_none());
3614 self.active_drag = Some(drag);
3615 }
3616
3617 pub fn stop_drag(&mut self, window: &Window) -> Option<Arc<dyn Any>> {
3621 let drag = self.active_drag.take();
3622 if drag.is_some()
3623 && let Some(platform_drag) = self.platform_owned_drag.as_ref()
3624 {
3625 if platform_drag.source_window == window.window_handle().window_id()
3626 && matches!(
3627 &platform_drag.state,
3628 PlatformOwnedDragState::RestoredInSourceWindow
3629 )
3630 {
3631 self.platform_owned_drag = None;
3632 }
3633 }
3634 Some(drag?.value)
3635 }
3636
3637 pub fn stop_active_drag(&mut self, window: &mut Window) -> bool {
3639 if self.stop_drag(window).is_some() {
3640 window.refresh();
3641 true
3642 } else {
3643 false
3644 }
3645 }
3646
3647 pub(crate) fn hand_active_drag_to_platform(&mut self, source_window: WindowId) -> bool {
3648 let Some(drag) = self.active_drag.take() else {
3649 return false;
3650 };
3651 self.platform_owned_drag = Some(PlatformOwnedDrag {
3652 source_window,
3653 state: PlatformOwnedDragState::Suspended(drag),
3654 });
3655 true
3656 }
3657
3658 pub(crate) fn restore_platform_drag(&mut self, source_window: WindowId) -> bool {
3659 let Some(platform_drag) = self
3660 .platform_owned_drag
3661 .as_mut()
3662 .filter(|drag| drag.source_window == source_window)
3663 else {
3664 return false;
3665 };
3666 let state = std::mem::replace(
3667 &mut platform_drag.state,
3668 PlatformOwnedDragState::RestoredInSourceWindow,
3669 );
3670 let PlatformOwnedDragState::Suspended(drag) = state else {
3671 return false;
3672 };
3673 self.active_drag = Some(drag);
3674 true
3675 }
3676
3677 pub(crate) fn hand_restored_drag_to_platform(&mut self, source_window: WindowId) -> bool {
3678 let Some(platform_drag) = self.platform_owned_drag.as_mut().filter(|drag| {
3679 drag.source_window == source_window
3680 && matches!(&drag.state, PlatformOwnedDragState::RestoredInSourceWindow)
3681 }) else {
3682 return false;
3683 };
3684 let Some(drag) = self.active_drag.take() else {
3685 return false;
3686 };
3687 platform_drag.state = PlatformOwnedDragState::Suspended(drag);
3688 true
3689 }
3690
3691 pub(crate) fn end_platform_drag(&mut self, source_window: WindowId) -> bool {
3692 if !self
3693 .platform_owned_drag
3694 .as_ref()
3695 .is_some_and(|drag| drag.source_window == source_window)
3696 {
3697 return false;
3698 }
3699 self.platform_owned_drag = None;
3700 self.active_drag = None;
3701 true
3702 }
3703
3704 pub fn set_active_drag_cursor_style(
3706 &mut self,
3707 cursor_style: CursorStyle,
3708 window: &mut Window,
3709 ) -> bool {
3710 if let Some(ref mut drag) = self.active_drag {
3711 drag.cursor_style = Some(cursor_style);
3712 window.refresh();
3713 true
3714 } else {
3715 false
3716 }
3717 }
3718
3719 pub fn set_prompt_builder(
3725 &mut self,
3726 renderer: impl Fn(
3727 PromptLevel,
3728 &str,
3729 Option<&str>,
3730 &[PromptButton],
3731 PromptHandle,
3732 &mut Window,
3733 &mut App,
3734 ) -> RenderablePromptHandle
3735 + 'static,
3736 ) {
3737 self.prompt_builder = Some(PromptBuilder::Custom(Box::new(renderer)));
3738 }
3739
3740 pub fn reset_prompt_builder(&mut self) {
3742 self.prompt_builder = Some(PromptBuilder::Default);
3743 }
3744
3745 pub fn remove_asset<A: Asset>(&mut self, source: &A::Source) {
3747 let asset_id = (TypeId::of::<A>(), hash(source));
3748 self.loading_assets.remove(&asset_id);
3749 }
3750
3751 #[cfg(any(test, feature = "test-support"))]
3755 pub fn has_asset<A: Asset>(&self, source: &A::Source) -> bool {
3756 let asset_id = (TypeId::of::<A>(), hash(source));
3757 self.loading_assets.contains_key(&asset_id)
3758 }
3759
3760 pub fn fetch_asset<A: Asset>(&mut self, source: &A::Source) -> Option<A::Output> {
3765 self.asset_entry::<A>(source).get()
3766 }
3767
3768 pub(crate) fn asset_entry<A: Asset>(&mut self, source: &A::Source) -> &CachedLoad<A::Output> {
3769 let asset_id = (TypeId::of::<A>(), hash(source));
3770 if !self.loading_assets.contains_key(&asset_id) {
3771 let future = A::load(source.clone(), self);
3772 let entry = CachedLoad::new(future, self);
3773 self.loading_assets.insert(asset_id, Box::new(entry));
3774 }
3775 self.loading_assets
3776 .get(&asset_id)
3777 .and_then(|entry| entry.downcast_ref())
3778 .expect("asset cache entries are keyed by their asset type")
3779 }
3780
3781 #[track_caller]
3786 pub fn focus_handle(&self) -> FocusHandle {
3787 FocusHandle::new(&self.focus_handles)
3788 }
3789
3790 #[cfg(any(test, feature = "test-support", debug_assertions))]
3794 pub fn get_name(&self) -> Option<&'static str> {
3795 self.name
3796 }
3797
3798 pub fn can_select_mixed_files_and_dirs(&self) -> bool {
3800 self.platform.can_select_mixed_files_and_dirs()
3801 }
3802
3803 pub fn drop_image(&mut self, image: Arc<RenderImage>, current_window: Option<&mut Window>) {
3809 for window in self.windows.values_mut().flatten() {
3811 _ = window.drop_image(image.clone());
3812 }
3813
3814 if let Some(window) = current_window {
3816 _ = window.drop_image(image);
3817 }
3818 }
3819
3820 #[cfg(any(feature = "inspector", debug_assertions))]
3822 pub fn set_inspector_renderer(&mut self, f: crate::InspectorRenderer) {
3823 self.inspector_renderer = Some(f);
3824 }
3825
3826 #[cfg(any(feature = "inspector", debug_assertions))]
3828 pub fn register_inspector_element<T: 'static, R: crate::IntoElement, F>(
3829 &mut self,
3830 factory: impl 'static + Fn(&mut Window, &mut App) -> F,
3831 ) where
3832 F: 'static + FnMut(crate::InspectorElementId, &T, &mut Window, &mut App) -> R,
3833 {
3834 self.inspector_element_registry.register(factory);
3835 }
3836
3837 pub fn init_colors(&mut self) {
3839 self.set_global(GlobalColors(Arc::new(Colors::default())));
3840 }
3841
3842 #[inline(never)]
3843 fn update_window_erased(
3844 &mut self,
3845 window_id: WindowId,
3846 update: &mut dyn FnMut(Option<(AnyView, &mut Window, &mut App)>),
3847 ) {
3848 self.update(|cx| {
3849 let Some(mut window) = cx.windows.get_mut(window_id).and_then(Option::take) else {
3850 update(None);
3851 return;
3852 };
3853
3854 let root_view = window.root.clone().unwrap();
3855
3856 cx.window_update_stack.push(window.handle.id);
3857 update(Some((root_view, &mut window, cx)));
3858 fn trail(window_id: WindowId, window: Box<Window>, cx: &mut App) -> Option<()> {
3859 cx.window_update_stack.pop();
3860
3861 if window.removed {
3862 cx.end_platform_drag(window_id);
3863 cx.window_handles.remove(&window_id);
3864 cx.windows.remove(window_id);
3865 if let Some(tracked) = cx.tracked_entities.remove(&window_id) {
3866 for entity_id in tracked {
3867 if let Some(windows) =
3868 cx.window_invalidators_by_entity.get_mut(&entity_id)
3869 {
3870 windows.remove(&window_id);
3871 }
3872 if cx.current_window_by_entity.get(&entity_id) == Some(&window_id) {
3873 cx.current_window_by_entity.remove(&entity_id);
3874 }
3875 }
3876 }
3877
3878 cx.window_closed_observers.clone().retain(&(), |callback| {
3879 callback(cx, window_id);
3880 true
3881 });
3882
3883 let quit_on_empty = match cx.quit_mode {
3884 QuitMode::Explicit => false,
3885 QuitMode::LastWindowClosed => true,
3886 QuitMode::Default => cfg!(not(target_os = "macos")),
3887 };
3888
3889 if quit_on_empty && cx.windows.is_empty() {
3890 cx.quit();
3891 }
3892 } else {
3893 cx.windows.get_mut(window_id)?.replace(window);
3894 }
3895 Some(())
3896 }
3897 if trail(window_id, window, cx).is_none() {
3898 update(None);
3899 }
3900 });
3901 }
3902
3903 #[inline(never)]
3904 fn update_entity_erased(
3905 &mut self,
3906 handle: &AnyEntity,
3907 entity_type: &str,
3908 update: &mut dyn FnMut(&mut dyn Any, &mut App),
3909 ) {
3910 self.update(|cx| {
3911 let mut lease = cx.entities.lease_erased(handle, entity_type);
3912 update(lease.entity.as_deref_mut().unwrap(), cx);
3913 cx.entities.end_lease_erased(handle.entity_id, lease);
3914 });
3915 }
3916
3917 #[inline(never)]
3918 #[track_caller]
3919 fn prepare_spawn(&self) -> AsyncApp {
3920 if self.quitting {
3921 debug_panic!("Can't spawn on main thread after on_app_quit")
3922 };
3923 self.to_async()
3924 }
3925}
3926
3927impl AppContext for App {
3928 fn new<T: 'static>(&mut self, build_entity: impl FnOnce(&mut Context<T>) -> T) -> Entity<T> {
3933 self.update(|cx| {
3934 let slot = cx.entities.reserve();
3935 let handle = slot.clone();
3936 let entity = build_entity(&mut Context::new_context(cx, slot.downgrade()));
3937
3938 cx.push_effect(Effect::EntityCreated {
3939 entity: handle.into_any(),
3940 tid: TypeId::of::<T>(),
3941 window: cx.window_update_stack.last().cloned(),
3942 });
3943
3944 cx.entities.insert(slot, entity)
3945 })
3946 }
3947
3948 fn reserve_entity<T: 'static>(&mut self) -> Reservation<T> {
3949 Reservation(self.entities.reserve())
3950 }
3951
3952 fn insert_entity<T: 'static>(
3953 &mut self,
3954 reservation: Reservation<T>,
3955 build_entity: impl FnOnce(&mut Context<T>) -> T,
3956 ) -> Entity<T> {
3957 self.update(|cx| {
3958 let slot = reservation.0;
3959 let entity = build_entity(&mut Context::new_context(cx, slot.downgrade()));
3960 cx.entities.insert(slot, entity)
3961 })
3962 }
3963
3964 #[inline(always)]
3967 fn update_entity<T: 'static, R>(
3968 &mut self,
3969 handle: &Entity<T>,
3970 update: impl FnOnce(&mut T, &mut Context<T>) -> R,
3971 ) -> R {
3972 let mut update = Some(update);
3973 let mut result = None;
3974 self.update_entity_erased(handle, type_name::<T>(), &mut |entity, cx| {
3975 let value = update.take().unwrap()(
3976 entity.downcast_mut::<T>().unwrap(),
3977 &mut Context::new_context(cx, handle.downgrade()),
3978 );
3979 result = Some(value);
3980 });
3981 result.unwrap()
3982 }
3983
3984 fn as_mut<'a, T>(&'a mut self, handle: &Entity<T>) -> GpuiBorrow<'a, T>
3985 where
3986 T: 'static,
3987 {
3988 GpuiBorrow::new(handle.clone(), self)
3989 }
3990
3991 #[inline(always)]
3992 fn read_entity<T, R>(&self, handle: &Entity<T>, read: impl FnOnce(&T, &App) -> R) -> R
3993 where
3994 T: 'static,
3995 {
3996 let entity = self.entities.read(handle);
3997 read(entity, self)
3998 }
3999
4000 fn notify(&mut self, entity_id: EntityId) {
4001 let window_invalidators = mem::take(
4002 self.window_invalidators_by_entity
4003 .entry(entity_id)
4004 .or_default(),
4005 );
4006
4007 let live_invalidators: SmallVec<[WindowInvalidator; 2]> = window_invalidators
4012 .iter()
4013 .filter(|(window_id, _)| {
4014 self.tracked_entities
4015 .get(window_id)
4016 .is_some_and(|set| set.contains(&entity_id))
4017 })
4018 .map(|(_, invalidator)| invalidator.clone())
4019 .collect();
4020
4021 if live_invalidators.is_empty() {
4022 if self.pending_notifications.insert(entity_id) {
4023 self.pending_effects
4024 .push_back(Effect::Notify { emitter: entity_id });
4025 }
4026 } else {
4027 for invalidator in &live_invalidators {
4028 invalidator.invalidate_view(entity_id, self);
4029 }
4030 }
4031
4032 self.window_invalidators_by_entity
4033 .insert(entity_id, window_invalidators);
4034 }
4035
4036 fn emit<EntityType, EventType>(&mut self, entity: &Entity<EntityType>, event: EventType)
4037 where
4038 EntityType: EventEmitter<EventType>,
4039 EventType: 'static,
4040 {
4041 let event = self
4042 .event_arena
4043 .alloc(|| event)
4044 .map(|it| it as &mut dyn Any);
4045 self.pending_effects.push_back(Effect::Emit {
4046 emitter: entity.entity_id(),
4047 event_type: TypeId::of::<EventType>(),
4048 event,
4049 });
4050 }
4051
4052 fn update_window<T, F>(&mut self, handle: AnyWindowHandle, update: F) -> Result<T>
4053 where
4054 F: FnOnce(AnyView, &mut Window, &mut App) -> T,
4055 {
4056 self.update_window_id(handle.id, update)
4057 }
4058
4059 fn with_window<R>(
4060 &mut self,
4061 entity_id: EntityId,
4062 f: impl FnOnce(&mut Window, &mut App) -> R,
4063 ) -> Option<R> {
4064 App::with_window(self, entity_id, f)
4065 }
4066
4067 fn read_window<T, R>(
4068 &self,
4069 window: &WindowHandle<T>,
4070 read: impl FnOnce(Entity<T>, &App) -> R,
4071 ) -> Result<R>
4072 where
4073 T: 'static,
4074 {
4075 let window = self
4076 .windows
4077 .get(window.id)
4078 .context("window not found")?
4079 .as_deref()
4080 .expect("attempted to read a window that is already on the stack");
4081
4082 let root_view = window.root.clone().unwrap();
4083 let view = root_view
4084 .downcast::<T>()
4085 .map_err(|_| anyhow!("root view's type has changed"))?;
4086
4087 Ok(read(view, self))
4088 }
4089
4090 fn background_spawn<R>(&self, future: impl Future<Output = R> + Send + 'static) -> Task<R>
4091 where
4092 R: Send + 'static,
4093 {
4094 self.background_executor.spawn(future)
4095 }
4096
4097 fn read_global<G, R>(&self, callback: impl FnOnce(&G, &App) -> R) -> R
4098 where
4099 G: Global,
4100 {
4101 let mut g = self.global::<G>();
4102 callback(g, self)
4103 }
4104
4105 fn insert_global_entity<T: 'static>(&mut self, entity: Entity<T>) {
4106 let any = entity.into_any();
4107 if !self.global_entities.contains(&any) {
4108 self.global_entities.push(any);
4109 }
4110 }
4111
4112 fn remove_global_entity<T: 'static>(&mut self, entity: &Entity<T>) {
4113 self.global_entities
4114 .retain(|any| any.entity_id() != entity.entity_id());
4115 }
4116
4117 fn global_entities<T: 'static>(&self) -> impl Iterator<Item = Entity<T>> {
4118 let mut iter = self.global_entities.iter();
4119 iter.filter_map(|any| any.clone().downcast::<T>().ok())
4120 }
4121}
4122
4123pub(crate) enum Effect {
4125 Notify {
4126 emitter: EntityId,
4127 },
4128 Emit {
4129 emitter: EntityId,
4130 event_type: TypeId,
4131 event: ArenaBox<dyn Any>,
4132 },
4133 RefreshWindows,
4134 NotifyGlobalObservers {
4135 global_type: TypeId,
4136 },
4137 Defer {
4138 callback: Box<dyn FnOnce(&mut App) + 'static>,
4139 },
4140 EntityCreated {
4141 entity: AnyEntity,
4142 tid: TypeId,
4143 window: Option<WindowId>,
4144 },
4145}
4146
4147impl std::fmt::Debug for Effect {
4148 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4149 match self {
4150 Effect::Notify { emitter } => write!(f, "Notify({})", emitter),
4151 Effect::Emit { emitter, .. } => write!(f, "Emit({:?})", emitter),
4152 Effect::RefreshWindows => write!(f, "RefreshWindows"),
4153 Effect::NotifyGlobalObservers { global_type } => {
4154 write!(f, "NotifyGlobalObservers({:?})", global_type)
4155 }
4156 Effect::Defer { .. } => write!(f, "Defer(..)"),
4157 Effect::EntityCreated { entity, .. } => write!(f, "EntityCreated({:?})", entity),
4158 }
4159 }
4160}
4161
4162pub(crate) struct GlobalLease<G: Global> {
4164 global: Box<dyn Any>,
4165 global_type: PhantomData<G>,
4166}
4167
4168impl<G: Global> GlobalLease<G> {
4169 fn new(global: Box<dyn Any>) -> Self {
4170 GlobalLease {
4171 global,
4172 global_type: PhantomData,
4173 }
4174 }
4175}
4176
4177impl<G: Global> Deref for GlobalLease<G> {
4178 type Target = G;
4179
4180 fn deref(&self) -> &Self::Target {
4181 self.global.downcast_ref().unwrap()
4182 }
4183}
4184
4185impl<G: Global> DerefMut for GlobalLease<G> {
4186 fn deref_mut(&mut self) -> &mut Self::Target {
4187 self.global.downcast_mut().unwrap()
4188 }
4189}
4190
4191#[derive(derive_setters::Setters)]
4196#[setters(generate = false)]
4197pub struct AnyDrag {
4198 pub view: AnyView,
4200
4201 pub value: Arc<dyn Any>,
4203
4204 #[setters(generate, rename = "offset")]
4206 pub cursor_offset: Point<Pixels>,
4207
4208 #[setters(generate)]
4210 pub cursor_style: Option<CursorStyle>,
4211
4212 pub external_payload_source: Option<ExternalDragPayloadSource>,
4215}
4216
4217impl AnyDrag {
4218 pub fn new<T: 'static + Sized>(value: T, view: impl Into<AnyView>) -> Self {
4220 Self {
4221 view: view.into(),
4222 value: Arc::new(value),
4223 cursor_offset: Point::default(),
4224 cursor_style: None,
4225 external_payload_source: None,
4226 }
4227 }
4228
4229 pub fn external_payload(
4231 mut self,
4232 predicate: impl FnOnce(&mut Window, &mut App) -> Option<ExternalDragPayload> + 'static,
4233 ) -> Self {
4234 self.external_payload_source = Some(Box::new(predicate));
4235 self
4236 }
4237
4238 pub fn is_type<T: 'static>(&self) -> bool {
4240 self.value.as_ref().type_id() == TypeId::of::<T>()
4241 }
4242}
4243
4244pub type ExternalDragPayloadSource =
4249 Box<dyn FnOnce(&mut Window, &mut App) -> Option<ExternalDragPayload> + 'static>;
4250
4251#[derive(Clone)]
4256pub struct AnyTooltip {
4257 pub view: AnyView,
4259
4260 pub mouse_position: Point<Pixels>,
4262
4263 pub check_visible_and_update: Rc<dyn Fn(Bounds<Pixels>, &mut Window, &mut App) -> bool>,
4267}
4268
4269#[derive(Clone, Copy, Debug, Eq, PartialEq)]
4271pub enum InputPreference {
4272 CharacterInput,
4274 KeyBindings,
4276}
4277
4278#[derive(Debug)]
4282pub struct KeystrokeEvent {
4283 pub keystroke: Keystroke,
4285
4286 pub input_preference: InputPreference,
4294
4295 pub action: Option<Box<dyn Action>>,
4298
4299 pub context_stack: Vec<KeyContext>,
4301}
4302
4303pub struct GpuiBorrow<'a, T> {
4305 inner: Option<Lease<T>>,
4306 app: &'a mut App,
4307}
4308
4309impl<'a, T: 'static> GpuiBorrow<'a, T> {
4310 fn new(inner: Entity<T>, app: &'a mut App) -> Self {
4311 app.start_update();
4312 let lease = app.entities.lease(&inner);
4313 Self {
4314 inner: Some(lease),
4315 app,
4316 }
4317 }
4318}
4319
4320impl<'a, T: 'static> std::borrow::Borrow<T> for GpuiBorrow<'a, T> {
4321 fn borrow(&self) -> &T {
4322 self.inner.as_ref().unwrap().borrow()
4323 }
4324}
4325
4326impl<'a, T: 'static> std::borrow::BorrowMut<T> for GpuiBorrow<'a, T> {
4327 fn borrow_mut(&mut self) -> &mut T {
4328 self.inner.as_mut().unwrap().borrow_mut()
4329 }
4330}
4331
4332impl<'a, T: 'static> std::ops::Deref for GpuiBorrow<'a, T> {
4333 type Target = T;
4334
4335 fn deref(&self) -> &Self::Target {
4336 self.inner.as_ref().unwrap()
4337 }
4338}
4339
4340impl<'a, T: 'static> std::ops::DerefMut for GpuiBorrow<'a, T> {
4341 fn deref_mut(&mut self) -> &mut T {
4342 self.inner.as_mut().unwrap()
4343 }
4344}
4345
4346impl<'a, T> Drop for GpuiBorrow<'a, T> {
4347 fn drop(&mut self) {
4348 let lease = self.inner.take().unwrap();
4349 self.app.notify(lease.id);
4350 self.app.entities.end_lease(lease);
4351 self.app.finish_update();
4352 }
4353}
4354
4355#[cfg(test)]
4356mod test {
4357 use std::{
4358 cell::{Cell, RefCell},
4359 ffi::OsString,
4360 path::PathBuf,
4361 rc::Rc,
4362 };
4363
4364 #[cfg(unix)]
4365 use std::os::unix::ffi::OsStringExt;
4366
4367 use crate::{AppContext, Context, Empty, IntoElement, Render, TestAppContext, Window};
4368
4369 struct RenderCounter(Rc<Cell<usize>>);
4370
4371 impl Render for RenderCounter {
4372 fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
4373 self.0.set(self.0.get() + 1);
4374 Empty
4375 }
4376 }
4377
4378 #[gpui::test]
4379 fn async_app_refresh_flushes_refresh_effect(cx: &mut TestAppContext) {
4380 let render_count = Rc::new(Cell::new(0));
4381
4382 let _window = cx.add_window({
4383 let render_count = render_count.clone();
4384 move |_, _| RenderCounter(render_count)
4385 });
4386
4387 cx.run_until_parked();
4388 let render_count_before_refresh = render_count.get();
4389
4390 cx.to_async().refresh();
4391
4392 assert_eq!(render_count.get(), render_count_before_refresh + 1);
4393 }
4394
4395 #[test]
4396 fn embedded_update_flushes_effects() {
4397 let cx = TestAppContext::single();
4398 let handle = super::ApplicationHandle { app: cx.app };
4399 let completed = Rc::new(Cell::new(false));
4400
4401 handle.update(|cx| {
4402 cx.defer({
4403 let completed = completed.clone();
4404 move |_| completed.set(true)
4405 });
4406 });
4407
4408 assert!(completed.get());
4409 }
4410
4411 #[gpui::test]
4412 fn nested_update_defers_new_effects_until_current_effect_returns(cx: &mut TestAppContext) {
4413 let order = Rc::new(RefCell::new(Vec::new()));
4414 cx.update({
4415 let order = order.clone();
4416 move |cx| {
4417 cx.defer(move |cx| {
4418 order.borrow_mut().push("outer-start");
4419 cx.update({
4420 let order = order.clone();
4421 |cx| {
4422 cx.defer(move |_| order.borrow_mut().push("nested"));
4423 }
4424 });
4425 order.borrow_mut().push("outer-end");
4426 });
4427 }
4428 });
4429
4430 assert_eq!(*order.borrow(), ["outer-start", "outer-end", "nested"]);
4431 }
4432
4433 #[gpui::test]
4434 fn adding_a_tab_group_after_removal_preserves_other_groups(cx: &mut TestAppContext) {
4435 use super::{SystemWindowTab, SystemWindowTabController};
4436
4437 let windows: Vec<_> = (0..4).map(|_| cx.add_window(|_, _| Empty)).collect();
4438 cx.update(|cx| {
4439 for (ix, window) in windows.iter().take(3).enumerate() {
4440 SystemWindowTabController::add_tab(
4441 cx,
4442 window.window_id(),
4443 vec![SystemWindowTab::new(
4444 format!("Window {ix}").into(),
4445 (*window).into(),
4446 )],
4447 );
4448 }
4449 SystemWindowTabController::remove_tab(cx, windows[0].window_id());
4450 SystemWindowTabController::add_tab(
4451 cx,
4452 windows[3].window_id(),
4453 vec![SystemWindowTab::new("New window".into(), windows[3].into())],
4454 );
4455
4456 let controller = cx.global::<SystemWindowTabController>();
4457 assert_eq!(controller.tab_groups.len(), 3);
4458 for window in &windows[1..] {
4459 assert_eq!(controller.tabs(window.window_id()).unwrap().len(), 1);
4460 }
4461 });
4462 }
4463
4464 #[gpui::test]
4465 fn drag_type_matches_the_payload(cx: &mut TestAppContext) {
4466 cx.update(|cx| {
4467 let view = cx.new(|_| Empty);
4468 let drag = super::AnyDrag::new(String::from("row"), view);
4469 assert!(drag.is_type::<String>());
4470 assert!(!drag.is_type::<usize>());
4471 assert!(!drag.is_type::<std::sync::Arc<dyn std::any::Any>>());
4472 });
4473 }
4474
4475 #[test]
4476 fn test_gpui_borrow() {
4477 let cx = TestAppContext::single();
4478 let observation_count = Rc::new(RefCell::new(0));
4479
4480 let state = cx.update(|cx| {
4481 let state = cx.new(|_| false);
4482 cx.observe(&state, {
4483 let observation_count = observation_count.clone();
4484 move |_, _| {
4485 let mut count = observation_count.borrow_mut();
4486 *count += 1;
4487 }
4488 })
4489 .detach();
4490
4491 state
4492 });
4493
4494 cx.update(|cx| {
4495 *std::borrow::BorrowMut::borrow_mut(&mut state.as_mut(cx)) = true;
4497 });
4498
4499 cx.update(|cx| {
4500 state.write(cx, false);
4501 });
4502
4503 assert_eq!(*observation_count.borrow(), 2);
4504 }
4505
4506 #[gpui::test]
4507 async fn test_restart_preserves_path_and_arguments(cx: &mut TestAppContext) {
4508 #[cfg(unix)]
4509 let user_data_dir = OsString::from_vec(b"/tmp/zed data/\xff".to_vec());
4510 #[cfg(not(unix))]
4511 let user_data_dir = OsString::from("C:\\zed data");
4512 let arguments = vec![OsString::from("--user-data-dir"), user_data_dir];
4513 let restart_path = PathBuf::from("updated-zed");
4514 let _application =
4515 super::Application(cx.app.clone()).with_restart_arguments(arguments.clone());
4516 let restart = cx.expect_restart();
4517
4518 cx.update(|cx| {
4519 cx.set_restart_path(restart_path.clone());
4520 cx.restart();
4521 });
4522
4523 let (path, restart_arguments) = restart.await.expect("restart was not requested");
4524 assert_eq!(path, Some(restart_path));
4525 assert_eq!(restart_arguments, arguments);
4526 }
4527}