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-support")]
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(any(feature = "inspector", 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-support")]
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);
79
80#[doc(hidden)]
83pub struct AppCell {
84 app: RefCell<App>,
85}
86
87impl AppCell {
88 #[doc(hidden)]
89 #[track_caller]
90 pub fn borrow(&self) -> AppRef<'_> {
91 if option_env!("TRACK_THREAD_BORROWS").is_some() {
92 let thread_id = std::thread::current().id();
93 eprintln!("borrowed {thread_id:?}");
94 }
95 AppRef(self.app.borrow())
96 }
97
98 #[doc(hidden)]
99 #[track_caller]
100 pub fn borrow_mut(&self) -> AppRefMut<'_> {
101 if option_env!("TRACK_THREAD_BORROWS").is_some() {
102 let thread_id = std::thread::current().id();
103 eprintln!("borrowed {thread_id:?}");
104 }
105 AppRefMut(self.app.borrow_mut())
106 }
107
108 #[doc(hidden)]
109 #[track_caller]
110 pub fn try_borrow_mut(&self) -> Result<AppRefMut<'_>, BorrowMutError> {
111 if option_env!("TRACK_THREAD_BORROWS").is_some() {
112 let thread_id = std::thread::current().id();
113 eprintln!("borrowed {thread_id:?}");
114 }
115 Ok(AppRefMut(self.app.try_borrow_mut()?))
116 }
117}
118
119#[doc(hidden)]
120#[derive(Deref, DerefMut)]
121pub struct AppRef<'a>(Ref<'a, App>);
122
123impl Drop for AppRef<'_> {
124 fn drop(&mut self) {
125 if option_env!("TRACK_THREAD_BORROWS").is_some() {
126 let thread_id = std::thread::current().id();
127 eprintln!("dropped borrow from {thread_id:?}");
128 }
129 }
130}
131
132#[doc(hidden)]
133#[derive(Deref, DerefMut)]
134pub struct AppRefMut<'a>(RefMut<'a, App>);
135
136impl Drop for AppRefMut<'_> {
137 fn drop(&mut self) {
138 if option_env!("TRACK_THREAD_BORROWS").is_some() {
139 let thread_id = std::thread::current().id();
140 eprintln!("dropped {thread_id:?}");
141 }
142 }
143}
144
145pub struct Application(Rc<AppCell>);
148
149pub struct ApplicationHandle {
155 app: Rc<AppCell>,
156}
157
158impl ApplicationHandle {
159 pub fn update<R>(&self, f: impl FnOnce(&mut App) -> R) -> R {
163 let cx = &mut *self.app.borrow_mut();
164 f(cx)
165 }
166
167 pub fn to_async(&self) -> AsyncApp {
170 self.update(|cx| cx.to_async())
171 }
172}
173
174impl Application {
177 pub fn with_platform(platform: Rc<dyn Platform>) -> Self {
179 Self(App::new_app(
180 platform,
181 Arc::new(()),
182 Arc::new(NullHttpClient),
183 ))
184 }
185
186 pub fn new_inaccessible(platform: Rc<dyn Platform>) -> Self {
196 let this = Self::with_platform(platform);
197 this.0.borrow_mut().accessibility_force_disabled = true;
198 this
199 }
200
201 pub fn with_assets(self, asset_source: impl AssetSource) -> Self {
203 let mut context_lock = self.0.borrow_mut();
204 let asset_source = Arc::new(asset_source);
205 context_lock.asset_source = asset_source.clone();
206 context_lock.svg_renderer = SvgRenderer::new(asset_source);
207 drop(context_lock);
208 self
209 }
210
211 pub fn with_restart_arguments(self, arguments: Vec<OsString>) -> Self {
213 self.0.borrow_mut().restart_arguments = arguments;
214 self
215 }
216
217 pub fn with_http_client(self, http_client: Arc<dyn HttpClient>) -> Self {
219 let mut context_lock = self.0.borrow_mut();
220 context_lock.http_client = http_client;
221 drop(context_lock);
222 self
223 }
224
225 pub fn with_quit_mode(self, mode: QuitMode) -> Self {
228 self.0.borrow_mut().quit_mode = mode;
229 self
230 }
231
232 pub fn run<F>(self, on_finish_launching: F)
235 where
236 F: 'static + FnOnce(&mut App),
237 {
238 let this = self.0.clone();
239 let platform = self.0.borrow().platform.clone();
240 platform.run(Box::new(move || {
241 let cx = &mut *this.borrow_mut();
242 on_finish_launching(cx);
243 }));
244 }
245
246 pub fn run_embedded<F>(self, on_finish_launching: F) -> ApplicationHandle
256 where
257 F: 'static + FnOnce(&mut App),
258 {
259 let this = self.0.clone();
260 let platform = self.0.borrow().platform.clone();
261 platform.run(Box::new(move || {
262 let cx = &mut *this.borrow_mut();
263 on_finish_launching(cx);
264 }));
265 ApplicationHandle { app: self.0 }
266 }
267
268 pub fn on_open_urls<F>(&self, mut callback: F) -> &Self
271 where
272 F: 'static + FnMut(Vec<String>),
273 {
274 self.0.borrow().platform.on_open_urls(Box::new(callback));
275 self
276 }
277
278 pub fn on_reopen<F>(&self, mut callback: F) -> &Self
281 where
282 F: 'static + FnMut(&mut App),
283 {
284 let this = Rc::downgrade(&self.0);
285 self.0.borrow_mut().platform.on_reopen(Box::new(move || {
286 if let Some(app) = this.upgrade() {
287 callback(&mut app.borrow_mut());
288 }
289 }));
290 self
291 }
292
293 pub fn background_executor(&self) -> BackgroundExecutor {
295 self.0.borrow().background_executor.clone()
296 }
297
298 pub fn foreground_executor(&self) -> ForegroundExecutor {
300 self.0.borrow().foreground_executor.clone()
301 }
302
303 pub fn text_system(&self) -> Arc<TextSystem> {
305 self.0.borrow().text_system.clone()
306 }
307
308 pub fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf> {
310 self.0.borrow().path_for_auxiliary_executable(name)
311 }
312}
313
314type Handler = Box<dyn FnMut(&mut App) -> bool + 'static>;
315type Listener = Box<dyn FnMut(&dyn Any, &mut App) -> bool + 'static>;
316pub(crate) type KeystrokeObserver =
317 Box<dyn FnMut(&KeystrokeEvent, &mut Window, &mut App) -> bool + 'static>;
318type QuitHandler = Box<dyn FnOnce(&mut App) -> LocalBoxFuture<'static, ()> + 'static>;
319type WindowClosedHandler = Box<dyn FnMut(&mut App, WindowId)>;
320type ReleaseListener = Box<dyn FnOnce(&mut dyn Any, &mut App) + 'static>;
321type NewEntityListener = Box<dyn FnMut(AnyEntity, &mut Option<&mut Window>, &mut App) + 'static>;
322
323#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
325pub enum QuitMode {
326 #[default]
328 Default,
329 LastWindowClosed,
331 Explicit,
333}
334
335#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
340pub enum CursorHideMode {
341 Never,
343 OnTyping,
345 #[default]
348 OnTypingAndAction,
349}
350
351#[doc(hidden)]
352#[derive(Clone, PartialEq, Eq)]
353pub struct SystemWindowTab {
354 pub id: WindowId,
355 pub title: SharedString,
356 pub handle: AnyWindowHandle,
357 pub last_active_at: Instant,
358}
359
360impl SystemWindowTab {
361 pub fn new(title: SharedString, handle: AnyWindowHandle) -> Self {
363 Self {
364 id: handle.id,
365 title,
366 handle,
367 last_active_at: Instant::now(),
368 }
369 }
370}
371
372#[derive(Default)]
374pub struct SystemWindowTabController {
375 visible: Option<bool>,
376 tab_groups: FxHashMap<usize, Vec<SystemWindowTab>>,
377}
378
379impl Global for SystemWindowTabController {}
380
381impl SystemWindowTabController {
382 pub fn new() -> Self {
384 Self {
385 visible: None,
386 tab_groups: FxHashMap::default(),
387 }
388 }
389
390 pub fn init(cx: &mut App) {
392 cx.set_global(SystemWindowTabController::new());
393 }
394
395 pub fn tab_groups(&self) -> &FxHashMap<usize, Vec<SystemWindowTab>> {
397 &self.tab_groups
398 }
399
400 pub fn get_next_tab_group_window(cx: &mut App, id: WindowId) -> Option<&AnyWindowHandle> {
402 let controller = cx.global::<SystemWindowTabController>();
403 let current_group = controller
404 .tab_groups
405 .iter()
406 .find_map(|(group, tabs)| tabs.iter().find(|tab| tab.id == id).map(|_| group));
407
408 let current_group = current_group?;
409 let mut group_ids: Vec<_> = controller.tab_groups.keys().collect();
411 let idx = group_ids.iter().position(|g| *g == current_group)?;
412 let next_idx = (idx + 1) % group_ids.len();
413
414 controller
415 .tab_groups
416 .get(group_ids[next_idx])
417 .and_then(|tabs| {
418 tabs.iter()
419 .max_by_key(|tab| tab.last_active_at)
420 .or_else(|| tabs.first())
421 .map(|tab| &tab.handle)
422 })
423 }
424
425 pub fn get_prev_tab_group_window(cx: &mut App, id: WindowId) -> Option<&AnyWindowHandle> {
427 let controller = cx.global::<SystemWindowTabController>();
428 let current_group = controller
429 .tab_groups
430 .iter()
431 .find_map(|(group, tabs)| tabs.iter().find(|tab| tab.id == id).map(|_| group));
432
433 let current_group = current_group?;
434 let mut group_ids: Vec<_> = controller.tab_groups.keys().collect();
436 let idx = group_ids.iter().position(|g| *g == current_group)?;
437 let prev_idx = if idx == 0 {
438 group_ids.len() - 1
439 } else {
440 idx - 1
441 };
442
443 controller
444 .tab_groups
445 .get(group_ids[prev_idx])
446 .and_then(|tabs| {
447 tabs.iter()
448 .max_by_key(|tab| tab.last_active_at)
449 .or_else(|| tabs.first())
450 .map(|tab| &tab.handle)
451 })
452 }
453
454 pub fn tabs(&self, id: WindowId) -> Option<&Vec<SystemWindowTab>> {
456 self.tab_groups
457 .values()
458 .find(|tabs| tabs.iter().any(|tab| tab.id == id))
459 }
460
461 pub fn init_visible(cx: &mut App, visible: bool) {
463 let mut controller = cx.global_mut::<SystemWindowTabController>();
464 if controller.visible.is_none() {
465 controller.visible = Some(visible);
466 }
467 }
468
469 pub fn is_visible(&self) -> bool {
471 self.visible.unwrap_or(false)
472 }
473
474 pub fn set_visible(cx: &mut App, visible: bool) {
476 let mut controller = cx.global_mut::<SystemWindowTabController>();
477 controller.visible = Some(visible);
478 }
479
480 pub fn update_last_active(cx: &mut App, id: WindowId) {
482 let mut controller = cx.global_mut::<SystemWindowTabController>();
483 for windows in controller.tab_groups.values_mut() {
484 for tab in windows.iter_mut() {
485 if tab.id == id {
486 tab.last_active_at = Instant::now();
487 }
488 }
489 }
490 }
491
492 pub fn update_tab_position(cx: &mut App, id: WindowId, ix: usize) {
494 let mut controller = cx.global_mut::<SystemWindowTabController>();
495 for (_, windows) in controller.tab_groups.iter_mut() {
496 if let Some(current_pos) = windows.iter().position(|tab| tab.id == id) {
497 if ix < windows.len() && current_pos != ix {
498 let window_tab = windows.remove(current_pos);
499 windows.insert(ix, window_tab);
500 }
501 break;
502 }
503 }
504 }
505
506 pub fn update_tab_title(cx: &mut App, id: WindowId, title: SharedString) {
508 let controller = cx.global::<SystemWindowTabController>();
509 let tab = controller
510 .tab_groups
511 .values()
512 .flat_map(|windows| windows.iter())
513 .find(|tab| tab.id == id);
514
515 if tab.map_or(true, |t| t.title == title) {
516 return;
517 }
518
519 let mut controller = cx.global_mut::<SystemWindowTabController>();
520 for windows in controller.tab_groups.values_mut() {
521 for tab in windows.iter_mut() {
522 if tab.id == id {
523 tab.title = title;
524 return;
525 }
526 }
527 }
528 }
529
530 pub fn add_tab(cx: &mut App, id: WindowId, tabs: Vec<SystemWindowTab>) {
532 let mut controller = cx.global_mut::<SystemWindowTabController>();
533 let Some(tab) = tabs.iter().find(|tab| tab.id == id).cloned() else {
534 return;
535 };
536
537 let mut expected_tab_ids: Vec<_> = tabs
538 .iter()
539 .filter(|tab| tab.id != id)
540 .map(|tab| tab.id)
541 .sorted()
542 .collect();
543
544 let mut tab_group_id = None;
545 for (group_id, group_tabs) in &controller.tab_groups {
546 let tab_ids: Vec<_> = group_tabs.iter().map(|tab| tab.id).sorted().collect();
547 if tab_ids == expected_tab_ids {
548 tab_group_id = Some(*group_id);
549 break;
550 }
551 }
552
553 if let Some(tab_group_id) = tab_group_id {
554 if let Some(tabs) = controller.tab_groups.get_mut(&tab_group_id) {
555 tabs.push(tab);
556 }
557 } else {
558 let new_group_id = controller.tab_groups.len();
559 controller.tab_groups.insert(new_group_id, tabs);
560 }
561 }
562
563 pub fn remove_tab(cx: &mut App, id: WindowId) -> Option<SystemWindowTab> {
565 let mut controller = cx.global_mut::<SystemWindowTabController>();
566 let mut removed_tab = None;
567
568 controller.tab_groups.retain(|_, tabs| {
569 if let Some(pos) = tabs.iter().position(|tab| tab.id == id) {
570 removed_tab = Some(tabs.remove(pos));
571 }
572 !tabs.is_empty()
573 });
574
575 removed_tab
576 }
577
578 pub fn move_tab_to_new_window(cx: &mut App, id: WindowId) {
580 let mut removed_tab = Self::remove_tab(cx, id);
581 let mut controller = cx.global_mut::<SystemWindowTabController>();
582
583 if let Some(tab) = removed_tab {
584 let new_group_id = controller.tab_groups.keys().max().map_or(0, |k| k + 1);
585 controller.tab_groups.insert(new_group_id, vec![tab]);
586 }
587 }
588
589 pub fn merge_all_windows(cx: &mut App, id: WindowId) {
591 let mut controller = cx.global_mut::<SystemWindowTabController>();
592 let Some(initial_tabs) = controller.tabs(id) else {
593 return;
594 };
595
596 let initial_tabs_len = initial_tabs.len();
597 let mut all_tabs = initial_tabs.clone();
598
599 for (_, mut tabs) in controller.tab_groups.drain() {
600 tabs.retain(|tab| !all_tabs[..initial_tabs_len].contains(tab));
601 all_tabs.extend(tabs);
602 }
603
604 controller.tab_groups.insert(0, all_tabs);
605 }
606
607 pub fn select_next_tab(cx: &mut App, id: WindowId) {
609 let mut controller = cx.global_mut::<SystemWindowTabController>();
610 let Some(tabs) = controller.tabs(id) else {
611 return;
612 };
613
614 let current_index = tabs.iter().position(|tab| tab.id == id).unwrap();
615 let next_index = (current_index + 1) % tabs.len();
616
617 let _ = &tabs[next_index].handle.update(cx, |_, window, _| {
618 window.activate_window();
619 });
620 }
621
622 pub fn select_previous_tab(cx: &mut App, id: WindowId) {
624 let mut controller = cx.global_mut::<SystemWindowTabController>();
625 let Some(tabs) = controller.tabs(id) else {
626 return;
627 };
628
629 let current_index = tabs.iter().position(|tab| tab.id == id).unwrap();
630 let previous_index = if current_index == 0 {
631 tabs.len() - 1
632 } else {
633 current_index - 1
634 };
635
636 let _ = &tabs[previous_index].handle.update(cx, |_, window, _| {
637 window.activate_window();
638 });
639 }
640}
641
642pub(crate) enum GpuiMode {
643 #[cfg(any(test, feature = "test-support"))]
644 Test {
645 skip_drawing: bool,
646 },
647 Production,
648}
649
650impl GpuiMode {
651 #[cfg(any(test, feature = "test-support"))]
652 pub fn test() -> Self {
653 GpuiMode::Test {
654 skip_drawing: false,
655 }
656 }
657
658 #[inline]
659 pub(crate) fn skip_drawing(&self) -> bool {
660 match self {
661 #[cfg(any(test, feature = "test-support"))]
662 GpuiMode::Test { skip_drawing } => *skip_drawing,
663 GpuiMode::Production => false,
664 }
665 }
666}
667
668struct PlatformOwnedDrag {
669 source_window: WindowId,
670 state: PlatformOwnedDragState,
671}
672
673enum PlatformOwnedDragState {
674 Suspended(AnyDrag),
675 RestoredInSourceWindow,
678}
679
680pub struct App {
684 pub(crate) this: Weak<AppCell>,
685 pub(crate) platform: Rc<dyn Platform>,
686 text_system: Arc<TextSystem>,
687
688 pub(crate) actions: Rc<ActionRegistry>,
689 pub(crate) active_drag: Option<AnyDrag>,
690 platform_owned_drag: Option<PlatformOwnedDrag>,
691 pub(crate) background_executor: BackgroundExecutor,
692 pub(crate) foreground_executor: ForegroundExecutor,
693 #[cfg(feature = "profiler")]
694 foreground_journal: crate::profiler::journal::ForegroundJournal,
695 pub(crate) entities: EntityMap,
696 pub(crate) new_entity_observers: SubscriberSet<TypeId, NewEntityListener>,
697 pub(crate) windows: SlotMap<WindowId, Option<Box<Window>>>,
698 pub(crate) window_handles: FxHashMap<WindowId, AnyWindowHandle>,
699 pub(crate) focus_handles: Arc<FocusMap>,
700 pub(crate) keymap: Rc<RefCell<Keymap>>,
701 pub(crate) keyboard_layout: Box<dyn PlatformKeyboardLayout>,
702 pub(crate) keyboard_mapper: Rc<dyn PlatformKeyboardMapper>,
703 pub(crate) global_action_listeners:
704 TypeIdHashMap<Vec<Rc<dyn Fn(&dyn Any, DispatchPhase, &mut Self)>>>,
705 pending_effects: VecDeque<Effect>,
706
707 pub(crate) observers: SubscriberSet<EntityId, Handler>,
708 pub(crate) event_listeners: SubscriberSet<EntityId, (TypeId, Listener)>,
709 pub(crate) keystroke_observers: SubscriberSet<(), KeystrokeObserver>,
710 pub(crate) keystroke_interceptors: SubscriberSet<(), KeystrokeObserver>,
711 pub(crate) keyboard_layout_observers: SubscriberSet<(), Handler>,
712 pub(crate) thermal_state_observers: SubscriberSet<(), Handler>,
713 pub(crate) system_wake_observers: SubscriberSet<(), Handler>,
714 pub(crate) release_listeners: SubscriberSet<EntityId, ReleaseListener>,
715 pub(crate) global_observers: SubscriberSet<TypeId, Handler>,
716 pub(crate) quit_observers: SubscriberSet<(), QuitHandler>,
717 pub(crate) restart_observers: SubscriberSet<(), Handler>,
718 pub(crate) window_closed_observers: SubscriberSet<(), WindowClosedHandler>,
719
720 pub(crate) element_arena: RefCell<Arena>,
723 pub(crate) event_arena: Arena,
725
726 pub(crate) globals_by_type: TypeIdHashMap<Box<dyn Any>>,
731
732 pub(crate) loading_assets: FxHashMap<(TypeId, u64), Box<dyn Any>>,
734 asset_source: Arc<dyn AssetSource>,
735 pub(crate) svg_renderer: SvgRenderer,
736 http_client: Arc<dyn HttpClient>,
737
738 pub(crate) pending_notifications: FxHashSet<EntityId>,
740 pub(crate) pending_global_notifications: TypeIdHashSet,
741 pub(crate) restart_path: Option<PathBuf>,
742 pub(crate) restart_arguments: Vec<OsString>,
743 pub(crate) layout_id_buffer: Vec<LayoutId>, pub(crate) propagate_event: bool,
745 pub(crate) prompt_builder: Option<PromptBuilder>,
746 pub(crate) window_invalidators_by_entity:
747 FxHashMap<EntityId, FxHashMap<WindowId, WindowInvalidator>>,
748 pub(crate) tracked_entities: FxHashMap<WindowId, FxHashSet<EntityId>>,
749 pub(crate) current_window_by_entity: FxHashMap<EntityId, WindowId>,
750 #[cfg(any(feature = "inspector", debug_assertions))]
751 pub(crate) inspector_renderer: Option<crate::InspectorRenderer>,
752 #[cfg(any(feature = "inspector", debug_assertions))]
753 pub(crate) inspector_element_registry: InspectorElementRegistry,
754 #[cfg(any(test, feature = "test-support", debug_assertions))]
755 pub(crate) name: Option<&'static str>,
756 pub(crate) text_rendering_mode: Rc<Cell<TextRenderingMode>>,
757
758 pub(crate) window_update_stack: Vec<WindowId>,
759 pub(crate) mode: GpuiMode,
760 pub(crate) cursor_hide_mode: CursorHideMode,
761 pub(crate) reduce_motion: bool,
762 pub(crate) synced_animation_epoch: Instant,
764 pub(crate) accessibility_force_disabled: bool,
767 flushing_effects: bool,
768 pending_updates: usize,
769 quit_mode: QuitMode,
770 quitting: bool,
771
772 #[cfg(any(test, feature = "leak-detection"))]
775 _ref_counts: Arc<RwLock<EntityRefCounts>>,
776}
777
778impl App {
779 #[allow(clippy::new_ret_no_self)]
780 pub(crate) fn new_app(
781 platform: Rc<dyn Platform>,
782 asset_source: Arc<dyn AssetSource>,
783 http_client: Arc<dyn HttpClient>,
784 ) -> Rc<AppCell> {
785 let background_executor = platform.background_executor();
786 let foreground_executor = platform.foreground_executor();
787 assert!(
788 background_executor.is_main_thread(),
789 "must construct App on main thread"
790 );
791 #[cfg(feature = "profiler")]
792 let foreground_journal = crate::profiler::journal::install_foreground_journal();
793 let synced_animation_epoch = background_executor.now();
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 #[cfg(feature = "profiler")]
818 foreground_journal,
819 svg_renderer: SvgRenderer::new(asset_source.clone()),
820 loading_assets: Default::default(),
821 asset_source,
822 http_client,
823 globals_by_type: Default::default(),
824 entities,
825 new_entity_observers: SubscriberSet::new(),
826 windows: SlotMap::with_key(),
827 window_update_stack: Vec::new(),
828 window_handles: FxHashMap::default(),
829 focus_handles: Arc::new(RwLock::new(SlotMap::with_key())),
830 keymap: Rc::new(RefCell::new(Keymap::default())),
831 keyboard_layout,
832 keyboard_mapper,
833 global_action_listeners: Default::default(),
834 pending_effects: VecDeque::new(),
835 pending_notifications: FxHashSet::default(),
836 pending_global_notifications: Default::default(),
837 observers: SubscriberSet::new(),
838 tracked_entities: FxHashMap::default(),
839 window_invalidators_by_entity: FxHashMap::default(),
840 current_window_by_entity: FxHashMap::default(),
841 event_listeners: SubscriberSet::new(),
842 release_listeners: SubscriberSet::new(),
843 keystroke_observers: SubscriberSet::new(),
844 keystroke_interceptors: SubscriberSet::new(),
845 keyboard_layout_observers: SubscriberSet::new(),
846 thermal_state_observers: SubscriberSet::new(),
847 system_wake_observers: SubscriberSet::new(),
848 global_observers: SubscriberSet::new(),
849 quit_observers: SubscriberSet::new(),
850 restart_observers: SubscriberSet::new(),
851 restart_path: None,
852 restart_arguments: Vec::new(),
853 window_closed_observers: SubscriberSet::new(),
854 layout_id_buffer: Default::default(),
855 propagate_event: true,
856 prompt_builder: Some(PromptBuilder::Default),
857 #[cfg(any(feature = "inspector", debug_assertions))]
858 inspector_renderer: None,
859 #[cfg(any(feature = "inspector", debug_assertions))]
860 inspector_element_registry: InspectorElementRegistry::default(),
861 quit_mode: QuitMode::default(),
862 quitting: false,
863 cursor_hide_mode: CursorHideMode::default(),
864 reduce_motion: false,
865 synced_animation_epoch,
866 accessibility_force_disabled: false,
867
868 #[cfg(any(test, feature = "test-support", debug_assertions))]
869 name: None,
870 element_arena: RefCell::new(Arena::new(1024 * 1024)),
871 event_arena: Arena::new(1024 * 1024),
872
873 #[cfg(any(test, feature = "leak-detection"))]
874 _ref_counts,
875 }),
876 });
877
878 init_app_menus(platform.as_ref(), &app.borrow());
879 SystemWindowTabController::init(&mut app.borrow_mut());
880
881 platform.on_keyboard_layout_change(Box::new({
882 let app = Rc::downgrade(&app);
883 move || {
884 if let Some(app) = app.upgrade() {
885 let cx = &mut app.borrow_mut();
886 cx.keyboard_layout = cx.platform.keyboard_layout();
887 cx.keyboard_mapper = cx.platform.keyboard_mapper();
888 cx.keyboard_layout_observers
889 .clone()
890 .retain(&(), move |callback| (callback)(cx));
891 }
892 }
893 }));
894
895 platform.on_thermal_state_change(Box::new({
896 let app = Rc::downgrade(&app);
897 move || {
898 if let Some(app) = app.upgrade() {
899 let cx = &mut app.borrow_mut();
900 cx.thermal_state_observers
901 .clone()
902 .retain(&(), move |callback| (callback)(cx));
903 }
904 }
905 }));
906
907 platform.on_system_wake(Box::new({
908 let app = Rc::downgrade(&app);
909 move || {
910 if let Some(app) = app.upgrade() {
911 let cx = &mut app.borrow_mut();
912 cx.system_wake_observers
913 .clone()
914 .retain(&(), move |callback| (callback)(cx));
915 }
916 }
917 }));
918
919 platform.on_quit(Box::new({
920 let cx = Rc::downgrade(&app);
921 move || {
922 let Some(cx) = cx.upgrade() else {
923 return true;
924 };
925 match cx.try_borrow_mut() {
926 Ok(mut cx) => {
927 cx.shutdown();
928 true
929 }
930 Err(_) => {
931 false
934 }
935 }
936 }
937 }));
938
939 app
940 }
941
942 #[doc(hidden)]
943 pub fn ref_counts_drop_handle(&self) -> impl Sized + use<> {
944 self.entities.ref_counts_drop_handle()
945 }
946
947 #[cfg(any(test, feature = "leak-detection"))]
953 pub fn leak_detector_snapshot(&self) -> LeakDetectorSnapshot {
954 self.entities.leak_detector_snapshot()
955 }
956
957 #[cfg(any(test, feature = "leak-detection"))]
969 pub fn assert_no_new_leaks(&self, snapshot: &LeakDetectorSnapshot) {
970 self.entities.assert_no_new_leaks(snapshot)
971 }
972
973 pub fn shutdown(&mut self) {
979 let mut futures = Vec::new();
980
981 for observer in self.quit_observers.remove(&()) {
982 futures.push(observer(self));
983 }
984
985 self.windows.clear();
986 self.window_handles.clear();
987 self.flush_effects();
988 self.quitting = true;
989
990 let futures = futures::future::join_all(futures);
991 #[cfg(not(target_family = "wasm"))]
992 if self
993 .foreground_executor
994 .block_with_timeout(SHUTDOWN_TIMEOUT, futures)
995 .is_err()
996 {
997 log::error!("timed out waiting on app_will_quit");
998 }
999 #[cfg(target_family = "wasm")]
1000 self.foreground_executor.spawn(futures).detach();
1001
1002 self.quitting = false;
1003 }
1004
1005 pub fn keyboard_layout(&self) -> &dyn PlatformKeyboardLayout {
1007 self.keyboard_layout.as_ref()
1008 }
1009
1010 pub fn keyboard_mapper(&self) -> &Rc<dyn PlatformKeyboardMapper> {
1012 &self.keyboard_mapper
1013 }
1014
1015 pub fn on_keyboard_layout_change<F>(&self, mut callback: F) -> Subscription
1017 where
1018 F: 'static + FnMut(&mut App),
1019 {
1020 let (subscription, activate) = self.keyboard_layout_observers.insert(
1021 (),
1022 Box::new(move |cx| {
1023 callback(cx);
1024 true
1025 }),
1026 );
1027 activate();
1028 subscription
1029 }
1030
1031 pub fn quit(&self) {
1033 self.platform.quit();
1034 }
1035
1036 pub fn cursor_hide_mode(&self) -> CursorHideMode {
1039 self.cursor_hide_mode
1040 }
1041
1042 pub fn set_cursor_hide_mode(&mut self, mode: CursorHideMode) {
1045 self.cursor_hide_mode = mode;
1046 }
1047
1048 pub fn is_cursor_visible(&self) -> bool {
1054 self.platform.is_cursor_visible()
1055 }
1056
1057 pub fn reduce_motion(&self) -> bool {
1060 self.reduce_motion
1061 }
1062
1063 pub fn set_reduce_motion(&mut self, reduce_motion: bool) {
1066 if self.reduce_motion != reduce_motion {
1067 self.reduce_motion = reduce_motion;
1068 self.refresh_windows();
1069 }
1070 }
1071
1072 pub fn refresh_windows(&mut self) {
1075 self.pending_effects.push_back(Effect::RefreshWindows);
1076 }
1077
1078 pub(crate) fn update<R>(&mut self, update: impl FnOnce(&mut Self) -> R) -> R {
1079 self.start_update();
1080 let result = update(self);
1081 self.finish_update();
1082 result
1083 }
1084
1085 pub(crate) fn start_update(&mut self) {
1086 self.pending_updates += 1;
1087 }
1088
1089 pub(crate) fn finish_update(&mut self) {
1090 if !self.flushing_effects && self.pending_updates == 1 {
1091 self.flushing_effects = true;
1092 self.flush_effects();
1093 self.flushing_effects = false;
1094 }
1095 self.pending_updates -= 1;
1096 }
1097
1098 pub fn observe<W>(
1100 &mut self,
1101 entity: &Entity<W>,
1102 mut on_notify: impl FnMut(Entity<W>, &mut App) + 'static,
1103 ) -> Subscription
1104 where
1105 W: 'static,
1106 {
1107 self.observe_internal(entity, move |e, cx| {
1108 on_notify(e, cx);
1109 true
1110 })
1111 }
1112
1113 pub(crate) fn detect_accessed_entities<R>(
1114 &mut self,
1115 callback: impl FnOnce(&mut App) -> R,
1116 ) -> (R, FxHashSet<EntityId>) {
1117 let accessed_entities_start = self.entities.accessed_entities.get_mut().clone();
1118 let result = callback(self);
1119 let entities_accessed_in_callback = self
1120 .entities
1121 .accessed_entities
1122 .get_mut()
1123 .difference(&accessed_entities_start)
1124 .copied()
1125 .collect::<FxHashSet<EntityId>>();
1126 (result, entities_accessed_in_callback)
1127 }
1128
1129 pub(crate) fn record_entities_accessed(
1130 &mut self,
1131 window_handle: AnyWindowHandle,
1132 invalidator: WindowInvalidator,
1133 entities: &FxHashSet<EntityId>,
1134 ) {
1135 let mut tracked_entities =
1136 std::mem::take(self.tracked_entities.entry(window_handle.id).or_default());
1137 for entity in tracked_entities.iter() {
1138 self.window_invalidators_by_entity
1139 .entry(*entity)
1140 .and_modify(|windows| {
1141 windows.remove(&window_handle.id);
1142 });
1143 }
1144 for entity in entities.iter() {
1145 self.window_invalidators_by_entity
1146 .entry(*entity)
1147 .or_default()
1148 .insert(window_handle.id, invalidator.clone());
1149 self.current_window_by_entity
1150 .insert(*entity, window_handle.id);
1151 }
1152 tracked_entities.clear();
1153 tracked_entities.extend(entities.iter().copied());
1154 self.tracked_entities
1155 .insert(window_handle.id, tracked_entities);
1156 }
1157
1158 pub(crate) fn new_observer(&mut self, key: EntityId, value: Handler) -> Subscription {
1159 let (subscription, activate) = self.observers.insert(key, value);
1160 self.defer(move |_| activate());
1161 subscription
1162 }
1163
1164 pub(crate) fn observe_internal<W>(
1165 &mut self,
1166 entity: &Entity<W>,
1167 mut on_notify: impl FnMut(Entity<W>, &mut App) -> bool + 'static,
1168 ) -> Subscription
1169 where
1170 W: 'static,
1171 {
1172 let entity_id = entity.entity_id();
1173 let handle = entity.downgrade();
1174 self.new_observer(
1175 entity_id,
1176 Box::new(move |cx| {
1177 if let Some(entity) = handle.upgrade() {
1178 on_notify(entity, cx)
1179 } else {
1180 false
1181 }
1182 }),
1183 )
1184 }
1185
1186 pub fn subscribe<T, Event>(
1189 &mut self,
1190 entity: &Entity<T>,
1191 mut on_event: impl FnMut(Entity<T>, &Event, &mut App) + 'static,
1192 ) -> Subscription
1193 where
1194 T: 'static + EventEmitter<Event>,
1195 Event: 'static,
1196 {
1197 self.subscribe_internal(entity, move |entity, event, cx| {
1198 on_event(entity, event, cx);
1199 true
1200 })
1201 }
1202
1203 pub(crate) fn new_subscription(
1204 &mut self,
1205 key: EntityId,
1206 value: (TypeId, Listener),
1207 ) -> Subscription {
1208 let (subscription, activate) = self.event_listeners.insert(key, value);
1209 self.defer(move |_| activate());
1210 subscription
1211 }
1212 pub(crate) fn subscribe_internal<T, Evt>(
1213 &mut self,
1214 entity: &Entity<T>,
1215 mut on_event: impl FnMut(Entity<T>, &Evt, &mut App) -> bool + 'static,
1216 ) -> Subscription
1217 where
1218 T: 'static + EventEmitter<Evt>,
1219 Evt: 'static,
1220 {
1221 let entity_id = entity.entity_id();
1222 let handle = entity.downgrade();
1223 self.new_subscription(
1224 entity_id,
1225 (
1226 TypeId::of::<Evt>(),
1227 Box::new(move |event, cx| {
1228 let event: &Evt = event.downcast_ref().expect("invalid event type");
1229 if let Some(entity) = handle.upgrade() {
1230 on_event(entity, event, cx)
1231 } else {
1232 false
1233 }
1234 }),
1235 ),
1236 )
1237 }
1238
1239 pub fn windows(&self) -> Vec<AnyWindowHandle> {
1243 self.windows
1244 .keys()
1245 .flat_map(|window_id| self.window_handles.get(&window_id).copied())
1246 .collect()
1247 }
1248
1249 pub fn window_stack(&self) -> Option<Vec<AnyWindowHandle>> {
1255 self.platform.window_stack()
1256 }
1257
1258 pub fn active_window(&self) -> Option<AnyWindowHandle> {
1260 self.platform.active_window()
1261 }
1262
1263 pub fn open_window<V: 'static + Render>(
1267 &mut self,
1268 options: crate::WindowOptions,
1269 build_root_view: impl FnOnce(&mut Window, &mut App) -> Entity<V>,
1270 ) -> anyhow::Result<WindowHandle<V>> {
1271 self.update(|cx| {
1272 let id = cx.windows.insert(None);
1273 let handle = WindowHandle::new(id);
1274 match Window::new(handle.into(), options, cx) {
1275 Ok(mut window) => {
1276 cx.window_update_stack.push(id);
1277 let root_view = build_root_view(&mut window, cx);
1278 cx.window_update_stack.pop();
1279 window.root.replace(root_view.into());
1280 window.defer(cx, |window: &mut Window, cx| window.appearance_changed(cx));
1281
1282 let clear = window.draw(cx);
1287 clear.clear(cx);
1288
1289 cx.window_handles.insert(id, window.handle);
1290 cx.windows.get_mut(id).unwrap().replace(Box::new(window));
1291 Ok(handle)
1292 }
1293 Err(e) => {
1294 cx.windows.remove(id);
1295 Err(e)
1296 }
1297 }
1298 })
1299 }
1300
1301 pub fn activate(&self, ignoring_other_apps: bool) {
1303 self.platform.activate(ignoring_other_apps);
1304 }
1305
1306 pub fn hide(&self) {
1308 self.platform.hide();
1309 }
1310
1311 pub fn hide_other_apps(&self) {
1313 self.platform.hide_other_apps();
1314 }
1315
1316 pub fn unhide_other_apps(&self) {
1318 self.platform.unhide_other_apps();
1319 }
1320
1321 pub fn displays(&self) -> Vec<Rc<dyn PlatformDisplay>> {
1323 self.platform.displays()
1324 }
1325
1326 pub fn primary_display(&self) -> Option<Rc<dyn PlatformDisplay>> {
1328 self.platform.primary_display()
1329 }
1330
1331 pub fn is_screen_capture_supported(&self) -> bool {
1333 self.platform.is_screen_capture_supported()
1334 }
1335
1336 pub fn screen_capture_sources(
1338 &self,
1339 ) -> oneshot::Receiver<Result<Vec<Rc<dyn ScreenCaptureSource>>>> {
1340 self.platform.screen_capture_sources()
1341 }
1342
1343 pub fn find_display(&self, id: DisplayId) -> Option<Rc<dyn PlatformDisplay>> {
1345 self.displays()
1346 .iter()
1347 .find(|display| display.id() == id)
1348 .cloned()
1349 }
1350
1351 pub fn thermal_state(&self) -> ThermalState {
1353 self.platform.thermal_state()
1354 }
1355
1356 pub fn on_thermal_state_change<F>(&self, mut callback: F) -> Subscription
1358 where
1359 F: 'static + FnMut(&mut App),
1360 {
1361 let (subscription, activate) = self.thermal_state_observers.insert(
1362 (),
1363 Box::new(move |cx| {
1364 callback(cx);
1365 true
1366 }),
1367 );
1368 activate();
1369 subscription
1370 }
1371
1372 pub fn on_system_wake<F>(&self, mut callback: F) -> Subscription
1374 where
1375 F: 'static + FnMut(&mut App),
1376 {
1377 let (subscription, activate) = self.system_wake_observers.insert(
1378 (),
1379 Box::new(move |cx| {
1380 callback(cx);
1381 true
1382 }),
1383 );
1384 activate();
1385 subscription
1386 }
1387
1388 pub fn window_appearance(&self) -> WindowAppearance {
1390 self.platform.window_appearance()
1391 }
1392
1393 pub fn set_window_appearance(&self, appearance: Option<WindowAppearance>) {
1404 self.platform.set_window_appearance(appearance);
1405 }
1406
1407 pub fn button_layout(&self) -> Option<WindowButtonLayout> {
1409 self.platform.button_layout()
1410 }
1411
1412 pub fn read_from_clipboard(&self) -> Option<ClipboardItem> {
1414 self.platform.read_from_clipboard()
1415 }
1416
1417 pub fn read_from_clipboard_async(
1425 &self,
1426 ) -> Task<Result<Option<ClipboardItem>, ClipboardReadError>> {
1427 self.platform.read_from_clipboard_async()
1428 }
1429
1430 pub fn set_text_rendering_mode(&mut self, mode: TextRenderingMode) {
1432 self.text_rendering_mode.set(mode);
1433 }
1434
1435 pub fn text_rendering_mode(&self) -> TextRenderingMode {
1437 self.text_rendering_mode.get()
1438 }
1439
1440 pub fn write_to_clipboard(&self, item: ClipboardItem) {
1442 self.platform.write_to_clipboard(item)
1443 }
1444
1445 #[cfg(any(target_os = "linux", target_os = "freebsd"))]
1448 pub fn read_from_primary(&self) -> Option<ClipboardItem> {
1449 self.platform.read_from_primary()
1450 }
1451
1452 #[cfg(any(target_os = "linux", target_os = "freebsd"))]
1455 pub fn write_to_primary(&self, item: ClipboardItem) {
1456 self.platform.write_to_primary(item)
1457 }
1458
1459 #[cfg(target_os = "macos")]
1465 pub fn read_from_find_pasteboard(&self) -> Option<ClipboardItem> {
1466 self.platform.read_from_find_pasteboard()
1467 }
1468
1469 #[cfg(target_os = "macos")]
1475 pub fn write_to_find_pasteboard(&self, item: ClipboardItem) {
1476 self.platform.write_to_find_pasteboard(item)
1477 }
1478
1479 pub fn write_credentials(
1481 &self,
1482 url: &str,
1483 username: &str,
1484 password: &[u8],
1485 ) -> Task<Result<()>> {
1486 self.platform.write_credentials(url, username, password)
1487 }
1488
1489 pub fn read_credentials(&self, url: &str) -> Task<Result<Option<(String, Vec<u8>)>>> {
1491 self.platform.read_credentials(url)
1492 }
1493
1494 pub fn delete_credentials(&self, url: &str) -> Task<Result<()>> {
1496 self.platform.delete_credentials(url)
1497 }
1498
1499 pub fn open_url(&self, url: &str) {
1501 self.platform.open_url(url);
1502 }
1503
1504 pub fn register_url_scheme(&self, scheme: &str) -> Task<Result<()>> {
1511 self.platform.register_url_scheme(scheme)
1512 }
1513
1514 pub fn set_app_identity(&self, identifier: &str, name: &str) {
1521 self.platform.set_app_identity(identifier, name);
1522 }
1523
1524 pub fn show_system_notification(&self, notification: SystemNotification) {
1531 self.platform.show_system_notification(notification);
1532 }
1533
1534 pub fn dismiss_system_notification(&self, tag: &str) {
1539 self.platform.dismiss_system_notification(tag);
1540 }
1541
1542 pub fn on_system_notification_response<F>(&self, mut callback: F)
1546 where
1547 F: 'static + FnMut(SystemNotificationResponse, &mut App),
1548 {
1549 let this = self.this.clone();
1550 self.platform
1551 .on_system_notification_response(Box::new(move |response| {
1552 if let Some(app) = this.upgrade() {
1553 callback(response, &mut app.borrow_mut());
1554 }
1555 }));
1556 }
1557
1558 pub fn app_path(&self) -> Result<PathBuf> {
1562 self.platform.app_path()
1563 }
1564
1565 pub fn compositor_name(&self) -> &'static str {
1569 self.platform.compositor_name()
1570 }
1571
1572 pub fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf> {
1574 self.platform.path_for_auxiliary_executable(name)
1575 }
1576
1577 pub fn prompt_for_paths(
1583 &self,
1584 options: PathPromptOptions,
1585 ) -> oneshot::Receiver<Result<Option<Vec<PathBuf>>>> {
1586 self.platform.prompt_for_paths(options)
1587 }
1588
1589 pub fn prompt_for_new_path(
1596 &self,
1597 directory: &Path,
1598 suggested_name: Option<&str>,
1599 ) -> oneshot::Receiver<Result<Option<PathBuf>>> {
1600 self.platform.prompt_for_new_path(directory, suggested_name)
1601 }
1602
1603 pub fn reveal_path(&self, path: &Path) {
1605 self.platform.reveal_path(path)
1606 }
1607
1608 pub fn open_with_system(&self, path: &Path) {
1610 self.platform.open_with_system(path)
1611 }
1612
1613 pub fn should_auto_hide_scrollbars(&self) -> bool {
1615 self.platform.should_auto_hide_scrollbars()
1616 }
1617
1618 pub fn restart(&mut self) {
1620 self.restart_observers
1621 .clone()
1622 .retain(&(), |observer| observer(self));
1623 self.platform.restart(
1624 self.restart_path.take(),
1625 std::mem::take(&mut self.restart_arguments),
1626 )
1627 }
1628
1629 pub fn set_restart_path(&mut self, path: PathBuf) {
1631 self.restart_path = Some(path);
1632 }
1633
1634 pub fn http_client(&self) -> Arc<dyn HttpClient> {
1636 self.http_client.clone()
1637 }
1638
1639 pub fn set_http_client(&mut self, new_client: Arc<dyn HttpClient>) {
1641 self.http_client = new_client;
1642 }
1643
1644 pub fn set_quit_mode(&mut self, mode: QuitMode) {
1647 self.quit_mode = mode;
1648 }
1649
1650 pub fn svg_renderer(&self) -> SvgRenderer {
1652 self.svg_renderer.clone()
1653 }
1654
1655 pub(crate) fn push_effect(&mut self, effect: Effect) {
1656 match &effect {
1657 Effect::Notify { emitter } => {
1658 if !self.pending_notifications.insert(*emitter) {
1659 return;
1660 }
1661 }
1662 Effect::NotifyGlobalObservers { global_type } => {
1663 if !self.pending_global_notifications.insert(*global_type) {
1664 return;
1665 }
1666 }
1667 _ => {}
1668 };
1669
1670 self.pending_effects.push_back(effect);
1671 }
1672
1673 fn flush_effects(&mut self) {
1677 loop {
1678 self.release_dropped_entities();
1679 self.release_dropped_focus_handles();
1680 if let Some(effect) = self.pending_effects.pop_front() {
1681 match effect {
1682 Effect::Notify { emitter } => {
1683 self.apply_notify_effect(emitter);
1684 }
1685
1686 Effect::Emit {
1687 emitter,
1688 event_type,
1689 event,
1690 } => self.apply_emit_effect(emitter, event_type, &*event),
1691
1692 Effect::RefreshWindows => {
1693 self.apply_refresh_effect();
1694 }
1695
1696 Effect::NotifyGlobalObservers { global_type } => {
1697 self.apply_notify_global_observers_effect(global_type);
1698 }
1699
1700 Effect::Defer { callback } => {
1701 self.apply_defer_effect(callback);
1702 }
1703 Effect::EntityCreated {
1704 entity,
1705 tid,
1706 window,
1707 } => {
1708 self.apply_entity_created_effect(entity, tid, window);
1709 }
1710 }
1711 } else {
1712 #[cfg(any(test, feature = "test-support", feature = "bench-support"))]
1713 for window in self
1714 .windows
1715 .values()
1716 .filter_map(|window| {
1717 let window = window.as_deref()?;
1718 window.invalidator.is_dirty().then_some(window.handle)
1719 })
1720 .collect::<Vec<_>>()
1721 {
1722 self.update_window(window, |_, window, cx| window.draw(cx).clear(cx))
1723 .unwrap();
1724 }
1725
1726 if self.pending_effects.is_empty() {
1727 for window in self.windows.values().filter_map(|window| window.as_deref()) {
1728 if window.invalidator.is_dirty()
1729 || window.needs_present.get()
1730 || !window.next_frame_callbacks.borrow().is_empty()
1731 {
1732 window.platform_window.schedule_frame();
1733 }
1734 }
1735
1736 self.event_arena.clear();
1737 break;
1738 }
1739 }
1740 }
1741 }
1742
1743 fn release_dropped_entities(&mut self) {
1747 loop {
1748 let dropped = self.entities.take_dropped();
1749 if dropped.is_empty() {
1750 break;
1751 }
1752
1753 for (entity_id, mut entity) in dropped {
1754 self.observers.remove(&entity_id);
1755 self.event_listeners.remove(&entity_id);
1756 self.window_invalidators_by_entity.remove(&entity_id);
1757 self.current_window_by_entity.remove(&entity_id);
1758 for release_callback in self.release_listeners.remove(&entity_id) {
1759 release_callback(entity.as_mut(), self);
1760 }
1761 }
1762 }
1763 }
1764
1765 fn release_dropped_focus_handles(&mut self) {
1767 self.focus_handles
1768 .clone()
1769 .write()
1770 .retain(|handle_id, focus| {
1771 if focus.ref_count.load(SeqCst) == 0 {
1772 for window_handle in self.windows() {
1773 window_handle
1774 .update(self, |_, window, cx| {
1775 if window.focus == Some(handle_id) {
1776 window.blur(cx);
1777 }
1778 })
1779 .unwrap();
1780 }
1781 false
1782 } else {
1783 true
1784 }
1785 });
1786 }
1787
1788 fn apply_notify_effect(&mut self, emitter: EntityId) {
1789 self.pending_notifications.remove(&emitter);
1790
1791 self.observers
1792 .clone()
1793 .retain(&emitter, |handler| handler(self));
1794 }
1795
1796 fn apply_emit_effect(&mut self, emitter: EntityId, event_type: TypeId, event: &dyn Any) {
1797 self.event_listeners
1798 .clone()
1799 .retain(&emitter, |(stored_type, handler)| {
1800 if *stored_type == event_type {
1801 handler(event, self)
1802 } else {
1803 true
1804 }
1805 });
1806 }
1807
1808 fn apply_refresh_effect(&mut self) {
1809 for window in self.windows.values_mut() {
1810 if let Some(window) = window.as_deref_mut() {
1811 window.refreshing = true;
1812 window.invalidator.set_dirty(true);
1813 }
1814 }
1815 }
1816
1817 fn apply_notify_global_observers_effect(&mut self, type_id: TypeId) {
1818 self.pending_global_notifications.remove(&type_id);
1819 self.global_observers
1820 .clone()
1821 .retain(&type_id, |observer| observer(self));
1822 }
1823
1824 fn apply_defer_effect(&mut self, callback: Box<dyn FnOnce(&mut Self) + 'static>) {
1825 callback(self);
1826 }
1827
1828 fn apply_entity_created_effect(
1829 &mut self,
1830 entity: AnyEntity,
1831 tid: TypeId,
1832 window: Option<WindowId>,
1833 ) {
1834 if let Some(id) = window {
1838 self.current_window_by_entity.insert(entity.entity_id(), id);
1839 }
1840
1841 self.new_entity_observers.clone().retain(&tid, |observer| {
1842 if let Some(id) = window {
1843 self.update_window_id(id, {
1844 let entity = entity.clone();
1845 |_, window, cx| (observer)(entity, &mut Some(window), cx)
1846 })
1847 .expect("All windows should be off the stack when flushing effects");
1848 } else {
1849 (observer)(entity.clone(), &mut None, self)
1850 }
1851 true
1852 });
1853 }
1854
1855 pub fn with_window<R>(
1861 &mut self,
1862 entity_id: EntityId,
1863 f: impl FnOnce(&mut Window, &mut App) -> R,
1864 ) -> Option<R> {
1865 let window_id = *self.current_window_by_entity.get(&entity_id)?;
1866 self.update_window_id(window_id, |_, window, cx| f(window, cx))
1867 .ok()
1868 }
1869
1870 fn ensure_window(&mut self, entity_id: EntityId, window: WindowId) {
1871 self.current_window_by_entity
1872 .entry(entity_id)
1873 .or_insert(window);
1874 }
1875
1876 pub(crate) fn update_window_id<T, F>(&mut self, id: WindowId, update: F) -> Result<T>
1877 where
1878 F: FnOnce(AnyView, &mut Window, &mut App) -> T,
1879 {
1880 self.update(|cx| {
1881 let mut window = cx.windows.get_mut(id)?.take()?;
1882
1883 let root_view = window.root.clone().unwrap();
1884
1885 cx.window_update_stack.push(window.handle.id);
1886 let result = update(root_view, &mut window, cx);
1887 fn trail(id: WindowId, window: Box<Window>, cx: &mut App) -> Option<()> {
1888 cx.window_update_stack.pop();
1889
1890 if window.removed {
1891 cx.end_platform_drag(id);
1892 cx.window_handles.remove(&id);
1893 cx.windows.remove(id);
1894 if let Some(tracked) = cx.tracked_entities.remove(&id) {
1895 for entity_id in tracked {
1896 if let Some(windows) =
1897 cx.window_invalidators_by_entity.get_mut(&entity_id)
1898 {
1899 windows.remove(&id);
1900 }
1901 if cx.current_window_by_entity.get(&entity_id) == Some(&id) {
1902 cx.current_window_by_entity.remove(&entity_id);
1903 }
1904 }
1905 }
1906
1907 cx.window_closed_observers.clone().retain(&(), |callback| {
1908 callback(cx, id);
1909 true
1910 });
1911
1912 let quit_on_empty = match cx.quit_mode {
1913 QuitMode::Explicit => false,
1914 QuitMode::LastWindowClosed => true,
1915 QuitMode::Default => cfg!(not(target_os = "macos")),
1916 };
1917
1918 if quit_on_empty && cx.windows.is_empty() {
1919 cx.quit();
1920 }
1921 } else {
1922 cx.windows.get_mut(id)?.replace(window);
1923 }
1924 Some(())
1925 }
1926 trail(id, window, cx)?;
1927
1928 Some(result)
1929 })
1930 .context("window not found")
1931 }
1932
1933 pub fn to_async(&self) -> AsyncApp {
1936 AsyncApp {
1937 app: self.this.clone(),
1938 background_executor: self.background_executor.clone(),
1939 foreground_executor: self.foreground_executor.clone(),
1940 }
1941 }
1942
1943 pub fn background_executor(&self) -> &BackgroundExecutor {
1945 &self.background_executor
1946 }
1947
1948 pub fn foreground_executor(&self) -> &ForegroundExecutor {
1950 if self.quitting {
1951 panic!("Can't spawn on main thread after on_app_quit")
1952 };
1953 &self.foreground_executor
1954 }
1955
1956 #[cfg(feature = "profiler")]
1959 pub fn foreground_journal(&self) -> crate::profiler::journal::ForegroundJournal {
1960 self.foreground_journal.clone()
1961 }
1962
1963 #[track_caller]
1966 pub fn spawn<AsyncFn, R>(&self, f: AsyncFn) -> Task<R>
1967 where
1968 AsyncFn: AsyncFnOnce(&mut AsyncApp) -> R + 'static,
1969 R: 'static,
1970 {
1971 if self.quitting {
1972 debug_panic!("Can't spawn on main thread after on_app_quit")
1973 };
1974
1975 let mut cx = self.to_async();
1976
1977 self.foreground_executor
1978 .spawn(async move { f(&mut cx).await }.boxed_local())
1979 }
1980
1981 pub fn spawn_with_priority<AsyncFn, R>(&self, priority: Priority, f: AsyncFn) -> Task<R>
1985 where
1986 AsyncFn: AsyncFnOnce(&mut AsyncApp) -> R + 'static,
1987 R: 'static,
1988 {
1989 if self.quitting {
1990 debug_panic!("Can't spawn on main thread after on_app_quit")
1991 };
1992
1993 let mut cx = self.to_async();
1994
1995 self.foreground_executor
1996 .spawn_with_priority(priority, async move { f(&mut cx).await }.boxed_local())
1997 }
1998
1999 pub fn defer(&mut self, f: impl FnOnce(&mut App) + 'static) {
2002 self.push_effect(Effect::Defer {
2003 callback: Box::new(f),
2004 });
2005 }
2006
2007 pub fn asset_source(&self) -> &Arc<dyn AssetSource> {
2009 &self.asset_source
2010 }
2011
2012 pub fn text_system(&self) -> &Arc<TextSystem> {
2014 &self.text_system
2015 }
2016
2017 pub fn has_global<G: Global>(&self) -> bool {
2019 self.globals_by_type.contains_key(&TypeId::of::<G>())
2020 }
2021
2022 #[track_caller]
2024 pub fn global<G: Global>(&self) -> &G {
2025 self.globals_by_type
2026 .get(&TypeId::of::<G>())
2027 .map(|any_state| any_state.downcast_ref::<G>().unwrap())
2028 .unwrap_or_else(|| panic!("no state of type {} exists", type_name::<G>()))
2029 }
2030
2031 pub fn try_global<G: Global>(&self) -> Option<&G> {
2033 self.globals_by_type
2034 .get(&TypeId::of::<G>())
2035 .map(|any_state| any_state.downcast_ref::<G>().unwrap())
2036 }
2037
2038 #[track_caller]
2040 pub fn global_mut<G: Global>(&mut self) -> &mut G {
2041 let global_type = TypeId::of::<G>();
2042 self.push_effect(Effect::NotifyGlobalObservers { global_type });
2043 self.globals_by_type
2044 .get_mut(&global_type)
2045 .and_then(|any_state| any_state.downcast_mut::<G>())
2046 .unwrap_or_else(|| panic!("no state of type {} exists", type_name::<G>()))
2047 }
2048
2049 pub fn default_global<G: Global + Default>(&mut self) -> &mut G {
2052 let global_type = TypeId::of::<G>();
2053 self.push_effect(Effect::NotifyGlobalObservers { global_type });
2054 self.globals_by_type
2055 .entry(global_type)
2056 .or_insert_with(|| Box::<G>::default())
2057 .downcast_mut::<G>()
2058 .unwrap()
2059 }
2060
2061 pub fn set_global<G: Global>(&mut self, global: G) {
2063 let global_type = TypeId::of::<G>();
2064 self.push_effect(Effect::NotifyGlobalObservers { global_type });
2065 self.globals_by_type.insert(global_type, Box::new(global));
2066 }
2067
2068 #[cfg(any(test, feature = "test-support"))]
2070 pub fn clear_globals(&mut self) {
2071 self.globals_by_type.drain();
2072 }
2073
2074 pub fn remove_global<G: Global>(&mut self) -> G {
2076 let global_type = TypeId::of::<G>();
2077 self.push_effect(Effect::NotifyGlobalObservers { global_type });
2078 *self
2079 .globals_by_type
2080 .remove(&global_type)
2081 .unwrap_or_else(|| panic!("no global added for {}", type_name::<G>()))
2082 .downcast()
2083 .unwrap()
2084 }
2085
2086 pub fn observe_global<G: Global>(
2088 &mut self,
2089 mut f: impl FnMut(&mut Self) + 'static,
2090 ) -> Subscription {
2091 let (subscription, activate) = self.global_observers.insert(
2092 TypeId::of::<G>(),
2093 Box::new(move |cx| {
2094 f(cx);
2095 true
2096 }),
2097 );
2098 self.defer(move |_| activate());
2099 subscription
2100 }
2101
2102 #[track_caller]
2104 pub(crate) fn lease_global<G: Global>(&mut self) -> GlobalLease<G> {
2105 GlobalLease::new(
2106 self.globals_by_type
2107 .remove(&TypeId::of::<G>())
2108 .with_context(|| format!("no global registered of type {}", type_name::<G>()))
2109 .unwrap(),
2110 )
2111 }
2112
2113 pub(crate) fn end_global_lease<G: Global>(&mut self, lease: GlobalLease<G>) {
2115 let global_type = TypeId::of::<G>();
2116
2117 self.push_effect(Effect::NotifyGlobalObservers { global_type });
2118 self.globals_by_type.insert(global_type, lease.global);
2119 }
2120
2121 pub(crate) fn new_entity_observer(
2122 &self,
2123 key: TypeId,
2124 value: NewEntityListener,
2125 ) -> Subscription {
2126 let (subscription, activate) = self.new_entity_observers.insert(key, value);
2127 activate();
2128 subscription
2129 }
2130
2131 pub fn observe_new<T: 'static>(
2134 &self,
2135 on_new: impl 'static + Fn(&mut T, Option<&mut Window>, &mut Context<T>),
2136 ) -> Subscription {
2137 self.new_entity_observer(
2138 TypeId::of::<T>(),
2139 Box::new(
2140 move |any_entity: AnyEntity, window: &mut Option<&mut Window>, cx: &mut App| {
2141 any_entity
2142 .downcast::<T>()
2143 .unwrap()
2144 .update(cx, |entity_state, cx| {
2145 on_new(entity_state, window.as_deref_mut(), cx)
2146 })
2147 },
2148 ),
2149 )
2150 }
2151
2152 pub fn observe_release<T>(
2155 &self,
2156 handle: &Entity<T>,
2157 on_release: impl FnOnce(&mut T, &mut App) + 'static,
2158 ) -> Subscription
2159 where
2160 T: 'static,
2161 {
2162 let (subscription, activate) = self.release_listeners.insert(
2163 handle.entity_id(),
2164 Box::new(move |entity, cx| {
2165 let entity = entity.downcast_mut().expect("invalid entity type");
2166 on_release(entity, cx)
2167 }),
2168 );
2169 activate();
2170 subscription
2171 }
2172
2173 pub fn observe_release_in<T>(
2176 &self,
2177 handle: &Entity<T>,
2178 window: &Window,
2179 on_release: impl FnOnce(&mut T, &mut Window, &mut App) + 'static,
2180 ) -> Subscription
2181 where
2182 T: 'static,
2183 {
2184 let window_handle = window.handle;
2185 self.observe_release(handle, move |entity, cx| {
2186 let _ = window_handle.update(cx, |_, window, cx| on_release(entity, window, cx));
2187 })
2188 }
2189
2190 pub fn observe_keystrokes(
2194 &mut self,
2195 mut f: impl FnMut(&KeystrokeEvent, &mut Window, &mut App) + 'static,
2196 ) -> Subscription {
2197 fn inner(
2198 keystroke_observers: &SubscriberSet<(), KeystrokeObserver>,
2199 handler: KeystrokeObserver,
2200 ) -> Subscription {
2201 let (subscription, activate) = keystroke_observers.insert((), handler);
2202 activate();
2203 subscription
2204 }
2205
2206 inner(
2207 &self.keystroke_observers,
2208 Box::new(move |event, window, cx| {
2209 f(event, window, cx);
2210 true
2211 }),
2212 )
2213 }
2214
2215 pub fn intercept_keystrokes(
2220 &mut self,
2221 mut f: impl FnMut(&KeystrokeEvent, &mut Window, &mut App) + 'static,
2222 ) -> Subscription {
2223 fn inner(
2224 keystroke_interceptors: &SubscriberSet<(), KeystrokeObserver>,
2225 handler: KeystrokeObserver,
2226 ) -> Subscription {
2227 let (subscription, activate) = keystroke_interceptors.insert((), handler);
2228 activate();
2229 subscription
2230 }
2231
2232 inner(
2233 &self.keystroke_interceptors,
2234 Box::new(move |event, window, cx| {
2235 f(event, window, cx);
2236 true
2237 }),
2238 )
2239 }
2240
2241 pub fn bind_keys(&mut self, bindings: impl IntoIterator<Item = KeyBinding>) {
2243 self.keymap.borrow_mut().add_bindings(bindings);
2244 self.pending_effects.push_back(Effect::RefreshWindows);
2245 }
2246
2247 pub fn clear_key_bindings(&mut self) {
2249 self.keymap.borrow_mut().clear();
2250 self.pending_effects.push_back(Effect::RefreshWindows);
2251 }
2252
2253 pub fn key_bindings(&self) -> Rc<RefCell<Keymap>> {
2255 self.keymap.clone()
2256 }
2257
2258 pub fn on_action<A: Action>(
2262 &mut self,
2263 listener: impl Fn(&A, &mut Self) + 'static,
2264 ) -> &mut Self {
2265 self.global_action_listeners
2266 .entry(TypeId::of::<A>())
2267 .or_default()
2268 .push(Rc::new(move |action, phase, cx| {
2269 if phase == DispatchPhase::Bubble {
2270 let action = action.downcast_ref().unwrap();
2271 listener(action, cx)
2272 }
2273 }));
2274 self
2275 }
2276
2277 pub fn stop_propagation(&mut self) {
2282 self.propagate_event = false;
2283 }
2284
2285 pub fn propagate(&mut self) {
2290 self.propagate_event = true;
2291 }
2292
2293 pub fn build_action(
2295 &self,
2296 name: &str,
2297 data: Option<serde_json::Value>,
2298 ) -> std::result::Result<Box<dyn Action>, ActionBuildError> {
2299 self.actions.build_action(name, data)
2300 }
2301
2302 pub fn all_action_names(&self) -> &[&'static str] {
2305 self.actions.all_action_names()
2306 }
2307
2308 pub fn all_bindings_for_input(&self, input: &[Keystroke]) -> Vec<KeyBinding> {
2312 RefCell::borrow(&self.keymap).all_bindings_for_input(input)
2313 }
2314
2315 pub fn action_schemas(
2317 &self,
2318 generator: &mut schemars::SchemaGenerator,
2319 ) -> Vec<(&'static str, Option<schemars::Schema>)> {
2320 self.actions.action_schemas(generator)
2321 }
2322
2323 pub fn action_schema_by_name(
2328 &self,
2329 name: &str,
2330 generator: &mut schemars::SchemaGenerator,
2331 ) -> Option<Option<schemars::Schema>> {
2332 self.actions.action_schema_by_name(name, generator)
2333 }
2334
2335 pub fn deprecated_actions_to_preferred_actions(&self) -> &HashMap<&'static str, &'static str> {
2337 self.actions.deprecated_aliases()
2338 }
2339
2340 pub fn action_deprecation_messages(&self) -> &HashMap<&'static str, &'static str> {
2342 self.actions.deprecation_messages()
2343 }
2344
2345 pub fn action_documentation(&self) -> &HashMap<&'static str, &'static str> {
2347 self.actions.documentation()
2348 }
2349
2350 pub fn on_app_quit<Fut>(
2353 &self,
2354 mut on_quit: impl FnMut(&mut App) -> Fut + 'static,
2355 ) -> Subscription
2356 where
2357 Fut: 'static + Future<Output = ()>,
2358 {
2359 let (subscription, activate) = self.quit_observers.insert(
2360 (),
2361 Box::new(move |cx| {
2362 let future = on_quit(cx);
2363 future.boxed_local()
2364 }),
2365 );
2366 activate();
2367 subscription
2368 }
2369
2370 pub fn on_app_restart(&self, mut on_restart: impl 'static + FnMut(&mut App)) -> Subscription {
2374 let (subscription, activate) = self.restart_observers.insert(
2375 (),
2376 Box::new(move |cx| {
2377 on_restart(cx);
2378 true
2379 }),
2380 );
2381 activate();
2382 subscription
2383 }
2384
2385 pub fn on_window_closed(
2388 &self,
2389 mut on_closed: impl FnMut(&mut App, WindowId) + 'static,
2390 ) -> Subscription {
2391 let (subscription, activate) = self.window_closed_observers.insert((), Box::new(on_closed));
2392 activate();
2393 subscription
2394 }
2395
2396 pub(crate) fn clear_pending_keystrokes(&mut self) {
2397 for window in self.windows() {
2398 window
2399 .update(self, |_, window, cx| {
2400 window.clear_pending_keystrokes(cx);
2401 })
2402 .ok();
2403 }
2404 }
2405
2406 pub fn is_action_available(&mut self, action: &dyn Action) -> bool {
2409 let mut action_available = false;
2410 if let Some(window) = self.active_window()
2411 && let Ok(window_action_available) =
2412 window.update(self, |_, window, cx| window.is_action_available(action, cx))
2413 {
2414 action_available = window_action_available;
2415 }
2416
2417 action_available
2418 || self
2419 .global_action_listeners
2420 .contains_key(&action.as_any().type_id())
2421 }
2422
2423 pub fn set_menus(&self, menus: impl IntoIterator<Item = Menu>) {
2425 let menus: Vec<Menu> = menus.into_iter().collect();
2426 self.platform.set_menus(menus, &self.keymap.borrow());
2427 }
2428
2429 pub fn get_menus(&self) -> Option<Vec<OwnedMenu>> {
2431 self.platform.get_menus()
2432 }
2433
2434 pub fn set_dock_menu(&self, menus: Vec<MenuItem>) {
2436 self.platform.set_dock_menu(menus, &self.keymap.borrow())
2437 }
2438
2439 pub fn perform_dock_menu_action(&self, action: usize) {
2441 self.platform.perform_dock_menu_action(action);
2442 }
2443
2444 pub fn add_recent_document(&self, path: &Path) {
2449 self.platform.add_recent_document(path);
2450 }
2451
2452 pub fn update_jump_list(
2455 &self,
2456 menus: Vec<MenuItem>,
2457 entries: Vec<SmallVec<[PathBuf; 2]>>,
2458 ) -> Task<Vec<SmallVec<[PathBuf; 2]>>> {
2459 self.platform.update_jump_list(menus, entries)
2460 }
2461
2462 pub fn dispatch_action(&mut self, action: &dyn Action) {
2465 if let Some(active_window) = self.active_window() {
2466 active_window
2467 .update(self, |_, window, cx| {
2468 window.dispatch_action(action.boxed_clone(), cx)
2469 })
2470 .log_err();
2471 } else {
2472 self.dispatch_global_action(action);
2473 }
2474 }
2475
2476 fn dispatch_global_action(&mut self, action: &dyn Action) {
2477 self.propagate_event = true;
2478
2479 if let Some(mut global_listeners) = self
2480 .global_action_listeners
2481 .remove(&action.as_any().type_id())
2482 {
2483 for listener in &global_listeners {
2484 listener(action.as_any(), DispatchPhase::Capture, self);
2485 if !self.propagate_event {
2486 break;
2487 }
2488 }
2489
2490 global_listeners.extend(
2491 self.global_action_listeners
2492 .remove(&action.as_any().type_id())
2493 .unwrap_or_default(),
2494 );
2495
2496 self.global_action_listeners
2497 .insert(action.as_any().type_id(), global_listeners);
2498 }
2499
2500 if self.propagate_event
2501 && let Some(mut global_listeners) = self
2502 .global_action_listeners
2503 .remove(&action.as_any().type_id())
2504 {
2505 for listener in global_listeners.iter().rev() {
2506 listener(action.as_any(), DispatchPhase::Bubble, self);
2507 if !self.propagate_event {
2508 break;
2509 }
2510 }
2511
2512 global_listeners.extend(
2513 self.global_action_listeners
2514 .remove(&action.as_any().type_id())
2515 .unwrap_or_default(),
2516 );
2517
2518 self.global_action_listeners
2519 .insert(action.as_any().type_id(), global_listeners);
2520 }
2521 }
2522
2523 pub fn has_active_drag(&self) -> bool {
2525 self.active_drag.is_some()
2526 }
2527
2528 pub fn active_drag_cursor_style(&self) -> Option<CursorStyle> {
2530 self.active_drag.as_ref().and_then(|drag| drag.cursor_style)
2531 }
2532
2533 pub fn stop_active_drag(&mut self, window: &mut Window) -> bool {
2535 if self.active_drag.is_some() {
2536 self.active_drag = None;
2537 if self.platform_owned_drag.as_ref().is_some_and(|drag| {
2538 drag.source_window == window.window_handle().window_id()
2539 && matches!(&drag.state, PlatformOwnedDragState::RestoredInSourceWindow)
2540 }) {
2541 self.platform_owned_drag = None;
2542 }
2543 window.refresh();
2544 true
2545 } else {
2546 false
2547 }
2548 }
2549
2550 pub(crate) fn hand_active_drag_to_platform(&mut self, source_window: WindowId) -> bool {
2551 let Some(drag) = self.active_drag.take() else {
2552 return false;
2553 };
2554 self.platform_owned_drag = Some(PlatformOwnedDrag {
2555 source_window,
2556 state: PlatformOwnedDragState::Suspended(drag),
2557 });
2558 true
2559 }
2560
2561 pub(crate) fn restore_platform_drag(&mut self, source_window: WindowId) -> bool {
2562 let Some(platform_drag) = self
2563 .platform_owned_drag
2564 .as_mut()
2565 .filter(|drag| drag.source_window == source_window)
2566 else {
2567 return false;
2568 };
2569 let state = std::mem::replace(
2570 &mut platform_drag.state,
2571 PlatformOwnedDragState::RestoredInSourceWindow,
2572 );
2573 let PlatformOwnedDragState::Suspended(drag) = state else {
2574 return false;
2575 };
2576 self.active_drag = Some(drag);
2577 true
2578 }
2579
2580 pub(crate) fn hand_restored_drag_to_platform(&mut self, source_window: WindowId) -> bool {
2581 let Some(platform_drag) = self.platform_owned_drag.as_mut().filter(|drag| {
2582 drag.source_window == source_window
2583 && matches!(&drag.state, PlatformOwnedDragState::RestoredInSourceWindow)
2584 }) else {
2585 return false;
2586 };
2587 let Some(drag) = self.active_drag.take() else {
2588 return false;
2589 };
2590 platform_drag.state = PlatformOwnedDragState::Suspended(drag);
2591 true
2592 }
2593
2594 pub(crate) fn end_platform_drag(&mut self, source_window: WindowId) -> bool {
2595 if !self
2596 .platform_owned_drag
2597 .as_ref()
2598 .is_some_and(|drag| drag.source_window == source_window)
2599 {
2600 return false;
2601 }
2602 self.platform_owned_drag = None;
2603 self.active_drag = None;
2604 true
2605 }
2606
2607 pub fn set_active_drag_cursor_style(
2609 &mut self,
2610 cursor_style: CursorStyle,
2611 window: &mut Window,
2612 ) -> bool {
2613 if let Some(ref mut drag) = self.active_drag {
2614 drag.cursor_style = Some(cursor_style);
2615 window.refresh();
2616 true
2617 } else {
2618 false
2619 }
2620 }
2621
2622 pub fn set_prompt_builder(
2625 &mut self,
2626 renderer: impl Fn(
2627 PromptLevel,
2628 &str,
2629 Option<&str>,
2630 &[PromptButton],
2631 PromptHandle,
2632 &mut Window,
2633 &mut App,
2634 ) -> RenderablePromptHandle
2635 + 'static,
2636 ) {
2637 self.prompt_builder = Some(PromptBuilder::Custom(Box::new(renderer)));
2638 }
2639
2640 pub fn reset_prompt_builder(&mut self) {
2642 self.prompt_builder = Some(PromptBuilder::Default);
2643 }
2644
2645 pub fn remove_asset<A: Asset>(&mut self, source: &A::Source) {
2647 let asset_id = (TypeId::of::<A>(), hash(source));
2648 self.loading_assets.remove(&asset_id);
2649 }
2650
2651 #[cfg(any(test, feature = "test-support"))]
2654 pub fn has_asset<A: Asset>(&self, source: &A::Source) -> bool {
2655 let asset_id = (TypeId::of::<A>(), hash(source));
2656 self.loading_assets.contains_key(&asset_id)
2657 }
2658
2659 pub fn fetch_asset<A: Asset>(&mut self, source: &A::Source) -> (Shared<Task<A::Output>>, bool) {
2664 let asset_id = (TypeId::of::<A>(), hash(source));
2665 let mut is_first = false;
2666 let task = self
2667 .loading_assets
2668 .remove(&asset_id)
2669 .map(|boxed_task| *boxed_task.downcast::<Shared<Task<A::Output>>>().unwrap())
2670 .unwrap_or_else(|| {
2671 is_first = true;
2672 let future = A::load(source.clone(), self);
2673
2674 self.background_executor().spawn(future).shared()
2675 });
2676
2677 self.loading_assets.insert(asset_id, Box::new(task.clone()));
2678
2679 (task, is_first)
2680 }
2681
2682 #[track_caller]
2685 pub fn focus_handle(&self) -> FocusHandle {
2686 FocusHandle::new(&self.focus_handles)
2687 }
2688
2689 pub fn notify(&mut self, entity_id: EntityId) {
2691 let window_invalidators = mem::take(
2692 self.window_invalidators_by_entity
2693 .entry(entity_id)
2694 .or_default(),
2695 );
2696
2697 let live_invalidators: SmallVec<[WindowInvalidator; 2]> = window_invalidators
2702 .iter()
2703 .filter(|(window_id, _)| {
2704 self.tracked_entities
2705 .get(window_id)
2706 .is_some_and(|set| set.contains(&entity_id))
2707 })
2708 .map(|(_, invalidator)| invalidator.clone())
2709 .collect();
2710
2711 if live_invalidators.is_empty() {
2712 if self.pending_notifications.insert(entity_id) {
2713 self.pending_effects
2714 .push_back(Effect::Notify { emitter: entity_id });
2715 }
2716 } else {
2717 for invalidator in &live_invalidators {
2718 invalidator.invalidate_view(entity_id, self);
2719 }
2720 }
2721
2722 self.window_invalidators_by_entity
2723 .insert(entity_id, window_invalidators);
2724 }
2725
2726 #[cfg(any(test, feature = "test-support", debug_assertions))]
2728 pub fn get_name(&self) -> Option<&'static str> {
2729 self.name
2730 }
2731
2732 pub fn can_select_mixed_files_and_dirs(&self) -> bool {
2734 self.platform.can_select_mixed_files_and_dirs()
2735 }
2736
2737 pub fn drop_image(&mut self, image: Arc<RenderImage>, current_window: Option<&mut Window>) {
2742 for window in self.windows.values_mut().flatten() {
2744 _ = window.drop_image(image.clone());
2745 }
2746
2747 if let Some(window) = current_window {
2749 _ = window.drop_image(image);
2750 }
2751 }
2752
2753 #[cfg(any(feature = "inspector", debug_assertions))]
2755 pub fn set_inspector_renderer(&mut self, f: crate::InspectorRenderer) {
2756 self.inspector_renderer = Some(f);
2757 }
2758
2759 #[cfg(any(feature = "inspector", debug_assertions))]
2761 pub fn register_inspector_element<T: 'static, R: crate::IntoElement>(
2762 &mut self,
2763 f: impl 'static + Fn(crate::InspectorElementId, &T, &mut Window, &mut App) -> R,
2764 ) {
2765 self.inspector_element_registry.register(f);
2766 }
2767
2768 pub fn init_colors(&mut self) {
2772 self.set_global(GlobalColors(Arc::new(Colors::default())));
2773 }
2774}
2775
2776impl AppContext for App {
2777 fn new<T: 'static>(&mut self, build_entity: impl FnOnce(&mut Context<T>) -> T) -> Entity<T> {
2782 self.update(|cx| {
2783 let slot = cx.entities.reserve();
2784 let handle = slot.clone();
2785 let entity = build_entity(&mut Context::new_context(cx, slot.downgrade()));
2786
2787 cx.push_effect(Effect::EntityCreated {
2788 entity: handle.into_any(),
2789 tid: TypeId::of::<T>(),
2790 window: cx.window_update_stack.last().cloned(),
2791 });
2792
2793 cx.entities.insert(slot, entity)
2794 })
2795 }
2796
2797 fn reserve_entity<T: 'static>(&mut self) -> Reservation<T> {
2798 Reservation(self.entities.reserve())
2799 }
2800
2801 fn insert_entity<T: 'static>(
2802 &mut self,
2803 reservation: Reservation<T>,
2804 build_entity: impl FnOnce(&mut Context<T>) -> T,
2805 ) -> Entity<T> {
2806 self.update(|cx| {
2807 let slot = reservation.0;
2808 let entity = build_entity(&mut Context::new_context(cx, slot.downgrade()));
2809 cx.entities.insert(slot, entity)
2810 })
2811 }
2812
2813 fn update_entity<T: 'static, R>(
2816 &mut self,
2817 handle: &Entity<T>,
2818 update: impl FnOnce(&mut T, &mut Context<T>) -> R,
2819 ) -> R {
2820 self.update(|cx| {
2821 let mut entity = cx.entities.lease(handle);
2822 let result = update(
2823 &mut entity,
2824 &mut Context::new_context(cx, handle.downgrade()),
2825 );
2826 cx.entities.end_lease(entity);
2827 result
2828 })
2829 }
2830
2831 fn as_mut<'a, T>(&'a mut self, handle: &Entity<T>) -> GpuiBorrow<'a, T>
2832 where
2833 T: 'static,
2834 {
2835 GpuiBorrow::new(handle.clone(), self)
2836 }
2837
2838 fn read_entity<T, R>(&self, handle: &Entity<T>, read: impl FnOnce(&T, &App) -> R) -> R
2839 where
2840 T: 'static,
2841 {
2842 let entity = self.entities.read(handle);
2843 read(entity, self)
2844 }
2845
2846 fn update_window<T, F>(&mut self, handle: AnyWindowHandle, update: F) -> Result<T>
2847 where
2848 F: FnOnce(AnyView, &mut Window, &mut App) -> T,
2849 {
2850 self.update_window_id(handle.id, update)
2851 }
2852
2853 fn with_window<R>(
2854 &mut self,
2855 entity_id: EntityId,
2856 f: impl FnOnce(&mut Window, &mut App) -> R,
2857 ) -> Option<R> {
2858 App::with_window(self, entity_id, f)
2859 }
2860
2861 fn read_window<T, R>(
2862 &self,
2863 window: &WindowHandle<T>,
2864 read: impl FnOnce(Entity<T>, &App) -> R,
2865 ) -> Result<R>
2866 where
2867 T: 'static,
2868 {
2869 let window = self
2870 .windows
2871 .get(window.id)
2872 .context("window not found")?
2873 .as_deref()
2874 .expect("attempted to read a window that is already on the stack");
2875
2876 let root_view = window.root.clone().unwrap();
2877 let view = root_view
2878 .downcast::<T>()
2879 .map_err(|_| anyhow!("root view's type has changed"))?;
2880
2881 Ok(read(view, self))
2882 }
2883
2884 fn background_spawn<R>(&self, future: impl Future<Output = R> + Send + 'static) -> Task<R>
2885 where
2886 R: Send + 'static,
2887 {
2888 self.background_executor.spawn(future)
2889 }
2890
2891 fn read_global<G, R>(&self, callback: impl FnOnce(&G, &App) -> R) -> R
2892 where
2893 G: Global,
2894 {
2895 let mut g = self.global::<G>();
2896 callback(g, self)
2897 }
2898}
2899
2900pub(crate) enum Effect {
2902 Notify {
2903 emitter: EntityId,
2904 },
2905 Emit {
2906 emitter: EntityId,
2907 event_type: TypeId,
2908 event: ArenaBox<dyn Any>,
2909 },
2910 RefreshWindows,
2911 NotifyGlobalObservers {
2912 global_type: TypeId,
2913 },
2914 Defer {
2915 callback: Box<dyn FnOnce(&mut App) + 'static>,
2916 },
2917 EntityCreated {
2918 entity: AnyEntity,
2919 tid: TypeId,
2920 window: Option<WindowId>,
2921 },
2922}
2923
2924impl std::fmt::Debug for Effect {
2925 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2926 match self {
2927 Effect::Notify { emitter } => write!(f, "Notify({})", emitter),
2928 Effect::Emit { emitter, .. } => write!(f, "Emit({:?})", emitter),
2929 Effect::RefreshWindows => write!(f, "RefreshWindows"),
2930 Effect::NotifyGlobalObservers { global_type } => {
2931 write!(f, "NotifyGlobalObservers({:?})", global_type)
2932 }
2933 Effect::Defer { .. } => write!(f, "Defer(..)"),
2934 Effect::EntityCreated { entity, .. } => write!(f, "EntityCreated({:?})", entity),
2935 }
2936 }
2937}
2938
2939pub(crate) struct GlobalLease<G: Global> {
2941 global: Box<dyn Any>,
2942 global_type: PhantomData<G>,
2943}
2944
2945impl<G: Global> GlobalLease<G> {
2946 fn new(global: Box<dyn Any>) -> Self {
2947 GlobalLease {
2948 global,
2949 global_type: PhantomData,
2950 }
2951 }
2952}
2953
2954impl<G: Global> Deref for GlobalLease<G> {
2955 type Target = G;
2956
2957 fn deref(&self) -> &Self::Target {
2958 self.global.downcast_ref().unwrap()
2959 }
2960}
2961
2962impl<G: Global> DerefMut for GlobalLease<G> {
2963 fn deref_mut(&mut self) -> &mut Self::Target {
2964 self.global.downcast_mut().unwrap()
2965 }
2966}
2967
2968pub struct AnyDrag {
2971 pub view: AnyView,
2973
2974 pub value: Arc<dyn Any>,
2976
2977 pub cursor_offset: Point<Pixels>,
2980
2981 pub cursor_style: Option<CursorStyle>,
2983
2984 pub external_payload_source: Option<ExternalDragPayloadSource>,
2987}
2988
2989pub type ExternalDragPayloadSource =
2992 Box<dyn FnOnce(&mut Window, &mut App) -> Option<ExternalDragPayload> + 'static>;
2993
2994#[derive(Clone)]
2997pub struct AnyTooltip {
2998 pub view: AnyView,
3000
3001 pub mouse_position: Point<Pixels>,
3003
3004 pub check_visible_and_update: Rc<dyn Fn(Bounds<Pixels>, &mut Window, &mut App) -> bool>,
3008}
3009
3010#[derive(Debug)]
3012pub struct KeystrokeEvent {
3013 pub keystroke: Keystroke,
3015
3016 pub action: Option<Box<dyn Action>>,
3018
3019 pub context_stack: Vec<KeyContext>,
3021}
3022
3023struct NullHttpClient;
3024
3025impl HttpClient for NullHttpClient {
3026 fn send(
3027 &self,
3028 _req: http_client::Request<http_client::AsyncBody>,
3029 ) -> futures::future::BoxFuture<
3030 'static,
3031 anyhow::Result<http_client::Response<http_client::AsyncBody>>,
3032 > {
3033 async move {
3034 anyhow::bail!("No HttpClient available");
3035 }
3036 .boxed()
3037 }
3038
3039 fn user_agent(&self) -> Option<&http_client::http::HeaderValue> {
3040 None
3041 }
3042
3043 fn proxy(&self) -> Option<&Url> {
3044 None
3045 }
3046}
3047
3048pub struct GpuiBorrow<'a, T> {
3050 inner: Option<Lease<T>>,
3051 app: &'a mut App,
3052}
3053
3054impl<'a, T: 'static> GpuiBorrow<'a, T> {
3055 fn new(inner: Entity<T>, app: &'a mut App) -> Self {
3056 app.start_update();
3057 let lease = app.entities.lease(&inner);
3058 Self {
3059 inner: Some(lease),
3060 app,
3061 }
3062 }
3063}
3064
3065impl<'a, T: 'static> std::borrow::Borrow<T> for GpuiBorrow<'a, T> {
3066 fn borrow(&self) -> &T {
3067 self.inner.as_ref().unwrap().borrow()
3068 }
3069}
3070
3071impl<'a, T: 'static> std::borrow::BorrowMut<T> for GpuiBorrow<'a, T> {
3072 fn borrow_mut(&mut self) -> &mut T {
3073 self.inner.as_mut().unwrap().borrow_mut()
3074 }
3075}
3076
3077impl<'a, T: 'static> std::ops::Deref for GpuiBorrow<'a, T> {
3078 type Target = T;
3079
3080 fn deref(&self) -> &Self::Target {
3081 self.inner.as_ref().unwrap()
3082 }
3083}
3084
3085impl<'a, T: 'static> std::ops::DerefMut for GpuiBorrow<'a, T> {
3086 fn deref_mut(&mut self) -> &mut T {
3087 self.inner.as_mut().unwrap()
3088 }
3089}
3090
3091impl<'a, T> Drop for GpuiBorrow<'a, T> {
3092 fn drop(&mut self) {
3093 let lease = self.inner.take().unwrap();
3094 self.app.notify(lease.id);
3095 self.app.entities.end_lease(lease);
3096 self.app.finish_update();
3097 }
3098}
3099
3100#[cfg(test)]
3101mod test {
3102 use std::{
3103 cell::{Cell, RefCell},
3104 ffi::OsString,
3105 path::PathBuf,
3106 rc::Rc,
3107 };
3108
3109 #[cfg(unix)]
3110 use std::os::unix::ffi::OsStringExt;
3111
3112 use crate::{AppContext, Context, Empty, IntoElement, Render, TestAppContext, Window};
3113
3114 struct RenderCounter(Rc<Cell<usize>>);
3115
3116 impl Render for RenderCounter {
3117 fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
3118 self.0.set(self.0.get() + 1);
3119 Empty
3120 }
3121 }
3122
3123 #[gpui::test]
3124 fn async_app_refresh_flushes_refresh_effect(cx: &mut TestAppContext) {
3125 let render_count = Rc::new(Cell::new(0));
3126
3127 let _window = cx.add_window({
3128 let render_count = render_count.clone();
3129 move |_, _| RenderCounter(render_count)
3130 });
3131
3132 cx.run_until_parked();
3133 let render_count_before_refresh = render_count.get();
3134
3135 cx.to_async().refresh();
3136
3137 assert_eq!(render_count.get(), render_count_before_refresh + 1);
3138 }
3139
3140 #[test]
3141 fn test_gpui_borrow() {
3142 let cx = TestAppContext::single();
3143 let observation_count = Rc::new(RefCell::new(0));
3144
3145 let state = cx.update(|cx| {
3146 let state = cx.new(|_| false);
3147 cx.observe(&state, {
3148 let observation_count = observation_count.clone();
3149 move |_, _| {
3150 let mut count = observation_count.borrow_mut();
3151 *count += 1;
3152 }
3153 })
3154 .detach();
3155
3156 state
3157 });
3158
3159 cx.update(|cx| {
3160 *std::borrow::BorrowMut::borrow_mut(&mut state.as_mut(cx)) = true;
3162 });
3163
3164 cx.update(|cx| {
3165 state.write(cx, false);
3166 });
3167
3168 assert_eq!(*observation_count.borrow(), 2);
3169 }
3170
3171 #[gpui::test]
3172 async fn test_restart_preserves_path_and_arguments(cx: &mut TestAppContext) {
3173 #[cfg(unix)]
3174 let user_data_dir = OsString::from_vec(b"/tmp/zed data/\xff".to_vec());
3175 #[cfg(not(unix))]
3176 let user_data_dir = OsString::from("C:\\zed data");
3177 let arguments = vec![OsString::from("--user-data-dir"), user_data_dir];
3178 let restart_path = PathBuf::from("updated-zed");
3179 let _application =
3180 super::Application(cx.app.clone()).with_restart_arguments(arguments.clone());
3181 let restart = cx.expect_restart();
3182
3183 cx.update(|cx| {
3184 cx.set_restart_path(restart_path.clone());
3185 cx.restart();
3186 });
3187
3188 let (path, restart_arguments) = restart.await.expect("restart was not requested");
3189 assert_eq!(path, Some(restart_path));
3190 assert_eq!(restart_arguments, arguments);
3191 }
3192}