1use scheduler::Instant;
2use std::{
3 any::{TypeId, type_name},
4 cell::{BorrowMutError, Cell, Ref, RefCell, RefMut},
5 marker::PhantomData,
6 mem,
7 ops::{Deref, DerefMut},
8 path::{Path, PathBuf},
9 rc::{Rc, Weak},
10 sync::{Arc, atomic::Ordering::SeqCst},
11 time::Duration,
12};
13
14use anyhow::{Context as _, Result, anyhow};
15use derive_more::{Deref, DerefMut};
16use futures::{
17 Future, FutureExt,
18 channel::oneshot,
19 future::{LocalBoxFuture, Shared},
20};
21use itertools::Itertools;
22use parking_lot::RwLock;
23use slotmap::SlotMap;
24
25pub use async_context::*;
26#[cfg(feature = "bench")]
27pub use bench_context::{BenchAppContext, BenchReport, BenchWindowContext, bench_platform};
28use collections::{FxHashMap, FxHashSet, HashMap, TypeIdHashMap, TypeIdHashSet, VecDeque};
29pub use context::*;
30pub use entity_map::*;
31use gpui_util::{ResultExt, debug_panic};
32#[cfg(any(test, feature = "test-support"))]
33pub use headless_app_context::*;
34use http_client::{HttpClient, Url};
35use smallvec::SmallVec;
36#[cfg(any(test, feature = "test-support"))]
37pub use test_app::*;
38#[cfg(any(test, feature = "test-support"))]
39pub use test_context::*;
40#[cfg(all(target_os = "macos", any(test, feature = "test-support")))]
41pub use visual_test_context::*;
42
43#[cfg(any(feature = "inspector", debug_assertions))]
44use crate::InspectorElementRegistry;
45use crate::{
46 Action, ActionBuildError, ActionRegistry, Any, AnyView, AnyWindowHandle, AppContext, Arena,
47 ArenaBox, Asset, AssetSource, BackgroundExecutor, Bounds, ClipboardItem, CursorStyle,
48 DispatchPhase, DisplayId, EventEmitter, ExternalDragPayload, FocusHandle, FocusMap,
49 ForegroundExecutor, Global, KeyBinding, KeyContext, Keymap, Keystroke, LayoutId, Menu,
50 MenuItem, OwnedMenu, PathPromptOptions, Pixels, Platform, PlatformDisplay,
51 PlatformKeyboardLayout, PlatformKeyboardMapper, Point, Priority, PromptBuilder, PromptButton,
52 PromptHandle, PromptLevel, Render, RenderImage, RenderablePromptHandle, Reservation,
53 ScreenCaptureSource, SharedString, SubscriberSet, Subscription, SvgRenderer,
54 SystemNotification, SystemNotificationResponse, Task, TextRenderingMode, TextSystem,
55 ThermalState, Window, WindowAppearance, WindowButtonLayout, WindowHandle, WindowId,
56 WindowInvalidator,
57 colors::{Colors, GlobalColors},
58 hash, init_app_menus,
59};
60
61mod async_context;
62#[cfg(feature = "bench")]
63mod bench_context;
64mod context;
65mod entity_map;
66#[cfg(any(test, feature = "test-support"))]
67mod headless_app_context;
68#[cfg(any(test, feature = "test-support"))]
69mod test_app;
70#[cfg(any(test, feature = "test-support"))]
71mod test_context;
72#[cfg(all(target_os = "macos", any(test, feature = "test-support")))]
73mod visual_test_context;
74
75pub const SHUTDOWN_TIMEOUT: Duration = Duration::from_millis(200);
77
78#[doc(hidden)]
81pub struct AppCell {
82 app: RefCell<App>,
83}
84
85impl AppCell {
86 #[doc(hidden)]
87 #[track_caller]
88 pub fn borrow(&self) -> AppRef<'_> {
89 if option_env!("TRACK_THREAD_BORROWS").is_some() {
90 let thread_id = std::thread::current().id();
91 eprintln!("borrowed {thread_id:?}");
92 }
93 AppRef(self.app.borrow())
94 }
95
96 #[doc(hidden)]
97 #[track_caller]
98 pub fn borrow_mut(&self) -> AppRefMut<'_> {
99 if option_env!("TRACK_THREAD_BORROWS").is_some() {
100 let thread_id = std::thread::current().id();
101 eprintln!("borrowed {thread_id:?}");
102 }
103 AppRefMut(self.app.borrow_mut())
104 }
105
106 #[doc(hidden)]
107 #[track_caller]
108 pub fn try_borrow_mut(&self) -> Result<AppRefMut<'_>, BorrowMutError> {
109 if option_env!("TRACK_THREAD_BORROWS").is_some() {
110 let thread_id = std::thread::current().id();
111 eprintln!("borrowed {thread_id:?}");
112 }
113 Ok(AppRefMut(self.app.try_borrow_mut()?))
114 }
115}
116
117#[doc(hidden)]
118#[derive(Deref, DerefMut)]
119pub struct AppRef<'a>(Ref<'a, App>);
120
121impl Drop for AppRef<'_> {
122 fn drop(&mut self) {
123 if option_env!("TRACK_THREAD_BORROWS").is_some() {
124 let thread_id = std::thread::current().id();
125 eprintln!("dropped borrow from {thread_id:?}");
126 }
127 }
128}
129
130#[doc(hidden)]
131#[derive(Deref, DerefMut)]
132pub struct AppRefMut<'a>(RefMut<'a, App>);
133
134impl Drop for AppRefMut<'_> {
135 fn drop(&mut self) {
136 if option_env!("TRACK_THREAD_BORROWS").is_some() {
137 let thread_id = std::thread::current().id();
138 eprintln!("dropped {thread_id:?}");
139 }
140 }
141}
142
143pub struct Application(Rc<AppCell>);
146
147pub struct ApplicationHandle {
153 app: Rc<AppCell>,
154}
155
156impl ApplicationHandle {
157 pub fn update<R>(&self, f: impl FnOnce(&mut App) -> R) -> R {
161 let cx = &mut *self.app.borrow_mut();
162 f(cx)
163 }
164
165 pub fn to_async(&self) -> AsyncApp {
168 self.update(|cx| cx.to_async())
169 }
170}
171
172impl Application {
175 pub fn with_platform(platform: Rc<dyn Platform>) -> Self {
177 Self(App::new_app(
178 platform,
179 Arc::new(()),
180 Arc::new(NullHttpClient),
181 ))
182 }
183
184 pub fn new_inaccessible(platform: Rc<dyn Platform>) -> Self {
194 let this = Self::with_platform(platform);
195 this.0.borrow_mut().accessibility_force_disabled = true;
196 this
197 }
198
199 pub fn with_assets(self, asset_source: impl AssetSource) -> Self {
201 let mut context_lock = self.0.borrow_mut();
202 let asset_source = Arc::new(asset_source);
203 context_lock.asset_source = asset_source.clone();
204 context_lock.svg_renderer = SvgRenderer::new(asset_source);
205 drop(context_lock);
206 self
207 }
208
209 pub fn with_http_client(self, http_client: Arc<dyn HttpClient>) -> Self {
211 let mut context_lock = self.0.borrow_mut();
212 context_lock.http_client = http_client;
213 drop(context_lock);
214 self
215 }
216
217 pub fn with_quit_mode(self, mode: QuitMode) -> Self {
220 self.0.borrow_mut().quit_mode = mode;
221 self
222 }
223
224 pub fn run<F>(self, on_finish_launching: F)
227 where
228 F: 'static + FnOnce(&mut App),
229 {
230 let this = self.0.clone();
231 let platform = self.0.borrow().platform.clone();
232 platform.run(Box::new(move || {
233 let cx = &mut *this.borrow_mut();
234 on_finish_launching(cx);
235 }));
236 }
237
238 pub fn run_embedded<F>(self, on_finish_launching: F) -> ApplicationHandle
248 where
249 F: 'static + FnOnce(&mut App),
250 {
251 let this = self.0.clone();
252 let platform = self.0.borrow().platform.clone();
253 platform.run(Box::new(move || {
254 let cx = &mut *this.borrow_mut();
255 on_finish_launching(cx);
256 }));
257 ApplicationHandle { app: self.0 }
258 }
259
260 pub fn on_open_urls<F>(&self, mut callback: F) -> &Self
263 where
264 F: 'static + FnMut(Vec<String>),
265 {
266 self.0.borrow().platform.on_open_urls(Box::new(callback));
267 self
268 }
269
270 pub fn on_reopen<F>(&self, mut callback: F) -> &Self
273 where
274 F: 'static + FnMut(&mut App),
275 {
276 let this = Rc::downgrade(&self.0);
277 self.0.borrow_mut().platform.on_reopen(Box::new(move || {
278 if let Some(app) = this.upgrade() {
279 callback(&mut app.borrow_mut());
280 }
281 }));
282 self
283 }
284
285 pub fn on_system_wake<F>(&self, mut callback: F) -> &Self
287 where
288 F: 'static + FnMut(&mut App),
289 {
290 let this = Rc::downgrade(&self.0);
291 self.0
292 .borrow_mut()
293 .platform
294 .on_system_wake(Box::new(move || {
295 if let Some(app) = this.upgrade() {
296 callback(&mut app.borrow_mut());
297 }
298 }));
299 self
300 }
301
302 pub fn background_executor(&self) -> BackgroundExecutor {
304 self.0.borrow().background_executor.clone()
305 }
306
307 pub fn foreground_executor(&self) -> ForegroundExecutor {
309 self.0.borrow().foreground_executor.clone()
310 }
311
312 pub fn text_system(&self) -> Arc<TextSystem> {
314 self.0.borrow().text_system.clone()
315 }
316
317 pub fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf> {
319 self.0.borrow().path_for_auxiliary_executable(name)
320 }
321}
322
323type Handler = Box<dyn FnMut(&mut App) -> bool + 'static>;
324type Listener = Box<dyn FnMut(&dyn Any, &mut App) -> bool + 'static>;
325pub(crate) type KeystrokeObserver =
326 Box<dyn FnMut(&KeystrokeEvent, &mut Window, &mut App) -> bool + 'static>;
327type QuitHandler = Box<dyn FnOnce(&mut App) -> LocalBoxFuture<'static, ()> + 'static>;
328type WindowClosedHandler = Box<dyn FnMut(&mut App, WindowId)>;
329type ReleaseListener = Box<dyn FnOnce(&mut dyn Any, &mut App) + 'static>;
330type NewEntityListener = Box<dyn FnMut(AnyEntity, &mut Option<&mut Window>, &mut App) + 'static>;
331
332#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
334pub enum QuitMode {
335 #[default]
337 Default,
338 LastWindowClosed,
340 Explicit,
342}
343
344#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
349pub enum CursorHideMode {
350 Never,
352 OnTyping,
354 #[default]
357 OnTypingAndAction,
358}
359
360#[doc(hidden)]
361#[derive(Clone, PartialEq, Eq)]
362pub struct SystemWindowTab {
363 pub id: WindowId,
364 pub title: SharedString,
365 pub handle: AnyWindowHandle,
366 pub last_active_at: Instant,
367}
368
369impl SystemWindowTab {
370 pub fn new(title: SharedString, handle: AnyWindowHandle) -> Self {
372 Self {
373 id: handle.id,
374 title,
375 handle,
376 last_active_at: Instant::now(),
377 }
378 }
379}
380
381#[derive(Default)]
383pub struct SystemWindowTabController {
384 visible: Option<bool>,
385 tab_groups: FxHashMap<usize, Vec<SystemWindowTab>>,
386}
387
388impl Global for SystemWindowTabController {}
389
390impl SystemWindowTabController {
391 pub fn new() -> Self {
393 Self {
394 visible: None,
395 tab_groups: FxHashMap::default(),
396 }
397 }
398
399 pub fn init(cx: &mut App) {
401 cx.set_global(SystemWindowTabController::new());
402 }
403
404 pub fn tab_groups(&self) -> &FxHashMap<usize, Vec<SystemWindowTab>> {
406 &self.tab_groups
407 }
408
409 pub fn get_next_tab_group_window(cx: &mut App, id: WindowId) -> Option<&AnyWindowHandle> {
411 let controller = cx.global::<SystemWindowTabController>();
412 let current_group = controller
413 .tab_groups
414 .iter()
415 .find_map(|(group, tabs)| tabs.iter().find(|tab| tab.id == id).map(|_| group));
416
417 let current_group = current_group?;
418 let mut group_ids: Vec<_> = controller.tab_groups.keys().collect();
420 let idx = group_ids.iter().position(|g| *g == current_group)?;
421 let next_idx = (idx + 1) % group_ids.len();
422
423 controller
424 .tab_groups
425 .get(group_ids[next_idx])
426 .and_then(|tabs| {
427 tabs.iter()
428 .max_by_key(|tab| tab.last_active_at)
429 .or_else(|| tabs.first())
430 .map(|tab| &tab.handle)
431 })
432 }
433
434 pub fn get_prev_tab_group_window(cx: &mut App, id: WindowId) -> Option<&AnyWindowHandle> {
436 let controller = cx.global::<SystemWindowTabController>();
437 let current_group = controller
438 .tab_groups
439 .iter()
440 .find_map(|(group, tabs)| tabs.iter().find(|tab| tab.id == id).map(|_| group));
441
442 let current_group = current_group?;
443 let mut group_ids: Vec<_> = controller.tab_groups.keys().collect();
445 let idx = group_ids.iter().position(|g| *g == current_group)?;
446 let prev_idx = if idx == 0 {
447 group_ids.len() - 1
448 } else {
449 idx - 1
450 };
451
452 controller
453 .tab_groups
454 .get(group_ids[prev_idx])
455 .and_then(|tabs| {
456 tabs.iter()
457 .max_by_key(|tab| tab.last_active_at)
458 .or_else(|| tabs.first())
459 .map(|tab| &tab.handle)
460 })
461 }
462
463 pub fn tabs(&self, id: WindowId) -> Option<&Vec<SystemWindowTab>> {
465 self.tab_groups
466 .values()
467 .find(|tabs| tabs.iter().any(|tab| tab.id == id))
468 }
469
470 pub fn init_visible(cx: &mut App, visible: bool) {
472 let mut controller = cx.global_mut::<SystemWindowTabController>();
473 if controller.visible.is_none() {
474 controller.visible = Some(visible);
475 }
476 }
477
478 pub fn is_visible(&self) -> bool {
480 self.visible.unwrap_or(false)
481 }
482
483 pub fn set_visible(cx: &mut App, visible: bool) {
485 let mut controller = cx.global_mut::<SystemWindowTabController>();
486 controller.visible = Some(visible);
487 }
488
489 pub fn update_last_active(cx: &mut App, id: WindowId) {
491 let mut controller = cx.global_mut::<SystemWindowTabController>();
492 for windows in controller.tab_groups.values_mut() {
493 for tab in windows.iter_mut() {
494 if tab.id == id {
495 tab.last_active_at = Instant::now();
496 }
497 }
498 }
499 }
500
501 pub fn update_tab_position(cx: &mut App, id: WindowId, ix: usize) {
503 let mut controller = cx.global_mut::<SystemWindowTabController>();
504 for (_, windows) in controller.tab_groups.iter_mut() {
505 if let Some(current_pos) = windows.iter().position(|tab| tab.id == id) {
506 if ix < windows.len() && current_pos != ix {
507 let window_tab = windows.remove(current_pos);
508 windows.insert(ix, window_tab);
509 }
510 break;
511 }
512 }
513 }
514
515 pub fn update_tab_title(cx: &mut App, id: WindowId, title: SharedString) {
517 let controller = cx.global::<SystemWindowTabController>();
518 let tab = controller
519 .tab_groups
520 .values()
521 .flat_map(|windows| windows.iter())
522 .find(|tab| tab.id == id);
523
524 if tab.map_or(true, |t| t.title == title) {
525 return;
526 }
527
528 let mut controller = cx.global_mut::<SystemWindowTabController>();
529 for windows in controller.tab_groups.values_mut() {
530 for tab in windows.iter_mut() {
531 if tab.id == id {
532 tab.title = title;
533 return;
534 }
535 }
536 }
537 }
538
539 pub fn add_tab(cx: &mut App, id: WindowId, tabs: Vec<SystemWindowTab>) {
541 let mut controller = cx.global_mut::<SystemWindowTabController>();
542 let Some(tab) = tabs.iter().find(|tab| tab.id == id).cloned() else {
543 return;
544 };
545
546 let mut expected_tab_ids: Vec<_> = tabs
547 .iter()
548 .filter(|tab| tab.id != id)
549 .map(|tab| tab.id)
550 .sorted()
551 .collect();
552
553 let mut tab_group_id = None;
554 for (group_id, group_tabs) in &controller.tab_groups {
555 let tab_ids: Vec<_> = group_tabs.iter().map(|tab| tab.id).sorted().collect();
556 if tab_ids == expected_tab_ids {
557 tab_group_id = Some(*group_id);
558 break;
559 }
560 }
561
562 if let Some(tab_group_id) = tab_group_id {
563 if let Some(tabs) = controller.tab_groups.get_mut(&tab_group_id) {
564 tabs.push(tab);
565 }
566 } else {
567 let new_group_id = controller.tab_groups.len();
568 controller.tab_groups.insert(new_group_id, tabs);
569 }
570 }
571
572 pub fn remove_tab(cx: &mut App, id: WindowId) -> Option<SystemWindowTab> {
574 let mut controller = cx.global_mut::<SystemWindowTabController>();
575 let mut removed_tab = None;
576
577 controller.tab_groups.retain(|_, tabs| {
578 if let Some(pos) = tabs.iter().position(|tab| tab.id == id) {
579 removed_tab = Some(tabs.remove(pos));
580 }
581 !tabs.is_empty()
582 });
583
584 removed_tab
585 }
586
587 pub fn move_tab_to_new_window(cx: &mut App, id: WindowId) {
589 let mut removed_tab = Self::remove_tab(cx, id);
590 let mut controller = cx.global_mut::<SystemWindowTabController>();
591
592 if let Some(tab) = removed_tab {
593 let new_group_id = controller.tab_groups.keys().max().map_or(0, |k| k + 1);
594 controller.tab_groups.insert(new_group_id, vec![tab]);
595 }
596 }
597
598 pub fn merge_all_windows(cx: &mut App, id: WindowId) {
600 let mut controller = cx.global_mut::<SystemWindowTabController>();
601 let Some(initial_tabs) = controller.tabs(id) else {
602 return;
603 };
604
605 let initial_tabs_len = initial_tabs.len();
606 let mut all_tabs = initial_tabs.clone();
607
608 for (_, mut tabs) in controller.tab_groups.drain() {
609 tabs.retain(|tab| !all_tabs[..initial_tabs_len].contains(tab));
610 all_tabs.extend(tabs);
611 }
612
613 controller.tab_groups.insert(0, all_tabs);
614 }
615
616 pub fn select_next_tab(cx: &mut App, id: WindowId) {
618 let mut controller = cx.global_mut::<SystemWindowTabController>();
619 let Some(tabs) = controller.tabs(id) else {
620 return;
621 };
622
623 let current_index = tabs.iter().position(|tab| tab.id == id).unwrap();
624 let next_index = (current_index + 1) % tabs.len();
625
626 let _ = &tabs[next_index].handle.update(cx, |_, window, _| {
627 window.activate_window();
628 });
629 }
630
631 pub fn select_previous_tab(cx: &mut App, id: WindowId) {
633 let mut controller = cx.global_mut::<SystemWindowTabController>();
634 let Some(tabs) = controller.tabs(id) else {
635 return;
636 };
637
638 let current_index = tabs.iter().position(|tab| tab.id == id).unwrap();
639 let previous_index = if current_index == 0 {
640 tabs.len() - 1
641 } else {
642 current_index - 1
643 };
644
645 let _ = &tabs[previous_index].handle.update(cx, |_, window, _| {
646 window.activate_window();
647 });
648 }
649}
650
651pub(crate) enum GpuiMode {
652 #[cfg(any(test, feature = "test-support"))]
653 Test {
654 skip_drawing: bool,
655 },
656 Production,
657}
658
659impl GpuiMode {
660 #[cfg(any(test, feature = "test-support"))]
661 pub fn test() -> Self {
662 GpuiMode::Test {
663 skip_drawing: false,
664 }
665 }
666
667 #[inline]
668 pub(crate) fn skip_drawing(&self) -> bool {
669 match self {
670 #[cfg(any(test, feature = "test-support"))]
671 GpuiMode::Test { skip_drawing } => *skip_drawing,
672 GpuiMode::Production => false,
673 }
674 }
675}
676
677struct PlatformOwnedDrag {
678 source_window: WindowId,
679 state: PlatformOwnedDragState,
680}
681
682enum PlatformOwnedDragState {
683 Suspended(AnyDrag),
684 RestoredInSourceWindow,
687}
688
689pub struct App {
693 pub(crate) this: Weak<AppCell>,
694 pub(crate) platform: Rc<dyn Platform>,
695 text_system: Arc<TextSystem>,
696
697 pub(crate) actions: Rc<ActionRegistry>,
698 pub(crate) active_drag: Option<AnyDrag>,
699 platform_owned_drag: Option<PlatformOwnedDrag>,
700 pub(crate) background_executor: BackgroundExecutor,
701 pub(crate) foreground_executor: ForegroundExecutor,
702 pub(crate) entities: EntityMap,
703 pub(crate) new_entity_observers: SubscriberSet<TypeId, NewEntityListener>,
704 pub(crate) windows: SlotMap<WindowId, Option<Box<Window>>>,
705 pub(crate) window_handles: FxHashMap<WindowId, AnyWindowHandle>,
706 pub(crate) focus_handles: Arc<FocusMap>,
707 pub(crate) keymap: Rc<RefCell<Keymap>>,
708 pub(crate) keyboard_layout: Box<dyn PlatformKeyboardLayout>,
709 pub(crate) keyboard_mapper: Rc<dyn PlatformKeyboardMapper>,
710 pub(crate) global_action_listeners:
711 TypeIdHashMap<Vec<Rc<dyn Fn(&dyn Any, DispatchPhase, &mut Self)>>>,
712 pending_effects: VecDeque<Effect>,
713
714 pub(crate) observers: SubscriberSet<EntityId, Handler>,
715 pub(crate) event_listeners: SubscriberSet<EntityId, (TypeId, Listener)>,
716 pub(crate) keystroke_observers: SubscriberSet<(), KeystrokeObserver>,
717 pub(crate) keystroke_interceptors: SubscriberSet<(), KeystrokeObserver>,
718 pub(crate) keyboard_layout_observers: SubscriberSet<(), Handler>,
719 pub(crate) thermal_state_observers: SubscriberSet<(), Handler>,
720 pub(crate) release_listeners: SubscriberSet<EntityId, ReleaseListener>,
721 pub(crate) global_observers: SubscriberSet<TypeId, Handler>,
722 pub(crate) quit_observers: SubscriberSet<(), QuitHandler>,
723 pub(crate) restart_observers: SubscriberSet<(), Handler>,
724 pub(crate) window_closed_observers: SubscriberSet<(), WindowClosedHandler>,
725
726 pub(crate) element_arena: RefCell<Arena>,
729 pub(crate) event_arena: Arena,
731
732 pub(crate) globals_by_type: TypeIdHashMap<Box<dyn Any>>,
737
738 pub(crate) loading_assets: FxHashMap<(TypeId, u64), Box<dyn Any>>,
740 asset_source: Arc<dyn AssetSource>,
741 pub(crate) svg_renderer: SvgRenderer,
742 http_client: Arc<dyn HttpClient>,
743
744 pub(crate) pending_notifications: FxHashSet<EntityId>,
746 pub(crate) pending_global_notifications: TypeIdHashSet,
747 pub(crate) restart_path: Option<PathBuf>,
748 pub(crate) layout_id_buffer: Vec<LayoutId>, pub(crate) propagate_event: bool,
750 pub(crate) prompt_builder: Option<PromptBuilder>,
751 pub(crate) window_invalidators_by_entity:
752 FxHashMap<EntityId, FxHashMap<WindowId, WindowInvalidator>>,
753 pub(crate) tracked_entities: FxHashMap<WindowId, FxHashSet<EntityId>>,
754 pub(crate) current_window_by_entity: FxHashMap<EntityId, WindowId>,
755 #[cfg(any(feature = "inspector", debug_assertions))]
756 pub(crate) inspector_renderer: Option<crate::InspectorRenderer>,
757 #[cfg(any(feature = "inspector", debug_assertions))]
758 pub(crate) inspector_element_registry: InspectorElementRegistry,
759 #[cfg(any(test, feature = "test-support", debug_assertions))]
760 pub(crate) name: Option<&'static str>,
761 pub(crate) text_rendering_mode: Rc<Cell<TextRenderingMode>>,
762
763 pub(crate) window_update_stack: Vec<WindowId>,
764 pub(crate) mode: GpuiMode,
765 pub(crate) cursor_hide_mode: CursorHideMode,
766 pub(crate) reduce_motion: bool,
767 pub(crate) accessibility_force_disabled: bool,
770 flushing_effects: bool,
771 pending_updates: usize,
772 quit_mode: QuitMode,
773 quitting: bool,
774
775 #[cfg(any(test, feature = "leak-detection"))]
778 _ref_counts: Arc<RwLock<EntityRefCounts>>,
779}
780
781impl App {
782 #[allow(clippy::new_ret_no_self)]
783 pub(crate) fn new_app(
784 platform: Rc<dyn Platform>,
785 asset_source: Arc<dyn AssetSource>,
786 http_client: Arc<dyn HttpClient>,
787 ) -> Rc<AppCell> {
788 let background_executor = platform.background_executor();
789 let foreground_executor = platform.foreground_executor();
790 assert!(
791 background_executor.is_main_thread(),
792 "must construct App on main thread"
793 );
794
795 let text_system = Arc::new(TextSystem::new(platform.text_system()));
796 let entities = EntityMap::new();
797 let keyboard_layout = platform.keyboard_layout();
798 let keyboard_mapper = platform.keyboard_mapper();
799
800 #[cfg(any(test, feature = "leak-detection"))]
801 let _ref_counts = entities.ref_counts_drop_handle();
802
803 let app = Rc::new_cyclic(|this| AppCell {
804 app: RefCell::new(App {
805 this: this.clone(),
806 platform: platform.clone(),
807 text_system,
808 text_rendering_mode: Rc::new(Cell::new(TextRenderingMode::default())),
809 mode: GpuiMode::Production,
810 actions: Rc::new(ActionRegistry::default()),
811 flushing_effects: false,
812 pending_updates: 0,
813 active_drag: None,
814 platform_owned_drag: None,
815 background_executor,
816 foreground_executor,
817 svg_renderer: SvgRenderer::new(asset_source.clone()),
818 loading_assets: Default::default(),
819 asset_source,
820 http_client,
821 globals_by_type: Default::default(),
822 entities,
823 new_entity_observers: SubscriberSet::new(),
824 windows: SlotMap::with_key(),
825 window_update_stack: Vec::new(),
826 window_handles: FxHashMap::default(),
827 focus_handles: Arc::new(RwLock::new(SlotMap::with_key())),
828 keymap: Rc::new(RefCell::new(Keymap::default())),
829 keyboard_layout,
830 keyboard_mapper,
831 global_action_listeners: Default::default(),
832 pending_effects: VecDeque::new(),
833 pending_notifications: FxHashSet::default(),
834 pending_global_notifications: Default::default(),
835 observers: SubscriberSet::new(),
836 tracked_entities: FxHashMap::default(),
837 window_invalidators_by_entity: FxHashMap::default(),
838 current_window_by_entity: FxHashMap::default(),
839 event_listeners: SubscriberSet::new(),
840 release_listeners: SubscriberSet::new(),
841 keystroke_observers: SubscriberSet::new(),
842 keystroke_interceptors: SubscriberSet::new(),
843 keyboard_layout_observers: SubscriberSet::new(),
844 thermal_state_observers: SubscriberSet::new(),
845 global_observers: SubscriberSet::new(),
846 quit_observers: SubscriberSet::new(),
847 restart_observers: SubscriberSet::new(),
848 restart_path: None,
849 window_closed_observers: SubscriberSet::new(),
850 layout_id_buffer: Default::default(),
851 propagate_event: true,
852 prompt_builder: Some(PromptBuilder::Default),
853 #[cfg(any(feature = "inspector", debug_assertions))]
854 inspector_renderer: None,
855 #[cfg(any(feature = "inspector", debug_assertions))]
856 inspector_element_registry: InspectorElementRegistry::default(),
857 quit_mode: QuitMode::default(),
858 quitting: false,
859 cursor_hide_mode: CursorHideMode::default(),
860 reduce_motion: false,
861 accessibility_force_disabled: false,
862
863 #[cfg(any(test, feature = "test-support", debug_assertions))]
864 name: None,
865 element_arena: RefCell::new(Arena::new(1024 * 1024)),
866 event_arena: Arena::new(1024 * 1024),
867
868 #[cfg(any(test, feature = "leak-detection"))]
869 _ref_counts,
870 }),
871 });
872
873 init_app_menus(platform.as_ref(), &app.borrow());
874 SystemWindowTabController::init(&mut app.borrow_mut());
875
876 platform.on_keyboard_layout_change(Box::new({
877 let app = Rc::downgrade(&app);
878 move || {
879 if let Some(app) = app.upgrade() {
880 let cx = &mut app.borrow_mut();
881 cx.keyboard_layout = cx.platform.keyboard_layout();
882 cx.keyboard_mapper = cx.platform.keyboard_mapper();
883 cx.keyboard_layout_observers
884 .clone()
885 .retain(&(), move |callback| (callback)(cx));
886 }
887 }
888 }));
889
890 platform.on_thermal_state_change(Box::new({
891 let app = Rc::downgrade(&app);
892 move || {
893 if let Some(app) = app.upgrade() {
894 let cx = &mut app.borrow_mut();
895 cx.thermal_state_observers
896 .clone()
897 .retain(&(), move |callback| (callback)(cx));
898 }
899 }
900 }));
901
902 platform.on_quit(Box::new({
903 let cx = Rc::downgrade(&app);
904 move || {
905 if let Some(cx) = cx.upgrade() {
906 cx.borrow_mut().shutdown();
907 }
908 }
909 }));
910
911 app
912 }
913
914 #[doc(hidden)]
915 pub fn ref_counts_drop_handle(&self) -> impl Sized + use<> {
916 self.entities.ref_counts_drop_handle()
917 }
918
919 #[cfg(any(test, feature = "leak-detection"))]
925 pub fn leak_detector_snapshot(&self) -> LeakDetectorSnapshot {
926 self.entities.leak_detector_snapshot()
927 }
928
929 #[cfg(any(test, feature = "leak-detection"))]
941 pub fn assert_no_new_leaks(&self, snapshot: &LeakDetectorSnapshot) {
942 self.entities.assert_no_new_leaks(snapshot)
943 }
944
945 pub fn shutdown(&mut self) {
948 let mut futures = Vec::new();
949
950 for observer in self.quit_observers.remove(&()) {
951 futures.push(observer(self));
952 }
953
954 self.windows.clear();
955 self.window_handles.clear();
956 self.flush_effects();
957 self.quitting = true;
958
959 let futures = futures::future::join_all(futures);
960 if self
961 .foreground_executor
962 .block_with_timeout(SHUTDOWN_TIMEOUT, futures)
963 .is_err()
964 {
965 log::error!("timed out waiting on app_will_quit");
966 }
967
968 self.quitting = false;
969 }
970
971 pub fn keyboard_layout(&self) -> &dyn PlatformKeyboardLayout {
973 self.keyboard_layout.as_ref()
974 }
975
976 pub fn keyboard_mapper(&self) -> &Rc<dyn PlatformKeyboardMapper> {
978 &self.keyboard_mapper
979 }
980
981 pub fn on_keyboard_layout_change<F>(&self, mut callback: F) -> Subscription
983 where
984 F: 'static + FnMut(&mut App),
985 {
986 let (subscription, activate) = self.keyboard_layout_observers.insert(
987 (),
988 Box::new(move |cx| {
989 callback(cx);
990 true
991 }),
992 );
993 activate();
994 subscription
995 }
996
997 pub fn quit(&self) {
999 self.platform.quit();
1000 }
1001
1002 pub fn cursor_hide_mode(&self) -> CursorHideMode {
1005 self.cursor_hide_mode
1006 }
1007
1008 pub fn set_cursor_hide_mode(&mut self, mode: CursorHideMode) {
1011 self.cursor_hide_mode = mode;
1012 }
1013
1014 pub fn is_cursor_visible(&self) -> bool {
1020 self.platform.is_cursor_visible()
1021 }
1022
1023 pub fn reduce_motion(&self) -> bool {
1026 self.reduce_motion
1027 }
1028
1029 pub fn set_reduce_motion(&mut self, reduce_motion: bool) {
1032 if self.reduce_motion != reduce_motion {
1033 self.reduce_motion = reduce_motion;
1034 self.refresh_windows();
1035 }
1036 }
1037
1038 pub fn refresh_windows(&mut self) {
1041 self.pending_effects.push_back(Effect::RefreshWindows);
1042 }
1043
1044 pub(crate) fn update<R>(&mut self, update: impl FnOnce(&mut Self) -> R) -> R {
1045 self.start_update();
1046 let result = update(self);
1047 self.finish_update();
1048 result
1049 }
1050
1051 pub(crate) fn start_update(&mut self) {
1052 self.pending_updates += 1;
1053 }
1054
1055 pub(crate) fn finish_update(&mut self) {
1056 if !self.flushing_effects && self.pending_updates == 1 {
1057 self.flushing_effects = true;
1058 self.flush_effects();
1059 self.flushing_effects = false;
1060 }
1061 self.pending_updates -= 1;
1062 }
1063
1064 pub fn observe<W>(
1066 &mut self,
1067 entity: &Entity<W>,
1068 mut on_notify: impl FnMut(Entity<W>, &mut App) + 'static,
1069 ) -> Subscription
1070 where
1071 W: 'static,
1072 {
1073 self.observe_internal(entity, move |e, cx| {
1074 on_notify(e, cx);
1075 true
1076 })
1077 }
1078
1079 pub(crate) fn detect_accessed_entities<R>(
1080 &mut self,
1081 callback: impl FnOnce(&mut App) -> R,
1082 ) -> (R, FxHashSet<EntityId>) {
1083 let accessed_entities_start = self.entities.accessed_entities.get_mut().clone();
1084 let result = callback(self);
1085 let entities_accessed_in_callback = self
1086 .entities
1087 .accessed_entities
1088 .get_mut()
1089 .difference(&accessed_entities_start)
1090 .copied()
1091 .collect::<FxHashSet<EntityId>>();
1092 (result, entities_accessed_in_callback)
1093 }
1094
1095 pub(crate) fn record_entities_accessed(
1096 &mut self,
1097 window_handle: AnyWindowHandle,
1098 invalidator: WindowInvalidator,
1099 entities: &FxHashSet<EntityId>,
1100 ) {
1101 let mut tracked_entities =
1102 std::mem::take(self.tracked_entities.entry(window_handle.id).or_default());
1103 for entity in tracked_entities.iter() {
1104 self.window_invalidators_by_entity
1105 .entry(*entity)
1106 .and_modify(|windows| {
1107 windows.remove(&window_handle.id);
1108 });
1109 }
1110 for entity in entities.iter() {
1111 self.window_invalidators_by_entity
1112 .entry(*entity)
1113 .or_default()
1114 .insert(window_handle.id, invalidator.clone());
1115 self.current_window_by_entity
1116 .insert(*entity, window_handle.id);
1117 }
1118 tracked_entities.clear();
1119 tracked_entities.extend(entities.iter().copied());
1120 self.tracked_entities
1121 .insert(window_handle.id, tracked_entities);
1122 }
1123
1124 pub(crate) fn new_observer(&mut self, key: EntityId, value: Handler) -> Subscription {
1125 let (subscription, activate) = self.observers.insert(key, value);
1126 self.defer(move |_| activate());
1127 subscription
1128 }
1129
1130 pub(crate) fn observe_internal<W>(
1131 &mut self,
1132 entity: &Entity<W>,
1133 mut on_notify: impl FnMut(Entity<W>, &mut App) -> bool + 'static,
1134 ) -> Subscription
1135 where
1136 W: 'static,
1137 {
1138 let entity_id = entity.entity_id();
1139 let handle = entity.downgrade();
1140 self.new_observer(
1141 entity_id,
1142 Box::new(move |cx| {
1143 if let Some(entity) = handle.upgrade() {
1144 on_notify(entity, cx)
1145 } else {
1146 false
1147 }
1148 }),
1149 )
1150 }
1151
1152 pub fn subscribe<T, Event>(
1155 &mut self,
1156 entity: &Entity<T>,
1157 mut on_event: impl FnMut(Entity<T>, &Event, &mut App) + 'static,
1158 ) -> Subscription
1159 where
1160 T: 'static + EventEmitter<Event>,
1161 Event: 'static,
1162 {
1163 self.subscribe_internal(entity, move |entity, event, cx| {
1164 on_event(entity, event, cx);
1165 true
1166 })
1167 }
1168
1169 pub(crate) fn new_subscription(
1170 &mut self,
1171 key: EntityId,
1172 value: (TypeId, Listener),
1173 ) -> Subscription {
1174 let (subscription, activate) = self.event_listeners.insert(key, value);
1175 self.defer(move |_| activate());
1176 subscription
1177 }
1178 pub(crate) fn subscribe_internal<T, Evt>(
1179 &mut self,
1180 entity: &Entity<T>,
1181 mut on_event: impl FnMut(Entity<T>, &Evt, &mut App) -> bool + 'static,
1182 ) -> Subscription
1183 where
1184 T: 'static + EventEmitter<Evt>,
1185 Evt: 'static,
1186 {
1187 let entity_id = entity.entity_id();
1188 let handle = entity.downgrade();
1189 self.new_subscription(
1190 entity_id,
1191 (
1192 TypeId::of::<Evt>(),
1193 Box::new(move |event, cx| {
1194 let event: &Evt = event.downcast_ref().expect("invalid event type");
1195 if let Some(entity) = handle.upgrade() {
1196 on_event(entity, event, cx)
1197 } else {
1198 false
1199 }
1200 }),
1201 ),
1202 )
1203 }
1204
1205 pub fn windows(&self) -> Vec<AnyWindowHandle> {
1209 self.windows
1210 .keys()
1211 .flat_map(|window_id| self.window_handles.get(&window_id).copied())
1212 .collect()
1213 }
1214
1215 pub fn window_stack(&self) -> Option<Vec<AnyWindowHandle>> {
1221 self.platform.window_stack()
1222 }
1223
1224 pub fn active_window(&self) -> Option<AnyWindowHandle> {
1226 self.platform.active_window()
1227 }
1228
1229 pub fn open_window<V: 'static + Render>(
1233 &mut self,
1234 options: crate::WindowOptions,
1235 build_root_view: impl FnOnce(&mut Window, &mut App) -> Entity<V>,
1236 ) -> anyhow::Result<WindowHandle<V>> {
1237 self.update(|cx| {
1238 let id = cx.windows.insert(None);
1239 let handle = WindowHandle::new(id);
1240 match Window::new(handle.into(), options, cx) {
1241 Ok(mut window) => {
1242 cx.window_update_stack.push(id);
1243 let root_view = build_root_view(&mut window, cx);
1244 cx.window_update_stack.pop();
1245 window.root.replace(root_view.into());
1246 window.defer(cx, |window: &mut Window, cx| window.appearance_changed(cx));
1247
1248 let clear = window.draw(cx);
1253 clear.clear(cx);
1254
1255 cx.window_handles.insert(id, window.handle);
1256 cx.windows.get_mut(id).unwrap().replace(Box::new(window));
1257 Ok(handle)
1258 }
1259 Err(e) => {
1260 cx.windows.remove(id);
1261 Err(e)
1262 }
1263 }
1264 })
1265 }
1266
1267 pub fn activate(&self, ignoring_other_apps: bool) {
1269 self.platform.activate(ignoring_other_apps);
1270 }
1271
1272 pub fn hide(&self) {
1274 self.platform.hide();
1275 }
1276
1277 pub fn hide_other_apps(&self) {
1279 self.platform.hide_other_apps();
1280 }
1281
1282 pub fn unhide_other_apps(&self) {
1284 self.platform.unhide_other_apps();
1285 }
1286
1287 pub fn displays(&self) -> Vec<Rc<dyn PlatformDisplay>> {
1289 self.platform.displays()
1290 }
1291
1292 pub fn primary_display(&self) -> Option<Rc<dyn PlatformDisplay>> {
1294 self.platform.primary_display()
1295 }
1296
1297 pub fn is_screen_capture_supported(&self) -> bool {
1299 self.platform.is_screen_capture_supported()
1300 }
1301
1302 pub fn screen_capture_sources(
1304 &self,
1305 ) -> oneshot::Receiver<Result<Vec<Rc<dyn ScreenCaptureSource>>>> {
1306 self.platform.screen_capture_sources()
1307 }
1308
1309 pub fn find_display(&self, id: DisplayId) -> Option<Rc<dyn PlatformDisplay>> {
1311 self.displays()
1312 .iter()
1313 .find(|display| display.id() == id)
1314 .cloned()
1315 }
1316
1317 pub fn thermal_state(&self) -> ThermalState {
1319 self.platform.thermal_state()
1320 }
1321
1322 pub fn on_thermal_state_change<F>(&self, mut callback: F) -> Subscription
1324 where
1325 F: 'static + FnMut(&mut App),
1326 {
1327 let (subscription, activate) = self.thermal_state_observers.insert(
1328 (),
1329 Box::new(move |cx| {
1330 callback(cx);
1331 true
1332 }),
1333 );
1334 activate();
1335 subscription
1336 }
1337
1338 pub fn window_appearance(&self) -> WindowAppearance {
1340 self.platform.window_appearance()
1341 }
1342
1343 pub fn set_window_appearance(&self, appearance: Option<WindowAppearance>) {
1354 self.platform.set_window_appearance(appearance);
1355 }
1356
1357 pub fn button_layout(&self) -> Option<WindowButtonLayout> {
1359 self.platform.button_layout()
1360 }
1361
1362 pub fn read_from_clipboard(&self) -> Option<ClipboardItem> {
1364 self.platform.read_from_clipboard()
1365 }
1366
1367 pub fn set_text_rendering_mode(&mut self, mode: TextRenderingMode) {
1369 self.text_rendering_mode.set(mode);
1370 }
1371
1372 pub fn text_rendering_mode(&self) -> TextRenderingMode {
1374 self.text_rendering_mode.get()
1375 }
1376
1377 pub fn write_to_clipboard(&self, item: ClipboardItem) {
1379 self.platform.write_to_clipboard(item)
1380 }
1381
1382 #[cfg(any(target_os = "linux", target_os = "freebsd"))]
1385 pub fn read_from_primary(&self) -> Option<ClipboardItem> {
1386 self.platform.read_from_primary()
1387 }
1388
1389 #[cfg(any(target_os = "linux", target_os = "freebsd"))]
1392 pub fn write_to_primary(&self, item: ClipboardItem) {
1393 self.platform.write_to_primary(item)
1394 }
1395
1396 #[cfg(target_os = "macos")]
1402 pub fn read_from_find_pasteboard(&self) -> Option<ClipboardItem> {
1403 self.platform.read_from_find_pasteboard()
1404 }
1405
1406 #[cfg(target_os = "macos")]
1412 pub fn write_to_find_pasteboard(&self, item: ClipboardItem) {
1413 self.platform.write_to_find_pasteboard(item)
1414 }
1415
1416 pub fn write_credentials(
1418 &self,
1419 url: &str,
1420 username: &str,
1421 password: &[u8],
1422 ) -> Task<Result<()>> {
1423 self.platform.write_credentials(url, username, password)
1424 }
1425
1426 pub fn read_credentials(&self, url: &str) -> Task<Result<Option<(String, Vec<u8>)>>> {
1428 self.platform.read_credentials(url)
1429 }
1430
1431 pub fn delete_credentials(&self, url: &str) -> Task<Result<()>> {
1433 self.platform.delete_credentials(url)
1434 }
1435
1436 pub fn open_url(&self, url: &str) {
1438 self.platform.open_url(url);
1439 }
1440
1441 pub fn register_url_scheme(&self, scheme: &str) -> Task<Result<()>> {
1448 self.platform.register_url_scheme(scheme)
1449 }
1450
1451 pub fn set_app_identity(&self, identifier: &str, name: &str) {
1458 self.platform.set_app_identity(identifier, name);
1459 }
1460
1461 pub fn show_system_notification(&self, notification: SystemNotification) {
1468 self.platform.show_system_notification(notification);
1469 }
1470
1471 pub fn dismiss_system_notification(&self, tag: &str) {
1476 self.platform.dismiss_system_notification(tag);
1477 }
1478
1479 pub fn on_system_notification_response<F>(&self, mut callback: F)
1483 where
1484 F: 'static + FnMut(SystemNotificationResponse, &mut App),
1485 {
1486 let this = self.this.clone();
1487 self.platform
1488 .on_system_notification_response(Box::new(move |response| {
1489 if let Some(app) = this.upgrade() {
1490 callback(response, &mut app.borrow_mut());
1491 }
1492 }));
1493 }
1494
1495 pub fn app_path(&self) -> Result<PathBuf> {
1499 self.platform.app_path()
1500 }
1501
1502 pub fn compositor_name(&self) -> &'static str {
1506 self.platform.compositor_name()
1507 }
1508
1509 pub fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf> {
1511 self.platform.path_for_auxiliary_executable(name)
1512 }
1513
1514 pub fn prompt_for_paths(
1520 &self,
1521 options: PathPromptOptions,
1522 ) -> oneshot::Receiver<Result<Option<Vec<PathBuf>>>> {
1523 self.platform.prompt_for_paths(options)
1524 }
1525
1526 pub fn prompt_for_new_path(
1533 &self,
1534 directory: &Path,
1535 suggested_name: Option<&str>,
1536 ) -> oneshot::Receiver<Result<Option<PathBuf>>> {
1537 self.platform.prompt_for_new_path(directory, suggested_name)
1538 }
1539
1540 pub fn reveal_path(&self, path: &Path) {
1542 self.platform.reveal_path(path)
1543 }
1544
1545 pub fn open_with_system(&self, path: &Path) {
1547 self.platform.open_with_system(path)
1548 }
1549
1550 pub fn should_auto_hide_scrollbars(&self) -> bool {
1552 self.platform.should_auto_hide_scrollbars()
1553 }
1554
1555 pub fn restart(&mut self) {
1557 self.restart_observers
1558 .clone()
1559 .retain(&(), |observer| observer(self));
1560 self.platform.restart(self.restart_path.take())
1561 }
1562
1563 pub fn set_restart_path(&mut self, path: PathBuf) {
1565 self.restart_path = Some(path);
1566 }
1567
1568 pub fn http_client(&self) -> Arc<dyn HttpClient> {
1570 self.http_client.clone()
1571 }
1572
1573 pub fn set_http_client(&mut self, new_client: Arc<dyn HttpClient>) {
1575 self.http_client = new_client;
1576 }
1577
1578 pub fn set_quit_mode(&mut self, mode: QuitMode) {
1581 self.quit_mode = mode;
1582 }
1583
1584 pub fn svg_renderer(&self) -> SvgRenderer {
1586 self.svg_renderer.clone()
1587 }
1588
1589 pub(crate) fn push_effect(&mut self, effect: Effect) {
1590 match &effect {
1591 Effect::Notify { emitter } => {
1592 if !self.pending_notifications.insert(*emitter) {
1593 return;
1594 }
1595 }
1596 Effect::NotifyGlobalObservers { global_type } => {
1597 if !self.pending_global_notifications.insert(*global_type) {
1598 return;
1599 }
1600 }
1601 _ => {}
1602 };
1603
1604 self.pending_effects.push_back(effect);
1605 }
1606
1607 fn flush_effects(&mut self) {
1611 loop {
1612 self.release_dropped_entities();
1613 self.release_dropped_focus_handles();
1614 if let Some(effect) = self.pending_effects.pop_front() {
1615 match effect {
1616 Effect::Notify { emitter } => {
1617 self.apply_notify_effect(emitter);
1618 }
1619
1620 Effect::Emit {
1621 emitter,
1622 event_type,
1623 event,
1624 } => self.apply_emit_effect(emitter, event_type, &*event),
1625
1626 Effect::RefreshWindows => {
1627 self.apply_refresh_effect();
1628 }
1629
1630 Effect::NotifyGlobalObservers { global_type } => {
1631 self.apply_notify_global_observers_effect(global_type);
1632 }
1633
1634 Effect::Defer { callback } => {
1635 self.apply_defer_effect(callback);
1636 }
1637 Effect::EntityCreated {
1638 entity,
1639 tid,
1640 window,
1641 } => {
1642 self.apply_entity_created_effect(entity, tid, window);
1643 }
1644 }
1645 } else {
1646 #[cfg(any(test, feature = "test-support", feature = "bench"))]
1647 for window in self
1648 .windows
1649 .values()
1650 .filter_map(|window| {
1651 let window = window.as_deref()?;
1652 window.invalidator.is_dirty().then_some(window.handle)
1653 })
1654 .collect::<Vec<_>>()
1655 {
1656 self.update_window(window, |_, window, cx| window.draw(cx).clear(cx))
1657 .unwrap();
1658 }
1659
1660 if self.pending_effects.is_empty() {
1661 self.event_arena.clear();
1662 break;
1663 }
1664 }
1665 }
1666 }
1667
1668 fn release_dropped_entities(&mut self) {
1672 loop {
1673 let dropped = self.entities.take_dropped();
1674 if dropped.is_empty() {
1675 break;
1676 }
1677
1678 for (entity_id, mut entity) in dropped {
1679 self.observers.remove(&entity_id);
1680 self.event_listeners.remove(&entity_id);
1681 self.window_invalidators_by_entity.remove(&entity_id);
1682 self.current_window_by_entity.remove(&entity_id);
1683 for release_callback in self.release_listeners.remove(&entity_id) {
1684 release_callback(entity.as_mut(), self);
1685 }
1686 }
1687 }
1688 }
1689
1690 fn release_dropped_focus_handles(&mut self) {
1692 self.focus_handles
1693 .clone()
1694 .write()
1695 .retain(|handle_id, focus| {
1696 if focus.ref_count.load(SeqCst) == 0 {
1697 for window_handle in self.windows() {
1698 window_handle
1699 .update(self, |_, window, _| {
1700 if window.focus == Some(handle_id) {
1701 window.blur();
1702 }
1703 })
1704 .unwrap();
1705 }
1706 false
1707 } else {
1708 true
1709 }
1710 });
1711 }
1712
1713 fn apply_notify_effect(&mut self, emitter: EntityId) {
1714 self.pending_notifications.remove(&emitter);
1715
1716 self.observers
1717 .clone()
1718 .retain(&emitter, |handler| handler(self));
1719 }
1720
1721 fn apply_emit_effect(&mut self, emitter: EntityId, event_type: TypeId, event: &dyn Any) {
1722 self.event_listeners
1723 .clone()
1724 .retain(&emitter, |(stored_type, handler)| {
1725 if *stored_type == event_type {
1726 handler(event, self)
1727 } else {
1728 true
1729 }
1730 });
1731 }
1732
1733 fn apply_refresh_effect(&mut self) {
1734 for window in self.windows.values_mut() {
1735 if let Some(window) = window.as_deref_mut() {
1736 window.refreshing = true;
1737 window.invalidator.set_dirty(true);
1738 }
1739 }
1740 }
1741
1742 fn apply_notify_global_observers_effect(&mut self, type_id: TypeId) {
1743 self.pending_global_notifications.remove(&type_id);
1744 self.global_observers
1745 .clone()
1746 .retain(&type_id, |observer| observer(self));
1747 }
1748
1749 fn apply_defer_effect(&mut self, callback: Box<dyn FnOnce(&mut Self) + 'static>) {
1750 callback(self);
1751 }
1752
1753 fn apply_entity_created_effect(
1754 &mut self,
1755 entity: AnyEntity,
1756 tid: TypeId,
1757 window: Option<WindowId>,
1758 ) {
1759 if let Some(id) = window {
1763 self.current_window_by_entity.insert(entity.entity_id(), id);
1764 }
1765
1766 self.new_entity_observers.clone().retain(&tid, |observer| {
1767 if let Some(id) = window {
1768 self.update_window_id(id, {
1769 let entity = entity.clone();
1770 |_, window, cx| (observer)(entity, &mut Some(window), cx)
1771 })
1772 .expect("All windows should be off the stack when flushing effects");
1773 } else {
1774 (observer)(entity.clone(), &mut None, self)
1775 }
1776 true
1777 });
1778 }
1779
1780 pub fn with_window<R>(
1786 &mut self,
1787 entity_id: EntityId,
1788 f: impl FnOnce(&mut Window, &mut App) -> R,
1789 ) -> Option<R> {
1790 let window_id = *self.current_window_by_entity.get(&entity_id)?;
1791 self.update_window_id(window_id, |_, window, cx| f(window, cx))
1792 .ok()
1793 }
1794
1795 fn ensure_window(&mut self, entity_id: EntityId, window: WindowId) {
1796 self.current_window_by_entity
1797 .entry(entity_id)
1798 .or_insert(window);
1799 }
1800
1801 pub(crate) fn update_window_id<T, F>(&mut self, id: WindowId, update: F) -> Result<T>
1802 where
1803 F: FnOnce(AnyView, &mut Window, &mut App) -> T,
1804 {
1805 self.update(|cx| {
1806 let mut window = cx.windows.get_mut(id)?.take()?;
1807
1808 let root_view = window.root.clone().unwrap();
1809
1810 cx.window_update_stack.push(window.handle.id);
1811 let result = update(root_view, &mut window, cx);
1812 fn trail(id: WindowId, window: Box<Window>, cx: &mut App) -> Option<()> {
1813 cx.window_update_stack.pop();
1814
1815 if window.removed {
1816 cx.end_platform_drag(id);
1817 cx.window_handles.remove(&id);
1818 cx.windows.remove(id);
1819 if let Some(tracked) = cx.tracked_entities.remove(&id) {
1820 for entity_id in tracked {
1821 if let Some(windows) =
1822 cx.window_invalidators_by_entity.get_mut(&entity_id)
1823 {
1824 windows.remove(&id);
1825 }
1826 if cx.current_window_by_entity.get(&entity_id) == Some(&id) {
1827 cx.current_window_by_entity.remove(&entity_id);
1828 }
1829 }
1830 }
1831
1832 cx.window_closed_observers.clone().retain(&(), |callback| {
1833 callback(cx, id);
1834 true
1835 });
1836
1837 let quit_on_empty = match cx.quit_mode {
1838 QuitMode::Explicit => false,
1839 QuitMode::LastWindowClosed => true,
1840 QuitMode::Default => cfg!(not(target_os = "macos")),
1841 };
1842
1843 if quit_on_empty && cx.windows.is_empty() {
1844 cx.quit();
1845 }
1846 } else {
1847 cx.windows.get_mut(id)?.replace(window);
1848 }
1849 Some(())
1850 }
1851 trail(id, window, cx)?;
1852
1853 Some(result)
1854 })
1855 .context("window not found")
1856 }
1857
1858 pub fn to_async(&self) -> AsyncApp {
1861 AsyncApp {
1862 app: self.this.clone(),
1863 background_executor: self.background_executor.clone(),
1864 foreground_executor: self.foreground_executor.clone(),
1865 }
1866 }
1867
1868 pub fn background_executor(&self) -> &BackgroundExecutor {
1870 &self.background_executor
1871 }
1872
1873 pub fn foreground_executor(&self) -> &ForegroundExecutor {
1875 if self.quitting {
1876 panic!("Can't spawn on main thread after on_app_quit")
1877 };
1878 &self.foreground_executor
1879 }
1880
1881 #[track_caller]
1884 pub fn spawn<AsyncFn, R>(&self, f: AsyncFn) -> Task<R>
1885 where
1886 AsyncFn: AsyncFnOnce(&mut AsyncApp) -> R + 'static,
1887 R: 'static,
1888 {
1889 if self.quitting {
1890 debug_panic!("Can't spawn on main thread after on_app_quit")
1891 };
1892
1893 let mut cx = self.to_async();
1894
1895 self.foreground_executor
1896 .spawn(async move { f(&mut cx).await }.boxed_local())
1897 }
1898
1899 pub fn spawn_with_priority<AsyncFn, R>(&self, priority: Priority, f: AsyncFn) -> Task<R>
1903 where
1904 AsyncFn: AsyncFnOnce(&mut AsyncApp) -> R + 'static,
1905 R: 'static,
1906 {
1907 if self.quitting {
1908 debug_panic!("Can't spawn on main thread after on_app_quit")
1909 };
1910
1911 let mut cx = self.to_async();
1912
1913 self.foreground_executor
1914 .spawn_with_priority(priority, async move { f(&mut cx).await }.boxed_local())
1915 }
1916
1917 pub fn defer(&mut self, f: impl FnOnce(&mut App) + 'static) {
1920 self.push_effect(Effect::Defer {
1921 callback: Box::new(f),
1922 });
1923 }
1924
1925 pub fn asset_source(&self) -> &Arc<dyn AssetSource> {
1927 &self.asset_source
1928 }
1929
1930 pub fn text_system(&self) -> &Arc<TextSystem> {
1932 &self.text_system
1933 }
1934
1935 pub fn has_global<G: Global>(&self) -> bool {
1937 self.globals_by_type.contains_key(&TypeId::of::<G>())
1938 }
1939
1940 #[track_caller]
1942 pub fn global<G: Global>(&self) -> &G {
1943 self.globals_by_type
1944 .get(&TypeId::of::<G>())
1945 .map(|any_state| any_state.downcast_ref::<G>().unwrap())
1946 .unwrap_or_else(|| panic!("no state of type {} exists", type_name::<G>()))
1947 }
1948
1949 pub fn try_global<G: Global>(&self) -> Option<&G> {
1951 self.globals_by_type
1952 .get(&TypeId::of::<G>())
1953 .map(|any_state| any_state.downcast_ref::<G>().unwrap())
1954 }
1955
1956 #[track_caller]
1958 pub fn global_mut<G: Global>(&mut self) -> &mut G {
1959 let global_type = TypeId::of::<G>();
1960 self.push_effect(Effect::NotifyGlobalObservers { global_type });
1961 self.globals_by_type
1962 .get_mut(&global_type)
1963 .and_then(|any_state| any_state.downcast_mut::<G>())
1964 .unwrap_or_else(|| panic!("no state of type {} exists", type_name::<G>()))
1965 }
1966
1967 pub fn default_global<G: Global + Default>(&mut self) -> &mut G {
1970 let global_type = TypeId::of::<G>();
1971 self.push_effect(Effect::NotifyGlobalObservers { global_type });
1972 self.globals_by_type
1973 .entry(global_type)
1974 .or_insert_with(|| Box::<G>::default())
1975 .downcast_mut::<G>()
1976 .unwrap()
1977 }
1978
1979 pub fn set_global<G: Global>(&mut self, global: G) {
1981 let global_type = TypeId::of::<G>();
1982 self.push_effect(Effect::NotifyGlobalObservers { global_type });
1983 self.globals_by_type.insert(global_type, Box::new(global));
1984 }
1985
1986 #[cfg(any(test, feature = "test-support"))]
1988 pub fn clear_globals(&mut self) {
1989 self.globals_by_type.drain();
1990 }
1991
1992 pub fn remove_global<G: Global>(&mut self) -> G {
1994 let global_type = TypeId::of::<G>();
1995 self.push_effect(Effect::NotifyGlobalObservers { global_type });
1996 *self
1997 .globals_by_type
1998 .remove(&global_type)
1999 .unwrap_or_else(|| panic!("no global added for {}", type_name::<G>()))
2000 .downcast()
2001 .unwrap()
2002 }
2003
2004 pub fn observe_global<G: Global>(
2006 &mut self,
2007 mut f: impl FnMut(&mut Self) + 'static,
2008 ) -> Subscription {
2009 let (subscription, activate) = self.global_observers.insert(
2010 TypeId::of::<G>(),
2011 Box::new(move |cx| {
2012 f(cx);
2013 true
2014 }),
2015 );
2016 self.defer(move |_| activate());
2017 subscription
2018 }
2019
2020 #[track_caller]
2022 pub(crate) fn lease_global<G: Global>(&mut self) -> GlobalLease<G> {
2023 GlobalLease::new(
2024 self.globals_by_type
2025 .remove(&TypeId::of::<G>())
2026 .with_context(|| format!("no global registered of type {}", type_name::<G>()))
2027 .unwrap(),
2028 )
2029 }
2030
2031 pub(crate) fn end_global_lease<G: Global>(&mut self, lease: GlobalLease<G>) {
2033 let global_type = TypeId::of::<G>();
2034
2035 self.push_effect(Effect::NotifyGlobalObservers { global_type });
2036 self.globals_by_type.insert(global_type, lease.global);
2037 }
2038
2039 pub(crate) fn new_entity_observer(
2040 &self,
2041 key: TypeId,
2042 value: NewEntityListener,
2043 ) -> Subscription {
2044 let (subscription, activate) = self.new_entity_observers.insert(key, value);
2045 activate();
2046 subscription
2047 }
2048
2049 pub fn observe_new<T: 'static>(
2052 &self,
2053 on_new: impl 'static + Fn(&mut T, Option<&mut Window>, &mut Context<T>),
2054 ) -> Subscription {
2055 self.new_entity_observer(
2056 TypeId::of::<T>(),
2057 Box::new(
2058 move |any_entity: AnyEntity, window: &mut Option<&mut Window>, cx: &mut App| {
2059 any_entity
2060 .downcast::<T>()
2061 .unwrap()
2062 .update(cx, |entity_state, cx| {
2063 on_new(entity_state, window.as_deref_mut(), cx)
2064 })
2065 },
2066 ),
2067 )
2068 }
2069
2070 pub fn observe_release<T>(
2073 &self,
2074 handle: &Entity<T>,
2075 on_release: impl FnOnce(&mut T, &mut App) + 'static,
2076 ) -> Subscription
2077 where
2078 T: 'static,
2079 {
2080 let (subscription, activate) = self.release_listeners.insert(
2081 handle.entity_id(),
2082 Box::new(move |entity, cx| {
2083 let entity = entity.downcast_mut().expect("invalid entity type");
2084 on_release(entity, cx)
2085 }),
2086 );
2087 activate();
2088 subscription
2089 }
2090
2091 pub fn observe_release_in<T>(
2094 &self,
2095 handle: &Entity<T>,
2096 window: &Window,
2097 on_release: impl FnOnce(&mut T, &mut Window, &mut App) + 'static,
2098 ) -> Subscription
2099 where
2100 T: 'static,
2101 {
2102 let window_handle = window.handle;
2103 self.observe_release(handle, move |entity, cx| {
2104 let _ = window_handle.update(cx, |_, window, cx| on_release(entity, window, cx));
2105 })
2106 }
2107
2108 pub fn observe_keystrokes(
2112 &mut self,
2113 mut f: impl FnMut(&KeystrokeEvent, &mut Window, &mut App) + 'static,
2114 ) -> Subscription {
2115 fn inner(
2116 keystroke_observers: &SubscriberSet<(), KeystrokeObserver>,
2117 handler: KeystrokeObserver,
2118 ) -> Subscription {
2119 let (subscription, activate) = keystroke_observers.insert((), handler);
2120 activate();
2121 subscription
2122 }
2123
2124 inner(
2125 &self.keystroke_observers,
2126 Box::new(move |event, window, cx| {
2127 f(event, window, cx);
2128 true
2129 }),
2130 )
2131 }
2132
2133 pub fn intercept_keystrokes(
2138 &mut self,
2139 mut f: impl FnMut(&KeystrokeEvent, &mut Window, &mut App) + 'static,
2140 ) -> Subscription {
2141 fn inner(
2142 keystroke_interceptors: &SubscriberSet<(), KeystrokeObserver>,
2143 handler: KeystrokeObserver,
2144 ) -> Subscription {
2145 let (subscription, activate) = keystroke_interceptors.insert((), handler);
2146 activate();
2147 subscription
2148 }
2149
2150 inner(
2151 &self.keystroke_interceptors,
2152 Box::new(move |event, window, cx| {
2153 f(event, window, cx);
2154 true
2155 }),
2156 )
2157 }
2158
2159 pub fn bind_keys(&mut self, bindings: impl IntoIterator<Item = KeyBinding>) {
2161 self.keymap.borrow_mut().add_bindings(bindings);
2162 self.pending_effects.push_back(Effect::RefreshWindows);
2163 }
2164
2165 pub fn clear_key_bindings(&mut self) {
2167 self.keymap.borrow_mut().clear();
2168 self.pending_effects.push_back(Effect::RefreshWindows);
2169 }
2170
2171 pub fn key_bindings(&self) -> Rc<RefCell<Keymap>> {
2173 self.keymap.clone()
2174 }
2175
2176 pub fn on_action<A: Action>(
2180 &mut self,
2181 listener: impl Fn(&A, &mut Self) + 'static,
2182 ) -> &mut Self {
2183 self.global_action_listeners
2184 .entry(TypeId::of::<A>())
2185 .or_default()
2186 .push(Rc::new(move |action, phase, cx| {
2187 if phase == DispatchPhase::Bubble {
2188 let action = action.downcast_ref().unwrap();
2189 listener(action, cx)
2190 }
2191 }));
2192 self
2193 }
2194
2195 pub fn stop_propagation(&mut self) {
2200 self.propagate_event = false;
2201 }
2202
2203 pub fn propagate(&mut self) {
2208 self.propagate_event = true;
2209 }
2210
2211 pub fn build_action(
2213 &self,
2214 name: &str,
2215 data: Option<serde_json::Value>,
2216 ) -> std::result::Result<Box<dyn Action>, ActionBuildError> {
2217 self.actions.build_action(name, data)
2218 }
2219
2220 pub fn all_action_names(&self) -> &[&'static str] {
2223 self.actions.all_action_names()
2224 }
2225
2226 pub fn all_bindings_for_input(&self, input: &[Keystroke]) -> Vec<KeyBinding> {
2230 RefCell::borrow(&self.keymap).all_bindings_for_input(input)
2231 }
2232
2233 pub fn action_schemas(
2235 &self,
2236 generator: &mut schemars::SchemaGenerator,
2237 ) -> Vec<(&'static str, Option<schemars::Schema>)> {
2238 self.actions.action_schemas(generator)
2239 }
2240
2241 pub fn action_schema_by_name(
2246 &self,
2247 name: &str,
2248 generator: &mut schemars::SchemaGenerator,
2249 ) -> Option<Option<schemars::Schema>> {
2250 self.actions.action_schema_by_name(name, generator)
2251 }
2252
2253 pub fn deprecated_actions_to_preferred_actions(&self) -> &HashMap<&'static str, &'static str> {
2255 self.actions.deprecated_aliases()
2256 }
2257
2258 pub fn action_deprecation_messages(&self) -> &HashMap<&'static str, &'static str> {
2260 self.actions.deprecation_messages()
2261 }
2262
2263 pub fn action_documentation(&self) -> &HashMap<&'static str, &'static str> {
2265 self.actions.documentation()
2266 }
2267
2268 pub fn on_app_quit<Fut>(
2271 &self,
2272 mut on_quit: impl FnMut(&mut App) -> Fut + 'static,
2273 ) -> Subscription
2274 where
2275 Fut: 'static + Future<Output = ()>,
2276 {
2277 let (subscription, activate) = self.quit_observers.insert(
2278 (),
2279 Box::new(move |cx| {
2280 let future = on_quit(cx);
2281 future.boxed_local()
2282 }),
2283 );
2284 activate();
2285 subscription
2286 }
2287
2288 pub fn on_app_restart(&self, mut on_restart: impl 'static + FnMut(&mut App)) -> Subscription {
2292 let (subscription, activate) = self.restart_observers.insert(
2293 (),
2294 Box::new(move |cx| {
2295 on_restart(cx);
2296 true
2297 }),
2298 );
2299 activate();
2300 subscription
2301 }
2302
2303 pub fn on_window_closed(
2306 &self,
2307 mut on_closed: impl FnMut(&mut App, WindowId) + 'static,
2308 ) -> Subscription {
2309 let (subscription, activate) = self.window_closed_observers.insert((), Box::new(on_closed));
2310 activate();
2311 subscription
2312 }
2313
2314 pub(crate) fn clear_pending_keystrokes(&mut self) {
2315 for window in self.windows() {
2316 window
2317 .update(self, |_, window, cx| {
2318 if window.pending_input_keystrokes().is_some() {
2319 window.clear_pending_keystrokes();
2320 window.pending_input_changed(cx);
2321 }
2322 })
2323 .ok();
2324 }
2325 }
2326
2327 pub fn is_action_available(&mut self, action: &dyn Action) -> bool {
2330 let mut action_available = false;
2331 if let Some(window) = self.active_window()
2332 && let Ok(window_action_available) =
2333 window.update(self, |_, window, cx| window.is_action_available(action, cx))
2334 {
2335 action_available = window_action_available;
2336 }
2337
2338 action_available
2339 || self
2340 .global_action_listeners
2341 .contains_key(&action.as_any().type_id())
2342 }
2343
2344 pub fn set_menus(&self, menus: impl IntoIterator<Item = Menu>) {
2346 let menus: Vec<Menu> = menus.into_iter().collect();
2347 self.platform.set_menus(menus, &self.keymap.borrow());
2348 }
2349
2350 pub fn get_menus(&self) -> Option<Vec<OwnedMenu>> {
2352 self.platform.get_menus()
2353 }
2354
2355 pub fn set_dock_menu(&self, menus: Vec<MenuItem>) {
2357 self.platform.set_dock_menu(menus, &self.keymap.borrow())
2358 }
2359
2360 pub fn perform_dock_menu_action(&self, action: usize) {
2362 self.platform.perform_dock_menu_action(action);
2363 }
2364
2365 pub fn add_recent_document(&self, path: &Path) {
2370 self.platform.add_recent_document(path);
2371 }
2372
2373 pub fn update_jump_list(
2376 &self,
2377 menus: Vec<MenuItem>,
2378 entries: Vec<SmallVec<[PathBuf; 2]>>,
2379 ) -> Task<Vec<SmallVec<[PathBuf; 2]>>> {
2380 self.platform.update_jump_list(menus, entries)
2381 }
2382
2383 pub fn dispatch_action(&mut self, action: &dyn Action) {
2386 if let Some(active_window) = self.active_window() {
2387 active_window
2388 .update(self, |_, window, cx| {
2389 window.dispatch_action(action.boxed_clone(), cx)
2390 })
2391 .log_err();
2392 } else {
2393 self.dispatch_global_action(action);
2394 }
2395 }
2396
2397 fn dispatch_global_action(&mut self, action: &dyn Action) {
2398 self.propagate_event = true;
2399
2400 if let Some(mut global_listeners) = self
2401 .global_action_listeners
2402 .remove(&action.as_any().type_id())
2403 {
2404 for listener in &global_listeners {
2405 listener(action.as_any(), DispatchPhase::Capture, self);
2406 if !self.propagate_event {
2407 break;
2408 }
2409 }
2410
2411 global_listeners.extend(
2412 self.global_action_listeners
2413 .remove(&action.as_any().type_id())
2414 .unwrap_or_default(),
2415 );
2416
2417 self.global_action_listeners
2418 .insert(action.as_any().type_id(), global_listeners);
2419 }
2420
2421 if self.propagate_event
2422 && let Some(mut global_listeners) = self
2423 .global_action_listeners
2424 .remove(&action.as_any().type_id())
2425 {
2426 for listener in global_listeners.iter().rev() {
2427 listener(action.as_any(), DispatchPhase::Bubble, self);
2428 if !self.propagate_event {
2429 break;
2430 }
2431 }
2432
2433 global_listeners.extend(
2434 self.global_action_listeners
2435 .remove(&action.as_any().type_id())
2436 .unwrap_or_default(),
2437 );
2438
2439 self.global_action_listeners
2440 .insert(action.as_any().type_id(), global_listeners);
2441 }
2442 }
2443
2444 pub fn has_active_drag(&self) -> bool {
2446 self.active_drag.is_some()
2447 }
2448
2449 pub fn active_drag_cursor_style(&self) -> Option<CursorStyle> {
2451 self.active_drag.as_ref().and_then(|drag| drag.cursor_style)
2452 }
2453
2454 pub fn stop_active_drag(&mut self, window: &mut Window) -> bool {
2456 if self.active_drag.is_some() {
2457 self.active_drag = None;
2458 if self.platform_owned_drag.as_ref().is_some_and(|drag| {
2459 drag.source_window == window.window_handle().window_id()
2460 && matches!(&drag.state, PlatformOwnedDragState::RestoredInSourceWindow)
2461 }) {
2462 self.platform_owned_drag = None;
2463 }
2464 window.refresh();
2465 true
2466 } else {
2467 false
2468 }
2469 }
2470
2471 pub(crate) fn hand_active_drag_to_platform(&mut self, source_window: WindowId) -> bool {
2472 let Some(drag) = self.active_drag.take() else {
2473 return false;
2474 };
2475 self.platform_owned_drag = Some(PlatformOwnedDrag {
2476 source_window,
2477 state: PlatformOwnedDragState::Suspended(drag),
2478 });
2479 true
2480 }
2481
2482 pub(crate) fn restore_platform_drag(&mut self, source_window: WindowId) -> bool {
2483 let Some(platform_drag) = self
2484 .platform_owned_drag
2485 .as_mut()
2486 .filter(|drag| drag.source_window == source_window)
2487 else {
2488 return false;
2489 };
2490 let state = std::mem::replace(
2491 &mut platform_drag.state,
2492 PlatformOwnedDragState::RestoredInSourceWindow,
2493 );
2494 let PlatformOwnedDragState::Suspended(drag) = state else {
2495 return false;
2496 };
2497 self.active_drag = Some(drag);
2498 true
2499 }
2500
2501 pub(crate) fn hand_restored_drag_to_platform(&mut self, source_window: WindowId) -> bool {
2502 let Some(platform_drag) = self.platform_owned_drag.as_mut().filter(|drag| {
2503 drag.source_window == source_window
2504 && matches!(&drag.state, PlatformOwnedDragState::RestoredInSourceWindow)
2505 }) else {
2506 return false;
2507 };
2508 let Some(drag) = self.active_drag.take() else {
2509 return false;
2510 };
2511 platform_drag.state = PlatformOwnedDragState::Suspended(drag);
2512 true
2513 }
2514
2515 pub(crate) fn end_platform_drag(&mut self, source_window: WindowId) -> bool {
2516 if !self
2517 .platform_owned_drag
2518 .as_ref()
2519 .is_some_and(|drag| drag.source_window == source_window)
2520 {
2521 return false;
2522 }
2523 self.platform_owned_drag = None;
2524 self.active_drag = None;
2525 true
2526 }
2527
2528 pub fn set_active_drag_cursor_style(
2530 &mut self,
2531 cursor_style: CursorStyle,
2532 window: &mut Window,
2533 ) -> bool {
2534 if let Some(ref mut drag) = self.active_drag {
2535 drag.cursor_style = Some(cursor_style);
2536 window.refresh();
2537 true
2538 } else {
2539 false
2540 }
2541 }
2542
2543 pub fn set_prompt_builder(
2546 &mut self,
2547 renderer: impl Fn(
2548 PromptLevel,
2549 &str,
2550 Option<&str>,
2551 &[PromptButton],
2552 PromptHandle,
2553 &mut Window,
2554 &mut App,
2555 ) -> RenderablePromptHandle
2556 + 'static,
2557 ) {
2558 self.prompt_builder = Some(PromptBuilder::Custom(Box::new(renderer)));
2559 }
2560
2561 pub fn reset_prompt_builder(&mut self) {
2563 self.prompt_builder = Some(PromptBuilder::Default);
2564 }
2565
2566 pub fn remove_asset<A: Asset>(&mut self, source: &A::Source) {
2568 let asset_id = (TypeId::of::<A>(), hash(source));
2569 self.loading_assets.remove(&asset_id);
2570 }
2571
2572 #[cfg(any(test, feature = "test-support"))]
2575 pub fn has_asset<A: Asset>(&self, source: &A::Source) -> bool {
2576 let asset_id = (TypeId::of::<A>(), hash(source));
2577 self.loading_assets.contains_key(&asset_id)
2578 }
2579
2580 pub fn fetch_asset<A: Asset>(&mut self, source: &A::Source) -> (Shared<Task<A::Output>>, bool) {
2585 let asset_id = (TypeId::of::<A>(), hash(source));
2586 let mut is_first = false;
2587 let task = self
2588 .loading_assets
2589 .remove(&asset_id)
2590 .map(|boxed_task| *boxed_task.downcast::<Shared<Task<A::Output>>>().unwrap())
2591 .unwrap_or_else(|| {
2592 is_first = true;
2593 let future = A::load(source.clone(), self);
2594
2595 self.background_executor().spawn(future).shared()
2596 });
2597
2598 self.loading_assets.insert(asset_id, Box::new(task.clone()));
2599
2600 (task, is_first)
2601 }
2602
2603 #[track_caller]
2606 pub fn focus_handle(&self) -> FocusHandle {
2607 FocusHandle::new(&self.focus_handles)
2608 }
2609
2610 pub fn notify(&mut self, entity_id: EntityId) {
2612 let window_invalidators = mem::take(
2613 self.window_invalidators_by_entity
2614 .entry(entity_id)
2615 .or_default(),
2616 );
2617
2618 let live_invalidators: SmallVec<[WindowInvalidator; 2]> = window_invalidators
2623 .iter()
2624 .filter(|(window_id, _)| {
2625 self.tracked_entities
2626 .get(window_id)
2627 .is_some_and(|set| set.contains(&entity_id))
2628 })
2629 .map(|(_, invalidator)| invalidator.clone())
2630 .collect();
2631
2632 if live_invalidators.is_empty() {
2633 if self.pending_notifications.insert(entity_id) {
2634 self.pending_effects
2635 .push_back(Effect::Notify { emitter: entity_id });
2636 }
2637 } else {
2638 for invalidator in &live_invalidators {
2639 invalidator.invalidate_view(entity_id, self);
2640 }
2641 }
2642
2643 self.window_invalidators_by_entity
2644 .insert(entity_id, window_invalidators);
2645 }
2646
2647 #[cfg(any(test, feature = "test-support", debug_assertions))]
2649 pub fn get_name(&self) -> Option<&'static str> {
2650 self.name
2651 }
2652
2653 pub fn can_select_mixed_files_and_dirs(&self) -> bool {
2655 self.platform.can_select_mixed_files_and_dirs()
2656 }
2657
2658 pub fn drop_image(&mut self, image: Arc<RenderImage>, current_window: Option<&mut Window>) {
2663 for window in self.windows.values_mut().flatten() {
2665 _ = window.drop_image(image.clone());
2666 }
2667
2668 if let Some(window) = current_window {
2670 _ = window.drop_image(image);
2671 }
2672 }
2673
2674 #[cfg(any(feature = "inspector", debug_assertions))]
2676 pub fn set_inspector_renderer(&mut self, f: crate::InspectorRenderer) {
2677 self.inspector_renderer = Some(f);
2678 }
2679
2680 #[cfg(any(feature = "inspector", debug_assertions))]
2682 pub fn register_inspector_element<T: 'static, R: crate::IntoElement>(
2683 &mut self,
2684 f: impl 'static + Fn(crate::InspectorElementId, &T, &mut Window, &mut App) -> R,
2685 ) {
2686 self.inspector_element_registry.register(f);
2687 }
2688
2689 pub fn init_colors(&mut self) {
2693 self.set_global(GlobalColors(Arc::new(Colors::default())));
2694 }
2695}
2696
2697impl AppContext for App {
2698 fn new<T: 'static>(&mut self, build_entity: impl FnOnce(&mut Context<T>) -> T) -> Entity<T> {
2703 self.update(|cx| {
2704 let slot = cx.entities.reserve();
2705 let handle = slot.clone();
2706 let entity = build_entity(&mut Context::new_context(cx, slot.downgrade()));
2707
2708 cx.push_effect(Effect::EntityCreated {
2709 entity: handle.into_any(),
2710 tid: TypeId::of::<T>(),
2711 window: cx.window_update_stack.last().cloned(),
2712 });
2713
2714 cx.entities.insert(slot, entity)
2715 })
2716 }
2717
2718 fn reserve_entity<T: 'static>(&mut self) -> Reservation<T> {
2719 Reservation(self.entities.reserve())
2720 }
2721
2722 fn insert_entity<T: 'static>(
2723 &mut self,
2724 reservation: Reservation<T>,
2725 build_entity: impl FnOnce(&mut Context<T>) -> T,
2726 ) -> Entity<T> {
2727 self.update(|cx| {
2728 let slot = reservation.0;
2729 let entity = build_entity(&mut Context::new_context(cx, slot.downgrade()));
2730 cx.entities.insert(slot, entity)
2731 })
2732 }
2733
2734 fn update_entity<T: 'static, R>(
2737 &mut self,
2738 handle: &Entity<T>,
2739 update: impl FnOnce(&mut T, &mut Context<T>) -> R,
2740 ) -> R {
2741 self.update(|cx| {
2742 let mut entity = cx.entities.lease(handle);
2743 let result = update(
2744 &mut entity,
2745 &mut Context::new_context(cx, handle.downgrade()),
2746 );
2747 cx.entities.end_lease(entity);
2748 result
2749 })
2750 }
2751
2752 fn as_mut<'a, T>(&'a mut self, handle: &Entity<T>) -> GpuiBorrow<'a, T>
2753 where
2754 T: 'static,
2755 {
2756 GpuiBorrow::new(handle.clone(), self)
2757 }
2758
2759 fn read_entity<T, R>(&self, handle: &Entity<T>, read: impl FnOnce(&T, &App) -> R) -> R
2760 where
2761 T: 'static,
2762 {
2763 let entity = self.entities.read(handle);
2764 read(entity, self)
2765 }
2766
2767 fn update_window<T, F>(&mut self, handle: AnyWindowHandle, update: F) -> Result<T>
2768 where
2769 F: FnOnce(AnyView, &mut Window, &mut App) -> T,
2770 {
2771 self.update_window_id(handle.id, update)
2772 }
2773
2774 fn with_window<R>(
2775 &mut self,
2776 entity_id: EntityId,
2777 f: impl FnOnce(&mut Window, &mut App) -> R,
2778 ) -> Option<R> {
2779 App::with_window(self, entity_id, f)
2780 }
2781
2782 fn read_window<T, R>(
2783 &self,
2784 window: &WindowHandle<T>,
2785 read: impl FnOnce(Entity<T>, &App) -> R,
2786 ) -> Result<R>
2787 where
2788 T: 'static,
2789 {
2790 let window = self
2791 .windows
2792 .get(window.id)
2793 .context("window not found")?
2794 .as_deref()
2795 .expect("attempted to read a window that is already on the stack");
2796
2797 let root_view = window.root.clone().unwrap();
2798 let view = root_view
2799 .downcast::<T>()
2800 .map_err(|_| anyhow!("root view's type has changed"))?;
2801
2802 Ok(read(view, self))
2803 }
2804
2805 fn background_spawn<R>(&self, future: impl Future<Output = R> + Send + 'static) -> Task<R>
2806 where
2807 R: Send + 'static,
2808 {
2809 self.background_executor.spawn(future)
2810 }
2811
2812 fn read_global<G, R>(&self, callback: impl FnOnce(&G, &App) -> R) -> R
2813 where
2814 G: Global,
2815 {
2816 let mut g = self.global::<G>();
2817 callback(g, self)
2818 }
2819}
2820
2821pub(crate) enum Effect {
2823 Notify {
2824 emitter: EntityId,
2825 },
2826 Emit {
2827 emitter: EntityId,
2828 event_type: TypeId,
2829 event: ArenaBox<dyn Any>,
2830 },
2831 RefreshWindows,
2832 NotifyGlobalObservers {
2833 global_type: TypeId,
2834 },
2835 Defer {
2836 callback: Box<dyn FnOnce(&mut App) + 'static>,
2837 },
2838 EntityCreated {
2839 entity: AnyEntity,
2840 tid: TypeId,
2841 window: Option<WindowId>,
2842 },
2843}
2844
2845impl std::fmt::Debug for Effect {
2846 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2847 match self {
2848 Effect::Notify { emitter } => write!(f, "Notify({})", emitter),
2849 Effect::Emit { emitter, .. } => write!(f, "Emit({:?})", emitter),
2850 Effect::RefreshWindows => write!(f, "RefreshWindows"),
2851 Effect::NotifyGlobalObservers { global_type } => {
2852 write!(f, "NotifyGlobalObservers({:?})", global_type)
2853 }
2854 Effect::Defer { .. } => write!(f, "Defer(..)"),
2855 Effect::EntityCreated { entity, .. } => write!(f, "EntityCreated({:?})", entity),
2856 }
2857 }
2858}
2859
2860pub(crate) struct GlobalLease<G: Global> {
2862 global: Box<dyn Any>,
2863 global_type: PhantomData<G>,
2864}
2865
2866impl<G: Global> GlobalLease<G> {
2867 fn new(global: Box<dyn Any>) -> Self {
2868 GlobalLease {
2869 global,
2870 global_type: PhantomData,
2871 }
2872 }
2873}
2874
2875impl<G: Global> Deref for GlobalLease<G> {
2876 type Target = G;
2877
2878 fn deref(&self) -> &Self::Target {
2879 self.global.downcast_ref().unwrap()
2880 }
2881}
2882
2883impl<G: Global> DerefMut for GlobalLease<G> {
2884 fn deref_mut(&mut self) -> &mut Self::Target {
2885 self.global.downcast_mut().unwrap()
2886 }
2887}
2888
2889pub struct AnyDrag {
2892 pub view: AnyView,
2894
2895 pub value: Arc<dyn Any>,
2897
2898 pub cursor_offset: Point<Pixels>,
2901
2902 pub cursor_style: Option<CursorStyle>,
2904
2905 pub external_payload_source: Option<ExternalDragPayloadSource>,
2908}
2909
2910pub type ExternalDragPayloadSource =
2913 Box<dyn FnOnce(&mut Window, &mut App) -> Option<ExternalDragPayload> + 'static>;
2914
2915#[derive(Clone)]
2918pub struct AnyTooltip {
2919 pub view: AnyView,
2921
2922 pub mouse_position: Point<Pixels>,
2924
2925 pub check_visible_and_update: Rc<dyn Fn(Bounds<Pixels>, &mut Window, &mut App) -> bool>,
2929}
2930
2931#[derive(Debug)]
2933pub struct KeystrokeEvent {
2934 pub keystroke: Keystroke,
2936
2937 pub action: Option<Box<dyn Action>>,
2939
2940 pub context_stack: Vec<KeyContext>,
2942}
2943
2944struct NullHttpClient;
2945
2946impl HttpClient for NullHttpClient {
2947 fn send(
2948 &self,
2949 _req: http_client::Request<http_client::AsyncBody>,
2950 ) -> futures::future::BoxFuture<
2951 'static,
2952 anyhow::Result<http_client::Response<http_client::AsyncBody>>,
2953 > {
2954 async move {
2955 anyhow::bail!("No HttpClient available");
2956 }
2957 .boxed()
2958 }
2959
2960 fn user_agent(&self) -> Option<&http_client::http::HeaderValue> {
2961 None
2962 }
2963
2964 fn proxy(&self) -> Option<&Url> {
2965 None
2966 }
2967}
2968
2969pub struct GpuiBorrow<'a, T> {
2971 inner: Option<Lease<T>>,
2972 app: &'a mut App,
2973}
2974
2975impl<'a, T: 'static> GpuiBorrow<'a, T> {
2976 fn new(inner: Entity<T>, app: &'a mut App) -> Self {
2977 app.start_update();
2978 let lease = app.entities.lease(&inner);
2979 Self {
2980 inner: Some(lease),
2981 app,
2982 }
2983 }
2984}
2985
2986impl<'a, T: 'static> std::borrow::Borrow<T> for GpuiBorrow<'a, T> {
2987 fn borrow(&self) -> &T {
2988 self.inner.as_ref().unwrap().borrow()
2989 }
2990}
2991
2992impl<'a, T: 'static> std::borrow::BorrowMut<T> for GpuiBorrow<'a, T> {
2993 fn borrow_mut(&mut self) -> &mut T {
2994 self.inner.as_mut().unwrap().borrow_mut()
2995 }
2996}
2997
2998impl<'a, T: 'static> std::ops::Deref for GpuiBorrow<'a, T> {
2999 type Target = T;
3000
3001 fn deref(&self) -> &Self::Target {
3002 self.inner.as_ref().unwrap()
3003 }
3004}
3005
3006impl<'a, T: 'static> std::ops::DerefMut for GpuiBorrow<'a, T> {
3007 fn deref_mut(&mut self) -> &mut T {
3008 self.inner.as_mut().unwrap()
3009 }
3010}
3011
3012impl<'a, T> Drop for GpuiBorrow<'a, T> {
3013 fn drop(&mut self) {
3014 let lease = self.inner.take().unwrap();
3015 self.app.notify(lease.id);
3016 self.app.entities.end_lease(lease);
3017 self.app.finish_update();
3018 }
3019}
3020
3021#[cfg(test)]
3022mod test {
3023 use std::{cell::RefCell, rc::Rc};
3024
3025 use crate::{AppContext, TestAppContext};
3026
3027 #[test]
3028 fn test_gpui_borrow() {
3029 let cx = TestAppContext::single();
3030 let observation_count = Rc::new(RefCell::new(0));
3031
3032 let state = cx.update(|cx| {
3033 let state = cx.new(|_| false);
3034 cx.observe(&state, {
3035 let observation_count = observation_count.clone();
3036 move |_, _| {
3037 let mut count = observation_count.borrow_mut();
3038 *count += 1;
3039 }
3040 })
3041 .detach();
3042
3043 state
3044 });
3045
3046 cx.update(|cx| {
3047 *std::borrow::BorrowMut::borrow_mut(&mut state.as_mut(cx)) = true;
3049 });
3050
3051 cx.update(|cx| {
3052 state.write(cx, false);
3053 });
3054
3055 assert_eq!(*observation_count.borrow(), 2);
3056 }
3057}