Skip to main content

gpui_core/
app.rs

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