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::{Future, FutureExt, channel::oneshot, future::LocalBoxFuture};
18use itertools::Itertools;
19use parking_lot::RwLock;
20use slotmap::SlotMap;
21
22pub use async_context::*;
23#[cfg(feature = "bench-support")]
24pub use bench_context::{BenchAppContext, BenchReport, BenchWindowContext, bench_platform};
25use collections::{FxHashMap, FxHashSet, HashMap, TypeIdHashMap, TypeIdHashSet, VecDeque};
26pub use context::*;
27pub use entity_map::*;
28use gpui_util::{ResultExt, debug_panic};
29#[cfg(any(test, feature = "test-support"))]
30pub use headless_app_context::*;
31use http_client::{HttpClient, Url};
32use smallvec::SmallVec;
33#[cfg(any(test, feature = "test-support"))]
34pub use test_app::*;
35#[cfg(any(test, feature = "test-support"))]
36pub use test_context::*;
37#[cfg(all(target_os = "macos", any(test, feature = "test-support")))]
38pub use visual_test_context::*;
39
40#[cfg(any(feature = "inspector", debug_assertions))]
41use crate::InspectorElementRegistry;
42use crate::asset_cache::CachedLoad;
43use crate::{
44 Action, ActionBuildError, ActionRegistry, ActivityGuard, Any, AnyView, AnyWindowHandle,
45 AppContext, Arena, ArenaBox, Asset, AssetSource, BackgroundExecutor, Bounds, ClipboardItem,
46 ClipboardReadError, CursorStyle, DispatchPhase, DisplayId, EventEmitter, ExternalDragPayload,
47 FocusHandle, FocusMap, ForegroundExecutor, Global, KeyBinding, KeyContext, Keymap, Keystroke,
48 LayoutId, Menu, MenuItem, OwnedMenu, PathPromptOptions, Pixels, Platform, PlatformDisplay,
49 PlatformKeyboardLayout, PlatformKeyboardMapper, Point, Priority, PromptBuilder, PromptButton,
50 PromptHandle, PromptLevel, Render, RenderImage, RenderablePromptHandle, Reservation,
51 ScreenCaptureSource, SharedString, SubscriberSet, Subscription, SvgRenderer,
52 SystemNotification, SystemNotificationResponse, Task, TextRenderingMode, TextSystem,
53 ThermalState, Window, WindowAppearance, WindowButtonLayout, WindowHandle, WindowId,
54 WindowInvalidator,
55 colors::{Colors, GlobalColors},
56 hash, init_app_menus,
57};
58
59mod async_context;
60#[cfg(feature = "bench-support")]
61mod bench_context;
62mod context;
63mod entity_map;
64#[cfg(any(test, feature = "test-support"))]
65mod headless_app_context;
66#[cfg(any(test, feature = "test-support"))]
67mod test_app;
68#[cfg(any(test, feature = "test-support"))]
69mod test_context;
70#[cfg(all(target_os = "macos", any(test, feature = "test-support")))]
71mod visual_test_context;
72
73pub const SHUTDOWN_TIMEOUT: Duration = Duration::from_millis(200);
76
77#[doc(hidden)]
80pub struct AppCell {
81 app: RefCell<App>,
82}
83
84impl AppCell {
85 #[doc(hidden)]
86 #[track_caller]
87 pub fn borrow(&self) -> AppRef<'_> {
88 if option_env!("TRACK_THREAD_BORROWS").is_some() {
89 let thread_id = std::thread::current().id();
90 eprintln!("borrowed {thread_id:?}");
91 }
92 AppRef(self.app.borrow())
93 }
94
95 #[doc(hidden)]
96 #[track_caller]
97 pub fn borrow_mut(&self) -> AppRefMut<'_> {
98 if option_env!("TRACK_THREAD_BORROWS").is_some() {
99 let thread_id = std::thread::current().id();
100 eprintln!("borrowed {thread_id:?}");
101 }
102 AppRefMut(self.app.borrow_mut())
103 }
104
105 #[doc(hidden)]
106 #[track_caller]
107 pub fn try_borrow_mut(&self) -> Result<AppRefMut<'_>, BorrowMutError> {
108 if option_env!("TRACK_THREAD_BORROWS").is_some() {
109 let thread_id = std::thread::current().id();
110 eprintln!("borrowed {thread_id:?}");
111 }
112 Ok(AppRefMut(self.app.try_borrow_mut()?))
113 }
114}
115
116#[doc(hidden)]
117#[derive(Deref, DerefMut)]
118pub struct AppRef<'a>(Ref<'a, App>);
119
120impl Drop for AppRef<'_> {
121 fn drop(&mut self) {
122 if option_env!("TRACK_THREAD_BORROWS").is_some() {
123 let thread_id = std::thread::current().id();
124 eprintln!("dropped borrow from {thread_id:?}");
125 }
126 }
127}
128
129#[doc(hidden)]
130#[derive(Deref, DerefMut)]
131pub struct AppRefMut<'a>(RefMut<'a, App>);
132
133impl Drop for AppRefMut<'_> {
134 fn drop(&mut self) {
135 if option_env!("TRACK_THREAD_BORROWS").is_some() {
136 let thread_id = std::thread::current().id();
137 eprintln!("dropped {thread_id:?}");
138 }
139 }
140}
141
142pub struct Application(Rc<AppCell>);
145
146pub struct ApplicationHandle {
152 app: Rc<AppCell>,
153}
154
155impl ApplicationHandle {
156 pub fn update<R>(&self, f: impl FnOnce(&mut App) -> R) -> R {
160 let cx = &mut *self.app.borrow_mut();
161 f(cx)
162 }
163
164 pub fn to_async(&self) -> AsyncApp {
167 self.update(|cx| cx.to_async())
168 }
169}
170
171impl Application {
174 pub fn with_platform(platform: Rc<dyn Platform>) -> Self {
176 Self(App::new_app(
177 platform,
178 Arc::new(()),
179 Arc::new(NullHttpClient),
180 ))
181 }
182
183 pub fn new_inaccessible(platform: Rc<dyn Platform>) -> Self {
193 let this = Self::with_platform(platform);
194 this.0.borrow_mut().accessibility_force_disabled = true;
195 this
196 }
197
198 pub fn with_assets(self, asset_source: impl AssetSource) -> Self {
200 let mut context_lock = self.0.borrow_mut();
201 let asset_source = Arc::new(asset_source);
202 context_lock.asset_source = asset_source.clone();
203 context_lock.svg_renderer = SvgRenderer::new(asset_source);
204 drop(context_lock);
205 self
206 }
207
208 pub fn with_restart_arguments(self, arguments: Vec<OsString>) -> Self {
210 self.0.borrow_mut().restart_arguments = arguments;
211 self
212 }
213
214 pub fn with_http_client(self, http_client: Arc<dyn HttpClient>) -> Self {
216 let mut context_lock = self.0.borrow_mut();
217 context_lock.http_client = http_client;
218 drop(context_lock);
219 self
220 }
221
222 pub fn with_quit_mode(self, mode: QuitMode) -> Self {
225 self.0.borrow_mut().quit_mode = mode;
226 self
227 }
228
229 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 #[cfg(target_family = "wasm")]
246 std::mem::forget(self);
247 }
248
249 pub fn run_embedded<F>(self, on_finish_launching: F) -> ApplicationHandle
259 where
260 F: 'static + FnOnce(&mut App),
261 {
262 let this = self.0.clone();
263 let platform = self.0.borrow().platform.clone();
264 platform.run(Box::new(move || {
265 let cx = &mut *this.borrow_mut();
266 on_finish_launching(cx);
267 }));
268 ApplicationHandle { app: self.0 }
269 }
270
271 pub fn on_open_urls<F>(&self, mut callback: F) -> &Self
274 where
275 F: 'static + FnMut(Vec<String>),
276 {
277 self.0.borrow().platform.on_open_urls(Box::new(callback));
278 self
279 }
280
281 pub fn on_reopen<F>(&self, mut callback: F) -> &Self
284 where
285 F: 'static + FnMut(&mut App),
286 {
287 let this = Rc::downgrade(&self.0);
288 self.0.borrow_mut().platform.on_reopen(Box::new(move || {
289 if let Some(app) = this.upgrade() {
290 callback(&mut app.borrow_mut());
291 }
292 }));
293 self
294 }
295
296 pub fn background_executor(&self) -> BackgroundExecutor {
298 self.0.borrow().background_executor.clone()
299 }
300
301 pub fn foreground_executor(&self) -> ForegroundExecutor {
303 self.0.borrow().foreground_executor.clone()
304 }
305
306 pub fn text_system(&self) -> Arc<TextSystem> {
308 self.0.borrow().text_system.clone()
309 }
310
311 pub fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf> {
313 self.0.borrow().path_for_auxiliary_executable(name)
314 }
315}
316
317type Handler = Box<dyn FnMut(&mut App) -> bool + 'static>;
318type Listener = Box<dyn FnMut(&dyn Any, &mut App) -> bool + 'static>;
319pub(crate) type KeystrokeObserver =
320 Box<dyn FnMut(&KeystrokeEvent, &mut Window, &mut App) -> bool + 'static>;
321type QuitHandler = Box<dyn FnOnce(&mut App) -> LocalBoxFuture<'static, ()> + 'static>;
322type WindowClosedHandler = Box<dyn FnMut(&mut App, WindowId)>;
323type ReleaseListener = Box<dyn FnOnce(&mut dyn Any, &mut App) + 'static>;
324type NewEntityListener = Box<dyn FnMut(AnyEntity, &mut Option<&mut Window>, &mut App) + 'static>;
325
326#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
328pub enum QuitMode {
329 #[default]
331 Default,
332 LastWindowClosed,
334 Explicit,
336}
337
338#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
343pub enum CursorHideMode {
344 Never,
346 OnTyping,
348 #[default]
351 OnTypingAndAction,
352}
353
354#[doc(hidden)]
355#[derive(Clone, PartialEq, Eq)]
356pub struct SystemWindowTab {
357 pub id: WindowId,
358 pub title: SharedString,
359 pub handle: AnyWindowHandle,
360 pub last_active_at: Instant,
361}
362
363impl SystemWindowTab {
364 pub fn new(title: SharedString, handle: AnyWindowHandle) -> Self {
366 Self {
367 id: handle.id,
368 title,
369 handle,
370 last_active_at: Instant::now(),
371 }
372 }
373}
374
375#[derive(Default)]
377pub struct SystemWindowTabController {
378 visible: Option<bool>,
379 tab_groups: FxHashMap<usize, Vec<SystemWindowTab>>,
380}
381
382impl Global for SystemWindowTabController {}
383
384impl SystemWindowTabController {
385 pub fn new() -> Self {
387 Self {
388 visible: None,
389 tab_groups: FxHashMap::default(),
390 }
391 }
392
393 pub fn init(cx: &mut App) {
395 cx.set_global(SystemWindowTabController::new());
396 }
397
398 pub fn tab_groups(&self) -> &FxHashMap<usize, Vec<SystemWindowTab>> {
400 &self.tab_groups
401 }
402
403 pub fn get_next_tab_group_window(cx: &mut App, id: WindowId) -> Option<&AnyWindowHandle> {
405 let controller = cx.global::<SystemWindowTabController>();
406 let current_group = controller
407 .tab_groups
408 .iter()
409 .find_map(|(group, tabs)| tabs.iter().find(|tab| tab.id == id).map(|_| group));
410
411 let current_group = current_group?;
412 let mut group_ids: Vec<_> = controller.tab_groups.keys().collect();
414 let idx = group_ids.iter().position(|g| *g == current_group)?;
415 let next_idx = (idx + 1) % group_ids.len();
416
417 controller
418 .tab_groups
419 .get(group_ids[next_idx])
420 .and_then(|tabs| {
421 tabs.iter()
422 .max_by_key(|tab| tab.last_active_at)
423 .or_else(|| tabs.first())
424 .map(|tab| &tab.handle)
425 })
426 }
427
428 pub fn get_prev_tab_group_window(cx: &mut App, id: WindowId) -> Option<&AnyWindowHandle> {
430 let controller = cx.global::<SystemWindowTabController>();
431 let current_group = controller
432 .tab_groups
433 .iter()
434 .find_map(|(group, tabs)| tabs.iter().find(|tab| tab.id == id).map(|_| group));
435
436 let current_group = current_group?;
437 let mut group_ids: Vec<_> = controller.tab_groups.keys().collect();
439 let idx = group_ids.iter().position(|g| *g == current_group)?;
440 let prev_idx = if idx == 0 {
441 group_ids.len() - 1
442 } else {
443 idx - 1
444 };
445
446 controller
447 .tab_groups
448 .get(group_ids[prev_idx])
449 .and_then(|tabs| {
450 tabs.iter()
451 .max_by_key(|tab| tab.last_active_at)
452 .or_else(|| tabs.first())
453 .map(|tab| &tab.handle)
454 })
455 }
456
457 pub fn tabs(&self, id: WindowId) -> Option<&Vec<SystemWindowTab>> {
459 self.tab_groups
460 .values()
461 .find(|tabs| tabs.iter().any(|tab| tab.id == id))
462 }
463
464 pub fn init_visible(cx: &mut App, visible: bool) {
466 let mut controller = cx.global_mut::<SystemWindowTabController>();
467 if controller.visible.is_none() {
468 controller.visible = Some(visible);
469 }
470 }
471
472 pub fn is_visible(&self) -> bool {
474 self.visible.unwrap_or(false)
475 }
476
477 pub fn set_visible(cx: &mut App, visible: bool) {
479 let mut controller = cx.global_mut::<SystemWindowTabController>();
480 controller.visible = Some(visible);
481 }
482
483 pub fn update_last_active(cx: &mut App, id: WindowId) {
485 let mut controller = cx.global_mut::<SystemWindowTabController>();
486 for windows in controller.tab_groups.values_mut() {
487 for tab in windows.iter_mut() {
488 if tab.id == id {
489 tab.last_active_at = Instant::now();
490 }
491 }
492 }
493 }
494
495 pub fn update_tab_position(cx: &mut App, id: WindowId, ix: usize) {
497 let mut controller = cx.global_mut::<SystemWindowTabController>();
498 for (_, windows) in controller.tab_groups.iter_mut() {
499 if let Some(current_pos) = windows.iter().position(|tab| tab.id == id) {
500 if ix < windows.len() && current_pos != ix {
501 let window_tab = windows.remove(current_pos);
502 windows.insert(ix, window_tab);
503 }
504 break;
505 }
506 }
507 }
508
509 pub fn update_tab_title(cx: &mut App, id: WindowId, title: SharedString) {
511 let controller = cx.global::<SystemWindowTabController>();
512 let tab = controller
513 .tab_groups
514 .values()
515 .flat_map(|windows| windows.iter())
516 .find(|tab| tab.id == id);
517
518 if tab.map_or(true, |t| t.title == title) {
519 return;
520 }
521
522 let mut controller = cx.global_mut::<SystemWindowTabController>();
523 for windows in controller.tab_groups.values_mut() {
524 for tab in windows.iter_mut() {
525 if tab.id == id {
526 tab.title = title;
527 return;
528 }
529 }
530 }
531 }
532
533 pub fn add_tab(cx: &mut App, id: WindowId, tabs: Vec<SystemWindowTab>) {
535 let mut controller = cx.global_mut::<SystemWindowTabController>();
536 let Some(tab) = tabs.iter().find(|tab| tab.id == id).cloned() else {
537 return;
538 };
539
540 let mut expected_tab_ids: Vec<_> = tabs
541 .iter()
542 .filter(|tab| tab.id != id)
543 .map(|tab| tab.id)
544 .sorted()
545 .collect();
546
547 let mut tab_group_id = None;
548 for (group_id, group_tabs) in &controller.tab_groups {
549 let tab_ids: Vec<_> = group_tabs.iter().map(|tab| tab.id).sorted().collect();
550 if tab_ids == expected_tab_ids {
551 tab_group_id = Some(*group_id);
552 break;
553 }
554 }
555
556 if let Some(tab_group_id) = tab_group_id {
557 if let Some(tabs) = controller.tab_groups.get_mut(&tab_group_id) {
558 tabs.push(tab);
559 }
560 } else {
561 let new_group_id = controller.tab_groups.len();
562 controller.tab_groups.insert(new_group_id, tabs);
563 }
564 }
565
566 pub fn remove_tab(cx: &mut App, id: WindowId) -> Option<SystemWindowTab> {
568 let mut controller = cx.global_mut::<SystemWindowTabController>();
569 let mut removed_tab = None;
570
571 controller.tab_groups.retain(|_, tabs| {
572 if let Some(pos) = tabs.iter().position(|tab| tab.id == id) {
573 removed_tab = Some(tabs.remove(pos));
574 }
575 !tabs.is_empty()
576 });
577
578 removed_tab
579 }
580
581 pub fn move_tab_to_new_window(cx: &mut App, id: WindowId) {
583 let mut removed_tab = Self::remove_tab(cx, id);
584 let mut controller = cx.global_mut::<SystemWindowTabController>();
585
586 if let Some(tab) = removed_tab {
587 let new_group_id = controller.tab_groups.keys().max().map_or(0, |k| k + 1);
588 controller.tab_groups.insert(new_group_id, vec![tab]);
589 }
590 }
591
592 pub fn merge_all_windows(cx: &mut App, id: WindowId) {
594 let mut controller = cx.global_mut::<SystemWindowTabController>();
595 let Some(initial_tabs) = controller.tabs(id) else {
596 return;
597 };
598
599 let initial_tabs_len = initial_tabs.len();
600 let mut all_tabs = initial_tabs.clone();
601
602 for (_, mut tabs) in controller.tab_groups.drain() {
603 tabs.retain(|tab| !all_tabs[..initial_tabs_len].contains(tab));
604 all_tabs.extend(tabs);
605 }
606
607 controller.tab_groups.insert(0, all_tabs);
608 }
609
610 pub fn select_next_tab(cx: &mut App, id: WindowId) {
612 let mut controller = cx.global_mut::<SystemWindowTabController>();
613 let Some(tabs) = controller.tabs(id) else {
614 return;
615 };
616
617 let current_index = tabs.iter().position(|tab| tab.id == id).unwrap();
618 let next_index = (current_index + 1) % tabs.len();
619
620 let _ = &tabs[next_index].handle.update(cx, |_, window, _| {
621 window.activate_window();
622 });
623 }
624
625 pub fn select_previous_tab(cx: &mut App, id: WindowId) {
627 let mut controller = cx.global_mut::<SystemWindowTabController>();
628 let Some(tabs) = controller.tabs(id) else {
629 return;
630 };
631
632 let current_index = tabs.iter().position(|tab| tab.id == id).unwrap();
633 let previous_index = if current_index == 0 {
634 tabs.len() - 1
635 } else {
636 current_index - 1
637 };
638
639 let _ = &tabs[previous_index].handle.update(cx, |_, window, _| {
640 window.activate_window();
641 });
642 }
643}
644
645pub(crate) enum GpuiMode {
646 #[cfg(any(test, feature = "test-support"))]
647 Test {
648 skip_drawing: bool,
649 },
650 Production,
651}
652
653impl GpuiMode {
654 #[cfg(any(test, feature = "test-support"))]
655 pub fn test() -> Self {
656 GpuiMode::Test {
657 skip_drawing: false,
658 }
659 }
660
661 #[inline]
662 pub(crate) fn skip_drawing(&self) -> bool {
663 match self {
664 #[cfg(any(test, feature = "test-support"))]
665 GpuiMode::Test { skip_drawing } => *skip_drawing,
666 GpuiMode::Production => false,
667 }
668 }
669}
670
671struct PlatformOwnedDrag {
672 source_window: WindowId,
673 state: PlatformOwnedDragState,
674}
675
676enum PlatformOwnedDragState {
677 Suspended(AnyDrag),
678 RestoredInSourceWindow,
681}
682
683pub struct App {
687 pub(crate) this: Weak<AppCell>,
688 pub(crate) platform: Rc<dyn Platform>,
689 text_system: Arc<TextSystem>,
690
691 pub(crate) actions: Rc<ActionRegistry>,
692 pub(crate) active_drag: Option<AnyDrag>,
693 platform_owned_drag: Option<PlatformOwnedDrag>,
694 pub(crate) background_executor: BackgroundExecutor,
695 pub(crate) foreground_executor: ForegroundExecutor,
696 #[cfg(feature = "profiler")]
697 foreground_journal: crate::profiler::journal::ForegroundJournal,
698 pub(crate) entities: EntityMap,
699 pub(crate) new_entity_observers: SubscriberSet<TypeId, NewEntityListener>,
700 pub(crate) windows: SlotMap<WindowId, Option<Box<Window>>>,
701 pub(crate) window_handles: FxHashMap<WindowId, AnyWindowHandle>,
702 pub(crate) focus_handles: Arc<FocusMap>,
703 pub(crate) keymap: Rc<RefCell<Keymap>>,
704 pub(crate) keyboard_layout: Box<dyn PlatformKeyboardLayout>,
705 pub(crate) keyboard_mapper: Rc<dyn PlatformKeyboardMapper>,
706 pub(crate) global_action_listeners:
707 TypeIdHashMap<Vec<Rc<dyn Fn(&dyn Any, DispatchPhase, &mut Self)>>>,
708 pending_effects: VecDeque<Effect>,
709
710 pub(crate) observers: SubscriberSet<EntityId, Handler>,
711 pub(crate) event_listeners: SubscriberSet<EntityId, (TypeId, Listener)>,
712 pub(crate) keystroke_observers: SubscriberSet<(), KeystrokeObserver>,
713 pub(crate) keystroke_interceptors: SubscriberSet<(), KeystrokeObserver>,
714 pub(crate) keyboard_layout_observers: SubscriberSet<(), Handler>,
715 pub(crate) thermal_state_observers: SubscriberSet<(), Handler>,
716 pub(crate) system_sleep_observers: SubscriberSet<(), Handler>,
717 pub(crate) system_wake_observers: SubscriberSet<(), Handler>,
718 pub(crate) release_listeners: SubscriberSet<EntityId, ReleaseListener>,
719 pub(crate) global_observers: SubscriberSet<TypeId, Handler>,
720 pub(crate) quit_observers: SubscriberSet<(), QuitHandler>,
721 pub(crate) restart_observers: SubscriberSet<(), Handler>,
722 pub(crate) window_closed_observers: SubscriberSet<(), WindowClosedHandler>,
723
724 pub(crate) element_arena: RefCell<Arena>,
727 pub(crate) event_arena: Arena,
729
730 pub(crate) globals_by_type: TypeIdHashMap<Box<dyn Any>>,
735
736 pub(crate) loading_assets: FxHashMap<(TypeId, u64), Box<dyn Any>>,
738 asset_source: Arc<dyn AssetSource>,
739 pub(crate) svg_renderer: SvgRenderer,
740 http_client: Arc<dyn HttpClient>,
741
742 pub(crate) pending_notifications: FxHashSet<EntityId>,
744 pub(crate) pending_global_notifications: TypeIdHashSet,
745 pub(crate) restart_path: Option<PathBuf>,
746 pub(crate) restart_arguments: Vec<OsString>,
747 pub(crate) layout_id_buffer: Vec<LayoutId>, pub(crate) propagate_event: bool,
749 pub(crate) prompt_builder: Option<PromptBuilder>,
750 pub(crate) window_invalidators_by_entity:
751 FxHashMap<EntityId, FxHashMap<WindowId, WindowInvalidator>>,
752 pub(crate) tracked_entities: FxHashMap<WindowId, FxHashSet<EntityId>>,
753 pub(crate) current_window_by_entity: FxHashMap<EntityId, WindowId>,
754 #[cfg(any(feature = "inspector", debug_assertions))]
755 pub(crate) inspector_renderer: Option<crate::InspectorRenderer>,
756 #[cfg(any(feature = "inspector", debug_assertions))]
757 pub(crate) inspector_element_registry: InspectorElementRegistry,
758 #[cfg(any(test, feature = "test-support", debug_assertions))]
759 pub(crate) name: Option<&'static str>,
760 pub(crate) text_rendering_mode: Rc<Cell<TextRenderingMode>>,
761
762 pub(crate) window_update_stack: Vec<WindowId>,
763 pub(crate) mode: GpuiMode,
764 pub(crate) cursor_hide_mode: CursorHideMode,
765 pub(crate) reduce_motion: bool,
766 pub(crate) synced_animation_epoch: Instant,
768 pub(crate) accessibility_force_disabled: bool,
771 flushing_effects: bool,
772 pending_updates: usize,
773 quit_mode: QuitMode,
774 quitting: bool,
775
776 #[cfg(any(test, feature = "leak-detection"))]
779 _ref_counts: Arc<RwLock<EntityRefCounts>>,
780}
781
782impl App {
783 #[allow(clippy::new_ret_no_self)]
784 pub(crate) fn new_app(
785 platform: Rc<dyn Platform>,
786 asset_source: Arc<dyn AssetSource>,
787 http_client: Arc<dyn HttpClient>,
788 ) -> Rc<AppCell> {
789 let background_executor = platform.background_executor();
790 let foreground_executor = platform.foreground_executor();
791 assert!(
792 background_executor.is_main_thread(),
793 "must construct App on main thread"
794 );
795 #[cfg(feature = "profiler")]
796 let foreground_journal = crate::profiler::journal::install_foreground_journal();
797 let synced_animation_epoch = background_executor.now();
798
799 let text_system = Arc::new(TextSystem::new(platform.text_system()));
800 let entities = EntityMap::new();
801 let keyboard_layout = platform.keyboard_layout();
802 let keyboard_mapper = platform.keyboard_mapper();
803
804 #[cfg(any(test, feature = "leak-detection"))]
805 let _ref_counts = entities.ref_counts_drop_handle();
806
807 let app = Rc::new_cyclic(|this| AppCell {
808 app: RefCell::new(App {
809 this: this.clone(),
810 platform: platform.clone(),
811 text_system,
812 text_rendering_mode: Rc::new(Cell::new(TextRenderingMode::default())),
813 mode: GpuiMode::Production,
814 actions: Rc::new(ActionRegistry::default()),
815 flushing_effects: false,
816 pending_updates: 0,
817 active_drag: None,
818 platform_owned_drag: None,
819 background_executor,
820 foreground_executor,
821 #[cfg(feature = "profiler")]
822 foreground_journal,
823 svg_renderer: SvgRenderer::new(asset_source.clone()),
824 loading_assets: Default::default(),
825 asset_source,
826 http_client,
827 globals_by_type: Default::default(),
828 entities,
829 new_entity_observers: SubscriberSet::new(),
830 windows: SlotMap::with_key(),
831 window_update_stack: Vec::new(),
832 window_handles: FxHashMap::default(),
833 focus_handles: Arc::new(RwLock::new(SlotMap::with_key())),
834 keymap: Rc::new(RefCell::new(Keymap::default())),
835 keyboard_layout,
836 keyboard_mapper,
837 global_action_listeners: Default::default(),
838 pending_effects: VecDeque::new(),
839 pending_notifications: FxHashSet::default(),
840 pending_global_notifications: Default::default(),
841 observers: SubscriberSet::new(),
842 tracked_entities: FxHashMap::default(),
843 window_invalidators_by_entity: FxHashMap::default(),
844 current_window_by_entity: FxHashMap::default(),
845 event_listeners: SubscriberSet::new(),
846 release_listeners: SubscriberSet::new(),
847 keystroke_observers: SubscriberSet::new(),
848 keystroke_interceptors: SubscriberSet::new(),
849 keyboard_layout_observers: SubscriberSet::new(),
850 thermal_state_observers: SubscriberSet::new(),
851 system_sleep_observers: SubscriberSet::new(),
852 system_wake_observers: SubscriberSet::new(),
853 global_observers: SubscriberSet::new(),
854 quit_observers: SubscriberSet::new(),
855 restart_observers: SubscriberSet::new(),
856 restart_path: None,
857 restart_arguments: Vec::new(),
858 window_closed_observers: SubscriberSet::new(),
859 layout_id_buffer: Default::default(),
860 propagate_event: true,
861 prompt_builder: Some(PromptBuilder::Default),
862 #[cfg(any(feature = "inspector", debug_assertions))]
863 inspector_renderer: None,
864 #[cfg(any(feature = "inspector", debug_assertions))]
865 inspector_element_registry: InspectorElementRegistry::default(),
866 quit_mode: QuitMode::default(),
867 quitting: false,
868 cursor_hide_mode: CursorHideMode::default(),
869 reduce_motion: false,
870 synced_animation_epoch,
871 accessibility_force_disabled: false,
872
873 #[cfg(any(test, feature = "test-support", debug_assertions))]
874 name: None,
875 element_arena: RefCell::new(Arena::new(1024 * 1024)),
876 event_arena: Arena::new(1024 * 1024),
877
878 #[cfg(any(test, feature = "leak-detection"))]
879 _ref_counts,
880 }),
881 });
882
883 init_app_menus(platform.as_ref(), &app.borrow());
884 SystemWindowTabController::init(&mut app.borrow_mut());
885
886 platform.on_keyboard_layout_change(Box::new({
887 let app = Rc::downgrade(&app);
888 move || {
889 if let Some(app) = app.upgrade() {
890 let cx = &mut app.borrow_mut();
891 cx.keyboard_layout = cx.platform.keyboard_layout();
892 cx.keyboard_mapper = cx.platform.keyboard_mapper();
893 cx.keyboard_layout_observers
894 .clone()
895 .retain(&(), move |callback| (callback)(cx));
896 }
897 }
898 }));
899
900 platform.on_thermal_state_change(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.thermal_state_observers
906 .clone()
907 .retain(&(), move |callback| (callback)(cx));
908 }
909 }
910 }));
911
912 platform.on_system_sleep(Box::new({
913 let app = Rc::downgrade(&app);
914 move || {
915 if let Some(app) = app.upgrade() {
916 let cx = &mut app.borrow_mut();
917 cx.system_sleep_observers
918 .clone()
919 .retain(&(), move |callback| (callback)(cx));
920 }
921 }
922 }));
923
924 platform.on_system_wake(Box::new({
925 let app = Rc::downgrade(&app);
926 move || {
927 if let Some(app) = app.upgrade() {
928 let cx = &mut app.borrow_mut();
929 cx.system_wake_observers
930 .clone()
931 .retain(&(), move |callback| (callback)(cx));
932 }
933 }
934 }));
935
936 platform.on_quit(Box::new({
937 let cx = Rc::downgrade(&app);
938 move || {
939 let Some(cx) = cx.upgrade() else {
940 return true;
941 };
942 match cx.try_borrow_mut() {
943 Ok(mut cx) => {
944 cx.shutdown();
945 true
946 }
947 Err(_) => {
948 false
951 }
952 }
953 }
954 }));
955
956 app
957 }
958
959 #[doc(hidden)]
960 pub fn ref_counts_drop_handle(&self) -> impl Sized + use<> {
961 self.entities.ref_counts_drop_handle()
962 }
963
964 #[cfg(any(test, feature = "leak-detection"))]
970 pub fn leak_detector_snapshot(&self) -> LeakDetectorSnapshot {
971 self.entities.leak_detector_snapshot()
972 }
973
974 #[cfg(any(test, feature = "leak-detection"))]
986 pub fn assert_no_new_leaks(&self, snapshot: &LeakDetectorSnapshot) {
987 self.entities.assert_no_new_leaks(snapshot)
988 }
989
990 pub fn shutdown(&mut self) {
996 let mut futures = Vec::new();
997
998 for observer in self.quit_observers.remove(&()) {
999 futures.push(observer(self));
1000 }
1001
1002 self.windows.clear();
1003 self.window_handles.clear();
1004 self.flush_effects();
1005 self.quitting = true;
1006
1007 let futures = futures::future::join_all(futures);
1008 #[cfg(not(target_family = "wasm"))]
1009 if self
1010 .foreground_executor
1011 .block_with_timeout(SHUTDOWN_TIMEOUT, futures)
1012 .is_err()
1013 {
1014 log::error!("timed out waiting on app_will_quit");
1015 }
1016 #[cfg(target_family = "wasm")]
1017 self.foreground_executor.spawn(futures).detach();
1018
1019 self.quitting = false;
1020 }
1021
1022 pub fn keyboard_layout(&self) -> &dyn PlatformKeyboardLayout {
1024 self.keyboard_layout.as_ref()
1025 }
1026
1027 pub fn keyboard_mapper(&self) -> &Rc<dyn PlatformKeyboardMapper> {
1029 &self.keyboard_mapper
1030 }
1031
1032 pub fn on_keyboard_layout_change<F>(&self, mut callback: F) -> Subscription
1034 where
1035 F: 'static + FnMut(&mut App),
1036 {
1037 let (subscription, activate) = self.keyboard_layout_observers.insert(
1038 (),
1039 Box::new(move |cx| {
1040 callback(cx);
1041 true
1042 }),
1043 );
1044 activate();
1045 subscription
1046 }
1047
1048 pub fn quit(&self) {
1050 self.platform.quit();
1051 }
1052
1053 pub fn cursor_hide_mode(&self) -> CursorHideMode {
1056 self.cursor_hide_mode
1057 }
1058
1059 pub fn set_cursor_hide_mode(&mut self, mode: CursorHideMode) {
1062 self.cursor_hide_mode = mode;
1063 }
1064
1065 pub fn is_cursor_visible(&self) -> bool {
1071 self.platform.is_cursor_visible()
1072 }
1073
1074 pub fn reduce_motion(&self) -> bool {
1077 self.reduce_motion
1078 }
1079
1080 pub fn set_reduce_motion(&mut self, reduce_motion: bool) {
1083 if self.reduce_motion != reduce_motion {
1084 self.reduce_motion = reduce_motion;
1085 self.refresh_windows();
1086 }
1087 }
1088
1089 pub fn refresh_windows(&mut self) {
1092 self.pending_effects.push_back(Effect::RefreshWindows);
1093 }
1094
1095 pub(crate) fn update<R>(&mut self, update: impl FnOnce(&mut Self) -> R) -> R {
1096 self.start_update();
1097 let result = update(self);
1098 self.finish_update();
1099 result
1100 }
1101
1102 pub(crate) fn start_update(&mut self) {
1103 self.pending_updates += 1;
1104 }
1105
1106 pub(crate) fn finish_update(&mut self) {
1107 if !self.flushing_effects && self.pending_updates == 1 {
1108 self.flushing_effects = true;
1109 self.flush_effects();
1110 self.flushing_effects = false;
1111 }
1112 self.pending_updates -= 1;
1113 }
1114
1115 pub fn observe<W>(
1117 &mut self,
1118 entity: &Entity<W>,
1119 mut on_notify: impl FnMut(Entity<W>, &mut App) + 'static,
1120 ) -> Subscription
1121 where
1122 W: 'static,
1123 {
1124 self.observe_internal(entity, move |e, cx| {
1125 on_notify(e, cx);
1126 true
1127 })
1128 }
1129
1130 pub(crate) fn detect_accessed_entities<R>(
1131 &mut self,
1132 callback: impl FnOnce(&mut App) -> R,
1133 ) -> (R, FxHashSet<EntityId>) {
1134 let accessed_entities_start = self.entities.accessed_entities.get_mut().clone();
1135 let result = callback(self);
1136 let entities_accessed_in_callback = self
1137 .entities
1138 .accessed_entities
1139 .get_mut()
1140 .difference(&accessed_entities_start)
1141 .copied()
1142 .collect::<FxHashSet<EntityId>>();
1143 (result, entities_accessed_in_callback)
1144 }
1145
1146 pub(crate) fn record_entities_accessed(
1147 &mut self,
1148 window_handle: AnyWindowHandle,
1149 invalidator: WindowInvalidator,
1150 entities: &FxHashSet<EntityId>,
1151 ) {
1152 let mut tracked_entities =
1153 std::mem::take(self.tracked_entities.entry(window_handle.id).or_default());
1154 for entity in tracked_entities.iter() {
1155 self.window_invalidators_by_entity
1156 .entry(*entity)
1157 .and_modify(|windows| {
1158 windows.remove(&window_handle.id);
1159 });
1160 }
1161 for entity in entities.iter() {
1162 self.window_invalidators_by_entity
1163 .entry(*entity)
1164 .or_default()
1165 .insert(window_handle.id, invalidator.clone());
1166 self.current_window_by_entity
1167 .insert(*entity, window_handle.id);
1168 }
1169 tracked_entities.clear();
1170 tracked_entities.extend(entities.iter().copied());
1171 self.tracked_entities
1172 .insert(window_handle.id, tracked_entities);
1173 }
1174
1175 pub(crate) fn new_observer(&mut self, key: EntityId, value: Handler) -> Subscription {
1176 let (subscription, activate) = self.observers.insert(key, value);
1177 self.defer(move |_| activate());
1178 subscription
1179 }
1180
1181 pub(crate) fn observe_internal<W>(
1182 &mut self,
1183 entity: &Entity<W>,
1184 mut on_notify: impl FnMut(Entity<W>, &mut App) -> bool + 'static,
1185 ) -> Subscription
1186 where
1187 W: 'static,
1188 {
1189 let entity_id = entity.entity_id();
1190 let handle = entity.downgrade();
1191 self.new_observer(
1192 entity_id,
1193 Box::new(move |cx| {
1194 if let Some(entity) = handle.upgrade() {
1195 on_notify(entity, cx)
1196 } else {
1197 false
1198 }
1199 }),
1200 )
1201 }
1202
1203 pub fn subscribe<T, Event>(
1206 &mut self,
1207 entity: &Entity<T>,
1208 mut on_event: impl FnMut(Entity<T>, &Event, &mut App) + 'static,
1209 ) -> Subscription
1210 where
1211 T: 'static + EventEmitter<Event>,
1212 Event: 'static,
1213 {
1214 self.subscribe_internal(entity, move |entity, event, cx| {
1215 on_event(entity, event, cx);
1216 true
1217 })
1218 }
1219
1220 pub(crate) fn new_subscription(
1221 &mut self,
1222 key: EntityId,
1223 value: (TypeId, Listener),
1224 ) -> Subscription {
1225 let (subscription, activate) = self.event_listeners.insert(key, value);
1226 self.defer(move |_| activate());
1227 subscription
1228 }
1229 pub(crate) fn subscribe_internal<T, Evt>(
1230 &mut self,
1231 entity: &Entity<T>,
1232 mut on_event: impl FnMut(Entity<T>, &Evt, &mut App) -> bool + 'static,
1233 ) -> Subscription
1234 where
1235 T: 'static + EventEmitter<Evt>,
1236 Evt: 'static,
1237 {
1238 let entity_id = entity.entity_id();
1239 let handle = entity.downgrade();
1240 self.new_subscription(
1241 entity_id,
1242 (
1243 TypeId::of::<Evt>(),
1244 Box::new(move |event, cx| {
1245 let event: &Evt = event.downcast_ref().expect("invalid event type");
1246 if let Some(entity) = handle.upgrade() {
1247 on_event(entity, event, cx)
1248 } else {
1249 false
1250 }
1251 }),
1252 ),
1253 )
1254 }
1255
1256 pub fn windows(&self) -> Vec<AnyWindowHandle> {
1260 self.windows
1261 .keys()
1262 .flat_map(|window_id| self.window_handles.get(&window_id).copied())
1263 .collect()
1264 }
1265
1266 pub fn window_stack(&self) -> Option<Vec<AnyWindowHandle>> {
1272 self.platform.window_stack()
1273 }
1274
1275 pub fn active_window(&self) -> Option<AnyWindowHandle> {
1277 self.platform.active_window()
1278 }
1279
1280 pub fn open_window<V: 'static + Render>(
1284 &mut self,
1285 options: crate::WindowOptions,
1286 build_root_view: impl FnOnce(&mut Window, &mut App) -> Entity<V>,
1287 ) -> anyhow::Result<WindowHandle<V>> {
1288 self.update(|cx| {
1289 let id = cx.windows.insert(None);
1290 let handle = WindowHandle::new(id);
1291 match Window::new(handle.into(), options, cx) {
1292 Ok(mut window) => {
1293 cx.window_update_stack.push(id);
1294 let root_view = build_root_view(&mut window, cx);
1295 cx.window_update_stack.pop();
1296 window.root.replace(root_view.into());
1297 window.defer(cx, |window: &mut Window, cx| window.appearance_changed(cx));
1298
1299 let clear = window.draw(cx);
1304 clear.clear(cx);
1305
1306 cx.window_handles.insert(id, window.handle);
1307 cx.windows.get_mut(id).unwrap().replace(Box::new(window));
1308 Ok(handle)
1309 }
1310 Err(e) => {
1311 cx.windows.remove(id);
1312 Err(e)
1313 }
1314 }
1315 })
1316 }
1317
1318 pub fn activate(&self, ignoring_other_apps: bool) {
1320 self.platform.activate(ignoring_other_apps);
1321 }
1322
1323 pub fn hide(&self) {
1325 self.platform.hide();
1326 }
1327
1328 pub fn hide_other_apps(&self) {
1330 self.platform.hide_other_apps();
1331 }
1332
1333 pub fn unhide_other_apps(&self) {
1335 self.platform.unhide_other_apps();
1336 }
1337
1338 pub fn displays(&self) -> Vec<Rc<dyn PlatformDisplay>> {
1340 self.platform.displays()
1341 }
1342
1343 pub fn primary_display(&self) -> Option<Rc<dyn PlatformDisplay>> {
1345 self.platform.primary_display()
1346 }
1347
1348 pub fn is_screen_capture_supported(&self) -> bool {
1350 self.platform.is_screen_capture_supported()
1351 }
1352
1353 pub fn screen_capture_sources(
1355 &self,
1356 ) -> oneshot::Receiver<Result<Vec<Rc<dyn ScreenCaptureSource>>>> {
1357 self.platform.screen_capture_sources()
1358 }
1359
1360 pub fn find_display(&self, id: DisplayId) -> Option<Rc<dyn PlatformDisplay>> {
1362 self.displays()
1363 .iter()
1364 .find(|display| display.id() == id)
1365 .cloned()
1366 }
1367
1368 pub fn thermal_state(&self) -> ThermalState {
1370 self.platform.thermal_state()
1371 }
1372
1373 pub fn prevent_idle_sleep(&self, reason: &str) -> Task<Result<ActivityGuard>> {
1375 self.platform.prevent_idle_sleep(reason)
1376 }
1377
1378 pub fn on_thermal_state_change<F>(&self, mut callback: F) -> Subscription
1380 where
1381 F: 'static + FnMut(&mut App),
1382 {
1383 let (subscription, activate) = self.thermal_state_observers.insert(
1384 (),
1385 Box::new(move |cx| {
1386 callback(cx);
1387 true
1388 }),
1389 );
1390 activate();
1391 subscription
1392 }
1393
1394 pub fn on_system_sleep<F>(&self, mut callback: F) -> Subscription
1399 where
1400 F: 'static + FnMut(&mut App),
1401 {
1402 let (subscription, activate) = self.system_sleep_observers.insert(
1403 (),
1404 Box::new(move |cx| {
1405 callback(cx);
1406 true
1407 }),
1408 );
1409 activate();
1410 subscription
1411 }
1412
1413 pub fn on_system_wake<F>(&self, mut callback: F) -> Subscription
1415 where
1416 F: 'static + FnMut(&mut App),
1417 {
1418 let (subscription, activate) = self.system_wake_observers.insert(
1419 (),
1420 Box::new(move |cx| {
1421 callback(cx);
1422 true
1423 }),
1424 );
1425 activate();
1426 subscription
1427 }
1428
1429 pub fn window_appearance(&self) -> WindowAppearance {
1431 self.platform.window_appearance()
1432 }
1433
1434 pub fn set_window_appearance(&self, appearance: Option<WindowAppearance>) {
1445 self.platform.set_window_appearance(appearance);
1446 }
1447
1448 pub fn button_layout(&self) -> Option<WindowButtonLayout> {
1450 self.platform.button_layout()
1451 }
1452
1453 pub fn read_from_clipboard(&self) -> Option<ClipboardItem> {
1455 self.platform.read_from_clipboard()
1456 }
1457
1458 pub fn read_from_clipboard_async(
1466 &self,
1467 ) -> Task<Result<Option<ClipboardItem>, ClipboardReadError>> {
1468 self.platform.read_from_clipboard_async()
1469 }
1470
1471 pub fn set_text_rendering_mode(&mut self, mode: TextRenderingMode) {
1473 self.text_rendering_mode.set(mode);
1474 }
1475
1476 pub fn text_rendering_mode(&self) -> TextRenderingMode {
1478 self.text_rendering_mode.get()
1479 }
1480
1481 pub fn write_to_clipboard(&self, item: ClipboardItem) {
1483 self.platform.write_to_clipboard(item)
1484 }
1485
1486 #[cfg(any(target_os = "linux", target_os = "freebsd"))]
1489 pub fn read_from_primary(&self) -> Option<ClipboardItem> {
1490 self.platform.read_from_primary()
1491 }
1492
1493 #[cfg(any(target_os = "linux", target_os = "freebsd"))]
1496 pub fn write_to_primary(&self, item: ClipboardItem) {
1497 self.platform.write_to_primary(item)
1498 }
1499
1500 #[cfg(target_os = "macos")]
1506 pub fn read_from_find_pasteboard(&self) -> Option<ClipboardItem> {
1507 self.platform.read_from_find_pasteboard()
1508 }
1509
1510 #[cfg(target_os = "macos")]
1516 pub fn write_to_find_pasteboard(&self, item: ClipboardItem) {
1517 self.platform.write_to_find_pasteboard(item)
1518 }
1519
1520 pub fn write_credentials(
1522 &self,
1523 url: &str,
1524 username: &str,
1525 password: &[u8],
1526 ) -> Task<Result<()>> {
1527 self.platform.write_credentials(url, username, password)
1528 }
1529
1530 pub fn read_credentials(&self, url: &str) -> Task<Result<Option<(String, Vec<u8>)>>> {
1532 self.platform.read_credentials(url)
1533 }
1534
1535 pub fn delete_credentials(&self, url: &str) -> Task<Result<()>> {
1537 self.platform.delete_credentials(url)
1538 }
1539
1540 pub fn open_url(&self, url: &str) {
1542 self.platform.open_url(url);
1543 }
1544
1545 pub fn register_url_scheme(&self, scheme: &str) -> Task<Result<()>> {
1552 self.platform.register_url_scheme(scheme)
1553 }
1554
1555 pub fn set_app_identity(&self, identifier: &str, name: &str) {
1562 self.platform.set_app_identity(identifier, name);
1563 }
1564
1565 pub fn show_system_notification(&self, notification: SystemNotification) {
1572 self.platform.show_system_notification(notification);
1573 }
1574
1575 pub fn dismiss_system_notification(&self, tag: &str) {
1580 self.platform.dismiss_system_notification(tag);
1581 }
1582
1583 pub fn on_system_notification_response<F>(&self, mut callback: F)
1587 where
1588 F: 'static + FnMut(SystemNotificationResponse, &mut App),
1589 {
1590 let this = self.this.clone();
1591 self.platform
1592 .on_system_notification_response(Box::new(move |response| {
1593 if let Some(app) = this.upgrade() {
1594 callback(response, &mut app.borrow_mut());
1595 }
1596 }));
1597 }
1598
1599 pub fn app_path(&self) -> Result<PathBuf> {
1603 self.platform.app_path()
1604 }
1605
1606 pub fn compositor_name(&self) -> &'static str {
1610 self.platform.compositor_name()
1611 }
1612
1613 pub fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf> {
1615 self.platform.path_for_auxiliary_executable(name)
1616 }
1617
1618 pub fn prompt_for_paths(
1624 &self,
1625 options: PathPromptOptions,
1626 ) -> oneshot::Receiver<Result<Option<Vec<PathBuf>>>> {
1627 self.platform.prompt_for_paths(options)
1628 }
1629
1630 pub fn prompt_for_new_path(
1637 &self,
1638 directory: &Path,
1639 suggested_name: Option<&str>,
1640 ) -> oneshot::Receiver<Result<Option<PathBuf>>> {
1641 self.platform.prompt_for_new_path(directory, suggested_name)
1642 }
1643
1644 pub fn reveal_path(&self, path: &Path) {
1646 self.platform.reveal_path(path)
1647 }
1648
1649 pub fn open_with_system(&self, path: &Path) {
1651 self.platform.open_with_system(path)
1652 }
1653
1654 pub fn should_auto_hide_scrollbars(&self) -> bool {
1656 self.platform.should_auto_hide_scrollbars()
1657 }
1658
1659 pub fn restart(&mut self) {
1661 self.restart_observers
1662 .clone()
1663 .retain(&(), |observer| observer(self));
1664 self.platform.restart(
1665 self.restart_path.take(),
1666 std::mem::take(&mut self.restart_arguments),
1667 )
1668 }
1669
1670 pub fn set_restart_path(&mut self, path: PathBuf) {
1672 self.restart_path = Some(path);
1673 }
1674
1675 pub fn http_client(&self) -> Arc<dyn HttpClient> {
1677 self.http_client.clone()
1678 }
1679
1680 pub fn set_http_client(&mut self, new_client: Arc<dyn HttpClient>) {
1682 self.http_client = new_client;
1683 }
1684
1685 pub fn set_quit_mode(&mut self, mode: QuitMode) {
1688 self.quit_mode = mode;
1689 }
1690
1691 pub fn svg_renderer(&self) -> SvgRenderer {
1693 self.svg_renderer.clone()
1694 }
1695
1696 pub(crate) fn push_effect(&mut self, effect: Effect) {
1697 match &effect {
1698 Effect::Notify { emitter } => {
1699 if !self.pending_notifications.insert(*emitter) {
1700 return;
1701 }
1702 }
1703 Effect::NotifyGlobalObservers { global_type } => {
1704 if !self.pending_global_notifications.insert(*global_type) {
1705 return;
1706 }
1707 }
1708 _ => {}
1709 };
1710
1711 self.pending_effects.push_back(effect);
1712 }
1713
1714 fn flush_effects(&mut self) {
1718 loop {
1719 self.release_dropped_entities();
1720 self.release_dropped_focus_handles();
1721 if let Some(effect) = self.pending_effects.pop_front() {
1722 match effect {
1723 Effect::Notify { emitter } => {
1724 self.apply_notify_effect(emitter);
1725 }
1726
1727 Effect::Emit {
1728 emitter,
1729 event_type,
1730 event,
1731 } => self.apply_emit_effect(emitter, event_type, &*event),
1732
1733 Effect::RefreshWindows => {
1734 self.apply_refresh_effect();
1735 }
1736
1737 Effect::NotifyGlobalObservers { global_type } => {
1738 self.apply_notify_global_observers_effect(global_type);
1739 }
1740
1741 Effect::Defer { callback } => {
1742 self.apply_defer_effect(callback);
1743 }
1744 Effect::EntityCreated {
1745 entity,
1746 tid,
1747 window,
1748 } => {
1749 self.apply_entity_created_effect(entity, tid, window);
1750 }
1751 }
1752 } else {
1753 #[cfg(any(test, feature = "test-support"))]
1754 if matches!(self.mode, GpuiMode::Test { .. }) {
1755 for window in self
1756 .windows
1757 .values()
1758 .filter_map(|window| {
1759 let window = window.as_deref()?;
1760 window.invalidator.is_dirty().then_some(window.handle)
1761 })
1762 .collect::<Vec<_>>()
1763 {
1764 self.update_window(window, |_, window, cx| window.draw(cx).clear(cx))
1765 .unwrap();
1766 }
1767 }
1768
1769 if self.pending_effects.is_empty() {
1770 for window in self.windows.values().filter_map(|window| window.as_deref()) {
1771 if window.invalidator.is_dirty()
1772 || window.needs_present.get()
1773 || !window.next_frame_callbacks.borrow().is_empty()
1774 {
1775 window.platform_window.schedule_frame();
1776 }
1777 }
1778
1779 self.event_arena.clear();
1780 break;
1781 }
1782 }
1783 }
1784 }
1785
1786 fn release_dropped_entities(&mut self) {
1790 loop {
1791 let dropped = self.entities.take_dropped();
1792 if dropped.is_empty() {
1793 break;
1794 }
1795
1796 for (entity_id, mut entity) in dropped {
1797 self.observers.remove(&entity_id);
1798 self.event_listeners.remove(&entity_id);
1799 self.window_invalidators_by_entity.remove(&entity_id);
1800 self.current_window_by_entity.remove(&entity_id);
1801 for release_callback in self.release_listeners.remove(&entity_id) {
1802 release_callback(entity.as_mut(), self);
1803 }
1804 }
1805 }
1806 }
1807
1808 fn release_dropped_focus_handles(&mut self) {
1810 self.focus_handles
1811 .clone()
1812 .write()
1813 .retain(|handle_id, focus| {
1814 if focus.ref_count.load(SeqCst) == 0 {
1815 for window_handle in self.windows() {
1816 window_handle
1817 .update(self, |_, window, cx| {
1818 if window.focus == Some(handle_id) {
1819 window.blur(cx);
1820 }
1821 })
1822 .unwrap();
1823 }
1824 false
1825 } else {
1826 true
1827 }
1828 });
1829 }
1830
1831 fn apply_notify_effect(&mut self, emitter: EntityId) {
1832 self.pending_notifications.remove(&emitter);
1833
1834 self.observers
1835 .clone()
1836 .retain(&emitter, |handler| handler(self));
1837 }
1838
1839 fn apply_emit_effect(&mut self, emitter: EntityId, event_type: TypeId, event: &dyn Any) {
1840 self.event_listeners
1841 .clone()
1842 .retain(&emitter, |(stored_type, handler)| {
1843 if *stored_type == event_type {
1844 handler(event, self)
1845 } else {
1846 true
1847 }
1848 });
1849 }
1850
1851 fn apply_refresh_effect(&mut self) {
1852 for window in self.windows.values_mut() {
1853 if let Some(window) = window.as_deref_mut() {
1854 window.refreshing = true;
1855 window.invalidator.set_dirty(true);
1856 }
1857 }
1858 }
1859
1860 fn apply_notify_global_observers_effect(&mut self, type_id: TypeId) {
1861 self.pending_global_notifications.remove(&type_id);
1862 self.global_observers
1863 .clone()
1864 .retain(&type_id, |observer| observer(self));
1865 }
1866
1867 fn apply_defer_effect(&mut self, callback: Box<dyn FnOnce(&mut Self) + 'static>) {
1868 callback(self);
1869 }
1870
1871 fn apply_entity_created_effect(
1872 &mut self,
1873 entity: AnyEntity,
1874 tid: TypeId,
1875 window: Option<WindowId>,
1876 ) {
1877 if let Some(id) = window {
1881 self.current_window_by_entity.insert(entity.entity_id(), id);
1882 }
1883
1884 self.new_entity_observers.clone().retain(&tid, |observer| {
1885 if let Some(id) = window {
1886 self.update_window_id(id, {
1887 let entity = entity.clone();
1888 |_, window, cx| (observer)(entity, &mut Some(window), cx)
1889 })
1890 .expect("All windows should be off the stack when flushing effects");
1891 } else {
1892 (observer)(entity.clone(), &mut None, self)
1893 }
1894 true
1895 });
1896 }
1897
1898 pub fn with_window<R>(
1904 &mut self,
1905 entity_id: EntityId,
1906 f: impl FnOnce(&mut Window, &mut App) -> R,
1907 ) -> Option<R> {
1908 let window_id = *self.current_window_by_entity.get(&entity_id)?;
1909 self.update_window_id(window_id, |_, window, cx| f(window, cx))
1910 .ok()
1911 }
1912
1913 fn ensure_window(&mut self, entity_id: EntityId, window: WindowId) {
1914 self.current_window_by_entity
1915 .entry(entity_id)
1916 .or_insert(window);
1917 }
1918
1919 pub(crate) fn update_window_id<T, F>(&mut self, id: WindowId, update: F) -> Result<T>
1920 where
1921 F: FnOnce(AnyView, &mut Window, &mut App) -> T,
1922 {
1923 self.update(|cx| {
1924 let mut window = cx.windows.get_mut(id)?.take()?;
1925
1926 let root_view = window.root.clone().unwrap();
1927
1928 cx.window_update_stack.push(window.handle.id);
1929 let result = update(root_view, &mut window, cx);
1930 fn trail(id: WindowId, window: Box<Window>, cx: &mut App) -> Option<()> {
1931 cx.window_update_stack.pop();
1932
1933 if window.removed {
1934 cx.end_platform_drag(id);
1935 cx.window_handles.remove(&id);
1936 cx.windows.remove(id);
1937 if let Some(tracked) = cx.tracked_entities.remove(&id) {
1938 for entity_id in tracked {
1939 if let Some(windows) =
1940 cx.window_invalidators_by_entity.get_mut(&entity_id)
1941 {
1942 windows.remove(&id);
1943 }
1944 if cx.current_window_by_entity.get(&entity_id) == Some(&id) {
1945 cx.current_window_by_entity.remove(&entity_id);
1946 }
1947 }
1948 }
1949
1950 cx.window_closed_observers.clone().retain(&(), |callback| {
1951 callback(cx, id);
1952 true
1953 });
1954
1955 let quit_on_empty = match cx.quit_mode {
1956 QuitMode::Explicit => false,
1957 QuitMode::LastWindowClosed => true,
1958 QuitMode::Default => cfg!(not(target_os = "macos")),
1959 };
1960
1961 if quit_on_empty && cx.windows.is_empty() {
1962 cx.quit();
1963 }
1964 } else {
1965 cx.windows.get_mut(id)?.replace(window);
1966 }
1967 Some(())
1968 }
1969 trail(id, window, cx)?;
1970
1971 Some(result)
1972 })
1973 .context("window not found")
1974 }
1975
1976 pub fn to_async(&self) -> AsyncApp {
1979 AsyncApp {
1980 app: self.this.clone(),
1981 background_executor: self.background_executor.clone(),
1982 foreground_executor: self.foreground_executor.clone(),
1983 }
1984 }
1985
1986 pub fn background_executor(&self) -> &BackgroundExecutor {
1988 &self.background_executor
1989 }
1990
1991 pub fn foreground_executor(&self) -> &ForegroundExecutor {
1993 if self.quitting {
1994 panic!("Can't spawn on main thread after on_app_quit")
1995 };
1996 &self.foreground_executor
1997 }
1998
1999 #[cfg(feature = "profiler")]
2002 pub fn foreground_journal(&self) -> crate::profiler::journal::ForegroundJournal {
2003 self.foreground_journal.clone()
2004 }
2005
2006 #[track_caller]
2009 pub fn spawn<AsyncFn, R>(&self, f: AsyncFn) -> Task<R>
2010 where
2011 AsyncFn: AsyncFnOnce(&mut AsyncApp) -> R + 'static,
2012 R: 'static,
2013 {
2014 if self.quitting {
2015 debug_panic!("Can't spawn on main thread after on_app_quit")
2016 };
2017
2018 let mut cx = self.to_async();
2019
2020 self.foreground_executor
2021 .spawn(async move { f(&mut cx).await }.boxed_local())
2022 }
2023
2024 pub fn spawn_with_priority<AsyncFn, R>(&self, priority: Priority, f: AsyncFn) -> Task<R>
2028 where
2029 AsyncFn: AsyncFnOnce(&mut AsyncApp) -> R + 'static,
2030 R: 'static,
2031 {
2032 if self.quitting {
2033 debug_panic!("Can't spawn on main thread after on_app_quit")
2034 };
2035
2036 let mut cx = self.to_async();
2037
2038 self.foreground_executor
2039 .spawn_with_priority(priority, async move { f(&mut cx).await }.boxed_local())
2040 }
2041
2042 pub fn defer(&mut self, f: impl FnOnce(&mut App) + 'static) {
2045 self.push_effect(Effect::Defer {
2046 callback: Box::new(f),
2047 });
2048 }
2049
2050 pub fn asset_source(&self) -> &Arc<dyn AssetSource> {
2052 &self.asset_source
2053 }
2054
2055 pub fn text_system(&self) -> &Arc<TextSystem> {
2057 &self.text_system
2058 }
2059
2060 pub fn has_global<G: Global>(&self) -> bool {
2062 self.globals_by_type.contains_key(&TypeId::of::<G>())
2063 }
2064
2065 #[track_caller]
2067 pub fn global<G: Global>(&self) -> &G {
2068 self.globals_by_type
2069 .get(&TypeId::of::<G>())
2070 .map(|any_state| any_state.downcast_ref::<G>().unwrap())
2071 .unwrap_or_else(|| panic!("no state of type {} exists", type_name::<G>()))
2072 }
2073
2074 pub fn try_global<G: Global>(&self) -> Option<&G> {
2076 self.globals_by_type
2077 .get(&TypeId::of::<G>())
2078 .map(|any_state| any_state.downcast_ref::<G>().unwrap())
2079 }
2080
2081 #[track_caller]
2083 pub fn global_mut<G: Global>(&mut self) -> &mut G {
2084 let global_type = TypeId::of::<G>();
2085 self.push_effect(Effect::NotifyGlobalObservers { global_type });
2086 self.globals_by_type
2087 .get_mut(&global_type)
2088 .and_then(|any_state| any_state.downcast_mut::<G>())
2089 .unwrap_or_else(|| panic!("no state of type {} exists", type_name::<G>()))
2090 }
2091
2092 pub fn default_global<G: Global + Default>(&mut self) -> &mut G {
2095 let global_type = TypeId::of::<G>();
2096 self.push_effect(Effect::NotifyGlobalObservers { global_type });
2097 self.globals_by_type
2098 .entry(global_type)
2099 .or_insert_with(|| Box::<G>::default())
2100 .downcast_mut::<G>()
2101 .unwrap()
2102 }
2103
2104 pub fn set_global<G: Global>(&mut self, global: G) {
2106 let global_type = TypeId::of::<G>();
2107 self.push_effect(Effect::NotifyGlobalObservers { global_type });
2108 self.globals_by_type.insert(global_type, Box::new(global));
2109 }
2110
2111 #[cfg(any(test, feature = "test-support"))]
2113 pub fn clear_globals(&mut self) {
2114 self.globals_by_type.drain();
2115 }
2116
2117 pub fn remove_global<G: Global>(&mut self) -> G {
2119 let global_type = TypeId::of::<G>();
2120 self.push_effect(Effect::NotifyGlobalObservers { global_type });
2121 *self
2122 .globals_by_type
2123 .remove(&global_type)
2124 .unwrap_or_else(|| panic!("no global added for {}", type_name::<G>()))
2125 .downcast()
2126 .unwrap()
2127 }
2128
2129 pub fn observe_global<G: Global>(
2131 &mut self,
2132 mut f: impl FnMut(&mut Self) + 'static,
2133 ) -> Subscription {
2134 let (subscription, activate) = self.global_observers.insert(
2135 TypeId::of::<G>(),
2136 Box::new(move |cx| {
2137 f(cx);
2138 true
2139 }),
2140 );
2141 self.defer(move |_| activate());
2142 subscription
2143 }
2144
2145 #[track_caller]
2147 pub(crate) fn lease_global<G: Global>(&mut self) -> GlobalLease<G> {
2148 GlobalLease::new(
2149 self.globals_by_type
2150 .remove(&TypeId::of::<G>())
2151 .with_context(|| format!("no global registered of type {}", type_name::<G>()))
2152 .unwrap(),
2153 )
2154 }
2155
2156 pub(crate) fn end_global_lease<G: Global>(&mut self, lease: GlobalLease<G>) {
2158 let global_type = TypeId::of::<G>();
2159
2160 self.push_effect(Effect::NotifyGlobalObservers { global_type });
2161 self.globals_by_type.insert(global_type, lease.global);
2162 }
2163
2164 pub(crate) fn new_entity_observer(
2165 &self,
2166 key: TypeId,
2167 value: NewEntityListener,
2168 ) -> Subscription {
2169 let (subscription, activate) = self.new_entity_observers.insert(key, value);
2170 activate();
2171 subscription
2172 }
2173
2174 pub fn observe_new<T: 'static>(
2177 &self,
2178 on_new: impl 'static + Fn(&mut T, Option<&mut Window>, &mut Context<T>),
2179 ) -> Subscription {
2180 self.new_entity_observer(
2181 TypeId::of::<T>(),
2182 Box::new(
2183 move |any_entity: AnyEntity, window: &mut Option<&mut Window>, cx: &mut App| {
2184 any_entity
2185 .downcast::<T>()
2186 .unwrap()
2187 .update(cx, |entity_state, cx| {
2188 on_new(entity_state, window.as_deref_mut(), cx)
2189 })
2190 },
2191 ),
2192 )
2193 }
2194
2195 pub fn observe_release<T>(
2198 &self,
2199 handle: &Entity<T>,
2200 on_release: impl FnOnce(&mut T, &mut App) + 'static,
2201 ) -> Subscription
2202 where
2203 T: 'static,
2204 {
2205 let (subscription, activate) = self.release_listeners.insert(
2206 handle.entity_id(),
2207 Box::new(move |entity, cx| {
2208 let entity = entity.downcast_mut().expect("invalid entity type");
2209 on_release(entity, cx)
2210 }),
2211 );
2212 activate();
2213 subscription
2214 }
2215
2216 pub fn observe_release_in<T>(
2219 &self,
2220 handle: &Entity<T>,
2221 window: &Window,
2222 on_release: impl FnOnce(&mut T, &mut Window, &mut App) + 'static,
2223 ) -> Subscription
2224 where
2225 T: 'static,
2226 {
2227 let window_handle = window.handle;
2228 self.observe_release(handle, move |entity, cx| {
2229 let _ = window_handle.update(cx, |_, window, cx| on_release(entity, window, cx));
2230 })
2231 }
2232
2233 pub fn observe_keystrokes(
2237 &mut self,
2238 mut f: impl FnMut(&KeystrokeEvent, &mut Window, &mut App) + 'static,
2239 ) -> Subscription {
2240 fn inner(
2241 keystroke_observers: &SubscriberSet<(), KeystrokeObserver>,
2242 handler: KeystrokeObserver,
2243 ) -> Subscription {
2244 let (subscription, activate) = keystroke_observers.insert((), handler);
2245 activate();
2246 subscription
2247 }
2248
2249 inner(
2250 &self.keystroke_observers,
2251 Box::new(move |event, window, cx| {
2252 f(event, window, cx);
2253 true
2254 }),
2255 )
2256 }
2257
2258 pub fn intercept_keystrokes(
2263 &mut self,
2264 mut f: impl FnMut(&KeystrokeEvent, &mut Window, &mut App) + 'static,
2265 ) -> Subscription {
2266 fn inner(
2267 keystroke_interceptors: &SubscriberSet<(), KeystrokeObserver>,
2268 handler: KeystrokeObserver,
2269 ) -> Subscription {
2270 let (subscription, activate) = keystroke_interceptors.insert((), handler);
2271 activate();
2272 subscription
2273 }
2274
2275 inner(
2276 &self.keystroke_interceptors,
2277 Box::new(move |event, window, cx| {
2278 f(event, window, cx);
2279 true
2280 }),
2281 )
2282 }
2283
2284 pub fn bind_keys(&mut self, bindings: impl IntoIterator<Item = KeyBinding>) {
2286 self.keymap.borrow_mut().add_bindings(bindings);
2287 self.pending_effects.push_back(Effect::RefreshWindows);
2288 }
2289
2290 pub fn clear_key_bindings(&mut self) {
2292 self.keymap.borrow_mut().clear();
2293 self.pending_effects.push_back(Effect::RefreshWindows);
2294 }
2295
2296 pub fn key_bindings(&self) -> Rc<RefCell<Keymap>> {
2298 self.keymap.clone()
2299 }
2300
2301 pub fn on_action<A: Action>(
2305 &mut self,
2306 listener: impl Fn(&A, &mut Self) + 'static,
2307 ) -> &mut Self {
2308 self.global_action_listeners
2309 .entry(TypeId::of::<A>())
2310 .or_default()
2311 .push(Rc::new(move |action, phase, cx| {
2312 if phase == DispatchPhase::Bubble {
2313 let action = action.downcast_ref().unwrap();
2314 listener(action, cx)
2315 }
2316 }));
2317 self
2318 }
2319
2320 pub fn stop_propagation(&mut self) {
2325 self.propagate_event = false;
2326 }
2327
2328 pub fn propagate(&mut self) {
2333 self.propagate_event = true;
2334 }
2335
2336 pub fn build_action(
2338 &self,
2339 name: &str,
2340 data: Option<serde_json::Value>,
2341 ) -> std::result::Result<Box<dyn Action>, ActionBuildError> {
2342 self.actions.build_action(name, data)
2343 }
2344
2345 pub fn all_action_names(&self) -> &[&'static str] {
2348 self.actions.all_action_names()
2349 }
2350
2351 pub fn all_bindings_for_input(&self, input: &[Keystroke]) -> Vec<KeyBinding> {
2355 RefCell::borrow(&self.keymap).all_bindings_for_input(input)
2356 }
2357
2358 pub fn action_schemas(
2360 &self,
2361 generator: &mut schemars::SchemaGenerator,
2362 ) -> Vec<(&'static str, Option<schemars::Schema>)> {
2363 self.actions.action_schemas(generator)
2364 }
2365
2366 pub fn action_schema_by_name(
2371 &self,
2372 name: &str,
2373 generator: &mut schemars::SchemaGenerator,
2374 ) -> Option<Option<schemars::Schema>> {
2375 self.actions.action_schema_by_name(name, generator)
2376 }
2377
2378 pub fn deprecated_actions_to_preferred_actions(&self) -> &HashMap<&'static str, &'static str> {
2380 self.actions.deprecated_aliases()
2381 }
2382
2383 pub fn action_deprecation_messages(&self) -> &HashMap<&'static str, &'static str> {
2385 self.actions.deprecation_messages()
2386 }
2387
2388 pub fn action_documentation(&self) -> &HashMap<&'static str, &'static str> {
2390 self.actions.documentation()
2391 }
2392
2393 pub fn on_app_quit<Fut>(
2396 &self,
2397 mut on_quit: impl FnMut(&mut App) -> Fut + 'static,
2398 ) -> Subscription
2399 where
2400 Fut: 'static + Future<Output = ()>,
2401 {
2402 let (subscription, activate) = self.quit_observers.insert(
2403 (),
2404 Box::new(move |cx| {
2405 let future = on_quit(cx);
2406 future.boxed_local()
2407 }),
2408 );
2409 activate();
2410 subscription
2411 }
2412
2413 pub fn on_app_restart(&self, mut on_restart: impl 'static + FnMut(&mut App)) -> Subscription {
2417 let (subscription, activate) = self.restart_observers.insert(
2418 (),
2419 Box::new(move |cx| {
2420 on_restart(cx);
2421 true
2422 }),
2423 );
2424 activate();
2425 subscription
2426 }
2427
2428 pub fn on_window_closed(
2431 &self,
2432 mut on_closed: impl FnMut(&mut App, WindowId) + 'static,
2433 ) -> Subscription {
2434 let (subscription, activate) = self.window_closed_observers.insert((), Box::new(on_closed));
2435 activate();
2436 subscription
2437 }
2438
2439 pub(crate) fn clear_pending_keystrokes(&mut self) {
2440 for window in self.windows() {
2441 window
2442 .update(self, |_, window, cx| {
2443 window.clear_pending_keystrokes(cx);
2444 })
2445 .ok();
2446 }
2447 }
2448
2449 pub fn is_action_available(&mut self, action: &dyn Action) -> bool {
2452 let mut action_available = false;
2453 if let Some(window) = self.active_window()
2454 && let Ok(window_action_available) =
2455 window.update(self, |_, window, cx| window.is_action_available(action, cx))
2456 {
2457 action_available = window_action_available;
2458 }
2459
2460 action_available
2461 || self
2462 .global_action_listeners
2463 .contains_key(&action.as_any().type_id())
2464 }
2465
2466 pub fn set_menus(&self, menus: impl IntoIterator<Item = Menu>) {
2468 let menus: Vec<Menu> = menus.into_iter().collect();
2469 self.platform.set_menus(menus, &self.keymap.borrow());
2470 }
2471
2472 pub fn get_menus(&self) -> Option<Vec<OwnedMenu>> {
2474 self.platform.get_menus()
2475 }
2476
2477 pub fn set_dock_menu(&self, menus: Vec<MenuItem>) {
2479 self.platform.set_dock_menu(menus, &self.keymap.borrow())
2480 }
2481
2482 pub fn perform_dock_menu_action(&self, action: usize) {
2484 self.platform.perform_dock_menu_action(action);
2485 }
2486
2487 pub fn add_recent_document(&self, path: &Path) {
2492 self.platform.add_recent_document(path);
2493 }
2494
2495 pub fn update_jump_list(
2498 &self,
2499 menus: Vec<MenuItem>,
2500 entries: Vec<SmallVec<[PathBuf; 2]>>,
2501 ) -> Task<Vec<SmallVec<[PathBuf; 2]>>> {
2502 self.platform.update_jump_list(menus, entries)
2503 }
2504
2505 pub fn dispatch_action(&mut self, action: &dyn Action) {
2508 if let Some(active_window) = self.active_window() {
2509 active_window
2510 .update(self, |_, window, cx| {
2511 window.dispatch_action(action.boxed_clone(), cx)
2512 })
2513 .log_err();
2514 } else {
2515 self.dispatch_global_action(action);
2516 }
2517 }
2518
2519 fn dispatch_global_action(&mut self, action: &dyn Action) {
2520 self.propagate_event = true;
2521
2522 if let Some(mut global_listeners) = self
2523 .global_action_listeners
2524 .remove(&action.as_any().type_id())
2525 {
2526 for listener in &global_listeners {
2527 listener(action.as_any(), DispatchPhase::Capture, self);
2528 if !self.propagate_event {
2529 break;
2530 }
2531 }
2532
2533 global_listeners.extend(
2534 self.global_action_listeners
2535 .remove(&action.as_any().type_id())
2536 .unwrap_or_default(),
2537 );
2538
2539 self.global_action_listeners
2540 .insert(action.as_any().type_id(), global_listeners);
2541 }
2542
2543 if self.propagate_event
2544 && let Some(mut global_listeners) = self
2545 .global_action_listeners
2546 .remove(&action.as_any().type_id())
2547 {
2548 for listener in global_listeners.iter().rev() {
2549 listener(action.as_any(), DispatchPhase::Bubble, self);
2550 if !self.propagate_event {
2551 break;
2552 }
2553 }
2554
2555 global_listeners.extend(
2556 self.global_action_listeners
2557 .remove(&action.as_any().type_id())
2558 .unwrap_or_default(),
2559 );
2560
2561 self.global_action_listeners
2562 .insert(action.as_any().type_id(), global_listeners);
2563 }
2564 }
2565
2566 pub fn has_active_drag(&self) -> bool {
2568 self.active_drag.is_some()
2569 }
2570
2571 pub fn active_drag_cursor_style(&self) -> Option<CursorStyle> {
2573 self.active_drag.as_ref().and_then(|drag| drag.cursor_style)
2574 }
2575
2576 pub fn stop_active_drag(&mut self, window: &mut Window) -> bool {
2578 if self.active_drag.is_some() {
2579 self.active_drag = None;
2580 if self.platform_owned_drag.as_ref().is_some_and(|drag| {
2581 drag.source_window == window.window_handle().window_id()
2582 && matches!(&drag.state, PlatformOwnedDragState::RestoredInSourceWindow)
2583 }) {
2584 self.platform_owned_drag = None;
2585 }
2586 window.refresh();
2587 true
2588 } else {
2589 false
2590 }
2591 }
2592
2593 pub(crate) fn hand_active_drag_to_platform(&mut self, source_window: WindowId) -> bool {
2594 let Some(drag) = self.active_drag.take() else {
2595 return false;
2596 };
2597 self.platform_owned_drag = Some(PlatformOwnedDrag {
2598 source_window,
2599 state: PlatformOwnedDragState::Suspended(drag),
2600 });
2601 true
2602 }
2603
2604 pub(crate) fn restore_platform_drag(&mut self, source_window: WindowId) -> bool {
2605 let Some(platform_drag) = self
2606 .platform_owned_drag
2607 .as_mut()
2608 .filter(|drag| drag.source_window == source_window)
2609 else {
2610 return false;
2611 };
2612 let state = std::mem::replace(
2613 &mut platform_drag.state,
2614 PlatformOwnedDragState::RestoredInSourceWindow,
2615 );
2616 let PlatformOwnedDragState::Suspended(drag) = state else {
2617 return false;
2618 };
2619 self.active_drag = Some(drag);
2620 true
2621 }
2622
2623 pub(crate) fn hand_restored_drag_to_platform(&mut self, source_window: WindowId) -> bool {
2624 let Some(platform_drag) = self.platform_owned_drag.as_mut().filter(|drag| {
2625 drag.source_window == source_window
2626 && matches!(&drag.state, PlatformOwnedDragState::RestoredInSourceWindow)
2627 }) else {
2628 return false;
2629 };
2630 let Some(drag) = self.active_drag.take() else {
2631 return false;
2632 };
2633 platform_drag.state = PlatformOwnedDragState::Suspended(drag);
2634 true
2635 }
2636
2637 pub(crate) fn end_platform_drag(&mut self, source_window: WindowId) -> bool {
2638 if !self
2639 .platform_owned_drag
2640 .as_ref()
2641 .is_some_and(|drag| drag.source_window == source_window)
2642 {
2643 return false;
2644 }
2645 self.platform_owned_drag = None;
2646 self.active_drag = None;
2647 true
2648 }
2649
2650 pub fn set_active_drag_cursor_style(
2652 &mut self,
2653 cursor_style: CursorStyle,
2654 window: &mut Window,
2655 ) -> bool {
2656 if let Some(ref mut drag) = self.active_drag {
2657 drag.cursor_style = Some(cursor_style);
2658 window.refresh();
2659 true
2660 } else {
2661 false
2662 }
2663 }
2664
2665 pub fn set_prompt_builder(
2668 &mut self,
2669 renderer: impl Fn(
2670 PromptLevel,
2671 &str,
2672 Option<&str>,
2673 &[PromptButton],
2674 PromptHandle,
2675 &mut Window,
2676 &mut App,
2677 ) -> RenderablePromptHandle
2678 + 'static,
2679 ) {
2680 self.prompt_builder = Some(PromptBuilder::Custom(Box::new(renderer)));
2681 }
2682
2683 pub fn reset_prompt_builder(&mut self) {
2685 self.prompt_builder = Some(PromptBuilder::Default);
2686 }
2687
2688 pub fn remove_asset<A: Asset>(&mut self, source: &A::Source) {
2690 let asset_id = (TypeId::of::<A>(), hash(source));
2691 self.loading_assets.remove(&asset_id);
2692 }
2693
2694 #[cfg(any(test, feature = "test-support"))]
2697 pub fn has_asset<A: Asset>(&self, source: &A::Source) -> bool {
2698 let asset_id = (TypeId::of::<A>(), hash(source));
2699 self.loading_assets.contains_key(&asset_id)
2700 }
2701
2702 pub fn fetch_asset<A: Asset>(&mut self, source: &A::Source) -> Option<A::Output> {
2707 self.asset_entry::<A>(source).get()
2708 }
2709
2710 pub(crate) fn asset_entry<A: Asset>(&mut self, source: &A::Source) -> &CachedLoad<A::Output> {
2711 let asset_id = (TypeId::of::<A>(), hash(source));
2712 if !self.loading_assets.contains_key(&asset_id) {
2713 let future = A::load(source.clone(), self);
2714 let entry = CachedLoad::new(future, self);
2715 self.loading_assets.insert(asset_id, Box::new(entry));
2716 }
2717 self.loading_assets
2718 .get(&asset_id)
2719 .and_then(|entry| entry.downcast_ref())
2720 .expect("asset cache entries are keyed by their asset type")
2721 }
2722
2723 #[track_caller]
2726 pub fn focus_handle(&self) -> FocusHandle {
2727 FocusHandle::new(&self.focus_handles)
2728 }
2729
2730 pub fn notify(&mut self, entity_id: EntityId) {
2732 let window_invalidators = mem::take(
2733 self.window_invalidators_by_entity
2734 .entry(entity_id)
2735 .or_default(),
2736 );
2737
2738 let live_invalidators: SmallVec<[WindowInvalidator; 2]> = window_invalidators
2743 .iter()
2744 .filter(|(window_id, _)| {
2745 self.tracked_entities
2746 .get(window_id)
2747 .is_some_and(|set| set.contains(&entity_id))
2748 })
2749 .map(|(_, invalidator)| invalidator.clone())
2750 .collect();
2751
2752 if live_invalidators.is_empty() {
2753 if self.pending_notifications.insert(entity_id) {
2754 self.pending_effects
2755 .push_back(Effect::Notify { emitter: entity_id });
2756 }
2757 } else {
2758 for invalidator in &live_invalidators {
2759 invalidator.invalidate_view(entity_id, self);
2760 }
2761 }
2762
2763 self.window_invalidators_by_entity
2764 .insert(entity_id, window_invalidators);
2765 }
2766
2767 #[cfg(any(test, feature = "test-support", debug_assertions))]
2769 pub fn get_name(&self) -> Option<&'static str> {
2770 self.name
2771 }
2772
2773 pub fn can_select_mixed_files_and_dirs(&self) -> bool {
2775 self.platform.can_select_mixed_files_and_dirs()
2776 }
2777
2778 pub fn drop_image(&mut self, image: Arc<RenderImage>, current_window: Option<&mut Window>) {
2783 for window in self.windows.values_mut().flatten() {
2785 _ = window.drop_image(image.clone());
2786 }
2787
2788 if let Some(window) = current_window {
2790 _ = window.drop_image(image);
2791 }
2792 }
2793
2794 #[cfg(any(feature = "inspector", debug_assertions))]
2796 pub fn set_inspector_renderer(&mut self, f: crate::InspectorRenderer) {
2797 self.inspector_renderer = Some(f);
2798 }
2799
2800 #[cfg(any(feature = "inspector", debug_assertions))]
2802 pub fn register_inspector_element<T: 'static, R: crate::IntoElement>(
2803 &mut self,
2804 f: impl 'static + Fn(crate::InspectorElementId, &T, &mut Window, &mut App) -> R,
2805 ) {
2806 self.inspector_element_registry.register(f);
2807 }
2808
2809 pub fn init_colors(&mut self) {
2813 self.set_global(GlobalColors(Arc::new(Colors::default())));
2814 }
2815}
2816
2817impl AppContext for App {
2818 fn new<T: 'static>(&mut self, build_entity: impl FnOnce(&mut Context<T>) -> T) -> Entity<T> {
2823 self.update(|cx| {
2824 let slot = cx.entities.reserve();
2825 let handle = slot.clone();
2826 let entity = build_entity(&mut Context::new_context(cx, slot.downgrade()));
2827
2828 cx.push_effect(Effect::EntityCreated {
2829 entity: handle.into_any(),
2830 tid: TypeId::of::<T>(),
2831 window: cx.window_update_stack.last().cloned(),
2832 });
2833
2834 cx.entities.insert(slot, entity)
2835 })
2836 }
2837
2838 fn reserve_entity<T: 'static>(&mut self) -> Reservation<T> {
2839 Reservation(self.entities.reserve())
2840 }
2841
2842 fn insert_entity<T: 'static>(
2843 &mut self,
2844 reservation: Reservation<T>,
2845 build_entity: impl FnOnce(&mut Context<T>) -> T,
2846 ) -> Entity<T> {
2847 self.update(|cx| {
2848 let slot = reservation.0;
2849 let entity = build_entity(&mut Context::new_context(cx, slot.downgrade()));
2850 cx.entities.insert(slot, entity)
2851 })
2852 }
2853
2854 fn update_entity<T: 'static, R>(
2857 &mut self,
2858 handle: &Entity<T>,
2859 update: impl FnOnce(&mut T, &mut Context<T>) -> R,
2860 ) -> R {
2861 self.update(|cx| {
2862 let mut entity = cx.entities.lease(handle);
2863 let result = update(
2864 &mut entity,
2865 &mut Context::new_context(cx, handle.downgrade()),
2866 );
2867 cx.entities.end_lease(entity);
2868 result
2869 })
2870 }
2871
2872 fn as_mut<'a, T>(&'a mut self, handle: &Entity<T>) -> GpuiBorrow<'a, T>
2873 where
2874 T: 'static,
2875 {
2876 GpuiBorrow::new(handle.clone(), self)
2877 }
2878
2879 fn read_entity<T, R>(&self, handle: &Entity<T>, read: impl FnOnce(&T, &App) -> R) -> R
2880 where
2881 T: 'static,
2882 {
2883 let entity = self.entities.read(handle);
2884 read(entity, self)
2885 }
2886
2887 fn update_window<T, F>(&mut self, handle: AnyWindowHandle, update: F) -> Result<T>
2888 where
2889 F: FnOnce(AnyView, &mut Window, &mut App) -> T,
2890 {
2891 self.update_window_id(handle.id, update)
2892 }
2893
2894 fn with_window<R>(
2895 &mut self,
2896 entity_id: EntityId,
2897 f: impl FnOnce(&mut Window, &mut App) -> R,
2898 ) -> Option<R> {
2899 App::with_window(self, entity_id, f)
2900 }
2901
2902 fn read_window<T, R>(
2903 &self,
2904 window: &WindowHandle<T>,
2905 read: impl FnOnce(Entity<T>, &App) -> R,
2906 ) -> Result<R>
2907 where
2908 T: 'static,
2909 {
2910 let window = self
2911 .windows
2912 .get(window.id)
2913 .context("window not found")?
2914 .as_deref()
2915 .expect("attempted to read a window that is already on the stack");
2916
2917 let root_view = window.root.clone().unwrap();
2918 let view = root_view
2919 .downcast::<T>()
2920 .map_err(|_| anyhow!("root view's type has changed"))?;
2921
2922 Ok(read(view, self))
2923 }
2924
2925 fn background_spawn<R>(&self, future: impl Future<Output = R> + Send + 'static) -> Task<R>
2926 where
2927 R: Send + 'static,
2928 {
2929 self.background_executor.spawn(future)
2930 }
2931
2932 fn read_global<G, R>(&self, callback: impl FnOnce(&G, &App) -> R) -> R
2933 where
2934 G: Global,
2935 {
2936 let mut g = self.global::<G>();
2937 callback(g, self)
2938 }
2939}
2940
2941pub(crate) enum Effect {
2943 Notify {
2944 emitter: EntityId,
2945 },
2946 Emit {
2947 emitter: EntityId,
2948 event_type: TypeId,
2949 event: ArenaBox<dyn Any>,
2950 },
2951 RefreshWindows,
2952 NotifyGlobalObservers {
2953 global_type: TypeId,
2954 },
2955 Defer {
2956 callback: Box<dyn FnOnce(&mut App) + 'static>,
2957 },
2958 EntityCreated {
2959 entity: AnyEntity,
2960 tid: TypeId,
2961 window: Option<WindowId>,
2962 },
2963}
2964
2965impl std::fmt::Debug for Effect {
2966 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2967 match self {
2968 Effect::Notify { emitter } => write!(f, "Notify({})", emitter),
2969 Effect::Emit { emitter, .. } => write!(f, "Emit({:?})", emitter),
2970 Effect::RefreshWindows => write!(f, "RefreshWindows"),
2971 Effect::NotifyGlobalObservers { global_type } => {
2972 write!(f, "NotifyGlobalObservers({:?})", global_type)
2973 }
2974 Effect::Defer { .. } => write!(f, "Defer(..)"),
2975 Effect::EntityCreated { entity, .. } => write!(f, "EntityCreated({:?})", entity),
2976 }
2977 }
2978}
2979
2980pub(crate) struct GlobalLease<G: Global> {
2982 global: Box<dyn Any>,
2983 global_type: PhantomData<G>,
2984}
2985
2986impl<G: Global> GlobalLease<G> {
2987 fn new(global: Box<dyn Any>) -> Self {
2988 GlobalLease {
2989 global,
2990 global_type: PhantomData,
2991 }
2992 }
2993}
2994
2995impl<G: Global> Deref for GlobalLease<G> {
2996 type Target = G;
2997
2998 fn deref(&self) -> &Self::Target {
2999 self.global.downcast_ref().unwrap()
3000 }
3001}
3002
3003impl<G: Global> DerefMut for GlobalLease<G> {
3004 fn deref_mut(&mut self) -> &mut Self::Target {
3005 self.global.downcast_mut().unwrap()
3006 }
3007}
3008
3009pub struct AnyDrag {
3012 pub view: AnyView,
3014
3015 pub value: Arc<dyn Any>,
3017
3018 pub cursor_offset: Point<Pixels>,
3021
3022 pub cursor_style: Option<CursorStyle>,
3024
3025 pub external_payload_source: Option<ExternalDragPayloadSource>,
3028}
3029
3030pub type ExternalDragPayloadSource =
3033 Box<dyn FnOnce(&mut Window, &mut App) -> Option<ExternalDragPayload> + 'static>;
3034
3035#[derive(Clone)]
3038pub struct AnyTooltip {
3039 pub view: AnyView,
3041
3042 pub mouse_position: Point<Pixels>,
3044
3045 pub check_visible_and_update: Rc<dyn Fn(Bounds<Pixels>, &mut Window, &mut App) -> bool>,
3049}
3050
3051#[derive(Debug)]
3053pub struct KeystrokeEvent {
3054 pub keystroke: Keystroke,
3056
3057 pub action: Option<Box<dyn Action>>,
3059
3060 pub context_stack: Vec<KeyContext>,
3062}
3063
3064struct NullHttpClient;
3065
3066impl HttpClient for NullHttpClient {
3067 fn send(
3068 &self,
3069 _req: http_client::Request<http_client::AsyncBody>,
3070 ) -> futures::future::BoxFuture<
3071 'static,
3072 anyhow::Result<http_client::Response<http_client::AsyncBody>>,
3073 > {
3074 async move {
3075 anyhow::bail!("No HttpClient available");
3076 }
3077 .boxed()
3078 }
3079
3080 fn user_agent(&self) -> Option<&http_client::http::HeaderValue> {
3081 None
3082 }
3083
3084 fn proxy(&self) -> Option<&Url> {
3085 None
3086 }
3087}
3088
3089pub struct GpuiBorrow<'a, T> {
3091 inner: Option<Lease<T>>,
3092 app: &'a mut App,
3093}
3094
3095impl<'a, T: 'static> GpuiBorrow<'a, T> {
3096 fn new(inner: Entity<T>, app: &'a mut App) -> Self {
3097 app.start_update();
3098 let lease = app.entities.lease(&inner);
3099 Self {
3100 inner: Some(lease),
3101 app,
3102 }
3103 }
3104}
3105
3106impl<'a, T: 'static> std::borrow::Borrow<T> for GpuiBorrow<'a, T> {
3107 fn borrow(&self) -> &T {
3108 self.inner.as_ref().unwrap().borrow()
3109 }
3110}
3111
3112impl<'a, T: 'static> std::borrow::BorrowMut<T> for GpuiBorrow<'a, T> {
3113 fn borrow_mut(&mut self) -> &mut T {
3114 self.inner.as_mut().unwrap().borrow_mut()
3115 }
3116}
3117
3118impl<'a, T: 'static> std::ops::Deref for GpuiBorrow<'a, T> {
3119 type Target = T;
3120
3121 fn deref(&self) -> &Self::Target {
3122 self.inner.as_ref().unwrap()
3123 }
3124}
3125
3126impl<'a, T: 'static> std::ops::DerefMut for GpuiBorrow<'a, T> {
3127 fn deref_mut(&mut self) -> &mut T {
3128 self.inner.as_mut().unwrap()
3129 }
3130}
3131
3132impl<'a, T> Drop for GpuiBorrow<'a, T> {
3133 fn drop(&mut self) {
3134 let lease = self.inner.take().unwrap();
3135 self.app.notify(lease.id);
3136 self.app.entities.end_lease(lease);
3137 self.app.finish_update();
3138 }
3139}
3140
3141#[cfg(test)]
3142mod test {
3143 use std::{
3144 cell::{Cell, RefCell},
3145 ffi::OsString,
3146 path::PathBuf,
3147 rc::Rc,
3148 };
3149
3150 #[cfg(unix)]
3151 use std::os::unix::ffi::OsStringExt;
3152
3153 use crate::{AppContext, Context, Empty, IntoElement, Render, TestAppContext, Window};
3154
3155 struct RenderCounter(Rc<Cell<usize>>);
3156
3157 impl Render for RenderCounter {
3158 fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
3159 self.0.set(self.0.get() + 1);
3160 Empty
3161 }
3162 }
3163
3164 #[gpui::test]
3165 fn async_app_refresh_flushes_refresh_effect(cx: &mut TestAppContext) {
3166 let render_count = Rc::new(Cell::new(0));
3167
3168 let _window = cx.add_window({
3169 let render_count = render_count.clone();
3170 move |_, _| RenderCounter(render_count)
3171 });
3172
3173 cx.run_until_parked();
3174 let render_count_before_refresh = render_count.get();
3175
3176 cx.to_async().refresh();
3177
3178 assert_eq!(render_count.get(), render_count_before_refresh + 1);
3179 }
3180
3181 #[test]
3182 fn test_gpui_borrow() {
3183 let cx = TestAppContext::single();
3184 let observation_count = Rc::new(RefCell::new(0));
3185
3186 let state = cx.update(|cx| {
3187 let state = cx.new(|_| false);
3188 cx.observe(&state, {
3189 let observation_count = observation_count.clone();
3190 move |_, _| {
3191 let mut count = observation_count.borrow_mut();
3192 *count += 1;
3193 }
3194 })
3195 .detach();
3196
3197 state
3198 });
3199
3200 cx.update(|cx| {
3201 *std::borrow::BorrowMut::borrow_mut(&mut state.as_mut(cx)) = true;
3203 });
3204
3205 cx.update(|cx| {
3206 state.write(cx, false);
3207 });
3208
3209 assert_eq!(*observation_count.borrow(), 2);
3210 }
3211
3212 #[gpui::test]
3213 async fn test_restart_preserves_path_and_arguments(cx: &mut TestAppContext) {
3214 #[cfg(unix)]
3215 let user_data_dir = OsString::from_vec(b"/tmp/zed data/\xff".to_vec());
3216 #[cfg(not(unix))]
3217 let user_data_dir = OsString::from("C:\\zed data");
3218 let arguments = vec![OsString::from("--user-data-dir"), user_data_dir];
3219 let restart_path = PathBuf::from("updated-zed");
3220 let _application =
3221 super::Application(cx.app.clone()).with_restart_arguments(arguments.clone());
3222 let restart = cx.expect_restart();
3223
3224 cx.update(|cx| {
3225 cx.set_restart_path(restart_path.clone());
3226 cx.restart();
3227 });
3228
3229 let (path, restart_arguments) = restart.await.expect("restart was not requested");
3230 assert_eq!(path, Some(restart_path));
3231 assert_eq!(restart_arguments, arguments);
3232 }
3233}