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