1use std::{
2 any::{TypeId, type_name},
3 cell::{BorrowMutError, Ref, RefCell, RefMut},
4 marker::PhantomData,
5 mem,
6 ops::{Deref, DerefMut},
7 path::{Path, PathBuf},
8 rc::{Rc, Weak},
9 sync::{Arc, atomic::Ordering::SeqCst},
10 time::{Duration, Instant},
11};
12
13use anyhow::{Context as _, Result, anyhow};
14use derive_more::{Deref, DerefMut};
15use futures::{
16 Future, FutureExt,
17 channel::oneshot,
18 future::{LocalBoxFuture, Shared},
19};
20use itertools::Itertools;
21use parking_lot::RwLock;
22use slotmap::SlotMap;
23
24pub use async_context::*;
25use collections::{FxHashMap, FxHashSet, HashMap, VecDeque};
26pub use context::*;
27pub use entity_map::*;
28use http_client::{HttpClient, Url};
29use smallvec::SmallVec;
30#[cfg(any(test, feature = "test-support"))]
31pub use test_context::*;
32use util::{ResultExt, debug_panic};
33
34#[cfg(any(feature = "inspector", debug_assertions))]
35use crate::InspectorElementRegistry;
36use crate::{
37 Action, ActionBuildError, ActionRegistry, Any, AnyView, AnyWindowHandle, AppContext, Asset,
38 AssetSource, AttentionType, BackgroundExecutor, BiometricStatus, Bounds, ClipboardItem,
39 CrashReport, CursorStyle, DialogOptions, DispatchPhase, DisplayId, EventEmitter, FocusHandle,
40 FocusMap, FocusedWindowInfo, ForegroundExecutor, Global, KeyBinding, KeyContext, Keymap,
41 Keystroke, LayoutId, MediaKeyEvent, Menu, MenuItem, NetworkStatus, OsInfo, OwnedMenu,
42 PathPromptOptions, PermissionStatus, Pixels, Platform, PlatformDisplay,
43 PlatformKeyboardLayout, PlatformKeyboardMapper, Point, PowerSaveBlockerKind, PromptBuilder,
44 PromptButton, PromptHandle, PromptLevel, Render, RenderImage, RenderablePromptHandle,
45 Reservation, ScreenCaptureSource, SharedString, Size, SubscriberSet, Subscription, SvgRenderer,
46 SystemPowerEvent, Task, TextSystem, TrayIconEvent, TrayMenuItem, Window, WindowAppearance,
47 WindowHandle, WindowId, WindowInvalidator, WindowPosition,
48 colors::{Colors, GlobalColors},
49 current_platform, hash, init_app_menus,
50};
51
52mod async_context;
53mod context;
54mod entity_map;
55#[cfg(any(test, feature = "test-support"))]
56mod test_context;
57
58pub const SHUTDOWN_TIMEOUT: Duration = Duration::from_millis(100);
60
61#[doc(hidden)]
64pub struct AppCell {
65 app: RefCell<App>,
66}
67
68impl AppCell {
69 #[doc(hidden)]
70 #[track_caller]
71 pub fn borrow(&self) -> AppRef<'_> {
72 if option_env!("TRACK_THREAD_BORROWS").is_some() {
73 let thread_id = std::thread::current().id();
74 eprintln!("borrowed {thread_id:?}");
75 }
76 AppRef(self.app.borrow())
77 }
78
79 #[doc(hidden)]
80 #[track_caller]
81 pub fn borrow_mut(&self) -> AppRefMut<'_> {
82 if option_env!("TRACK_THREAD_BORROWS").is_some() {
83 let thread_id = std::thread::current().id();
84 eprintln!("borrowed {thread_id:?}");
85 }
86 AppRefMut(self.app.borrow_mut())
87 }
88
89 #[doc(hidden)]
90 #[track_caller]
91 pub fn try_borrow_mut(&self) -> Result<AppRefMut<'_>, BorrowMutError> {
92 if option_env!("TRACK_THREAD_BORROWS").is_some() {
93 let thread_id = std::thread::current().id();
94 eprintln!("borrowed {thread_id:?}");
95 }
96 Ok(AppRefMut(self.app.try_borrow_mut()?))
97 }
98}
99
100#[doc(hidden)]
101#[derive(Deref, DerefMut)]
102pub struct AppRef<'a>(Ref<'a, App>);
103
104impl Drop for AppRef<'_> {
105 fn drop(&mut self) {
106 if option_env!("TRACK_THREAD_BORROWS").is_some() {
107 let thread_id = std::thread::current().id();
108 eprintln!("dropped borrow from {thread_id:?}");
109 }
110 }
111}
112
113#[doc(hidden)]
114#[derive(Deref, DerefMut)]
115pub struct AppRefMut<'a>(RefMut<'a, App>);
116
117impl Drop for AppRefMut<'_> {
118 fn drop(&mut self) {
119 if option_env!("TRACK_THREAD_BORROWS").is_some() {
120 let thread_id = std::thread::current().id();
121 eprintln!("dropped {thread_id:?}");
122 }
123 }
124}
125
126pub struct Application(Rc<AppCell>);
129
130impl Application {
133 #[allow(clippy::new_without_default)]
135 pub fn new() -> Self {
136 #[cfg(any(test, feature = "test-support"))]
137 log::info!("GPUI was compiled in test mode");
138
139 Self(App::new_app(
140 current_platform(false),
141 Arc::new(()),
142 Arc::new(NullHttpClient),
143 ))
144 }
145
146 pub fn headless() -> Self {
150 Self(App::new_app(
151 current_platform(true),
152 Arc::new(()),
153 Arc::new(NullHttpClient),
154 ))
155 }
156
157 pub fn with_assets(self, asset_source: impl AssetSource) -> Self {
159 let mut context_lock = self.0.borrow_mut();
160 let asset_source = Arc::new(asset_source);
161 context_lock.asset_source = asset_source.clone();
162 context_lock.svg_renderer = SvgRenderer::new(asset_source);
163 drop(context_lock);
164 self
165 }
166
167 pub fn with_http_client(self, http_client: Arc<dyn HttpClient>) -> Self {
169 let mut context_lock = self.0.borrow_mut();
170 context_lock.http_client = http_client;
171 drop(context_lock);
172 self
173 }
174
175 pub fn run<F>(self, on_finish_launching: F)
178 where
179 F: 'static + FnOnce(&mut App),
180 {
181 let this = self.0.clone();
182 let platform = self.0.borrow().platform.clone();
183 platform.run(Box::new(move || {
184 let cx = &mut *this.borrow_mut();
185 on_finish_launching(cx);
186 }));
187 }
188
189 pub fn on_open_urls<F>(&self, mut callback: F) -> &Self
192 where
193 F: 'static + FnMut(Vec<String>),
194 {
195 self.0.borrow().platform.on_open_urls(Box::new(callback));
196 self
197 }
198
199 pub fn on_reopen<F>(&self, mut callback: F) -> &Self
202 where
203 F: 'static + FnMut(&mut App),
204 {
205 let this = Rc::downgrade(&self.0);
206 self.0.borrow_mut().platform.on_reopen(Box::new(move || {
207 if let Some(app) = this.upgrade() {
208 callback(&mut app.borrow_mut());
209 }
210 }));
211 self
212 }
213
214 pub fn background_executor(&self) -> BackgroundExecutor {
216 self.0.borrow().background_executor.clone()
217 }
218
219 pub fn foreground_executor(&self) -> ForegroundExecutor {
221 self.0.borrow().foreground_executor.clone()
222 }
223
224 pub fn text_system(&self) -> Arc<TextSystem> {
226 self.0.borrow().text_system.clone()
227 }
228
229 pub fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf> {
231 self.0.borrow().path_for_auxiliary_executable(name)
232 }
233}
234
235type Handler = Box<dyn FnMut(&mut App) -> bool + 'static>;
236type Listener = Box<dyn FnMut(&dyn Any, &mut App) -> bool + 'static>;
237pub(crate) type KeystrokeObserver =
238 Box<dyn FnMut(&KeystrokeEvent, &mut Window, &mut App) -> bool + 'static>;
239type QuitHandler = Box<dyn FnOnce(&mut App) -> LocalBoxFuture<'static, ()> + 'static>;
240type WindowClosedHandler = Box<dyn FnMut(&mut App)>;
241type ReleaseListener = Box<dyn FnOnce(&mut dyn Any, &mut App) + 'static>;
242type NewEntityListener = Box<dyn FnMut(AnyEntity, &mut Option<&mut Window>, &mut App) + 'static>;
243
244#[doc(hidden)]
245#[derive(Clone, PartialEq, Eq)]
246pub struct SystemWindowTab {
247 pub id: WindowId,
248 pub title: SharedString,
249 pub handle: AnyWindowHandle,
250 pub last_active_at: Instant,
251}
252
253impl SystemWindowTab {
254 pub fn new(title: SharedString, handle: AnyWindowHandle) -> Self {
256 Self {
257 id: handle.id,
258 title,
259 handle,
260 last_active_at: Instant::now(),
261 }
262 }
263}
264
265#[derive(Default)]
267pub struct SystemWindowTabController {
268 visible: Option<bool>,
269 tab_groups: FxHashMap<usize, Vec<SystemWindowTab>>,
270}
271
272impl Global for SystemWindowTabController {}
273
274impl SystemWindowTabController {
275 pub fn new() -> Self {
277 Self {
278 visible: None,
279 tab_groups: FxHashMap::default(),
280 }
281 }
282
283 pub fn init(cx: &mut App) {
285 cx.set_global(SystemWindowTabController::new());
286 }
287
288 pub fn tab_groups(&self) -> &FxHashMap<usize, Vec<SystemWindowTab>> {
290 &self.tab_groups
291 }
292
293 pub fn get_next_tab_group_window(cx: &mut App, id: WindowId) -> Option<&AnyWindowHandle> {
295 let controller = cx.global::<SystemWindowTabController>();
296 let current_group = controller
297 .tab_groups
298 .iter()
299 .find_map(|(group, tabs)| tabs.iter().find(|tab| tab.id == id).map(|_| group));
300
301 let current_group = current_group?;
302 let mut group_ids: Vec<_> = controller.tab_groups.keys().collect();
303 let idx = group_ids.iter().position(|g| *g == current_group)?;
304 let next_idx = (idx + 1) % group_ids.len();
305
306 controller
307 .tab_groups
308 .get(group_ids[next_idx])
309 .and_then(|tabs| {
310 tabs.iter()
311 .max_by_key(|tab| tab.last_active_at)
312 .or_else(|| tabs.first())
313 .map(|tab| &tab.handle)
314 })
315 }
316
317 pub fn get_prev_tab_group_window(cx: &mut App, id: WindowId) -> Option<&AnyWindowHandle> {
319 let controller = cx.global::<SystemWindowTabController>();
320 let current_group = controller
321 .tab_groups
322 .iter()
323 .find_map(|(group, tabs)| tabs.iter().find(|tab| tab.id == id).map(|_| group));
324
325 let current_group = current_group?;
326 let mut group_ids: Vec<_> = controller.tab_groups.keys().collect();
327 let idx = group_ids.iter().position(|g| *g == current_group)?;
328 let prev_idx = if idx == 0 {
329 group_ids.len() - 1
330 } else {
331 idx - 1
332 };
333
334 controller
335 .tab_groups
336 .get(group_ids[prev_idx])
337 .and_then(|tabs| {
338 tabs.iter()
339 .max_by_key(|tab| tab.last_active_at)
340 .or_else(|| tabs.first())
341 .map(|tab| &tab.handle)
342 })
343 }
344
345 pub fn tabs(&self, id: WindowId) -> Option<&Vec<SystemWindowTab>> {
347 let tab_group = self
348 .tab_groups
349 .iter()
350 .find_map(|(group, tabs)| tabs.iter().find(|tab| tab.id == id).map(|_| *group));
351
352 if let Some(tab_group) = tab_group {
353 self.tab_groups.get(&tab_group)
354 } else {
355 None
356 }
357 }
358
359 pub fn init_visible(cx: &mut App, visible: bool) {
361 let mut controller = cx.global_mut::<SystemWindowTabController>();
362 if controller.visible.is_none() {
363 controller.visible = Some(visible);
364 }
365 }
366
367 pub fn is_visible(&self) -> bool {
369 self.visible.unwrap_or(false)
370 }
371
372 pub fn set_visible(cx: &mut App, visible: bool) {
374 let mut controller = cx.global_mut::<SystemWindowTabController>();
375 controller.visible = Some(visible);
376 }
377
378 pub fn update_last_active(cx: &mut App, id: WindowId) {
380 let mut controller = cx.global_mut::<SystemWindowTabController>();
381 for windows in controller.tab_groups.values_mut() {
382 for tab in windows.iter_mut() {
383 if tab.id == id {
384 tab.last_active_at = Instant::now();
385 }
386 }
387 }
388 }
389
390 pub fn update_tab_position(cx: &mut App, id: WindowId, ix: usize) {
392 let mut controller = cx.global_mut::<SystemWindowTabController>();
393 for (_, windows) in controller.tab_groups.iter_mut() {
394 if let Some(current_pos) = windows.iter().position(|tab| tab.id == id) {
395 if ix < windows.len() && current_pos != ix {
396 let window_tab = windows.remove(current_pos);
397 windows.insert(ix, window_tab);
398 }
399 break;
400 }
401 }
402 }
403
404 pub fn update_tab_title(cx: &mut App, id: WindowId, title: SharedString) {
406 let controller = cx.global::<SystemWindowTabController>();
407 let tab = controller
408 .tab_groups
409 .values()
410 .flat_map(|windows| windows.iter())
411 .find(|tab| tab.id == id);
412
413 if tab.map_or(true, |t| t.title == title) {
414 return;
415 }
416
417 let mut controller = cx.global_mut::<SystemWindowTabController>();
418 for windows in controller.tab_groups.values_mut() {
419 for tab in windows.iter_mut() {
420 if tab.id == id {
421 tab.title = title.clone();
422 }
423 }
424 }
425 }
426
427 pub fn add_tab(cx: &mut App, id: WindowId, tabs: Vec<SystemWindowTab>) {
429 let mut controller = cx.global_mut::<SystemWindowTabController>();
430 let Some(tab) = tabs.clone().into_iter().find(|tab| tab.id == id) else {
431 return;
432 };
433
434 let mut expected_tab_ids: Vec<_> = tabs
435 .iter()
436 .filter(|tab| tab.id != id)
437 .map(|tab| tab.id)
438 .sorted()
439 .collect();
440
441 let mut tab_group_id = None;
442 for (group_id, group_tabs) in &controller.tab_groups {
443 let tab_ids: Vec<_> = group_tabs.iter().map(|tab| tab.id).sorted().collect();
444 if tab_ids == expected_tab_ids {
445 tab_group_id = Some(*group_id);
446 break;
447 }
448 }
449
450 if let Some(tab_group_id) = tab_group_id {
451 if let Some(tabs) = controller.tab_groups.get_mut(&tab_group_id) {
452 tabs.push(tab);
453 }
454 } else {
455 let new_group_id = controller.tab_groups.len();
456 controller.tab_groups.insert(new_group_id, tabs);
457 }
458 }
459
460 pub fn remove_tab(cx: &mut App, id: WindowId) -> Option<SystemWindowTab> {
462 let mut controller = cx.global_mut::<SystemWindowTabController>();
463 let mut removed_tab = None;
464
465 controller.tab_groups.retain(|_, tabs| {
466 if let Some(pos) = tabs.iter().position(|tab| tab.id == id) {
467 removed_tab = Some(tabs.remove(pos));
468 }
469 !tabs.is_empty()
470 });
471
472 removed_tab
473 }
474
475 pub fn move_tab_to_new_window(cx: &mut App, id: WindowId) {
477 let mut removed_tab = Self::remove_tab(cx, id);
478 let mut controller = cx.global_mut::<SystemWindowTabController>();
479
480 if let Some(tab) = removed_tab {
481 let new_group_id = controller.tab_groups.keys().max().map_or(0, |k| k + 1);
482 controller.tab_groups.insert(new_group_id, vec![tab]);
483 }
484 }
485
486 pub fn merge_all_windows(cx: &mut App, id: WindowId) {
488 let mut controller = cx.global_mut::<SystemWindowTabController>();
489 let Some(initial_tabs) = controller.tabs(id) else {
490 return;
491 };
492
493 let mut all_tabs = initial_tabs.clone();
494 for tabs in controller.tab_groups.values() {
495 all_tabs.extend(
496 tabs.iter()
497 .filter(|tab| !initial_tabs.contains(tab))
498 .cloned(),
499 );
500 }
501
502 controller.tab_groups.clear();
503 controller.tab_groups.insert(0, all_tabs);
504 }
505
506 pub fn select_next_tab(cx: &mut App, id: WindowId) {
508 let mut controller = cx.global_mut::<SystemWindowTabController>();
509 let Some(tabs) = controller.tabs(id) else {
510 return;
511 };
512
513 let current_index = tabs.iter().position(|tab| tab.id == id).unwrap();
514 let next_index = (current_index + 1) % tabs.len();
515
516 let _ = &tabs[next_index].handle.update(cx, |_, window, _| {
517 window.activate_window();
518 });
519 }
520
521 pub fn select_previous_tab(cx: &mut App, id: WindowId) {
523 let mut controller = cx.global_mut::<SystemWindowTabController>();
524 let Some(tabs) = controller.tabs(id) else {
525 return;
526 };
527
528 let current_index = tabs.iter().position(|tab| tab.id == id).unwrap();
529 let previous_index = if current_index == 0 {
530 tabs.len() - 1
531 } else {
532 current_index - 1
533 };
534
535 let _ = &tabs[previous_index].handle.update(cx, |_, window, _| {
536 window.activate_window();
537 });
538 }
539}
540
541pub struct App {
545 pub(crate) this: Weak<AppCell>,
546 pub(crate) platform: Rc<dyn Platform>,
547 text_system: Arc<TextSystem>,
548 flushing_effects: bool,
549 pending_updates: usize,
550 pub(crate) actions: Rc<ActionRegistry>,
551 pub(crate) active_drag: Option<AnyDrag>,
552 pub(crate) background_executor: BackgroundExecutor,
553 pub(crate) foreground_executor: ForegroundExecutor,
554 pub(crate) loading_assets: FxHashMap<(TypeId, u64), Box<dyn Any>>,
555 asset_source: Arc<dyn AssetSource>,
556 pub(crate) svg_renderer: SvgRenderer,
557 http_client: Arc<dyn HttpClient>,
558 pub(crate) globals_by_type: FxHashMap<TypeId, Box<dyn Any>>,
559 pub(crate) entities: EntityMap,
560 pub(crate) window_update_stack: Vec<WindowId>,
561 pub(crate) new_entity_observers: SubscriberSet<TypeId, NewEntityListener>,
562 pub(crate) windows: SlotMap<WindowId, Option<Window>>,
563 pub(crate) window_handles: FxHashMap<WindowId, AnyWindowHandle>,
564 pub(crate) focus_handles: Arc<FocusMap>,
565 pub(crate) keymap: Rc<RefCell<Keymap>>,
566 pub(crate) keyboard_layout: Box<dyn PlatformKeyboardLayout>,
567 pub(crate) keyboard_mapper: Rc<dyn PlatformKeyboardMapper>,
568 pub(crate) global_action_listeners:
569 FxHashMap<TypeId, Vec<Rc<dyn Fn(&dyn Any, DispatchPhase, &mut Self)>>>,
570 pending_effects: VecDeque<Effect>,
571 pub(crate) pending_notifications: FxHashSet<EntityId>,
572 pub(crate) pending_global_notifications: FxHashSet<TypeId>,
573 pub(crate) observers: SubscriberSet<EntityId, Handler>,
574 pub(crate) event_listeners: SubscriberSet<EntityId, (TypeId, Listener)>,
576 pub(crate) keystroke_observers: SubscriberSet<(), KeystrokeObserver>,
577 pub(crate) keystroke_interceptors: SubscriberSet<(), KeystrokeObserver>,
578 pub(crate) keyboard_layout_observers: SubscriberSet<(), Handler>,
579 pub(crate) release_listeners: SubscriberSet<EntityId, ReleaseListener>,
580 pub(crate) global_observers: SubscriberSet<TypeId, Handler>,
581 pub(crate) quit_observers: SubscriberSet<(), QuitHandler>,
582 pub(crate) restart_observers: SubscriberSet<(), Handler>,
583 pub(crate) restart_path: Option<PathBuf>,
584 pub(crate) window_closed_observers: SubscriberSet<(), WindowClosedHandler>,
585 pub(crate) layout_id_buffer: Vec<LayoutId>, pub(crate) propagate_event: bool,
587 pub(crate) prompt_builder: Option<PromptBuilder>,
588 pub(crate) window_invalidators_by_entity:
589 FxHashMap<EntityId, FxHashMap<WindowId, WindowInvalidator>>,
590 pub(crate) tracked_entities: FxHashMap<WindowId, FxHashSet<EntityId>>,
591 #[cfg(any(feature = "inspector", debug_assertions))]
592 pub(crate) inspector_renderer: Option<crate::InspectorRenderer>,
593 #[cfg(any(feature = "inspector", debug_assertions))]
594 pub(crate) inspector_element_registry: InspectorElementRegistry,
595 #[cfg(any(test, feature = "test-support", debug_assertions))]
596 pub(crate) name: Option<&'static str>,
597 quitting: bool,
598}
599
600impl App {
601 #[allow(clippy::new_ret_no_self)]
602 pub(crate) fn new_app(
603 platform: Rc<dyn Platform>,
604 asset_source: Arc<dyn AssetSource>,
605 http_client: Arc<dyn HttpClient>,
606 ) -> Rc<AppCell> {
607 let executor = platform.background_executor();
608 let foreground_executor = platform.foreground_executor();
609 assert!(
610 executor.is_main_thread(),
611 "must construct App on main thread"
612 );
613
614 let text_system = Arc::new(TextSystem::new(platform.text_system()));
615 let entities = EntityMap::new();
616 let keyboard_layout = platform.keyboard_layout();
617 let keyboard_mapper = platform.keyboard_mapper();
618
619 let app = Rc::new_cyclic(|this| AppCell {
620 app: RefCell::new(App {
621 this: this.clone(),
622 platform: platform.clone(),
623 text_system,
624 actions: Rc::new(ActionRegistry::default()),
625 flushing_effects: false,
626 pending_updates: 0,
627 active_drag: None,
628 background_executor: executor,
629 foreground_executor,
630 svg_renderer: SvgRenderer::new(asset_source.clone()),
631 loading_assets: Default::default(),
632 asset_source,
633 http_client,
634 globals_by_type: FxHashMap::default(),
635 entities,
636 new_entity_observers: SubscriberSet::new(),
637 windows: SlotMap::with_key(),
638 window_update_stack: Vec::new(),
639 window_handles: FxHashMap::default(),
640 focus_handles: Arc::new(RwLock::new(SlotMap::with_key())),
641 keymap: Rc::new(RefCell::new(Keymap::default())),
642 keyboard_layout,
643 keyboard_mapper,
644 global_action_listeners: FxHashMap::default(),
645 pending_effects: VecDeque::new(),
646 pending_notifications: FxHashSet::default(),
647 pending_global_notifications: FxHashSet::default(),
648 observers: SubscriberSet::new(),
649 tracked_entities: FxHashMap::default(),
650 window_invalidators_by_entity: FxHashMap::default(),
651 event_listeners: SubscriberSet::new(),
652 release_listeners: SubscriberSet::new(),
653 keystroke_observers: SubscriberSet::new(),
654 keystroke_interceptors: SubscriberSet::new(),
655 keyboard_layout_observers: SubscriberSet::new(),
656 global_observers: SubscriberSet::new(),
657 quit_observers: SubscriberSet::new(),
658 restart_observers: SubscriberSet::new(),
659 restart_path: None,
660 window_closed_observers: SubscriberSet::new(),
661 layout_id_buffer: Default::default(),
662 propagate_event: true,
663 prompt_builder: Some(PromptBuilder::Default),
664 #[cfg(any(feature = "inspector", debug_assertions))]
665 inspector_renderer: None,
666 #[cfg(any(feature = "inspector", debug_assertions))]
667 inspector_element_registry: InspectorElementRegistry::default(),
668 quitting: false,
669
670 #[cfg(any(test, feature = "test-support", debug_assertions))]
671 name: None,
672 }),
673 });
674
675 init_app_menus(platform.as_ref(), &app.borrow());
676 SystemWindowTabController::init(&mut app.borrow_mut());
677
678 platform.on_keyboard_layout_change(Box::new({
679 let app = Rc::downgrade(&app);
680 move || {
681 if let Some(app) = app.upgrade() {
682 let cx = &mut app.borrow_mut();
683 cx.keyboard_layout = cx.platform.keyboard_layout();
684 cx.keyboard_mapper = cx.platform.keyboard_mapper();
685 cx.keyboard_layout_observers
686 .clone()
687 .retain(&(), move |callback| (callback)(cx));
688 }
689 }
690 }));
691
692 platform.on_quit(Box::new({
693 let cx = app.clone();
694 move || {
695 cx.borrow_mut().shutdown();
696 }
697 }));
698
699 app
700 }
701
702 pub fn shutdown(&mut self) {
705 let mut futures = Vec::new();
706
707 for observer in self.quit_observers.remove(&()) {
708 futures.push(observer(self));
709 }
710
711 self.windows.clear();
712 self.window_handles.clear();
713 self.flush_effects();
714 self.quitting = true;
715
716 let futures = futures::future::join_all(futures);
717 if self
718 .background_executor
719 .block_with_timeout(SHUTDOWN_TIMEOUT, futures)
720 .is_err()
721 {
722 log::error!("timed out waiting on app_will_quit");
723 }
724
725 self.quitting = false;
726 }
727
728 pub fn keyboard_layout(&self) -> &dyn PlatformKeyboardLayout {
730 self.keyboard_layout.as_ref()
731 }
732
733 pub fn keyboard_mapper(&self) -> &Rc<dyn PlatformKeyboardMapper> {
735 &self.keyboard_mapper
736 }
737
738 pub fn on_keyboard_layout_change<F>(&self, mut callback: F) -> Subscription
740 where
741 F: 'static + FnMut(&mut App),
742 {
743 let (subscription, activate) = self.keyboard_layout_observers.insert(
744 (),
745 Box::new(move |cx| {
746 callback(cx);
747 true
748 }),
749 );
750 activate();
751 subscription
752 }
753
754 pub fn quit(&self) {
756 self.platform.quit();
757 }
758
759 pub fn refresh_windows(&mut self) {
762 self.pending_effects.push_back(Effect::RefreshWindows);
763 }
764
765 pub(crate) fn update<R>(&mut self, update: impl FnOnce(&mut Self) -> R) -> R {
766 self.start_update();
767 let result = update(self);
768 self.finish_update();
769 result
770 }
771
772 pub(crate) fn start_update(&mut self) {
773 self.pending_updates += 1;
774 }
775
776 pub(crate) fn finish_update(&mut self) {
777 if !self.flushing_effects && self.pending_updates == 1 {
778 self.flushing_effects = true;
779 self.flush_effects();
780 self.flushing_effects = false;
781 }
782 self.pending_updates -= 1;
783 }
784
785 pub fn observe<W>(
787 &mut self,
788 entity: &Entity<W>,
789 mut on_notify: impl FnMut(Entity<W>, &mut App) + 'static,
790 ) -> Subscription
791 where
792 W: 'static,
793 {
794 self.observe_internal(entity, move |e, cx| {
795 on_notify(e, cx);
796 true
797 })
798 }
799
800 pub(crate) fn detect_accessed_entities<R>(
801 &mut self,
802 callback: impl FnOnce(&mut App) -> R,
803 ) -> (R, FxHashSet<EntityId>) {
804 let accessed_entities_start = self.entities.accessed_entities.borrow().clone();
805 let result = callback(self);
806 let accessed_entities_end = self.entities.accessed_entities.borrow().clone();
807 let entities_accessed_in_callback = accessed_entities_end
808 .difference(&accessed_entities_start)
809 .copied()
810 .collect::<FxHashSet<EntityId>>();
811 (result, entities_accessed_in_callback)
812 }
813
814 pub(crate) fn record_entities_accessed(
815 &mut self,
816 window_handle: AnyWindowHandle,
817 invalidator: WindowInvalidator,
818 entities: &FxHashSet<EntityId>,
819 ) {
820 let mut tracked_entities =
821 std::mem::take(self.tracked_entities.entry(window_handle.id).or_default());
822 for entity in tracked_entities.iter() {
823 self.window_invalidators_by_entity
824 .entry(*entity)
825 .and_modify(|windows| {
826 windows.remove(&window_handle.id);
827 });
828 }
829 for entity in entities.iter() {
830 self.window_invalidators_by_entity
831 .entry(*entity)
832 .or_default()
833 .insert(window_handle.id, invalidator.clone());
834 }
835 tracked_entities.clear();
836 tracked_entities.extend(entities.iter().copied());
837 self.tracked_entities
838 .insert(window_handle.id, tracked_entities);
839 }
840
841 pub(crate) fn new_observer(&mut self, key: EntityId, value: Handler) -> Subscription {
842 let (subscription, activate) = self.observers.insert(key, value);
843 self.defer(move |_| activate());
844 subscription
845 }
846
847 pub(crate) fn observe_internal<W>(
848 &mut self,
849 entity: &Entity<W>,
850 mut on_notify: impl FnMut(Entity<W>, &mut App) -> bool + 'static,
851 ) -> Subscription
852 where
853 W: 'static,
854 {
855 let entity_id = entity.entity_id();
856 let handle = entity.downgrade();
857 self.new_observer(
858 entity_id,
859 Box::new(move |cx| {
860 if let Some(entity) = handle.upgrade() {
861 on_notify(entity, cx)
862 } else {
863 false
864 }
865 }),
866 )
867 }
868
869 pub fn subscribe<T, Event>(
872 &mut self,
873 entity: &Entity<T>,
874 mut on_event: impl FnMut(Entity<T>, &Event, &mut App) + 'static,
875 ) -> Subscription
876 where
877 T: 'static + EventEmitter<Event>,
878 Event: 'static,
879 {
880 self.subscribe_internal(entity, move |entity, event, cx| {
881 on_event(entity, event, cx);
882 true
883 })
884 }
885
886 pub(crate) fn new_subscription(
887 &mut self,
888 key: EntityId,
889 value: (TypeId, Listener),
890 ) -> Subscription {
891 let (subscription, activate) = self.event_listeners.insert(key, value);
892 self.defer(move |_| activate());
893 subscription
894 }
895 pub(crate) fn subscribe_internal<T, Evt>(
896 &mut self,
897 entity: &Entity<T>,
898 mut on_event: impl FnMut(Entity<T>, &Evt, &mut App) -> bool + 'static,
899 ) -> Subscription
900 where
901 T: 'static + EventEmitter<Evt>,
902 Evt: 'static,
903 {
904 let entity_id = entity.entity_id();
905 let handle = entity.downgrade();
906 self.new_subscription(
907 entity_id,
908 (
909 TypeId::of::<Evt>(),
910 Box::new(move |event, cx| {
911 let event: &Evt = event.downcast_ref().expect("invalid event type");
912 if let Some(entity) = handle.upgrade() {
913 on_event(entity, event, cx)
914 } else {
915 false
916 }
917 }),
918 ),
919 )
920 }
921
922 pub fn windows(&self) -> Vec<AnyWindowHandle> {
926 self.windows
927 .keys()
928 .flat_map(|window_id| self.window_handles.get(&window_id).copied())
929 .collect()
930 }
931
932 pub fn window_stack(&self) -> Option<Vec<AnyWindowHandle>> {
938 self.platform.window_stack()
939 }
940
941 pub fn active_window(&self) -> Option<AnyWindowHandle> {
943 self.platform.active_window()
944 }
945
946 pub fn open_window<V: 'static + Render>(
950 &mut self,
951 options: crate::WindowOptions,
952 build_root_view: impl FnOnce(&mut Window, &mut App) -> Entity<V>,
953 ) -> anyhow::Result<WindowHandle<V>> {
954 self.update(|cx| {
955 let id = cx.windows.insert(None);
956 let handle = WindowHandle::new(id);
957 match Window::new(handle.into(), options, cx) {
958 Ok(mut window) => {
959 cx.window_update_stack.push(id);
960 let root_view = build_root_view(&mut window, cx);
961 cx.window_update_stack.pop();
962 window.root.replace(root_view.into());
963 window.defer(cx, |window: &mut Window, cx| window.appearance_changed(cx));
964
965 let clear = window.draw(cx);
970 clear.clear();
971
972 cx.window_handles.insert(id, window.handle);
973 cx.windows.get_mut(id).unwrap().replace(window);
974 Ok(handle)
975 }
976 Err(e) => {
977 cx.windows.remove(id);
978 Err(e)
979 }
980 }
981 })
982 }
983
984 pub fn activate(&self, ignoring_other_apps: bool) {
986 self.platform.activate(ignoring_other_apps);
987 }
988
989 pub fn hide(&self) {
991 self.platform.hide();
992 }
993
994 pub fn hide_other_apps(&self) {
996 self.platform.hide_other_apps();
997 }
998
999 pub fn unhide_other_apps(&self) {
1001 self.platform.unhide_other_apps();
1002 }
1003
1004 pub fn set_tray_icon(&self, icon: Option<&[u8]>) {
1006 self.platform.set_tray_icon(icon);
1007 }
1008
1009 pub fn set_tray_menu(&self, menu: Vec<TrayMenuItem>) {
1011 self.platform.set_tray_menu(menu);
1012 }
1013
1014 pub fn set_tray_tooltip(&self, tooltip: &str) {
1016 self.platform.set_tray_tooltip(tooltip);
1017 }
1018
1019 pub fn set_tray_panel_mode(&self, enabled: bool) {
1022 self.platform.set_tray_panel_mode(enabled);
1023 }
1024
1025 pub fn tray_icon_bounds(&self) -> Option<Bounds<Pixels>> {
1027 self.platform.get_tray_icon_bounds()
1028 }
1029
1030 pub fn on_tray_icon_event(
1032 &self,
1033 mut callback: impl FnMut(TrayIconEvent, &mut App) + 'static,
1034 ) {
1035 let this = self.this.clone();
1036 self.platform.on_tray_icon_event(Box::new(move |event| {
1037 if let Some(app) = this.upgrade() {
1038 callback(event, &mut app.borrow_mut());
1039 }
1040 }));
1041 }
1042
1043 pub fn on_tray_menu_action(&self, mut callback: impl FnMut(SharedString, &mut App) + 'static) {
1045 let this = self.this.clone();
1046 self.platform.on_tray_menu_action(Box::new(move |id| {
1047 if let Some(app) = this.upgrade() {
1048 callback(id, &mut app.borrow_mut());
1049 }
1050 }));
1051 }
1052
1053 pub fn register_global_hotkey(&self, id: u32, keystroke: &Keystroke) -> Result<()> {
1055 self.platform.register_global_hotkey(id, keystroke)
1056 }
1057
1058 pub fn unregister_global_hotkey(&self, id: u32) {
1060 self.platform.unregister_global_hotkey(id);
1061 }
1062
1063 pub fn on_global_hotkey(&self, callback: impl FnMut(u32) + 'static) {
1065 self.platform.on_global_hotkey(Box::new(callback));
1066 }
1067
1068 pub fn focused_window_info(&self) -> Option<FocusedWindowInfo> {
1070 self.platform.focused_window_info()
1071 }
1072
1073 pub fn accessibility_status(&self) -> PermissionStatus {
1075 self.platform.accessibility_status()
1076 }
1077
1078 pub fn request_accessibility_permission(&self) {
1080 self.platform.request_accessibility_permission();
1081 }
1082
1083 pub fn microphone_status(&self) -> PermissionStatus {
1085 self.platform.microphone_status()
1086 }
1087
1088 pub fn request_microphone_permission(&self, callback: impl FnOnce(bool) + 'static) {
1090 self.platform
1091 .request_microphone_permission(Box::new(callback));
1092 }
1093
1094 pub fn set_auto_launch(&self, app_id: &str, enabled: bool) -> Result<()> {
1096 self.platform.set_auto_launch(app_id, enabled)
1097 }
1098
1099 pub fn is_auto_launch_enabled(&self, app_id: &str) -> bool {
1101 self.platform.is_auto_launch_enabled(app_id)
1102 }
1103
1104 pub fn show_notification(&self, title: &str, body: &str) -> Result<()> {
1106 self.platform.show_notification(title, body)
1107 }
1108
1109 pub fn set_keep_alive_without_windows(&self, keep_alive: bool) {
1111 self.platform.set_keep_alive_without_windows(keep_alive);
1112 }
1113
1114 pub fn on_system_power_event(
1116 &self,
1117 mut callback: impl FnMut(SystemPowerEvent, &mut App) + 'static,
1118 ) {
1119 let this = self.this.clone();
1120 self.platform
1121 .on_system_power_event(Box::new(move |event| {
1122 if let Some(app) = this.upgrade() {
1123 callback(event, &mut app.borrow_mut());
1124 }
1125 }));
1126 }
1127
1128 pub fn start_power_save_blocker(&self, kind: PowerSaveBlockerKind) -> Option<u32> {
1130 self.platform.start_power_save_blocker(kind)
1131 }
1132
1133 pub fn stop_power_save_blocker(&self, id: u32) {
1135 self.platform.stop_power_save_blocker(id);
1136 }
1137
1138 pub fn system_idle_time(&self) -> Option<Duration> {
1140 self.platform.system_idle_time()
1141 }
1142
1143 pub fn network_status(&self) -> NetworkStatus {
1145 self.platform.network_status()
1146 }
1147
1148 pub fn on_network_status_change(
1150 &self,
1151 mut callback: impl FnMut(NetworkStatus, &mut App) + 'static,
1152 ) {
1153 let this = self.this.clone();
1154 self.platform
1155 .on_network_status_change(Box::new(move |status| {
1156 if let Some(app) = this.upgrade() {
1157 callback(status, &mut app.borrow_mut());
1158 }
1159 }));
1160 }
1161
1162 pub fn on_media_key_event(
1164 &self,
1165 mut callback: impl FnMut(MediaKeyEvent, &mut App) + 'static,
1166 ) {
1167 let this = self.this.clone();
1168 self.platform
1169 .on_media_key_event(Box::new(move |event| {
1170 if let Some(app) = this.upgrade() {
1171 callback(event, &mut app.borrow_mut());
1172 }
1173 }));
1174 }
1175
1176 pub fn request_user_attention(&self, attention_type: AttentionType) {
1178 self.platform.request_user_attention(attention_type);
1179 }
1180
1181 pub fn cancel_user_attention(&self) {
1183 self.platform.cancel_user_attention();
1184 }
1185
1186 pub fn set_dock_badge(&self, label: Option<&str>) {
1188 self.platform.set_dock_badge(label);
1189 }
1190
1191 pub fn show_context_menu(
1193 &self,
1194 position: Point<Pixels>,
1195 items: Vec<TrayMenuItem>,
1196 mut callback: impl FnMut(SharedString, &mut App) + 'static,
1197 ) {
1198 let this = self.this.clone();
1199 self.platform.show_context_menu(
1200 position,
1201 items,
1202 Box::new(move |id| {
1203 if let Some(app) = this.upgrade() {
1204 callback(id, &mut app.borrow_mut());
1205 }
1206 }),
1207 );
1208 }
1209
1210 pub fn show_dialog(&self, options: DialogOptions) -> oneshot::Receiver<usize> {
1212 self.platform.show_dialog(options)
1213 }
1214
1215 pub fn os_info(&self) -> OsInfo {
1217 self.platform.os_info()
1218 }
1219
1220 pub fn biometric_status(&self) -> BiometricStatus {
1222 self.platform.biometric_status()
1223 }
1224
1225 pub fn authenticate_biometric(
1227 &self,
1228 reason: &str,
1229 callback: impl FnOnce(bool) + Send + 'static,
1230 ) {
1231 self.platform
1232 .authenticate_biometric(reason, Box::new(callback));
1233 }
1234
1235 pub fn set_crash_handler(
1237 &self,
1238 app_version: Option<String>,
1239 handler: impl Fn(CrashReport) + Send + Sync + 'static,
1240 ) {
1241 let os_info = self.platform.os_info();
1242 let handler = std::sync::Arc::new(handler);
1243 std::panic::set_hook(Box::new(move |panic_info| {
1244 let message = if let Some(msg) = panic_info.payload().downcast_ref::<&str>() {
1245 msg.to_string()
1246 } else if let Some(msg) = panic_info.payload().downcast_ref::<String>() {
1247 msg.clone()
1248 } else {
1249 "Unknown panic".to_string()
1250 };
1251
1252 let location = panic_info
1253 .location()
1254 .map(|loc| format!("{}:{}:{}", loc.file(), loc.line(), loc.column()))
1255 .unwrap_or_default();
1256
1257 let full_message = if location.is_empty() {
1258 message
1259 } else {
1260 format!("{message} at {location}")
1261 };
1262
1263 let backtrace = std::backtrace::Backtrace::force_capture().to_string();
1264
1265 let report = CrashReport {
1266 message: full_message,
1267 backtrace,
1268 os_info: os_info.clone(),
1269 app_version: app_version.clone(),
1270 };
1271
1272 handler(report);
1273 }));
1274 }
1275
1276 pub fn displays(&self) -> Vec<Rc<dyn PlatformDisplay>> {
1278 self.platform.displays()
1279 }
1280
1281 pub fn primary_display(&self) -> Option<Rc<dyn PlatformDisplay>> {
1283 self.platform.primary_display()
1284 }
1285
1286 pub fn compute_window_bounds(
1288 &self,
1289 size: Size<Pixels>,
1290 position: &WindowPosition,
1291 ) -> Bounds<Pixels> {
1292 let displays = self.platform.displays();
1293 let primary = self.platform.primary_display();
1294 crate::platform::window_positioner::compute_window_bounds(
1295 size,
1296 position,
1297 &displays,
1298 primary.as_ref(),
1299 )
1300 }
1301
1302 pub fn is_screen_capture_supported(&self) -> bool {
1304 self.platform.is_screen_capture_supported()
1305 }
1306
1307 pub fn screen_capture_sources(
1309 &self,
1310 ) -> oneshot::Receiver<Result<Vec<Rc<dyn ScreenCaptureSource>>>> {
1311 self.platform.screen_capture_sources()
1312 }
1313
1314 pub fn find_display(&self, id: DisplayId) -> Option<Rc<dyn PlatformDisplay>> {
1316 self.displays()
1317 .iter()
1318 .find(|display| display.id() == id)
1319 .cloned()
1320 }
1321
1322 pub fn window_appearance(&self) -> WindowAppearance {
1324 self.platform.window_appearance()
1325 }
1326
1327 #[cfg(any(target_os = "linux", target_os = "freebsd"))]
1330 pub fn write_to_primary(&self, item: ClipboardItem) {
1331 self.platform.write_to_primary(item)
1332 }
1333
1334 pub fn write_to_clipboard(&self, item: ClipboardItem) {
1336 self.platform.write_to_clipboard(item)
1337 }
1338
1339 #[cfg(any(target_os = "linux", target_os = "freebsd"))]
1342 pub fn read_from_primary(&self) -> Option<ClipboardItem> {
1343 self.platform.read_from_primary()
1344 }
1345
1346 pub fn read_from_clipboard(&self) -> Option<ClipboardItem> {
1348 self.platform.read_from_clipboard()
1349 }
1350
1351 pub fn write_credentials(
1353 &self,
1354 url: &str,
1355 username: &str,
1356 password: &[u8],
1357 ) -> Task<Result<()>> {
1358 self.platform.write_credentials(url, username, password)
1359 }
1360
1361 pub fn read_credentials(&self, url: &str) -> Task<Result<Option<(String, Vec<u8>)>>> {
1363 self.platform.read_credentials(url)
1364 }
1365
1366 pub fn delete_credentials(&self, url: &str) -> Task<Result<()>> {
1368 self.platform.delete_credentials(url)
1369 }
1370
1371 pub fn open_url(&self, url: &str) {
1373 self.platform.open_url(url);
1374 }
1375
1376 pub fn register_url_scheme(&self, scheme: &str) -> Task<Result<()>> {
1383 self.platform.register_url_scheme(scheme)
1384 }
1385
1386 pub fn app_path(&self) -> Result<PathBuf> {
1390 self.platform.app_path()
1391 }
1392
1393 pub fn compositor_name(&self) -> &'static str {
1397 self.platform.compositor_name()
1398 }
1399
1400 pub fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf> {
1402 self.platform.path_for_auxiliary_executable(name)
1403 }
1404
1405 pub fn prompt_for_paths(
1411 &self,
1412 options: PathPromptOptions,
1413 ) -> oneshot::Receiver<Result<Option<Vec<PathBuf>>>> {
1414 self.platform.prompt_for_paths(options)
1415 }
1416
1417 pub fn prompt_for_new_path(
1424 &self,
1425 directory: &Path,
1426 suggested_name: Option<&str>,
1427 ) -> oneshot::Receiver<Result<Option<PathBuf>>> {
1428 self.platform.prompt_for_new_path(directory, suggested_name)
1429 }
1430
1431 pub fn reveal_path(&self, path: &Path) {
1433 self.platform.reveal_path(path)
1434 }
1435
1436 pub fn open_with_system(&self, path: &Path) {
1438 self.platform.open_with_system(path)
1439 }
1440
1441 pub fn should_auto_hide_scrollbars(&self) -> bool {
1443 self.platform.should_auto_hide_scrollbars()
1444 }
1445
1446 pub fn restart(&mut self) {
1448 self.restart_observers
1449 .clone()
1450 .retain(&(), |observer| observer(self));
1451 self.platform.restart(self.restart_path.take())
1452 }
1453
1454 pub fn set_restart_path(&mut self, path: PathBuf) {
1456 self.restart_path = Some(path);
1457 }
1458
1459 pub fn http_client(&self) -> Arc<dyn HttpClient> {
1461 self.http_client.clone()
1462 }
1463
1464 pub fn set_http_client(&mut self, new_client: Arc<dyn HttpClient>) {
1466 self.http_client = new_client;
1467 }
1468
1469 pub fn svg_renderer(&self) -> SvgRenderer {
1471 self.svg_renderer.clone()
1472 }
1473
1474 pub(crate) fn push_effect(&mut self, effect: Effect) {
1475 match &effect {
1476 Effect::Notify { emitter } => {
1477 if !self.pending_notifications.insert(*emitter) {
1478 return;
1479 }
1480 }
1481 Effect::NotifyGlobalObservers { global_type } => {
1482 if !self.pending_global_notifications.insert(*global_type) {
1483 return;
1484 }
1485 }
1486 _ => {}
1487 };
1488
1489 self.pending_effects.push_back(effect);
1490 }
1491
1492 fn flush_effects(&mut self) {
1496 loop {
1497 self.release_dropped_entities();
1498 self.release_dropped_focus_handles();
1499 if let Some(effect) = self.pending_effects.pop_front() {
1500 match effect {
1501 Effect::Notify { emitter } => {
1502 self.apply_notify_effect(emitter);
1503 }
1504
1505 Effect::Emit {
1506 emitter,
1507 event_type,
1508 event,
1509 } => self.apply_emit_effect(emitter, event_type, event),
1510
1511 Effect::RefreshWindows => {
1512 self.apply_refresh_effect();
1513 }
1514
1515 Effect::NotifyGlobalObservers { global_type } => {
1516 self.apply_notify_global_observers_effect(global_type);
1517 }
1518
1519 Effect::Defer { callback } => {
1520 self.apply_defer_effect(callback);
1521 }
1522 Effect::EntityCreated {
1523 entity,
1524 tid,
1525 window,
1526 } => {
1527 self.apply_entity_created_effect(entity, tid, window);
1528 }
1529 }
1530 } else {
1531 #[cfg(any(test, feature = "test-support"))]
1532 for window in self
1533 .windows
1534 .values()
1535 .filter_map(|window| {
1536 let window = window.as_ref()?;
1537 window.invalidator.is_dirty().then_some(window.handle)
1538 })
1539 .collect::<Vec<_>>()
1540 {
1541 self.update_window(window, |_, window, cx| window.draw(cx).clear())
1542 .unwrap();
1543 }
1544
1545 if self.pending_effects.is_empty() {
1546 break;
1547 }
1548 }
1549 }
1550 }
1551
1552 fn release_dropped_entities(&mut self) {
1556 loop {
1557 let dropped = self.entities.take_dropped();
1558 if dropped.is_empty() {
1559 break;
1560 }
1561
1562 for (entity_id, mut entity) in dropped {
1563 self.observers.remove(&entity_id);
1564 self.event_listeners.remove(&entity_id);
1565 for release_callback in self.release_listeners.remove(&entity_id) {
1566 release_callback(entity.as_mut(), self);
1567 }
1568 }
1569 }
1570 }
1571
1572 fn release_dropped_focus_handles(&mut self) {
1574 self.focus_handles
1575 .clone()
1576 .write()
1577 .retain(|handle_id, focus| {
1578 if focus.ref_count.load(SeqCst) == 0 {
1579 for window_handle in self.windows() {
1580 window_handle
1581 .update(self, |_, window, _| {
1582 if window.focus == Some(handle_id) {
1583 window.blur();
1584 }
1585 })
1586 .unwrap();
1587 }
1588 false
1589 } else {
1590 true
1591 }
1592 });
1593 }
1594
1595 fn apply_notify_effect(&mut self, emitter: EntityId) {
1596 self.pending_notifications.remove(&emitter);
1597
1598 self.observers
1599 .clone()
1600 .retain(&emitter, |handler| handler(self));
1601 }
1602
1603 fn apply_emit_effect(&mut self, emitter: EntityId, event_type: TypeId, event: Box<dyn Any>) {
1604 self.event_listeners
1605 .clone()
1606 .retain(&emitter, |(stored_type, handler)| {
1607 if *stored_type == event_type {
1608 handler(event.as_ref(), self)
1609 } else {
1610 true
1611 }
1612 });
1613 }
1614
1615 fn apply_refresh_effect(&mut self) {
1616 for window in self.windows.values_mut() {
1617 if let Some(window) = window.as_mut() {
1618 window.refreshing = true;
1619 window.invalidator.set_dirty(true);
1620 }
1621 }
1622 }
1623
1624 fn apply_notify_global_observers_effect(&mut self, type_id: TypeId) {
1625 self.pending_global_notifications.remove(&type_id);
1626 self.global_observers
1627 .clone()
1628 .retain(&type_id, |observer| observer(self));
1629 }
1630
1631 fn apply_defer_effect(&mut self, callback: Box<dyn FnOnce(&mut Self) + 'static>) {
1632 callback(self);
1633 }
1634
1635 fn apply_entity_created_effect(
1636 &mut self,
1637 entity: AnyEntity,
1638 tid: TypeId,
1639 window: Option<WindowId>,
1640 ) {
1641 self.new_entity_observers.clone().retain(&tid, |observer| {
1642 if let Some(id) = window {
1643 self.update_window_id(id, {
1644 let entity = entity.clone();
1645 |_, window, cx| (observer)(entity, &mut Some(window), cx)
1646 })
1647 .expect("All windows should be off the stack when flushing effects");
1648 } else {
1649 (observer)(entity.clone(), &mut None, self)
1650 }
1651 true
1652 });
1653 }
1654
1655 fn update_window_id<T, F>(&mut self, id: WindowId, update: F) -> Result<T>
1656 where
1657 F: FnOnce(AnyView, &mut Window, &mut App) -> T,
1658 {
1659 self.update(|cx| {
1660 let mut window = cx.windows.get_mut(id)?.take()?;
1661
1662 let root_view = window.root.clone().unwrap();
1663
1664 cx.window_update_stack.push(window.handle.id);
1665 let result = update(root_view, &mut window, cx);
1666 cx.window_update_stack.pop();
1667
1668 if window.removed {
1669 cx.window_handles.remove(&id);
1670 cx.windows.remove(id);
1671
1672 cx.window_closed_observers.clone().retain(&(), |callback| {
1673 callback(cx);
1674 true
1675 });
1676 } else {
1677 cx.windows.get_mut(id)?.replace(window);
1678 }
1679
1680 Some(result)
1681 })
1682 .context("window not found")
1683 }
1684
1685 pub fn to_async(&self) -> AsyncApp {
1688 AsyncApp {
1689 app: self.this.clone(),
1690 background_executor: self.background_executor.clone(),
1691 foreground_executor: self.foreground_executor.clone(),
1692 }
1693 }
1694
1695 pub fn background_executor(&self) -> &BackgroundExecutor {
1697 &self.background_executor
1698 }
1699
1700 pub fn foreground_executor(&self) -> &ForegroundExecutor {
1702 if self.quitting {
1703 panic!("Can't spawn on main thread after on_app_quit")
1704 };
1705 &self.foreground_executor
1706 }
1707
1708 #[track_caller]
1711 pub fn spawn<AsyncFn, R>(&self, f: AsyncFn) -> Task<R>
1712 where
1713 AsyncFn: AsyncFnOnce(&mut AsyncApp) -> R + 'static,
1714 R: 'static,
1715 {
1716 if self.quitting {
1717 debug_panic!("Can't spawn on main thread after on_app_quit")
1718 };
1719
1720 let mut cx = self.to_async();
1721
1722 self.foreground_executor
1723 .spawn(async move { f(&mut cx).await })
1724 }
1725
1726 pub fn defer(&mut self, f: impl FnOnce(&mut App) + 'static) {
1729 self.push_effect(Effect::Defer {
1730 callback: Box::new(f),
1731 });
1732 }
1733
1734 pub fn asset_source(&self) -> &Arc<dyn AssetSource> {
1736 &self.asset_source
1737 }
1738
1739 pub fn text_system(&self) -> &Arc<TextSystem> {
1741 &self.text_system
1742 }
1743
1744 pub fn has_global<G: Global>(&self) -> bool {
1746 self.globals_by_type.contains_key(&TypeId::of::<G>())
1747 }
1748
1749 #[track_caller]
1751 pub fn global<G: Global>(&self) -> &G {
1752 self.globals_by_type
1753 .get(&TypeId::of::<G>())
1754 .map(|any_state| any_state.downcast_ref::<G>().unwrap())
1755 .with_context(|| format!("no state of type {} exists", type_name::<G>()))
1756 .unwrap()
1757 }
1758
1759 pub fn try_global<G: Global>(&self) -> Option<&G> {
1761 self.globals_by_type
1762 .get(&TypeId::of::<G>())
1763 .map(|any_state| any_state.downcast_ref::<G>().unwrap())
1764 }
1765
1766 #[track_caller]
1768 pub fn global_mut<G: Global>(&mut self) -> &mut G {
1769 let global_type = TypeId::of::<G>();
1770 self.push_effect(Effect::NotifyGlobalObservers { global_type });
1771 self.globals_by_type
1772 .get_mut(&global_type)
1773 .and_then(|any_state| any_state.downcast_mut::<G>())
1774 .with_context(|| format!("no state of type {} exists", type_name::<G>()))
1775 .unwrap()
1776 }
1777
1778 pub fn default_global<G: Global + Default>(&mut self) -> &mut G {
1781 let global_type = TypeId::of::<G>();
1782 self.push_effect(Effect::NotifyGlobalObservers { global_type });
1783 self.globals_by_type
1784 .entry(global_type)
1785 .or_insert_with(|| Box::<G>::default())
1786 .downcast_mut::<G>()
1787 .unwrap()
1788 }
1789
1790 pub fn set_global<G: Global>(&mut self, global: G) {
1792 let global_type = TypeId::of::<G>();
1793 self.push_effect(Effect::NotifyGlobalObservers { global_type });
1794 self.globals_by_type.insert(global_type, Box::new(global));
1795 }
1796
1797 #[cfg(any(test, feature = "test-support"))]
1799 pub fn clear_globals(&mut self) {
1800 self.globals_by_type.drain();
1801 }
1802
1803 pub fn remove_global<G: Global>(&mut self) -> G {
1805 let global_type = TypeId::of::<G>();
1806 self.push_effect(Effect::NotifyGlobalObservers { global_type });
1807 *self
1808 .globals_by_type
1809 .remove(&global_type)
1810 .unwrap_or_else(|| panic!("no global added for {}", std::any::type_name::<G>()))
1811 .downcast()
1812 .unwrap()
1813 }
1814
1815 pub fn observe_global<G: Global>(
1817 &mut self,
1818 mut f: impl FnMut(&mut Self) + 'static,
1819 ) -> Subscription {
1820 let (subscription, activate) = self.global_observers.insert(
1821 TypeId::of::<G>(),
1822 Box::new(move |cx| {
1823 f(cx);
1824 true
1825 }),
1826 );
1827 self.defer(move |_| activate());
1828 subscription
1829 }
1830
1831 #[track_caller]
1833 pub(crate) fn lease_global<G: Global>(&mut self) -> GlobalLease<G> {
1834 GlobalLease::new(
1835 self.globals_by_type
1836 .remove(&TypeId::of::<G>())
1837 .with_context(|| format!("no global registered of type {}", type_name::<G>()))
1838 .unwrap(),
1839 )
1840 }
1841
1842 pub(crate) fn end_global_lease<G: Global>(&mut self, lease: GlobalLease<G>) {
1844 let global_type = TypeId::of::<G>();
1845
1846 self.push_effect(Effect::NotifyGlobalObservers { global_type });
1847 self.globals_by_type.insert(global_type, lease.global);
1848 }
1849
1850 pub(crate) fn new_entity_observer(
1851 &self,
1852 key: TypeId,
1853 value: NewEntityListener,
1854 ) -> Subscription {
1855 let (subscription, activate) = self.new_entity_observers.insert(key, value);
1856 activate();
1857 subscription
1858 }
1859
1860 pub fn observe_new<T: 'static>(
1863 &self,
1864 on_new: impl 'static + Fn(&mut T, Option<&mut Window>, &mut Context<T>),
1865 ) -> Subscription {
1866 self.new_entity_observer(
1867 TypeId::of::<T>(),
1868 Box::new(
1869 move |any_entity: AnyEntity, window: &mut Option<&mut Window>, cx: &mut App| {
1870 any_entity
1871 .downcast::<T>()
1872 .unwrap()
1873 .update(cx, |entity_state, cx| {
1874 on_new(entity_state, window.as_deref_mut(), cx)
1875 })
1876 },
1877 ),
1878 )
1879 }
1880
1881 pub fn observe_release<T>(
1884 &self,
1885 handle: &Entity<T>,
1886 on_release: impl FnOnce(&mut T, &mut App) + 'static,
1887 ) -> Subscription
1888 where
1889 T: 'static,
1890 {
1891 let (subscription, activate) = self.release_listeners.insert(
1892 handle.entity_id(),
1893 Box::new(move |entity, cx| {
1894 let entity = entity.downcast_mut().expect("invalid entity type");
1895 on_release(entity, cx)
1896 }),
1897 );
1898 activate();
1899 subscription
1900 }
1901
1902 pub fn observe_release_in<T>(
1905 &self,
1906 handle: &Entity<T>,
1907 window: &Window,
1908 on_release: impl FnOnce(&mut T, &mut Window, &mut App) + 'static,
1909 ) -> Subscription
1910 where
1911 T: 'static,
1912 {
1913 let window_handle = window.handle;
1914 self.observe_release(handle, move |entity, cx| {
1915 let _ = window_handle.update(cx, |_, window, cx| on_release(entity, window, cx));
1916 })
1917 }
1918
1919 pub fn observe_keystrokes(
1923 &mut self,
1924 mut f: impl FnMut(&KeystrokeEvent, &mut Window, &mut App) + 'static,
1925 ) -> Subscription {
1926 fn inner(
1927 keystroke_observers: &SubscriberSet<(), KeystrokeObserver>,
1928 handler: KeystrokeObserver,
1929 ) -> Subscription {
1930 let (subscription, activate) = keystroke_observers.insert((), handler);
1931 activate();
1932 subscription
1933 }
1934
1935 inner(
1936 &self.keystroke_observers,
1937 Box::new(move |event, window, cx| {
1938 f(event, window, cx);
1939 true
1940 }),
1941 )
1942 }
1943
1944 pub fn intercept_keystrokes(
1949 &mut self,
1950 mut f: impl FnMut(&KeystrokeEvent, &mut Window, &mut App) + 'static,
1951 ) -> Subscription {
1952 fn inner(
1953 keystroke_interceptors: &SubscriberSet<(), KeystrokeObserver>,
1954 handler: KeystrokeObserver,
1955 ) -> Subscription {
1956 let (subscription, activate) = keystroke_interceptors.insert((), handler);
1957 activate();
1958 subscription
1959 }
1960
1961 inner(
1962 &self.keystroke_interceptors,
1963 Box::new(move |event, window, cx| {
1964 f(event, window, cx);
1965 true
1966 }),
1967 )
1968 }
1969
1970 pub fn bind_keys(&mut self, bindings: impl IntoIterator<Item = KeyBinding>) {
1972 self.keymap.borrow_mut().add_bindings(bindings);
1973 self.pending_effects.push_back(Effect::RefreshWindows);
1974 }
1975
1976 pub fn clear_key_bindings(&mut self) {
1978 self.keymap.borrow_mut().clear();
1979 self.pending_effects.push_back(Effect::RefreshWindows);
1980 }
1981
1982 pub fn key_bindings(&self) -> Rc<RefCell<Keymap>> {
1984 self.keymap.clone()
1985 }
1986
1987 pub fn on_action<A: Action>(&mut self, listener: impl Fn(&A, &mut Self) + 'static) {
1991 self.global_action_listeners
1992 .entry(TypeId::of::<A>())
1993 .or_default()
1994 .push(Rc::new(move |action, phase, cx| {
1995 if phase == DispatchPhase::Bubble {
1996 let action = action.downcast_ref().unwrap();
1997 listener(action, cx)
1998 }
1999 }));
2000 }
2001
2002 pub fn stop_propagation(&mut self) {
2007 self.propagate_event = false;
2008 }
2009
2010 pub fn propagate(&mut self) {
2015 self.propagate_event = true;
2016 }
2017
2018 pub fn build_action(
2020 &self,
2021 name: &str,
2022 data: Option<serde_json::Value>,
2023 ) -> std::result::Result<Box<dyn Action>, ActionBuildError> {
2024 self.actions.build_action(name, data)
2025 }
2026
2027 pub fn all_action_names(&self) -> &[&'static str] {
2030 self.actions.all_action_names()
2031 }
2032
2033 pub fn all_bindings_for_input(&self, input: &[Keystroke]) -> Vec<KeyBinding> {
2037 RefCell::borrow(&self.keymap).all_bindings_for_input(input)
2038 }
2039
2040 pub fn action_schemas(
2042 &self,
2043 generator: &mut schemars::SchemaGenerator,
2044 ) -> Vec<(&'static str, Option<schemars::Schema>)> {
2045 self.actions.action_schemas(generator)
2046 }
2047
2048 pub fn deprecated_actions_to_preferred_actions(&self) -> &HashMap<&'static str, &'static str> {
2050 self.actions.deprecated_aliases()
2051 }
2052
2053 pub fn action_deprecation_messages(&self) -> &HashMap<&'static str, &'static str> {
2055 self.actions.deprecation_messages()
2056 }
2057
2058 pub fn action_documentation(&self) -> &HashMap<&'static str, &'static str> {
2060 self.actions.documentation()
2061 }
2062
2063 pub fn on_app_quit<Fut>(
2066 &self,
2067 mut on_quit: impl FnMut(&mut App) -> Fut + 'static,
2068 ) -> Subscription
2069 where
2070 Fut: 'static + Future<Output = ()>,
2071 {
2072 let (subscription, activate) = self.quit_observers.insert(
2073 (),
2074 Box::new(move |cx| {
2075 let future = on_quit(cx);
2076 future.boxed_local()
2077 }),
2078 );
2079 activate();
2080 subscription
2081 }
2082
2083 pub fn on_app_restart(&self, mut on_restart: impl 'static + FnMut(&mut App)) -> Subscription {
2087 let (subscription, activate) = self.restart_observers.insert(
2088 (),
2089 Box::new(move |cx| {
2090 on_restart(cx);
2091 true
2092 }),
2093 );
2094 activate();
2095 subscription
2096 }
2097
2098 pub fn on_window_closed(&self, mut on_closed: impl FnMut(&mut App) + 'static) -> Subscription {
2101 let (subscription, activate) = self.window_closed_observers.insert((), Box::new(on_closed));
2102 activate();
2103 subscription
2104 }
2105
2106 pub(crate) fn clear_pending_keystrokes(&mut self) {
2107 for window in self.windows() {
2108 window
2109 .update(self, |_, window, _| {
2110 window.clear_pending_keystrokes();
2111 })
2112 .ok();
2113 }
2114 }
2115
2116 pub fn is_action_available(&mut self, action: &dyn Action) -> bool {
2119 let mut action_available = false;
2120 if let Some(window) = self.active_window()
2121 && let Ok(window_action_available) =
2122 window.update(self, |_, window, cx| window.is_action_available(action, cx))
2123 {
2124 action_available = window_action_available;
2125 }
2126
2127 action_available
2128 || self
2129 .global_action_listeners
2130 .contains_key(&action.as_any().type_id())
2131 }
2132
2133 pub fn set_menus(&self, menus: Vec<Menu>) {
2135 self.platform.set_menus(menus, &self.keymap.borrow());
2136 }
2137
2138 pub fn get_menus(&self) -> Option<Vec<OwnedMenu>> {
2140 self.platform.get_menus()
2141 }
2142
2143 pub fn set_dock_menu(&self, menus: Vec<MenuItem>) {
2145 self.platform.set_dock_menu(menus, &self.keymap.borrow())
2146 }
2147
2148 pub fn perform_dock_menu_action(&self, action: usize) {
2150 self.platform.perform_dock_menu_action(action);
2151 }
2152
2153 pub fn add_recent_document(&self, path: &Path) {
2158 self.platform.add_recent_document(path);
2159 }
2160
2161 pub fn update_jump_list(
2164 &self,
2165 menus: Vec<MenuItem>,
2166 entries: Vec<SmallVec<[PathBuf; 2]>>,
2167 ) -> Vec<SmallVec<[PathBuf; 2]>> {
2168 self.platform.update_jump_list(menus, entries)
2169 }
2170
2171 pub fn dispatch_action(&mut self, action: &dyn Action) {
2174 if let Some(active_window) = self.active_window() {
2175 active_window
2176 .update(self, |_, window, cx| {
2177 window.dispatch_action(action.boxed_clone(), cx)
2178 })
2179 .log_err();
2180 } else {
2181 self.dispatch_global_action(action);
2182 }
2183 }
2184
2185 fn dispatch_global_action(&mut self, action: &dyn Action) {
2186 self.propagate_event = true;
2187
2188 if let Some(mut global_listeners) = self
2189 .global_action_listeners
2190 .remove(&action.as_any().type_id())
2191 {
2192 for listener in &global_listeners {
2193 listener(action.as_any(), DispatchPhase::Capture, self);
2194 if !self.propagate_event {
2195 break;
2196 }
2197 }
2198
2199 global_listeners.extend(
2200 self.global_action_listeners
2201 .remove(&action.as_any().type_id())
2202 .unwrap_or_default(),
2203 );
2204
2205 self.global_action_listeners
2206 .insert(action.as_any().type_id(), global_listeners);
2207 }
2208
2209 if self.propagate_event
2210 && let Some(mut global_listeners) = self
2211 .global_action_listeners
2212 .remove(&action.as_any().type_id())
2213 {
2214 for listener in global_listeners.iter().rev() {
2215 listener(action.as_any(), DispatchPhase::Bubble, self);
2216 if !self.propagate_event {
2217 break;
2218 }
2219 }
2220
2221 global_listeners.extend(
2222 self.global_action_listeners
2223 .remove(&action.as_any().type_id())
2224 .unwrap_or_default(),
2225 );
2226
2227 self.global_action_listeners
2228 .insert(action.as_any().type_id(), global_listeners);
2229 }
2230 }
2231
2232 pub fn has_active_drag(&self) -> bool {
2234 self.active_drag.is_some()
2235 }
2236
2237 pub fn active_drag_cursor_style(&self) -> Option<CursorStyle> {
2239 self.active_drag.as_ref().and_then(|drag| drag.cursor_style)
2240 }
2241
2242 pub fn stop_active_drag(&mut self, window: &mut Window) -> bool {
2244 if self.active_drag.is_some() {
2245 self.active_drag = None;
2246 window.refresh();
2247 true
2248 } else {
2249 false
2250 }
2251 }
2252
2253 pub fn set_active_drag_cursor_style(
2255 &mut self,
2256 cursor_style: CursorStyle,
2257 window: &mut Window,
2258 ) -> bool {
2259 if let Some(ref mut drag) = self.active_drag {
2260 drag.cursor_style = Some(cursor_style);
2261 window.refresh();
2262 true
2263 } else {
2264 false
2265 }
2266 }
2267
2268 pub fn set_prompt_builder(
2271 &mut self,
2272 renderer: impl Fn(
2273 PromptLevel,
2274 &str,
2275 Option<&str>,
2276 &[PromptButton],
2277 PromptHandle,
2278 &mut Window,
2279 &mut App,
2280 ) -> RenderablePromptHandle
2281 + 'static,
2282 ) {
2283 self.prompt_builder = Some(PromptBuilder::Custom(Box::new(renderer)));
2284 }
2285
2286 pub fn reset_prompt_builder(&mut self) {
2288 self.prompt_builder = Some(PromptBuilder::Default);
2289 }
2290
2291 pub fn remove_asset<A: Asset>(&mut self, source: &A::Source) {
2293 let asset_id = (TypeId::of::<A>(), hash(source));
2294 self.loading_assets.remove(&asset_id);
2295 }
2296
2297 pub fn fetch_asset<A: Asset>(&mut self, source: &A::Source) -> (Shared<Task<A::Output>>, bool) {
2302 let asset_id = (TypeId::of::<A>(), hash(source));
2303 let mut is_first = false;
2304 let task = self
2305 .loading_assets
2306 .remove(&asset_id)
2307 .map(|boxed_task| *boxed_task.downcast::<Shared<Task<A::Output>>>().unwrap())
2308 .unwrap_or_else(|| {
2309 is_first = true;
2310 let future = A::load(source.clone(), self);
2311
2312 self.background_executor().spawn(future).shared()
2313 });
2314
2315 self.loading_assets.insert(asset_id, Box::new(task.clone()));
2316
2317 (task, is_first)
2318 }
2319
2320 #[track_caller]
2323 pub fn focus_handle(&self) -> FocusHandle {
2324 FocusHandle::new(&self.focus_handles)
2325 }
2326
2327 pub fn notify(&mut self, entity_id: EntityId) {
2329 let window_invalidators = mem::take(
2330 self.window_invalidators_by_entity
2331 .entry(entity_id)
2332 .or_default(),
2333 );
2334
2335 if window_invalidators.is_empty() {
2336 if self.pending_notifications.insert(entity_id) {
2337 self.pending_effects
2338 .push_back(Effect::Notify { emitter: entity_id });
2339 }
2340 } else {
2341 for invalidator in window_invalidators.values() {
2342 invalidator.invalidate_view(entity_id, self);
2343 }
2344 }
2345
2346 self.window_invalidators_by_entity
2347 .insert(entity_id, window_invalidators);
2348 }
2349
2350 #[cfg(any(test, feature = "test-support", debug_assertions))]
2352 pub fn get_name(&self) -> Option<&'static str> {
2353 self.name
2354 }
2355
2356 pub fn can_select_mixed_files_and_dirs(&self) -> bool {
2358 self.platform.can_select_mixed_files_and_dirs()
2359 }
2360
2361 pub fn drop_image(&mut self, image: Arc<RenderImage>, current_window: Option<&mut Window>) {
2366 for window in self.windows.values_mut().flatten() {
2368 _ = window.drop_image(image.clone());
2369 }
2370
2371 if let Some(window) = current_window {
2373 _ = window.drop_image(image);
2374 }
2375 }
2376
2377 #[cfg(any(feature = "inspector", debug_assertions))]
2379 pub fn set_inspector_renderer(&mut self, f: crate::InspectorRenderer) {
2380 self.inspector_renderer = Some(f);
2381 }
2382
2383 #[cfg(any(feature = "inspector", debug_assertions))]
2385 pub fn register_inspector_element<T: 'static, R: crate::IntoElement>(
2386 &mut self,
2387 f: impl 'static + Fn(crate::InspectorElementId, &T, &mut Window, &mut App) -> R,
2388 ) {
2389 self.inspector_element_registry.register(f);
2390 }
2391
2392 pub fn init_colors(&mut self) {
2396 self.set_global(GlobalColors(Arc::new(Colors::default())));
2397 }
2398}
2399
2400impl AppContext for App {
2401 type Result<T> = T;
2402
2403 fn new<T: 'static>(&mut self, build_entity: impl FnOnce(&mut Context<T>) -> T) -> Entity<T> {
2408 self.update(|cx| {
2409 let slot = cx.entities.reserve();
2410 let handle = slot.clone();
2411 let entity = build_entity(&mut Context::new_context(cx, slot.downgrade()));
2412
2413 cx.push_effect(Effect::EntityCreated {
2414 entity: handle.clone().into_any(),
2415 tid: TypeId::of::<T>(),
2416 window: cx.window_update_stack.last().cloned(),
2417 });
2418
2419 cx.entities.insert(slot, entity);
2420 handle
2421 })
2422 }
2423
2424 fn reserve_entity<T: 'static>(&mut self) -> Self::Result<Reservation<T>> {
2425 Reservation(self.entities.reserve())
2426 }
2427
2428 fn insert_entity<T: 'static>(
2429 &mut self,
2430 reservation: Reservation<T>,
2431 build_entity: impl FnOnce(&mut Context<T>) -> T,
2432 ) -> Self::Result<Entity<T>> {
2433 self.update(|cx| {
2434 let slot = reservation.0;
2435 let entity = build_entity(&mut Context::new_context(cx, slot.downgrade()));
2436 cx.entities.insert(slot, entity)
2437 })
2438 }
2439
2440 fn update_entity<T: 'static, R>(
2443 &mut self,
2444 handle: &Entity<T>,
2445 update: impl FnOnce(&mut T, &mut Context<T>) -> R,
2446 ) -> R {
2447 self.update(|cx| {
2448 let mut entity = cx.entities.lease(handle);
2449 let result = update(
2450 &mut entity,
2451 &mut Context::new_context(cx, handle.downgrade()),
2452 );
2453 cx.entities.end_lease(entity);
2454 result
2455 })
2456 }
2457
2458 fn as_mut<'a, T>(&'a mut self, handle: &Entity<T>) -> GpuiBorrow<'a, T>
2459 where
2460 T: 'static,
2461 {
2462 GpuiBorrow::new(handle.clone(), self)
2463 }
2464
2465 fn read_entity<T, R>(
2466 &self,
2467 handle: &Entity<T>,
2468 read: impl FnOnce(&T, &App) -> R,
2469 ) -> Self::Result<R>
2470 where
2471 T: 'static,
2472 {
2473 let entity = self.entities.read(handle);
2474 read(entity, self)
2475 }
2476
2477 fn update_window<T, F>(&mut self, handle: AnyWindowHandle, update: F) -> Result<T>
2478 where
2479 F: FnOnce(AnyView, &mut Window, &mut App) -> T,
2480 {
2481 self.update_window_id(handle.id, update)
2482 }
2483
2484 fn read_window<T, R>(
2485 &self,
2486 window: &WindowHandle<T>,
2487 read: impl FnOnce(Entity<T>, &App) -> R,
2488 ) -> Result<R>
2489 where
2490 T: 'static,
2491 {
2492 let window = self
2493 .windows
2494 .get(window.id)
2495 .context("window not found")?
2496 .as_ref()
2497 .expect("attempted to read a window that is already on the stack");
2498
2499 let root_view = window.root.clone().unwrap();
2500 let view = root_view
2501 .downcast::<T>()
2502 .map_err(|_| anyhow!("root view's type has changed"))?;
2503
2504 Ok(read(view, self))
2505 }
2506
2507 fn background_spawn<R>(&self, future: impl Future<Output = R> + Send + 'static) -> Task<R>
2508 where
2509 R: Send + 'static,
2510 {
2511 self.background_executor.spawn(future)
2512 }
2513
2514 fn read_global<G, R>(&self, callback: impl FnOnce(&G, &App) -> R) -> Self::Result<R>
2515 where
2516 G: Global,
2517 {
2518 let mut g = self.global::<G>();
2519 callback(g, self)
2520 }
2521}
2522
2523pub(crate) enum Effect {
2525 Notify {
2526 emitter: EntityId,
2527 },
2528 Emit {
2529 emitter: EntityId,
2530 event_type: TypeId,
2531 event: Box<dyn Any>,
2532 },
2533 RefreshWindows,
2534 NotifyGlobalObservers {
2535 global_type: TypeId,
2536 },
2537 Defer {
2538 callback: Box<dyn FnOnce(&mut App) + 'static>,
2539 },
2540 EntityCreated {
2541 entity: AnyEntity,
2542 tid: TypeId,
2543 window: Option<WindowId>,
2544 },
2545}
2546
2547impl std::fmt::Debug for Effect {
2548 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2549 match self {
2550 Effect::Notify { emitter } => write!(f, "Notify({})", emitter),
2551 Effect::Emit { emitter, .. } => write!(f, "Emit({:?})", emitter),
2552 Effect::RefreshWindows => write!(f, "RefreshWindows"),
2553 Effect::NotifyGlobalObservers { global_type } => {
2554 write!(f, "NotifyGlobalObservers({:?})", global_type)
2555 }
2556 Effect::Defer { .. } => write!(f, "Defer(..)"),
2557 Effect::EntityCreated { entity, .. } => write!(f, "EntityCreated({:?})", entity),
2558 }
2559 }
2560}
2561
2562pub(crate) struct GlobalLease<G: Global> {
2564 global: Box<dyn Any>,
2565 global_type: PhantomData<G>,
2566}
2567
2568impl<G: Global> GlobalLease<G> {
2569 fn new(global: Box<dyn Any>) -> Self {
2570 GlobalLease {
2571 global,
2572 global_type: PhantomData,
2573 }
2574 }
2575}
2576
2577impl<G: Global> Deref for GlobalLease<G> {
2578 type Target = G;
2579
2580 fn deref(&self) -> &Self::Target {
2581 self.global.downcast_ref().unwrap()
2582 }
2583}
2584
2585impl<G: Global> DerefMut for GlobalLease<G> {
2586 fn deref_mut(&mut self) -> &mut Self::Target {
2587 self.global.downcast_mut().unwrap()
2588 }
2589}
2590
2591pub struct AnyDrag {
2594 pub view: AnyView,
2596
2597 pub value: Arc<dyn Any>,
2599
2600 pub cursor_offset: Point<Pixels>,
2603
2604 pub cursor_style: Option<CursorStyle>,
2606}
2607
2608#[derive(Clone)]
2611pub struct AnyTooltip {
2612 pub view: AnyView,
2614
2615 pub mouse_position: Point<Pixels>,
2617
2618 pub check_visible_and_update: Rc<dyn Fn(Bounds<Pixels>, &mut Window, &mut App) -> bool>,
2622}
2623
2624#[derive(Debug)]
2626pub struct KeystrokeEvent {
2627 pub keystroke: Keystroke,
2629
2630 pub action: Option<Box<dyn Action>>,
2632
2633 pub context_stack: Vec<KeyContext>,
2635}
2636
2637struct NullHttpClient;
2638
2639impl HttpClient for NullHttpClient {
2640 fn send(
2641 &self,
2642 _req: http_client::Request<http_client::AsyncBody>,
2643 ) -> futures::future::BoxFuture<
2644 'static,
2645 anyhow::Result<http_client::Response<http_client::AsyncBody>>,
2646 > {
2647 async move {
2648 anyhow::bail!("No HttpClient available");
2649 }
2650 .boxed()
2651 }
2652
2653 fn user_agent(&self) -> Option<&http_client::http::HeaderValue> {
2654 None
2655 }
2656
2657 fn proxy(&self) -> Option<&Url> {
2658 None
2659 }
2660
2661 fn type_name(&self) -> &'static str {
2662 type_name::<Self>()
2663 }
2664}
2665
2666pub struct GpuiBorrow<'a, T> {
2668 inner: Option<Lease<T>>,
2669 app: &'a mut App,
2670}
2671
2672impl<'a, T: 'static> GpuiBorrow<'a, T> {
2673 fn new(inner: Entity<T>, app: &'a mut App) -> Self {
2674 app.start_update();
2675 let lease = app.entities.lease(&inner);
2676 Self {
2677 inner: Some(lease),
2678 app,
2679 }
2680 }
2681}
2682
2683impl<'a, T: 'static> std::borrow::Borrow<T> for GpuiBorrow<'a, T> {
2684 fn borrow(&self) -> &T {
2685 self.inner.as_ref().unwrap().borrow()
2686 }
2687}
2688
2689impl<'a, T: 'static> std::borrow::BorrowMut<T> for GpuiBorrow<'a, T> {
2690 fn borrow_mut(&mut self) -> &mut T {
2691 self.inner.as_mut().unwrap().borrow_mut()
2692 }
2693}
2694
2695impl<'a, T: 'static> std::ops::Deref for GpuiBorrow<'a, T> {
2696 type Target = T;
2697
2698 fn deref(&self) -> &Self::Target {
2699 self.inner.as_ref().unwrap()
2700 }
2701}
2702
2703impl<'a, T: 'static> std::ops::DerefMut for GpuiBorrow<'a, T> {
2704 fn deref_mut(&mut self) -> &mut T {
2705 self.inner.as_mut().unwrap()
2706 }
2707}
2708
2709impl<'a, T> Drop for GpuiBorrow<'a, T> {
2710 fn drop(&mut self) {
2711 let lease = self.inner.take().unwrap();
2712 self.app.notify(lease.id);
2713 self.app.entities.end_lease(lease);
2714 self.app.finish_update();
2715 }
2716}
2717
2718#[cfg(test)]
2719mod test {
2720 use std::{cell::RefCell, rc::Rc};
2721
2722 use crate::{AppContext, TestAppContext};
2723
2724 #[test]
2725 fn test_gpui_borrow() {
2726 let cx = TestAppContext::single();
2727 let observation_count = Rc::new(RefCell::new(0));
2728
2729 let state = cx.update(|cx| {
2730 let state = cx.new(|_| false);
2731 cx.observe(&state, {
2732 let observation_count = observation_count.clone();
2733 move |_, _| {
2734 let mut count = observation_count.borrow_mut();
2735 *count += 1;
2736 }
2737 })
2738 .detach();
2739
2740 state
2741 });
2742
2743 cx.update(|cx| {
2744 *std::borrow::BorrowMut::borrow_mut(&mut state.as_mut(cx)) = true;
2746 });
2747
2748 cx.update(|cx| {
2749 state.write(cx, false);
2750 });
2751
2752 assert_eq!(*observation_count.borrow(), 2);
2753 }
2754}