Skip to main content

gpui/
app.rs

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