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        let accessed_entities_start = self.entities.accessed_entities.get_mut().clone();
1464        let result = callback(self);
1465        let entities_accessed_in_callback = self
1466            .entities
1467            .accessed_entities
1468            .get_mut()
1469            .difference(&accessed_entities_start)
1470            .copied()
1471            .collect::<FxHashSet<EntityId>>();
1472        (result, entities_accessed_in_callback)
1473    }
1474
1475    pub(crate) fn record_entities_accessed(
1476        &mut self,
1477        window_handle: AnyWindowHandle,
1478        invalidator: WindowInvalidator,
1479        entities: &FxHashSet<EntityId>,
1480    ) {
1481        let mut tracked_entities =
1482            std::mem::take(self.tracked_entities.entry(window_handle.id).or_default());
1483        for entity in tracked_entities.iter() {
1484            self.window_invalidators_by_entity
1485                .entry(*entity)
1486                .and_modify(|windows| {
1487                    windows.remove(&window_handle.id);
1488                });
1489        }
1490        for entity in entities.iter() {
1491            self.window_invalidators_by_entity
1492                .entry(*entity)
1493                .or_default()
1494                .insert(window_handle.id, invalidator.clone());
1495            self.current_window_by_entity
1496                .insert(*entity, window_handle.id);
1497        }
1498        tracked_entities.clear();
1499        tracked_entities.extend(entities.iter().copied());
1500        self.tracked_entities
1501            .insert(window_handle.id, tracked_entities);
1502    }
1503
1504    pub(crate) fn new_observer(&mut self, key: EntityId, value: Handler) -> Subscription {
1505        let (subscription, activate) = self.observers.insert_pending(key, value);
1506        self.defer(move |_| activate());
1507        subscription
1508    }
1509
1510    pub(crate) fn observe_internal<W>(
1511        &mut self,
1512        entity: &Entity<W>,
1513        mut on_notify: impl FnMut(Entity<W>, &mut App) -> bool + 'static,
1514    ) -> Subscription
1515    where
1516        W: 'static,
1517    {
1518        let entity_id = entity.entity_id();
1519        let handle = entity.downgrade();
1520        self.new_observer(
1521            entity_id,
1522            Box::new(move |cx| {
1523                if let Some(entity) = handle.upgrade() {
1524                    on_notify(entity, cx)
1525                } else {
1526                    false
1527                }
1528            }),
1529        )
1530    }
1531
1532    /// Arrange for the given callback to be invoked whenever the given entity emits an event of a given type.
1533    /// The callback is provided a handle to the emitting entity and a reference to the emitted event.
1534    pub fn subscribe<T, Event>(
1535        &mut self,
1536        entity: &Entity<T>,
1537        mut on_event: impl FnMut(Entity<T>, &Event, &mut App) + 'static,
1538    ) -> Subscription
1539    where
1540        T: 'static + EventEmitter<Event>,
1541        Event: 'static,
1542    {
1543        self.subscribe_internal(entity, move |entity, event, cx| {
1544            on_event(entity, event, cx);
1545            true
1546        })
1547    }
1548
1549    pub(crate) fn new_subscription(
1550        &mut self,
1551        key: EntityId,
1552        value: (TypeId, Listener),
1553    ) -> Subscription {
1554        let (subscription, activate) = self.event_listeners.insert_pending(key, value);
1555        self.defer(move |_| activate());
1556        subscription
1557    }
1558    pub(crate) fn subscribe_internal<T, Evt>(
1559        &mut self,
1560        entity: &Entity<T>,
1561        mut on_event: impl FnMut(Entity<T>, &Evt, &mut App) -> bool + 'static,
1562    ) -> Subscription
1563    where
1564        T: 'static + EventEmitter<Evt>,
1565        Evt: 'static,
1566    {
1567        let entity_id = entity.entity_id();
1568        let handle = entity.downgrade();
1569        self.new_subscription(
1570            entity_id,
1571            (
1572                TypeId::of::<Evt>(),
1573                Box::new(move |event, cx| {
1574                    let event: &Evt = event.downcast_ref().expect("invalid event type");
1575                    if let Some(entity) = handle.upgrade() {
1576                        on_event(entity, event, cx)
1577                    } else {
1578                        false
1579                    }
1580                }),
1581            ),
1582        )
1583    }
1584
1585    /// Returns handles to all open windows in the application.
1586    /// Each handle could be downcast to a handle typed for the root view of that window.
1587    /// To find all windows of a given type, you could filter on
1588    pub fn windows(&self) -> Vec<AnyWindowHandle> {
1589        self.windows
1590            .keys()
1591            .flat_map(|window_id| self.window_handles.get(&window_id).copied())
1592            .collect()
1593    }
1594
1595    /// Returns the window handles ordered by their appearance on screen, front to back.
1596    ///
1597    /// The first window in the returned list is the active/topmost window of the application.
1598    ///
1599    /// This method returns None if the platform doesn't implement the method yet.
1600    pub fn window_stack(&self) -> Option<Vec<AnyWindowHandle>> {
1601        self.platform.window_stack()
1602    }
1603
1604    /// Returns a handle to the window that is currently focused at the platform level, if one exists.
1605    pub fn active_window(&self) -> Option<AnyWindowHandle> {
1606        self.platform.active_window()
1607    }
1608
1609    /// Opens a new window with the given option and the root view returned by the given function.
1610    /// The function is invoked with a `Window`, which can be used to interact with window-specific
1611    /// functionality.
1612    pub fn open_window<V: 'static + Render>(
1613        &mut self,
1614        options: crate::WindowOptions,
1615        build_root_view: impl FnOnce(&mut Window, &mut App) -> Entity<V>,
1616    ) -> anyhow::Result<WindowHandle<V>> {
1617        self.update(|cx| {
1618            let id = cx.windows.insert(None);
1619            let handle = WindowHandle::new(id);
1620            match Window::new(handle.into(), options, cx) {
1621                Ok(mut window) => {
1622                    cx.window_update_stack.push(id);
1623                    let root_view = build_root_view(&mut window, cx);
1624                    cx.window_update_stack.pop();
1625                    window.root.replace(root_view.into());
1626                    window.defer(cx, |window: &mut Window, cx| window.appearance_changed(cx));
1627
1628                    // allow a window to draw at least once before returning
1629                    // this didn't cause any issues on non windows platforms as it seems we always won the race to on_request_frame
1630                    // on windows we quite frequently lose the race and return a window that has never rendered, which leads to a crash
1631                    // where DispatchTree::root_node_id asserts on empty nodes
1632                    let clear = window.draw(cx);
1633                    clear.clear(cx);
1634
1635                    cx.window_handles.insert(id, window.handle);
1636                    cx.windows.get_mut(id).unwrap().replace(Box::new(window));
1637                    Ok(handle)
1638                }
1639                Err(e) => {
1640                    cx.windows.remove(id);
1641                    Err(e)
1642                }
1643            }
1644        })
1645    }
1646
1647    /// Instructs the platform to activate the application by bringing it to the foreground.
1648    pub fn activate(&self, ignoring_other_apps: bool) {
1649        self.platform.activate(ignoring_other_apps);
1650    }
1651
1652    /// Hide the application at the platform level.
1653    pub fn hide(&self) {
1654        self.platform.hide();
1655    }
1656
1657    /// Hide other applications at the platform level.
1658    pub fn hide_other_apps(&self) {
1659        self.platform.hide_other_apps();
1660    }
1661
1662    /// Unhide other applications at the platform level.
1663    pub fn unhide_other_apps(&self) {
1664        self.platform.unhide_other_apps();
1665    }
1666
1667    /// Returns the list of currently active displays.
1668    pub fn displays(&self) -> Vec<Rc<dyn PlatformDisplay>> {
1669        self.platform.displays()
1670    }
1671
1672    /// Returns the primary display that will be used for new windows.
1673    pub fn primary_display(&self) -> Option<Rc<dyn PlatformDisplay>> {
1674        self.platform.primary_display()
1675    }
1676
1677    /// Returns whether `screen_capture_sources` may work.
1678    pub fn is_screen_capture_supported(&self) -> bool {
1679        self.platform.is_screen_capture_supported()
1680    }
1681
1682    /// Returns a list of available screen capture sources.
1683    pub fn screen_capture_sources(
1684        &self,
1685    ) -> oneshot::Receiver<Result<Vec<Rc<dyn ScreenCaptureSource>>>> {
1686        self.platform.screen_capture_sources()
1687    }
1688
1689    /// Returns the display with the given ID, if one exists.
1690    pub fn find_display(&self, id: DisplayId) -> Option<Rc<dyn PlatformDisplay>> {
1691        self.displays()
1692            .iter()
1693            .find(|display| display.id() == id)
1694            .cloned()
1695    }
1696
1697    /// Returns the current thermal state of the system.
1698    pub fn thermal_state(&self) -> ThermalState {
1699        self.platform.thermal_state()
1700    }
1701
1702    /// Prevents idle sleep while the returned guard is held.
1703    pub fn prevent_idle_sleep(&self, reason: &str) -> Task<Result<ActivityGuard>> {
1704        self.platform.prevent_idle_sleep(reason)
1705    }
1706
1707    /// Invokes a handler when the thermal state changes
1708    pub fn on_thermal_state_change<F>(&self, mut callback: F) -> Subscription
1709    where
1710        F: 'static + FnMut(&mut App),
1711    {
1712        self.thermal_state_observers.insert(Box::new(move |cx| {
1713            callback(cx);
1714            true
1715        }))
1716    }
1717
1718    /// Invokes a handler when the system is about to sleep.
1719    ///
1720    /// The platform gives the process only a short time before suspending, so
1721    /// handlers should record state or cancel work rather than start it.
1722    pub fn on_system_sleep<F>(&self, mut callback: F) -> Subscription
1723    where
1724        F: 'static + FnMut(&mut App),
1725    {
1726        self.system_sleep_observers.insert(Box::new(move |cx| {
1727            callback(cx);
1728            true
1729        }))
1730    }
1731
1732    pub(crate) fn displays_changed(&mut self) {
1733        let current = read_displays(self.platform.as_ref());
1734        let events = display_events(&self.displays, &current);
1735        self.displays = current;
1736        for event in &events {
1737            let DisplayEvent::Changed { id, .. } = *event else {
1738                continue;
1739            };
1740            for handle in self.windows() {
1741                self.update_window(handle, |_, window, cx| {
1742                    if window.display_id == Some(id) {
1743                        window.notify_display_observers(cx);
1744                    }
1745                })
1746                .log_err();
1747            }
1748        }
1749        for event in events {
1750            self.display_observers
1751                .clone()
1752                .retain(|callback| (callback)(event, self));
1753        }
1754    }
1755
1756    pub(crate) fn knows_display(&self, id: DisplayId) -> bool {
1757        self.displays.contains_key(&id)
1758    }
1759
1760    /// The refresh interval of a connected display, as of the platform's last
1761    /// display change notification.
1762    pub(crate) fn display_refresh_interval(&self, id: DisplayId) -> Option<Duration> {
1763        self.displays.get(&id)?.refresh_interval
1764    }
1765
1766    /// Invokes a handler when a display is connected, disconnected, or its
1767    /// properties change.
1768    pub fn observe_displays<F>(&self, mut callback: F) -> Subscription
1769    where
1770        F: 'static + FnMut(DisplayEvent, &mut App),
1771    {
1772        self.display_observers.insert(Box::new(move |event, cx| {
1773            callback(event, cx);
1774            true
1775        }))
1776    }
1777
1778    /// Invokes a handler when the system wakes from sleep.
1779    pub fn on_system_wake<F>(&self, mut callback: F) -> Subscription
1780    where
1781        F: 'static + FnMut(&mut App),
1782    {
1783        self.system_wake_observers.insert(Box::new(move |cx| {
1784            callback(cx);
1785            true
1786        }))
1787    }
1788
1789    /// Observes mobile application lifecycle changes. Desktop platforms do not
1790    /// emit these events. On iOS these currently describe the single connected
1791    /// scene, not individual windows.
1792    ///
1793    /// Save important changes incrementally: neither disconnection nor quit is
1794    /// guaranteed before the system terminates a backgrounded application.
1795    /// Dropping the returned subscription removes the observer.
1796    pub fn on_app_lifecycle(
1797        &self,
1798        mut callback: impl FnMut(AppLifecyclePhase, &mut App) + 'static,
1799    ) -> Subscription {
1800        self.app_lifecycle_observers
1801            .insert(Box::new(move |phase, cx| {
1802                callback(phase, cx);
1803                true
1804            }))
1805    }
1806
1807    /// Observes mobile memory-pressure warnings so applications can release
1808    /// expendable caches. Dropping the subscription removes the observer.
1809    pub fn on_memory_warning(&self, mut callback: impl FnMut(&mut App) + 'static) -> Subscription {
1810        self.memory_warning_observers.insert(Box::new(move |cx| {
1811            callback(cx);
1812            true
1813        }))
1814    }
1815
1816    /// Returns the appearance of the application's windows.
1817    pub fn window_appearance(&self) -> WindowAppearance {
1818        self.platform.window_appearance()
1819    }
1820
1821    /// Overrides the appearance (light/dark) applied to the app's windows, independent of
1822    /// the OS-wide setting. Pass `None` to clear the override and follow the system again.
1823    /// The current value is reported by [`App::window_appearance`].
1824    ///
1825    /// On macOS this sets the underlying `NSApplication.appearance`, which controls the
1826    /// native window chrome (the window border and titlebar) of every window. Use this
1827    /// when the app uses a dark theme while the system is in light mode (or vice versa)
1828    /// so the window edges render to match the theme. While an appearance is forced,
1829    /// windows stop tracking system light/dark changes; pass `None` to resume following
1830    /// the system. On other platforms this is a no-op.
1831    pub fn set_window_appearance(&self, appearance: Option<WindowAppearance>) {
1832        self.platform.set_window_appearance(appearance);
1833    }
1834
1835    /// Returns the window button layout configuration when supported.
1836    pub fn button_layout(&self) -> Option<WindowButtonLayout> {
1837        self.platform.button_layout()
1838    }
1839
1840    /// Reads data from the platform clipboard.
1841    pub fn read_from_clipboard(&self) -> Option<ClipboardItem> {
1842        self.platform.read_from_clipboard()
1843    }
1844
1845    /// Reads data from the platform clipboard, resolving once the contents
1846    /// are available.
1847    ///
1848    /// Prefer this over [`App::read_from_clipboard`] in code that can await:
1849    /// on platforms where clipboard access is asynchronous and
1850    /// permission-gated (e.g. web), the synchronous read always returns
1851    /// `None` while this method performs a real read.
1852    pub fn read_from_clipboard_async(
1853        &self,
1854    ) -> Task<Result<Option<ClipboardItem>, ClipboardReadError>> {
1855        self.platform.read_from_clipboard_async()
1856    }
1857
1858    /// Sets the text rendering mode for the application.
1859    pub fn set_text_rendering_mode(&mut self, mode: TextRenderingMode) {
1860        self.text_rendering_mode.set(mode);
1861    }
1862
1863    /// Returns the current text rendering mode for the application.
1864    pub fn text_rendering_mode(&self) -> TextRenderingMode {
1865        self.text_rendering_mode.get()
1866    }
1867
1868    /// Returns the operating system's power mode, or [`PowerMode::Unknown`]
1869    /// when the platform cannot determine it.
1870    pub fn power_mode(&self) -> PowerMode {
1871        self.power_mode
1872    }
1873
1874    /// Writes data to the platform clipboard.
1875    pub fn write_to_clipboard(&self, item: ClipboardItem) {
1876        self.platform.write_to_clipboard(item)
1877    }
1878
1879    /// Reads data from the primary selection buffer.
1880    /// Only available on Linux.
1881    #[cfg(any(target_os = "linux", target_os = "freebsd"))]
1882    pub fn read_from_primary(&self) -> Option<ClipboardItem> {
1883        self.platform.read_from_primary()
1884    }
1885
1886    /// Writes data to the primary selection buffer.
1887    /// Only available on Linux.
1888    #[cfg(any(target_os = "linux", target_os = "freebsd"))]
1889    pub fn write_to_primary(&self, item: ClipboardItem) {
1890        self.platform.write_to_primary(item)
1891    }
1892
1893    /// Reads data from macOS's "Find" pasteboard.
1894    ///
1895    /// Used to share the current search string between apps.
1896    ///
1897    /// https://developer.apple.com/documentation/appkit/nspasteboard/name-swift.struct/find
1898    #[cfg(target_os = "macos")]
1899    pub fn read_from_find_pasteboard(&self) -> Option<ClipboardItem> {
1900        self.platform.read_from_find_pasteboard()
1901    }
1902
1903    /// Writes data to macOS's "Find" pasteboard.
1904    ///
1905    /// Used to share the current search string between apps.
1906    ///
1907    /// https://developer.apple.com/documentation/appkit/nspasteboard/name-swift.struct/find
1908    #[cfg(target_os = "macos")]
1909    pub fn write_to_find_pasteboard(&self, item: ClipboardItem) {
1910        self.platform.write_to_find_pasteboard(item)
1911    }
1912
1913    /// Writes credentials to the platform keychain.
1914    pub fn write_credentials(
1915        &self,
1916        url: &str,
1917        username: &str,
1918        password: &[u8],
1919    ) -> Task<Result<()>> {
1920        self.platform.write_credentials(url, username, password)
1921    }
1922
1923    /// Atomically writes credentials unless an item with this URL and username exists.
1924    ///
1925    /// Returns `true` if written, or `false` if the existing item was left unchanged.
1926    ///
1927    /// # Errors
1928    ///
1929    /// Returns an error if Keychain access fails or the platform lacks support.
1930    #[cfg(target_os = "macos")]
1931    pub fn write_credentials_if_not_exists(
1932        &self,
1933        url: &str,
1934        username: &str,
1935        password: &[u8],
1936    ) -> Task<Result<bool>> {
1937        self.platform
1938            .write_credentials_if_not_exists(url, username, password)
1939    }
1940
1941    /// Reads credentials from the platform keychain.
1942    pub fn read_credentials(&self, url: &str) -> Task<Result<Option<(String, Vec<u8>)>>> {
1943        self.platform.read_credentials(url)
1944    }
1945
1946    /// Deletes credentials from the platform keychain.
1947    pub fn delete_credentials(&self, url: &str) -> Task<Result<()>> {
1948        self.platform.delete_credentials(url)
1949    }
1950
1951    /// Directs the platform's default browser to open the given URL.
1952    pub fn open_url(&self, url: &str) {
1953        self.platform.open_url(url);
1954    }
1955
1956    /// Registers the given URL scheme (e.g. `zed` for `zed://` urls) to be
1957    /// opened by the current app.
1958    ///
1959    /// On some platforms (e.g. macOS) you may be able to register URL schemes
1960    /// as part of app distribution, but this method exists to let you register
1961    /// schemes at runtime.
1962    pub fn register_url_scheme(&self, scheme: &str) -> Task<Result<()>> {
1963        self.platform.register_url_scheme(scheme)
1964    }
1965
1966    /// Sets the application's process-wide identity and user-visible name.
1967    ///
1968    /// The identifier is used for platform identity mechanisms such as the
1969    /// Windows AppUserModelID. The name is used wherever the operating system
1970    /// presents the application to the user. Call this once, early in startup,
1971    /// before opening windows or posting notifications.
1972    pub fn set_app_identity(&self, identifier: &str, name: &str) {
1973        self.platform.set_app_identity(identifier, name);
1974    }
1975
1976    /// Posts a notification to the operating system's notification center.
1977    ///
1978    /// Posting a notification whose [`SystemNotification::tag`] matches an
1979    /// earlier one replaces that notification where the platform supports it.
1980    /// No-op on platforms without notification support, or when delivery is
1981    /// unavailable (e.g. authorization was denied).
1982    pub fn show_system_notification(&self, notification: SystemNotification) {
1983        self.platform.show_system_notification(notification);
1984    }
1985
1986    /// Removes the delivered or pending notification with this tag.
1987    ///
1988    /// Best-effort: some platforms cannot retract a notification once shown,
1989    /// in which case it ages out of the notification center on its own.
1990    pub fn dismiss_system_notification(&self, tag: &str) {
1991        self.platform.dismiss_system_notification(tag);
1992    }
1993
1994    /// Registers the handler invoked when the user activates a system
1995    /// notification, either by clicking its body or one of its action
1996    /// buttons. Subsequent registrations replace the handler.
1997    pub fn on_system_notification_response<F>(&self, mut callback: F)
1998    where
1999        F: 'static + FnMut(SystemNotificationResponse, &mut App),
2000    {
2001        let this = self.this.clone();
2002        self.platform
2003            .on_system_notification_response(Box::new(move |response| {
2004                if let Some(app) = this.upgrade() {
2005                    callback(response, &mut app.borrow_mut());
2006                }
2007            }));
2008    }
2009
2010    /// Returns the full pathname of the current app bundle.
2011    ///
2012    /// Returns an error if the app is not being run from a bundle.
2013    pub fn app_path(&self) -> Result<PathBuf> {
2014        self.platform.app_path()
2015    }
2016
2017    /// On Linux, returns the name of the compositor in use.
2018    ///
2019    /// Returns an empty string on other platforms.
2020    pub fn compositor_name(&self) -> &'static str {
2021        self.platform.compositor_name()
2022    }
2023
2024    /// Returns the host OS and application target reported by the backend.
2025    pub fn platform_info(&self) -> crate::PlatformInfo {
2026        self.platform.platform_info()
2027    }
2028
2029    /// Returns the file URL of the executable with the specified name in the application bundle
2030    pub fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf> {
2031        self.platform.path_for_auxiliary_executable(name)
2032    }
2033
2034    /// Displays a platform modal for selecting paths.
2035    ///
2036    /// When one or more paths are selected, they'll be relayed asynchronously via the returned oneshot channel.
2037    /// If cancelled, a `None` will be relayed instead.
2038    /// May return an error on Linux if the file picker couldn't be opened.
2039    pub fn prompt_for_paths(
2040        &self,
2041        options: PathPromptOptions,
2042    ) -> oneshot::Receiver<Result<Option<Vec<PathBuf>>>> {
2043        self.platform.prompt_for_paths(options)
2044    }
2045
2046    /// Displays a platform modal for selecting a new path where a file can be saved.
2047    ///
2048    /// The provided directory will be used to set the initial location.
2049    /// When a path is selected, it is relayed asynchronously via the returned oneshot channel.
2050    /// If cancelled, a `None` will be relayed instead.
2051    /// May return an error on Linux if the file picker couldn't be opened.
2052    pub fn prompt_for_new_path(
2053        &self,
2054        directory: &Path,
2055        suggested_name: Option<&str>,
2056    ) -> oneshot::Receiver<Result<Option<PathBuf>>> {
2057        self.platform.prompt_for_new_path(directory, suggested_name)
2058    }
2059
2060    /// Reveals the specified path at the platform level, such as in Finder on macOS.
2061    pub fn reveal_path(&self, path: &Path) {
2062        self.platform.reveal_path(path)
2063    }
2064
2065    /// Opens the specified path with the system's default application.
2066    pub fn open_with_system(&self, path: &Path) {
2067        self.platform.open_with_system(path)
2068    }
2069
2070    /// Returns whether the user has configured scrollbars to auto-hide at the platform level.
2071    pub fn should_auto_hide_scrollbars(&self) -> bool {
2072        self.platform.should_auto_hide_scrollbars()
2073    }
2074
2075    /// Restarts the application.
2076    pub fn restart(&mut self) {
2077        self.restart_observers
2078            .clone()
2079            .retain(|observer| observer(self));
2080        self.platform.restart(
2081            self.restart_path.take(),
2082            std::mem::take(&mut self.restart_arguments),
2083        )
2084    }
2085
2086    /// Sets the path to use when restarting the application.
2087    pub fn set_restart_path(&mut self, path: PathBuf) {
2088        self.restart_path = Some(path);
2089    }
2090
2091    /// Returns the HTTP client for the application.
2092    pub fn http_client(&self) -> Arc<dyn HttpClient> {
2093        self.http_client.clone()
2094    }
2095
2096    /// Sets the HTTP client for the application.
2097    pub fn set_http_client(&mut self, new_client: Arc<dyn HttpClient>) {
2098        self.http_client = new_client;
2099    }
2100
2101    /// Configures when the application should automatically quit.
2102    /// By default, [`QuitMode::Default`] is used.
2103    pub fn set_quit_mode(&mut self, mode: QuitMode) {
2104        self.quit_mode = mode;
2105    }
2106
2107    /// Sets whether the application participates in the system's foreground UI.
2108    ///
2109    /// Only has an effect on macOS, where [`Self::request_windowing`] normally sets it. Use this
2110    /// for an accessory app that shows windows, such as a menu bar utility. It overrides the
2111    /// policy until the next [`Self::request_windowing`], and the app counts as headless while
2112    /// `Accessory`. After switching to [`ActivationPolicy::Regular`], activate the app yourself
2113    /// with [`Self::activate`]; otherwise its menu bar may not appear until the app is
2114    /// reactivated.
2115    pub fn set_activation_policy(&mut self, policy: ActivationPolicy) {
2116        self.platform.set_activation_policy(policy);
2117    }
2118
2119    /// Returns the SVG renderer used by the application.
2120    pub fn svg_renderer(&self) -> SvgRenderer {
2121        self.svg_renderer.clone()
2122    }
2123
2124    pub(crate) fn push_effect(&mut self, effect: Effect) {
2125        match &effect {
2126            Effect::Notify { emitter } => {
2127                if !self.pending_notifications.insert(*emitter) {
2128                    return;
2129                }
2130            }
2131            Effect::NotifyGlobalObservers { global_type } => {
2132                if !self.pending_global_notifications.insert(*global_type) {
2133                    return;
2134                }
2135            }
2136            _ => {}
2137        };
2138
2139        self.pending_effects.push_back(effect);
2140    }
2141
2142    /// Called at the end of [`App::update`] to complete any side effects
2143    /// such as notifying observers, emitting events, etc. Effects can themselves
2144    /// cause effects, so we continue looping until all effects are processed.
2145    fn flush_effects(&mut self) {
2146        loop {
2147            self.release_dropped_entities();
2148            self.release_dropped_focus_handles();
2149            if let Some(effect) = self.pending_effects.pop_front() {
2150                match effect {
2151                    Effect::Notify { emitter } => {
2152                        self.apply_notify_effect(emitter);
2153                    }
2154
2155                    Effect::Emit {
2156                        emitter,
2157                        event_type,
2158                        event,
2159                    } => self.apply_emit_effect(emitter, event_type, &*event),
2160
2161                    Effect::RefreshWindows => {
2162                        self.apply_refresh_effect();
2163                    }
2164
2165                    Effect::NotifyGlobalObservers { global_type } => {
2166                        self.apply_notify_global_observers_effect(global_type);
2167                    }
2168
2169                    Effect::Defer { callback } => {
2170                        self.apply_defer_effect(callback);
2171                    }
2172                    Effect::EntityCreated {
2173                        entity,
2174                        tid,
2175                        window,
2176                    } => {
2177                        self.apply_entity_created_effect(entity, tid, window);
2178                    }
2179                }
2180            } else {
2181                #[cfg(any(test, feature = "test-support"))]
2182                if matches!(self.mode, GpuiMode::Test { .. }) {
2183                    for window in self
2184                        .windows
2185                        .values()
2186                        .filter_map(|window| {
2187                            let window = window.as_deref()?;
2188                            window.invalidator.is_dirty().then_some(window.handle)
2189                        })
2190                        .collect::<Vec<_>>()
2191                    {
2192                        self.update_window(window, |_, window, cx| window.draw(cx).clear(cx))
2193                            .unwrap();
2194                    }
2195                }
2196
2197                if self.pending_effects.is_empty() {
2198                    for window in self.windows.values().filter_map(|window| window.as_deref()) {
2199                        if window.invalidator.is_dirty()
2200                            || window.needs_present.get()
2201                            || !window.next_frame_callbacks.borrow().is_empty()
2202                        {
2203                            window.platform_window.schedule_frame();
2204                        }
2205                    }
2206
2207                    self.event_arena.clear();
2208                    break;
2209                }
2210            }
2211        }
2212    }
2213
2214    /// Repeatedly called during `flush_effects` to release any entities whose
2215    /// reference count has become zero. We invoke any release observers before dropping
2216    /// each entity.
2217    fn release_dropped_entities(&mut self) {
2218        loop {
2219            let dropped = self.entities.take_dropped();
2220            if dropped.is_empty() {
2221                break;
2222            }
2223
2224            for (entity_id, mut entity) in dropped {
2225                self.observers.remove(&entity_id);
2226                self.event_listeners.remove(&entity_id);
2227                self.window_invalidators_by_entity.remove(&entity_id);
2228                self.current_window_by_entity.remove(&entity_id);
2229                for release_callback in self.release_listeners.remove(&entity_id) {
2230                    release_callback(entity.as_mut(), self);
2231                }
2232            }
2233        }
2234    }
2235
2236    /// Repeatedly called during `flush_effects` to handle a focused handle being dropped.
2237    fn release_dropped_focus_handles(&mut self) {
2238        let focus_handles = self.focus_handles.clone();
2239        let mut focus_handles = focus_handles.write();
2240        let FocusMap {
2241            handles,
2242            dropped_handles,
2243        } = &mut *focus_handles;
2244        if dropped_handles.is_empty() {
2245            return;
2246        }
2247
2248        let windows = self
2249            .windows
2250            .values()
2251            .filter_map(|window| {
2252                let window = window.as_ref()?;
2253                dropped_handles
2254                    .contains(&window.focus?)
2255                    .then_some(window.handle)
2256            })
2257            .collect::<SmallVec<[_; 1]>>();
2258        for handle_id in dropped_handles.drain(..) {
2259            handles.remove(handle_id);
2260        }
2261        drop(focus_handles);
2262
2263        for window_handle in windows {
2264            window_handle
2265                .update(self, |_, window, cx| window.blur(cx))
2266                .ok();
2267        }
2268    }
2269
2270    fn apply_notify_effect(&mut self, emitter: EntityId) {
2271        self.pending_notifications.remove(&emitter);
2272
2273        self.observers
2274            .clone()
2275            .retain(&emitter, |handler| handler(self));
2276    }
2277
2278    fn apply_emit_effect(&mut self, emitter: EntityId, event_type: TypeId, event: &dyn Any) {
2279        self.event_listeners
2280            .clone()
2281            .retain(&emitter, |(stored_type, handler)| {
2282                if *stored_type == event_type {
2283                    handler(event, self)
2284                } else {
2285                    true
2286                }
2287            });
2288    }
2289
2290    fn apply_refresh_effect(&mut self) {
2291        for window in self.windows.values_mut() {
2292            if let Some(window) = window.as_deref_mut() {
2293                window.refreshing = true;
2294                window.invalidator.set_dirty(true);
2295            }
2296        }
2297    }
2298
2299    fn apply_notify_global_observers_effect(&mut self, type_id: TypeId) {
2300        self.pending_global_notifications.remove(&type_id);
2301        self.global_observers
2302            .clone()
2303            .retain(&type_id, |observer| observer(self));
2304    }
2305
2306    fn apply_defer_effect(&mut self, callback: Box<dyn FnOnce(&mut Self) + 'static>) {
2307        callback(self);
2308    }
2309
2310    fn apply_entity_created_effect(
2311        &mut self,
2312        entity: AnyEntity,
2313        tid: TypeId,
2314        window: Option<WindowId>,
2315    ) {
2316        // Seed the entity's current window from its creation context so
2317        // `with_window` resolves correctly before the entity has ever been
2318        // rendered.
2319        if let Some(id) = window {
2320            self.current_window_by_entity.insert(entity.entity_id(), id);
2321        }
2322
2323        self.new_entity_observers.clone().retain(&tid, |observer| {
2324            if let Some(id) = window {
2325                self.update_window_id(id, {
2326                    let entity = entity.clone();
2327                    |_, window, cx| (observer)(entity, &mut Some(window), cx)
2328                })
2329                .expect("All windows should be off the stack when flushing effects");
2330            } else {
2331                (observer)(entity.clone(), &mut None, self)
2332            }
2333            true
2334        });
2335    }
2336
2337    /// Run `f` against the entity's *current* window — the most recently
2338    /// rendered window that referenced the entity, or its creation window if
2339    /// it has yet to be rendered. Returns `None` if the entity has no
2340    /// current window, or if that window has been closed, or if it is
2341    /// already on the update stack.
2342    #[inline(always)]
2343    pub fn with_window<R>(
2344        &mut self,
2345        entity_id: EntityId,
2346        f: impl FnOnce(&mut Window, &mut App) -> R,
2347    ) -> Option<R> {
2348        let window_id = *self.current_window_by_entity.get(&entity_id)?;
2349        self.update_window_id(window_id, |_, window, cx| f(window, cx))
2350            .ok()
2351    }
2352
2353    fn ensure_window(&mut self, entity_id: EntityId, window: WindowId) {
2354        self.current_window_by_entity
2355            .entry(entity_id)
2356            .or_insert(window);
2357    }
2358
2359    #[inline(always)]
2360    pub(crate) fn update_window_id<T, F>(&mut self, id: WindowId, update: F) -> Result<T>
2361    where
2362        F: FnOnce(AnyView, &mut Window, &mut App) -> T,
2363    {
2364        let mut update = Some(update);
2365        let mut result = None;
2366        self.update_window_erased(id, &mut |arguments| {
2367            if let Some((root_view, window, cx)) = arguments {
2368                result = Some(update.take().unwrap()(root_view, window, cx));
2369            } else {
2370                drop(update.take());
2371                drop(result.take());
2372            }
2373        });
2374        result.context("window not found")
2375    }
2376
2377    /// Creates an `AsyncApp`, which can be cloned and has a static lifetime
2378    /// so it can be held across `await` points.
2379    pub fn to_async(&self) -> AsyncApp {
2380        AsyncApp {
2381            app: self.this.clone(),
2382            background_executor: self.background_executor.clone(),
2383            foreground_executor: self.foreground_executor.clone(),
2384        }
2385    }
2386
2387    /// Obtains a reference to the executor, which can be used to spawn futures.
2388    pub fn background_executor(&self) -> &BackgroundExecutor {
2389        &self.background_executor
2390    }
2391
2392    /// Whether this app runs on the deterministic test scheduler. See
2393    /// [`BackgroundExecutor::is_test`].
2394    pub fn is_test(&self) -> bool {
2395        self.background_executor.is_test()
2396    }
2397
2398    /// Obtains a reference to the executor, which can be used to spawn futures.
2399    pub fn foreground_executor(&self) -> &ForegroundExecutor {
2400        if self.quitting {
2401            panic!("Can't spawn on main thread after on_app_quit")
2402        };
2403        &self.foreground_executor
2404    }
2405
2406    /// Returns the foreground work journal for this app's foreground thread.
2407    /// Apps constructed on the same thread share the stream.
2408    #[cfg(feature = "profiler")]
2409    pub fn foreground_journal(&self) -> crate::profiler::journal::ForegroundJournal {
2410        self.foreground_journal.clone()
2411    }
2412
2413    /// Starts detecting foreground hangs on a dedicated thread.
2414    ///
2415    /// Nothing is spawned unless the app calls this. The thread polls a
2416    /// detector over this app's foreground journal every `config.interval`
2417    /// and passes each poll's incidents, including empty polls, to `on_poll`
2418    /// on that thread. When the app quits, a final poll with
2419    /// [`HangMonitorPollReason::Flush`] runs during shutdown, concurrently
2420    /// with quit handlers and within [`SHUTDOWN_TIMEOUT`], so `on_poll` can
2421    /// deliver batched results.
2422    ///
2423    /// # Errors
2424    ///
2425    /// Fails if the monitor was already started or its thread can't be
2426    /// spawned.
2427    ///
2428    /// [`HangMonitorPollReason::Flush`]: crate::profiler::hang::HangMonitorPollReason::Flush
2429    #[cfg(all(feature = "profiler", not(target_family = "wasm")))]
2430    pub fn start_hang_monitor(
2431        &mut self,
2432        config: crate::profiler::hang::HangMonitorConfig,
2433        on_poll: impl FnMut(crate::profiler::hang::HangMonitorPoll) + Send + 'static,
2434    ) -> Result<(), crate::profiler::hang::HangMonitorError> {
2435        use crate::profiler::hang::{HangDetector, HangMonitor, HangMonitorError};
2436
2437        if self.hang_monitor.is_some() {
2438            debug_assert!(false, "the hang monitor was started twice");
2439            return Err(HangMonitorError::AlreadyStarted);
2440        }
2441        let detector = HangDetector::new(
2442            self.foreground_journal(),
2443            config.threshold,
2444            config.frame_budget,
2445        );
2446        let monitor = HangMonitor::spawn(detector, config.interval, on_poll)
2447            .map_err(HangMonitorError::Spawn)?;
2448        self.hang_monitor = Some(monitor);
2449        Ok(())
2450    }
2451
2452    /// Spawns the future returned by the given function on the main thread. The closure will be invoked
2453    /// with [AsyncApp], which allows the application state to be accessed across await points.
2454    #[track_caller]
2455    #[inline(always)]
2456    pub fn spawn<AsyncFn, R>(&self, f: AsyncFn) -> Task<R>
2457    where
2458        AsyncFn: AsyncFnOnce(&mut AsyncApp) -> R + 'static,
2459        R: 'static,
2460    {
2461        let mut cx = self.prepare_spawn();
2462
2463        self.foreground_executor
2464            .spawn(async move { f(&mut cx).await }.boxed_local())
2465    }
2466
2467    /// Spawns the future returned by the given function on the main thread with
2468    /// the given priority. The closure will be invoked with [AsyncApp], which
2469    /// allows the application state to be accessed across await points.
2470    pub fn spawn_with_priority<AsyncFn, R>(&self, priority: Priority, f: AsyncFn) -> Task<R>
2471    where
2472        AsyncFn: AsyncFnOnce(&mut AsyncApp) -> R + 'static,
2473        R: 'static,
2474    {
2475        if self.quitting {
2476            debug_panic!("Can't spawn on main thread after on_app_quit")
2477        };
2478
2479        let mut cx = self.to_async();
2480
2481        self.foreground_executor
2482            .spawn_with_priority(priority, async move { f(&mut cx).await }.boxed_local())
2483    }
2484
2485    /// Schedules the given function to be run at the end of the current effect cycle, allowing entities
2486    /// that are currently on the stack to be returned to the app.
2487    pub fn defer(&mut self, f: impl FnOnce(&mut App) + 'static) {
2488        self.push_effect(Effect::Defer {
2489            callback: Box::new(f),
2490        });
2491    }
2492
2493    /// Accessor for the application's asset source, which is provided when constructing the `App`.
2494    pub fn asset_source(&self) -> &Arc<dyn AssetSource> {
2495        &self.asset_source
2496    }
2497
2498    /// Accessor for the text system.
2499    pub fn text_system(&self) -> &Arc<TextSystem> {
2500        &self.text_system
2501    }
2502
2503    /// Invokes a callback with grapheme clusters that exhausted font fallback.
2504    ///
2505    /// Registering a callback replaces the previous callback and enables missing-glyph
2506    /// detection. The callback runs on the foreground executor after shaping has
2507    /// released its internal locks. Dropping its subscription disables detection until
2508    /// another callback is registered.
2509    ///
2510    /// Reports are queued without blocking shaping, then deduplicated before delivery.
2511    /// The bounded queue can drop reports on overflow. Dropped reports may be reported
2512    /// again when the text is reshaped; no retry is scheduled automatically.
2513    pub fn on_missing_glyphs(
2514        &self,
2515        callback: impl FnMut(&[MissingGlyph], &mut App) + 'static,
2516    ) -> Subscription {
2517        let registration = self.missing_glyph_callback.replace(Box::new(callback));
2518
2519        if let Some(mut receiver) = self.text_system.take_missing_glyph_receiver() {
2520            let callback = self.missing_glyph_callback.clone();
2521            self.spawn(async move |cx| {
2522                while let Ok(missing_glyphs) = receiver.recv().await {
2523                    cx.update(|cx| callback.invoke(&missing_glyphs, cx));
2524                }
2525            })
2526            .detach();
2527        }
2528        self.text_system.enable_missing_glyph_reporting();
2529
2530        let callback = self.missing_glyph_callback.clone();
2531        let text_system = self.text_system.clone();
2532        Subscription::new(move || {
2533            if callback.remove(&registration) {
2534                text_system.disable_missing_glyph_reporting();
2535            }
2536        })
2537    }
2538
2539    /// Check whether a global of the given type has been assigned.
2540    pub fn has_global<G: Global>(&self) -> bool {
2541        self.globals_by_type.contains_key(&TypeId::of::<G>())
2542    }
2543
2544    /// Access the global of the given type. Panics if a global for that type has not been assigned.
2545    #[track_caller]
2546    pub fn global<G: Global>(&self) -> &G {
2547        self.globals_by_type
2548            .get(&TypeId::of::<G>())
2549            .map(|any_state| any_state.downcast_ref::<G>().unwrap())
2550            .unwrap_or_else(|| panic!("no state of type {} exists", type_name::<G>()))
2551    }
2552
2553    /// Access the global of the given type if a value has been assigned.
2554    pub fn try_global<G: Global>(&self) -> Option<&G> {
2555        self.globals_by_type
2556            .get(&TypeId::of::<G>())
2557            .map(|any_state| any_state.downcast_ref::<G>().unwrap())
2558    }
2559
2560    /// Access the global of the given type mutably. Panics if a global for that type has not been assigned.
2561    #[track_caller]
2562    pub fn global_mut<G: Global>(&mut self) -> &mut G {
2563        let global_type = TypeId::of::<G>();
2564        self.push_effect(Effect::NotifyGlobalObservers { global_type });
2565        self.globals_by_type
2566            .get_mut(&global_type)
2567            .and_then(|any_state| any_state.downcast_mut::<G>())
2568            .unwrap_or_else(|| panic!("no state of type {} exists", type_name::<G>()))
2569    }
2570
2571    /// Access the global of the given type mutably. A default value is assigned if a global of this type has not
2572    /// yet been assigned.
2573    pub fn default_global<G: Global + Default>(&mut self) -> &mut G {
2574        let global_type = TypeId::of::<G>();
2575        self.push_effect(Effect::NotifyGlobalObservers { global_type });
2576        self.globals_by_type
2577            .entry(global_type)
2578            .or_insert_with(|| Box::<G>::default())
2579            .downcast_mut::<G>()
2580            .unwrap()
2581    }
2582
2583    /// Sets the value of the global of the given type.
2584    pub fn set_global<G: Global>(&mut self, global: G) {
2585        let global_type = TypeId::of::<G>();
2586        self.push_effect(Effect::NotifyGlobalObservers { global_type });
2587        self.globals_by_type.insert(global_type, Box::new(global));
2588    }
2589
2590    /// Clear all stored globals. Does not notify global observers.
2591    #[cfg(any(test, feature = "test-support"))]
2592    pub fn clear_globals(&mut self) {
2593        self.globals_by_type.drain();
2594    }
2595
2596    /// Remove the global of the given type from the app context. Does not notify global observers.
2597    pub fn remove_global<G: Global>(&mut self) -> G {
2598        let global_type = TypeId::of::<G>();
2599        self.push_effect(Effect::NotifyGlobalObservers { global_type });
2600        *self
2601            .globals_by_type
2602            .remove(&global_type)
2603            .unwrap_or_else(|| panic!("no global added for {}", type_name::<G>()))
2604            .downcast()
2605            .unwrap()
2606    }
2607
2608    /// Register a callback to be invoked when a global of the given type is updated.
2609    pub fn observe_global<G: Global>(
2610        &mut self,
2611        mut f: impl FnMut(&mut Self) + 'static,
2612    ) -> Subscription {
2613        let (subscription, activate) = self.global_observers.insert_pending(
2614            TypeId::of::<G>(),
2615            Box::new(move |cx| {
2616                f(cx);
2617                true
2618            }),
2619        );
2620        self.defer(move |_| activate());
2621        subscription
2622    }
2623
2624    /// Move the global of the given type to the stack.
2625    #[track_caller]
2626    pub(crate) fn lease_global<G: Global>(&mut self) -> GlobalLease<G> {
2627        GlobalLease::new(
2628            self.globals_by_type
2629                .remove(&TypeId::of::<G>())
2630                .with_context(|| format!("no global registered of type {}", type_name::<G>()))
2631                .unwrap(),
2632        )
2633    }
2634
2635    /// Restore the global of the given type after it is moved to the stack.
2636    pub(crate) fn end_global_lease<G: Global>(&mut self, lease: GlobalLease<G>) {
2637        let global_type = TypeId::of::<G>();
2638
2639        self.push_effect(Effect::NotifyGlobalObservers { global_type });
2640        self.globals_by_type.insert(global_type, lease.global);
2641    }
2642
2643    pub(crate) fn new_entity_observer(
2644        &self,
2645        key: TypeId,
2646        value: NewEntityListener,
2647    ) -> Subscription {
2648        self.new_entity_observers.insert(key, value)
2649    }
2650
2651    /// Arrange for the given function to be invoked whenever a view of the specified type is created.
2652    /// The function will be passed a mutable reference to the view along with an appropriate context.
2653    pub fn observe_new<T: 'static>(
2654        &self,
2655        on_new: impl 'static + Fn(&mut T, Option<&mut Window>, &mut Context<T>),
2656    ) -> Subscription {
2657        self.new_entity_observer(
2658            TypeId::of::<T>(),
2659            Box::new(
2660                move |any_entity: AnyEntity, window: &mut Option<&mut Window>, cx: &mut App| {
2661                    any_entity
2662                        .downcast::<T>()
2663                        .unwrap()
2664                        .update(cx, |entity_state, cx| {
2665                            on_new(entity_state, window.as_deref_mut(), cx)
2666                        })
2667                },
2668            ),
2669        )
2670    }
2671
2672    /// Observe the release of a entity. The callback is invoked after the entity
2673    /// has no more strong references but before it has been dropped.
2674    pub fn observe_release<T>(
2675        &self,
2676        handle: &Entity<T>,
2677        on_release: impl FnOnce(&mut T, &mut App) + 'static,
2678    ) -> Subscription
2679    where
2680        T: 'static,
2681    {
2682        self.release_listeners.insert(
2683            handle.entity_id(),
2684            Box::new(move |entity, cx| {
2685                let entity = entity.downcast_mut().expect("invalid entity type");
2686                on_release(entity, cx)
2687            }),
2688        )
2689    }
2690
2691    /// Observe the release of a entity. The callback is invoked after the entity
2692    /// has no more strong references but before it has been dropped.
2693    pub fn observe_release_in<T>(
2694        &self,
2695        handle: &Entity<T>,
2696        window: &Window,
2697        on_release: impl FnOnce(&mut T, &mut Window, &mut App) + 'static,
2698    ) -> Subscription
2699    where
2700        T: 'static,
2701    {
2702        let window_handle = window.handle;
2703        self.observe_release(handle, move |entity, cx| {
2704            let _ = window_handle.update(cx, |_, window, cx| on_release(entity, window, cx));
2705        })
2706    }
2707
2708    /// Register a callback to be invoked after a keystroke is resolved in any window,
2709    /// including the action that handled it, if any. Keystrokes consumed by an
2710    /// interceptor or raw keyboard event handler are not observed.
2711    /// Standalone modifiers are observed on release.
2712    pub fn observe_keystrokes(
2713        &mut self,
2714        mut f: impl FnMut(&KeystrokeEvent, &mut Window, &mut App) + 'static,
2715    ) -> Subscription {
2716        self.keystroke_observers
2717            .insert(Box::new(move |event, window, cx| {
2718                f(event, window, cx);
2719                true
2720            }))
2721    }
2722
2723    /// Register a callback to be invoked when a keystroke is received by the application
2724    /// in any window. Note that this fires _before_ all other action and event mechanisms have resolved
2725    /// unlike [`App::observe_keystrokes`] which fires after. This means that `cx.stop_propagation` calls
2726    /// within interceptors will prevent action dispatch
2727    pub fn intercept_keystrokes(
2728        &mut self,
2729        mut f: impl FnMut(&KeystrokeEvent, &mut Window, &mut App) + 'static,
2730    ) -> Subscription {
2731        self.keystroke_interceptors
2732            .insert(Box::new(move |event, window, cx| {
2733                f(event, window, cx);
2734                true
2735            }))
2736    }
2737
2738    /// Register key bindings.
2739    pub fn bind_keys(&mut self, bindings: impl IntoIterator<Item = KeyBinding>) {
2740        self.keymap.borrow_mut().add_bindings(bindings);
2741        self.pending_effects.push_back(Effect::RefreshWindows);
2742    }
2743
2744    /// Clear all key bindings in the app.
2745    pub fn clear_key_bindings(&mut self) {
2746        self.keymap.borrow_mut().clear();
2747        self.pending_effects.push_back(Effect::RefreshWindows);
2748    }
2749
2750    /// Get all key bindings in the app.
2751    pub fn key_bindings(&self) -> Rc<RefCell<Keymap>> {
2752        self.keymap.clone()
2753    }
2754
2755    /// Register a global handler for actions invoked via the keyboard. These handlers are run at
2756    /// the end of the bubble phase for actions, and so will only be invoked if there are no other
2757    /// handlers or if they called `cx.propagate()`.
2758    pub fn on_action<A: Action>(
2759        &mut self,
2760        listener: impl Fn(&A, &mut Self) + 'static,
2761    ) -> &mut Self {
2762        self.global_action_listeners
2763            .entry(TypeId::of::<A>())
2764            .or_default()
2765            .push(Rc::new(move |action, phase, cx| {
2766                if phase == DispatchPhase::Bubble {
2767                    let action = action.downcast_ref().unwrap();
2768                    listener(action, cx)
2769                }
2770            }));
2771        self
2772    }
2773
2774    /// Event handlers propagate events by default. Call this method to stop dispatching to
2775    /// event handlers with a lower z-index (mouse) or higher in the tree (keyboard). This is
2776    /// the opposite of [`Self::propagate`]. It's also possible to cancel a call to [`Self::propagate`] by
2777    /// calling this method before effects are flushed.
2778    pub fn stop_propagation(&mut self) {
2779        self.propagate_event = false;
2780    }
2781
2782    /// Action handlers stop propagation by default during the bubble phase of action dispatch
2783    /// dispatching to action handlers higher in the element tree. This is the opposite of
2784    /// [`Self::stop_propagation`]. It's also possible to cancel a call to [`Self::stop_propagation`] by calling
2785    /// this method before effects are flushed.
2786    pub fn propagate(&mut self) {
2787        self.propagate_event = true;
2788    }
2789
2790    /// Build an action from some arbitrary data, typically a keymap entry.
2791    pub fn build_action(
2792        &self,
2793        name: &str,
2794        data: Option<serde_json::Value>,
2795    ) -> std::result::Result<Box<dyn Action>, ActionBuildError> {
2796        self.actions.build_action(name, data)
2797    }
2798
2799    /// Get all action names that have been registered. Note that registration only allows for
2800    /// actions to be built dynamically, and is unrelated to binding actions in the element tree.
2801    pub fn all_action_names(&self) -> &[&'static str] {
2802        self.actions.all_action_names()
2803    }
2804
2805    /// Returns key bindings that invoke the given action on the currently focused element, without
2806    /// checking context. Bindings are returned in the order they were added. For display, the last
2807    /// binding should take precedence.
2808    pub fn all_bindings_for_input(&self, input: &[Keystroke]) -> Vec<KeyBinding> {
2809        RefCell::borrow(&self.keymap).all_bindings_for_input(input)
2810    }
2811
2812    /// Get all non-internal actions that have been registered, along with their schemas.
2813    pub fn action_schemas(
2814        &self,
2815        generator: &mut schemars::SchemaGenerator,
2816    ) -> Vec<(&'static str, Option<schemars::Schema>)> {
2817        self.actions.action_schemas(generator)
2818    }
2819
2820    /// Get the schema for a specific action by name.
2821    /// Returns `None` if the action is not found.
2822    /// Returns `Some(None)` if the action exists but has no schema.
2823    /// Returns `Some(Some(schema))` if the action exists and has a schema.
2824    pub fn action_schema_by_name(
2825        &self,
2826        name: &str,
2827        generator: &mut schemars::SchemaGenerator,
2828    ) -> Option<Option<schemars::Schema>> {
2829        self.actions.action_schema_by_name(name, generator)
2830    }
2831
2832    /// Get a map from a deprecated action name to the canonical name.
2833    pub fn deprecated_actions_to_preferred_actions(&self) -> &HashMap<&'static str, &'static str> {
2834        self.actions.deprecated_aliases()
2835    }
2836
2837    /// Get a map from an action name to the deprecation messages.
2838    pub fn action_deprecation_messages(&self) -> &HashMap<&'static str, &'static str> {
2839        self.actions.deprecation_messages()
2840    }
2841
2842    /// Get a map from an action name to the documentation.
2843    pub fn action_documentation(&self) -> &HashMap<&'static str, &'static str> {
2844        self.actions.documentation()
2845    }
2846
2847    /// Register a callback to be invoked when the application is about to quit.
2848    /// It is not possible to cancel the quit event at this point.
2849    pub fn on_app_quit<Fut>(
2850        &self,
2851        mut on_quit: impl FnMut(&mut App) -> Fut + 'static,
2852    ) -> Subscription
2853    where
2854        Fut: 'static + Future<Output = ()>,
2855    {
2856        self.quit_observers.insert(Box::new(move |cx| {
2857            let future = on_quit(cx);
2858            future.boxed_local()
2859        }))
2860    }
2861
2862    /// Register a callback to be invoked when the application is about to restart.
2863    ///
2864    /// These callbacks are called before any `on_app_quit` callbacks.
2865    pub fn on_app_restart(&self, mut on_restart: impl 'static + FnMut(&mut App)) -> Subscription {
2866        self.restart_observers.insert(Box::new(move |cx| {
2867            on_restart(cx);
2868            true
2869        }))
2870    }
2871
2872    /// Register a callback to be invoked when a window is closed
2873    /// The window is no longer accessible at the point this callback is invoked.
2874    pub fn on_window_closed(
2875        &self,
2876        on_closed: impl FnMut(&mut App, WindowId) + 'static,
2877    ) -> Subscription {
2878        self.window_closed_observers.insert(Box::new(on_closed))
2879    }
2880
2881    pub(crate) fn clear_pending_keystrokes(&mut self) {
2882        for window in self.windows() {
2883            window
2884                .update(self, |_, window, cx| {
2885                    window.clear_pending_keystrokes(cx);
2886                })
2887                .ok();
2888        }
2889    }
2890
2891    /// Checks if the given action is bound in the current context, as defined by the app's current focus,
2892    /// the bindings in the element tree, and any global action listeners.
2893    pub fn is_action_available(&mut self, action: &dyn Action) -> bool {
2894        let mut action_available = false;
2895        if let Some(window) = self.active_window()
2896            && let Ok(window_action_available) =
2897                window.update(self, |_, window, cx| window.is_action_available(action, cx))
2898        {
2899            action_available = window_action_available;
2900        }
2901
2902        action_available
2903            || self
2904                .global_action_listeners
2905                .contains_key(&action.as_any().type_id())
2906    }
2907
2908    /// Sets the menu bar for this application. This will replace any existing menu bar.
2909    pub fn set_menus(&self, menus: impl IntoIterator<Item = Menu>) {
2910        let menus: Vec<Menu> = menus.into_iter().collect();
2911        self.platform.set_menus(menus, &self.keymap.borrow());
2912    }
2913
2914    /// Gets the menu bar for this application.
2915    pub fn get_menus(&self) -> Option<Vec<OwnedMenu>> {
2916        self.platform.get_menus()
2917    }
2918
2919    /// Sets the right click menu for the app icon in the dock
2920    pub fn set_dock_menu(&self, menus: Vec<MenuItem>) {
2921        self.platform.set_dock_menu(menus, &self.keymap.borrow())
2922    }
2923
2924    /// Performs the action associated with the given dock menu item, only used on Windows for now.
2925    pub fn perform_dock_menu_action(&self, action: usize) {
2926        self.platform.perform_dock_menu_action(action);
2927    }
2928
2929    /// Adds given path to the bottom of the list of recent paths for the application.
2930    /// The list is usually shown on the application icon's context menu in the dock,
2931    /// and allows to open the recent files via that context menu.
2932    /// If the path is already in the list, it will be moved to the bottom of the list.
2933    pub fn add_recent_document(&self, path: &Path) {
2934        self.platform.add_recent_document(path);
2935    }
2936
2937    /// Updates the jump list with the updated list of recent paths for the application, only used on Windows for now.
2938    /// Note that this also sets the dock menu on Windows.
2939    pub fn update_jump_list(
2940        &self,
2941        menus: Vec<MenuItem>,
2942        entries: Vec<SmallVec<[PathBuf; 2]>>,
2943    ) -> Task<Vec<SmallVec<[PathBuf; 2]>>> {
2944        self.platform.update_jump_list(menus, entries)
2945    }
2946
2947    /// Dispatch an action to the currently active window or global action handler
2948    /// See [`crate::Action`] for more information on how actions work
2949    pub fn dispatch_action(&mut self, action: &dyn Action) {
2950        if let Some(active_window) = self.active_window() {
2951            active_window
2952                .update(self, |_, window, cx| {
2953                    window.dispatch_action(action.boxed_clone(), cx)
2954                })
2955                .log_err();
2956        } else {
2957            self.dispatch_global_action(action);
2958        }
2959    }
2960
2961    fn dispatch_global_action(&mut self, action: &dyn Action) {
2962        self.propagate_event = true;
2963
2964        if let Some(mut global_listeners) = self
2965            .global_action_listeners
2966            .remove(&action.as_any().type_id())
2967        {
2968            for listener in &global_listeners {
2969                listener(action.as_any(), DispatchPhase::Capture, self);
2970                if !self.propagate_event {
2971                    break;
2972                }
2973            }
2974
2975            global_listeners.extend(
2976                self.global_action_listeners
2977                    .remove(&action.as_any().type_id())
2978                    .unwrap_or_default(),
2979            );
2980
2981            self.global_action_listeners
2982                .insert(action.as_any().type_id(), global_listeners);
2983        }
2984
2985        if self.propagate_event
2986            && let Some(mut global_listeners) = self
2987                .global_action_listeners
2988                .remove(&action.as_any().type_id())
2989        {
2990            for listener in global_listeners.iter().rev() {
2991                listener(action.as_any(), DispatchPhase::Bubble, self);
2992                if !self.propagate_event {
2993                    break;
2994                }
2995            }
2996
2997            global_listeners.extend(
2998                self.global_action_listeners
2999                    .remove(&action.as_any().type_id())
3000                    .unwrap_or_default(),
3001            );
3002
3003            self.global_action_listeners
3004                .insert(action.as_any().type_id(), global_listeners);
3005        }
3006    }
3007
3008    /// Is there currently something being dragged?
3009    pub fn has_active_drag(&self) -> bool {
3010        self.active_drag.is_some()
3011    }
3012
3013    /// Gets the cursor style of the currently active drag operation.
3014    pub fn active_drag_cursor_style(&self) -> Option<CursorStyle> {
3015        self.active_drag.as_ref().and_then(|drag| drag.cursor_style)
3016    }
3017
3018    /// Stops active drag and clears any related effects.
3019    pub fn stop_active_drag(&mut self, window: &mut Window) -> bool {
3020        if self.active_drag.is_some() {
3021            self.active_drag = None;
3022            if self.platform_owned_drag.as_ref().is_some_and(|drag| {
3023                drag.source_window == window.window_handle().window_id()
3024                    && matches!(&drag.state, PlatformOwnedDragState::RestoredInSourceWindow)
3025            }) {
3026                self.platform_owned_drag = None;
3027            }
3028            window.refresh();
3029            true
3030        } else {
3031            false
3032        }
3033    }
3034
3035    pub(crate) fn hand_active_drag_to_platform(&mut self, source_window: WindowId) -> bool {
3036        let Some(drag) = self.active_drag.take() else {
3037            return false;
3038        };
3039        self.platform_owned_drag = Some(PlatformOwnedDrag {
3040            source_window,
3041            state: PlatformOwnedDragState::Suspended(drag),
3042        });
3043        true
3044    }
3045
3046    pub(crate) fn restore_platform_drag(&mut self, source_window: WindowId) -> bool {
3047        let Some(platform_drag) = self
3048            .platform_owned_drag
3049            .as_mut()
3050            .filter(|drag| drag.source_window == source_window)
3051        else {
3052            return false;
3053        };
3054        let state = std::mem::replace(
3055            &mut platform_drag.state,
3056            PlatformOwnedDragState::RestoredInSourceWindow,
3057        );
3058        let PlatformOwnedDragState::Suspended(drag) = state else {
3059            return false;
3060        };
3061        self.active_drag = Some(drag);
3062        true
3063    }
3064
3065    pub(crate) fn hand_restored_drag_to_platform(&mut self, source_window: WindowId) -> bool {
3066        let Some(platform_drag) = self.platform_owned_drag.as_mut().filter(|drag| {
3067            drag.source_window == source_window
3068                && matches!(&drag.state, PlatformOwnedDragState::RestoredInSourceWindow)
3069        }) else {
3070            return false;
3071        };
3072        let Some(drag) = self.active_drag.take() else {
3073            return false;
3074        };
3075        platform_drag.state = PlatformOwnedDragState::Suspended(drag);
3076        true
3077    }
3078
3079    pub(crate) fn end_platform_drag(&mut self, source_window: WindowId) -> bool {
3080        if !self
3081            .platform_owned_drag
3082            .as_ref()
3083            .is_some_and(|drag| drag.source_window == source_window)
3084        {
3085            return false;
3086        }
3087        self.platform_owned_drag = None;
3088        self.active_drag = None;
3089        true
3090    }
3091
3092    /// Sets the cursor style for the currently active drag operation.
3093    pub fn set_active_drag_cursor_style(
3094        &mut self,
3095        cursor_style: CursorStyle,
3096        window: &mut Window,
3097    ) -> bool {
3098        if let Some(ref mut drag) = self.active_drag {
3099            drag.cursor_style = Some(cursor_style);
3100            window.refresh();
3101            true
3102        } else {
3103            false
3104        }
3105    }
3106
3107    /// Set the prompt renderer for GPUI. This will replace the default or platform specific
3108    /// prompts with this custom implementation.
3109    pub fn set_prompt_builder(
3110        &mut self,
3111        renderer: impl Fn(
3112            PromptLevel,
3113            &str,
3114            Option<&str>,
3115            &[PromptButton],
3116            PromptHandle,
3117            &mut Window,
3118            &mut App,
3119        ) -> RenderablePromptHandle
3120        + 'static,
3121    ) {
3122        self.prompt_builder = Some(PromptBuilder::Custom(Box::new(renderer)));
3123    }
3124
3125    /// Reset the prompt builder to the default implementation.
3126    pub fn reset_prompt_builder(&mut self) {
3127        self.prompt_builder = Some(PromptBuilder::Default);
3128    }
3129
3130    /// Remove an asset from GPUI's cache
3131    pub fn remove_asset<A: Asset>(&mut self, source: &A::Source) {
3132        let asset_id = (TypeId::of::<A>(), hash(source));
3133        self.loading_assets.remove(&asset_id);
3134    }
3135
3136    /// Check whether an asset is present in GPUI's cache (loading or loaded),
3137    /// without fetching it.
3138    #[cfg(any(test, feature = "test-support"))]
3139    pub fn has_asset<A: Asset>(&self, source: &A::Source) -> bool {
3140        let asset_id = (TypeId::of::<A>(), hash(source));
3141        self.loading_assets.contains_key(&asset_id)
3142    }
3143
3144    /// Starts loading an uncached asset and returns its result once available.
3145    ///
3146    /// Pending loads and completed results are cached until [`Self::remove_asset`].
3147    /// This method does not subscribe a view to completion notifications.
3148    pub fn fetch_asset<A: Asset>(&mut self, source: &A::Source) -> Option<A::Output> {
3149        self.asset_entry::<A>(source).get()
3150    }
3151
3152    pub(crate) fn asset_entry<A: Asset>(&mut self, source: &A::Source) -> &CachedLoad<A::Output> {
3153        let asset_id = (TypeId::of::<A>(), hash(source));
3154        if !self.loading_assets.contains_key(&asset_id) {
3155            let future = A::load(source.clone(), self);
3156            let entry = CachedLoad::new(future, self);
3157            self.loading_assets.insert(asset_id, Box::new(entry));
3158        }
3159        self.loading_assets
3160            .get(&asset_id)
3161            .and_then(|entry| entry.downcast_ref())
3162            .expect("asset cache entries are keyed by their asset type")
3163    }
3164
3165    /// Obtain a new [`FocusHandle`], which allows you to track and manipulate the keyboard focus
3166    /// for elements rendered within this window.
3167    #[track_caller]
3168    pub fn focus_handle(&self) -> FocusHandle {
3169        FocusHandle::new(&self.focus_handles)
3170    }
3171
3172    /// Tell GPUI that an entity has changed and observers of it should be notified.
3173    pub fn notify(&mut self, entity_id: EntityId) {
3174        let window_invalidators = mem::take(
3175            self.window_invalidators_by_entity
3176                .entry(entity_id)
3177                .or_default(),
3178        );
3179
3180        // `window_invalidators_by_entity` is monotonic, so an entry alone
3181        // doesn't mean the window is currently rendering the entity. Filter
3182        // through `tracked_entities` to keep invalidation tight to windows
3183        // that actually display this entity right now.
3184        let live_invalidators: SmallVec<[WindowInvalidator; 2]> = window_invalidators
3185            .iter()
3186            .filter(|(window_id, _)| {
3187                self.tracked_entities
3188                    .get(window_id)
3189                    .is_some_and(|set| set.contains(&entity_id))
3190            })
3191            .map(|(_, invalidator)| invalidator.clone())
3192            .collect();
3193
3194        if live_invalidators.is_empty() {
3195            if self.pending_notifications.insert(entity_id) {
3196                self.pending_effects
3197                    .push_back(Effect::Notify { emitter: entity_id });
3198            }
3199        } else {
3200            for invalidator in &live_invalidators {
3201                invalidator.invalidate_view(entity_id, self);
3202            }
3203        }
3204
3205        self.window_invalidators_by_entity
3206            .insert(entity_id, window_invalidators);
3207    }
3208
3209    /// Returns the name for this [`App`].
3210    #[cfg(any(test, feature = "test-support", debug_assertions))]
3211    pub fn get_name(&self) -> Option<&'static str> {
3212        self.name
3213    }
3214
3215    /// Returns `true` if the platform file picker supports selecting a mix of files and directories.
3216    pub fn can_select_mixed_files_and_dirs(&self) -> bool {
3217        self.platform.can_select_mixed_files_and_dirs()
3218    }
3219
3220    /// Removes an image from the sprite atlas on all windows.
3221    ///
3222    /// If the current window is being updated, it will be removed from `App.windows`, you can use `current_window` to specify the current window.
3223    /// This is a no-op if the image is not in the sprite atlas.
3224    pub fn drop_image(&mut self, image: Arc<RenderImage>, current_window: Option<&mut Window>) {
3225        // remove the texture from all other windows
3226        for window in self.windows.values_mut().flatten() {
3227            _ = window.drop_image(image.clone());
3228        }
3229
3230        // remove the texture from the current window
3231        if let Some(window) = current_window {
3232            _ = window.drop_image(image);
3233        }
3234    }
3235
3236    /// Sets the renderer for the inspector.
3237    #[cfg(any(feature = "inspector", debug_assertions))]
3238    pub fn set_inspector_renderer(&mut self, f: crate::InspectorRenderer) {
3239        self.inspector_renderer = Some(f);
3240    }
3241
3242    /// Registers a renderer specific to an inspector state.
3243    #[cfg(any(feature = "inspector", debug_assertions))]
3244    pub fn register_inspector_element<T: 'static, R: crate::IntoElement, F>(
3245        &mut self,
3246        factory: impl 'static + Fn(&mut Window, &mut App) -> F,
3247    ) where
3248        F: 'static + FnMut(crate::InspectorElementId, &T, &mut Window, &mut App) -> R,
3249    {
3250        self.inspector_element_registry.register(factory);
3251    }
3252
3253    /// Initializes gpui's default colors for the application.
3254    ///
3255    /// These colors can be accessed through `cx.default_colors()`.
3256    pub fn init_colors(&mut self) {
3257        self.set_global(GlobalColors(Arc::new(Colors::default())));
3258    }
3259
3260    #[inline(never)]
3261    fn update_window_erased(
3262        &mut self,
3263        window_id: WindowId,
3264        update: &mut dyn FnMut(Option<(AnyView, &mut Window, &mut App)>),
3265    ) {
3266        self.update(|cx| {
3267            let Some(mut window) = cx.windows.get_mut(window_id).and_then(Option::take) else {
3268                update(None);
3269                return;
3270            };
3271
3272            let root_view = window.root.clone().unwrap();
3273
3274            cx.window_update_stack.push(window.handle.id);
3275            update(Some((root_view, &mut window, cx)));
3276            fn trail(window_id: WindowId, window: Box<Window>, cx: &mut App) -> Option<()> {
3277                cx.window_update_stack.pop();
3278
3279                if window.removed {
3280                    cx.end_platform_drag(window_id);
3281                    cx.window_handles.remove(&window_id);
3282                    cx.windows.remove(window_id);
3283                    if let Some(tracked) = cx.tracked_entities.remove(&window_id) {
3284                        for entity_id in tracked {
3285                            if let Some(windows) =
3286                                cx.window_invalidators_by_entity.get_mut(&entity_id)
3287                            {
3288                                windows.remove(&window_id);
3289                            }
3290                            if cx.current_window_by_entity.get(&entity_id) == Some(&window_id) {
3291                                cx.current_window_by_entity.remove(&entity_id);
3292                            }
3293                        }
3294                    }
3295
3296                    cx.window_closed_observers.clone().retain(|callback| {
3297                        callback(cx, window_id);
3298                        true
3299                    });
3300
3301                    let quit_on_empty = match cx.quit_mode {
3302                        QuitMode::Explicit => false,
3303                        QuitMode::LastWindowClosed => true,
3304                        QuitMode::Default => cfg!(not(target_os = "macos")),
3305                    };
3306
3307                    if quit_on_empty && cx.windows.is_empty() {
3308                        cx.quit();
3309                    }
3310                } else {
3311                    cx.windows.get_mut(window_id)?.replace(window);
3312                }
3313                Some(())
3314            }
3315            if trail(window_id, window, cx).is_none() {
3316                update(None);
3317            }
3318        });
3319    }
3320
3321    #[inline(never)]
3322    fn update_entity_erased(
3323        &mut self,
3324        handle: &AnyEntity,
3325        entity_type: &str,
3326        update: &mut dyn FnMut(&mut dyn Any, &mut App),
3327    ) {
3328        self.update(|cx| {
3329            let mut lease = cx.entities.lease_erased(handle, entity_type);
3330            update(lease.entity.as_deref_mut().unwrap(), cx);
3331            cx.entities.end_lease_erased(handle.entity_id, lease);
3332        });
3333    }
3334
3335    #[inline(never)]
3336    #[track_caller]
3337    fn prepare_spawn(&self) -> AsyncApp {
3338        if self.quitting {
3339            debug_panic!("Can't spawn on main thread after on_app_quit")
3340        };
3341        self.to_async()
3342    }
3343}
3344
3345impl AppContext for App {
3346    /// Builds an entity that is owned by the application.
3347    ///
3348    /// The given function will be invoked with a [`Context`] and must return an object representing the entity. An
3349    /// [`Entity`] handle will be returned, which can be used to access the entity in a context.
3350    fn new<T: 'static>(&mut self, build_entity: impl FnOnce(&mut Context<T>) -> T) -> Entity<T> {
3351        self.update(|cx| {
3352            let slot = cx.entities.reserve();
3353            let handle = slot.clone();
3354            let entity = build_entity(&mut Context::new_context(cx, slot.downgrade()));
3355
3356            cx.push_effect(Effect::EntityCreated {
3357                entity: handle.into_any(),
3358                tid: TypeId::of::<T>(),
3359                window: cx.window_update_stack.last().cloned(),
3360            });
3361
3362            cx.entities.insert(slot, entity)
3363        })
3364    }
3365
3366    fn reserve_entity<T: 'static>(&mut self) -> Reservation<T> {
3367        Reservation(self.entities.reserve())
3368    }
3369
3370    fn insert_entity<T: 'static>(
3371        &mut self,
3372        reservation: Reservation<T>,
3373        build_entity: impl FnOnce(&mut Context<T>) -> T,
3374    ) -> Entity<T> {
3375        self.update(|cx| {
3376            let slot = reservation.0;
3377            let entity = build_entity(&mut Context::new_context(cx, slot.downgrade()));
3378            cx.entities.insert(slot, entity)
3379        })
3380    }
3381
3382    /// Updates the entity referenced by the given handle. The function is passed a mutable reference to the
3383    /// entity along with a `Context` for the entity.
3384    #[inline(always)]
3385    fn update_entity<T: 'static, R>(
3386        &mut self,
3387        handle: &Entity<T>,
3388        update: impl FnOnce(&mut T, &mut Context<T>) -> R,
3389    ) -> R {
3390        let mut update = Some(update);
3391        let mut result = None;
3392        self.update_entity_erased(handle, type_name::<T>(), &mut |entity, cx| {
3393            let value = update.take().unwrap()(
3394                entity.downcast_mut::<T>().unwrap(),
3395                &mut Context::new_context(cx, handle.downgrade()),
3396            );
3397            result = Some(value);
3398        });
3399        result.unwrap()
3400    }
3401
3402    fn as_mut<'a, T>(&'a mut self, handle: &Entity<T>) -> GpuiBorrow<'a, T>
3403    where
3404        T: 'static,
3405    {
3406        GpuiBorrow::new(handle.clone(), self)
3407    }
3408
3409    #[inline(always)]
3410    fn read_entity<T, R>(&self, handle: &Entity<T>, read: impl FnOnce(&T, &App) -> R) -> R
3411    where
3412        T: 'static,
3413    {
3414        let entity = self.entities.read(handle);
3415        read(entity, self)
3416    }
3417
3418    fn update_window<T, F>(&mut self, handle: AnyWindowHandle, update: F) -> Result<T>
3419    where
3420        F: FnOnce(AnyView, &mut Window, &mut App) -> T,
3421    {
3422        self.update_window_id(handle.id, update)
3423    }
3424
3425    fn with_window<R>(
3426        &mut self,
3427        entity_id: EntityId,
3428        f: impl FnOnce(&mut Window, &mut App) -> R,
3429    ) -> Option<R> {
3430        App::with_window(self, entity_id, f)
3431    }
3432
3433    fn read_window<T, R>(
3434        &self,
3435        window: &WindowHandle<T>,
3436        read: impl FnOnce(Entity<T>, &App) -> R,
3437    ) -> Result<R>
3438    where
3439        T: 'static,
3440    {
3441        let window = self
3442            .windows
3443            .get(window.id)
3444            .context("window not found")?
3445            .as_deref()
3446            .expect("attempted to read a window that is already on the stack");
3447
3448        let root_view = window.root.clone().unwrap();
3449        let view = root_view
3450            .downcast::<T>()
3451            .map_err(|_| anyhow!("root view's type has changed"))?;
3452
3453        Ok(read(view, self))
3454    }
3455
3456    fn background_spawn<R>(&self, future: impl Future<Output = R> + Send + 'static) -> Task<R>
3457    where
3458        R: Send + 'static,
3459    {
3460        self.background_executor.spawn(future)
3461    }
3462
3463    fn read_global<G, R>(&self, callback: impl FnOnce(&G, &App) -> R) -> R
3464    where
3465        G: Global,
3466    {
3467        let g = self.global::<G>();
3468        callback(g, self)
3469    }
3470}
3471
3472/// These effects are processed at the end of each application update cycle.
3473pub(crate) enum Effect {
3474    Notify {
3475        emitter: EntityId,
3476    },
3477    Emit {
3478        emitter: EntityId,
3479        event_type: TypeId,
3480        event: ArenaBox<dyn Any>,
3481    },
3482    RefreshWindows,
3483    NotifyGlobalObservers {
3484        global_type: TypeId,
3485    },
3486    Defer {
3487        callback: Box<dyn FnOnce(&mut App) + 'static>,
3488    },
3489    EntityCreated {
3490        entity: AnyEntity,
3491        tid: TypeId,
3492        window: Option<WindowId>,
3493    },
3494}
3495
3496impl std::fmt::Debug for Effect {
3497    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3498        match self {
3499            Effect::Notify { emitter } => write!(f, "Notify({})", emitter),
3500            Effect::Emit { emitter, .. } => write!(f, "Emit({:?})", emitter),
3501            Effect::RefreshWindows => write!(f, "RefreshWindows"),
3502            Effect::NotifyGlobalObservers { global_type } => {
3503                write!(f, "NotifyGlobalObservers({:?})", global_type)
3504            }
3505            Effect::Defer { .. } => write!(f, "Defer(..)"),
3506            Effect::EntityCreated { entity, .. } => write!(f, "EntityCreated({:?})", entity),
3507        }
3508    }
3509}
3510
3511/// Wraps a global variable value during `update_global` while the value has been moved to the stack.
3512pub(crate) struct GlobalLease<G: Global> {
3513    global: Box<dyn Any>,
3514    global_type: PhantomData<G>,
3515}
3516
3517impl<G: Global> GlobalLease<G> {
3518    fn new(global: Box<dyn Any>) -> Self {
3519        GlobalLease {
3520            global,
3521            global_type: PhantomData,
3522        }
3523    }
3524}
3525
3526impl<G: Global> Deref for GlobalLease<G> {
3527    type Target = G;
3528
3529    fn deref(&self) -> &Self::Target {
3530        self.global.downcast_ref().unwrap()
3531    }
3532}
3533
3534impl<G: Global> DerefMut for GlobalLease<G> {
3535    fn deref_mut(&mut self) -> &mut Self::Target {
3536        self.global.downcast_mut().unwrap()
3537    }
3538}
3539
3540/// Contains state associated with an active drag operation, started by dragging an element
3541/// within the window or by dragging into the app from the underlying platform.
3542pub struct AnyDrag {
3543    /// The view used to render this drag
3544    pub view: AnyView,
3545
3546    /// The value of the dragged item, to be dropped
3547    pub value: Arc<dyn Any>,
3548
3549    /// This is used to render the dragged item in the same place
3550    /// on the original element that the drag was initiated
3551    pub cursor_offset: Point<Pixels>,
3552
3553    /// The cursor style to use while dragging
3554    pub cursor_style: Option<CursorStyle>,
3555
3556    /// Resolves the payload to offer the platform if the drag leaves the window.
3557    /// Invoked at most once per drag gesture, at promotion time.
3558    pub external_payload_source: Option<ExternalDragPayloadSource>,
3559}
3560
3561/// Lazily resolves the payload handed to the platform when an internal drag is
3562/// promoted to a native drag session.
3563pub type ExternalDragPayloadSource =
3564    Box<dyn FnOnce(&mut Window, &mut App) -> Option<ExternalDragPayload> + 'static>;
3565
3566/// Contains state associated with a tooltip. You'll only need this struct if you're implementing
3567/// tooltip behavior on a custom element. Otherwise, use [Div::tooltip](crate::Interactivity::tooltip).
3568#[derive(Clone)]
3569pub struct AnyTooltip {
3570    /// The view used to display the tooltip
3571    pub view: AnyView,
3572
3573    /// The absolute position of the mouse when the tooltip was deployed.
3574    pub mouse_position: Point<Pixels>,
3575
3576    /// Given the bounds of the tooltip, checks whether the tooltip should still be visible and
3577    /// updates its state accordingly. This is needed atop the hovered element's mouse move handler
3578    /// to handle the case where the element is not painted (e.g. via use of `visible_on_hover`).
3579    pub check_visible_and_update: Rc<dyn Fn(Bounds<Pixels>, &mut Window, &mut App) -> bool>,
3580}
3581
3582/// Whether a keystroke should prefer character input or key bindings.
3583#[derive(Clone, Copy, Debug, Eq, PartialEq)]
3584pub enum InputPreference {
3585    /// Prefer typing text over triggering key bindings.
3586    CharacterInput,
3587    /// Dispatch key bindings normally, if any match.
3588    KeyBindings,
3589}
3590
3591/// A keystroke event, and potentially the associated action
3592#[derive(Debug)]
3593pub struct KeystrokeEvent {
3594    /// The keystroke that occurred
3595    pub keystroke: Keystroke,
3596
3597    /// Whether this keystroke should prefer character input or key bindings.
3598    /// This is [`InputPreference::CharacterInput`] when the platform prefers text for the key
3599    /// (e.g. AltGr on Windows) and the focused input accepts text. Interceptors still receive
3600    /// these keystrokes and can consume them.
3601    ///
3602    /// If the keystroke is part of a multi-stroke binding, it still waits as pending input
3603    /// even when this is [`InputPreference::CharacterInput`].
3604    pub input_preference: InputPreference,
3605
3606    /// The action that was resolved for the keystroke, if any
3607    pub action: Option<Box<dyn Action>>,
3608
3609    /// The context stack at the time
3610    pub context_stack: Vec<KeyContext>,
3611}
3612
3613struct NullHttpClient;
3614
3615impl HttpClient for NullHttpClient {
3616    fn send(
3617        &self,
3618        _req: http_client::Request<http_client::AsyncBody>,
3619    ) -> futures::future::BoxFuture<
3620        'static,
3621        anyhow::Result<http_client::Response<http_client::AsyncBody>>,
3622    > {
3623        async move {
3624            anyhow::bail!("No HttpClient available");
3625        }
3626        .boxed()
3627    }
3628
3629    fn user_agent(&self) -> Option<&http_client::http::HeaderValue> {
3630        None
3631    }
3632
3633    fn proxy(&self) -> Option<&Url> {
3634        None
3635    }
3636}
3637
3638/// A mutable reference to an entity owned by GPUI
3639pub struct GpuiBorrow<'a, T> {
3640    inner: Option<Lease<T>>,
3641    app: &'a mut App,
3642}
3643
3644impl<'a, T: 'static> GpuiBorrow<'a, T> {
3645    fn new(inner: Entity<T>, app: &'a mut App) -> Self {
3646        app.start_update();
3647        let lease = app.entities.lease(&inner);
3648        Self {
3649            inner: Some(lease),
3650            app,
3651        }
3652    }
3653}
3654
3655impl<'a, T: 'static> std::borrow::Borrow<T> for GpuiBorrow<'a, T> {
3656    fn borrow(&self) -> &T {
3657        self.inner.as_ref().unwrap().borrow()
3658    }
3659}
3660
3661impl<'a, T: 'static> std::borrow::BorrowMut<T> for GpuiBorrow<'a, T> {
3662    fn borrow_mut(&mut self) -> &mut T {
3663        self.inner.as_mut().unwrap().borrow_mut()
3664    }
3665}
3666
3667impl<'a, T: 'static> std::ops::Deref for GpuiBorrow<'a, T> {
3668    type Target = T;
3669
3670    fn deref(&self) -> &Self::Target {
3671        self.inner.as_ref().unwrap()
3672    }
3673}
3674
3675impl<'a, T: 'static> std::ops::DerefMut for GpuiBorrow<'a, T> {
3676    fn deref_mut(&mut self) -> &mut T {
3677        self.inner.as_mut().unwrap()
3678    }
3679}
3680
3681impl<'a, T> Drop for GpuiBorrow<'a, T> {
3682    fn drop(&mut self) {
3683        let lease = self.inner.take().unwrap();
3684        self.app.notify(lease.id);
3685        self.app.entities.end_lease(lease);
3686        self.app.finish_update();
3687    }
3688}
3689
3690#[cfg(test)]
3691mod test {
3692    use std::{
3693        cell::{Cell, RefCell},
3694        ffi::OsString,
3695        path::PathBuf,
3696        rc::Rc,
3697    };
3698
3699    #[cfg(unix)]
3700    use std::os::unix::ffi::OsStringExt;
3701
3702    use crate::{
3703        AppContext, Context, Empty, FallbackFontClass, IntoElement, MissingGlyph, Render,
3704        TestAppContext, Window,
3705    };
3706
3707    #[gpui::test]
3708    fn app_borrow_diagnostics(cx: &mut TestAppContext) {
3709        use std::panic::{AssertUnwindSafe, catch_unwind};
3710
3711        let app = cx.app.clone();
3712        let first_line = line!() + 1;
3713        let first = app.borrow();
3714        let second = app.borrow();
3715        drop(first);
3716        assert!(app.try_borrow_mut().is_err());
3717        let attempted_line = line!() + 1;
3718        let panic = catch_unwind(AssertUnwindSafe(|| drop(app.borrow_mut())));
3719        let message = *panic
3720            .expect_err("conflicting borrow")
3721            .downcast::<String>()
3722            .unwrap();
3723        assert!(message.contains(&format!(
3724            "mutable App borrow at {}:{attempted_line}:",
3725            file!()
3726        )));
3727        assert!(message.contains(&format!(
3728            "shared borrow group began at {}:{first_line}:",
3729            file!()
3730        )));
3731        drop(second);
3732
3733        let origin_line = line!() + 2;
3734        let panic = catch_unwind(AssertUnwindSafe(|| {
3735            let _borrow = app.try_borrow_mut().expect("initial borrow");
3736            drop(app.borrow());
3737        }));
3738        let message = *panic
3739            .expect_err("conflicting borrow")
3740            .downcast::<String>()
3741            .unwrap();
3742        assert!(message.contains("attempted shared App borrow"));
3743        assert!(message.contains(&format!(
3744            "mutable borrow group began at {}:{origin_line}:",
3745            file!()
3746        )));
3747
3748        let next_line = line!() + 1;
3749        let _borrow = app.borrow();
3750        assert_eq!(
3751            app.borrow_origin.get().expect("new origin").0.line(),
3752            next_line
3753        );
3754    }
3755
3756    struct RenderCounter(Rc<Cell<usize>>);
3757
3758    impl Render for RenderCounter {
3759        fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
3760            self.0.set(self.0.get() + 1);
3761            Empty
3762        }
3763    }
3764
3765    #[gpui::test]
3766    fn async_app_refresh_flushes_refresh_effect(cx: &mut TestAppContext) {
3767        let render_count = Rc::new(Cell::new(0));
3768
3769        let _window = cx.add_window({
3770            let render_count = render_count.clone();
3771            move |_, _| RenderCounter(render_count)
3772        });
3773
3774        cx.run_until_parked();
3775        let render_count_before_refresh = render_count.get();
3776
3777        cx.to_async().refresh();
3778
3779        assert_eq!(render_count.get(), render_count_before_refresh + 1);
3780    }
3781
3782    #[gpui::test]
3783    fn missing_glyph_callbacks_follow_subscription_lifetime(cx: &mut TestAppContext) {
3784        let observed = Rc::new(RefCell::new(Vec::new()));
3785        let subscription = cx.update(|cx| {
3786            let observed = observed.clone();
3787            cx.on_missing_glyphs(move |missing_glyphs, _| {
3788                observed.borrow_mut().extend_from_slice(missing_glyphs);
3789            })
3790        });
3791        cx.update(|cx| {
3792            cx.text_system()
3793                .report_missing_glyphs_in_test(vec![missing_glyph("active")]);
3794        });
3795        cx.run_until_parked();
3796        assert_eq!(observed.borrow().as_slice(), &[missing_glyph("active")]);
3797
3798        let second_observed = Rc::new(RefCell::new(Vec::new()));
3799        let second_subscription = cx.update(|cx| {
3800            let second_observed = second_observed.clone();
3801            cx.on_missing_glyphs(move |missing_glyphs, _| {
3802                second_observed
3803                    .borrow_mut()
3804                    .extend_from_slice(missing_glyphs);
3805            })
3806        });
3807        cx.update(|cx| {
3808            cx.text_system()
3809                .report_missing_glyphs_in_test(vec![missing_glyph("replacement")]);
3810        });
3811        cx.run_until_parked();
3812        assert_eq!(observed.borrow().as_slice(), &[missing_glyph("active")]);
3813        assert_eq!(
3814            second_observed.borrow().as_slice(),
3815            &[missing_glyph("replacement")]
3816        );
3817
3818        drop(subscription);
3819        cx.update(|cx| {
3820            cx.text_system()
3821                .report_missing_glyphs_in_test(vec![missing_glyph("after old drop")]);
3822        });
3823        cx.run_until_parked();
3824        assert_eq!(
3825            second_observed.borrow().as_slice(),
3826            &[
3827                missing_glyph("replacement"),
3828                missing_glyph("after old drop")
3829            ]
3830        );
3831
3832        drop(second_subscription);
3833        cx.update(|cx| {
3834            cx.text_system()
3835                .report_missing_glyphs_in_test(vec![missing_glyph("inactive")]);
3836        });
3837        cx.run_until_parked();
3838        assert_eq!(second_observed.borrow().len(), 2);
3839    }
3840
3841    #[test]
3842    fn test_gpui_borrow() {
3843        let cx = TestAppContext::single();
3844        let observation_count = Rc::new(RefCell::new(0));
3845
3846        let state = cx.update(|cx| {
3847            let state = cx.new(|_| false);
3848            cx.observe(&state, {
3849                let observation_count = observation_count.clone();
3850                move |_, _| {
3851                    let mut count = observation_count.borrow_mut();
3852                    *count += 1;
3853                }
3854            })
3855            .detach();
3856
3857            state
3858        });
3859
3860        cx.update(|cx| {
3861            // Calling this like this so that we don't clobber the borrow_mut above
3862            *std::borrow::BorrowMut::borrow_mut(&mut state.as_mut(cx)) = true;
3863        });
3864
3865        cx.update(|cx| {
3866            state.write(cx, false);
3867        });
3868
3869        assert_eq!(*observation_count.borrow(), 2);
3870    }
3871
3872    #[gpui::test]
3873    async fn test_restart_preserves_path_and_arguments(cx: &mut TestAppContext) {
3874        #[cfg(unix)]
3875        let user_data_dir = OsString::from_vec(b"/tmp/zed data/\xff".to_vec());
3876        #[cfg(not(unix))]
3877        let user_data_dir = OsString::from("C:\\zed data");
3878        let arguments = vec![OsString::from("--user-data-dir"), user_data_dir];
3879        let restart_path = PathBuf::from("updated-zed");
3880        let _application =
3881            super::Application(cx.app.clone()).with_restart_arguments(arguments.clone());
3882        let restart = cx.expect_restart();
3883
3884        cx.update(|cx| {
3885            cx.set_restart_path(restart_path.clone());
3886            cx.restart();
3887        });
3888
3889        let (path, restart_arguments) = restart.await.expect("restart was not requested");
3890        assert_eq!(path, Some(restart_path));
3891        assert_eq!(restart_arguments, arguments);
3892    }
3893
3894    fn missing_glyph(grapheme: &'static str) -> MissingGlyph {
3895        MissingGlyph::new(grapheme.into(), FallbackFontClass::Proportional)
3896    }
3897}