Skip to main content

gpui_core/
app.rs

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,
38    AppResourceProfile, Asset, AssetSource, AttentionType, BackgroundExecutor, BiometricStatus,
39    Bounds, ClipboardItem, CrashReport, CursorStyle, DialogOptions, DispatchPhase, DisplayId,
40    EventEmitter, FocusHandle, FocusMap, FocusedWindowInfo, ForegroundExecutor, Global, KeyBinding,
41    KeyContext, Keymap, Keystroke, LayoutId, MediaKeyEvent, Menu, MenuItem, NetworkStatus, OsInfo,
42    OwnedMenu, PathPromptOptions, PermissionRequestStatus, PermissionStatus, Pixels, Platform,
43    PlatformDisplay, PlatformKeyboardLayout, PlatformKeyboardMapper, Point, PowerSaveBlockerKind,
44    PromptBuilder, PromptButton, PromptHandle, PromptLevel, Render, RenderImage,
45    RenderablePromptHandle, Reservation, ScreenCaptureSource, SharedString, Size, SubscriberSet,
46    Subscription, SvgRenderer, SystemPowerEvent, Task, TextSystem, ThermalState, TrayAnchor,
47    TrayIconClickEvent, TrayIconEvent, TrayIconRenderingMode, TrayMenuItem, Window,
48    WindowAppearance, WindowHandle, WindowId, WindowInvalidator, WindowPosition,
49    colors::{Colors, GlobalColors},
50    hash, init_app_menus, point, px, size,
51};
52
53mod async_context;
54mod context;
55mod entity_map;
56#[cfg(any(test, feature = "test-support"))]
57mod test_context;
58
59/// The duration for which futures returned from [Context::on_app_quit] can run before the application fully quits.
60pub const SHUTDOWN_TIMEOUT: Duration = Duration::from_millis(100);
61
62/// Temporary(?) wrapper around [`RefCell<App>`] to help us debug any double borrows.
63/// Strongly consider removing after stabilization.
64#[doc(hidden)]
65pub struct AppCell {
66    app: RefCell<App>,
67}
68
69impl AppCell {
70    #[doc(hidden)]
71    #[track_caller]
72    pub fn borrow(&self) -> AppRef<'_> {
73        if option_env!("TRACK_THREAD_BORROWS").is_some() {
74            let thread_id = std::thread::current().id();
75            eprintln!("borrowed {thread_id:?}");
76        }
77        AppRef(self.app.borrow())
78    }
79
80    #[doc(hidden)]
81    #[track_caller]
82    pub fn borrow_mut(&self) -> AppRefMut<'_> {
83        if option_env!("TRACK_THREAD_BORROWS").is_some() {
84            let thread_id = std::thread::current().id();
85            eprintln!("borrowed {thread_id:?}");
86        }
87        AppRefMut(self.app.borrow_mut())
88    }
89
90    #[doc(hidden)]
91    #[track_caller]
92    pub fn try_borrow_mut(&self) -> Result<AppRefMut<'_>, BorrowMutError> {
93        if option_env!("TRACK_THREAD_BORROWS").is_some() {
94            let thread_id = std::thread::current().id();
95            eprintln!("borrowed {thread_id:?}");
96        }
97        Ok(AppRefMut(self.app.try_borrow_mut()?))
98    }
99}
100
101#[doc(hidden)]
102#[derive(Deref, DerefMut)]
103pub struct AppRef<'a>(Ref<'a, App>);
104
105impl Drop for AppRef<'_> {
106    fn drop(&mut self) {
107        if option_env!("TRACK_THREAD_BORROWS").is_some() {
108            let thread_id = std::thread::current().id();
109            eprintln!("dropped borrow from {thread_id:?}");
110        }
111    }
112}
113
114#[doc(hidden)]
115#[derive(Deref, DerefMut)]
116pub struct AppRefMut<'a>(RefMut<'a, App>);
117
118impl Drop for AppRefMut<'_> {
119    fn drop(&mut self) {
120        if option_env!("TRACK_THREAD_BORROWS").is_some() {
121            let thread_id = std::thread::current().id();
122            eprintln!("dropped {thread_id:?}");
123        }
124    }
125}
126
127/// A reference to a GPUI application, typically constructed in the `main` function of your app.
128/// You won't interact with this type much outside of initial configuration and startup.
129pub struct Application(Rc<AppCell>);
130
131/// A strong handle to an [`Application`] started with [`Application::run_embedded`].
132///
133/// Dropping this handle releases the app, so an embedder must hold it for as long as the
134/// app should run. While held, it is the embedder's entry point back into GPUI each time
135/// the external run loop gives it control.
136pub struct ApplicationHandle {
137    app: Rc<AppCell>,
138}
139
140impl ApplicationHandle {
141    /// Invoke `f` with the app context. Must not be called re-entrantly from code that
142    /// is already inside an update; the app state is a `RefCell` and will panic on a
143    /// double borrow.
144    pub fn update<R>(&self, f: impl FnOnce(&mut App) -> R) -> R {
145        let cx = &mut *self.app.borrow_mut();
146        f(cx)
147    }
148
149    /// An [`AsyncApp`] for use across await points. It holds the app weakly; keeping the
150    /// app alive remains this handle's job.
151    pub fn to_async(&self) -> AsyncApp {
152        self.update(|cx| cx.to_async())
153    }
154}
155
156/// Represents an application before it is fully launched. Once your app is
157/// configured, you'll start the app with `App::run`.
158impl Application {
159    /// Builds an application with a caller-provided platform implementation.
160    ///
161    /// This is a low-level construction seam for platform facade and backend crates.
162    pub fn with_platform(platform: Rc<dyn Platform>) -> Self {
163        Self(App::new_app(
164            platform,
165            Arc::new(()),
166            Arc::new(NullHttpClient),
167            AppResourceProfile::default(),
168        ))
169    }
170
171    /// Builds this app with accessibility integration forcibly disabled.
172    ///
173    /// In this mode, accessibility APIs such as
174    /// [`StatefulInteractiveElement::role`](crate::StatefulInteractiveElement::role)
175    /// silently no-op.
176    pub fn inaccessible(self) -> Self {
177        self.0.borrow_mut().accessibility_force_disabled = true;
178        self
179    }
180
181    /// Assign
182    pub fn with_assets(self, asset_source: impl AssetSource) -> Self {
183        let mut context_lock = self.0.borrow_mut();
184        let asset_source = Arc::new(asset_source);
185        context_lock.asset_source = asset_source.clone();
186        context_lock.svg_renderer = SvgRenderer::new(asset_source);
187        drop(context_lock);
188        self
189    }
190
191    /// Sets the HTTP client for the application.
192    pub fn with_http_client(self, http_client: Arc<dyn HttpClient>) -> Self {
193        let mut context_lock = self.0.borrow_mut();
194        context_lock.http_client = http_client;
195        drop(context_lock);
196        self
197    }
198
199    /// Configures when the application should automatically quit.
200    /// By default, [`QuitMode::Default`] is used.
201    pub fn with_quit_mode(self, mode: QuitMode) -> Self {
202        self.0.borrow_mut().set_quit_mode(mode);
203        self
204    }
205
206    /// Sets the resource profile for the application.
207    ///
208    /// The resource profile controls internal cache sizes and GPU resource
209    /// allocation. Use [`crate::AppProfile`] presets for common scenarios, or provide
210    /// a custom [`AppResourceProfile`] for fine-grained control.
211    ///
212    /// **Must be called before [`Application::run`]** — this rebuilds text
213    /// caches with the configured budget. Atlas configuration takes effect for
214    /// subsequently opened windows.
215    ///
216    /// The core crate does not select a desktop backend. Applications using the
217    /// published `gpui` facade should call `gpui::Application::new()` instead.
218    ///
219    /// ```rust,ignore
220    /// gpui::Application::new()
221    ///     .with_resource_profile(AppProfile::Minimal)
222    ///     .run(|cx| { /* ... */ });
223    /// ```
224    pub fn with_resource_profile(self, profile: impl Into<AppResourceProfile>) -> Self {
225        let profile = profile.into();
226        // Set the element arena size before any windows (and thus thread-local
227        // arenas) are created. This must happen on the main thread, which is
228        // guaranteed by the `Application` API. Clamp to >= 1 because the
229        // underlying `Arena::new` requires a non-zero chunk size and would
230        // otherwise panic lazily on first use in another thread.
231        crate::window::ELEMENT_ARENA_SIZE.store(
232            profile.element_arena_size.max(1),
233            std::sync::atomic::Ordering::Relaxed,
234        );
235        let mut context_lock = self.0.borrow_mut();
236        context_lock.platform.configure_gpu_resources(&profile.gpu);
237        context_lock.text_system = Arc::new(TextSystem::new(
238            context_lock.platform.text_system(),
239            &profile.text,
240        ));
241        context_lock.resource_profile = profile;
242        drop(context_lock);
243        self
244    }
245
246    /// Start the application. The provided callback will be called once the
247    /// app is fully launched.
248    pub fn run<F>(self, on_finish_launching: F)
249    where
250        F: 'static + FnOnce(&mut App),
251    {
252        let this = self.0.clone();
253        let platform = self.0.borrow().platform.clone();
254        platform.run(Box::new(move || {
255            let cx = &mut *this.borrow_mut();
256            on_finish_launching(cx);
257        }));
258    }
259
260    /// Start the application for an embedder that drives the run loop itself.
261    ///
262    /// On ordinary platforms `Platform::run` blocks for the lifetime of the app, and the
263    /// app state is kept alive by [`Application::run`]'s stack frame. Embedded platforms -
264    /// where the run loop belongs to someone else, e.g. GPUI compiled into a Wasm guest,
265    /// or a GPUI view hosted inside a foreign native application - implement
266    /// `Platform::run` to invoke the launch callback and return immediately. This method
267    /// supports that shape: it returns an [`ApplicationHandle`] that keeps the app alive
268    /// and lets the embedder re-enter it whenever the external run loop yields control.
269    pub fn run_embedded<F>(self, on_finish_launching: F) -> ApplicationHandle
270    where
271        F: 'static + FnOnce(&mut App),
272    {
273        let this = self.0.clone();
274        let platform = self.0.borrow().platform.clone();
275        platform.run(Box::new(move || {
276            let cx = &mut *this.borrow_mut();
277            on_finish_launching(cx);
278        }));
279        ApplicationHandle { app: self.0 }
280    }
281
282    /// Register a handler to be invoked when the platform instructs the application
283    /// to open one or more URLs.
284    pub fn on_open_urls<F>(&self, mut callback: F) -> &Self
285    where
286        F: 'static + FnMut(Vec<String>),
287    {
288        self.0.borrow().platform.on_open_urls(Box::new(callback));
289        self
290    }
291
292    /// Invokes a handler when an already-running application is launched.
293    /// On macOS, this can occur when the application icon is double-clicked or the app is launched via the dock.
294    pub fn on_reopen<F>(&self, mut callback: F) -> &Self
295    where
296        F: 'static + FnMut(&mut App),
297    {
298        let this = Rc::downgrade(&self.0);
299        self.0.borrow_mut().platform.on_reopen(Box::new(move || {
300            if let Some(app) = this.upgrade() {
301                callback(&mut app.borrow_mut());
302            }
303        }));
304        self
305    }
306
307    /// Returns a handle to the [`BackgroundExecutor`] associated with this app, which can be used to spawn futures in the background.
308    pub fn background_executor(&self) -> BackgroundExecutor {
309        self.0.borrow().background_executor.clone()
310    }
311
312    /// Returns a handle to the [`ForegroundExecutor`] associated with this app, which can be used to spawn futures in the foreground.
313    pub fn foreground_executor(&self) -> ForegroundExecutor {
314        self.0.borrow().foreground_executor.clone()
315    }
316
317    /// Returns a reference to the [`TextSystem`] associated with this app.
318    pub fn text_system(&self) -> Arc<TextSystem> {
319        self.0.borrow().text_system.clone()
320    }
321
322    /// Returns the file URL of the executable with the specified name in the application bundle
323    pub fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf> {
324        self.0.borrow().path_for_auxiliary_executable(name)
325    }
326}
327
328type Handler = Box<dyn FnMut(&mut App) -> bool + 'static>;
329type Listener = Box<dyn FnMut(&dyn Any, &mut App) -> bool + 'static>;
330pub(crate) type KeystrokeObserver =
331    Box<dyn FnMut(&KeystrokeEvent, &mut Window, &mut App) -> bool + 'static>;
332type QuitHandler = Box<dyn FnOnce(&mut App) -> LocalBoxFuture<'static, ()> + 'static>;
333type WindowClosedHandler = Box<dyn FnMut(&mut App)>;
334type ReleaseListener = Box<dyn FnOnce(&mut dyn Any, &mut App) + 'static>;
335type NewEntityListener = Box<dyn FnMut(AnyEntity, &mut Option<&mut Window>, &mut App) + 'static>;
336
337/// Defines when the application should automatically quit.
338#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
339pub enum QuitMode {
340    /// Use [`QuitMode::Explicit`] on macOS and [`QuitMode::LastWindowClosed`] on other platforms.
341    #[default]
342    Default,
343    /// Quit automatically when the last window is closed.
344    LastWindowClosed,
345    /// Quit only when requested via [`App::quit`].
346    Explicit,
347}
348
349#[doc(hidden)]
350#[derive(Clone, PartialEq, Eq)]
351pub struct SystemWindowTab {
352    pub id: WindowId,
353    pub title: SharedString,
354    pub handle: AnyWindowHandle,
355    pub last_active_at: Instant,
356}
357
358impl SystemWindowTab {
359    /// Create a new instance of the window tab.
360    pub fn new(title: SharedString, handle: AnyWindowHandle) -> Self {
361        Self {
362            id: handle.id,
363            title,
364            handle,
365            last_active_at: Instant::now(),
366        }
367    }
368}
369
370/// A controller for managing window tabs.
371#[derive(Default)]
372pub struct SystemWindowTabController {
373    visible: Option<bool>,
374    tab_groups: FxHashMap<usize, Vec<SystemWindowTab>>,
375}
376
377impl Global for SystemWindowTabController {}
378
379impl SystemWindowTabController {
380    /// Create a new instance of the window tab controller.
381    pub fn new() -> Self {
382        Self {
383            visible: None,
384            tab_groups: FxHashMap::default(),
385        }
386    }
387
388    /// Initialize the global window tab controller.
389    pub fn init(cx: &mut App) {
390        cx.set_global(SystemWindowTabController::new());
391    }
392
393    /// Get all tab groups.
394    pub fn tab_groups(&self) -> &FxHashMap<usize, Vec<SystemWindowTab>> {
395        &self.tab_groups
396    }
397
398    /// Get the next tab group window handle.
399    pub fn get_next_tab_group_window(cx: &mut App, id: WindowId) -> Option<&AnyWindowHandle> {
400        let controller = cx.global::<SystemWindowTabController>();
401        let current_group = controller
402            .tab_groups
403            .iter()
404            .find_map(|(group, tabs)| tabs.iter().find(|tab| tab.id == id).map(|_| group));
405
406        let current_group = current_group?;
407        let mut group_ids: Vec<_> = controller.tab_groups.keys().collect();
408        let idx = group_ids.iter().position(|g| *g == current_group)?;
409        let next_idx = (idx + 1) % group_ids.len();
410
411        controller
412            .tab_groups
413            .get(group_ids[next_idx])
414            .and_then(|tabs| {
415                tabs.iter()
416                    .max_by_key(|tab| tab.last_active_at)
417                    .or_else(|| tabs.first())
418                    .map(|tab| &tab.handle)
419            })
420    }
421
422    /// Get the previous tab group window handle.
423    pub fn get_prev_tab_group_window(cx: &mut App, id: WindowId) -> Option<&AnyWindowHandle> {
424        let controller = cx.global::<SystemWindowTabController>();
425        let current_group = controller
426            .tab_groups
427            .iter()
428            .find_map(|(group, tabs)| tabs.iter().find(|tab| tab.id == id).map(|_| group));
429
430        let current_group = current_group?;
431        let mut group_ids: Vec<_> = controller.tab_groups.keys().collect();
432        let idx = group_ids.iter().position(|g| *g == current_group)?;
433        let prev_idx = if idx == 0 {
434            group_ids.len() - 1
435        } else {
436            idx - 1
437        };
438
439        controller
440            .tab_groups
441            .get(group_ids[prev_idx])
442            .and_then(|tabs| {
443                tabs.iter()
444                    .max_by_key(|tab| tab.last_active_at)
445                    .or_else(|| tabs.first())
446                    .map(|tab| &tab.handle)
447            })
448    }
449
450    /// Get all tabs in the same window.
451    pub fn tabs(&self, id: WindowId) -> Option<&Vec<SystemWindowTab>> {
452        let tab_group = self
453            .tab_groups
454            .iter()
455            .find_map(|(group, tabs)| tabs.iter().find(|tab| tab.id == id).map(|_| *group));
456
457        if let Some(tab_group) = tab_group {
458            self.tab_groups.get(&tab_group)
459        } else {
460            None
461        }
462    }
463
464    /// Initialize the visibility of the system window tab controller.
465    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    /// Get the visibility of the system window tab controller.
473    pub fn is_visible(&self) -> bool {
474        self.visible.unwrap_or(false)
475    }
476
477    /// Set the visibility of the system window tab controller.
478    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    /// Update the last active of a window.
484    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    /// Update the position of a tab within its group.
496    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    /// Update the title of a tab.
510    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.clone();
527                }
528            }
529        }
530    }
531
532    /// Insert a tab into a tab group.
533    pub fn add_tab(cx: &mut App, id: WindowId, tabs: Vec<SystemWindowTab>) {
534        let mut controller = cx.global_mut::<SystemWindowTabController>();
535        let Some(tab) = tabs.clone().into_iter().find(|tab| tab.id == id) else {
536            return;
537        };
538
539        let mut expected_tab_ids: Vec<_> = tabs
540            .iter()
541            .filter(|tab| tab.id != id)
542            .map(|tab| tab.id)
543            .sorted()
544            .collect();
545
546        let mut tab_group_id = None;
547        for (group_id, group_tabs) in &controller.tab_groups {
548            let tab_ids: Vec<_> = group_tabs.iter().map(|tab| tab.id).sorted().collect();
549            if tab_ids == expected_tab_ids {
550                tab_group_id = Some(*group_id);
551                break;
552            }
553        }
554
555        if let Some(tab_group_id) = tab_group_id {
556            if let Some(tabs) = controller.tab_groups.get_mut(&tab_group_id) {
557                tabs.push(tab);
558            }
559        } else {
560            let new_group_id = controller.tab_groups.len();
561            controller.tab_groups.insert(new_group_id, tabs);
562        }
563    }
564
565    /// Remove a tab from a tab group.
566    pub fn remove_tab(cx: &mut App, id: WindowId) -> Option<SystemWindowTab> {
567        let mut controller = cx.global_mut::<SystemWindowTabController>();
568        let mut removed_tab = None;
569
570        controller.tab_groups.retain(|_, tabs| {
571            if let Some(pos) = tabs.iter().position(|tab| tab.id == id) {
572                removed_tab = Some(tabs.remove(pos));
573            }
574            !tabs.is_empty()
575        });
576
577        removed_tab
578    }
579
580    /// Move a tab to a new tab group.
581    pub fn move_tab_to_new_window(cx: &mut App, id: WindowId) {
582        let mut removed_tab = Self::remove_tab(cx, id);
583        let mut controller = cx.global_mut::<SystemWindowTabController>();
584
585        if let Some(tab) = removed_tab {
586            let new_group_id = controller.tab_groups.keys().max().map_or(0, |k| k + 1);
587            controller.tab_groups.insert(new_group_id, vec![tab]);
588        }
589    }
590
591    /// Merge all tab groups into a single group.
592    pub fn merge_all_windows(cx: &mut App, id: WindowId) {
593        let mut controller = cx.global_mut::<SystemWindowTabController>();
594        let Some(initial_tabs) = controller.tabs(id) else {
595            return;
596        };
597
598        let mut all_tabs = initial_tabs.clone();
599        for tabs in controller.tab_groups.values() {
600            all_tabs.extend(
601                tabs.iter()
602                    .filter(|tab| !initial_tabs.contains(tab))
603                    .cloned(),
604            );
605        }
606
607        controller.tab_groups.clear();
608        controller.tab_groups.insert(0, all_tabs);
609    }
610
611    /// Selects the next tab in the tab group in the trailing direction.
612    pub fn select_next_tab(cx: &mut App, id: WindowId) {
613        let mut controller = cx.global_mut::<SystemWindowTabController>();
614        let Some(tabs) = controller.tabs(id) else {
615            return;
616        };
617
618        let current_index = tabs.iter().position(|tab| tab.id == id).unwrap();
619        let next_index = (current_index + 1) % tabs.len();
620
621        let _ = &tabs[next_index].handle.update(cx, |_, window, _| {
622            window.activate_window();
623        });
624    }
625
626    /// Selects the previous tab in the tab group in the leading direction.
627    pub fn select_previous_tab(cx: &mut App, id: WindowId) {
628        let mut controller = cx.global_mut::<SystemWindowTabController>();
629        let Some(tabs) = controller.tabs(id) else {
630            return;
631        };
632
633        let current_index = tabs.iter().position(|tab| tab.id == id).unwrap();
634        let previous_index = if current_index == 0 {
635            tabs.len() - 1
636        } else {
637            current_index - 1
638        };
639
640        let _ = &tabs[previous_index].handle.update(cx, |_, window, _| {
641            window.activate_window();
642        });
643    }
644}
645
646/// Contains the state of the full application, and passed as a reference to a variety of callbacks.
647/// Other [Context] derefs to this type.
648/// You need a reference to an `App` to access the state of a [Entity].
649pub struct App {
650    pub(crate) this: Weak<AppCell>,
651    pub(crate) platform: Rc<dyn Platform>,
652    pub(crate) accessibility_force_disabled: bool,
653    pub(crate) resource_profile: AppResourceProfile,
654    text_system: Arc<TextSystem>,
655    flushing_effects: bool,
656    pending_updates: usize,
657    pub(crate) actions: Rc<ActionRegistry>,
658    pub(crate) active_drag: Option<AnyDrag>,
659    pub(crate) background_executor: BackgroundExecutor,
660    pub(crate) foreground_executor: ForegroundExecutor,
661    pub(crate) loading_assets: FxHashMap<(TypeId, u64), Box<dyn Any>>,
662    asset_source: Arc<dyn AssetSource>,
663    pub(crate) svg_renderer: SvgRenderer,
664    http_client: Arc<dyn HttpClient>,
665    pub(crate) globals_by_type: FxHashMap<TypeId, Box<dyn Any>>,
666    pub(crate) entities: EntityMap,
667    pub(crate) window_update_stack: Vec<WindowId>,
668    pub(crate) new_entity_observers: SubscriberSet<TypeId, NewEntityListener>,
669    pub(crate) windows: SlotMap<WindowId, Option<Window>>,
670    pub(crate) window_handles: FxHashMap<WindowId, AnyWindowHandle>,
671    pub(crate) focus_handles: Arc<FocusMap>,
672    pub(crate) keymap: Rc<RefCell<Keymap>>,
673    pub(crate) keyboard_layout: Box<dyn PlatformKeyboardLayout>,
674    pub(crate) keyboard_mapper: Rc<dyn PlatformKeyboardMapper>,
675    pub(crate) global_action_listeners:
676        FxHashMap<TypeId, Vec<Rc<dyn Fn(&dyn Any, DispatchPhase, &mut Self)>>>,
677    pending_effects: VecDeque<Effect>,
678    pub(crate) pending_notifications: FxHashSet<EntityId>,
679    pub(crate) pending_global_notifications: FxHashSet<TypeId>,
680    pub(crate) observers: SubscriberSet<EntityId, Handler>,
681    // TypeId is the type of the event that the listener callback expects
682    pub(crate) event_listeners: SubscriberSet<EntityId, (TypeId, Listener)>,
683    pub(crate) keystroke_observers: SubscriberSet<(), KeystrokeObserver>,
684    pub(crate) keystroke_interceptors: SubscriberSet<(), KeystrokeObserver>,
685    pub(crate) keyboard_layout_observers: SubscriberSet<(), Handler>,
686    pub(crate) thermal_state_observers: SubscriberSet<(), Handler>,
687    pub(crate) release_listeners: SubscriberSet<EntityId, ReleaseListener>,
688    pub(crate) global_observers: SubscriberSet<TypeId, Handler>,
689    pub(crate) quit_observers: SubscriberSet<(), QuitHandler>,
690    pub(crate) restart_observers: SubscriberSet<(), Handler>,
691    pub(crate) restart_path: Option<PathBuf>,
692    pub(crate) window_closed_observers: SubscriberSet<(), WindowClosedHandler>,
693    pub(crate) layout_id_buffer: Vec<LayoutId>, // We recycle this memory across layout requests.
694    pub(crate) propagate_event: bool,
695    pub(crate) prompt_builder: Option<PromptBuilder>,
696    pub(crate) window_invalidators_by_entity:
697        FxHashMap<EntityId, FxHashMap<WindowId, WindowInvalidator>>,
698    pub(crate) tracked_entities: FxHashMap<WindowId, FxHashSet<EntityId>>,
699    #[cfg(any(feature = "inspector", debug_assertions))]
700    pub(crate) inspector_renderer: Option<crate::InspectorRenderer>,
701    #[cfg(any(feature = "inspector", debug_assertions))]
702    pub(crate) inspector_element_registry: InspectorElementRegistry,
703    #[cfg(any(test, feature = "test-support", debug_assertions))]
704    pub(crate) name: Option<&'static str>,
705    quitting: bool,
706    pub(crate) quit_mode: QuitMode,
707}
708
709impl App {
710    #[allow(clippy::new_ret_no_self)]
711    pub(crate) fn new_app(
712        platform: Rc<dyn Platform>,
713        asset_source: Arc<dyn AssetSource>,
714        http_client: Arc<dyn HttpClient>,
715        resource_profile: AppResourceProfile,
716    ) -> Rc<AppCell> {
717        let executor = platform.background_executor();
718        let foreground_executor = platform.foreground_executor();
719        assert!(
720            executor.is_main_thread(),
721            "must construct App on main thread"
722        );
723
724        let text_system = Arc::new(TextSystem::new(
725            platform.text_system(),
726            &resource_profile.text,
727        ));
728        platform.configure_gpu_resources(&resource_profile.gpu);
729        let entities = EntityMap::new();
730        let keyboard_layout = platform.keyboard_layout();
731        let keyboard_mapper = platform.keyboard_mapper();
732
733        let app = Rc::new_cyclic(|this| AppCell {
734            app: RefCell::new(App {
735                this: this.clone(),
736                platform: platform.clone(),
737                accessibility_force_disabled: false,
738                resource_profile,
739                text_system,
740                actions: Rc::new(ActionRegistry::default()),
741                flushing_effects: false,
742                pending_updates: 0,
743                active_drag: None,
744                background_executor: executor,
745                foreground_executor,
746                svg_renderer: SvgRenderer::new(asset_source.clone()),
747                loading_assets: Default::default(),
748                asset_source,
749                http_client,
750                globals_by_type: FxHashMap::default(),
751                entities,
752                new_entity_observers: SubscriberSet::new(),
753                windows: SlotMap::with_key(),
754                window_update_stack: Vec::new(),
755                window_handles: FxHashMap::default(),
756                focus_handles: Arc::new(RwLock::new(SlotMap::with_key())),
757                keymap: Rc::new(RefCell::new(Keymap::default())),
758                keyboard_layout,
759                keyboard_mapper,
760                global_action_listeners: FxHashMap::default(),
761                pending_effects: VecDeque::new(),
762                pending_notifications: FxHashSet::default(),
763                pending_global_notifications: FxHashSet::default(),
764                observers: SubscriberSet::new(),
765                tracked_entities: FxHashMap::default(),
766                window_invalidators_by_entity: FxHashMap::default(),
767                event_listeners: SubscriberSet::new(),
768                release_listeners: SubscriberSet::new(),
769                keystroke_observers: SubscriberSet::new(),
770                keystroke_interceptors: SubscriberSet::new(),
771                keyboard_layout_observers: SubscriberSet::new(),
772                thermal_state_observers: SubscriberSet::new(),
773                global_observers: SubscriberSet::new(),
774                quit_observers: SubscriberSet::new(),
775                restart_observers: SubscriberSet::new(),
776                restart_path: None,
777                window_closed_observers: SubscriberSet::new(),
778                layout_id_buffer: Default::default(),
779                propagate_event: true,
780                prompt_builder: Some(PromptBuilder::Default),
781                #[cfg(any(feature = "inspector", debug_assertions))]
782                inspector_renderer: None,
783                #[cfg(any(feature = "inspector", debug_assertions))]
784                inspector_element_registry: InspectorElementRegistry::default(),
785                quitting: false,
786                quit_mode: QuitMode::default(),
787
788                #[cfg(any(test, feature = "test-support", debug_assertions))]
789                name: None,
790            }),
791        });
792
793        init_app_menus(platform.as_ref(), &app.borrow());
794        SystemWindowTabController::init(&mut app.borrow_mut());
795
796        platform.on_keyboard_layout_change(Box::new({
797            let app = Rc::downgrade(&app);
798            move || {
799                if let Some(app) = app.upgrade() {
800                    let cx = &mut app.borrow_mut();
801                    cx.keyboard_layout = cx.platform.keyboard_layout();
802                    cx.keyboard_mapper = cx.platform.keyboard_mapper();
803                    cx.keyboard_layout_observers
804                        .clone()
805                        .retain(&(), move |callback| (callback)(cx));
806                }
807            }
808        }));
809
810        platform.on_thermal_state_change(Box::new({
811            let app = Rc::downgrade(&app);
812            move || {
813                if let Some(app) = app.upgrade() {
814                    let cx = &mut app.borrow_mut();
815                    cx.thermal_state_observers
816                        .clone()
817                        .retain(&(), move |callback| (callback)(cx));
818                }
819            }
820        }));
821
822        platform.on_quit(Box::new({
823            let cx = app.clone();
824            move || match cx.try_borrow_mut() {
825                Ok(mut cx) => {
826                    cx.shutdown();
827                    true
828                }
829                Err(_) => {
830                    // Quit was requested while the AppCell was borrowed, so we
831                    // can't shut down synchronously. The platform decides how
832                    // to proceed (Windows Restart Manager posts WM_QUIT).
833                    false
834                }
835            }
836        }));
837
838        app
839    }
840
841    /// Quit the application gracefully. Handlers registered with [`Context::on_app_quit`]
842    /// will be given 100ms to complete before exiting.
843    pub fn shutdown(&mut self) {
844        let mut futures = Vec::new();
845
846        for observer in self.quit_observers.remove(&()) {
847            futures.push(observer(self));
848        }
849
850        self.windows.clear();
851        self.window_handles.clear();
852        self.flush_effects();
853        self.quitting = true;
854
855        let futures = futures::future::join_all(futures);
856        if self
857            .background_executor
858            .block_with_timeout(SHUTDOWN_TIMEOUT, futures)
859            .is_err()
860        {
861            log::error!("timed out waiting on app_will_quit");
862        }
863
864        self.quitting = false;
865    }
866
867    /// Get the id of the current keyboard layout
868    pub fn keyboard_layout(&self) -> &dyn PlatformKeyboardLayout {
869        self.keyboard_layout.as_ref()
870    }
871
872    /// Get the current keyboard mapper.
873    pub fn keyboard_mapper(&self) -> &Rc<dyn PlatformKeyboardMapper> {
874        &self.keyboard_mapper
875    }
876
877    /// Invokes a handler when the current keyboard layout changes
878    pub fn on_keyboard_layout_change<F>(&self, mut callback: F) -> Subscription
879    where
880        F: 'static + FnMut(&mut App),
881    {
882        let (subscription, activate) = self.keyboard_layout_observers.insert(
883            (),
884            Box::new(move |cx| {
885                callback(cx);
886                true
887            }),
888        );
889        activate();
890        subscription
891    }
892
893    /// Returns the current thermal state of the system.
894    pub fn thermal_state(&self) -> ThermalState {
895        self.platform.thermal_state()
896    }
897
898    /// Invokes a handler when the thermal state changes.
899    pub fn on_thermal_state_change<F>(&self, mut callback: F) -> Subscription
900    where
901        F: 'static + FnMut(&mut App),
902    {
903        let (subscription, activate) = self.thermal_state_observers.insert(
904            (),
905            Box::new(move |cx| {
906                callback(cx);
907                true
908            }),
909        );
910        activate();
911        subscription
912    }
913
914    /// Gracefully quit the application via the platform's standard routine.
915    pub fn quit(&self) {
916        self.platform.quit();
917    }
918
919    /// Ask the platform renderer to drop idle pooled GPU resources where
920    /// supported.
921    ///
922    /// Intended for long-running applications (tray icons, notification
923    /// popups) that want to reclaim GPU memory during idle periods such as
924    /// after the last visible window is hidden. The renderer will re-allocate
925    /// resources on demand on the next frame.
926    ///
927    /// This is a best-effort operation. Platforms that do not maintain
928    /// trimmable GPU pools may no-op, and active renderer resources are kept
929    /// alive until they can be safely released.
930    pub fn trim_gpu_caches(&self) {
931        self.platform.trim_renderer_caches();
932    }
933
934    /// Snapshot of the renderer's pooled GPU resource usage. See
935    /// [`crate::RendererCacheStats`].
936    ///
937    /// Intended primarily for diagnostics and benchmarking. Useful as a guard
938    /// before calling [`App::trim_gpu_caches`] when callers want to skip the
939    /// trim if no buffers are idle.
940    pub fn renderer_cache_stats(&self) -> crate::RendererCacheStats {
941        self.platform.renderer_cache_stats()
942    }
943
944    /// Schedules all windows in the application to be redrawn. This can be called
945    /// multiple times in an update cycle and still result in a single redraw.
946    pub fn refresh_windows(&mut self) {
947        self.pending_effects.push_back(Effect::RefreshWindows);
948    }
949
950    pub(crate) fn update<R>(&mut self, update: impl FnOnce(&mut Self) -> R) -> R {
951        self.start_update();
952        let result = update(self);
953        self.finish_update();
954        result
955    }
956
957    pub(crate) fn start_update(&mut self) {
958        self.pending_updates += 1;
959    }
960
961    pub(crate) fn finish_update(&mut self) {
962        if !self.flushing_effects && self.pending_updates == 1 {
963            self.flushing_effects = true;
964            self.flush_effects();
965            self.flushing_effects = false;
966        }
967        self.pending_updates -= 1;
968    }
969
970    /// Arrange a callback to be invoked when the given entity calls `notify` on its respective context.
971    pub fn observe<W>(
972        &mut self,
973        entity: &Entity<W>,
974        mut on_notify: impl FnMut(Entity<W>, &mut App) + 'static,
975    ) -> Subscription
976    where
977        W: 'static,
978    {
979        self.observe_internal(entity, move |e, cx| {
980            on_notify(e, cx);
981            true
982        })
983    }
984
985    pub(crate) fn detect_accessed_entities<R>(
986        &mut self,
987        callback: impl FnOnce(&mut App) -> R,
988    ) -> (R, FxHashSet<EntityId>) {
989        let accessed_entities_start = self.entities.accessed_entities.borrow().clone();
990        let result = callback(self);
991        let accessed_entities_end = self.entities.accessed_entities.borrow().clone();
992        let entities_accessed_in_callback = accessed_entities_end
993            .difference(&accessed_entities_start)
994            .copied()
995            .collect::<FxHashSet<EntityId>>();
996        (result, entities_accessed_in_callback)
997    }
998
999    pub(crate) fn record_entities_accessed(
1000        &mut self,
1001        window_handle: AnyWindowHandle,
1002        invalidator: WindowInvalidator,
1003        entities: &FxHashSet<EntityId>,
1004    ) {
1005        let mut tracked_entities =
1006            std::mem::take(self.tracked_entities.entry(window_handle.id).or_default());
1007        for entity in tracked_entities.iter() {
1008            self.window_invalidators_by_entity
1009                .entry(*entity)
1010                .and_modify(|windows| {
1011                    windows.remove(&window_handle.id);
1012                });
1013        }
1014        for entity in entities.iter() {
1015            self.window_invalidators_by_entity
1016                .entry(*entity)
1017                .or_default()
1018                .insert(window_handle.id, invalidator.clone());
1019        }
1020        tracked_entities.clear();
1021        tracked_entities.extend(entities.iter().copied());
1022        self.tracked_entities
1023            .insert(window_handle.id, tracked_entities);
1024    }
1025
1026    pub(crate) fn new_observer(&mut self, key: EntityId, value: Handler) -> Subscription {
1027        let (subscription, activate) = self.observers.insert(key, value);
1028        self.defer(move |_| activate());
1029        subscription
1030    }
1031
1032    pub(crate) fn observe_internal<W>(
1033        &mut self,
1034        entity: &Entity<W>,
1035        mut on_notify: impl FnMut(Entity<W>, &mut App) -> bool + 'static,
1036    ) -> Subscription
1037    where
1038        W: 'static,
1039    {
1040        let entity_id = entity.entity_id();
1041        let handle = entity.downgrade();
1042        self.new_observer(
1043            entity_id,
1044            Box::new(move |cx| {
1045                if let Some(entity) = handle.upgrade() {
1046                    on_notify(entity, cx)
1047                } else {
1048                    false
1049                }
1050            }),
1051        )
1052    }
1053
1054    /// Arrange for the given callback to be invoked whenever the given entity emits an event of a given type.
1055    /// The callback is provided a handle to the emitting entity and a reference to the emitted event.
1056    pub fn subscribe<T, Event>(
1057        &mut self,
1058        entity: &Entity<T>,
1059        mut on_event: impl FnMut(Entity<T>, &Event, &mut App) + 'static,
1060    ) -> Subscription
1061    where
1062        T: 'static + EventEmitter<Event>,
1063        Event: 'static,
1064    {
1065        self.subscribe_internal(entity, move |entity, event, cx| {
1066            on_event(entity, event, cx);
1067            true
1068        })
1069    }
1070
1071    pub(crate) fn new_subscription(
1072        &mut self,
1073        key: EntityId,
1074        value: (TypeId, Listener),
1075    ) -> Subscription {
1076        let (subscription, activate) = self.event_listeners.insert(key, value);
1077        self.defer(move |_| activate());
1078        subscription
1079    }
1080    pub(crate) fn subscribe_internal<T, Evt>(
1081        &mut self,
1082        entity: &Entity<T>,
1083        mut on_event: impl FnMut(Entity<T>, &Evt, &mut App) -> bool + 'static,
1084    ) -> Subscription
1085    where
1086        T: 'static + EventEmitter<Evt>,
1087        Evt: 'static,
1088    {
1089        let entity_id = entity.entity_id();
1090        let handle = entity.downgrade();
1091        self.new_subscription(
1092            entity_id,
1093            (
1094                TypeId::of::<Evt>(),
1095                Box::new(move |event, cx| {
1096                    let event: &Evt = event.downcast_ref().expect("invalid event type");
1097                    if let Some(entity) = handle.upgrade() {
1098                        on_event(entity, event, cx)
1099                    } else {
1100                        false
1101                    }
1102                }),
1103            ),
1104        )
1105    }
1106
1107    /// Returns handles to all open windows in the application.
1108    /// Each handle could be downcast to a handle typed for the root view of that window.
1109    /// To find all windows of a given type, you could filter on
1110    pub fn windows(&self) -> Vec<AnyWindowHandle> {
1111        self.windows
1112            .keys()
1113            .flat_map(|window_id| self.window_handles.get(&window_id).copied())
1114            .collect()
1115    }
1116
1117    /// Returns the window handles ordered by their appearance on screen, front to back.
1118    ///
1119    /// The first window in the returned list is the active/topmost window of the application.
1120    ///
1121    /// This method returns None if the platform doesn't implement the method yet.
1122    pub fn window_stack(&self) -> Option<Vec<AnyWindowHandle>> {
1123        self.platform.window_stack()
1124    }
1125
1126    /// Returns a handle to the window that is currently focused at the platform level, if one exists.
1127    pub fn active_window(&self) -> Option<AnyWindowHandle> {
1128        self.platform.active_window()
1129    }
1130
1131    /// Opens a new window with the given option and the root view returned by the given function.
1132    /// The function is invoked with a `Window`, which can be used to interact with window-specific
1133    /// functionality.
1134    pub fn open_window<V: 'static + Render>(
1135        &mut self,
1136        options: crate::WindowOptions,
1137        build_root_view: impl FnOnce(&mut Window, &mut App) -> Entity<V>,
1138    ) -> anyhow::Result<WindowHandle<V>> {
1139        self.update(|cx| {
1140            let id = cx.windows.insert(None);
1141            let handle = WindowHandle::new(id);
1142            match Window::new(handle.into(), options, cx) {
1143                Ok(mut window) => {
1144                    cx.window_update_stack.push(id);
1145                    let root_view = build_root_view(&mut window, cx);
1146                    cx.window_update_stack.pop();
1147                    window.root.replace(root_view.into());
1148                    window.defer(cx, |window: &mut Window, cx| window.appearance_changed(cx));
1149
1150                    // allow a window to draw at least once before returning
1151                    // this didn't cause any issues on non windows platforms as it seems we always won the race to on_request_frame
1152                    // on windows we quite frequently lose the race and return a window that has never rendered, which leads to a crash
1153                    // where DispatchTree::root_node_id asserts on empty nodes
1154                    let clear = window.draw(cx);
1155                    clear.clear();
1156
1157                    cx.window_handles.insert(id, window.handle);
1158                    cx.windows.get_mut(id).unwrap().replace(window);
1159                    Ok(handle)
1160                }
1161                Err(e) => {
1162                    cx.windows.remove(id);
1163                    Err(e)
1164                }
1165            }
1166        })
1167    }
1168
1169    /// Instructs the platform to activate the application by bringing it to the foreground.
1170    pub fn activate(&self, ignoring_other_apps: bool) {
1171        self.platform.activate(ignoring_other_apps);
1172    }
1173
1174    /// Hide the application at the platform level.
1175    pub fn hide(&self) {
1176        self.platform.hide();
1177    }
1178
1179    /// Hide other applications at the platform level.
1180    pub fn hide_other_apps(&self) {
1181        self.platform.hide_other_apps();
1182    }
1183
1184    /// Unhide other applications at the platform level.
1185    pub fn unhide_other_apps(&self) {
1186        self.platform.unhide_other_apps();
1187    }
1188
1189    /// Set the system tray icon.
1190    pub fn set_tray_icon(&self, icon: Option<&[u8]>) {
1191        self.platform.set_tray_icon(icon);
1192    }
1193
1194    /// Set how the system tray icon should be rendered.
1195    pub fn set_tray_icon_rendering_mode(&self, rendering_mode: TrayIconRenderingMode) {
1196        self.platform.set_tray_icon_rendering_mode(rendering_mode);
1197    }
1198
1199    /// Set the system tray menu items.
1200    pub fn set_tray_menu(&self, menu: Vec<TrayMenuItem>) {
1201        self.platform.set_tray_menu(menu);
1202    }
1203
1204    /// Set the system tray tooltip.
1205    pub fn set_tray_tooltip(&self, tooltip: &str) {
1206        self.platform.set_tray_tooltip(tooltip);
1207    }
1208
1209    /// Enable or disable tray panel mode.
1210    /// When enabled, clicking the tray icon fires `TrayIconEvent::LeftClick` instead of showing the NSMenu.
1211    pub fn set_tray_panel_mode(&self, enabled: bool) {
1212        self.platform.set_tray_panel_mode(enabled);
1213    }
1214
1215    #[allow(missing_docs)]
1216    pub fn tray_icon_anchor(&self) -> Option<TrayAnchor> {
1217        self.platform.get_tray_icon_anchor()
1218    }
1219
1220    /// Get the screen bounds of the tray icon, useful for positioning a panel below it.
1221    pub fn tray_icon_bounds(&self) -> Option<Bounds<Pixels>> {
1222        self.platform.get_tray_icon_bounds()
1223    }
1224
1225    /// Build an approximate tray anchor from a screen position.
1226    ///
1227    /// This is useful on Linux StatusNotifierItem hosts, where click events
1228    /// provide a logical screen-coordinate hint but not the actual tray icon
1229    /// bounds. If the hint falls outside known displays, the primary display is
1230    /// used as a best-effort fallback so callers can still fall back from
1231    /// `WindowPosition::TrayAnchored` to a corner position if needed.
1232    pub fn tray_anchor_for_position(&self, position: Point<Pixels>) -> Option<TrayAnchor> {
1233        // This is a logical-size approximation of a tray icon, not a measured
1234        // host icon size. Linux SNI does not expose the actual icon bounds.
1235        const APPROXIMATE_TRAY_ICON_SIZE: Pixels = px(24.0);
1236
1237        let displays = self.displays();
1238        let display = displays
1239            .iter()
1240            .find(|display| display.bounds().contains(&position))
1241            .cloned()
1242            .or_else(|| self.primary_display())?;
1243        let display_bounds = display.bounds();
1244        let half_size = APPROXIMATE_TRAY_ICON_SIZE * 0.5;
1245        let local_position = position - display_bounds.origin;
1246
1247        Some(TrayAnchor {
1248            display_id: display.id(),
1249            bounds: Bounds::new(
1250                point(local_position.x - half_size, local_position.y - half_size),
1251                size(APPROXIMATE_TRAY_ICON_SIZE, APPROXIMATE_TRAY_ICON_SIZE),
1252            ),
1253        })
1254    }
1255
1256    /// Register a callback for system tray icon events.
1257    pub fn on_tray_icon_event(&self, mut callback: impl FnMut(TrayIconEvent, &mut App) + 'static) {
1258        let this = self.this.clone();
1259        self.platform.on_tray_icon_event(Box::new(move |event| {
1260            if let Some(app) = this.upgrade() {
1261                callback(event, &mut app.borrow_mut());
1262            }
1263        }));
1264    }
1265
1266    /// Register a callback for system tray icon click events with optional position information.
1267    pub fn on_tray_icon_click_event(
1268        &self,
1269        mut callback: impl FnMut(TrayIconClickEvent, &mut App) + 'static,
1270    ) {
1271        let this = self.this.clone();
1272        self.platform
1273            .on_tray_icon_click_event(Box::new(move |event| {
1274                if let Some(app) = this.upgrade() {
1275                    callback(event, &mut app.borrow_mut());
1276                }
1277            }));
1278    }
1279
1280    /// Register a callback for when a tray menu item is clicked.
1281    pub fn on_tray_menu_action(&self, mut callback: impl FnMut(SharedString, &mut App) + 'static) {
1282        let this = self.this.clone();
1283        self.platform.on_tray_menu_action(Box::new(move |id| {
1284            if let Some(app) = this.upgrade() {
1285                callback(id, &mut app.borrow_mut());
1286            }
1287        }));
1288    }
1289
1290    /// Register a global hotkey with the given ID and keystroke.
1291    pub fn register_global_hotkey(&self, id: u32, keystroke: &Keystroke) -> Result<()> {
1292        self.platform.register_global_hotkey(id, keystroke)
1293    }
1294
1295    /// Unregister a previously registered global hotkey.
1296    pub fn unregister_global_hotkey(&self, id: u32) {
1297        self.platform.unregister_global_hotkey(id);
1298    }
1299
1300    /// Register a callback for global hotkey events.
1301    pub fn on_global_hotkey(&self, callback: impl FnMut(u32) + 'static) {
1302        self.platform.on_global_hotkey(Box::new(callback));
1303    }
1304
1305    /// Get information about the currently focused window from any application.
1306    pub fn focused_window_info(&self) -> Option<FocusedWindowInfo> {
1307        self.platform.focused_window_info()
1308    }
1309
1310    /// Check accessibility permission status.
1311    pub fn accessibility_status(&self) -> PermissionStatus {
1312        self.platform.accessibility_status()
1313    }
1314
1315    /// Request accessibility permission from the user.
1316    pub fn request_accessibility_permission(&self) -> PermissionRequestStatus {
1317        self.platform.request_accessibility_permission()
1318    }
1319
1320    /// Check microphone permission status.
1321    pub fn microphone_status(&self) -> PermissionStatus {
1322        self.platform.microphone_status()
1323    }
1324
1325    /// Request microphone permission from the user.
1326    pub fn request_microphone_permission(
1327        &self,
1328        callback: impl FnOnce(bool) + 'static,
1329    ) -> PermissionRequestStatus {
1330        self.platform
1331            .request_microphone_permission(Box::new(callback))
1332    }
1333
1334    /// Set whether the application should auto-launch at login.
1335    pub fn set_auto_launch(&self, app_id: &str, enabled: bool) -> Result<()> {
1336        self.platform.set_auto_launch(app_id, enabled)
1337    }
1338
1339    /// Check whether the application is set to auto-launch at login.
1340    pub fn is_auto_launch_enabled(&self, app_id: &str) -> bool {
1341        self.platform.is_auto_launch_enabled(app_id)
1342    }
1343
1344    /// Show an OS notification.
1345    pub fn show_notification(&self, title: &str, body: &str) -> Result<()> {
1346        self.platform.show_notification(title, body)
1347    }
1348
1349    /// Configures when the application should automatically quit.
1350    /// By default, [`QuitMode::Default`] is used.
1351    pub fn set_quit_mode(&mut self, mode: QuitMode) {
1352        self.quit_mode = mode;
1353        self.platform.set_quit_mode(mode);
1354    }
1355
1356    /// Register a callback for system power events (sleep, wake, shutdown).
1357    pub fn on_system_power_event(
1358        &self,
1359        mut callback: impl FnMut(SystemPowerEvent, &mut App) + 'static,
1360    ) {
1361        let this = self.this.clone();
1362        self.platform.on_system_power_event(Box::new(move |event| {
1363            if let Some(app) = this.upgrade() {
1364                callback(event, &mut app.borrow_mut());
1365            }
1366        }));
1367    }
1368
1369    /// Start a power save blocker to prevent the system from sleeping or the display from dimming.
1370    pub fn start_power_save_blocker(&self, kind: PowerSaveBlockerKind) -> Option<u32> {
1371        self.platform.start_power_save_blocker(kind)
1372    }
1373
1374    /// Stop a previously started power save blocker by its ID.
1375    pub fn stop_power_save_blocker(&self, id: u32) {
1376        self.platform.stop_power_save_blocker(id);
1377    }
1378
1379    /// Get the duration since the last user input event.
1380    pub fn system_idle_time(&self) -> Option<Duration> {
1381        self.platform.system_idle_time()
1382    }
1383
1384    /// Get the current network connectivity status.
1385    pub fn network_status(&self) -> NetworkStatus {
1386        self.platform.network_status()
1387    }
1388
1389    /// Register a callback for network connectivity status changes.
1390    pub fn on_network_status_change(
1391        &self,
1392        mut callback: impl FnMut(NetworkStatus, &mut App) + 'static,
1393    ) {
1394        let this = self.this.clone();
1395        self.platform
1396            .on_network_status_change(Box::new(move |status| {
1397                if let Some(app) = this.upgrade() {
1398                    callback(status, &mut app.borrow_mut());
1399                }
1400            }));
1401    }
1402
1403    /// Register a callback for media key events (play, pause, next, previous).
1404    pub fn on_media_key_event(&self, mut callback: impl FnMut(MediaKeyEvent, &mut App) + 'static) {
1405        let this = self.this.clone();
1406        self.platform.on_media_key_event(Box::new(move |event| {
1407            if let Some(app) = this.upgrade() {
1408                callback(event, &mut app.borrow_mut());
1409            }
1410        }));
1411    }
1412
1413    /// Request the user's attention by bouncing the dock icon or flashing the taskbar.
1414    pub fn request_user_attention(&self, attention_type: AttentionType) {
1415        self.platform.request_user_attention(attention_type);
1416    }
1417
1418    /// Cancel a previous user attention request.
1419    pub fn cancel_user_attention(&self) {
1420        self.platform.cancel_user_attention();
1421    }
1422
1423    /// Set the dock badge label (macOS) or taskbar overlay text.
1424    pub fn set_dock_badge(&self, label: Option<&str>) {
1425        self.platform.set_dock_badge(label);
1426    }
1427
1428    /// Show a context menu at the given screen position with the specified menu items.
1429    pub fn show_context_menu(
1430        &self,
1431        position: Point<Pixels>,
1432        items: Vec<TrayMenuItem>,
1433        mut callback: impl FnMut(SharedString, &mut App) + 'static,
1434    ) {
1435        let this = self.this.clone();
1436        self.platform.show_context_menu(
1437            position,
1438            items,
1439            Box::new(move |id| {
1440                if let Some(app) = this.upgrade() {
1441                    callback(id, &mut app.borrow_mut());
1442                }
1443            }),
1444        );
1445    }
1446
1447    /// Show a native dialog with the given options, returning the index of the clicked button.
1448    pub fn show_dialog(&self, options: DialogOptions) -> oneshot::Receiver<usize> {
1449        self.platform.show_dialog(options)
1450    }
1451
1452    /// Get operating system information (name, version, architecture).
1453    pub fn os_info(&self) -> OsInfo {
1454        self.platform.os_info()
1455    }
1456
1457    /// Check whether biometric authentication (Touch ID, Windows Hello) is available.
1458    pub fn biometric_status(&self) -> BiometricStatus {
1459        self.platform.biometric_status()
1460    }
1461
1462    /// Authenticate the user via biometrics with the given reason string.
1463    pub fn authenticate_biometric(
1464        &self,
1465        reason: &str,
1466        callback: impl FnOnce(bool) + Send + 'static,
1467    ) {
1468        self.platform
1469            .authenticate_biometric(reason, Box::new(callback));
1470    }
1471
1472    /// Install a panic hook that captures crash reports with backtraces and OS info.
1473    pub fn set_crash_handler(
1474        &self,
1475        app_version: Option<String>,
1476        handler: impl Fn(CrashReport) + Send + Sync + 'static,
1477    ) {
1478        let os_info = self.platform.os_info();
1479        let handler = std::sync::Arc::new(handler);
1480        std::panic::set_hook(Box::new(move |panic_info| {
1481            let message = if let Some(msg) = panic_info.payload().downcast_ref::<&str>() {
1482                msg.to_string()
1483            } else if let Some(msg) = panic_info.payload().downcast_ref::<String>() {
1484                msg.clone()
1485            } else {
1486                "Unknown panic".to_string()
1487            };
1488
1489            let location = panic_info
1490                .location()
1491                .map(|loc| format!("{}:{}:{}", loc.file(), loc.line(), loc.column()))
1492                .unwrap_or_default();
1493
1494            let full_message = if location.is_empty() {
1495                message
1496            } else {
1497                format!("{message} at {location}")
1498            };
1499
1500            let backtrace = std::backtrace::Backtrace::force_capture().to_string();
1501
1502            let report = CrashReport {
1503                message: full_message,
1504                backtrace,
1505                os_info: os_info.clone(),
1506                app_version: app_version.clone(),
1507            };
1508
1509            handler(report);
1510        }));
1511    }
1512
1513    /// Returns the list of currently active displays.
1514    pub fn displays(&self) -> Vec<Rc<dyn PlatformDisplay>> {
1515        self.platform.displays()
1516    }
1517
1518    /// Returns the primary display that will be used for new windows.
1519    pub fn primary_display(&self) -> Option<Rc<dyn PlatformDisplay>> {
1520        self.platform.primary_display()
1521    }
1522
1523    /// Compute window bounds from a desired size and a semantic position.
1524    pub fn compute_window_bounds(
1525        &self,
1526        size: Size<Pixels>,
1527        position: &WindowPosition,
1528    ) -> Bounds<Pixels> {
1529        let displays = self.platform.displays();
1530        let primary = self.platform.primary_display();
1531        crate::platform::window_positioner::compute_window_bounds(
1532            size,
1533            position,
1534            &displays,
1535            primary.as_ref(),
1536        )
1537    }
1538
1539    /// Returns whether `screen_capture_sources` may work.
1540    pub fn is_screen_capture_supported(&self) -> bool {
1541        self.platform.is_screen_capture_supported()
1542    }
1543
1544    /// Returns a list of available screen capture sources.
1545    pub fn screen_capture_sources(
1546        &self,
1547    ) -> oneshot::Receiver<Result<Vec<Rc<dyn ScreenCaptureSource>>>> {
1548        self.platform.screen_capture_sources()
1549    }
1550
1551    /// Returns the display with the given ID, if one exists.
1552    pub fn find_display(&self, id: DisplayId) -> Option<Rc<dyn PlatformDisplay>> {
1553        self.displays()
1554            .iter()
1555            .find(|display| display.id() == id)
1556            .cloned()
1557    }
1558
1559    /// Returns the appearance of the application's windows.
1560    pub fn window_appearance(&self) -> WindowAppearance {
1561        self.platform.window_appearance()
1562    }
1563
1564    /// Overrides the appearance (light/dark) applied to the app's windows, independent of
1565    /// the OS-wide setting. Pass `None` to clear the override and follow the system again.
1566    /// The current value is reported by [`App::window_appearance`].
1567    ///
1568    /// On macOS this sets the underlying `NSApplication.appearance`, which controls the
1569    /// native window chrome (the window border and titlebar) of every window. Use this
1570    /// when the app uses a dark theme while the system is in light mode (or vice versa)
1571    /// so the window edges render to match the theme. While an appearance is forced,
1572    /// windows stop tracking system light/dark changes; pass `None` to resume following
1573    /// the system. On other platforms the override is stored and reported by
1574    /// [`App::window_appearance`] without changing native chrome.
1575    pub fn set_window_appearance(&self, appearance: Option<WindowAppearance>) {
1576        self.platform.set_window_appearance(appearance);
1577    }
1578
1579    /// Writes data to the primary selection buffer.
1580    /// Only available on Linux.
1581    #[cfg(any(target_os = "linux", target_os = "freebsd"))]
1582    pub fn write_to_primary(&self, item: ClipboardItem) {
1583        self.platform.write_to_primary(item)
1584    }
1585
1586    /// Writes data to the platform clipboard.
1587    pub fn write_to_clipboard(&self, item: ClipboardItem) {
1588        self.platform.write_to_clipboard(item)
1589    }
1590
1591    /// Reads data from the primary selection buffer.
1592    /// Only available on Linux.
1593    #[cfg(any(target_os = "linux", target_os = "freebsd"))]
1594    pub fn read_from_primary(&self) -> Option<ClipboardItem> {
1595        self.platform.read_from_primary()
1596    }
1597
1598    /// Reads data from the platform clipboard.
1599    pub fn read_from_clipboard(&self) -> Option<ClipboardItem> {
1600        self.platform.read_from_clipboard()
1601    }
1602
1603    /// Writes credentials to the platform keychain.
1604    pub fn write_credentials(
1605        &self,
1606        url: &str,
1607        username: &str,
1608        password: &[u8],
1609    ) -> Task<Result<()>> {
1610        self.platform.write_credentials(url, username, password)
1611    }
1612
1613    /// Reads credentials from the platform keychain.
1614    pub fn read_credentials(&self, url: &str) -> Task<Result<Option<(String, Vec<u8>)>>> {
1615        self.platform.read_credentials(url)
1616    }
1617
1618    /// Deletes credentials from the platform keychain.
1619    pub fn delete_credentials(&self, url: &str) -> Task<Result<()>> {
1620        self.platform.delete_credentials(url)
1621    }
1622
1623    /// Directs the platform's default browser to open the given URL.
1624    pub fn open_url(&self, url: &str) {
1625        self.platform.open_url(url);
1626    }
1627
1628    /// Registers the given URL scheme (e.g. `zed` for `zed://` urls) to be
1629    /// opened by the current app.
1630    ///
1631    /// On some platforms (e.g. macOS) you may be able to register URL schemes
1632    /// as part of app distribution, but this method exists to let you register
1633    /// schemes at runtime.
1634    pub fn register_url_scheme(&self, scheme: &str) -> Task<Result<()>> {
1635        self.platform.register_url_scheme(scheme)
1636    }
1637
1638    /// Returns the full pathname of the current app bundle.
1639    ///
1640    /// Returns an error if the app is not being run from a bundle.
1641    pub fn app_path(&self) -> Result<PathBuf> {
1642        self.platform.app_path()
1643    }
1644
1645    /// On Linux, returns the name of the compositor in use.
1646    ///
1647    /// Returns an empty string on other platforms.
1648    pub fn compositor_name(&self) -> &'static str {
1649        self.platform.compositor_name()
1650    }
1651
1652    /// Returns the file URL of the executable with the specified name in the application bundle
1653    pub fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf> {
1654        self.platform.path_for_auxiliary_executable(name)
1655    }
1656
1657    /// Displays a platform modal for selecting paths.
1658    ///
1659    /// When one or more paths are selected, they'll be relayed asynchronously via the returned oneshot channel.
1660    /// If cancelled, a `None` will be relayed instead.
1661    /// May return an error on Linux if the file picker couldn't be opened.
1662    pub fn prompt_for_paths(
1663        &self,
1664        options: PathPromptOptions,
1665    ) -> oneshot::Receiver<Result<Option<Vec<PathBuf>>>> {
1666        self.platform.prompt_for_paths(options)
1667    }
1668
1669    /// Displays a platform modal for selecting a new path where a file can be saved.
1670    ///
1671    /// The provided directory will be used to set the initial location.
1672    /// When a path is selected, it is relayed asynchronously via the returned oneshot channel.
1673    /// If cancelled, a `None` will be relayed instead.
1674    /// May return an error on Linux if the file picker couldn't be opened.
1675    pub fn prompt_for_new_path(
1676        &self,
1677        directory: &Path,
1678        suggested_name: Option<&str>,
1679    ) -> oneshot::Receiver<Result<Option<PathBuf>>> {
1680        self.platform.prompt_for_new_path(directory, suggested_name)
1681    }
1682
1683    /// Reveals the specified path at the platform level, such as in Finder on macOS.
1684    pub fn reveal_path(&self, path: &Path) {
1685        self.platform.reveal_path(path)
1686    }
1687
1688    /// Opens the specified path with the system's default application.
1689    pub fn open_with_system(&self, path: &Path) {
1690        self.platform.open_with_system(path)
1691    }
1692
1693    /// Returns whether the user has configured scrollbars to auto-hide at the platform level.
1694    pub fn should_auto_hide_scrollbars(&self) -> bool {
1695        self.platform.should_auto_hide_scrollbars()
1696    }
1697
1698    /// Restarts the application.
1699    pub fn restart(&mut self) {
1700        self.restart_observers
1701            .clone()
1702            .retain(&(), |observer| observer(self));
1703        self.platform.restart(self.restart_path.take())
1704    }
1705
1706    /// Sets the path to use when restarting the application.
1707    pub fn set_restart_path(&mut self, path: PathBuf) {
1708        self.restart_path = Some(path);
1709    }
1710
1711    /// Returns the HTTP client for the application.
1712    pub fn http_client(&self) -> Arc<dyn HttpClient> {
1713        self.http_client.clone()
1714    }
1715
1716    /// Sets the HTTP client for the application.
1717    pub fn set_http_client(&mut self, new_client: Arc<dyn HttpClient>) {
1718        self.http_client = new_client;
1719    }
1720
1721    /// Returns the SVG renderer used by the application.
1722    pub fn svg_renderer(&self) -> SvgRenderer {
1723        self.svg_renderer.clone()
1724    }
1725
1726    pub(crate) fn push_effect(&mut self, effect: Effect) {
1727        match &effect {
1728            Effect::Notify { emitter } => {
1729                if !self.pending_notifications.insert(*emitter) {
1730                    return;
1731                }
1732            }
1733            Effect::NotifyGlobalObservers { global_type } => {
1734                if !self.pending_global_notifications.insert(*global_type) {
1735                    return;
1736                }
1737            }
1738            _ => {}
1739        };
1740
1741        self.pending_effects.push_back(effect);
1742    }
1743
1744    /// Called at the end of [`App::update`] to complete any side effects
1745    /// such as notifying observers, emitting events, etc. Effects can themselves
1746    /// cause effects, so we continue looping until all effects are processed.
1747    fn flush_effects(&mut self) {
1748        loop {
1749            self.release_dropped_entities();
1750            self.release_dropped_focus_handles();
1751            if let Some(effect) = self.pending_effects.pop_front() {
1752                match effect {
1753                    Effect::Notify { emitter } => {
1754                        self.apply_notify_effect(emitter);
1755                    }
1756
1757                    Effect::Emit {
1758                        emitter,
1759                        event_type,
1760                        event,
1761                    } => self.apply_emit_effect(emitter, event_type, event),
1762
1763                    Effect::RefreshWindows => {
1764                        self.apply_refresh_effect();
1765                    }
1766
1767                    Effect::NotifyGlobalObservers { global_type } => {
1768                        self.apply_notify_global_observers_effect(global_type);
1769                    }
1770
1771                    Effect::Defer { callback } => {
1772                        self.apply_defer_effect(callback);
1773                    }
1774                    Effect::EntityCreated {
1775                        entity,
1776                        tid,
1777                        window,
1778                    } => {
1779                        self.apply_entity_created_effect(entity, tid, window);
1780                    }
1781                }
1782            } else {
1783                #[cfg(any(test, feature = "test-support"))]
1784                for window in self
1785                    .windows
1786                    .values()
1787                    .filter_map(|window| {
1788                        let window = window.as_ref()?;
1789                        window.invalidator.is_dirty().then_some(window.handle)
1790                    })
1791                    .collect::<Vec<_>>()
1792                {
1793                    self.update_window(window, |_, window, cx| window.draw(cx).clear())
1794                        .unwrap();
1795                }
1796
1797                if self.pending_effects.is_empty() {
1798                    for window in self.windows.values().filter_map(|window| window.as_ref()) {
1799                        if window.invalidator.is_dirty()
1800                            || window.needs_present.get()
1801                            || !window.next_frame_callbacks.borrow().is_empty()
1802                        {
1803                            window.platform_window.schedule_frame();
1804                        }
1805                    }
1806
1807                    break;
1808                }
1809            }
1810        }
1811    }
1812
1813    /// Repeatedly called during `flush_effects` to release any entities whose
1814    /// reference count has become zero. We invoke any release observers before dropping
1815    /// each entity.
1816    fn release_dropped_entities(&mut self) {
1817        loop {
1818            let dropped = self.entities.take_dropped();
1819            if dropped.is_empty() {
1820                break;
1821            }
1822
1823            for (entity_id, mut entity) in dropped {
1824                self.observers.remove(&entity_id);
1825                self.event_listeners.remove(&entity_id);
1826                for release_callback in self.release_listeners.remove(&entity_id) {
1827                    release_callback(entity.as_mut(), self);
1828                }
1829            }
1830        }
1831    }
1832
1833    /// Repeatedly called during `flush_effects` to handle a focused handle being dropped.
1834    fn release_dropped_focus_handles(&mut self) {
1835        self.focus_handles
1836            .clone()
1837            .write()
1838            .retain(|handle_id, focus| {
1839                if focus.ref_count.load(SeqCst) == 0 {
1840                    for window_handle in self.windows() {
1841                        window_handle
1842                            .update(self, |_, window, cx| {
1843                                if window.focus == Some(handle_id) {
1844                                    window.blur(cx);
1845                                }
1846                            })
1847                            .unwrap();
1848                    }
1849                    false
1850                } else {
1851                    true
1852                }
1853            });
1854    }
1855
1856    fn apply_notify_effect(&mut self, emitter: EntityId) {
1857        self.pending_notifications.remove(&emitter);
1858
1859        self.observers
1860            .clone()
1861            .retain(&emitter, |handler| handler(self));
1862    }
1863
1864    fn apply_emit_effect(&mut self, emitter: EntityId, event_type: TypeId, event: Box<dyn Any>) {
1865        self.event_listeners
1866            .clone()
1867            .retain(&emitter, |(stored_type, handler)| {
1868                if *stored_type == event_type {
1869                    handler(event.as_ref(), self)
1870                } else {
1871                    true
1872                }
1873            });
1874    }
1875
1876    fn apply_refresh_effect(&mut self) {
1877        for window in self.windows.values_mut() {
1878            if let Some(window) = window.as_mut() {
1879                window.refreshing = true;
1880                window.invalidator.set_dirty(true);
1881            }
1882        }
1883    }
1884
1885    fn apply_notify_global_observers_effect(&mut self, type_id: TypeId) {
1886        self.pending_global_notifications.remove(&type_id);
1887        self.global_observers
1888            .clone()
1889            .retain(&type_id, |observer| observer(self));
1890    }
1891
1892    fn apply_defer_effect(&mut self, callback: Box<dyn FnOnce(&mut Self) + 'static>) {
1893        callback(self);
1894    }
1895
1896    fn apply_entity_created_effect(
1897        &mut self,
1898        entity: AnyEntity,
1899        tid: TypeId,
1900        window: Option<WindowId>,
1901    ) {
1902        self.new_entity_observers.clone().retain(&tid, |observer| {
1903            if let Some(id) = window {
1904                self.update_window_id(id, {
1905                    let entity = entity.clone();
1906                    |_, window, cx| (observer)(entity, &mut Some(window), cx)
1907                })
1908                .expect("All windows should be off the stack when flushing effects");
1909            } else {
1910                (observer)(entity.clone(), &mut None, self)
1911            }
1912            true
1913        });
1914    }
1915
1916    fn update_window_id<T, F>(&mut self, id: WindowId, update: F) -> Result<T>
1917    where
1918        F: FnOnce(AnyView, &mut Window, &mut App) -> T,
1919    {
1920        self.update(|cx| {
1921            let mut window = cx.windows.get_mut(id)?.take()?;
1922
1923            let root_view = window.root.clone().unwrap();
1924
1925            cx.window_update_stack.push(window.handle.id);
1926            let result = update(root_view, &mut window, cx);
1927            cx.window_update_stack.pop();
1928
1929            if window.removed {
1930                cx.window_handles.remove(&id);
1931                cx.windows.remove(id);
1932
1933                cx.window_closed_observers.clone().retain(&(), |callback| {
1934                    callback(cx);
1935                    true
1936                });
1937
1938                let quit_on_empty = match cx.quit_mode {
1939                    QuitMode::Explicit => false,
1940                    QuitMode::LastWindowClosed => true,
1941                    QuitMode::Default => cfg!(not(target_os = "macos")),
1942                };
1943
1944                if quit_on_empty && cx.windows.is_empty() {
1945                    cx.quit();
1946                }
1947            } else {
1948                cx.windows.get_mut(id)?.replace(window);
1949            }
1950
1951            Some(result)
1952        })
1953        .context("window not found")
1954    }
1955
1956    /// Creates an `AsyncApp`, which can be cloned and has a static lifetime
1957    /// so it can be held across `await` points.
1958    pub fn to_async(&self) -> AsyncApp {
1959        AsyncApp {
1960            app: self.this.clone(),
1961            background_executor: self.background_executor.clone(),
1962            foreground_executor: self.foreground_executor.clone(),
1963        }
1964    }
1965
1966    /// Obtains a reference to the executor, which can be used to spawn futures.
1967    pub fn background_executor(&self) -> &BackgroundExecutor {
1968        &self.background_executor
1969    }
1970
1971    /// Obtains a reference to the executor, which can be used to spawn futures.
1972    pub fn foreground_executor(&self) -> &ForegroundExecutor {
1973        if self.quitting {
1974            panic!("Can't spawn on main thread after on_app_quit")
1975        };
1976        &self.foreground_executor
1977    }
1978
1979    /// Spawns the future returned by the given function on the main thread. The closure will be invoked
1980    /// with [AsyncApp], which allows the application state to be accessed across await points.
1981    #[track_caller]
1982    pub fn spawn<AsyncFn, R>(&self, f: AsyncFn) -> Task<R>
1983    where
1984        AsyncFn: AsyncFnOnce(&mut AsyncApp) -> R + 'static,
1985        R: 'static,
1986    {
1987        if self.quitting {
1988            debug_panic!("Can't spawn on main thread after on_app_quit")
1989        };
1990
1991        let mut cx = self.to_async();
1992
1993        self.foreground_executor
1994            .spawn(async move { f(&mut cx).await })
1995    }
1996
1997    /// Schedules the given function to be run at the end of the current effect cycle, allowing entities
1998    /// that are currently on the stack to be returned to the app.
1999    pub fn defer(&mut self, f: impl FnOnce(&mut App) + 'static) {
2000        self.push_effect(Effect::Defer {
2001            callback: Box::new(f),
2002        });
2003    }
2004
2005    /// Accessor for the application's asset source, which is provided when constructing the `App`.
2006    pub fn asset_source(&self) -> &Arc<dyn AssetSource> {
2007        &self.asset_source
2008    }
2009
2010    /// Accessor for the text system.
2011    pub fn text_system(&self) -> &Arc<TextSystem> {
2012        &self.text_system
2013    }
2014
2015    /// Check whether a global of the given type has been assigned.
2016    pub fn has_global<G: Global>(&self) -> bool {
2017        self.globals_by_type.contains_key(&TypeId::of::<G>())
2018    }
2019
2020    /// Access the global of the given type. Panics if a global for that type has not been assigned.
2021    #[track_caller]
2022    pub fn global<G: Global>(&self) -> &G {
2023        self.globals_by_type
2024            .get(&TypeId::of::<G>())
2025            .map(|any_state| any_state.downcast_ref::<G>().unwrap())
2026            .with_context(|| format!("no state of type {} exists", type_name::<G>()))
2027            .unwrap()
2028    }
2029
2030    /// Access the global of the given type if a value has been assigned.
2031    pub fn try_global<G: Global>(&self) -> Option<&G> {
2032        self.globals_by_type
2033            .get(&TypeId::of::<G>())
2034            .map(|any_state| any_state.downcast_ref::<G>().unwrap())
2035    }
2036
2037    /// Access the global of the given type mutably. Panics if a global for that type has not been assigned.
2038    #[track_caller]
2039    pub fn global_mut<G: Global>(&mut self) -> &mut G {
2040        let global_type = TypeId::of::<G>();
2041        self.push_effect(Effect::NotifyGlobalObservers { global_type });
2042        self.globals_by_type
2043            .get_mut(&global_type)
2044            .and_then(|any_state| any_state.downcast_mut::<G>())
2045            .with_context(|| format!("no state of type {} exists", type_name::<G>()))
2046            .unwrap()
2047    }
2048
2049    /// Access the global of the given type mutably. A default value is assigned if a global of this type has not
2050    /// yet been assigned.
2051    pub fn default_global<G: Global + Default>(&mut self) -> &mut G {
2052        let global_type = TypeId::of::<G>();
2053        self.push_effect(Effect::NotifyGlobalObservers { global_type });
2054        self.globals_by_type
2055            .entry(global_type)
2056            .or_insert_with(|| Box::<G>::default())
2057            .downcast_mut::<G>()
2058            .unwrap()
2059    }
2060
2061    /// Sets the value of the global of the given type.
2062    pub fn set_global<G: Global>(&mut self, global: G) {
2063        let global_type = TypeId::of::<G>();
2064        self.push_effect(Effect::NotifyGlobalObservers { global_type });
2065        self.globals_by_type.insert(global_type, Box::new(global));
2066    }
2067
2068    /// Clear all stored globals. Does not notify global observers.
2069    #[cfg(any(test, feature = "test-support"))]
2070    pub fn clear_globals(&mut self) {
2071        self.globals_by_type.drain();
2072    }
2073
2074    /// Remove the global of the given type from the app context. Does not notify global observers.
2075    pub fn remove_global<G: Global>(&mut self) -> G {
2076        let global_type = TypeId::of::<G>();
2077        self.push_effect(Effect::NotifyGlobalObservers { global_type });
2078        *self
2079            .globals_by_type
2080            .remove(&global_type)
2081            .unwrap_or_else(|| panic!("no global added for {}", std::any::type_name::<G>()))
2082            .downcast()
2083            .unwrap()
2084    }
2085
2086    /// Register a callback to be invoked when a global of the given type is updated.
2087    pub fn observe_global<G: Global>(
2088        &mut self,
2089        mut f: impl FnMut(&mut Self) + 'static,
2090    ) -> Subscription {
2091        let (subscription, activate) = self.global_observers.insert(
2092            TypeId::of::<G>(),
2093            Box::new(move |cx| {
2094                f(cx);
2095                true
2096            }),
2097        );
2098        self.defer(move |_| activate());
2099        subscription
2100    }
2101
2102    /// Move the global of the given type to the stack.
2103    #[track_caller]
2104    pub(crate) fn lease_global<G: Global>(&mut self) -> GlobalLease<G> {
2105        GlobalLease::new(
2106            self.globals_by_type
2107                .remove(&TypeId::of::<G>())
2108                .with_context(|| format!("no global registered of type {}", type_name::<G>()))
2109                .unwrap(),
2110        )
2111    }
2112
2113    /// Restore the global of the given type after it is moved to the stack.
2114    pub(crate) fn end_global_lease<G: Global>(&mut self, lease: GlobalLease<G>) {
2115        let global_type = TypeId::of::<G>();
2116
2117        self.push_effect(Effect::NotifyGlobalObservers { global_type });
2118        self.globals_by_type.insert(global_type, lease.global);
2119    }
2120
2121    pub(crate) fn new_entity_observer(
2122        &self,
2123        key: TypeId,
2124        value: NewEntityListener,
2125    ) -> Subscription {
2126        let (subscription, activate) = self.new_entity_observers.insert(key, value);
2127        activate();
2128        subscription
2129    }
2130
2131    /// Arrange for the given function to be invoked whenever a view of the specified type is created.
2132    /// The function will be passed a mutable reference to the view along with an appropriate context.
2133    pub fn observe_new<T: 'static>(
2134        &self,
2135        on_new: impl 'static + Fn(&mut T, Option<&mut Window>, &mut Context<T>),
2136    ) -> Subscription {
2137        self.new_entity_observer(
2138            TypeId::of::<T>(),
2139            Box::new(
2140                move |any_entity: AnyEntity, window: &mut Option<&mut Window>, cx: &mut App| {
2141                    any_entity
2142                        .downcast::<T>()
2143                        .unwrap()
2144                        .update(cx, |entity_state, cx| {
2145                            on_new(entity_state, window.as_deref_mut(), cx)
2146                        })
2147                },
2148            ),
2149        )
2150    }
2151
2152    /// Observe the release of a entity. The callback is invoked after the entity
2153    /// has no more strong references but before it has been dropped.
2154    pub fn observe_release<T>(
2155        &self,
2156        handle: &Entity<T>,
2157        on_release: impl FnOnce(&mut T, &mut App) + 'static,
2158    ) -> Subscription
2159    where
2160        T: 'static,
2161    {
2162        let (subscription, activate) = self.release_listeners.insert(
2163            handle.entity_id(),
2164            Box::new(move |entity, cx| {
2165                let entity = entity.downcast_mut().expect("invalid entity type");
2166                on_release(entity, cx)
2167            }),
2168        );
2169        activate();
2170        subscription
2171    }
2172
2173    /// Observe the release of a entity. The callback is invoked after the entity
2174    /// has no more strong references but before it has been dropped.
2175    pub fn observe_release_in<T>(
2176        &self,
2177        handle: &Entity<T>,
2178        window: &Window,
2179        on_release: impl FnOnce(&mut T, &mut Window, &mut App) + 'static,
2180    ) -> Subscription
2181    where
2182        T: 'static,
2183    {
2184        let window_handle = window.handle;
2185        self.observe_release(handle, move |entity, cx| {
2186            let _ = window_handle.update(cx, |_, window, cx| on_release(entity, window, cx));
2187        })
2188    }
2189
2190    /// Register a callback to be invoked when a keystroke is received by the application
2191    /// in any window. Note that this fires after all other action and event mechanisms have resolved
2192    /// and that this API will not be invoked if the event's propagation is stopped.
2193    pub fn observe_keystrokes(
2194        &mut self,
2195        mut f: impl FnMut(&KeystrokeEvent, &mut Window, &mut App) + 'static,
2196    ) -> Subscription {
2197        fn inner(
2198            keystroke_observers: &SubscriberSet<(), KeystrokeObserver>,
2199            handler: KeystrokeObserver,
2200        ) -> Subscription {
2201            let (subscription, activate) = keystroke_observers.insert((), handler);
2202            activate();
2203            subscription
2204        }
2205
2206        inner(
2207            &self.keystroke_observers,
2208            Box::new(move |event, window, cx| {
2209                f(event, window, cx);
2210                true
2211            }),
2212        )
2213    }
2214
2215    /// Register a callback to be invoked when a keystroke is received by the application
2216    /// in any window. Note that this fires _before_ all other action and event mechanisms have resolved
2217    /// unlike [`App::observe_keystrokes`] which fires after. This means that `cx.stop_propagation` calls
2218    /// within interceptors will prevent action dispatch
2219    pub fn intercept_keystrokes(
2220        &mut self,
2221        mut f: impl FnMut(&KeystrokeEvent, &mut Window, &mut App) + 'static,
2222    ) -> Subscription {
2223        fn inner(
2224            keystroke_interceptors: &SubscriberSet<(), KeystrokeObserver>,
2225            handler: KeystrokeObserver,
2226        ) -> Subscription {
2227            let (subscription, activate) = keystroke_interceptors.insert((), handler);
2228            activate();
2229            subscription
2230        }
2231
2232        inner(
2233            &self.keystroke_interceptors,
2234            Box::new(move |event, window, cx| {
2235                f(event, window, cx);
2236                true
2237            }),
2238        )
2239    }
2240
2241    /// Register key bindings.
2242    pub fn bind_keys(&mut self, bindings: impl IntoIterator<Item = KeyBinding>) {
2243        self.keymap.borrow_mut().add_bindings(bindings);
2244        self.pending_effects.push_back(Effect::RefreshWindows);
2245    }
2246
2247    /// Clear all key bindings in the app.
2248    pub fn clear_key_bindings(&mut self) {
2249        self.keymap.borrow_mut().clear();
2250        self.pending_effects.push_back(Effect::RefreshWindows);
2251    }
2252
2253    /// Get all key bindings in the app.
2254    pub fn key_bindings(&self) -> Rc<RefCell<Keymap>> {
2255        self.keymap.clone()
2256    }
2257
2258    /// Register a global handler for actions invoked via the keyboard. These handlers are run at
2259    /// the end of the bubble phase for actions, and so will only be invoked if there are no other
2260    /// handlers or if they called `cx.propagate()`.
2261    pub fn on_action<A: Action>(&mut self, listener: impl Fn(&A, &mut Self) + 'static) {
2262        self.global_action_listeners
2263            .entry(TypeId::of::<A>())
2264            .or_default()
2265            .push(Rc::new(move |action, phase, cx| {
2266                if phase == DispatchPhase::Bubble {
2267                    let action = action.downcast_ref().unwrap();
2268                    listener(action, cx)
2269                }
2270            }));
2271    }
2272
2273    /// Event handlers propagate events by default. Call this method to stop dispatching to
2274    /// event handlers with a lower z-index (mouse) or higher in the tree (keyboard). This is
2275    /// the opposite of [`Self::propagate`]. It's also possible to cancel a call to [`Self::propagate`] by
2276    /// calling this method before effects are flushed.
2277    pub fn stop_propagation(&mut self) {
2278        self.propagate_event = false;
2279    }
2280
2281    /// Action handlers stop propagation by default during the bubble phase of action dispatch
2282    /// dispatching to action handlers higher in the element tree. This is the opposite of
2283    /// [`Self::stop_propagation`]. It's also possible to cancel a call to [`Self::stop_propagation`] by calling
2284    /// this method before effects are flushed.
2285    pub fn propagate(&mut self) {
2286        self.propagate_event = true;
2287    }
2288
2289    /// Build an action from some arbitrary data, typically a keymap entry.
2290    pub fn build_action(
2291        &self,
2292        name: &str,
2293        data: Option<serde_json::Value>,
2294    ) -> std::result::Result<Box<dyn Action>, ActionBuildError> {
2295        self.actions.build_action(name, data)
2296    }
2297
2298    /// Get all action names that have been registered. Note that registration only allows for
2299    /// actions to be built dynamically, and is unrelated to binding actions in the element tree.
2300    pub fn all_action_names(&self) -> &[&'static str] {
2301        self.actions.all_action_names()
2302    }
2303
2304    /// Returns key bindings that invoke the given action on the currently focused element, without
2305    /// checking context. Bindings are returned in the order they were added. For display, the last
2306    /// binding should take precedence.
2307    pub fn all_bindings_for_input(&self, input: &[Keystroke]) -> Vec<KeyBinding> {
2308        RefCell::borrow(&self.keymap).all_bindings_for_input(input)
2309    }
2310
2311    /// Get all non-internal actions that have been registered, along with their schemas.
2312    pub fn action_schemas(
2313        &self,
2314        generator: &mut schemars::SchemaGenerator,
2315    ) -> Vec<(&'static str, Option<schemars::Schema>)> {
2316        self.actions.action_schemas(generator)
2317    }
2318
2319    /// Get a map from a deprecated action name to the canonical name.
2320    pub fn deprecated_actions_to_preferred_actions(&self) -> &HashMap<&'static str, &'static str> {
2321        self.actions.deprecated_aliases()
2322    }
2323
2324    /// Get a map from an action name to the deprecation messages.
2325    pub fn action_deprecation_messages(&self) -> &HashMap<&'static str, &'static str> {
2326        self.actions.deprecation_messages()
2327    }
2328
2329    /// Get a map from an action name to the documentation.
2330    pub fn action_documentation(&self) -> &HashMap<&'static str, &'static str> {
2331        self.actions.documentation()
2332    }
2333
2334    /// Register a callback to be invoked when the application is about to quit.
2335    /// It is not possible to cancel the quit event at this point.
2336    pub fn on_app_quit<Fut>(
2337        &self,
2338        mut on_quit: impl FnMut(&mut App) -> Fut + 'static,
2339    ) -> Subscription
2340    where
2341        Fut: 'static + Future<Output = ()>,
2342    {
2343        let (subscription, activate) = self.quit_observers.insert(
2344            (),
2345            Box::new(move |cx| {
2346                let future = on_quit(cx);
2347                future.boxed_local()
2348            }),
2349        );
2350        activate();
2351        subscription
2352    }
2353
2354    /// Register a callback to be invoked when the application is about to restart.
2355    ///
2356    /// These callbacks are called before any `on_app_quit` callbacks.
2357    pub fn on_app_restart(&self, mut on_restart: impl 'static + FnMut(&mut App)) -> Subscription {
2358        let (subscription, activate) = self.restart_observers.insert(
2359            (),
2360            Box::new(move |cx| {
2361                on_restart(cx);
2362                true
2363            }),
2364        );
2365        activate();
2366        subscription
2367    }
2368
2369    /// Register a callback to be invoked when a window is closed
2370    /// The window is no longer accessible at the point this callback is invoked.
2371    pub fn on_window_closed(&self, mut on_closed: impl FnMut(&mut App) + 'static) -> Subscription {
2372        let (subscription, activate) = self.window_closed_observers.insert((), Box::new(on_closed));
2373        activate();
2374        subscription
2375    }
2376
2377    pub(crate) fn clear_pending_keystrokes(&mut self) {
2378        for window in self.windows() {
2379            window
2380                .update(self, |_, window, cx| {
2381                    window.clear_pending_keystrokes(cx);
2382                })
2383                .ok();
2384        }
2385    }
2386
2387    /// Checks if the given action is bound in the current context, as defined by the app's current focus,
2388    /// the bindings in the element tree, and any global action listeners.
2389    pub fn is_action_available(&mut self, action: &dyn Action) -> bool {
2390        let mut action_available = false;
2391        if let Some(window) = self.active_window()
2392            && let Ok(window_action_available) =
2393                window.update(self, |_, window, cx| window.is_action_available(action, cx))
2394        {
2395            action_available = window_action_available;
2396        }
2397
2398        action_available
2399            || self
2400                .global_action_listeners
2401                .contains_key(&action.as_any().type_id())
2402    }
2403
2404    /// Sets the menu bar for this application. This will replace any existing menu bar.
2405    pub fn set_menus(&self, menus: Vec<Menu>) {
2406        self.platform.set_menus(menus, &self.keymap.borrow());
2407    }
2408
2409    /// Gets the menu bar for this application.
2410    pub fn get_menus(&self) -> Option<Vec<OwnedMenu>> {
2411        self.platform.get_menus()
2412    }
2413
2414    /// Sets the right click menu for the app icon in the dock
2415    pub fn set_dock_menu(&self, menus: Vec<MenuItem>) {
2416        self.platform.set_dock_menu(menus, &self.keymap.borrow())
2417    }
2418
2419    /// Performs the action associated with the given dock menu item, only used on Windows for now.
2420    pub fn perform_dock_menu_action(&self, action: usize) {
2421        self.platform.perform_dock_menu_action(action);
2422    }
2423
2424    /// Adds given path to the bottom of the list of recent paths for the application.
2425    /// The list is usually shown on the application icon's context menu in the dock,
2426    /// and allows to open the recent files via that context menu.
2427    /// If the path is already in the list, it will be moved to the bottom of the list.
2428    pub fn add_recent_document(&self, path: &Path) {
2429        self.platform.add_recent_document(path);
2430    }
2431
2432    /// Updates the jump list with the updated list of recent paths for the application, only used on Windows for now.
2433    /// Note that this also sets the dock menu on Windows.
2434    pub fn update_jump_list(
2435        &self,
2436        menus: Vec<MenuItem>,
2437        entries: Vec<SmallVec<[PathBuf; 2]>>,
2438    ) -> Vec<SmallVec<[PathBuf; 2]>> {
2439        self.platform.update_jump_list(menus, entries)
2440    }
2441
2442    /// Dispatch an action to the currently active window or global action handler
2443    /// See [`crate::Action`] for more information on how actions work
2444    pub fn dispatch_action(&mut self, action: &dyn Action) {
2445        if let Some(active_window) = self.active_window() {
2446            active_window
2447                .update(self, |_, window, cx| {
2448                    window.dispatch_action(action.boxed_clone(), cx)
2449                })
2450                .log_err();
2451        } else {
2452            self.dispatch_global_action(action);
2453        }
2454    }
2455
2456    fn dispatch_global_action(&mut self, action: &dyn Action) {
2457        self.propagate_event = true;
2458
2459        if let Some(mut global_listeners) = self
2460            .global_action_listeners
2461            .remove(&action.as_any().type_id())
2462        {
2463            for listener in &global_listeners {
2464                listener(action.as_any(), DispatchPhase::Capture, self);
2465                if !self.propagate_event {
2466                    break;
2467                }
2468            }
2469
2470            global_listeners.extend(
2471                self.global_action_listeners
2472                    .remove(&action.as_any().type_id())
2473                    .unwrap_or_default(),
2474            );
2475
2476            self.global_action_listeners
2477                .insert(action.as_any().type_id(), global_listeners);
2478        }
2479
2480        if self.propagate_event
2481            && let Some(mut global_listeners) = self
2482                .global_action_listeners
2483                .remove(&action.as_any().type_id())
2484        {
2485            for listener in global_listeners.iter().rev() {
2486                listener(action.as_any(), DispatchPhase::Bubble, self);
2487                if !self.propagate_event {
2488                    break;
2489                }
2490            }
2491
2492            global_listeners.extend(
2493                self.global_action_listeners
2494                    .remove(&action.as_any().type_id())
2495                    .unwrap_or_default(),
2496            );
2497
2498            self.global_action_listeners
2499                .insert(action.as_any().type_id(), global_listeners);
2500        }
2501    }
2502
2503    /// Is there currently something being dragged?
2504    pub fn has_active_drag(&self) -> bool {
2505        self.active_drag.is_some()
2506    }
2507
2508    /// Gets the cursor style of the currently active drag operation.
2509    pub fn active_drag_cursor_style(&self) -> Option<CursorStyle> {
2510        self.active_drag.as_ref().and_then(|drag| drag.cursor_style)
2511    }
2512
2513    /// Stops active drag and clears any related effects.
2514    pub fn stop_active_drag(&mut self, window: &mut Window) -> bool {
2515        if self.active_drag.is_some() {
2516            self.active_drag = None;
2517            window.refresh();
2518            true
2519        } else {
2520            false
2521        }
2522    }
2523
2524    /// Sets the cursor style for the currently active drag operation.
2525    pub fn set_active_drag_cursor_style(
2526        &mut self,
2527        cursor_style: CursorStyle,
2528        window: &mut Window,
2529    ) -> bool {
2530        if let Some(ref mut drag) = self.active_drag {
2531            drag.cursor_style = Some(cursor_style);
2532            window.refresh();
2533            true
2534        } else {
2535            false
2536        }
2537    }
2538
2539    /// Set the prompt renderer for GPUI. This will replace the default or platform specific
2540    /// prompts with this custom implementation.
2541    pub fn set_prompt_builder(
2542        &mut self,
2543        renderer: impl Fn(
2544            PromptLevel,
2545            &str,
2546            Option<&str>,
2547            &[PromptButton],
2548            PromptHandle,
2549            &mut Window,
2550            &mut App,
2551        ) -> RenderablePromptHandle
2552        + 'static,
2553    ) {
2554        self.prompt_builder = Some(PromptBuilder::Custom(Box::new(renderer)));
2555    }
2556
2557    /// Reset the prompt builder to the default implementation.
2558    pub fn reset_prompt_builder(&mut self) {
2559        self.prompt_builder = Some(PromptBuilder::Default);
2560    }
2561
2562    /// Remove an asset from GPUI's cache
2563    pub fn remove_asset<A: Asset>(&mut self, source: &A::Source) {
2564        let asset_id = (TypeId::of::<A>(), hash(source));
2565        self.loading_assets.remove(&asset_id);
2566    }
2567
2568    /// Asynchronously load an asset, if the asset hasn't finished loading this will return None.
2569    ///
2570    /// Note that the multiple calls to this method will only result in one `Asset::load` call at a
2571    /// time, and the results of this call will be cached
2572    pub fn fetch_asset<A: Asset>(&mut self, source: &A::Source) -> (Shared<Task<A::Output>>, bool) {
2573        let asset_id = (TypeId::of::<A>(), hash(source));
2574        let mut is_first = false;
2575        let task = self
2576            .loading_assets
2577            .remove(&asset_id)
2578            .map(|boxed_task| *boxed_task.downcast::<Shared<Task<A::Output>>>().unwrap())
2579            .unwrap_or_else(|| {
2580                is_first = true;
2581                let future = A::load(source.clone(), self);
2582
2583                self.background_executor().spawn(future).shared()
2584            });
2585
2586        self.loading_assets.insert(asset_id, Box::new(task.clone()));
2587
2588        (task, is_first)
2589    }
2590
2591    /// Obtain a new [`FocusHandle`], which allows you to track and manipulate the keyboard focus
2592    /// for elements rendered within this window.
2593    #[track_caller]
2594    pub fn focus_handle(&self) -> FocusHandle {
2595        FocusHandle::new(&self.focus_handles)
2596    }
2597
2598    /// Tell GPUI that an entity has changed and observers of it should be notified.
2599    pub fn notify(&mut self, entity_id: EntityId) {
2600        let window_invalidators = mem::take(
2601            self.window_invalidators_by_entity
2602                .entry(entity_id)
2603                .or_default(),
2604        );
2605
2606        if window_invalidators.is_empty() {
2607            if self.pending_notifications.insert(entity_id) {
2608                self.pending_effects
2609                    .push_back(Effect::Notify { emitter: entity_id });
2610            }
2611        } else {
2612            for invalidator in window_invalidators.values() {
2613                invalidator.invalidate_view(entity_id, self);
2614            }
2615        }
2616
2617        self.window_invalidators_by_entity
2618            .insert(entity_id, window_invalidators);
2619    }
2620
2621    /// Returns the name for this [`App`].
2622    #[cfg(any(test, feature = "test-support", debug_assertions))]
2623    pub fn get_name(&self) -> Option<&'static str> {
2624        self.name
2625    }
2626
2627    /// Returns `true` if the platform file picker supports selecting a mix of files and directories.
2628    pub fn can_select_mixed_files_and_dirs(&self) -> bool {
2629        self.platform.can_select_mixed_files_and_dirs()
2630    }
2631
2632    /// Removes an image from the sprite atlas on all windows.
2633    ///
2634    /// If the current window is being updated, it will be removed from `App.windows`, you can use `current_window` to specify the current window.
2635    /// This is a no-op if the image is not in the sprite atlas.
2636    pub fn drop_image(&mut self, image: Arc<RenderImage>, current_window: Option<&mut Window>) {
2637        // remove the texture from all other windows
2638        for window in self.windows.values_mut().flatten() {
2639            _ = window.drop_image(image.clone());
2640        }
2641
2642        // remove the texture from the current window
2643        if let Some(window) = current_window {
2644            _ = window.drop_image(image);
2645        }
2646    }
2647
2648    /// Sets the renderer for the inspector.
2649    #[cfg(any(feature = "inspector", debug_assertions))]
2650    pub fn set_inspector_renderer(&mut self, f: crate::InspectorRenderer) {
2651        self.inspector_renderer = Some(f);
2652    }
2653
2654    /// Registers a renderer specific to an inspector state.
2655    #[cfg(any(feature = "inspector", debug_assertions))]
2656    pub fn register_inspector_element<T: 'static, R: crate::IntoElement>(
2657        &mut self,
2658        f: impl 'static + Fn(crate::InspectorElementId, &T, &mut Window, &mut App) -> R,
2659    ) {
2660        self.inspector_element_registry.register(f);
2661    }
2662
2663    /// Initializes gpui's default colors for the application.
2664    ///
2665    /// These colors can be accessed through `cx.default_colors()`.
2666    pub fn init_colors(&mut self) {
2667        self.set_global(GlobalColors(Arc::new(Colors::default())));
2668    }
2669}
2670
2671impl AppContext for App {
2672    type Result<T> = T;
2673
2674    /// Builds an entity that is owned by the application.
2675    ///
2676    /// The given function will be invoked with a [`Context`] and must return an object representing the entity. An
2677    /// [`Entity`] handle will be returned, which can be used to access the entity in a context.
2678    fn new<T: 'static>(&mut self, build_entity: impl FnOnce(&mut Context<T>) -> T) -> Entity<T> {
2679        self.update(|cx| {
2680            let slot = cx.entities.reserve();
2681            let handle = slot.clone();
2682            let entity = build_entity(&mut Context::new_context(cx, slot.downgrade()));
2683
2684            cx.push_effect(Effect::EntityCreated {
2685                entity: handle.clone().into_any(),
2686                tid: TypeId::of::<T>(),
2687                window: cx.window_update_stack.last().cloned(),
2688            });
2689
2690            cx.entities.insert(slot, entity);
2691            handle
2692        })
2693    }
2694
2695    fn reserve_entity<T: 'static>(&mut self) -> Self::Result<Reservation<T>> {
2696        Reservation(self.entities.reserve())
2697    }
2698
2699    fn insert_entity<T: 'static>(
2700        &mut self,
2701        reservation: Reservation<T>,
2702        build_entity: impl FnOnce(&mut Context<T>) -> T,
2703    ) -> Self::Result<Entity<T>> {
2704        self.update(|cx| {
2705            let slot = reservation.0;
2706            let entity = build_entity(&mut Context::new_context(cx, slot.downgrade()));
2707            cx.entities.insert(slot, entity)
2708        })
2709    }
2710
2711    /// Updates the entity referenced by the given handle. The function is passed a mutable reference to the
2712    /// entity along with a `Context` for the entity.
2713    fn update_entity<T: 'static, R>(
2714        &mut self,
2715        handle: &Entity<T>,
2716        update: impl FnOnce(&mut T, &mut Context<T>) -> R,
2717    ) -> R {
2718        self.update(|cx| {
2719            let mut entity = cx.entities.lease(handle);
2720            let result = update(
2721                &mut entity,
2722                &mut Context::new_context(cx, handle.downgrade()),
2723            );
2724            cx.entities.end_lease(entity);
2725            result
2726        })
2727    }
2728
2729    fn as_mut<'a, T>(&'a mut self, handle: &Entity<T>) -> GpuiBorrow<'a, T>
2730    where
2731        T: 'static,
2732    {
2733        GpuiBorrow::new(handle.clone(), self)
2734    }
2735
2736    fn read_entity<T, R>(
2737        &self,
2738        handle: &Entity<T>,
2739        read: impl FnOnce(&T, &App) -> R,
2740    ) -> Self::Result<R>
2741    where
2742        T: 'static,
2743    {
2744        let entity = self.entities.read(handle);
2745        read(entity, self)
2746    }
2747
2748    fn update_window<T, F>(&mut self, handle: AnyWindowHandle, update: F) -> Result<T>
2749    where
2750        F: FnOnce(AnyView, &mut Window, &mut App) -> T,
2751    {
2752        self.update_window_id(handle.id, update)
2753    }
2754
2755    fn read_window<T, R>(
2756        &self,
2757        window: &WindowHandle<T>,
2758        read: impl FnOnce(Entity<T>, &App) -> R,
2759    ) -> Result<R>
2760    where
2761        T: 'static,
2762    {
2763        let window = self
2764            .windows
2765            .get(window.id)
2766            .context("window not found")?
2767            .as_ref()
2768            .expect("attempted to read a window that is already on the stack");
2769
2770        let root_view = window.root.clone().unwrap();
2771        let view = root_view
2772            .downcast::<T>()
2773            .map_err(|_| anyhow!("root view's type has changed"))?;
2774
2775        Ok(read(view, self))
2776    }
2777
2778    fn background_spawn<R>(&self, future: impl Future<Output = R> + Send + 'static) -> Task<R>
2779    where
2780        R: Send + 'static,
2781    {
2782        self.background_executor.spawn(future)
2783    }
2784
2785    fn read_global<G, R>(&self, callback: impl FnOnce(&G, &App) -> R) -> Self::Result<R>
2786    where
2787        G: Global,
2788    {
2789        let mut g = self.global::<G>();
2790        callback(g, self)
2791    }
2792}
2793
2794/// These effects are processed at the end of each application update cycle.
2795pub(crate) enum Effect {
2796    Notify {
2797        emitter: EntityId,
2798    },
2799    Emit {
2800        emitter: EntityId,
2801        event_type: TypeId,
2802        event: Box<dyn Any>,
2803    },
2804    RefreshWindows,
2805    NotifyGlobalObservers {
2806        global_type: TypeId,
2807    },
2808    Defer {
2809        callback: Box<dyn FnOnce(&mut App) + 'static>,
2810    },
2811    EntityCreated {
2812        entity: AnyEntity,
2813        tid: TypeId,
2814        window: Option<WindowId>,
2815    },
2816}
2817
2818impl std::fmt::Debug for Effect {
2819    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2820        match self {
2821            Effect::Notify { emitter } => write!(f, "Notify({})", emitter),
2822            Effect::Emit { emitter, .. } => write!(f, "Emit({:?})", emitter),
2823            Effect::RefreshWindows => write!(f, "RefreshWindows"),
2824            Effect::NotifyGlobalObservers { global_type } => {
2825                write!(f, "NotifyGlobalObservers({:?})", global_type)
2826            }
2827            Effect::Defer { .. } => write!(f, "Defer(..)"),
2828            Effect::EntityCreated { entity, .. } => write!(f, "EntityCreated({:?})", entity),
2829        }
2830    }
2831}
2832
2833/// Wraps a global variable value during `update_global` while the value has been moved to the stack.
2834pub(crate) struct GlobalLease<G: Global> {
2835    global: Box<dyn Any>,
2836    global_type: PhantomData<G>,
2837}
2838
2839impl<G: Global> GlobalLease<G> {
2840    fn new(global: Box<dyn Any>) -> Self {
2841        GlobalLease {
2842            global,
2843            global_type: PhantomData,
2844        }
2845    }
2846}
2847
2848impl<G: Global> Deref for GlobalLease<G> {
2849    type Target = G;
2850
2851    fn deref(&self) -> &Self::Target {
2852        self.global.downcast_ref().unwrap()
2853    }
2854}
2855
2856impl<G: Global> DerefMut for GlobalLease<G> {
2857    fn deref_mut(&mut self) -> &mut Self::Target {
2858        self.global.downcast_mut().unwrap()
2859    }
2860}
2861
2862/// Contains state associated with an active drag operation, started by dragging an element
2863/// within the window or by dragging into the app from the underlying platform.
2864pub struct AnyDrag {
2865    /// The view used to render this drag
2866    pub view: AnyView,
2867
2868    /// The value of the dragged item, to be dropped
2869    pub value: Arc<dyn Any>,
2870
2871    /// This is used to render the dragged item in the same place
2872    /// on the original element that the drag was initiated
2873    pub cursor_offset: Point<Pixels>,
2874
2875    /// The cursor style to use while dragging
2876    pub cursor_style: Option<CursorStyle>,
2877}
2878
2879/// Contains state associated with a tooltip. You'll only need this struct if you're implementing
2880/// tooltip behavior on a custom element. Otherwise, use [Div::tooltip](crate::Interactivity::tooltip).
2881#[derive(Clone)]
2882pub struct AnyTooltip {
2883    /// The view used to display the tooltip
2884    pub view: AnyView,
2885
2886    /// The absolute position of the mouse when the tooltip was deployed.
2887    pub mouse_position: Point<Pixels>,
2888
2889    /// Given the bounds of the tooltip, checks whether the tooltip should still be visible and
2890    /// updates its state accordingly. This is needed atop the hovered element's mouse move handler
2891    /// to handle the case where the element is not painted (e.g. via use of `visible_on_hover`).
2892    pub check_visible_and_update: Rc<dyn Fn(Bounds<Pixels>, &mut Window, &mut App) -> bool>,
2893}
2894
2895/// A keystroke event, and potentially the associated action
2896#[derive(Debug)]
2897pub struct KeystrokeEvent {
2898    /// The keystroke that occurred
2899    pub keystroke: Keystroke,
2900
2901    /// The action that was resolved for the keystroke, if any
2902    pub action: Option<Box<dyn Action>>,
2903
2904    /// The context stack at the time
2905    pub context_stack: Vec<KeyContext>,
2906}
2907
2908struct NullHttpClient;
2909
2910impl HttpClient for NullHttpClient {
2911    fn send(
2912        &self,
2913        _req: http_client::Request<http_client::AsyncBody>,
2914    ) -> futures::future::BoxFuture<
2915        'static,
2916        anyhow::Result<http_client::Response<http_client::AsyncBody>>,
2917    > {
2918        async move {
2919            anyhow::bail!("No HttpClient available");
2920        }
2921        .boxed()
2922    }
2923
2924    fn user_agent(&self) -> Option<&http_client::http::HeaderValue> {
2925        None
2926    }
2927
2928    fn proxy(&self) -> Option<&Url> {
2929        None
2930    }
2931
2932    fn type_name(&self) -> &'static str {
2933        type_name::<Self>()
2934    }
2935}
2936
2937/// A mutable reference to an entity owned by GPUI
2938pub struct GpuiBorrow<'a, T> {
2939    inner: Option<Lease<T>>,
2940    app: &'a mut App,
2941}
2942
2943impl<'a, T: 'static> GpuiBorrow<'a, T> {
2944    fn new(inner: Entity<T>, app: &'a mut App) -> Self {
2945        app.start_update();
2946        let lease = app.entities.lease(&inner);
2947        Self {
2948            inner: Some(lease),
2949            app,
2950        }
2951    }
2952}
2953
2954impl<'a, T: 'static> std::borrow::Borrow<T> for GpuiBorrow<'a, T> {
2955    fn borrow(&self) -> &T {
2956        self.inner.as_ref().unwrap().borrow()
2957    }
2958}
2959
2960impl<'a, T: 'static> std::borrow::BorrowMut<T> for GpuiBorrow<'a, T> {
2961    fn borrow_mut(&mut self) -> &mut T {
2962        self.inner.as_mut().unwrap().borrow_mut()
2963    }
2964}
2965
2966impl<'a, T: 'static> std::ops::Deref for GpuiBorrow<'a, T> {
2967    type Target = T;
2968
2969    fn deref(&self) -> &Self::Target {
2970        self.inner.as_ref().unwrap()
2971    }
2972}
2973
2974impl<'a, T: 'static> std::ops::DerefMut for GpuiBorrow<'a, T> {
2975    fn deref_mut(&mut self) -> &mut T {
2976        self.inner.as_mut().unwrap()
2977    }
2978}
2979
2980impl<'a, T> Drop for GpuiBorrow<'a, T> {
2981    fn drop(&mut self) {
2982        let lease = self.inner.take().unwrap();
2983        self.app.notify(lease.id);
2984        self.app.entities.end_lease(lease);
2985        self.app.finish_update();
2986    }
2987}
2988
2989#[cfg(test)]
2990mod test {
2991    use std::{
2992        cell::{Cell, RefCell},
2993        rc::Rc,
2994        sync::Arc,
2995    };
2996
2997    use rand::{SeedableRng, rngs::StdRng};
2998
2999    use super::{Application, ApplicationHandle, NullHttpClient};
3000    use crate::{
3001        AppContext, AppResourceProfile, BackgroundExecutor, Context, Empty, ForegroundExecutor,
3002        IntoElement, Platform, QuitMode, Render, TestAppContext, TestDispatcher, TestPlatform,
3003        TrayIconClickEvent, TrayIconEvent, TrayIconRenderingMode, Window, WindowAppearance, point,
3004        px,
3005    };
3006
3007    struct RenderCounter(Rc<Cell<usize>>);
3008
3009    impl Render for RenderCounter {
3010        fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
3011            self.0.set(self.0.get() + 1);
3012            Empty
3013        }
3014    }
3015
3016    #[crate::test]
3017    fn async_app_refresh_flushes_refresh_effect(cx: &mut TestAppContext) {
3018        let render_count = Rc::new(Cell::new(0));
3019
3020        let _window = cx.add_window({
3021            let render_count = render_count.clone();
3022            move |_, _| RenderCounter(render_count)
3023        });
3024
3025        cx.run_until_parked();
3026        let render_count_before_refresh = render_count.get();
3027
3028        cx.to_async().refresh().unwrap();
3029
3030        assert_eq!(render_count.get(), render_count_before_refresh + 1);
3031    }
3032
3033    #[test]
3034    fn test_with_platform_uses_injected_platform() {
3035        let dispatcher = Arc::new(TestDispatcher::new(StdRng::seed_from_u64(0)));
3036        let platform: Rc<dyn Platform> = TestPlatform::new(
3037            BackgroundExecutor::new(dispatcher.clone()),
3038            ForegroundExecutor::new(dispatcher),
3039        );
3040
3041        let application = Application::with_platform(platform.clone());
3042
3043        assert!(Rc::ptr_eq(&application.0.borrow().platform, &platform));
3044    }
3045
3046    #[test]
3047    fn test_with_quit_mode_updates_core_and_platform_state() {
3048        let dispatcher = Arc::new(TestDispatcher::new(StdRng::seed_from_u64(0)));
3049        let platform = TestPlatform::new(
3050            BackgroundExecutor::new(dispatcher.clone()),
3051            ForegroundExecutor::new(dispatcher),
3052        );
3053
3054        let application =
3055            Application::with_platform(platform.clone()).with_quit_mode(QuitMode::Explicit);
3056
3057        assert_eq!(application.0.borrow().quit_mode, QuitMode::Explicit);
3058        assert_eq!(*platform.last_quit_mode.lock(), Some(QuitMode::Explicit));
3059    }
3060
3061    #[test]
3062    fn test_inaccessible_sets_force_disabled() {
3063        let dispatcher = Arc::new(TestDispatcher::new(StdRng::seed_from_u64(0)));
3064        let platform = TestPlatform::new(
3065            BackgroundExecutor::new(dispatcher.clone()),
3066            ForegroundExecutor::new(dispatcher),
3067        );
3068        let application = Application(super::App::new_app(
3069            platform,
3070            Arc::new(()),
3071            Arc::new(NullHttpClient),
3072            AppResourceProfile::default(),
3073        ))
3074        .inaccessible();
3075
3076        assert!(application.0.borrow().accessibility_force_disabled);
3077    }
3078
3079    #[test]
3080    fn test_with_resource_profile_rebuilds_text_system_budget() {
3081        let dispatcher = Arc::new(TestDispatcher::new(StdRng::seed_from_u64(0)));
3082        let platform = TestPlatform::new(
3083            BackgroundExecutor::new(dispatcher.clone()),
3084            ForegroundExecutor::new(dispatcher),
3085        );
3086        let mut profile = AppResourceProfile::default();
3087        profile.text.line_layout_cache_max_entries = 7;
3088        profile.text.line_layout_cache_low_watermark = 3;
3089        profile.text.raster_bounds_cache_max_entries = Some(11);
3090        profile.element_arena_size =
3091            crate::window::ELEMENT_ARENA_SIZE.load(std::sync::atomic::Ordering::Relaxed);
3092
3093        let application = Application(super::App::new_app(
3094            platform,
3095            Arc::new(()),
3096            Arc::new(NullHttpClient),
3097            AppResourceProfile::default(),
3098        ))
3099        .with_resource_profile(profile);
3100
3101        let app = application.0.borrow();
3102        assert_eq!(app.text_system.resource_budget_for_test(), (7, 3, Some(11)));
3103        assert_eq!(app.resource_profile.text.line_layout_cache_max_entries, 7);
3104        assert_eq!(
3105            app.resource_profile.gpu.instance_buffer_initial_size,
3106            2 * 1024 * 1024
3107        );
3108    }
3109
3110    #[test]
3111    fn test_with_resource_profile_updates_gpu_budget() {
3112        let dispatcher = Arc::new(TestDispatcher::new(StdRng::seed_from_u64(0)));
3113        let platform = TestPlatform::new(
3114            BackgroundExecutor::new(dispatcher.clone()),
3115            ForegroundExecutor::new(dispatcher),
3116        );
3117        let platform_handle = platform.clone();
3118        let mut profile = AppResourceProfile::default();
3119        profile.gpu.instance_buffer_initial_size = 768 * 1024;
3120        profile.element_arena_size =
3121            crate::window::ELEMENT_ARENA_SIZE.load(std::sync::atomic::Ordering::Relaxed);
3122
3123        let application = Application(super::App::new_app(
3124            platform,
3125            Arc::new(()),
3126            Arc::new(NullHttpClient),
3127            AppResourceProfile::default(),
3128        ))
3129        .with_resource_profile(profile);
3130
3131        let app = application.0.borrow();
3132        assert_eq!(
3133            app.resource_profile.gpu.instance_buffer_initial_size,
3134            768 * 1024
3135        );
3136        assert_eq!(
3137            platform_handle
3138                .gpu_resource_budget
3139                .lock()
3140                .instance_buffer_initial_size,
3141            768 * 1024
3142        );
3143    }
3144
3145    #[test]
3146    fn test_application_handle_keeps_app_alive_for_embedders() {
3147        let dispatcher = Arc::new(TestDispatcher::new(StdRng::seed_from_u64(0)));
3148        let platform = TestPlatform::new(
3149            BackgroundExecutor::new(dispatcher.clone()),
3150            ForegroundExecutor::new(dispatcher),
3151        );
3152        let application = Application(super::App::new_app(
3153            platform,
3154            Arc::new(()),
3155            Arc::new(NullHttpClient),
3156            AppResourceProfile::default(),
3157        ));
3158        let weak_app = Rc::downgrade(&application.0);
3159        let handle = ApplicationHandle {
3160            app: application.0.clone(),
3161        };
3162        drop(application);
3163
3164        assert!(weak_app.upgrade().is_some());
3165
3166        let did_update = Rc::new(RefCell::new(false));
3167        let did_update_clone = did_update.clone();
3168        handle.update(move |_| {
3169            *did_update_clone.borrow_mut() = true;
3170        });
3171
3172        assert!(*did_update.borrow());
3173
3174        drop(handle);
3175        assert!(weak_app.upgrade().is_none());
3176    }
3177
3178    #[test]
3179    fn test_with_resource_profile_clamps_line_layout_cache_to_one_entry() {
3180        let dispatcher = Arc::new(TestDispatcher::new(StdRng::seed_from_u64(0)));
3181        let platform = TestPlatform::new(
3182            BackgroundExecutor::new(dispatcher.clone()),
3183            ForegroundExecutor::new(dispatcher),
3184        );
3185        let mut profile = AppResourceProfile::default();
3186        profile.text.line_layout_cache_max_entries = 0;
3187        profile.text.line_layout_cache_low_watermark = 5;
3188        profile.element_arena_size =
3189            crate::window::ELEMENT_ARENA_SIZE.load(std::sync::atomic::Ordering::Relaxed);
3190
3191        let application = Application(super::App::new_app(
3192            platform,
3193            Arc::new(()),
3194            Arc::new(NullHttpClient),
3195            AppResourceProfile::default(),
3196        ))
3197        .with_resource_profile(profile);
3198
3199        let app = application.0.borrow();
3200        assert_eq!(
3201            app.text_system.resource_budget_for_test(),
3202            (1, 0, None),
3203            "line layout caches should retain a valid minimum capacity"
3204        );
3205    }
3206
3207    #[test]
3208    fn test_gpui_borrow() {
3209        let cx = TestAppContext::single();
3210        let observation_count = Rc::new(RefCell::new(0));
3211
3212        let state = cx.update(|cx| {
3213            let state = cx.new(|_| false);
3214            cx.observe(&state, {
3215                let observation_count = observation_count.clone();
3216                move |_, _| {
3217                    let mut count = observation_count.borrow_mut();
3218                    *count += 1;
3219                }
3220            })
3221            .detach();
3222
3223            state
3224        });
3225
3226        cx.update(|cx| {
3227            // Calling this like this so that we don't clobber the borrow_mut above
3228            *std::borrow::BorrowMut::borrow_mut(&mut state.as_mut(cx)) = true;
3229        });
3230
3231        cx.update(|cx| {
3232            state.write(cx, false);
3233        });
3234
3235        assert_eq!(*observation_count.borrow(), 2);
3236    }
3237
3238    #[test]
3239    fn test_tray_icon_rendering_mode_default() {
3240        assert_eq!(
3241            TrayIconRenderingMode::default(),
3242            TrayIconRenderingMode::Adaptive
3243        );
3244    }
3245
3246    #[test]
3247    fn test_set_tray_icon_forwards_to_platform() {
3248        let cx = TestAppContext::single();
3249        let icon = [1_u8, 2, 3, 4];
3250
3251        cx.update(|cx| {
3252            cx.set_tray_icon(Some(&icon));
3253        });
3254
3255        assert_eq!(cx.tray_icon(), Some(icon.to_vec()));
3256    }
3257
3258    #[test]
3259    fn test_set_tray_icon_rendering_mode_forwards_to_platform() {
3260        let cx = TestAppContext::single();
3261
3262        cx.update(|cx| {
3263            cx.set_tray_icon_rendering_mode(TrayIconRenderingMode::Original);
3264        });
3265
3266        assert_eq!(
3267            cx.tray_icon_rendering_mode(),
3268            TrayIconRenderingMode::Original
3269        );
3270    }
3271
3272    #[test]
3273    fn test_tray_icon_rendering_mode_and_icon_updates_are_order_independent() {
3274        let first = TestAppContext::single();
3275        let second = TestAppContext::single();
3276        let icon = [9_u8, 8, 7, 6];
3277
3278        first.update(|cx| {
3279            cx.set_tray_icon_rendering_mode(TrayIconRenderingMode::Original);
3280            cx.set_tray_icon(Some(&icon));
3281        });
3282
3283        second.update(|cx| {
3284            cx.set_tray_icon(Some(&icon));
3285            cx.set_tray_icon_rendering_mode(TrayIconRenderingMode::Original);
3286        });
3287
3288        assert_eq!(first.tray_icon(), Some(icon.to_vec()));
3289        assert_eq!(second.tray_icon(), Some(icon.to_vec()));
3290        assert_eq!(
3291            first.tray_icon_rendering_mode(),
3292            TrayIconRenderingMode::Original
3293        );
3294        assert_eq!(
3295            second.tray_icon_rendering_mode(),
3296            TrayIconRenderingMode::Original
3297        );
3298    }
3299
3300    #[test]
3301    fn test_tray_icon_click_event_keeps_legacy_callback_compatible() {
3302        let cx = TestAppContext::single();
3303        let legacy_event = Rc::new(RefCell::new(None));
3304        let click_event = Rc::new(RefCell::new(None));
3305
3306        cx.update({
3307            let legacy_event = legacy_event.clone();
3308            let click_event = click_event.clone();
3309            |cx| {
3310                cx.on_tray_icon_event(move |event, _| {
3311                    *legacy_event.borrow_mut() = Some(event);
3312                });
3313                cx.on_tray_icon_click_event(move |event, _| {
3314                    *click_event.borrow_mut() = Some(event);
3315                });
3316            }
3317        });
3318
3319        let event =
3320            TrayIconClickEvent::with_position(TrayIconEvent::LeftClick, point(px(120.0), px(24.0)));
3321        cx.simulate_tray_icon_click_event(event.clone());
3322
3323        assert_eq!(*legacy_event.borrow(), Some(TrayIconEvent::LeftClick));
3324        assert_eq!(*click_event.borrow(), Some(event));
3325    }
3326
3327    #[test]
3328    fn test_tray_icon_callbacks_keep_re_registration_during_dispatch() {
3329        let cx = TestAppContext::single();
3330        let legacy_events = Rc::new(RefCell::new(Vec::new()));
3331        let click_events = Rc::new(RefCell::new(Vec::new()));
3332
3333        cx.update({
3334            let legacy_events = legacy_events.clone();
3335            let click_events = click_events.clone();
3336            move |cx| {
3337                cx.on_tray_icon_event({
3338                    let legacy_events = legacy_events.clone();
3339                    move |event, cx| {
3340                        legacy_events.borrow_mut().push(("old", event));
3341                        cx.on_tray_icon_event({
3342                            let legacy_events = legacy_events.clone();
3343                            move |event, _| {
3344                                legacy_events.borrow_mut().push(("new", event));
3345                            }
3346                        });
3347                    }
3348                });
3349
3350                cx.on_tray_icon_click_event({
3351                    let click_events = click_events.clone();
3352                    move |event, cx| {
3353                        click_events.borrow_mut().push(("old", event.kind));
3354                        cx.on_tray_icon_click_event({
3355                            let click_events = click_events.clone();
3356                            move |event, _| {
3357                                click_events.borrow_mut().push(("new", event.kind));
3358                            }
3359                        });
3360                    }
3361                });
3362            }
3363        });
3364
3365        cx.simulate_tray_icon_click_event(TrayIconClickEvent::new(TrayIconEvent::LeftClick));
3366        cx.simulate_tray_icon_click_event(TrayIconClickEvent::new(TrayIconEvent::RightClick));
3367
3368        assert_eq!(
3369            *legacy_events.borrow(),
3370            vec![
3371                ("old", TrayIconEvent::LeftClick),
3372                ("new", TrayIconEvent::RightClick)
3373            ]
3374        );
3375        assert_eq!(
3376            *click_events.borrow(),
3377            vec![
3378                ("old", TrayIconEvent::LeftClick),
3379                ("new", TrayIconEvent::RightClick)
3380            ]
3381        );
3382    }
3383
3384    #[test]
3385    fn test_set_window_appearance_override_is_reported_by_getter() {
3386        let cx = TestAppContext::single();
3387        assert_eq!(
3388            cx.read(|cx| cx.window_appearance()),
3389            WindowAppearance::Light
3390        );
3391
3392        cx.update(|cx| cx.set_window_appearance(Some(WindowAppearance::Dark)));
3393        assert_eq!(cx.read(|cx| cx.window_appearance()), WindowAppearance::Dark);
3394
3395        cx.update(|cx| cx.set_window_appearance(Some(WindowAppearance::VibrantLight)));
3396        assert_eq!(
3397            cx.read(|cx| cx.window_appearance()),
3398            WindowAppearance::VibrantLight
3399        );
3400
3401        cx.update(|cx| cx.set_window_appearance(None));
3402        assert_eq!(
3403            cx.read(|cx| cx.window_appearance()),
3404            WindowAppearance::Light
3405        );
3406    }
3407
3408    #[test]
3409    fn test_tray_anchor_for_position_uses_display_local_bounds() {
3410        let cx = TestAppContext::single();
3411        let anchor = cx.update(|cx| cx.tray_anchor_for_position(point(px(120.0), px(24.0))));
3412        let anchor = anchor.expect("expected tray anchor");
3413
3414        assert_eq!(anchor.display_id.0, 1);
3415        assert_eq!(anchor.bounds.origin, point(px(108.0), px(12.0)));
3416        assert_eq!(anchor.bounds.size.width, px(24.0));
3417        assert_eq!(anchor.bounds.size.height, px(24.0));
3418    }
3419
3420    #[test]
3421    fn test_tray_anchor_for_position_keeps_out_of_display_hint() {
3422        let cx = TestAppContext::single();
3423        let anchor = cx.update(|cx| cx.tray_anchor_for_position(point(px(-20.0), px(10.0))));
3424        let anchor = anchor.expect("expected tray anchor");
3425
3426        assert_eq!(anchor.display_id.0, 1);
3427        assert_eq!(anchor.bounds.origin, point(px(-32.0), px(-2.0)));
3428    }
3429}