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. Every open window's renderer is
941    /// trimmed first, then the platform-level shared caches; platforms that
942    /// do not maintain trimmable GPU pools may no-op, and active renderer
943    /// resources are kept alive until they can be safely released.
944    pub fn trim_gpu_caches(&self) {
945        for (_, window) in self.windows.iter() {
946            if let Some(window) = window {
947                window.platform_window.trim_renderer_caches();
948            }
949        }
950        self.platform.trim_renderer_caches();
951    }
952
953    /// Snapshot of the renderer's pooled GPU resource usage. See
954    /// [`crate::RendererCacheStats`].
955    ///
956    /// Intended primarily for diagnostics and benchmarking. Useful as a guard
957    /// before calling [`App::trim_gpu_caches`] when callers want to skip the
958    /// trim if no buffers are idle.
959    pub fn renderer_cache_stats(&self) -> crate::RendererCacheStats {
960        self.platform.renderer_cache_stats()
961    }
962
963    /// Schedules all windows in the application to be redrawn. This can be called
964    /// multiple times in an update cycle and still result in a single redraw.
965    pub fn refresh_windows(&mut self) {
966        self.pending_effects.push_back(Effect::RefreshWindows);
967    }
968
969    pub(crate) fn update<R>(&mut self, update: impl FnOnce(&mut Self) -> R) -> R {
970        self.start_update();
971        let result = update(self);
972        self.finish_update();
973        result
974    }
975
976    pub(crate) fn start_update(&mut self) {
977        self.pending_updates += 1;
978    }
979
980    pub(crate) fn finish_update(&mut self) {
981        if !self.flushing_effects && self.pending_updates == 1 {
982            self.flushing_effects = true;
983            self.flush_effects();
984            self.flushing_effects = false;
985        }
986        self.pending_updates -= 1;
987    }
988
989    /// Arrange a callback to be invoked when the given entity calls `notify` on its respective context.
990    pub fn observe<W>(
991        &mut self,
992        entity: &Entity<W>,
993        mut on_notify: impl FnMut(Entity<W>, &mut App) + 'static,
994    ) -> Subscription
995    where
996        W: 'static,
997    {
998        self.observe_internal(entity, move |e, cx| {
999            on_notify(e, cx);
1000            true
1001        })
1002    }
1003
1004    pub(crate) fn detect_accessed_entities<R>(
1005        &mut self,
1006        callback: impl FnOnce(&mut App) -> R,
1007    ) -> (R, FxHashSet<EntityId>) {
1008        let accessed_entities_start = self.entities.accessed_entities.borrow().clone();
1009        let result = callback(self);
1010        let accessed_entities_end = self.entities.accessed_entities.borrow().clone();
1011        let entities_accessed_in_callback = accessed_entities_end
1012            .difference(&accessed_entities_start)
1013            .copied()
1014            .collect::<FxHashSet<EntityId>>();
1015        (result, entities_accessed_in_callback)
1016    }
1017
1018    pub(crate) fn record_entities_accessed(
1019        &mut self,
1020        window_handle: AnyWindowHandle,
1021        invalidator: WindowInvalidator,
1022        entities: &FxHashSet<EntityId>,
1023    ) {
1024        let mut tracked_entities =
1025            std::mem::take(self.tracked_entities.entry(window_handle.id).or_default());
1026        for entity in tracked_entities.iter() {
1027            self.window_invalidators_by_entity
1028                .entry(*entity)
1029                .and_modify(|windows| {
1030                    windows.remove(&window_handle.id);
1031                });
1032        }
1033        for entity in entities.iter() {
1034            self.window_invalidators_by_entity
1035                .entry(*entity)
1036                .or_default()
1037                .insert(window_handle.id, invalidator.clone());
1038        }
1039        tracked_entities.clear();
1040        tracked_entities.extend(entities.iter().copied());
1041        self.tracked_entities
1042            .insert(window_handle.id, tracked_entities);
1043    }
1044
1045    pub(crate) fn new_observer(&mut self, key: EntityId, value: Handler) -> Subscription {
1046        let (subscription, activate) = self.observers.insert(key, value);
1047        self.defer(move |_| activate());
1048        subscription
1049    }
1050
1051    pub(crate) fn observe_internal<W>(
1052        &mut self,
1053        entity: &Entity<W>,
1054        mut on_notify: impl FnMut(Entity<W>, &mut App) -> bool + 'static,
1055    ) -> Subscription
1056    where
1057        W: 'static,
1058    {
1059        let entity_id = entity.entity_id();
1060        let handle = entity.downgrade();
1061        self.new_observer(
1062            entity_id,
1063            Box::new(move |cx| {
1064                if let Some(entity) = handle.upgrade() {
1065                    on_notify(entity, cx)
1066                } else {
1067                    false
1068                }
1069            }),
1070        )
1071    }
1072
1073    /// Arrange for the given callback to be invoked whenever the given entity emits an event of a given type.
1074    /// The callback is provided a handle to the emitting entity and a reference to the emitted event.
1075    pub fn subscribe<T, Event>(
1076        &mut self,
1077        entity: &Entity<T>,
1078        mut on_event: impl FnMut(Entity<T>, &Event, &mut App) + 'static,
1079    ) -> Subscription
1080    where
1081        T: 'static + EventEmitter<Event>,
1082        Event: 'static,
1083    {
1084        self.subscribe_internal(entity, move |entity, event, cx| {
1085            on_event(entity, event, cx);
1086            true
1087        })
1088    }
1089
1090    pub(crate) fn new_subscription(
1091        &mut self,
1092        key: EntityId,
1093        value: (TypeId, Listener),
1094    ) -> Subscription {
1095        let (subscription, activate) = self.event_listeners.insert(key, value);
1096        self.defer(move |_| activate());
1097        subscription
1098    }
1099    pub(crate) fn subscribe_internal<T, Evt>(
1100        &mut self,
1101        entity: &Entity<T>,
1102        mut on_event: impl FnMut(Entity<T>, &Evt, &mut App) -> bool + 'static,
1103    ) -> Subscription
1104    where
1105        T: 'static + EventEmitter<Evt>,
1106        Evt: 'static,
1107    {
1108        let entity_id = entity.entity_id();
1109        let handle = entity.downgrade();
1110        self.new_subscription(
1111            entity_id,
1112            (
1113                TypeId::of::<Evt>(),
1114                Box::new(move |event, cx| {
1115                    let event: &Evt = event.downcast_ref().expect("invalid event type");
1116                    if let Some(entity) = handle.upgrade() {
1117                        on_event(entity, event, cx)
1118                    } else {
1119                        false
1120                    }
1121                }),
1122            ),
1123        )
1124    }
1125
1126    /// Returns handles to all open windows in the application.
1127    /// Each handle could be downcast to a handle typed for the root view of that window.
1128    /// To find all windows of a given type, you could filter on
1129    pub fn windows(&self) -> Vec<AnyWindowHandle> {
1130        self.windows
1131            .keys()
1132            .flat_map(|window_id| self.window_handles.get(&window_id).copied())
1133            .collect()
1134    }
1135
1136    /// Returns the window handles ordered by their appearance on screen, front to back.
1137    ///
1138    /// The first window in the returned list is the active/topmost window of the application.
1139    ///
1140    /// This method returns None if the platform doesn't implement the method yet.
1141    pub fn window_stack(&self) -> Option<Vec<AnyWindowHandle>> {
1142        self.platform.window_stack()
1143    }
1144
1145    /// Returns a handle to the window that is currently focused at the platform level, if one exists.
1146    pub fn active_window(&self) -> Option<AnyWindowHandle> {
1147        self.platform.active_window()
1148    }
1149
1150    /// Opens a new window with the given option and the root view returned by the given function.
1151    /// The function is invoked with a `Window`, which can be used to interact with window-specific
1152    /// functionality.
1153    pub fn open_window<V: 'static + Render>(
1154        &mut self,
1155        options: crate::WindowOptions,
1156        build_root_view: impl FnOnce(&mut Window, &mut App) -> Entity<V>,
1157    ) -> anyhow::Result<WindowHandle<V>> {
1158        self.update(|cx| {
1159            let id = cx.windows.insert(None);
1160            let handle = WindowHandle::new(id);
1161            match Window::new(handle.into(), options, cx) {
1162                Ok(mut window) => {
1163                    cx.window_update_stack.push(id);
1164                    let root_view = build_root_view(&mut window, cx);
1165                    cx.window_update_stack.pop();
1166                    window.root.replace(root_view.into());
1167                    window.defer(cx, |window: &mut Window, cx| window.appearance_changed(cx));
1168
1169                    // allow a window to draw at least once before returning
1170                    // this didn't cause any issues on non windows platforms as it seems we always won the race to on_request_frame
1171                    // on windows we quite frequently lose the race and return a window that has never rendered, which leads to a crash
1172                    // where DispatchTree::root_node_id asserts on empty nodes
1173                    let clear = window.draw(cx);
1174                    clear.clear();
1175
1176                    cx.window_handles.insert(id, window.handle);
1177                    cx.windows.get_mut(id).unwrap().replace(window);
1178                    Ok(handle)
1179                }
1180                Err(e) => {
1181                    cx.windows.remove(id);
1182                    Err(e)
1183                }
1184            }
1185        })
1186    }
1187
1188    /// Instructs the platform to activate the application by bringing it to the foreground.
1189    pub fn activate(&self, ignoring_other_apps: bool) {
1190        self.platform.activate(ignoring_other_apps);
1191    }
1192
1193    /// Hide the application at the platform level.
1194    pub fn hide(&self) {
1195        self.platform.hide();
1196    }
1197
1198    /// Hide other applications at the platform level.
1199    pub fn hide_other_apps(&self) {
1200        self.platform.hide_other_apps();
1201    }
1202
1203    /// Unhide other applications at the platform level.
1204    pub fn unhide_other_apps(&self) {
1205        self.platform.unhide_other_apps();
1206    }
1207
1208    /// Set the system tray icon.
1209    pub fn set_tray_icon(&self, icon: Option<&[u8]>) {
1210        self.platform.set_tray_icon(icon);
1211    }
1212
1213    /// Set how the system tray icon should be rendered.
1214    pub fn set_tray_icon_rendering_mode(&self, rendering_mode: TrayIconRenderingMode) {
1215        self.platform.set_tray_icon_rendering_mode(rendering_mode);
1216    }
1217
1218    /// Set the system tray menu items.
1219    pub fn set_tray_menu(&self, menu: Vec<TrayMenuItem>) {
1220        self.platform.set_tray_menu(menu);
1221    }
1222
1223    /// Set the system tray tooltip.
1224    pub fn set_tray_tooltip(&self, tooltip: &str) {
1225        self.platform.set_tray_tooltip(tooltip);
1226    }
1227
1228    /// Enable or disable tray panel mode.
1229    ///
1230    /// macOS only. When enabled, an attached menu is detached from the tray
1231    /// icon so clicks fire [`TrayIconEvent`]s instead of opening the menu.
1232    /// With no menu attached, clicks fire events regardless of this setting.
1233    pub fn set_tray_panel_mode(&self, enabled: bool) {
1234        self.platform.set_tray_panel_mode(enabled);
1235    }
1236
1237    #[allow(missing_docs)]
1238    pub fn tray_icon_anchor(&self) -> Option<TrayAnchor> {
1239        self.platform.get_tray_icon_anchor()
1240    }
1241
1242    /// Get the screen bounds of the tray icon, useful for positioning a panel below it.
1243    pub fn tray_icon_bounds(&self) -> Option<Bounds<Pixels>> {
1244        self.platform.get_tray_icon_bounds()
1245    }
1246
1247    /// Build an approximate tray anchor from a screen position.
1248    ///
1249    /// This is useful on Linux StatusNotifierItem hosts, where click events
1250    /// provide a logical screen-coordinate hint but not the actual tray icon
1251    /// bounds. If the hint falls outside known displays, the primary display is
1252    /// used as a best-effort fallback so callers can still fall back from
1253    /// `WindowPosition::TrayAnchored` to a corner position if needed.
1254    pub fn tray_anchor_for_position(&self, position: Point<Pixels>) -> Option<TrayAnchor> {
1255        // This is a logical-size approximation of a tray icon, not a measured
1256        // host icon size. Linux SNI does not expose the actual icon bounds.
1257        const APPROXIMATE_TRAY_ICON_SIZE: Pixels = px(24.0);
1258
1259        let displays = self.displays();
1260        let display = displays
1261            .iter()
1262            .find(|display| display.bounds().contains(&position))
1263            .cloned()
1264            .or_else(|| self.primary_display())?;
1265        let display_bounds = display.bounds();
1266        let half_size = APPROXIMATE_TRAY_ICON_SIZE * 0.5;
1267        let local_position = position - display_bounds.origin;
1268
1269        Some(TrayAnchor {
1270            display_id: display.id(),
1271            bounds: Bounds::new(
1272                point(local_position.x - half_size, local_position.y - half_size),
1273                size(APPROXIMATE_TRAY_ICON_SIZE, APPROXIMATE_TRAY_ICON_SIZE),
1274            ),
1275        })
1276    }
1277
1278    /// Register a callback for system tray icon events.
1279    ///
1280    /// Platform notes:
1281    /// - macOS: clicks are delivered whenever no menu is attached to the tray
1282    ///   icon; call [`Self::set_tray_panel_mode(true)`](Self::set_tray_panel_mode)
1283    ///   to detach a menu and receive clicks instead of it. Left, right, and
1284    ///   double clicks are distinguished. Callbacks run on the next main
1285    ///   queue turn after the click, not synchronously inside it.
1286    /// - Linux (StatusNotifierItem): left/secondary activation is mapped to
1287    ///   `LeftClick`/`RightClick` with a position hint; not every host (e.g.
1288    ///   some AppIndicator extensions) delivers activation events at all.
1289    pub fn on_tray_icon_event(&self, mut callback: impl FnMut(TrayIconEvent, &mut App) + 'static) {
1290        let this = self.this.clone();
1291        self.platform.on_tray_icon_event(Box::new(move |event| {
1292            if let Some(app) = this.upgrade() {
1293                callback(event, &mut app.borrow_mut());
1294            }
1295        }));
1296    }
1297
1298    /// Register a callback for system tray icon click events with optional
1299    /// position information.
1300    ///
1301    /// See [`Self::on_tray_icon_event`] for delivery semantics. The
1302    /// `position` field carries a logical screen-coordinate hint where the
1303    /// platform provides one (Linux SNI); it is `None` on macOS, which has
1304    /// no click-position equivalent — use [`Self::tray_icon_bounds`] there.
1305    pub fn on_tray_icon_click_event(
1306        &self,
1307        mut callback: impl FnMut(TrayIconClickEvent, &mut App) + 'static,
1308    ) {
1309        let this = self.this.clone();
1310        self.platform
1311            .on_tray_icon_click_event(Box::new(move |event| {
1312                if let Some(app) = this.upgrade() {
1313                    callback(event, &mut app.borrow_mut());
1314                }
1315            }));
1316    }
1317
1318    /// Register a callback for when a tray menu item is clicked.
1319    pub fn on_tray_menu_action(&self, mut callback: impl FnMut(SharedString, &mut App) + 'static) {
1320        let this = self.this.clone();
1321        self.platform.on_tray_menu_action(Box::new(move |id| {
1322            if let Some(app) = this.upgrade() {
1323                callback(id, &mut app.borrow_mut());
1324            }
1325        }));
1326    }
1327
1328    /// Register a global hotkey with the given ID and keystroke.
1329    pub fn register_global_hotkey(&self, id: u32, keystroke: &Keystroke) -> Result<()> {
1330        self.platform.register_global_hotkey(id, keystroke)
1331    }
1332
1333    /// Unregister a previously registered global hotkey.
1334    pub fn unregister_global_hotkey(&self, id: u32) {
1335        self.platform.unregister_global_hotkey(id);
1336    }
1337
1338    /// Register a callback for global hotkey events.
1339    pub fn on_global_hotkey(&self, callback: impl FnMut(u32) + 'static) {
1340        self.platform.on_global_hotkey(Box::new(callback));
1341    }
1342
1343    /// Get information about the currently focused window from any application.
1344    pub fn focused_window_info(&self) -> Option<FocusedWindowInfo> {
1345        self.platform.focused_window_info()
1346    }
1347
1348    /// Check accessibility permission status.
1349    pub fn accessibility_status(&self) -> PermissionStatus {
1350        self.platform.accessibility_status()
1351    }
1352
1353    /// Request accessibility permission from the user.
1354    pub fn request_accessibility_permission(&self) -> PermissionRequestStatus {
1355        self.platform.request_accessibility_permission()
1356    }
1357
1358    /// Check microphone permission status.
1359    pub fn microphone_status(&self) -> PermissionStatus {
1360        self.platform.microphone_status()
1361    }
1362
1363    /// Request microphone permission from the user.
1364    pub fn request_microphone_permission(
1365        &self,
1366        callback: impl FnOnce(bool) + 'static,
1367    ) -> PermissionRequestStatus {
1368        self.platform
1369            .request_microphone_permission(Box::new(callback))
1370    }
1371
1372    /// Set whether the application should auto-launch at login.
1373    pub fn set_auto_launch(&self, app_id: &str, enabled: bool) -> Result<()> {
1374        self.platform.set_auto_launch(app_id, enabled)
1375    }
1376
1377    /// Check whether the application is set to auto-launch at login.
1378    pub fn is_auto_launch_enabled(&self, app_id: &str) -> bool {
1379        self.platform.is_auto_launch_enabled(app_id)
1380    }
1381
1382    /// Show an OS notification.
1383    pub fn show_notification(&self, title: &str, body: &str) -> Result<()> {
1384        self.platform.show_notification(title, body)
1385    }
1386
1387    /// Configures when the application should automatically quit.
1388    /// By default, [`QuitMode::Default`] is used.
1389    pub fn set_quit_mode(&mut self, mode: QuitMode) {
1390        self.quit_mode = mode;
1391        self.platform.set_quit_mode(mode);
1392    }
1393
1394    /// Register a callback for system power events (sleep, wake, shutdown).
1395    pub fn on_system_power_event(
1396        &self,
1397        mut callback: impl FnMut(SystemPowerEvent, &mut App) + 'static,
1398    ) {
1399        let this = self.this.clone();
1400        self.platform.on_system_power_event(Box::new(move |event| {
1401            if let Some(app) = this.upgrade() {
1402                callback(event, &mut app.borrow_mut());
1403            }
1404        }));
1405    }
1406
1407    /// Start a power save blocker to prevent the system from sleeping or the display from dimming.
1408    pub fn start_power_save_blocker(&self, kind: PowerSaveBlockerKind) -> Option<u32> {
1409        self.platform.start_power_save_blocker(kind)
1410    }
1411
1412    /// Stop a previously started power save blocker by its ID.
1413    pub fn stop_power_save_blocker(&self, id: u32) {
1414        self.platform.stop_power_save_blocker(id);
1415    }
1416
1417    /// Get the duration since the last user input event.
1418    pub fn system_idle_time(&self) -> Option<Duration> {
1419        self.platform.system_idle_time()
1420    }
1421
1422    /// Get the current network connectivity status.
1423    pub fn network_status(&self) -> NetworkStatus {
1424        self.platform.network_status()
1425    }
1426
1427    /// Register a callback for network connectivity status changes.
1428    pub fn on_network_status_change(
1429        &self,
1430        mut callback: impl FnMut(NetworkStatus, &mut App) + 'static,
1431    ) {
1432        let this = self.this.clone();
1433        self.platform
1434            .on_network_status_change(Box::new(move |status| {
1435                if let Some(app) = this.upgrade() {
1436                    callback(status, &mut app.borrow_mut());
1437                }
1438            }));
1439    }
1440
1441    /// Register a callback for media key events (play, pause, next, previous).
1442    pub fn on_media_key_event(&self, mut callback: impl FnMut(MediaKeyEvent, &mut App) + 'static) {
1443        let this = self.this.clone();
1444        self.platform.on_media_key_event(Box::new(move |event| {
1445            if let Some(app) = this.upgrade() {
1446                callback(event, &mut app.borrow_mut());
1447            }
1448        }));
1449    }
1450
1451    /// Request the user's attention by bouncing the dock icon or flashing the taskbar.
1452    pub fn request_user_attention(&self, attention_type: AttentionType) {
1453        self.platform.request_user_attention(attention_type);
1454    }
1455
1456    /// Cancel a previous user attention request.
1457    pub fn cancel_user_attention(&self) {
1458        self.platform.cancel_user_attention();
1459    }
1460
1461    /// Set the dock badge label (macOS) or taskbar overlay text.
1462    pub fn set_dock_badge(&self, label: Option<&str>) {
1463        self.platform.set_dock_badge(label);
1464    }
1465
1466    /// Show a context menu at the given screen position with the specified menu items.
1467    pub fn show_context_menu(
1468        &self,
1469        position: Point<Pixels>,
1470        items: Vec<TrayMenuItem>,
1471        mut callback: impl FnMut(SharedString, &mut App) + 'static,
1472    ) {
1473        let this = self.this.clone();
1474        self.platform.show_context_menu(
1475            position,
1476            items,
1477            Box::new(move |id| {
1478                if let Some(app) = this.upgrade() {
1479                    callback(id, &mut app.borrow_mut());
1480                }
1481            }),
1482        );
1483    }
1484
1485    /// Show a native dialog with the given options, returning the index of the clicked button.
1486    pub fn show_dialog(&self, options: DialogOptions) -> oneshot::Receiver<usize> {
1487        self.platform.show_dialog(options)
1488    }
1489
1490    /// Get operating system information (name, version, architecture).
1491    pub fn os_info(&self) -> OsInfo {
1492        self.platform.os_info()
1493    }
1494
1495    /// Check whether biometric authentication (Touch ID, Windows Hello) is available.
1496    pub fn biometric_status(&self) -> BiometricStatus {
1497        self.platform.biometric_status()
1498    }
1499
1500    /// Authenticate the user via biometrics with the given reason string.
1501    pub fn authenticate_biometric(
1502        &self,
1503        reason: &str,
1504        callback: impl FnOnce(bool) + Send + 'static,
1505    ) {
1506        self.platform
1507            .authenticate_biometric(reason, Box::new(callback));
1508    }
1509
1510    /// Install a panic hook that captures crash reports with backtraces and OS info.
1511    pub fn set_crash_handler(
1512        &self,
1513        app_version: Option<String>,
1514        handler: impl Fn(CrashReport) + Send + Sync + 'static,
1515    ) {
1516        let os_info = self.platform.os_info();
1517        let handler = std::sync::Arc::new(handler);
1518        std::panic::set_hook(Box::new(move |panic_info| {
1519            let message = if let Some(msg) = panic_info.payload().downcast_ref::<&str>() {
1520                msg.to_string()
1521            } else if let Some(msg) = panic_info.payload().downcast_ref::<String>() {
1522                msg.clone()
1523            } else {
1524                "Unknown panic".to_string()
1525            };
1526
1527            let location = panic_info
1528                .location()
1529                .map(|loc| format!("{}:{}:{}", loc.file(), loc.line(), loc.column()))
1530                .unwrap_or_default();
1531
1532            let full_message = if location.is_empty() {
1533                message
1534            } else {
1535                format!("{message} at {location}")
1536            };
1537
1538            let backtrace = std::backtrace::Backtrace::force_capture().to_string();
1539
1540            let report = CrashReport {
1541                message: full_message,
1542                backtrace,
1543                os_info: os_info.clone(),
1544                app_version: app_version.clone(),
1545            };
1546
1547            handler(report);
1548        }));
1549    }
1550
1551    /// Returns the list of currently active displays.
1552    pub fn displays(&self) -> Vec<Rc<dyn PlatformDisplay>> {
1553        self.platform.displays()
1554    }
1555
1556    /// Returns the primary display that will be used for new windows.
1557    pub fn primary_display(&self) -> Option<Rc<dyn PlatformDisplay>> {
1558        self.platform.primary_display()
1559    }
1560
1561    /// Compute window bounds from a desired size and a semantic position.
1562    pub fn compute_window_bounds(
1563        &self,
1564        size: Size<Pixels>,
1565        position: &WindowPosition,
1566    ) -> Bounds<Pixels> {
1567        let displays = self.platform.displays();
1568        let primary = self.platform.primary_display();
1569        crate::platform::window_positioner::compute_window_bounds(
1570            size,
1571            position,
1572            &displays,
1573            primary.as_ref(),
1574        )
1575    }
1576
1577    /// Returns whether `screen_capture_sources` may work.
1578    pub fn is_screen_capture_supported(&self) -> bool {
1579        self.platform.is_screen_capture_supported()
1580    }
1581
1582    /// Returns a list of available screen capture sources.
1583    pub fn screen_capture_sources(
1584        &self,
1585    ) -> oneshot::Receiver<Result<Vec<Rc<dyn ScreenCaptureSource>>>> {
1586        self.platform.screen_capture_sources()
1587    }
1588
1589    /// Returns the display with the given ID, if one exists.
1590    pub fn find_display(&self, id: DisplayId) -> Option<Rc<dyn PlatformDisplay>> {
1591        self.displays()
1592            .iter()
1593            .find(|display| display.id() == id)
1594            .cloned()
1595    }
1596
1597    /// Returns the appearance of the application's windows.
1598    pub fn window_appearance(&self) -> WindowAppearance {
1599        self.platform.window_appearance()
1600    }
1601
1602    /// Overrides the appearance (light/dark) applied to the app's windows, independent of
1603    /// the OS-wide setting. Pass `None` to clear the override and follow the system again.
1604    /// The current value is reported by [`App::window_appearance`].
1605    ///
1606    /// On macOS this sets the underlying `NSApplication.appearance`, which controls the
1607    /// native window chrome (the window border and titlebar) of every window. Use this
1608    /// when the app uses a dark theme while the system is in light mode (or vice versa)
1609    /// so the window edges render to match the theme. While an appearance is forced,
1610    /// windows stop tracking system light/dark changes; pass `None` to resume following
1611    /// the system. On other platforms the override is stored and reported by
1612    /// [`App::window_appearance`] without changing native chrome.
1613    pub fn set_window_appearance(&self, appearance: Option<WindowAppearance>) {
1614        self.platform.set_window_appearance(appearance);
1615    }
1616
1617    /// Writes data to the primary selection buffer.
1618    /// Only available on Linux.
1619    #[cfg(any(target_os = "linux", target_os = "freebsd"))]
1620    pub fn write_to_primary(&self, item: ClipboardItem) {
1621        self.platform.write_to_primary(item)
1622    }
1623
1624    /// Writes data to the platform clipboard.
1625    pub fn write_to_clipboard(&self, item: ClipboardItem) {
1626        self.platform.write_to_clipboard(item)
1627    }
1628
1629    /// Reads data from the primary selection buffer.
1630    /// Only available on Linux.
1631    #[cfg(any(target_os = "linux", target_os = "freebsd"))]
1632    pub fn read_from_primary(&self) -> Option<ClipboardItem> {
1633        self.platform.read_from_primary()
1634    }
1635
1636    /// Reads data from the platform clipboard.
1637    pub fn read_from_clipboard(&self) -> Option<ClipboardItem> {
1638        self.platform.read_from_clipboard()
1639    }
1640
1641    /// Writes credentials to the platform keychain.
1642    pub fn write_credentials(
1643        &self,
1644        url: &str,
1645        username: &str,
1646        password: &[u8],
1647    ) -> Task<Result<()>> {
1648        self.platform.write_credentials(url, username, password)
1649    }
1650
1651    /// Reads credentials from the platform keychain.
1652    pub fn read_credentials(&self, url: &str) -> Task<Result<Option<(String, Vec<u8>)>>> {
1653        self.platform.read_credentials(url)
1654    }
1655
1656    /// Deletes credentials from the platform keychain.
1657    pub fn delete_credentials(&self, url: &str) -> Task<Result<()>> {
1658        self.platform.delete_credentials(url)
1659    }
1660
1661    /// Directs the platform's default browser to open the given URL.
1662    pub fn open_url(&self, url: &str) {
1663        self.platform.open_url(url);
1664    }
1665
1666    /// Registers the given URL scheme (e.g. `zed` for `zed://` urls) to be
1667    /// opened by the current app.
1668    ///
1669    /// On some platforms (e.g. macOS) you may be able to register URL schemes
1670    /// as part of app distribution, but this method exists to let you register
1671    /// schemes at runtime.
1672    pub fn register_url_scheme(&self, scheme: &str) -> Task<Result<()>> {
1673        self.platform.register_url_scheme(scheme)
1674    }
1675
1676    /// Returns the full pathname of the current app bundle.
1677    ///
1678    /// Returns an error if the app is not being run from a bundle.
1679    pub fn app_path(&self) -> Result<PathBuf> {
1680        self.platform.app_path()
1681    }
1682
1683    /// On Linux, returns the name of the compositor in use.
1684    ///
1685    /// Returns an empty string on other platforms.
1686    pub fn compositor_name(&self) -> &'static str {
1687        self.platform.compositor_name()
1688    }
1689
1690    /// Returns the file URL of the executable with the specified name in the application bundle
1691    pub fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf> {
1692        self.platform.path_for_auxiliary_executable(name)
1693    }
1694
1695    /// Displays a platform modal for selecting paths.
1696    ///
1697    /// When one or more paths are selected, they'll be relayed asynchronously via the returned oneshot channel.
1698    /// If cancelled, a `None` will be relayed instead.
1699    /// May return an error on Linux if the file picker couldn't be opened.
1700    pub fn prompt_for_paths(
1701        &self,
1702        options: PathPromptOptions,
1703    ) -> oneshot::Receiver<Result<Option<Vec<PathBuf>>>> {
1704        self.platform.prompt_for_paths(options)
1705    }
1706
1707    /// Displays a platform modal for selecting a new path where a file can be saved.
1708    ///
1709    /// The provided directory will be used to set the initial location.
1710    /// When a path is selected, it is relayed asynchronously via the returned oneshot channel.
1711    /// If cancelled, a `None` will be relayed instead.
1712    /// May return an error on Linux if the file picker couldn't be opened.
1713    pub fn prompt_for_new_path(
1714        &self,
1715        directory: &Path,
1716        suggested_name: Option<&str>,
1717    ) -> oneshot::Receiver<Result<Option<PathBuf>>> {
1718        self.platform.prompt_for_new_path(directory, suggested_name)
1719    }
1720
1721    /// Reveals the specified path at the platform level, such as in Finder on macOS.
1722    pub fn reveal_path(&self, path: &Path) {
1723        self.platform.reveal_path(path)
1724    }
1725
1726    /// Opens the specified path with the system's default application.
1727    pub fn open_with_system(&self, path: &Path) {
1728        self.platform.open_with_system(path)
1729    }
1730
1731    /// Returns whether the user has configured scrollbars to auto-hide at the platform level.
1732    pub fn should_auto_hide_scrollbars(&self) -> bool {
1733        self.platform.should_auto_hide_scrollbars()
1734    }
1735
1736    /// Restarts the application.
1737    pub fn restart(&mut self) {
1738        self.restart_observers
1739            .clone()
1740            .retain(&(), |observer| observer(self));
1741        self.platform.restart(
1742            self.restart_path.take(),
1743            mem::take(&mut self.restart_arguments),
1744        )
1745    }
1746
1747    /// Sets the path to use when restarting the application.
1748    pub fn set_restart_path(&mut self, path: PathBuf) {
1749        self.restart_path = Some(path);
1750    }
1751
1752    /// Returns the HTTP client for the application.
1753    pub fn http_client(&self) -> Arc<dyn HttpClient> {
1754        self.http_client.clone()
1755    }
1756
1757    /// Sets the HTTP client for the application.
1758    pub fn set_http_client(&mut self, new_client: Arc<dyn HttpClient>) {
1759        self.http_client = new_client;
1760    }
1761
1762    /// Returns the SVG renderer used by the application.
1763    pub fn svg_renderer(&self) -> SvgRenderer {
1764        self.svg_renderer.clone()
1765    }
1766
1767    pub(crate) fn push_effect(&mut self, effect: Effect) {
1768        match &effect {
1769            Effect::Notify { emitter } => {
1770                if !self.pending_notifications.insert(*emitter) {
1771                    return;
1772                }
1773            }
1774            Effect::NotifyGlobalObservers { global_type } => {
1775                if !self.pending_global_notifications.insert(*global_type) {
1776                    return;
1777                }
1778            }
1779            _ => {}
1780        };
1781
1782        self.pending_effects.push_back(effect);
1783    }
1784
1785    /// Called at the end of [`App::update`] to complete any side effects
1786    /// such as notifying observers, emitting events, etc. Effects can themselves
1787    /// cause effects, so we continue looping until all effects are processed.
1788    fn flush_effects(&mut self) {
1789        loop {
1790            self.release_dropped_entities();
1791            self.release_dropped_focus_handles();
1792            if let Some(effect) = self.pending_effects.pop_front() {
1793                match effect {
1794                    Effect::Notify { emitter } => {
1795                        self.apply_notify_effect(emitter);
1796                    }
1797
1798                    Effect::Emit {
1799                        emitter,
1800                        event_type,
1801                        event,
1802                    } => self.apply_emit_effect(emitter, event_type, event),
1803
1804                    Effect::RefreshWindows => {
1805                        self.apply_refresh_effect();
1806                    }
1807
1808                    Effect::NotifyGlobalObservers { global_type } => {
1809                        self.apply_notify_global_observers_effect(global_type);
1810                    }
1811
1812                    Effect::Defer { callback } => {
1813                        self.apply_defer_effect(callback);
1814                    }
1815                    Effect::EntityCreated {
1816                        entity,
1817                        tid,
1818                        window,
1819                    } => {
1820                        self.apply_entity_created_effect(entity, tid, window);
1821                    }
1822                }
1823            } else {
1824                #[cfg(any(test, feature = "test-support"))]
1825                for window in self
1826                    .windows
1827                    .values()
1828                    .filter_map(|window| {
1829                        let window = window.as_ref()?;
1830                        window.invalidator.is_dirty().then_some(window.handle)
1831                    })
1832                    .collect::<Vec<_>>()
1833                {
1834                    self.update_window(window, |_, window, cx| window.draw(cx).clear())
1835                        .unwrap();
1836                }
1837
1838                if self.pending_effects.is_empty() {
1839                    for window in self.windows.values().filter_map(|window| window.as_ref()) {
1840                        if window.invalidator.is_dirty()
1841                            || window.needs_present.get()
1842                            || !window.next_frame_callbacks.borrow().is_empty()
1843                        {
1844                            window.platform_window.schedule_frame();
1845                        }
1846                    }
1847
1848                    break;
1849                }
1850            }
1851        }
1852    }
1853
1854    /// Repeatedly called during `flush_effects` to release any entities whose
1855    /// reference count has become zero. We invoke any release observers before dropping
1856    /// each entity.
1857    fn release_dropped_entities(&mut self) {
1858        loop {
1859            let dropped = self.entities.take_dropped();
1860            if dropped.is_empty() {
1861                break;
1862            }
1863
1864            for (entity_id, mut entity) in dropped {
1865                self.observers.remove(&entity_id);
1866                self.event_listeners.remove(&entity_id);
1867                for release_callback in self.release_listeners.remove(&entity_id) {
1868                    release_callback(entity.as_mut(), self);
1869                }
1870            }
1871        }
1872    }
1873
1874    /// Repeatedly called during `flush_effects` to handle a focused handle being dropped.
1875    fn release_dropped_focus_handles(&mut self) {
1876        self.focus_handles
1877            .clone()
1878            .write()
1879            .retain(|handle_id, focus| {
1880                if focus.ref_count.load(SeqCst) == 0 {
1881                    for window_handle in self.windows() {
1882                        window_handle
1883                            .update(self, |_, window, cx| {
1884                                if window.focus == Some(handle_id) {
1885                                    window.blur(cx);
1886                                }
1887                            })
1888                            .unwrap();
1889                    }
1890                    false
1891                } else {
1892                    true
1893                }
1894            });
1895    }
1896
1897    fn apply_notify_effect(&mut self, emitter: EntityId) {
1898        self.pending_notifications.remove(&emitter);
1899
1900        self.observers
1901            .clone()
1902            .retain(&emitter, |handler| handler(self));
1903    }
1904
1905    fn apply_emit_effect(&mut self, emitter: EntityId, event_type: TypeId, event: Box<dyn Any>) {
1906        self.event_listeners
1907            .clone()
1908            .retain(&emitter, |(stored_type, handler)| {
1909                if *stored_type == event_type {
1910                    handler(event.as_ref(), self)
1911                } else {
1912                    true
1913                }
1914            });
1915    }
1916
1917    fn apply_refresh_effect(&mut self) {
1918        for window in self.windows.values_mut() {
1919            if let Some(window) = window.as_mut() {
1920                window.refreshing = true;
1921                window.invalidator.set_dirty(true);
1922            }
1923        }
1924    }
1925
1926    fn apply_notify_global_observers_effect(&mut self, type_id: TypeId) {
1927        self.pending_global_notifications.remove(&type_id);
1928        self.global_observers
1929            .clone()
1930            .retain(&type_id, |observer| observer(self));
1931    }
1932
1933    fn apply_defer_effect(&mut self, callback: Box<dyn FnOnce(&mut Self) + 'static>) {
1934        callback(self);
1935    }
1936
1937    fn apply_entity_created_effect(
1938        &mut self,
1939        entity: AnyEntity,
1940        tid: TypeId,
1941        window: Option<WindowId>,
1942    ) {
1943        self.new_entity_observers.clone().retain(&tid, |observer| {
1944            if let Some(id) = window {
1945                self.update_window_id(id, {
1946                    let entity = entity.clone();
1947                    |_, window, cx| (observer)(entity, &mut Some(window), cx)
1948                })
1949                .expect("All windows should be off the stack when flushing effects");
1950            } else {
1951                (observer)(entity.clone(), &mut None, self)
1952            }
1953            true
1954        });
1955    }
1956
1957    fn update_window_id<T, F>(&mut self, id: WindowId, update: F) -> Result<T>
1958    where
1959        F: FnOnce(AnyView, &mut Window, &mut App) -> T,
1960    {
1961        self.update(|cx| {
1962            let mut window = cx.windows.get_mut(id)?.take()?;
1963
1964            let root_view = window.root.clone().unwrap();
1965
1966            cx.window_update_stack.push(window.handle.id);
1967            let result = update(root_view, &mut window, cx);
1968            cx.window_update_stack.pop();
1969
1970            if window.removed {
1971                cx.window_handles.remove(&id);
1972                cx.windows.remove(id);
1973
1974                cx.window_closed_observers.clone().retain(&(), |callback| {
1975                    callback(cx);
1976                    true
1977                });
1978
1979                let quit_on_empty = match cx.quit_mode {
1980                    QuitMode::Explicit => false,
1981                    QuitMode::LastWindowClosed => true,
1982                    QuitMode::Default => cfg!(not(target_os = "macos")),
1983                };
1984
1985                if quit_on_empty && cx.windows.is_empty() {
1986                    cx.quit();
1987                }
1988            } else {
1989                cx.windows.get_mut(id)?.replace(window);
1990            }
1991
1992            Some(result)
1993        })
1994        .context("window not found")
1995    }
1996
1997    /// Creates an `AsyncApp`, which can be cloned and has a static lifetime
1998    /// so it can be held across `await` points.
1999    pub fn to_async(&self) -> AsyncApp {
2000        AsyncApp {
2001            app: self.this.clone(),
2002            background_executor: self.background_executor.clone(),
2003            foreground_executor: self.foreground_executor.clone(),
2004        }
2005    }
2006
2007    /// Obtains a reference to the executor, which can be used to spawn futures.
2008    pub fn background_executor(&self) -> &BackgroundExecutor {
2009        &self.background_executor
2010    }
2011
2012    /// Whether this app runs on the deterministic test dispatcher. See
2013    /// [`BackgroundExecutor::is_test`].
2014    pub fn is_test(&self) -> bool {
2015        self.background_executor.is_test()
2016    }
2017
2018    /// Obtains a reference to the executor, which can be used to spawn futures.
2019    pub fn foreground_executor(&self) -> &ForegroundExecutor {
2020        if self.quitting {
2021            panic!("Can't spawn on main thread after on_app_quit")
2022        };
2023        &self.foreground_executor
2024    }
2025
2026    /// Spawns the future returned by the given function on the main thread. The closure will be invoked
2027    /// with [AsyncApp], which allows the application state to be accessed across await points.
2028    #[track_caller]
2029    pub fn spawn<AsyncFn, R>(&self, f: AsyncFn) -> Task<R>
2030    where
2031        AsyncFn: AsyncFnOnce(&mut AsyncApp) -> R + 'static,
2032        R: 'static,
2033    {
2034        if self.quitting {
2035            debug_panic!("Can't spawn on main thread after on_app_quit")
2036        };
2037
2038        let mut cx = self.to_async();
2039
2040        self.foreground_executor
2041            .spawn(async move { f(&mut cx).await })
2042    }
2043
2044    /// Schedules the given function to be run at the end of the current effect cycle, allowing entities
2045    /// that are currently on the stack to be returned to the app.
2046    pub fn defer(&mut self, f: impl FnOnce(&mut App) + 'static) {
2047        self.push_effect(Effect::Defer {
2048            callback: Box::new(f),
2049        });
2050    }
2051
2052    /// Accessor for the application's asset source, which is provided when constructing the `App`.
2053    pub fn asset_source(&self) -> &Arc<dyn AssetSource> {
2054        &self.asset_source
2055    }
2056
2057    /// Accessor for the text system.
2058    pub fn text_system(&self) -> &Arc<TextSystem> {
2059        &self.text_system
2060    }
2061
2062    /// Check whether a global of the given type has been assigned.
2063    pub fn has_global<G: Global>(&self) -> bool {
2064        self.globals_by_type.contains_key(&TypeId::of::<G>())
2065    }
2066
2067    /// Access the global of the given type. Panics if a global for that type has not been assigned.
2068    #[track_caller]
2069    pub fn global<G: Global>(&self) -> &G {
2070        self.globals_by_type
2071            .get(&TypeId::of::<G>())
2072            .map(|any_state| any_state.downcast_ref::<G>().unwrap())
2073            .with_context(|| format!("no state of type {} exists", type_name::<G>()))
2074            .unwrap()
2075    }
2076
2077    /// Access the global of the given type if a value has been assigned.
2078    pub fn try_global<G: Global>(&self) -> Option<&G> {
2079        self.globals_by_type
2080            .get(&TypeId::of::<G>())
2081            .map(|any_state| any_state.downcast_ref::<G>().unwrap())
2082    }
2083
2084    /// Access the global of the given type mutably. Panics if a global for that type has not been assigned.
2085    #[track_caller]
2086    pub fn global_mut<G: Global>(&mut self) -> &mut G {
2087        let global_type = TypeId::of::<G>();
2088        self.push_effect(Effect::NotifyGlobalObservers { global_type });
2089        self.globals_by_type
2090            .get_mut(&global_type)
2091            .and_then(|any_state| any_state.downcast_mut::<G>())
2092            .with_context(|| format!("no state of type {} exists", type_name::<G>()))
2093            .unwrap()
2094    }
2095
2096    /// Access the global of the given type mutably. A default value is assigned if a global of this type has not
2097    /// yet been assigned.
2098    pub fn default_global<G: Global + Default>(&mut self) -> &mut G {
2099        let global_type = TypeId::of::<G>();
2100        self.push_effect(Effect::NotifyGlobalObservers { global_type });
2101        self.globals_by_type
2102            .entry(global_type)
2103            .or_insert_with(|| Box::<G>::default())
2104            .downcast_mut::<G>()
2105            .unwrap()
2106    }
2107
2108    /// Sets the value of the global of the given type.
2109    pub fn set_global<G: Global>(&mut self, global: G) {
2110        let global_type = TypeId::of::<G>();
2111        self.push_effect(Effect::NotifyGlobalObservers { global_type });
2112        self.globals_by_type.insert(global_type, Box::new(global));
2113    }
2114
2115    /// Clear all stored globals. Does not notify global observers.
2116    #[cfg(any(test, feature = "test-support"))]
2117    pub fn clear_globals(&mut self) {
2118        self.globals_by_type.drain();
2119    }
2120
2121    /// Remove the global of the given type from the app context. Does not notify global observers.
2122    pub fn remove_global<G: Global>(&mut self) -> G {
2123        let global_type = TypeId::of::<G>();
2124        self.push_effect(Effect::NotifyGlobalObservers { global_type });
2125        *self
2126            .globals_by_type
2127            .remove(&global_type)
2128            .unwrap_or_else(|| panic!("no global added for {}", std::any::type_name::<G>()))
2129            .downcast()
2130            .unwrap()
2131    }
2132
2133    /// Register a callback to be invoked when a global of the given type is updated.
2134    pub fn observe_global<G: Global>(
2135        &mut self,
2136        mut f: impl FnMut(&mut Self) + 'static,
2137    ) -> Subscription {
2138        let (subscription, activate) = self.global_observers.insert(
2139            TypeId::of::<G>(),
2140            Box::new(move |cx| {
2141                f(cx);
2142                true
2143            }),
2144        );
2145        self.defer(move |_| activate());
2146        subscription
2147    }
2148
2149    /// Move the global of the given type to the stack.
2150    #[track_caller]
2151    pub(crate) fn lease_global<G: Global>(&mut self) -> GlobalLease<G> {
2152        GlobalLease::new(
2153            self.globals_by_type
2154                .remove(&TypeId::of::<G>())
2155                .with_context(|| format!("no global registered of type {}", type_name::<G>()))
2156                .unwrap(),
2157        )
2158    }
2159
2160    /// Restore the global of the given type after it is moved to the stack.
2161    pub(crate) fn end_global_lease<G: Global>(&mut self, lease: GlobalLease<G>) {
2162        let global_type = TypeId::of::<G>();
2163
2164        self.push_effect(Effect::NotifyGlobalObservers { global_type });
2165        self.globals_by_type.insert(global_type, lease.global);
2166    }
2167
2168    pub(crate) fn new_entity_observer(
2169        &self,
2170        key: TypeId,
2171        value: NewEntityListener,
2172    ) -> Subscription {
2173        let (subscription, activate) = self.new_entity_observers.insert(key, value);
2174        activate();
2175        subscription
2176    }
2177
2178    /// Arrange for the given function to be invoked whenever a view of the specified type is created.
2179    /// The function will be passed a mutable reference to the view along with an appropriate context.
2180    pub fn observe_new<T: 'static>(
2181        &self,
2182        on_new: impl 'static + Fn(&mut T, Option<&mut Window>, &mut Context<T>),
2183    ) -> Subscription {
2184        self.new_entity_observer(
2185            TypeId::of::<T>(),
2186            Box::new(
2187                move |any_entity: AnyEntity, window: &mut Option<&mut Window>, cx: &mut App| {
2188                    any_entity
2189                        .downcast::<T>()
2190                        .unwrap()
2191                        .update(cx, |entity_state, cx| {
2192                            on_new(entity_state, window.as_deref_mut(), cx)
2193                        })
2194                },
2195            ),
2196        )
2197    }
2198
2199    /// Observe the release of a entity. The callback is invoked after the entity
2200    /// has no more strong references but before it has been dropped.
2201    pub fn observe_release<T>(
2202        &self,
2203        handle: &Entity<T>,
2204        on_release: impl FnOnce(&mut T, &mut App) + 'static,
2205    ) -> Subscription
2206    where
2207        T: 'static,
2208    {
2209        let (subscription, activate) = self.release_listeners.insert(
2210            handle.entity_id(),
2211            Box::new(move |entity, cx| {
2212                let entity = entity.downcast_mut().expect("invalid entity type");
2213                on_release(entity, cx)
2214            }),
2215        );
2216        activate();
2217        subscription
2218    }
2219
2220    /// Observe the release of a entity. The callback is invoked after the entity
2221    /// has no more strong references but before it has been dropped.
2222    pub fn observe_release_in<T>(
2223        &self,
2224        handle: &Entity<T>,
2225        window: &Window,
2226        on_release: impl FnOnce(&mut T, &mut Window, &mut App) + 'static,
2227    ) -> Subscription
2228    where
2229        T: 'static,
2230    {
2231        let window_handle = window.handle;
2232        self.observe_release(handle, move |entity, cx| {
2233            let _ = window_handle.update(cx, |_, window, cx| on_release(entity, window, cx));
2234        })
2235    }
2236
2237    /// Register a callback to be invoked after a keystroke is resolved in any window,
2238    /// including the action that handled it, if any. Keystrokes consumed by an
2239    /// interceptor or raw keyboard event handler are not observed.
2240    /// Standalone modifiers are observed on release.
2241    pub fn observe_keystrokes(
2242        &mut self,
2243        mut f: impl FnMut(&KeystrokeEvent, &mut Window, &mut App) + 'static,
2244    ) -> Subscription {
2245        fn inner(
2246            keystroke_observers: &SubscriberSet<(), KeystrokeObserver>,
2247            handler: KeystrokeObserver,
2248        ) -> Subscription {
2249            let (subscription, activate) = keystroke_observers.insert((), handler);
2250            activate();
2251            subscription
2252        }
2253
2254        inner(
2255            &self.keystroke_observers,
2256            Box::new(move |event, window, cx| {
2257                f(event, window, cx);
2258                true
2259            }),
2260        )
2261    }
2262
2263    /// Registers a callback to be invoked with grapheme clusters that exhausted
2264    /// font fallback, as observed by the platform text system. Intended for
2265    /// dynamic font installation: the callback can register a font covering the
2266    /// reported graphemes with [`TextSystem::add_fonts`], which invalidates
2267    /// cached layouts so the text is shaped again.
2268    ///
2269    /// Reports are deduplicated and bounded (see `MAX_REPORTED_MISSING_GLYPHS`).
2270    /// Only one registration is available per application; later calls log a
2271    /// warning and are ignored. The callback runs on the main thread until the
2272    /// application quits.
2273    pub fn on_missing_glyphs(&self, mut callback: impl FnMut(&[MissingGlyph], &mut App) + 'static) {
2274        let Some(mut receiver) = self.text_system.take_missing_glyph_receiver() else {
2275            log::warn!("App::on_missing_glyphs called more than once; ignoring registration");
2276            return;
2277        };
2278        self.spawn(async move |cx| {
2279            while let Ok(missing_glyphs) = receiver.recv().await {
2280                if cx.update(|cx| callback(&missing_glyphs, cx)).is_err() {
2281                    // The application is shutting down.
2282                    break;
2283                }
2284            }
2285        })
2286        .detach();
2287    }
2288
2289    /// Register a callback to be invoked when a keystroke is received by the application
2290    /// in any window. Note that this fires _before_ all other action and event mechanisms have resolved
2291    /// unlike [`App::observe_keystrokes`] which fires after. This means that `cx.stop_propagation` calls
2292    /// within interceptors will prevent action dispatch
2293    pub fn intercept_keystrokes(
2294        &mut self,
2295        mut f: impl FnMut(&KeystrokeEvent, &mut Window, &mut App) + 'static,
2296    ) -> Subscription {
2297        fn inner(
2298            keystroke_interceptors: &SubscriberSet<(), KeystrokeObserver>,
2299            handler: KeystrokeObserver,
2300        ) -> Subscription {
2301            let (subscription, activate) = keystroke_interceptors.insert((), handler);
2302            activate();
2303            subscription
2304        }
2305
2306        inner(
2307            &self.keystroke_interceptors,
2308            Box::new(move |event, window, cx| {
2309                f(event, window, cx);
2310                true
2311            }),
2312        )
2313    }
2314
2315    /// Register key bindings.
2316    pub fn bind_keys(&mut self, bindings: impl IntoIterator<Item = KeyBinding>) {
2317        self.keymap.borrow_mut().add_bindings(bindings);
2318        self.pending_effects.push_back(Effect::RefreshWindows);
2319    }
2320
2321    /// Clear all key bindings in the app.
2322    pub fn clear_key_bindings(&mut self) {
2323        self.keymap.borrow_mut().clear();
2324        self.pending_effects.push_back(Effect::RefreshWindows);
2325    }
2326
2327    /// Get all key bindings in the app.
2328    pub fn key_bindings(&self) -> Rc<RefCell<Keymap>> {
2329        self.keymap.clone()
2330    }
2331
2332    /// Register a global handler for actions invoked via the keyboard. These handlers are run at
2333    /// the end of the bubble phase for actions, and so will only be invoked if there are no other
2334    /// handlers or if they called `cx.propagate()`.
2335    pub fn on_action<A: Action>(&mut self, listener: impl Fn(&A, &mut Self) + 'static) {
2336        self.global_action_listeners
2337            .entry(TypeId::of::<A>())
2338            .or_default()
2339            .push(Rc::new(move |action, phase, cx| {
2340                if phase == DispatchPhase::Bubble {
2341                    let action = action.downcast_ref().unwrap();
2342                    listener(action, cx)
2343                }
2344            }));
2345    }
2346
2347    /// Event handlers propagate events by default. Call this method to stop dispatching to
2348    /// event handlers with a lower z-index (mouse) or higher in the tree (keyboard). This is
2349    /// the opposite of [`Self::propagate`]. It's also possible to cancel a call to [`Self::propagate`] by
2350    /// calling this method before effects are flushed.
2351    pub fn stop_propagation(&mut self) {
2352        self.propagate_event = false;
2353    }
2354
2355    /// Action handlers stop propagation by default during the bubble phase of action dispatch
2356    /// dispatching to action handlers higher in the element tree. This is the opposite of
2357    /// [`Self::stop_propagation`]. It's also possible to cancel a call to [`Self::stop_propagation`] by calling
2358    /// this method before effects are flushed.
2359    pub fn propagate(&mut self) {
2360        self.propagate_event = true;
2361    }
2362
2363    /// Build an action from some arbitrary data, typically a keymap entry.
2364    pub fn build_action(
2365        &self,
2366        name: &str,
2367        data: Option<serde_json::Value>,
2368    ) -> std::result::Result<Box<dyn Action>, ActionBuildError> {
2369        self.actions.build_action(name, data)
2370    }
2371
2372    /// Get all action names that have been registered. Note that registration only allows for
2373    /// actions to be built dynamically, and is unrelated to binding actions in the element tree.
2374    pub fn all_action_names(&self) -> &[&'static str] {
2375        self.actions.all_action_names()
2376    }
2377
2378    /// Returns key bindings that invoke the given action on the currently focused element, without
2379    /// checking context. Bindings are returned in the order they were added. For display, the last
2380    /// binding should take precedence.
2381    pub fn all_bindings_for_input(&self, input: &[Keystroke]) -> Vec<KeyBinding> {
2382        RefCell::borrow(&self.keymap).all_bindings_for_input(input)
2383    }
2384
2385    /// Get all non-internal actions that have been registered, along with their schemas.
2386    pub fn action_schemas(
2387        &self,
2388        generator: &mut schemars::SchemaGenerator,
2389    ) -> Vec<(&'static str, Option<schemars::Schema>)> {
2390        self.actions.action_schemas(generator)
2391    }
2392
2393    /// Get a map from a deprecated action name to the canonical name.
2394    pub fn deprecated_actions_to_preferred_actions(&self) -> &HashMap<&'static str, &'static str> {
2395        self.actions.deprecated_aliases()
2396    }
2397
2398    /// Get a map from an action name to the deprecation messages.
2399    pub fn action_deprecation_messages(&self) -> &HashMap<&'static str, &'static str> {
2400        self.actions.deprecation_messages()
2401    }
2402
2403    /// Get a map from an action name to the documentation.
2404    pub fn action_documentation(&self) -> &HashMap<&'static str, &'static str> {
2405        self.actions.documentation()
2406    }
2407
2408    /// Register a callback to be invoked when the application is about to quit.
2409    /// It is not possible to cancel the quit event at this point.
2410    pub fn on_app_quit<Fut>(
2411        &self,
2412        mut on_quit: impl FnMut(&mut App) -> Fut + 'static,
2413    ) -> Subscription
2414    where
2415        Fut: 'static + Future<Output = ()>,
2416    {
2417        let (subscription, activate) = self.quit_observers.insert(
2418            (),
2419            Box::new(move |cx| {
2420                let future = on_quit(cx);
2421                future.boxed_local()
2422            }),
2423        );
2424        activate();
2425        subscription
2426    }
2427
2428    /// Register a callback to be invoked when the application is about to restart.
2429    ///
2430    /// These callbacks are called before any `on_app_quit` callbacks.
2431    pub fn on_app_restart(&self, mut on_restart: impl 'static + FnMut(&mut App)) -> Subscription {
2432        let (subscription, activate) = self.restart_observers.insert(
2433            (),
2434            Box::new(move |cx| {
2435                on_restart(cx);
2436                true
2437            }),
2438        );
2439        activate();
2440        subscription
2441    }
2442
2443    /// Register a callback to be invoked when a window is closed
2444    /// The window is no longer accessible at the point this callback is invoked.
2445    pub fn on_window_closed(&self, mut on_closed: impl FnMut(&mut App) + 'static) -> Subscription {
2446        let (subscription, activate) = self.window_closed_observers.insert((), Box::new(on_closed));
2447        activate();
2448        subscription
2449    }
2450
2451    pub(crate) fn clear_pending_keystrokes(&mut self) {
2452        for window in self.windows() {
2453            window
2454                .update(self, |_, window, cx| {
2455                    window.clear_pending_keystrokes(cx);
2456                })
2457                .ok();
2458        }
2459    }
2460
2461    /// Checks if the given action is bound in the current context, as defined by the app's current focus,
2462    /// the bindings in the element tree, and any global action listeners.
2463    pub fn is_action_available(&mut self, action: &dyn Action) -> bool {
2464        let mut action_available = false;
2465        if let Some(window) = self.active_window()
2466            && let Ok(window_action_available) =
2467                window.update(self, |_, window, cx| window.is_action_available(action, cx))
2468        {
2469            action_available = window_action_available;
2470        }
2471
2472        action_available
2473            || self
2474                .global_action_listeners
2475                .contains_key(&action.as_any().type_id())
2476    }
2477
2478    /// Sets the menu bar for this application. This will replace any existing menu bar.
2479    pub fn set_menus(&self, menus: Vec<Menu>) {
2480        self.platform.set_menus(menus, &self.keymap.borrow());
2481    }
2482
2483    /// Gets the menu bar for this application.
2484    pub fn get_menus(&self) -> Option<Vec<OwnedMenu>> {
2485        self.platform.get_menus()
2486    }
2487
2488    /// Sets the right click menu for the app icon in the dock
2489    pub fn set_dock_menu(&self, menus: Vec<MenuItem>) {
2490        self.platform.set_dock_menu(menus, &self.keymap.borrow())
2491    }
2492
2493    /// Performs the action associated with the given dock menu item, only used on Windows for now.
2494    pub fn perform_dock_menu_action(&self, action: usize) {
2495        self.platform.perform_dock_menu_action(action);
2496    }
2497
2498    /// Adds given path to the bottom of the list of recent paths for the application.
2499    /// The list is usually shown on the application icon's context menu in the dock,
2500    /// and allows to open the recent files via that context menu.
2501    /// If the path is already in the list, it will be moved to the bottom of the list.
2502    pub fn add_recent_document(&self, path: &Path) {
2503        self.platform.add_recent_document(path);
2504    }
2505
2506    /// Updates the jump list with the updated list of recent paths for the application, only used on Windows for now.
2507    /// Note that this also sets the dock menu on Windows.
2508    pub fn update_jump_list(
2509        &self,
2510        menus: Vec<MenuItem>,
2511        entries: Vec<SmallVec<[PathBuf; 2]>>,
2512    ) -> Vec<SmallVec<[PathBuf; 2]>> {
2513        self.platform.update_jump_list(menus, entries)
2514    }
2515
2516    /// Dispatch an action to the currently active window or global action handler
2517    /// See [`crate::Action`] for more information on how actions work
2518    pub fn dispatch_action(&mut self, action: &dyn Action) {
2519        if let Some(active_window) = self.active_window() {
2520            active_window
2521                .update(self, |_, window, cx| {
2522                    window.dispatch_action(action.boxed_clone(), cx)
2523                })
2524                .log_err();
2525        } else {
2526            self.dispatch_global_action(action);
2527        }
2528    }
2529
2530    fn dispatch_global_action(&mut self, action: &dyn Action) {
2531        self.propagate_event = true;
2532
2533        if let Some(mut global_listeners) = self
2534            .global_action_listeners
2535            .remove(&action.as_any().type_id())
2536        {
2537            for listener in &global_listeners {
2538                listener(action.as_any(), DispatchPhase::Capture, self);
2539                if !self.propagate_event {
2540                    break;
2541                }
2542            }
2543
2544            global_listeners.extend(
2545                self.global_action_listeners
2546                    .remove(&action.as_any().type_id())
2547                    .unwrap_or_default(),
2548            );
2549
2550            self.global_action_listeners
2551                .insert(action.as_any().type_id(), global_listeners);
2552        }
2553
2554        if self.propagate_event
2555            && let Some(mut global_listeners) = self
2556                .global_action_listeners
2557                .remove(&action.as_any().type_id())
2558        {
2559            for listener in global_listeners.iter().rev() {
2560                listener(action.as_any(), DispatchPhase::Bubble, self);
2561                if !self.propagate_event {
2562                    break;
2563                }
2564            }
2565
2566            global_listeners.extend(
2567                self.global_action_listeners
2568                    .remove(&action.as_any().type_id())
2569                    .unwrap_or_default(),
2570            );
2571
2572            self.global_action_listeners
2573                .insert(action.as_any().type_id(), global_listeners);
2574        }
2575    }
2576
2577    /// Is there currently something being dragged?
2578    pub fn has_active_drag(&self) -> bool {
2579        self.active_drag.is_some()
2580    }
2581
2582    /// Gets the cursor style of the currently active drag operation.
2583    pub fn active_drag_cursor_style(&self) -> Option<CursorStyle> {
2584        self.active_drag.as_ref().and_then(|drag| drag.cursor_style)
2585    }
2586
2587    /// Stops active drag and clears any related effects.
2588    pub fn stop_active_drag(&mut self, window: &mut Window) -> bool {
2589        if self.active_drag.is_some() {
2590            self.active_drag = None;
2591            window.refresh();
2592            true
2593        } else {
2594            false
2595        }
2596    }
2597
2598    /// Sets the cursor style for the currently active drag operation.
2599    pub fn set_active_drag_cursor_style(
2600        &mut self,
2601        cursor_style: CursorStyle,
2602        window: &mut Window,
2603    ) -> bool {
2604        if let Some(ref mut drag) = self.active_drag {
2605            drag.cursor_style = Some(cursor_style);
2606            window.refresh();
2607            true
2608        } else {
2609            false
2610        }
2611    }
2612
2613    /// Set the prompt renderer for GPUI. This will replace the default or platform specific
2614    /// prompts with this custom implementation.
2615    pub fn set_prompt_builder(
2616        &mut self,
2617        renderer: impl Fn(
2618            PromptLevel,
2619            &str,
2620            Option<&str>,
2621            &[PromptButton],
2622            PromptHandle,
2623            &mut Window,
2624            &mut App,
2625        ) -> RenderablePromptHandle
2626        + 'static,
2627    ) {
2628        self.prompt_builder = Some(PromptBuilder::Custom(Box::new(renderer)));
2629    }
2630
2631    /// Reset the prompt builder to the default implementation.
2632    pub fn reset_prompt_builder(&mut self) {
2633        self.prompt_builder = Some(PromptBuilder::Default);
2634    }
2635
2636    /// Remove an asset from GPUI's cache
2637    pub fn remove_asset<A: Asset>(&mut self, source: &A::Source) {
2638        let asset_id = (TypeId::of::<A>(), hash(source));
2639        self.loading_assets.remove(&asset_id);
2640    }
2641
2642    /// Check whether an asset is present in GPUI's cache (loading or loaded),
2643    /// without fetching it.
2644    #[cfg(any(test, feature = "test-support"))]
2645    pub fn has_asset<A: Asset>(&self, source: &A::Source) -> bool {
2646        let asset_id = (TypeId::of::<A>(), hash(source));
2647        self.loading_assets.contains_key(&asset_id)
2648    }
2649
2650    /// Starts loading an uncached asset and returns its result once available.
2651    ///
2652    /// Pending loads and completed results are cached until [`Self::remove_asset`].
2653    /// This method does not subscribe a view to completion notifications.
2654    pub fn fetch_asset<A: Asset>(&mut self, source: &A::Source) -> Option<A::Output> {
2655        self.asset_entry::<A>(source).get()
2656    }
2657
2658    pub(crate) fn asset_entry<A: Asset>(&mut self, source: &A::Source) -> &CachedLoad<A::Output> {
2659        let asset_id = (TypeId::of::<A>(), hash(source));
2660        if !self.loading_assets.contains_key(&asset_id) {
2661            let future = A::load(source.clone(), self);
2662            let entry = CachedLoad::new(future, self);
2663            self.loading_assets.insert(asset_id, Box::new(entry));
2664        }
2665        self.loading_assets
2666            .get(&asset_id)
2667            .and_then(|entry| entry.downcast_ref())
2668            .expect("asset cache entries are keyed by their asset type")
2669    }
2670
2671    /// Obtain a new [`FocusHandle`], which allows you to track and manipulate the keyboard focus
2672    /// for elements rendered within this window.
2673    #[track_caller]
2674    pub fn focus_handle(&self) -> FocusHandle {
2675        FocusHandle::new(&self.focus_handles)
2676    }
2677
2678    /// Tell GPUI that an entity has changed and observers of it should be notified.
2679    pub fn notify(&mut self, entity_id: EntityId) {
2680        let window_invalidators = mem::take(
2681            self.window_invalidators_by_entity
2682                .entry(entity_id)
2683                .or_default(),
2684        );
2685
2686        if window_invalidators.is_empty() {
2687            if self.pending_notifications.insert(entity_id) {
2688                self.pending_effects
2689                    .push_back(Effect::Notify { emitter: entity_id });
2690            }
2691        } else {
2692            for invalidator in window_invalidators.values() {
2693                invalidator.invalidate_view(entity_id, self);
2694            }
2695        }
2696
2697        self.window_invalidators_by_entity
2698            .insert(entity_id, window_invalidators);
2699    }
2700
2701    /// Returns the name for this [`App`].
2702    #[cfg(any(test, feature = "test-support", debug_assertions))]
2703    pub fn get_name(&self) -> Option<&'static str> {
2704        self.name
2705    }
2706
2707    /// Returns `true` if the platform file picker supports selecting a mix of files and directories.
2708    pub fn can_select_mixed_files_and_dirs(&self) -> bool {
2709        self.platform.can_select_mixed_files_and_dirs()
2710    }
2711
2712    /// Removes an image from the sprite atlas on all windows.
2713    ///
2714    /// If the current window is being updated, it will be removed from `App.windows`, you can use `current_window` to specify the current window.
2715    /// This is a no-op if the image is not in the sprite atlas.
2716    pub fn drop_image(&mut self, image: Arc<RenderImage>, current_window: Option<&mut Window>) {
2717        // remove the texture from all other windows
2718        for window in self.windows.values_mut().flatten() {
2719            _ = window.drop_image(image.clone());
2720        }
2721
2722        // remove the texture from the current window
2723        if let Some(window) = current_window {
2724            _ = window.drop_image(image);
2725        }
2726    }
2727
2728    /// Sets the renderer for the inspector.
2729    #[cfg(any(feature = "inspector", debug_assertions))]
2730    pub fn set_inspector_renderer(&mut self, f: crate::InspectorRenderer) {
2731        self.inspector_renderer = Some(f);
2732    }
2733
2734    /// Registers a renderer specific to an inspector state.
2735    #[cfg(any(feature = "inspector", debug_assertions))]
2736    pub fn register_inspector_element<T: 'static, R: crate::IntoElement>(
2737        &mut self,
2738        f: impl 'static + Fn(crate::InspectorElementId, &T, &mut Window, &mut App) -> R,
2739    ) {
2740        self.inspector_element_registry.register(f);
2741    }
2742
2743    /// Initializes gpui's default colors for the application.
2744    ///
2745    /// These colors can be accessed through `cx.default_colors()`.
2746    pub fn init_colors(&mut self) {
2747        self.set_global(GlobalColors(Arc::new(Colors::default())));
2748    }
2749}
2750
2751impl AppContext for App {
2752    type Result<T> = T;
2753
2754    /// Builds an entity that is owned by the application.
2755    ///
2756    /// The given function will be invoked with a [`Context`] and must return an object representing the entity. An
2757    /// [`Entity`] handle will be returned, which can be used to access the entity in a context.
2758    fn new<T: 'static>(&mut self, build_entity: impl FnOnce(&mut Context<T>) -> T) -> Entity<T> {
2759        self.update(|cx| {
2760            let slot = cx.entities.reserve();
2761            let handle = slot.clone();
2762            let entity = build_entity(&mut Context::new_context(cx, slot.downgrade()));
2763
2764            cx.push_effect(Effect::EntityCreated {
2765                entity: handle.clone().into_any(),
2766                tid: TypeId::of::<T>(),
2767                window: cx.window_update_stack.last().cloned(),
2768            });
2769
2770            cx.entities.insert(slot, entity);
2771            handle
2772        })
2773    }
2774
2775    fn reserve_entity<T: 'static>(&mut self) -> Self::Result<Reservation<T>> {
2776        Reservation(self.entities.reserve())
2777    }
2778
2779    fn insert_entity<T: 'static>(
2780        &mut self,
2781        reservation: Reservation<T>,
2782        build_entity: impl FnOnce(&mut Context<T>) -> T,
2783    ) -> Self::Result<Entity<T>> {
2784        self.update(|cx| {
2785            let slot = reservation.0;
2786            let entity = build_entity(&mut Context::new_context(cx, slot.downgrade()));
2787            cx.entities.insert(slot, entity)
2788        })
2789    }
2790
2791    /// Updates the entity referenced by the given handle. The function is passed a mutable reference to the
2792    /// entity along with a `Context` for the entity.
2793    fn update_entity<T: 'static, R>(
2794        &mut self,
2795        handle: &Entity<T>,
2796        update: impl FnOnce(&mut T, &mut Context<T>) -> R,
2797    ) -> R {
2798        self.update(|cx| {
2799            let mut entity = cx.entities.lease(handle);
2800            let result = update(
2801                &mut entity,
2802                &mut Context::new_context(cx, handle.downgrade()),
2803            );
2804            cx.entities.end_lease(entity);
2805            result
2806        })
2807    }
2808
2809    fn as_mut<'a, T>(&'a mut self, handle: &Entity<T>) -> GpuiBorrow<'a, T>
2810    where
2811        T: 'static,
2812    {
2813        GpuiBorrow::new(handle.clone(), self)
2814    }
2815
2816    fn read_entity<T, R>(
2817        &self,
2818        handle: &Entity<T>,
2819        read: impl FnOnce(&T, &App) -> R,
2820    ) -> Self::Result<R>
2821    where
2822        T: 'static,
2823    {
2824        let entity = self.entities.read(handle);
2825        read(entity, self)
2826    }
2827
2828    fn update_window<T, F>(&mut self, handle: AnyWindowHandle, update: F) -> Result<T>
2829    where
2830        F: FnOnce(AnyView, &mut Window, &mut App) -> T,
2831    {
2832        self.update_window_id(handle.id, update)
2833    }
2834
2835    fn read_window<T, R>(
2836        &self,
2837        window: &WindowHandle<T>,
2838        read: impl FnOnce(Entity<T>, &App) -> R,
2839    ) -> Result<R>
2840    where
2841        T: 'static,
2842    {
2843        let window = self
2844            .windows
2845            .get(window.id)
2846            .context("window not found")?
2847            .as_ref()
2848            .expect("attempted to read a window that is already on the stack");
2849
2850        let root_view = window.root.clone().unwrap();
2851        let view = root_view
2852            .downcast::<T>()
2853            .map_err(|_| anyhow!("root view's type has changed"))?;
2854
2855        Ok(read(view, self))
2856    }
2857
2858    fn background_spawn<R>(&self, future: impl Future<Output = R> + Send + 'static) -> Task<R>
2859    where
2860        R: Send + 'static,
2861    {
2862        self.background_executor.spawn(future)
2863    }
2864
2865    fn read_global<G, R>(&self, callback: impl FnOnce(&G, &App) -> R) -> Self::Result<R>
2866    where
2867        G: Global,
2868    {
2869        let mut g = self.global::<G>();
2870        callback(g, self)
2871    }
2872}
2873
2874/// These effects are processed at the end of each application update cycle.
2875pub(crate) enum Effect {
2876    Notify {
2877        emitter: EntityId,
2878    },
2879    Emit {
2880        emitter: EntityId,
2881        event_type: TypeId,
2882        event: Box<dyn Any>,
2883    },
2884    RefreshWindows,
2885    NotifyGlobalObservers {
2886        global_type: TypeId,
2887    },
2888    Defer {
2889        callback: Box<dyn FnOnce(&mut App) + 'static>,
2890    },
2891    EntityCreated {
2892        entity: AnyEntity,
2893        tid: TypeId,
2894        window: Option<WindowId>,
2895    },
2896}
2897
2898impl std::fmt::Debug for Effect {
2899    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2900        match self {
2901            Effect::Notify { emitter } => write!(f, "Notify({})", emitter),
2902            Effect::Emit { emitter, .. } => write!(f, "Emit({:?})", emitter),
2903            Effect::RefreshWindows => write!(f, "RefreshWindows"),
2904            Effect::NotifyGlobalObservers { global_type } => {
2905                write!(f, "NotifyGlobalObservers({:?})", global_type)
2906            }
2907            Effect::Defer { .. } => write!(f, "Defer(..)"),
2908            Effect::EntityCreated { entity, .. } => write!(f, "EntityCreated({:?})", entity),
2909        }
2910    }
2911}
2912
2913/// Wraps a global variable value during `update_global` while the value has been moved to the stack.
2914pub(crate) struct GlobalLease<G: Global> {
2915    global: Box<dyn Any>,
2916    global_type: PhantomData<G>,
2917}
2918
2919impl<G: Global> GlobalLease<G> {
2920    fn new(global: Box<dyn Any>) -> Self {
2921        GlobalLease {
2922            global,
2923            global_type: PhantomData,
2924        }
2925    }
2926}
2927
2928impl<G: Global> Deref for GlobalLease<G> {
2929    type Target = G;
2930
2931    fn deref(&self) -> &Self::Target {
2932        self.global.downcast_ref().unwrap()
2933    }
2934}
2935
2936impl<G: Global> DerefMut for GlobalLease<G> {
2937    fn deref_mut(&mut self) -> &mut Self::Target {
2938        self.global.downcast_mut().unwrap()
2939    }
2940}
2941
2942/// Contains state associated with an active drag operation, started by dragging an element
2943/// within the window or by dragging into the app from the underlying platform.
2944pub struct AnyDrag {
2945    /// The view used to render this drag
2946    pub view: AnyView,
2947
2948    /// The value of the dragged item, to be dropped
2949    pub value: Arc<dyn Any>,
2950
2951    /// This is used to render the dragged item in the same place
2952    /// on the original element that the drag was initiated
2953    pub cursor_offset: Point<Pixels>,
2954
2955    /// The cursor style to use while dragging
2956    pub cursor_style: Option<CursorStyle>,
2957}
2958
2959/// Contains state associated with a tooltip. You'll only need this struct if you're implementing
2960/// tooltip behavior on a custom element. Otherwise, use [Div::tooltip](crate::Interactivity::tooltip).
2961#[derive(Clone)]
2962pub struct AnyTooltip {
2963    /// The view used to display the tooltip
2964    pub view: AnyView,
2965
2966    /// The absolute position of the mouse when the tooltip was deployed.
2967    pub mouse_position: Point<Pixels>,
2968
2969    /// Given the bounds of the tooltip, checks whether the tooltip should still be visible and
2970    /// updates its state accordingly. This is needed atop the hovered element's mouse move handler
2971    /// to handle the case where the element is not painted (e.g. via use of `visible_on_hover`).
2972    pub check_visible_and_update: Rc<dyn Fn(Bounds<Pixels>, &mut Window, &mut App) -> bool>,
2973}
2974
2975/// Whether a keystroke should prefer character input or key bindings.
2976#[derive(Clone, Copy, Debug, Eq, PartialEq)]
2977pub enum InputPreference {
2978    /// Prefer typing text over triggering key bindings.
2979    CharacterInput,
2980    /// Dispatch key bindings normally, if any match.
2981    KeyBindings,
2982}
2983
2984/// A keystroke event, and potentially the associated action
2985#[derive(Debug)]
2986pub struct KeystrokeEvent {
2987    /// The keystroke that occurred
2988    pub keystroke: Keystroke,
2989
2990    /// Whether this keystroke should prefer character input or key bindings.
2991    /// This is [`InputPreference::CharacterInput`] when the platform prefers text for the key
2992    /// (e.g. AltGr on Windows) and the focused input accepts text. Interceptors still receive
2993    /// these keystrokes and can consume them.
2994    ///
2995    /// If the keystroke is part of a multi-stroke binding, it still waits as pending input
2996    /// even when this is [`InputPreference::CharacterInput`].
2997    pub input_preference: InputPreference,
2998
2999    /// The action that was resolved for the keystroke, if any
3000    pub action: Option<Box<dyn Action>>,
3001
3002    /// The context stack at the time
3003    pub context_stack: Vec<KeyContext>,
3004}
3005
3006struct NullHttpClient;
3007
3008impl HttpClient for NullHttpClient {
3009    fn send(
3010        &self,
3011        _req: http_client::Request<http_client::AsyncBody>,
3012    ) -> futures::future::BoxFuture<
3013        'static,
3014        anyhow::Result<http_client::Response<http_client::AsyncBody>>,
3015    > {
3016        async move {
3017            anyhow::bail!("No HttpClient available");
3018        }
3019        .boxed()
3020    }
3021
3022    fn user_agent(&self) -> Option<&http_client::http::HeaderValue> {
3023        None
3024    }
3025
3026    fn proxy(&self) -> Option<&Url> {
3027        None
3028    }
3029
3030    fn type_name(&self) -> &'static str {
3031        type_name::<Self>()
3032    }
3033}
3034
3035/// A mutable reference to an entity owned by GPUI
3036pub struct GpuiBorrow<'a, T> {
3037    inner: Option<Lease<T>>,
3038    app: &'a mut App,
3039}
3040
3041impl<'a, T: 'static> GpuiBorrow<'a, T> {
3042    fn new(inner: Entity<T>, app: &'a mut App) -> Self {
3043        app.start_update();
3044        let lease = app.entities.lease(&inner);
3045        Self {
3046            inner: Some(lease),
3047            app,
3048        }
3049    }
3050}
3051
3052impl<'a, T: 'static> std::borrow::Borrow<T> for GpuiBorrow<'a, T> {
3053    fn borrow(&self) -> &T {
3054        self.inner.as_ref().unwrap().borrow()
3055    }
3056}
3057
3058impl<'a, T: 'static> std::borrow::BorrowMut<T> for GpuiBorrow<'a, T> {
3059    fn borrow_mut(&mut self) -> &mut T {
3060        self.inner.as_mut().unwrap().borrow_mut()
3061    }
3062}
3063
3064impl<'a, T: 'static> std::ops::Deref for GpuiBorrow<'a, T> {
3065    type Target = T;
3066
3067    fn deref(&self) -> &Self::Target {
3068        self.inner.as_ref().unwrap()
3069    }
3070}
3071
3072impl<'a, T: 'static> std::ops::DerefMut for GpuiBorrow<'a, T> {
3073    fn deref_mut(&mut self) -> &mut T {
3074        self.inner.as_mut().unwrap()
3075    }
3076}
3077
3078impl<'a, T> Drop for GpuiBorrow<'a, T> {
3079    fn drop(&mut self) {
3080        let lease = self.inner.take().unwrap();
3081        self.app.notify(lease.id);
3082        self.app.entities.end_lease(lease);
3083        self.app.finish_update();
3084    }
3085}
3086
3087#[cfg(test)]
3088mod test {
3089    use std::{
3090        cell::{Cell, RefCell},
3091        ffi::OsString,
3092        path::PathBuf,
3093        rc::Rc,
3094        sync::Arc,
3095    };
3096
3097    #[cfg(unix)]
3098    use std::os::unix::ffi::OsStringExt;
3099
3100    use rand::{SeedableRng, rngs::StdRng};
3101
3102    use super::{Application, ApplicationHandle, NullHttpClient};
3103    use crate::{
3104        AppContext, AppResourceProfile, BackgroundExecutor, Context, Empty, ForegroundExecutor,
3105        IntoElement, Platform, QuitMode, Render, TestAppContext, TestDispatcher, TestPlatform,
3106        TrayIconClickEvent, TrayIconEvent, TrayIconRenderingMode, Window, WindowAppearance, point,
3107        px,
3108    };
3109
3110    struct RenderCounter(Rc<Cell<usize>>);
3111
3112    impl Render for RenderCounter {
3113        fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
3114            self.0.set(self.0.get() + 1);
3115            Empty
3116        }
3117    }
3118
3119    #[crate::test]
3120    fn async_app_refresh_flushes_refresh_effect(cx: &mut TestAppContext) {
3121        let render_count = Rc::new(Cell::new(0));
3122
3123        let _window = cx.add_window({
3124            let render_count = render_count.clone();
3125            move |_, _| RenderCounter(render_count)
3126        });
3127
3128        cx.run_until_parked();
3129        let render_count_before_refresh = render_count.get();
3130
3131        cx.to_async().refresh().unwrap();
3132
3133        assert_eq!(render_count.get(), render_count_before_refresh + 1);
3134    }
3135
3136    #[test]
3137    fn test_with_platform_uses_injected_platform() {
3138        let dispatcher = Arc::new(TestDispatcher::new(StdRng::seed_from_u64(0)));
3139        let platform: Rc<dyn Platform> = TestPlatform::new(
3140            BackgroundExecutor::new(dispatcher.clone()),
3141            ForegroundExecutor::new(dispatcher),
3142        );
3143
3144        let application = Application::with_platform(platform.clone());
3145
3146        assert!(Rc::ptr_eq(&application.0.borrow().platform, &platform));
3147    }
3148
3149    #[test]
3150    fn test_with_quit_mode_updates_core_and_platform_state() {
3151        let dispatcher = Arc::new(TestDispatcher::new(StdRng::seed_from_u64(0)));
3152        let platform = TestPlatform::new(
3153            BackgroundExecutor::new(dispatcher.clone()),
3154            ForegroundExecutor::new(dispatcher),
3155        );
3156
3157        let application =
3158            Application::with_platform(platform.clone()).with_quit_mode(QuitMode::Explicit);
3159
3160        assert_eq!(application.0.borrow().quit_mode, QuitMode::Explicit);
3161        assert_eq!(*platform.last_quit_mode.lock(), Some(QuitMode::Explicit));
3162    }
3163
3164    #[test]
3165    fn test_inaccessible_sets_force_disabled() {
3166        let dispatcher = Arc::new(TestDispatcher::new(StdRng::seed_from_u64(0)));
3167        let platform = TestPlatform::new(
3168            BackgroundExecutor::new(dispatcher.clone()),
3169            ForegroundExecutor::new(dispatcher),
3170        );
3171        let application = Application(super::App::new_app(
3172            platform,
3173            Arc::new(()),
3174            Arc::new(NullHttpClient),
3175            AppResourceProfile::default(),
3176        ))
3177        .inaccessible();
3178
3179        assert!(application.0.borrow().accessibility_force_disabled);
3180    }
3181
3182    #[test]
3183    fn test_with_resource_profile_rebuilds_text_system_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 mut profile = AppResourceProfile::default();
3190        profile.text.line_layout_cache_max_entries = 7;
3191        profile.text.line_layout_cache_low_watermark = 3;
3192        profile.text.raster_bounds_cache_max_entries = Some(11);
3193        profile.element_arena_size =
3194            crate::window::ELEMENT_ARENA_SIZE.load(std::sync::atomic::Ordering::Relaxed);
3195
3196        let application = Application(super::App::new_app(
3197            platform,
3198            Arc::new(()),
3199            Arc::new(NullHttpClient),
3200            AppResourceProfile::default(),
3201        ))
3202        .with_resource_profile(profile);
3203
3204        let app = application.0.borrow();
3205        assert_eq!(app.text_system.resource_budget_for_test(), (7, 3, Some(11)));
3206        assert_eq!(app.resource_profile.text.line_layout_cache_max_entries, 7);
3207        assert_eq!(
3208            app.resource_profile.gpu.instance_buffer_initial_size,
3209            2 * 1024 * 1024
3210        );
3211    }
3212
3213    #[test]
3214    fn test_with_resource_profile_updates_gpu_budget() {
3215        let dispatcher = Arc::new(TestDispatcher::new(StdRng::seed_from_u64(0)));
3216        let platform = TestPlatform::new(
3217            BackgroundExecutor::new(dispatcher.clone()),
3218            ForegroundExecutor::new(dispatcher),
3219        );
3220        let platform_handle = platform.clone();
3221        let mut profile = AppResourceProfile::default();
3222        profile.gpu.instance_buffer_initial_size = 768 * 1024;
3223        profile.element_arena_size =
3224            crate::window::ELEMENT_ARENA_SIZE.load(std::sync::atomic::Ordering::Relaxed);
3225
3226        let application = Application(super::App::new_app(
3227            platform,
3228            Arc::new(()),
3229            Arc::new(NullHttpClient),
3230            AppResourceProfile::default(),
3231        ))
3232        .with_resource_profile(profile);
3233
3234        let app = application.0.borrow();
3235        assert_eq!(
3236            app.resource_profile.gpu.instance_buffer_initial_size,
3237            768 * 1024
3238        );
3239        assert_eq!(
3240            platform_handle
3241                .gpu_resource_budget
3242                .lock()
3243                .instance_buffer_initial_size,
3244            768 * 1024
3245        );
3246    }
3247
3248    #[test]
3249    fn test_application_handle_keeps_app_alive_for_embedders() {
3250        let dispatcher = Arc::new(TestDispatcher::new(StdRng::seed_from_u64(0)));
3251        let platform = TestPlatform::new(
3252            BackgroundExecutor::new(dispatcher.clone()),
3253            ForegroundExecutor::new(dispatcher),
3254        );
3255        let application = Application(super::App::new_app(
3256            platform,
3257            Arc::new(()),
3258            Arc::new(NullHttpClient),
3259            AppResourceProfile::default(),
3260        ));
3261        let weak_app = Rc::downgrade(&application.0);
3262        let handle = ApplicationHandle {
3263            app: application.0.clone(),
3264        };
3265        drop(application);
3266
3267        assert!(weak_app.upgrade().is_some());
3268
3269        let did_update = Rc::new(RefCell::new(false));
3270        let did_update_clone = did_update.clone();
3271        handle.update(move |_| {
3272            *did_update_clone.borrow_mut() = true;
3273        });
3274
3275        assert!(*did_update.borrow());
3276
3277        drop(handle);
3278        assert!(weak_app.upgrade().is_none());
3279    }
3280
3281    #[test]
3282    fn test_with_resource_profile_clamps_line_layout_cache_to_one_entry() {
3283        let dispatcher = Arc::new(TestDispatcher::new(StdRng::seed_from_u64(0)));
3284        let platform = TestPlatform::new(
3285            BackgroundExecutor::new(dispatcher.clone()),
3286            ForegroundExecutor::new(dispatcher),
3287        );
3288        let mut profile = AppResourceProfile::default();
3289        profile.text.line_layout_cache_max_entries = 0;
3290        profile.text.line_layout_cache_low_watermark = 5;
3291        profile.element_arena_size =
3292            crate::window::ELEMENT_ARENA_SIZE.load(std::sync::atomic::Ordering::Relaxed);
3293
3294        let application = Application(super::App::new_app(
3295            platform,
3296            Arc::new(()),
3297            Arc::new(NullHttpClient),
3298            AppResourceProfile::default(),
3299        ))
3300        .with_resource_profile(profile);
3301
3302        let app = application.0.borrow();
3303        assert_eq!(
3304            app.text_system.resource_budget_for_test(),
3305            (1, 0, None),
3306            "line layout caches should retain a valid minimum capacity"
3307        );
3308    }
3309
3310    #[test]
3311    fn test_gpui_borrow() {
3312        let cx = TestAppContext::single();
3313        let observation_count = Rc::new(RefCell::new(0));
3314
3315        let state = cx.update(|cx| {
3316            let state = cx.new(|_| false);
3317            cx.observe(&state, {
3318                let observation_count = observation_count.clone();
3319                move |_, _| {
3320                    let mut count = observation_count.borrow_mut();
3321                    *count += 1;
3322                }
3323            })
3324            .detach();
3325
3326            state
3327        });
3328
3329        cx.update(|cx| {
3330            // Calling this like this so that we don't clobber the borrow_mut above
3331            *std::borrow::BorrowMut::borrow_mut(&mut state.as_mut(cx)) = true;
3332        });
3333
3334        cx.update(|cx| {
3335            state.write(cx, false);
3336        });
3337
3338        assert_eq!(*observation_count.borrow(), 2);
3339    }
3340
3341    #[test]
3342    fn test_tray_icon_rendering_mode_default() {
3343        assert_eq!(
3344            TrayIconRenderingMode::default(),
3345            TrayIconRenderingMode::Adaptive
3346        );
3347    }
3348
3349    #[test]
3350    fn test_set_tray_icon_forwards_to_platform() {
3351        let cx = TestAppContext::single();
3352        let icon = [1_u8, 2, 3, 4];
3353
3354        cx.update(|cx| {
3355            cx.set_tray_icon(Some(&icon));
3356        });
3357
3358        assert_eq!(cx.tray_icon(), Some(icon.to_vec()));
3359    }
3360
3361    #[test]
3362    fn test_set_tray_icon_rendering_mode_forwards_to_platform() {
3363        let cx = TestAppContext::single();
3364
3365        cx.update(|cx| {
3366            cx.set_tray_icon_rendering_mode(TrayIconRenderingMode::Original);
3367        });
3368
3369        assert_eq!(
3370            cx.tray_icon_rendering_mode(),
3371            TrayIconRenderingMode::Original
3372        );
3373    }
3374
3375    #[test]
3376    fn test_tray_icon_rendering_mode_and_icon_updates_are_order_independent() {
3377        let first = TestAppContext::single();
3378        let second = TestAppContext::single();
3379        let icon = [9_u8, 8, 7, 6];
3380
3381        first.update(|cx| {
3382            cx.set_tray_icon_rendering_mode(TrayIconRenderingMode::Original);
3383            cx.set_tray_icon(Some(&icon));
3384        });
3385
3386        second.update(|cx| {
3387            cx.set_tray_icon(Some(&icon));
3388            cx.set_tray_icon_rendering_mode(TrayIconRenderingMode::Original);
3389        });
3390
3391        assert_eq!(first.tray_icon(), Some(icon.to_vec()));
3392        assert_eq!(second.tray_icon(), Some(icon.to_vec()));
3393        assert_eq!(
3394            first.tray_icon_rendering_mode(),
3395            TrayIconRenderingMode::Original
3396        );
3397        assert_eq!(
3398            second.tray_icon_rendering_mode(),
3399            TrayIconRenderingMode::Original
3400        );
3401    }
3402
3403    #[test]
3404    fn test_tray_icon_click_event_keeps_legacy_callback_compatible() {
3405        let cx = TestAppContext::single();
3406        let legacy_event = Rc::new(RefCell::new(None));
3407        let click_event = Rc::new(RefCell::new(None));
3408
3409        cx.update({
3410            let legacy_event = legacy_event.clone();
3411            let click_event = click_event.clone();
3412            |cx| {
3413                cx.on_tray_icon_event(move |event, _| {
3414                    *legacy_event.borrow_mut() = Some(event);
3415                });
3416                cx.on_tray_icon_click_event(move |event, _| {
3417                    *click_event.borrow_mut() = Some(event);
3418                });
3419            }
3420        });
3421
3422        let event =
3423            TrayIconClickEvent::with_position(TrayIconEvent::LeftClick, point(px(120.0), px(24.0)));
3424        cx.simulate_tray_icon_click_event(event.clone());
3425
3426        assert_eq!(*legacy_event.borrow(), Some(TrayIconEvent::LeftClick));
3427        assert_eq!(*click_event.borrow(), Some(event));
3428    }
3429
3430    #[test]
3431    fn test_tray_icon_callbacks_keep_re_registration_during_dispatch() {
3432        let cx = TestAppContext::single();
3433        let legacy_events = Rc::new(RefCell::new(Vec::new()));
3434        let click_events = Rc::new(RefCell::new(Vec::new()));
3435
3436        cx.update({
3437            let legacy_events = legacy_events.clone();
3438            let click_events = click_events.clone();
3439            move |cx| {
3440                cx.on_tray_icon_event({
3441                    let legacy_events = legacy_events.clone();
3442                    move |event, cx| {
3443                        legacy_events.borrow_mut().push(("old", event));
3444                        cx.on_tray_icon_event({
3445                            let legacy_events = legacy_events.clone();
3446                            move |event, _| {
3447                                legacy_events.borrow_mut().push(("new", event));
3448                            }
3449                        });
3450                    }
3451                });
3452
3453                cx.on_tray_icon_click_event({
3454                    let click_events = click_events.clone();
3455                    move |event, cx| {
3456                        click_events.borrow_mut().push(("old", event.kind));
3457                        cx.on_tray_icon_click_event({
3458                            let click_events = click_events.clone();
3459                            move |event, _| {
3460                                click_events.borrow_mut().push(("new", event.kind));
3461                            }
3462                        });
3463                    }
3464                });
3465            }
3466        });
3467
3468        cx.simulate_tray_icon_click_event(TrayIconClickEvent::new(TrayIconEvent::LeftClick));
3469        cx.simulate_tray_icon_click_event(TrayIconClickEvent::new(TrayIconEvent::RightClick));
3470
3471        assert_eq!(
3472            *legacy_events.borrow(),
3473            vec![
3474                ("old", TrayIconEvent::LeftClick),
3475                ("new", TrayIconEvent::RightClick)
3476            ]
3477        );
3478        assert_eq!(
3479            *click_events.borrow(),
3480            vec![
3481                ("old", TrayIconEvent::LeftClick),
3482                ("new", TrayIconEvent::RightClick)
3483            ]
3484        );
3485    }
3486
3487    #[test]
3488    fn test_set_window_appearance_override_is_reported_by_getter() {
3489        let cx = TestAppContext::single();
3490        assert_eq!(
3491            cx.read(|cx| cx.window_appearance()),
3492            WindowAppearance::Light
3493        );
3494
3495        cx.update(|cx| cx.set_window_appearance(Some(WindowAppearance::Dark)));
3496        assert_eq!(cx.read(|cx| cx.window_appearance()), WindowAppearance::Dark);
3497
3498        cx.update(|cx| cx.set_window_appearance(Some(WindowAppearance::VibrantLight)));
3499        assert_eq!(
3500            cx.read(|cx| cx.window_appearance()),
3501            WindowAppearance::VibrantLight
3502        );
3503
3504        cx.update(|cx| cx.set_window_appearance(None));
3505        assert_eq!(
3506            cx.read(|cx| cx.window_appearance()),
3507            WindowAppearance::Light
3508        );
3509    }
3510
3511    #[test]
3512    fn test_tray_anchor_for_position_uses_display_local_bounds() {
3513        let cx = TestAppContext::single();
3514        let anchor = cx.update(|cx| cx.tray_anchor_for_position(point(px(120.0), px(24.0))));
3515        let anchor = anchor.expect("expected tray anchor");
3516
3517        assert_eq!(anchor.display_id.0, 1);
3518        assert_eq!(anchor.bounds.origin, point(px(108.0), px(12.0)));
3519        assert_eq!(anchor.bounds.size.width, px(24.0));
3520        assert_eq!(anchor.bounds.size.height, px(24.0));
3521    }
3522
3523    #[test]
3524    fn test_tray_anchor_for_position_keeps_out_of_display_hint() {
3525        let cx = TestAppContext::single();
3526        let anchor = cx.update(|cx| cx.tray_anchor_for_position(point(px(-20.0), px(10.0))));
3527        let anchor = anchor.expect("expected tray anchor");
3528
3529        assert_eq!(anchor.display_id.0, 1);
3530        assert_eq!(anchor.bounds.origin, point(px(-32.0), px(-2.0)));
3531    }
3532
3533    #[crate::test]
3534    async fn test_on_missing_glyphs_delivers_reports(cx: &mut TestAppContext) {
3535        use crate::{FallbackFontClass, MissingGlyph};
3536
3537        let reported = Rc::new(RefCell::new(Vec::new()));
3538        cx.update(|cx| {
3539            cx.on_missing_glyphs({
3540                let reported = reported.clone();
3541                move |glyphs, _| reported.borrow_mut().extend(glyphs.iter().cloned())
3542            });
3543            cx.text_system().report_missing_glyphs_in_test(vec![
3544                MissingGlyph::new("\u{1F980}".into(), FallbackFontClass::Monospace),
3545                MissingGlyph::new("\u{1F980}".into(), FallbackFontClass::Monospace),
3546            ]);
3547        });
3548
3549        cx.run_until_parked();
3550
3551        // Duplicate reports within one batch are delivered once.
3552        assert_eq!(
3553            reported.borrow().as_slice(),
3554            &[MissingGlyph::new(
3555                "\u{1F980}".into(),
3556                FallbackFontClass::Monospace
3557            )]
3558        );
3559    }
3560
3561    #[crate::test]
3562    async fn test_restart_preserves_path_and_arguments(cx: &mut TestAppContext) {
3563        #[cfg(unix)]
3564        let user_data_dir = OsString::from_vec(b"/tmp/zed data/\xff".to_vec());
3565        #[cfg(not(unix))]
3566        let user_data_dir = OsString::from("C:\\zed data");
3567        let arguments = vec![OsString::from("--user-data-dir"), user_data_dir];
3568        let restart_path = PathBuf::from("updated-zed");
3569        let _application =
3570            super::Application(cx.app.clone()).with_restart_arguments(arguments.clone());
3571        let restart = cx.expect_restart();
3572
3573        cx.update(|cx| {
3574            cx.set_restart_path(restart_path.clone());
3575            cx.restart();
3576        });
3577
3578        let (path, restart_arguments) = restart.await.expect("restart was not requested");
3579        assert_eq!(path, Some(restart_path));
3580        assert_eq!(restart_arguments, arguments);
3581    }
3582}