Skip to main content

gpui_core/
app.rs

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