Skip to main content

gpui_core/
app.rs

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