app.rs

   1use std::{
   2    any::{TypeId, type_name},
   3    cell::{BorrowMutError, Cell, Ref, RefCell, RefMut},
   4    marker::PhantomData,
   5    mem,
   6    ops::{Deref, DerefMut},
   7    path::{Path, PathBuf},
   8    rc::{Rc, Weak},
   9    sync::{Arc, atomic::Ordering::SeqCst},
  10    time::{Duration, Instant},
  11};
  12
  13use anyhow::{Context as _, Result, anyhow};
  14use derive_more::{Deref, DerefMut};
  15use futures::{
  16    Future, FutureExt,
  17    channel::oneshot,
  18    future::{LocalBoxFuture, Shared},
  19};
  20use itertools::Itertools;
  21use parking_lot::RwLock;
  22use slotmap::SlotMap;
  23
  24pub use async_context::*;
  25use collections::{FxHashMap, FxHashSet, HashMap, VecDeque};
  26pub use context::*;
  27pub use entity_map::*;
  28use http_client::{HttpClient, Url};
  29use smallvec::SmallVec;
  30#[cfg(any(test, feature = "test-support"))]
  31pub use test_context::*;
  32use util::{ResultExt, debug_panic};
  33#[cfg(all(target_os = "macos", any(test, feature = "test-support")))]
  34pub use visual_test_context::*;
  35
  36#[cfg(any(feature = "inspector", debug_assertions))]
  37use crate::InspectorElementRegistry;
  38use crate::{
  39    Action, ActionBuildError, ActionRegistry, Any, AnyView, AnyWindowHandle, AppContext, Arena,
  40    ArenaBox, Asset, AssetSource, BackgroundExecutor, Bounds, ClipboardItem, CursorStyle,
  41    DispatchPhase, DisplayId, EventEmitter, FocusHandle, FocusMap, ForegroundExecutor, Global,
  42    KeyBinding, KeyContext, Keymap, Keystroke, LayoutId, Menu, MenuItem, OwnedMenu,
  43    PathPromptOptions, Pixels, Platform, PlatformDisplay, PlatformKeyboardLayout,
  44    PlatformKeyboardMapper, Point, Priority, PromptBuilder, PromptButton, PromptHandle,
  45    PromptLevel, Render, RenderImage, RenderablePromptHandle, Reservation, ScreenCaptureSource,
  46    SharedString, SubscriberSet, Subscription, SvgRenderer, Task, TextRenderingMode, TextSystem,
  47    ThermalState, Window, WindowAppearance, WindowHandle, WindowId, WindowInvalidator,
  48    colors::{Colors, GlobalColors},
  49    current_platform, hash, init_app_menus,
  50};
  51
  52mod async_context;
  53mod context;
  54mod entity_map;
  55#[cfg(any(test, feature = "test-support"))]
  56mod test_context;
  57#[cfg(all(target_os = "macos", any(test, feature = "test-support")))]
  58mod visual_test_context;
  59
  60/// The duration for which futures returned from [Context::on_app_quit] can run before the application fully quits.
  61pub const SHUTDOWN_TIMEOUT: Duration = Duration::from_millis(100);
  62
  63/// Temporary(?) wrapper around [`RefCell<App>`] to help us debug any double borrows.
  64/// Strongly consider removing after stabilization.
  65#[doc(hidden)]
  66pub struct AppCell {
  67    app: RefCell<App>,
  68}
  69
  70impl AppCell {
  71    #[doc(hidden)]
  72    #[track_caller]
  73    pub fn borrow(&self) -> AppRef<'_> {
  74        if option_env!("TRACK_THREAD_BORROWS").is_some() {
  75            let thread_id = std::thread::current().id();
  76            eprintln!("borrowed {thread_id:?}");
  77        }
  78        AppRef(self.app.borrow())
  79    }
  80
  81    #[doc(hidden)]
  82    #[track_caller]
  83    pub fn borrow_mut(&self) -> AppRefMut<'_> {
  84        if option_env!("TRACK_THREAD_BORROWS").is_some() {
  85            let thread_id = std::thread::current().id();
  86            eprintln!("borrowed {thread_id:?}");
  87        }
  88        AppRefMut(self.app.borrow_mut())
  89    }
  90
  91    #[doc(hidden)]
  92    #[track_caller]
  93    pub fn try_borrow_mut(&self) -> Result<AppRefMut<'_>, BorrowMutError> {
  94        if option_env!("TRACK_THREAD_BORROWS").is_some() {
  95            let thread_id = std::thread::current().id();
  96            eprintln!("borrowed {thread_id:?}");
  97        }
  98        Ok(AppRefMut(self.app.try_borrow_mut()?))
  99    }
 100}
 101
 102#[doc(hidden)]
 103#[derive(Deref, DerefMut)]
 104pub struct AppRef<'a>(Ref<'a, App>);
 105
 106impl Drop for AppRef<'_> {
 107    fn drop(&mut self) {
 108        if option_env!("TRACK_THREAD_BORROWS").is_some() {
 109            let thread_id = std::thread::current().id();
 110            eprintln!("dropped borrow from {thread_id:?}");
 111        }
 112    }
 113}
 114
 115#[doc(hidden)]
 116#[derive(Deref, DerefMut)]
 117pub struct AppRefMut<'a>(RefMut<'a, App>);
 118
 119impl Drop for AppRefMut<'_> {
 120    fn drop(&mut self) {
 121        if option_env!("TRACK_THREAD_BORROWS").is_some() {
 122            let thread_id = std::thread::current().id();
 123            eprintln!("dropped {thread_id:?}");
 124        }
 125    }
 126}
 127
 128/// A reference to a GPUI application, typically constructed in the `main` function of your app.
 129/// You won't interact with this type much outside of initial configuration and startup.
 130pub struct Application(Rc<AppCell>);
 131
 132/// Represents an application before it is fully launched. Once your app is
 133/// configured, you'll start the app with `App::run`.
 134impl Application {
 135    /// Builds an app with the given asset source.
 136    #[allow(clippy::new_without_default)]
 137    pub fn new() -> Self {
 138        #[cfg(any(test, feature = "test-support"))]
 139        log::info!("GPUI was compiled in test mode");
 140
 141        Self(App::new_app(
 142            current_platform(false),
 143            Arc::new(()),
 144            Arc::new(NullHttpClient),
 145        ))
 146    }
 147
 148    /// Build an app in headless mode. This prevents opening windows,
 149    /// but makes it possible to run an application in an context like
 150    /// SSH, where GUI applications are not allowed.
 151    pub fn headless() -> Self {
 152        Self(App::new_app(
 153            current_platform(true),
 154            Arc::new(()),
 155            Arc::new(NullHttpClient),
 156        ))
 157    }
 158
 159    /// Assigns the source of assets for the application.
 160    pub fn with_assets(self, asset_source: impl AssetSource) -> Self {
 161        let mut context_lock = self.0.borrow_mut();
 162        let asset_source = Arc::new(asset_source);
 163        context_lock.asset_source = asset_source.clone();
 164        context_lock.svg_renderer = SvgRenderer::new(asset_source);
 165        drop(context_lock);
 166        self
 167    }
 168
 169    /// Sets the HTTP client for the application.
 170    pub fn with_http_client(self, http_client: Arc<dyn HttpClient>) -> Self {
 171        let mut context_lock = self.0.borrow_mut();
 172        context_lock.http_client = http_client;
 173        drop(context_lock);
 174        self
 175    }
 176
 177    /// Configures when the application should automatically quit.
 178    /// By default, [`QuitMode::Default`] is used.
 179    pub fn with_quit_mode(self, mode: QuitMode) -> Self {
 180        self.0.borrow_mut().quit_mode = mode;
 181        self
 182    }
 183
 184    /// Start the application. The provided callback will be called once the
 185    /// app is fully launched.
 186    pub fn run<F>(self, on_finish_launching: F)
 187    where
 188        F: 'static + FnOnce(&mut App),
 189    {
 190        let this = self.0.clone();
 191        let platform = self.0.borrow().platform.clone();
 192        platform.run(Box::new(move || {
 193            let cx = &mut *this.borrow_mut();
 194            on_finish_launching(cx);
 195        }));
 196    }
 197
 198    /// Register a handler to be invoked when the platform instructs the application
 199    /// to open one or more URLs.
 200    pub fn on_open_urls<F>(&self, mut callback: F) -> &Self
 201    where
 202        F: 'static + FnMut(Vec<String>),
 203    {
 204        self.0.borrow().platform.on_open_urls(Box::new(callback));
 205        self
 206    }
 207
 208    /// Invokes a handler when an already-running application is launched.
 209    /// On macOS, this can occur when the application icon is double-clicked or the app is launched via the dock.
 210    pub fn on_reopen<F>(&self, mut callback: F) -> &Self
 211    where
 212        F: 'static + FnMut(&mut App),
 213    {
 214        let this = Rc::downgrade(&self.0);
 215        self.0.borrow_mut().platform.on_reopen(Box::new(move || {
 216            if let Some(app) = this.upgrade() {
 217                callback(&mut app.borrow_mut());
 218            }
 219        }));
 220        self
 221    }
 222
 223    /// Returns a handle to the [`BackgroundExecutor`] associated with this app, which can be used to spawn futures in the background.
 224    pub fn background_executor(&self) -> BackgroundExecutor {
 225        self.0.borrow().background_executor.clone()
 226    }
 227
 228    /// Returns a handle to the [`ForegroundExecutor`] associated with this app, which can be used to spawn futures in the foreground.
 229    pub fn foreground_executor(&self) -> ForegroundExecutor {
 230        self.0.borrow().foreground_executor.clone()
 231    }
 232
 233    /// Returns a reference to the [`TextSystem`] associated with this app.
 234    pub fn text_system(&self) -> Arc<TextSystem> {
 235        self.0.borrow().text_system.clone()
 236    }
 237
 238    /// Returns the file URL of the executable with the specified name in the application bundle
 239    pub fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf> {
 240        self.0.borrow().path_for_auxiliary_executable(name)
 241    }
 242}
 243
 244type Handler = Box<dyn FnMut(&mut App) -> bool + 'static>;
 245type Listener = Box<dyn FnMut(&dyn Any, &mut App) -> bool + 'static>;
 246pub(crate) type KeystrokeObserver =
 247    Box<dyn FnMut(&KeystrokeEvent, &mut Window, &mut App) -> bool + 'static>;
 248type QuitHandler = Box<dyn FnOnce(&mut App) -> LocalBoxFuture<'static, ()> + 'static>;
 249type WindowClosedHandler = Box<dyn FnMut(&mut App)>;
 250type ReleaseListener = Box<dyn FnOnce(&mut dyn Any, &mut App) + 'static>;
 251type NewEntityListener = Box<dyn FnMut(AnyEntity, &mut Option<&mut Window>, &mut App) + 'static>;
 252
 253/// Defines when the application should automatically quit.
 254#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
 255pub enum QuitMode {
 256    /// Use [`QuitMode::Explicit`] on macOS and [`QuitMode::LastWindowClosed`] on other platforms.
 257    #[default]
 258    Default,
 259    /// Quit automatically when the last window is closed.
 260    LastWindowClosed,
 261    /// Quit only when requested via [`App::quit`].
 262    Explicit,
 263}
 264
 265#[doc(hidden)]
 266#[derive(Clone, PartialEq, Eq)]
 267pub struct SystemWindowTab {
 268    pub id: WindowId,
 269    pub title: SharedString,
 270    pub handle: AnyWindowHandle,
 271    pub last_active_at: Instant,
 272}
 273
 274impl SystemWindowTab {
 275    /// Create a new instance of the window tab.
 276    pub fn new(title: SharedString, handle: AnyWindowHandle) -> Self {
 277        Self {
 278            id: handle.id,
 279            title,
 280            handle,
 281            last_active_at: Instant::now(),
 282        }
 283    }
 284}
 285
 286/// A controller for managing window tabs.
 287#[derive(Default)]
 288pub struct SystemWindowTabController {
 289    visible: Option<bool>,
 290    tab_groups: FxHashMap<usize, Vec<SystemWindowTab>>,
 291}
 292
 293impl Global for SystemWindowTabController {}
 294
 295impl SystemWindowTabController {
 296    /// Create a new instance of the window tab controller.
 297    pub fn new() -> Self {
 298        Self {
 299            visible: None,
 300            tab_groups: FxHashMap::default(),
 301        }
 302    }
 303
 304    /// Initialize the global window tab controller.
 305    pub fn init(cx: &mut App) {
 306        cx.set_global(SystemWindowTabController::new());
 307    }
 308
 309    /// Get all tab groups.
 310    pub fn tab_groups(&self) -> &FxHashMap<usize, Vec<SystemWindowTab>> {
 311        &self.tab_groups
 312    }
 313
 314    /// Get the next tab group window handle.
 315    pub fn get_next_tab_group_window(cx: &mut App, id: WindowId) -> Option<&AnyWindowHandle> {
 316        let controller = cx.global::<SystemWindowTabController>();
 317        let current_group = controller
 318            .tab_groups
 319            .iter()
 320            .find_map(|(group, tabs)| tabs.iter().find(|tab| tab.id == id).map(|_| group));
 321
 322        let current_group = current_group?;
 323        // TODO: `.keys()` returns arbitrary order, what does "next" mean?
 324        let mut group_ids: Vec<_> = controller.tab_groups.keys().collect();
 325        let idx = group_ids.iter().position(|g| *g == current_group)?;
 326        let next_idx = (idx + 1) % group_ids.len();
 327
 328        controller
 329            .tab_groups
 330            .get(group_ids[next_idx])
 331            .and_then(|tabs| {
 332                tabs.iter()
 333                    .max_by_key(|tab| tab.last_active_at)
 334                    .or_else(|| tabs.first())
 335                    .map(|tab| &tab.handle)
 336            })
 337    }
 338
 339    /// Get the previous tab group window handle.
 340    pub fn get_prev_tab_group_window(cx: &mut App, id: WindowId) -> Option<&AnyWindowHandle> {
 341        let controller = cx.global::<SystemWindowTabController>();
 342        let current_group = controller
 343            .tab_groups
 344            .iter()
 345            .find_map(|(group, tabs)| tabs.iter().find(|tab| tab.id == id).map(|_| group));
 346
 347        let current_group = current_group?;
 348        // TODO: `.keys()` returns arbitrary order, what does "previous" mean?
 349        let mut group_ids: Vec<_> = controller.tab_groups.keys().collect();
 350        let idx = group_ids.iter().position(|g| *g == current_group)?;
 351        let prev_idx = if idx == 0 {
 352            group_ids.len() - 1
 353        } else {
 354            idx - 1
 355        };
 356
 357        controller
 358            .tab_groups
 359            .get(group_ids[prev_idx])
 360            .and_then(|tabs| {
 361                tabs.iter()
 362                    .max_by_key(|tab| tab.last_active_at)
 363                    .or_else(|| tabs.first())
 364                    .map(|tab| &tab.handle)
 365            })
 366    }
 367
 368    /// Get all tabs in the same window.
 369    pub fn tabs(&self, id: WindowId) -> Option<&Vec<SystemWindowTab>> {
 370        self.tab_groups
 371            .values()
 372            .find(|tabs| tabs.iter().any(|tab| tab.id == id))
 373    }
 374
 375    /// Initialize the visibility of the system window tab controller.
 376    pub fn init_visible(cx: &mut App, visible: bool) {
 377        let mut controller = cx.global_mut::<SystemWindowTabController>();
 378        if controller.visible.is_none() {
 379            controller.visible = Some(visible);
 380        }
 381    }
 382
 383    /// Get the visibility of the system window tab controller.
 384    pub fn is_visible(&self) -> bool {
 385        self.visible.unwrap_or(false)
 386    }
 387
 388    /// Set the visibility of the system window tab controller.
 389    pub fn set_visible(cx: &mut App, visible: bool) {
 390        let mut controller = cx.global_mut::<SystemWindowTabController>();
 391        controller.visible = Some(visible);
 392    }
 393
 394    /// Update the last active of a window.
 395    pub fn update_last_active(cx: &mut App, id: WindowId) {
 396        let mut controller = cx.global_mut::<SystemWindowTabController>();
 397        for windows in controller.tab_groups.values_mut() {
 398            for tab in windows.iter_mut() {
 399                if tab.id == id {
 400                    tab.last_active_at = Instant::now();
 401                }
 402            }
 403        }
 404    }
 405
 406    /// Update the position of a tab within its group.
 407    pub fn update_tab_position(cx: &mut App, id: WindowId, ix: usize) {
 408        let mut controller = cx.global_mut::<SystemWindowTabController>();
 409        for (_, windows) in controller.tab_groups.iter_mut() {
 410            if let Some(current_pos) = windows.iter().position(|tab| tab.id == id) {
 411                if ix < windows.len() && current_pos != ix {
 412                    let window_tab = windows.remove(current_pos);
 413                    windows.insert(ix, window_tab);
 414                }
 415                break;
 416            }
 417        }
 418    }
 419
 420    /// Update the title of a tab.
 421    pub fn update_tab_title(cx: &mut App, id: WindowId, title: SharedString) {
 422        let controller = cx.global::<SystemWindowTabController>();
 423        let tab = controller
 424            .tab_groups
 425            .values()
 426            .flat_map(|windows| windows.iter())
 427            .find(|tab| tab.id == id);
 428
 429        if tab.map_or(true, |t| t.title == title) {
 430            return;
 431        }
 432
 433        let mut controller = cx.global_mut::<SystemWindowTabController>();
 434        for windows in controller.tab_groups.values_mut() {
 435            for tab in windows.iter_mut() {
 436                if tab.id == id {
 437                    tab.title = title;
 438                    return;
 439                }
 440            }
 441        }
 442    }
 443
 444    /// Insert a tab into a tab group.
 445    pub fn add_tab(cx: &mut App, id: WindowId, tabs: Vec<SystemWindowTab>) {
 446        let mut controller = cx.global_mut::<SystemWindowTabController>();
 447        let Some(tab) = tabs.iter().find(|tab| tab.id == id).cloned() else {
 448            return;
 449        };
 450
 451        let mut expected_tab_ids: Vec<_> = tabs
 452            .iter()
 453            .filter(|tab| tab.id != id)
 454            .map(|tab| tab.id)
 455            .sorted()
 456            .collect();
 457
 458        let mut tab_group_id = None;
 459        for (group_id, group_tabs) in &controller.tab_groups {
 460            let tab_ids: Vec<_> = group_tabs.iter().map(|tab| tab.id).sorted().collect();
 461            if tab_ids == expected_tab_ids {
 462                tab_group_id = Some(*group_id);
 463                break;
 464            }
 465        }
 466
 467        if let Some(tab_group_id) = tab_group_id {
 468            if let Some(tabs) = controller.tab_groups.get_mut(&tab_group_id) {
 469                tabs.push(tab);
 470            }
 471        } else {
 472            let new_group_id = controller.tab_groups.len();
 473            controller.tab_groups.insert(new_group_id, tabs);
 474        }
 475    }
 476
 477    /// Remove a tab from a tab group.
 478    pub fn remove_tab(cx: &mut App, id: WindowId) -> Option<SystemWindowTab> {
 479        let mut controller = cx.global_mut::<SystemWindowTabController>();
 480        let mut removed_tab = None;
 481
 482        controller.tab_groups.retain(|_, tabs| {
 483            if let Some(pos) = tabs.iter().position(|tab| tab.id == id) {
 484                removed_tab = Some(tabs.remove(pos));
 485            }
 486            !tabs.is_empty()
 487        });
 488
 489        removed_tab
 490    }
 491
 492    /// Move a tab to a new tab group.
 493    pub fn move_tab_to_new_window(cx: &mut App, id: WindowId) {
 494        let mut removed_tab = Self::remove_tab(cx, id);
 495        let mut controller = cx.global_mut::<SystemWindowTabController>();
 496
 497        if let Some(tab) = removed_tab {
 498            let new_group_id = controller.tab_groups.keys().max().map_or(0, |k| k + 1);
 499            controller.tab_groups.insert(new_group_id, vec![tab]);
 500        }
 501    }
 502
 503    /// Merge all tab groups into a single group.
 504    pub fn merge_all_windows(cx: &mut App, id: WindowId) {
 505        let mut controller = cx.global_mut::<SystemWindowTabController>();
 506        let Some(initial_tabs) = controller.tabs(id) else {
 507            return;
 508        };
 509
 510        let initial_tabs_len = initial_tabs.len();
 511        let mut all_tabs = initial_tabs.clone();
 512
 513        for (_, mut tabs) in controller.tab_groups.drain() {
 514            tabs.retain(|tab| !all_tabs[..initial_tabs_len].contains(tab));
 515            all_tabs.extend(tabs);
 516        }
 517
 518        controller.tab_groups.insert(0, all_tabs);
 519    }
 520
 521    /// Selects the next tab in the tab group in the trailing direction.
 522    pub fn select_next_tab(cx: &mut App, id: WindowId) {
 523        let mut controller = cx.global_mut::<SystemWindowTabController>();
 524        let Some(tabs) = controller.tabs(id) else {
 525            return;
 526        };
 527
 528        let current_index = tabs.iter().position(|tab| tab.id == id).unwrap();
 529        let next_index = (current_index + 1) % tabs.len();
 530
 531        let _ = &tabs[next_index].handle.update(cx, |_, window, _| {
 532            window.activate_window();
 533        });
 534    }
 535
 536    /// Selects the previous tab in the tab group in the leading direction.
 537    pub fn select_previous_tab(cx: &mut App, id: WindowId) {
 538        let mut controller = cx.global_mut::<SystemWindowTabController>();
 539        let Some(tabs) = controller.tabs(id) else {
 540            return;
 541        };
 542
 543        let current_index = tabs.iter().position(|tab| tab.id == id).unwrap();
 544        let previous_index = if current_index == 0 {
 545            tabs.len() - 1
 546        } else {
 547            current_index - 1
 548        };
 549
 550        let _ = &tabs[previous_index].handle.update(cx, |_, window, _| {
 551            window.activate_window();
 552        });
 553    }
 554}
 555
 556pub(crate) enum GpuiMode {
 557    #[cfg(any(test, feature = "test-support"))]
 558    Test {
 559        skip_drawing: bool,
 560    },
 561    Production,
 562}
 563
 564impl GpuiMode {
 565    #[cfg(any(test, feature = "test-support"))]
 566    pub fn test() -> Self {
 567        GpuiMode::Test {
 568            skip_drawing: false,
 569        }
 570    }
 571
 572    #[inline]
 573    pub(crate) fn skip_drawing(&self) -> bool {
 574        match self {
 575            #[cfg(any(test, feature = "test-support"))]
 576            GpuiMode::Test { skip_drawing } => *skip_drawing,
 577            GpuiMode::Production => false,
 578        }
 579    }
 580}
 581
 582/// Contains the state of the full application, and passed as a reference to a variety of callbacks.
 583/// Other [Context] derefs to this type.
 584/// You need a reference to an `App` to access the state of a [Entity].
 585pub struct App {
 586    pub(crate) this: Weak<AppCell>,
 587    pub(crate) platform: Rc<dyn Platform>,
 588    pub(crate) mode: GpuiMode,
 589    text_system: Arc<TextSystem>,
 590    flushing_effects: bool,
 591    pending_updates: usize,
 592    pub(crate) actions: Rc<ActionRegistry>,
 593    pub(crate) active_drag: Option<AnyDrag>,
 594    pub(crate) background_executor: BackgroundExecutor,
 595    pub(crate) foreground_executor: ForegroundExecutor,
 596    pub(crate) loading_assets: FxHashMap<(TypeId, u64), Box<dyn Any>>,
 597    asset_source: Arc<dyn AssetSource>,
 598    pub(crate) svg_renderer: SvgRenderer,
 599    http_client: Arc<dyn HttpClient>,
 600    pub(crate) globals_by_type: FxHashMap<TypeId, Box<dyn Any>>,
 601    pub(crate) entities: EntityMap,
 602    pub(crate) window_update_stack: Vec<WindowId>,
 603    pub(crate) new_entity_observers: SubscriberSet<TypeId, NewEntityListener>,
 604    pub(crate) windows: SlotMap<WindowId, Option<Box<Window>>>,
 605    pub(crate) window_handles: FxHashMap<WindowId, AnyWindowHandle>,
 606    pub(crate) focus_handles: Arc<FocusMap>,
 607    pub(crate) keymap: Rc<RefCell<Keymap>>,
 608    pub(crate) keyboard_layout: Box<dyn PlatformKeyboardLayout>,
 609    pub(crate) keyboard_mapper: Rc<dyn PlatformKeyboardMapper>,
 610    pub(crate) global_action_listeners:
 611        FxHashMap<TypeId, Vec<Rc<dyn Fn(&dyn Any, DispatchPhase, &mut Self)>>>,
 612    pending_effects: VecDeque<Effect>,
 613    pub(crate) pending_notifications: FxHashSet<EntityId>,
 614    pub(crate) pending_global_notifications: FxHashSet<TypeId>,
 615    pub(crate) observers: SubscriberSet<EntityId, Handler>,
 616    // TypeId is the type of the event that the listener callback expects
 617    pub(crate) event_listeners: SubscriberSet<EntityId, (TypeId, Listener)>,
 618    pub(crate) keystroke_observers: SubscriberSet<(), KeystrokeObserver>,
 619    pub(crate) keystroke_interceptors: SubscriberSet<(), KeystrokeObserver>,
 620    pub(crate) keyboard_layout_observers: SubscriberSet<(), Handler>,
 621    pub(crate) thermal_state_observers: SubscriberSet<(), Handler>,
 622    pub(crate) release_listeners: SubscriberSet<EntityId, ReleaseListener>,
 623    pub(crate) global_observers: SubscriberSet<TypeId, Handler>,
 624    pub(crate) quit_observers: SubscriberSet<(), QuitHandler>,
 625    pub(crate) restart_observers: SubscriberSet<(), Handler>,
 626    pub(crate) restart_path: Option<PathBuf>,
 627    pub(crate) window_closed_observers: SubscriberSet<(), WindowClosedHandler>,
 628    pub(crate) layout_id_buffer: Vec<LayoutId>, // We recycle this memory across layout requests.
 629    pub(crate) propagate_event: bool,
 630    pub(crate) prompt_builder: Option<PromptBuilder>,
 631    pub(crate) window_invalidators_by_entity:
 632        FxHashMap<EntityId, FxHashMap<WindowId, WindowInvalidator>>,
 633    pub(crate) tracked_entities: FxHashMap<WindowId, FxHashSet<EntityId>>,
 634    #[cfg(any(feature = "inspector", debug_assertions))]
 635    pub(crate) inspector_renderer: Option<crate::InspectorRenderer>,
 636    #[cfg(any(feature = "inspector", debug_assertions))]
 637    pub(crate) inspector_element_registry: InspectorElementRegistry,
 638    #[cfg(any(test, feature = "test-support", debug_assertions))]
 639    pub(crate) name: Option<&'static str>,
 640    pub(crate) text_rendering_mode: Rc<Cell<TextRenderingMode>>,
 641    quit_mode: QuitMode,
 642    quitting: bool,
 643    /// Per-App element arena. This isolates element allocations between different
 644    /// App instances (important for tests where multiple Apps run concurrently).
 645    pub(crate) element_arena: RefCell<Arena>,
 646    /// Per-App event arena.
 647    pub(crate) event_arena: Arena,
 648}
 649
 650impl App {
 651    #[allow(clippy::new_ret_no_self)]
 652    pub(crate) fn new_app(
 653        platform: Rc<dyn Platform>,
 654        asset_source: Arc<dyn AssetSource>,
 655        http_client: Arc<dyn HttpClient>,
 656    ) -> Rc<AppCell> {
 657        let background_executor = platform.background_executor();
 658        let foreground_executor = platform.foreground_executor();
 659        assert!(
 660            background_executor.is_main_thread(),
 661            "must construct App on main thread"
 662        );
 663
 664        let text_system = Arc::new(TextSystem::new(platform.text_system()));
 665        let entities = EntityMap::new();
 666        let keyboard_layout = platform.keyboard_layout();
 667        let keyboard_mapper = platform.keyboard_mapper();
 668
 669        let app = Rc::new_cyclic(|this| AppCell {
 670            app: RefCell::new(App {
 671                this: this.clone(),
 672                platform: platform.clone(),
 673                text_system,
 674                text_rendering_mode: Rc::new(Cell::new(TextRenderingMode::default())),
 675                mode: GpuiMode::Production,
 676                actions: Rc::new(ActionRegistry::default()),
 677                flushing_effects: false,
 678                pending_updates: 0,
 679                active_drag: None,
 680                background_executor,
 681                foreground_executor,
 682                svg_renderer: SvgRenderer::new(asset_source.clone()),
 683                loading_assets: Default::default(),
 684                asset_source,
 685                http_client,
 686                globals_by_type: FxHashMap::default(),
 687                entities,
 688                new_entity_observers: SubscriberSet::new(),
 689                windows: SlotMap::with_key(),
 690                window_update_stack: Vec::new(),
 691                window_handles: FxHashMap::default(),
 692                focus_handles: Arc::new(RwLock::new(SlotMap::with_key())),
 693                keymap: Rc::new(RefCell::new(Keymap::default())),
 694                keyboard_layout,
 695                keyboard_mapper,
 696                global_action_listeners: FxHashMap::default(),
 697                pending_effects: VecDeque::new(),
 698                pending_notifications: FxHashSet::default(),
 699                pending_global_notifications: FxHashSet::default(),
 700                observers: SubscriberSet::new(),
 701                tracked_entities: FxHashMap::default(),
 702                window_invalidators_by_entity: FxHashMap::default(),
 703                event_listeners: SubscriberSet::new(),
 704                release_listeners: SubscriberSet::new(),
 705                keystroke_observers: SubscriberSet::new(),
 706                keystroke_interceptors: SubscriberSet::new(),
 707                keyboard_layout_observers: SubscriberSet::new(),
 708                thermal_state_observers: SubscriberSet::new(),
 709                global_observers: SubscriberSet::new(),
 710                quit_observers: SubscriberSet::new(),
 711                restart_observers: SubscriberSet::new(),
 712                restart_path: None,
 713                window_closed_observers: SubscriberSet::new(),
 714                layout_id_buffer: Default::default(),
 715                propagate_event: true,
 716                prompt_builder: Some(PromptBuilder::Default),
 717                #[cfg(any(feature = "inspector", debug_assertions))]
 718                inspector_renderer: None,
 719                #[cfg(any(feature = "inspector", debug_assertions))]
 720                inspector_element_registry: InspectorElementRegistry::default(),
 721                quit_mode: QuitMode::default(),
 722                quitting: false,
 723
 724                #[cfg(any(test, feature = "test-support", debug_assertions))]
 725                name: None,
 726                element_arena: RefCell::new(Arena::new(1024 * 1024)),
 727                event_arena: Arena::new(1024 * 1024),
 728            }),
 729        });
 730
 731        init_app_menus(platform.as_ref(), &app.borrow());
 732        SystemWindowTabController::init(&mut app.borrow_mut());
 733
 734        platform.on_keyboard_layout_change(Box::new({
 735            let app = Rc::downgrade(&app);
 736            move || {
 737                if let Some(app) = app.upgrade() {
 738                    let cx = &mut app.borrow_mut();
 739                    cx.keyboard_layout = cx.platform.keyboard_layout();
 740                    cx.keyboard_mapper = cx.platform.keyboard_mapper();
 741                    cx.keyboard_layout_observers
 742                        .clone()
 743                        .retain(&(), move |callback| (callback)(cx));
 744                }
 745            }
 746        }));
 747
 748        platform.on_thermal_state_change(Box::new({
 749            let app = Rc::downgrade(&app);
 750            move || {
 751                if let Some(app) = app.upgrade() {
 752                    let cx = &mut app.borrow_mut();
 753                    cx.thermal_state_observers
 754                        .clone()
 755                        .retain(&(), move |callback| (callback)(cx));
 756                }
 757            }
 758        }));
 759
 760        platform.on_quit(Box::new({
 761            let cx = app.clone();
 762            move || {
 763                cx.borrow_mut().shutdown();
 764            }
 765        }));
 766
 767        app
 768    }
 769
 770    /// Quit the application gracefully. Handlers registered with [`Context::on_app_quit`]
 771    /// will be given 100ms to complete before exiting.
 772    pub fn shutdown(&mut self) {
 773        let mut futures = Vec::new();
 774
 775        for observer in self.quit_observers.remove(&()) {
 776            futures.push(observer(self));
 777        }
 778
 779        self.windows.clear();
 780        self.window_handles.clear();
 781        self.flush_effects();
 782        self.quitting = true;
 783
 784        let futures = futures::future::join_all(futures);
 785        if self
 786            .foreground_executor
 787            .block_with_timeout(SHUTDOWN_TIMEOUT, futures)
 788            .is_err()
 789        {
 790            log::error!("timed out waiting on app_will_quit");
 791        }
 792
 793        self.quitting = false;
 794    }
 795
 796    /// Get the id of the current keyboard layout
 797    pub fn keyboard_layout(&self) -> &dyn PlatformKeyboardLayout {
 798        self.keyboard_layout.as_ref()
 799    }
 800
 801    /// Get the current keyboard mapper.
 802    pub fn keyboard_mapper(&self) -> &Rc<dyn PlatformKeyboardMapper> {
 803        &self.keyboard_mapper
 804    }
 805
 806    /// Invokes a handler when the current keyboard layout changes
 807    pub fn on_keyboard_layout_change<F>(&self, mut callback: F) -> Subscription
 808    where
 809        F: 'static + FnMut(&mut App),
 810    {
 811        let (subscription, activate) = self.keyboard_layout_observers.insert(
 812            (),
 813            Box::new(move |cx| {
 814                callback(cx);
 815                true
 816            }),
 817        );
 818        activate();
 819        subscription
 820    }
 821
 822    /// Gracefully quit the application via the platform's standard routine.
 823    pub fn quit(&self) {
 824        self.platform.quit();
 825    }
 826
 827    /// Schedules all windows in the application to be redrawn. This can be called
 828    /// multiple times in an update cycle and still result in a single redraw.
 829    pub fn refresh_windows(&mut self) {
 830        self.pending_effects.push_back(Effect::RefreshWindows);
 831    }
 832
 833    pub(crate) fn update<R>(&mut self, update: impl FnOnce(&mut Self) -> R) -> R {
 834        self.start_update();
 835        let result = update(self);
 836        self.finish_update();
 837        result
 838    }
 839
 840    pub(crate) fn start_update(&mut self) {
 841        self.pending_updates += 1;
 842    }
 843
 844    pub(crate) fn finish_update(&mut self) {
 845        if !self.flushing_effects && self.pending_updates == 1 {
 846            self.flushing_effects = true;
 847            self.flush_effects();
 848            self.flushing_effects = false;
 849        }
 850        self.pending_updates -= 1;
 851    }
 852
 853    /// Arrange a callback to be invoked when the given entity calls `notify` on its respective context.
 854    pub fn observe<W>(
 855        &mut self,
 856        entity: &Entity<W>,
 857        mut on_notify: impl FnMut(Entity<W>, &mut App) + 'static,
 858    ) -> Subscription
 859    where
 860        W: 'static,
 861    {
 862        self.observe_internal(entity, move |e, cx| {
 863            on_notify(e, cx);
 864            true
 865        })
 866    }
 867
 868    pub(crate) fn detect_accessed_entities<R>(
 869        &mut self,
 870        callback: impl FnOnce(&mut App) -> R,
 871    ) -> (R, FxHashSet<EntityId>) {
 872        let accessed_entities_start = self.entities.accessed_entities.borrow().clone();
 873        let result = callback(self);
 874        let accessed_entities_end = self.entities.accessed_entities.borrow().clone();
 875        let entities_accessed_in_callback = accessed_entities_end
 876            .difference(&accessed_entities_start)
 877            .copied()
 878            .collect::<FxHashSet<EntityId>>();
 879        (result, entities_accessed_in_callback)
 880    }
 881
 882    pub(crate) fn record_entities_accessed(
 883        &mut self,
 884        window_handle: AnyWindowHandle,
 885        invalidator: WindowInvalidator,
 886        entities: &FxHashSet<EntityId>,
 887    ) {
 888        let mut tracked_entities =
 889            std::mem::take(self.tracked_entities.entry(window_handle.id).or_default());
 890        for entity in tracked_entities.iter() {
 891            self.window_invalidators_by_entity
 892                .entry(*entity)
 893                .and_modify(|windows| {
 894                    windows.remove(&window_handle.id);
 895                });
 896        }
 897        for entity in entities.iter() {
 898            self.window_invalidators_by_entity
 899                .entry(*entity)
 900                .or_default()
 901                .insert(window_handle.id, invalidator.clone());
 902        }
 903        tracked_entities.clear();
 904        tracked_entities.extend(entities.iter().copied());
 905        self.tracked_entities
 906            .insert(window_handle.id, tracked_entities);
 907    }
 908
 909    pub(crate) fn new_observer(&mut self, key: EntityId, value: Handler) -> Subscription {
 910        let (subscription, activate) = self.observers.insert(key, value);
 911        self.defer(move |_| activate());
 912        subscription
 913    }
 914
 915    pub(crate) fn observe_internal<W>(
 916        &mut self,
 917        entity: &Entity<W>,
 918        mut on_notify: impl FnMut(Entity<W>, &mut App) -> bool + 'static,
 919    ) -> Subscription
 920    where
 921        W: 'static,
 922    {
 923        let entity_id = entity.entity_id();
 924        let handle = entity.downgrade();
 925        self.new_observer(
 926            entity_id,
 927            Box::new(move |cx| {
 928                if let Some(entity) = handle.upgrade() {
 929                    on_notify(entity, cx)
 930                } else {
 931                    false
 932                }
 933            }),
 934        )
 935    }
 936
 937    /// Arrange for the given callback to be invoked whenever the given entity emits an event of a given type.
 938    /// The callback is provided a handle to the emitting entity and a reference to the emitted event.
 939    pub fn subscribe<T, Event>(
 940        &mut self,
 941        entity: &Entity<T>,
 942        mut on_event: impl FnMut(Entity<T>, &Event, &mut App) + 'static,
 943    ) -> Subscription
 944    where
 945        T: 'static + EventEmitter<Event>,
 946        Event: 'static,
 947    {
 948        self.subscribe_internal(entity, move |entity, event, cx| {
 949            on_event(entity, event, cx);
 950            true
 951        })
 952    }
 953
 954    pub(crate) fn new_subscription(
 955        &mut self,
 956        key: EntityId,
 957        value: (TypeId, Listener),
 958    ) -> Subscription {
 959        let (subscription, activate) = self.event_listeners.insert(key, value);
 960        self.defer(move |_| activate());
 961        subscription
 962    }
 963    pub(crate) fn subscribe_internal<T, Evt>(
 964        &mut self,
 965        entity: &Entity<T>,
 966        mut on_event: impl FnMut(Entity<T>, &Evt, &mut App) -> bool + 'static,
 967    ) -> Subscription
 968    where
 969        T: 'static + EventEmitter<Evt>,
 970        Evt: 'static,
 971    {
 972        let entity_id = entity.entity_id();
 973        let handle = entity.downgrade();
 974        self.new_subscription(
 975            entity_id,
 976            (
 977                TypeId::of::<Evt>(),
 978                Box::new(move |event, cx| {
 979                    let event: &Evt = event.downcast_ref().expect("invalid event type");
 980                    if let Some(entity) = handle.upgrade() {
 981                        on_event(entity, event, cx)
 982                    } else {
 983                        false
 984                    }
 985                }),
 986            ),
 987        )
 988    }
 989
 990    /// Returns handles to all open windows in the application.
 991    /// Each handle could be downcast to a handle typed for the root view of that window.
 992    /// To find all windows of a given type, you could filter on
 993    pub fn windows(&self) -> Vec<AnyWindowHandle> {
 994        self.windows
 995            .keys()
 996            .flat_map(|window_id| self.window_handles.get(&window_id).copied())
 997            .collect()
 998    }
 999
1000    /// Returns the window handles ordered by their appearance on screen, front to back.
1001    ///
1002    /// The first window in the returned list is the active/topmost window of the application.
1003    ///
1004    /// This method returns None if the platform doesn't implement the method yet.
1005    pub fn window_stack(&self) -> Option<Vec<AnyWindowHandle>> {
1006        self.platform.window_stack()
1007    }
1008
1009    /// Returns a handle to the window that is currently focused at the platform level, if one exists.
1010    pub fn active_window(&self) -> Option<AnyWindowHandle> {
1011        self.platform.active_window()
1012    }
1013
1014    /// Opens a new window with the given option and the root view returned by the given function.
1015    /// The function is invoked with a `Window`, which can be used to interact with window-specific
1016    /// functionality.
1017    pub fn open_window<V: 'static + Render>(
1018        &mut self,
1019        options: crate::WindowOptions,
1020        build_root_view: impl FnOnce(&mut Window, &mut App) -> Entity<V>,
1021    ) -> anyhow::Result<WindowHandle<V>> {
1022        self.update(|cx| {
1023            let id = cx.windows.insert(None);
1024            let handle = WindowHandle::new(id);
1025            match Window::new(handle.into(), options, cx) {
1026                Ok(mut window) => {
1027                    cx.window_update_stack.push(id);
1028                    let root_view = build_root_view(&mut window, cx);
1029                    cx.window_update_stack.pop();
1030                    window.root.replace(root_view.into());
1031                    window.defer(cx, |window: &mut Window, cx| window.appearance_changed(cx));
1032
1033                    // allow a window to draw at least once before returning
1034                    // this didn't cause any issues on non windows platforms as it seems we always won the race to on_request_frame
1035                    // on windows we quite frequently lose the race and return a window that has never rendered, which leads to a crash
1036                    // where DispatchTree::root_node_id asserts on empty nodes
1037                    let clear = window.draw(cx);
1038                    clear.clear();
1039
1040                    cx.window_handles.insert(id, window.handle);
1041                    cx.windows.get_mut(id).unwrap().replace(Box::new(window));
1042                    Ok(handle)
1043                }
1044                Err(e) => {
1045                    cx.windows.remove(id);
1046                    Err(e)
1047                }
1048            }
1049        })
1050    }
1051
1052    /// Instructs the platform to activate the application by bringing it to the foreground.
1053    pub fn activate(&self, ignoring_other_apps: bool) {
1054        self.platform.activate(ignoring_other_apps);
1055    }
1056
1057    /// Hide the application at the platform level.
1058    pub fn hide(&self) {
1059        self.platform.hide();
1060    }
1061
1062    /// Hide other applications at the platform level.
1063    pub fn hide_other_apps(&self) {
1064        self.platform.hide_other_apps();
1065    }
1066
1067    /// Unhide other applications at the platform level.
1068    pub fn unhide_other_apps(&self) {
1069        self.platform.unhide_other_apps();
1070    }
1071
1072    /// Returns the list of currently active displays.
1073    pub fn displays(&self) -> Vec<Rc<dyn PlatformDisplay>> {
1074        self.platform.displays()
1075    }
1076
1077    /// Returns the primary display that will be used for new windows.
1078    pub fn primary_display(&self) -> Option<Rc<dyn PlatformDisplay>> {
1079        self.platform.primary_display()
1080    }
1081
1082    /// Returns whether `screen_capture_sources` may work.
1083    pub fn is_screen_capture_supported(&self) -> bool {
1084        self.platform.is_screen_capture_supported()
1085    }
1086
1087    /// Returns a list of available screen capture sources.
1088    pub fn screen_capture_sources(
1089        &self,
1090    ) -> oneshot::Receiver<Result<Vec<Rc<dyn ScreenCaptureSource>>>> {
1091        self.platform.screen_capture_sources()
1092    }
1093
1094    /// Returns the display with the given ID, if one exists.
1095    pub fn find_display(&self, id: DisplayId) -> Option<Rc<dyn PlatformDisplay>> {
1096        self.displays()
1097            .iter()
1098            .find(|display| display.id() == id)
1099            .cloned()
1100    }
1101
1102    /// Returns the current thermal state of the system.
1103    pub fn thermal_state(&self) -> ThermalState {
1104        self.platform.thermal_state()
1105    }
1106
1107    /// Invokes a handler when the thermal state changes
1108    pub fn on_thermal_state_change<F>(&self, mut callback: F) -> Subscription
1109    where
1110        F: 'static + FnMut(&mut App),
1111    {
1112        let (subscription, activate) = self.thermal_state_observers.insert(
1113            (),
1114            Box::new(move |cx| {
1115                callback(cx);
1116                true
1117            }),
1118        );
1119        activate();
1120        subscription
1121    }
1122
1123    /// Returns the appearance of the application's windows.
1124    pub fn window_appearance(&self) -> WindowAppearance {
1125        self.platform.window_appearance()
1126    }
1127
1128    /// Reads data from the platform clipboard.
1129    pub fn read_from_clipboard(&self) -> Option<ClipboardItem> {
1130        self.platform.read_from_clipboard()
1131    }
1132
1133    /// Sets the text rendering mode for the application.
1134    pub fn set_text_rendering_mode(&mut self, mode: TextRenderingMode) {
1135        self.text_rendering_mode.set(mode);
1136    }
1137
1138    /// Returns the current text rendering mode for the application.
1139    pub fn text_rendering_mode(&self) -> TextRenderingMode {
1140        self.text_rendering_mode.get()
1141    }
1142
1143    /// Writes data to the platform clipboard.
1144    pub fn write_to_clipboard(&self, item: ClipboardItem) {
1145        self.platform.write_to_clipboard(item)
1146    }
1147
1148    /// Reads data from the primary selection buffer.
1149    /// Only available on Linux.
1150    #[cfg(any(target_os = "linux", target_os = "freebsd"))]
1151    pub fn read_from_primary(&self) -> Option<ClipboardItem> {
1152        self.platform.read_from_primary()
1153    }
1154
1155    /// Writes data to the primary selection buffer.
1156    /// Only available on Linux.
1157    #[cfg(any(target_os = "linux", target_os = "freebsd"))]
1158    pub fn write_to_primary(&self, item: ClipboardItem) {
1159        self.platform.write_to_primary(item)
1160    }
1161
1162    /// Reads data from macOS's "Find" pasteboard.
1163    ///
1164    /// Used to share the current search string between apps.
1165    ///
1166    /// https://developer.apple.com/documentation/appkit/nspasteboard/name-swift.struct/find
1167    #[cfg(target_os = "macos")]
1168    pub fn read_from_find_pasteboard(&self) -> Option<ClipboardItem> {
1169        self.platform.read_from_find_pasteboard()
1170    }
1171
1172    /// Writes data to macOS's "Find" pasteboard.
1173    ///
1174    /// Used to share the current search string between apps.
1175    ///
1176    /// https://developer.apple.com/documentation/appkit/nspasteboard/name-swift.struct/find
1177    #[cfg(target_os = "macos")]
1178    pub fn write_to_find_pasteboard(&self, item: ClipboardItem) {
1179        self.platform.write_to_find_pasteboard(item)
1180    }
1181
1182    /// Writes credentials to the platform keychain.
1183    pub fn write_credentials(
1184        &self,
1185        url: &str,
1186        username: &str,
1187        password: &[u8],
1188    ) -> Task<Result<()>> {
1189        self.platform.write_credentials(url, username, password)
1190    }
1191
1192    /// Reads credentials from the platform keychain.
1193    pub fn read_credentials(&self, url: &str) -> Task<Result<Option<(String, Vec<u8>)>>> {
1194        self.platform.read_credentials(url)
1195    }
1196
1197    /// Deletes credentials from the platform keychain.
1198    pub fn delete_credentials(&self, url: &str) -> Task<Result<()>> {
1199        self.platform.delete_credentials(url)
1200    }
1201
1202    /// Directs the platform's default browser to open the given URL.
1203    pub fn open_url(&self, url: &str) {
1204        self.platform.open_url(url);
1205    }
1206
1207    /// Registers the given URL scheme (e.g. `zed` for `zed://` urls) to be
1208    /// opened by the current app.
1209    ///
1210    /// On some platforms (e.g. macOS) you may be able to register URL schemes
1211    /// as part of app distribution, but this method exists to let you register
1212    /// schemes at runtime.
1213    pub fn register_url_scheme(&self, scheme: &str) -> Task<Result<()>> {
1214        self.platform.register_url_scheme(scheme)
1215    }
1216
1217    /// Returns the full pathname of the current app bundle.
1218    ///
1219    /// Returns an error if the app is not being run from a bundle.
1220    pub fn app_path(&self) -> Result<PathBuf> {
1221        self.platform.app_path()
1222    }
1223
1224    /// On Linux, returns the name of the compositor in use.
1225    ///
1226    /// Returns an empty string on other platforms.
1227    pub fn compositor_name(&self) -> &'static str {
1228        self.platform.compositor_name()
1229    }
1230
1231    /// Returns the file URL of the executable with the specified name in the application bundle
1232    pub fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf> {
1233        self.platform.path_for_auxiliary_executable(name)
1234    }
1235
1236    /// Displays a platform modal for selecting paths.
1237    ///
1238    /// When one or more paths are selected, they'll be relayed asynchronously via the returned oneshot channel.
1239    /// If cancelled, a `None` will be relayed instead.
1240    /// May return an error on Linux if the file picker couldn't be opened.
1241    pub fn prompt_for_paths(
1242        &self,
1243        options: PathPromptOptions,
1244    ) -> oneshot::Receiver<Result<Option<Vec<PathBuf>>>> {
1245        self.platform.prompt_for_paths(options)
1246    }
1247
1248    /// Displays a platform modal for selecting a new path where a file can be saved.
1249    ///
1250    /// The provided directory will be used to set the initial location.
1251    /// When a path is selected, it is relayed asynchronously via the returned oneshot channel.
1252    /// If cancelled, a `None` will be relayed instead.
1253    /// May return an error on Linux if the file picker couldn't be opened.
1254    pub fn prompt_for_new_path(
1255        &self,
1256        directory: &Path,
1257        suggested_name: Option<&str>,
1258    ) -> oneshot::Receiver<Result<Option<PathBuf>>> {
1259        self.platform.prompt_for_new_path(directory, suggested_name)
1260    }
1261
1262    /// Reveals the specified path at the platform level, such as in Finder on macOS.
1263    pub fn reveal_path(&self, path: &Path) {
1264        self.platform.reveal_path(path)
1265    }
1266
1267    /// Opens the specified path with the system's default application.
1268    pub fn open_with_system(&self, path: &Path) {
1269        self.platform.open_with_system(path)
1270    }
1271
1272    /// Returns whether the user has configured scrollbars to auto-hide at the platform level.
1273    pub fn should_auto_hide_scrollbars(&self) -> bool {
1274        self.platform.should_auto_hide_scrollbars()
1275    }
1276
1277    /// Restarts the application.
1278    pub fn restart(&mut self) {
1279        self.restart_observers
1280            .clone()
1281            .retain(&(), |observer| observer(self));
1282        self.platform.restart(self.restart_path.take())
1283    }
1284
1285    /// Sets the path to use when restarting the application.
1286    pub fn set_restart_path(&mut self, path: PathBuf) {
1287        self.restart_path = Some(path);
1288    }
1289
1290    /// Returns the HTTP client for the application.
1291    pub fn http_client(&self) -> Arc<dyn HttpClient> {
1292        self.http_client.clone()
1293    }
1294
1295    /// Sets the HTTP client for the application.
1296    pub fn set_http_client(&mut self, new_client: Arc<dyn HttpClient>) {
1297        self.http_client = new_client;
1298    }
1299
1300    /// Configures when the application should automatically quit.
1301    /// By default, [`QuitMode::Default`] is used.
1302    pub fn set_quit_mode(&mut self, mode: QuitMode) {
1303        self.quit_mode = mode;
1304    }
1305
1306    /// Returns the SVG renderer used by the application.
1307    pub fn svg_renderer(&self) -> SvgRenderer {
1308        self.svg_renderer.clone()
1309    }
1310
1311    pub(crate) fn push_effect(&mut self, effect: Effect) {
1312        match &effect {
1313            Effect::Notify { emitter } => {
1314                if !self.pending_notifications.insert(*emitter) {
1315                    return;
1316                }
1317            }
1318            Effect::NotifyGlobalObservers { global_type } => {
1319                if !self.pending_global_notifications.insert(*global_type) {
1320                    return;
1321                }
1322            }
1323            _ => {}
1324        };
1325
1326        self.pending_effects.push_back(effect);
1327    }
1328
1329    /// Called at the end of [`App::update`] to complete any side effects
1330    /// such as notifying observers, emitting events, etc. Effects can themselves
1331    /// cause effects, so we continue looping until all effects are processed.
1332    fn flush_effects(&mut self) {
1333        loop {
1334            self.release_dropped_entities();
1335            self.release_dropped_focus_handles();
1336            if let Some(effect) = self.pending_effects.pop_front() {
1337                match effect {
1338                    Effect::Notify { emitter } => {
1339                        self.apply_notify_effect(emitter);
1340                    }
1341
1342                    Effect::Emit {
1343                        emitter,
1344                        event_type,
1345                        event,
1346                    } => self.apply_emit_effect(emitter, event_type, &*event),
1347
1348                    Effect::RefreshWindows => {
1349                        self.apply_refresh_effect();
1350                    }
1351
1352                    Effect::NotifyGlobalObservers { global_type } => {
1353                        self.apply_notify_global_observers_effect(global_type);
1354                    }
1355
1356                    Effect::Defer { callback } => {
1357                        self.apply_defer_effect(callback);
1358                    }
1359                    Effect::EntityCreated {
1360                        entity,
1361                        tid,
1362                        window,
1363                    } => {
1364                        self.apply_entity_created_effect(entity, tid, window);
1365                    }
1366                }
1367            } else {
1368                #[cfg(any(test, feature = "test-support"))]
1369                for window in self
1370                    .windows
1371                    .values()
1372                    .filter_map(|window| {
1373                        let window = window.as_deref()?;
1374                        window.invalidator.is_dirty().then_some(window.handle)
1375                    })
1376                    .collect::<Vec<_>>()
1377                {
1378                    self.update_window(window, |_, window, cx| window.draw(cx).clear())
1379                        .unwrap();
1380                }
1381
1382                if self.pending_effects.is_empty() {
1383                    self.event_arena.clear();
1384                    break;
1385                }
1386            }
1387        }
1388    }
1389
1390    /// Repeatedly called during `flush_effects` to release any entities whose
1391    /// reference count has become zero. We invoke any release observers before dropping
1392    /// each entity.
1393    fn release_dropped_entities(&mut self) {
1394        loop {
1395            let dropped = self.entities.take_dropped();
1396            if dropped.is_empty() {
1397                break;
1398            }
1399
1400            for (entity_id, mut entity) in dropped {
1401                self.observers.remove(&entity_id);
1402                self.event_listeners.remove(&entity_id);
1403                for release_callback in self.release_listeners.remove(&entity_id) {
1404                    release_callback(entity.as_mut(), self);
1405                }
1406            }
1407        }
1408    }
1409
1410    /// Repeatedly called during `flush_effects` to handle a focused handle being dropped.
1411    fn release_dropped_focus_handles(&mut self) {
1412        self.focus_handles
1413            .clone()
1414            .write()
1415            .retain(|handle_id, focus| {
1416                if focus.ref_count.load(SeqCst) == 0 {
1417                    for window_handle in self.windows() {
1418                        window_handle
1419                            .update(self, |_, window, _| {
1420                                if window.focus == Some(handle_id) {
1421                                    window.blur();
1422                                }
1423                            })
1424                            .unwrap();
1425                    }
1426                    false
1427                } else {
1428                    true
1429                }
1430            });
1431    }
1432
1433    fn apply_notify_effect(&mut self, emitter: EntityId) {
1434        self.pending_notifications.remove(&emitter);
1435
1436        self.observers
1437            .clone()
1438            .retain(&emitter, |handler| handler(self));
1439    }
1440
1441    fn apply_emit_effect(&mut self, emitter: EntityId, event_type: TypeId, event: &dyn Any) {
1442        self.event_listeners
1443            .clone()
1444            .retain(&emitter, |(stored_type, handler)| {
1445                if *stored_type == event_type {
1446                    handler(event, self)
1447                } else {
1448                    true
1449                }
1450            });
1451    }
1452
1453    fn apply_refresh_effect(&mut self) {
1454        for window in self.windows.values_mut() {
1455            if let Some(window) = window.as_deref_mut() {
1456                window.refreshing = true;
1457                window.invalidator.set_dirty(true);
1458            }
1459        }
1460    }
1461
1462    fn apply_notify_global_observers_effect(&mut self, type_id: TypeId) {
1463        self.pending_global_notifications.remove(&type_id);
1464        self.global_observers
1465            .clone()
1466            .retain(&type_id, |observer| observer(self));
1467    }
1468
1469    fn apply_defer_effect(&mut self, callback: Box<dyn FnOnce(&mut Self) + 'static>) {
1470        callback(self);
1471    }
1472
1473    fn apply_entity_created_effect(
1474        &mut self,
1475        entity: AnyEntity,
1476        tid: TypeId,
1477        window: Option<WindowId>,
1478    ) {
1479        self.new_entity_observers.clone().retain(&tid, |observer| {
1480            if let Some(id) = window {
1481                self.update_window_id(id, {
1482                    let entity = entity.clone();
1483                    |_, window, cx| (observer)(entity, &mut Some(window), cx)
1484                })
1485                .expect("All windows should be off the stack when flushing effects");
1486            } else {
1487                (observer)(entity.clone(), &mut None, self)
1488            }
1489            true
1490        });
1491    }
1492
1493    fn update_window_id<T, F>(&mut self, id: WindowId, update: F) -> Result<T>
1494    where
1495        F: FnOnce(AnyView, &mut Window, &mut App) -> T,
1496    {
1497        self.update(|cx| {
1498            let mut window = cx.windows.get_mut(id)?.take()?;
1499
1500            let root_view = window.root.clone().unwrap();
1501
1502            cx.window_update_stack.push(window.handle.id);
1503            let result = update(root_view, &mut window, cx);
1504            fn trail(id: WindowId, window: Box<Window>, cx: &mut App) -> Option<()> {
1505                cx.window_update_stack.pop();
1506
1507                if window.removed {
1508                    cx.window_handles.remove(&id);
1509                    cx.windows.remove(id);
1510
1511                    cx.window_closed_observers.clone().retain(&(), |callback| {
1512                        callback(cx);
1513                        true
1514                    });
1515
1516                    let quit_on_empty = match cx.quit_mode {
1517                        QuitMode::Explicit => false,
1518                        QuitMode::LastWindowClosed => true,
1519                        QuitMode::Default => cfg!(not(target_os = "macos")),
1520                    };
1521
1522                    if quit_on_empty && cx.windows.is_empty() {
1523                        cx.quit();
1524                    }
1525                } else {
1526                    cx.windows.get_mut(id)?.replace(window);
1527                }
1528                Some(())
1529            }
1530            trail(id, window, cx)?;
1531
1532            Some(result)
1533        })
1534        .context("window not found")
1535    }
1536
1537    /// Creates an `AsyncApp`, which can be cloned and has a static lifetime
1538    /// so it can be held across `await` points.
1539    pub fn to_async(&self) -> AsyncApp {
1540        AsyncApp {
1541            app: self.this.clone(),
1542            background_executor: self.background_executor.clone(),
1543            foreground_executor: self.foreground_executor.clone(),
1544        }
1545    }
1546
1547    /// Obtains a reference to the executor, which can be used to spawn futures.
1548    pub fn background_executor(&self) -> &BackgroundExecutor {
1549        &self.background_executor
1550    }
1551
1552    /// Obtains a reference to the executor, which can be used to spawn futures.
1553    pub fn foreground_executor(&self) -> &ForegroundExecutor {
1554        if self.quitting {
1555            panic!("Can't spawn on main thread after on_app_quit")
1556        };
1557        &self.foreground_executor
1558    }
1559
1560    /// Spawns the future returned by the given function on the main thread. The closure will be invoked
1561    /// with [AsyncApp], which allows the application state to be accessed across await points.
1562    #[track_caller]
1563    pub fn spawn<AsyncFn, R>(&self, f: AsyncFn) -> Task<R>
1564    where
1565        AsyncFn: AsyncFnOnce(&mut AsyncApp) -> R + 'static,
1566        R: 'static,
1567    {
1568        if self.quitting {
1569            debug_panic!("Can't spawn on main thread after on_app_quit")
1570        };
1571
1572        let mut cx = self.to_async();
1573
1574        self.foreground_executor
1575            .spawn(async move { f(&mut cx).await }.boxed_local())
1576    }
1577
1578    /// Spawns the future returned by the given function on the main thread with
1579    /// the given priority. The closure will be invoked with [AsyncApp], which
1580    /// allows the application state to be accessed across await points.
1581    pub fn spawn_with_priority<AsyncFn, R>(&self, priority: Priority, f: AsyncFn) -> Task<R>
1582    where
1583        AsyncFn: AsyncFnOnce(&mut AsyncApp) -> R + 'static,
1584        R: 'static,
1585    {
1586        if self.quitting {
1587            debug_panic!("Can't spawn on main thread after on_app_quit")
1588        };
1589
1590        let mut cx = self.to_async();
1591
1592        self.foreground_executor
1593            .spawn_with_priority(priority, async move { f(&mut cx).await }.boxed_local())
1594    }
1595
1596    /// Schedules the given function to be run at the end of the current effect cycle, allowing entities
1597    /// that are currently on the stack to be returned to the app.
1598    pub fn defer(&mut self, f: impl FnOnce(&mut App) + 'static) {
1599        self.push_effect(Effect::Defer {
1600            callback: Box::new(f),
1601        });
1602    }
1603
1604    /// Accessor for the application's asset source, which is provided when constructing the `App`.
1605    pub fn asset_source(&self) -> &Arc<dyn AssetSource> {
1606        &self.asset_source
1607    }
1608
1609    /// Accessor for the text system.
1610    pub fn text_system(&self) -> &Arc<TextSystem> {
1611        &self.text_system
1612    }
1613
1614    /// Check whether a global of the given type has been assigned.
1615    pub fn has_global<G: Global>(&self) -> bool {
1616        self.globals_by_type.contains_key(&TypeId::of::<G>())
1617    }
1618
1619    /// Access the global of the given type. Panics if a global for that type has not been assigned.
1620    #[track_caller]
1621    pub fn global<G: Global>(&self) -> &G {
1622        self.globals_by_type
1623            .get(&TypeId::of::<G>())
1624            .map(|any_state| any_state.downcast_ref::<G>().unwrap())
1625            .with_context(|| format!("no state of type {} exists", type_name::<G>()))
1626            .unwrap()
1627    }
1628
1629    /// Access the global of the given type if a value has been assigned.
1630    pub fn try_global<G: Global>(&self) -> Option<&G> {
1631        self.globals_by_type
1632            .get(&TypeId::of::<G>())
1633            .map(|any_state| any_state.downcast_ref::<G>().unwrap())
1634    }
1635
1636    /// Access the global of the given type mutably. Panics if a global for that type has not been assigned.
1637    #[track_caller]
1638    pub fn global_mut<G: Global>(&mut self) -> &mut G {
1639        let global_type = TypeId::of::<G>();
1640        self.push_effect(Effect::NotifyGlobalObservers { global_type });
1641        self.globals_by_type
1642            .get_mut(&global_type)
1643            .and_then(|any_state| any_state.downcast_mut::<G>())
1644            .with_context(|| format!("no state of type {} exists", type_name::<G>()))
1645            .unwrap()
1646    }
1647
1648    /// Access the global of the given type mutably. A default value is assigned if a global of this type has not
1649    /// yet been assigned.
1650    pub fn default_global<G: Global + Default>(&mut self) -> &mut G {
1651        let global_type = TypeId::of::<G>();
1652        self.push_effect(Effect::NotifyGlobalObservers { global_type });
1653        self.globals_by_type
1654            .entry(global_type)
1655            .or_insert_with(|| Box::<G>::default())
1656            .downcast_mut::<G>()
1657            .unwrap()
1658    }
1659
1660    /// Sets the value of the global of the given type.
1661    pub fn set_global<G: Global>(&mut self, global: G) {
1662        let global_type = TypeId::of::<G>();
1663        self.push_effect(Effect::NotifyGlobalObservers { global_type });
1664        self.globals_by_type.insert(global_type, Box::new(global));
1665    }
1666
1667    /// Clear all stored globals. Does not notify global observers.
1668    #[cfg(any(test, feature = "test-support"))]
1669    pub fn clear_globals(&mut self) {
1670        self.globals_by_type.drain();
1671    }
1672
1673    /// Remove the global of the given type from the app context. Does not notify global observers.
1674    pub fn remove_global<G: Global>(&mut self) -> G {
1675        let global_type = TypeId::of::<G>();
1676        self.push_effect(Effect::NotifyGlobalObservers { global_type });
1677        *self
1678            .globals_by_type
1679            .remove(&global_type)
1680            .unwrap_or_else(|| panic!("no global added for {}", std::any::type_name::<G>()))
1681            .downcast()
1682            .unwrap()
1683    }
1684
1685    /// Register a callback to be invoked when a global of the given type is updated.
1686    pub fn observe_global<G: Global>(
1687        &mut self,
1688        mut f: impl FnMut(&mut Self) + 'static,
1689    ) -> Subscription {
1690        let (subscription, activate) = self.global_observers.insert(
1691            TypeId::of::<G>(),
1692            Box::new(move |cx| {
1693                f(cx);
1694                true
1695            }),
1696        );
1697        self.defer(move |_| activate());
1698        subscription
1699    }
1700
1701    /// Move the global of the given type to the stack.
1702    #[track_caller]
1703    pub(crate) fn lease_global<G: Global>(&mut self) -> GlobalLease<G> {
1704        GlobalLease::new(
1705            self.globals_by_type
1706                .remove(&TypeId::of::<G>())
1707                .with_context(|| format!("no global registered of type {}", type_name::<G>()))
1708                .unwrap(),
1709        )
1710    }
1711
1712    /// Restore the global of the given type after it is moved to the stack.
1713    pub(crate) fn end_global_lease<G: Global>(&mut self, lease: GlobalLease<G>) {
1714        let global_type = TypeId::of::<G>();
1715
1716        self.push_effect(Effect::NotifyGlobalObservers { global_type });
1717        self.globals_by_type.insert(global_type, lease.global);
1718    }
1719
1720    pub(crate) fn new_entity_observer(
1721        &self,
1722        key: TypeId,
1723        value: NewEntityListener,
1724    ) -> Subscription {
1725        let (subscription, activate) = self.new_entity_observers.insert(key, value);
1726        activate();
1727        subscription
1728    }
1729
1730    /// Arrange for the given function to be invoked whenever a view of the specified type is created.
1731    /// The function will be passed a mutable reference to the view along with an appropriate context.
1732    pub fn observe_new<T: 'static>(
1733        &self,
1734        on_new: impl 'static + Fn(&mut T, Option<&mut Window>, &mut Context<T>),
1735    ) -> Subscription {
1736        self.new_entity_observer(
1737            TypeId::of::<T>(),
1738            Box::new(
1739                move |any_entity: AnyEntity, window: &mut Option<&mut Window>, cx: &mut App| {
1740                    any_entity
1741                        .downcast::<T>()
1742                        .unwrap()
1743                        .update(cx, |entity_state, cx| {
1744                            on_new(entity_state, window.as_deref_mut(), cx)
1745                        })
1746                },
1747            ),
1748        )
1749    }
1750
1751    /// Observe the release of a entity. The callback is invoked after the entity
1752    /// has no more strong references but before it has been dropped.
1753    pub fn observe_release<T>(
1754        &self,
1755        handle: &Entity<T>,
1756        on_release: impl FnOnce(&mut T, &mut App) + 'static,
1757    ) -> Subscription
1758    where
1759        T: 'static,
1760    {
1761        let (subscription, activate) = self.release_listeners.insert(
1762            handle.entity_id(),
1763            Box::new(move |entity, cx| {
1764                let entity = entity.downcast_mut().expect("invalid entity type");
1765                on_release(entity, cx)
1766            }),
1767        );
1768        activate();
1769        subscription
1770    }
1771
1772    /// Observe the release of a entity. The callback is invoked after the entity
1773    /// has no more strong references but before it has been dropped.
1774    pub fn observe_release_in<T>(
1775        &self,
1776        handle: &Entity<T>,
1777        window: &Window,
1778        on_release: impl FnOnce(&mut T, &mut Window, &mut App) + 'static,
1779    ) -> Subscription
1780    where
1781        T: 'static,
1782    {
1783        let window_handle = window.handle;
1784        self.observe_release(handle, move |entity, cx| {
1785            let _ = window_handle.update(cx, |_, window, cx| on_release(entity, window, cx));
1786        })
1787    }
1788
1789    /// Register a callback to be invoked when a keystroke is received by the application
1790    /// in any window. Note that this fires after all other action and event mechanisms have resolved
1791    /// and that this API will not be invoked if the event's propagation is stopped.
1792    pub fn observe_keystrokes(
1793        &mut self,
1794        mut f: impl FnMut(&KeystrokeEvent, &mut Window, &mut App) + 'static,
1795    ) -> Subscription {
1796        fn inner(
1797            keystroke_observers: &SubscriberSet<(), KeystrokeObserver>,
1798            handler: KeystrokeObserver,
1799        ) -> Subscription {
1800            let (subscription, activate) = keystroke_observers.insert((), handler);
1801            activate();
1802            subscription
1803        }
1804
1805        inner(
1806            &self.keystroke_observers,
1807            Box::new(move |event, window, cx| {
1808                f(event, window, cx);
1809                true
1810            }),
1811        )
1812    }
1813
1814    /// Register a callback to be invoked when a keystroke is received by the application
1815    /// in any window. Note that this fires _before_ all other action and event mechanisms have resolved
1816    /// unlike [`App::observe_keystrokes`] which fires after. This means that `cx.stop_propagation` calls
1817    /// within interceptors will prevent action dispatch
1818    pub fn intercept_keystrokes(
1819        &mut self,
1820        mut f: impl FnMut(&KeystrokeEvent, &mut Window, &mut App) + 'static,
1821    ) -> Subscription {
1822        fn inner(
1823            keystroke_interceptors: &SubscriberSet<(), KeystrokeObserver>,
1824            handler: KeystrokeObserver,
1825        ) -> Subscription {
1826            let (subscription, activate) = keystroke_interceptors.insert((), handler);
1827            activate();
1828            subscription
1829        }
1830
1831        inner(
1832            &self.keystroke_interceptors,
1833            Box::new(move |event, window, cx| {
1834                f(event, window, cx);
1835                true
1836            }),
1837        )
1838    }
1839
1840    /// Register key bindings.
1841    pub fn bind_keys(&mut self, bindings: impl IntoIterator<Item = KeyBinding>) {
1842        self.keymap.borrow_mut().add_bindings(bindings);
1843        self.pending_effects.push_back(Effect::RefreshWindows);
1844    }
1845
1846    /// Clear all key bindings in the app.
1847    pub fn clear_key_bindings(&mut self) {
1848        self.keymap.borrow_mut().clear();
1849        self.pending_effects.push_back(Effect::RefreshWindows);
1850    }
1851
1852    /// Get all key bindings in the app.
1853    pub fn key_bindings(&self) -> Rc<RefCell<Keymap>> {
1854        self.keymap.clone()
1855    }
1856
1857    /// Register a global handler for actions invoked via the keyboard. These handlers are run at
1858    /// the end of the bubble phase for actions, and so will only be invoked if there are no other
1859    /// handlers or if they called `cx.propagate()`.
1860    pub fn on_action<A: Action>(
1861        &mut self,
1862        listener: impl Fn(&A, &mut Self) + 'static,
1863    ) -> &mut Self {
1864        self.global_action_listeners
1865            .entry(TypeId::of::<A>())
1866            .or_default()
1867            .push(Rc::new(move |action, phase, cx| {
1868                if phase == DispatchPhase::Bubble {
1869                    let action = action.downcast_ref().unwrap();
1870                    listener(action, cx)
1871                }
1872            }));
1873        self
1874    }
1875
1876    /// Event handlers propagate events by default. Call this method to stop dispatching to
1877    /// event handlers with a lower z-index (mouse) or higher in the tree (keyboard). This is
1878    /// the opposite of [`Self::propagate`]. It's also possible to cancel a call to [`Self::propagate`] by
1879    /// calling this method before effects are flushed.
1880    pub fn stop_propagation(&mut self) {
1881        self.propagate_event = false;
1882    }
1883
1884    /// Action handlers stop propagation by default during the bubble phase of action dispatch
1885    /// dispatching to action handlers higher in the element tree. This is the opposite of
1886    /// [`Self::stop_propagation`]. It's also possible to cancel a call to [`Self::stop_propagation`] by calling
1887    /// this method before effects are flushed.
1888    pub fn propagate(&mut self) {
1889        self.propagate_event = true;
1890    }
1891
1892    /// Build an action from some arbitrary data, typically a keymap entry.
1893    pub fn build_action(
1894        &self,
1895        name: &str,
1896        data: Option<serde_json::Value>,
1897    ) -> std::result::Result<Box<dyn Action>, ActionBuildError> {
1898        self.actions.build_action(name, data)
1899    }
1900
1901    /// Get all action names that have been registered. Note that registration only allows for
1902    /// actions to be built dynamically, and is unrelated to binding actions in the element tree.
1903    pub fn all_action_names(&self) -> &[&'static str] {
1904        self.actions.all_action_names()
1905    }
1906
1907    /// Returns key bindings that invoke the given action on the currently focused element, without
1908    /// checking context. Bindings are returned in the order they were added. For display, the last
1909    /// binding should take precedence.
1910    pub fn all_bindings_for_input(&self, input: &[Keystroke]) -> Vec<KeyBinding> {
1911        RefCell::borrow(&self.keymap).all_bindings_for_input(input)
1912    }
1913
1914    /// Get all non-internal actions that have been registered, along with their schemas.
1915    pub fn action_schemas(
1916        &self,
1917        generator: &mut schemars::SchemaGenerator,
1918    ) -> Vec<(&'static str, Option<schemars::Schema>)> {
1919        self.actions.action_schemas(generator)
1920    }
1921
1922    /// Get the schema for a specific action by name.
1923    /// Returns `None` if the action is not found.
1924    /// Returns `Some(None)` if the action exists but has no schema.
1925    /// Returns `Some(Some(schema))` if the action exists and has a schema.
1926    pub fn action_schema_by_name(
1927        &self,
1928        name: &str,
1929        generator: &mut schemars::SchemaGenerator,
1930    ) -> Option<Option<schemars::Schema>> {
1931        self.actions.action_schema_by_name(name, generator)
1932    }
1933
1934    /// Get a map from a deprecated action name to the canonical name.
1935    pub fn deprecated_actions_to_preferred_actions(&self) -> &HashMap<&'static str, &'static str> {
1936        self.actions.deprecated_aliases()
1937    }
1938
1939    /// Get a map from an action name to the deprecation messages.
1940    pub fn action_deprecation_messages(&self) -> &HashMap<&'static str, &'static str> {
1941        self.actions.deprecation_messages()
1942    }
1943
1944    /// Get a map from an action name to the documentation.
1945    pub fn action_documentation(&self) -> &HashMap<&'static str, &'static str> {
1946        self.actions.documentation()
1947    }
1948
1949    /// Register a callback to be invoked when the application is about to quit.
1950    /// It is not possible to cancel the quit event at this point.
1951    pub fn on_app_quit<Fut>(
1952        &self,
1953        mut on_quit: impl FnMut(&mut App) -> Fut + 'static,
1954    ) -> Subscription
1955    where
1956        Fut: 'static + Future<Output = ()>,
1957    {
1958        let (subscription, activate) = self.quit_observers.insert(
1959            (),
1960            Box::new(move |cx| {
1961                let future = on_quit(cx);
1962                future.boxed_local()
1963            }),
1964        );
1965        activate();
1966        subscription
1967    }
1968
1969    /// Register a callback to be invoked when the application is about to restart.
1970    ///
1971    /// These callbacks are called before any `on_app_quit` callbacks.
1972    pub fn on_app_restart(&self, mut on_restart: impl 'static + FnMut(&mut App)) -> Subscription {
1973        let (subscription, activate) = self.restart_observers.insert(
1974            (),
1975            Box::new(move |cx| {
1976                on_restart(cx);
1977                true
1978            }),
1979        );
1980        activate();
1981        subscription
1982    }
1983
1984    /// Register a callback to be invoked when a window is closed
1985    /// The window is no longer accessible at the point this callback is invoked.
1986    pub fn on_window_closed(&self, mut on_closed: impl FnMut(&mut App) + 'static) -> Subscription {
1987        let (subscription, activate) = self.window_closed_observers.insert((), Box::new(on_closed));
1988        activate();
1989        subscription
1990    }
1991
1992    pub(crate) fn clear_pending_keystrokes(&mut self) {
1993        for window in self.windows() {
1994            window
1995                .update(self, |_, window, cx| {
1996                    if window.pending_input_keystrokes().is_some() {
1997                        window.clear_pending_keystrokes();
1998                        window.pending_input_changed(cx);
1999                    }
2000                })
2001                .ok();
2002        }
2003    }
2004
2005    /// Checks if the given action is bound in the current context, as defined by the app's current focus,
2006    /// the bindings in the element tree, and any global action listeners.
2007    pub fn is_action_available(&mut self, action: &dyn Action) -> bool {
2008        let mut action_available = false;
2009        if let Some(window) = self.active_window()
2010            && let Ok(window_action_available) =
2011                window.update(self, |_, window, cx| window.is_action_available(action, cx))
2012        {
2013            action_available = window_action_available;
2014        }
2015
2016        action_available
2017            || self
2018                .global_action_listeners
2019                .contains_key(&action.as_any().type_id())
2020    }
2021
2022    /// Sets the menu bar for this application. This will replace any existing menu bar.
2023    pub fn set_menus(&self, menus: Vec<Menu>) {
2024        self.platform.set_menus(menus, &self.keymap.borrow());
2025    }
2026
2027    /// Gets the menu bar for this application.
2028    pub fn get_menus(&self) -> Option<Vec<OwnedMenu>> {
2029        self.platform.get_menus()
2030    }
2031
2032    /// Sets the right click menu for the app icon in the dock
2033    pub fn set_dock_menu(&self, menus: Vec<MenuItem>) {
2034        self.platform.set_dock_menu(menus, &self.keymap.borrow())
2035    }
2036
2037    /// Performs the action associated with the given dock menu item, only used on Windows for now.
2038    pub fn perform_dock_menu_action(&self, action: usize) {
2039        self.platform.perform_dock_menu_action(action);
2040    }
2041
2042    /// Adds given path to the bottom of the list of recent paths for the application.
2043    /// The list is usually shown on the application icon's context menu in the dock,
2044    /// and allows to open the recent files via that context menu.
2045    /// If the path is already in the list, it will be moved to the bottom of the list.
2046    pub fn add_recent_document(&self, path: &Path) {
2047        self.platform.add_recent_document(path);
2048    }
2049
2050    /// Updates the jump list with the updated list of recent paths for the application, only used on Windows for now.
2051    /// Note that this also sets the dock menu on Windows.
2052    pub fn update_jump_list(
2053        &self,
2054        menus: Vec<MenuItem>,
2055        entries: Vec<SmallVec<[PathBuf; 2]>>,
2056    ) -> Task<Vec<SmallVec<[PathBuf; 2]>>> {
2057        self.platform.update_jump_list(menus, entries)
2058    }
2059
2060    /// Dispatch an action to the currently active window or global action handler
2061    /// See [`crate::Action`] for more information on how actions work
2062    pub fn dispatch_action(&mut self, action: &dyn Action) {
2063        if let Some(active_window) = self.active_window() {
2064            active_window
2065                .update(self, |_, window, cx| {
2066                    window.dispatch_action(action.boxed_clone(), cx)
2067                })
2068                .log_err();
2069        } else {
2070            self.dispatch_global_action(action);
2071        }
2072    }
2073
2074    fn dispatch_global_action(&mut self, action: &dyn Action) {
2075        self.propagate_event = true;
2076
2077        if let Some(mut global_listeners) = self
2078            .global_action_listeners
2079            .remove(&action.as_any().type_id())
2080        {
2081            for listener in &global_listeners {
2082                listener(action.as_any(), DispatchPhase::Capture, self);
2083                if !self.propagate_event {
2084                    break;
2085                }
2086            }
2087
2088            global_listeners.extend(
2089                self.global_action_listeners
2090                    .remove(&action.as_any().type_id())
2091                    .unwrap_or_default(),
2092            );
2093
2094            self.global_action_listeners
2095                .insert(action.as_any().type_id(), global_listeners);
2096        }
2097
2098        if self.propagate_event
2099            && let Some(mut global_listeners) = self
2100                .global_action_listeners
2101                .remove(&action.as_any().type_id())
2102        {
2103            for listener in global_listeners.iter().rev() {
2104                listener(action.as_any(), DispatchPhase::Bubble, self);
2105                if !self.propagate_event {
2106                    break;
2107                }
2108            }
2109
2110            global_listeners.extend(
2111                self.global_action_listeners
2112                    .remove(&action.as_any().type_id())
2113                    .unwrap_or_default(),
2114            );
2115
2116            self.global_action_listeners
2117                .insert(action.as_any().type_id(), global_listeners);
2118        }
2119    }
2120
2121    /// Is there currently something being dragged?
2122    pub fn has_active_drag(&self) -> bool {
2123        self.active_drag.is_some()
2124    }
2125
2126    /// Gets the cursor style of the currently active drag operation.
2127    pub fn active_drag_cursor_style(&self) -> Option<CursorStyle> {
2128        self.active_drag.as_ref().and_then(|drag| drag.cursor_style)
2129    }
2130
2131    /// Stops active drag and clears any related effects.
2132    pub fn stop_active_drag(&mut self, window: &mut Window) -> bool {
2133        if self.active_drag.is_some() {
2134            self.active_drag = None;
2135            window.refresh();
2136            true
2137        } else {
2138            false
2139        }
2140    }
2141
2142    /// Sets the cursor style for the currently active drag operation.
2143    pub fn set_active_drag_cursor_style(
2144        &mut self,
2145        cursor_style: CursorStyle,
2146        window: &mut Window,
2147    ) -> bool {
2148        if let Some(ref mut drag) = self.active_drag {
2149            drag.cursor_style = Some(cursor_style);
2150            window.refresh();
2151            true
2152        } else {
2153            false
2154        }
2155    }
2156
2157    /// Set the prompt renderer for GPUI. This will replace the default or platform specific
2158    /// prompts with this custom implementation.
2159    pub fn set_prompt_builder(
2160        &mut self,
2161        renderer: impl Fn(
2162            PromptLevel,
2163            &str,
2164            Option<&str>,
2165            &[PromptButton],
2166            PromptHandle,
2167            &mut Window,
2168            &mut App,
2169        ) -> RenderablePromptHandle
2170        + 'static,
2171    ) {
2172        self.prompt_builder = Some(PromptBuilder::Custom(Box::new(renderer)));
2173    }
2174
2175    /// Reset the prompt builder to the default implementation.
2176    pub fn reset_prompt_builder(&mut self) {
2177        self.prompt_builder = Some(PromptBuilder::Default);
2178    }
2179
2180    /// Remove an asset from GPUI's cache
2181    pub fn remove_asset<A: Asset>(&mut self, source: &A::Source) {
2182        let asset_id = (TypeId::of::<A>(), hash(source));
2183        self.loading_assets.remove(&asset_id);
2184    }
2185
2186    /// Asynchronously load an asset, if the asset hasn't finished loading this will return None.
2187    ///
2188    /// Note that the multiple calls to this method will only result in one `Asset::load` call at a
2189    /// time, and the results of this call will be cached
2190    pub fn fetch_asset<A: Asset>(&mut self, source: &A::Source) -> (Shared<Task<A::Output>>, bool) {
2191        let asset_id = (TypeId::of::<A>(), hash(source));
2192        let mut is_first = false;
2193        let task = self
2194            .loading_assets
2195            .remove(&asset_id)
2196            .map(|boxed_task| *boxed_task.downcast::<Shared<Task<A::Output>>>().unwrap())
2197            .unwrap_or_else(|| {
2198                is_first = true;
2199                let future = A::load(source.clone(), self);
2200
2201                self.background_executor().spawn(future).shared()
2202            });
2203
2204        self.loading_assets.insert(asset_id, Box::new(task.clone()));
2205
2206        (task, is_first)
2207    }
2208
2209    /// Obtain a new [`FocusHandle`], which allows you to track and manipulate the keyboard focus
2210    /// for elements rendered within this window.
2211    #[track_caller]
2212    pub fn focus_handle(&self) -> FocusHandle {
2213        FocusHandle::new(&self.focus_handles)
2214    }
2215
2216    /// Tell GPUI that an entity has changed and observers of it should be notified.
2217    pub fn notify(&mut self, entity_id: EntityId) {
2218        let window_invalidators = mem::take(
2219            self.window_invalidators_by_entity
2220                .entry(entity_id)
2221                .or_default(),
2222        );
2223
2224        if window_invalidators.is_empty() {
2225            if self.pending_notifications.insert(entity_id) {
2226                self.pending_effects
2227                    .push_back(Effect::Notify { emitter: entity_id });
2228            }
2229        } else {
2230            for invalidator in window_invalidators.values() {
2231                invalidator.invalidate_view(entity_id, self);
2232            }
2233        }
2234
2235        self.window_invalidators_by_entity
2236            .insert(entity_id, window_invalidators);
2237    }
2238
2239    /// Returns the name for this [`App`].
2240    #[cfg(any(test, feature = "test-support", debug_assertions))]
2241    pub fn get_name(&self) -> Option<&'static str> {
2242        self.name
2243    }
2244
2245    /// Returns `true` if the platform file picker supports selecting a mix of files and directories.
2246    pub fn can_select_mixed_files_and_dirs(&self) -> bool {
2247        self.platform.can_select_mixed_files_and_dirs()
2248    }
2249
2250    /// Removes an image from the sprite atlas on all windows.
2251    ///
2252    /// If the current window is being updated, it will be removed from `App.windows`, you can use `current_window` to specify the current window.
2253    /// This is a no-op if the image is not in the sprite atlas.
2254    pub fn drop_image(&mut self, image: Arc<RenderImage>, current_window: Option<&mut Window>) {
2255        // remove the texture from all other windows
2256        for window in self.windows.values_mut().flatten() {
2257            _ = window.drop_image(image.clone());
2258        }
2259
2260        // remove the texture from the current window
2261        if let Some(window) = current_window {
2262            _ = window.drop_image(image);
2263        }
2264    }
2265
2266    /// Sets the renderer for the inspector.
2267    #[cfg(any(feature = "inspector", debug_assertions))]
2268    pub fn set_inspector_renderer(&mut self, f: crate::InspectorRenderer) {
2269        self.inspector_renderer = Some(f);
2270    }
2271
2272    /// Registers a renderer specific to an inspector state.
2273    #[cfg(any(feature = "inspector", debug_assertions))]
2274    pub fn register_inspector_element<T: 'static, R: crate::IntoElement>(
2275        &mut self,
2276        f: impl 'static + Fn(crate::InspectorElementId, &T, &mut Window, &mut App) -> R,
2277    ) {
2278        self.inspector_element_registry.register(f);
2279    }
2280
2281    /// Initializes gpui's default colors for the application.
2282    ///
2283    /// These colors can be accessed through `cx.default_colors()`.
2284    pub fn init_colors(&mut self) {
2285        self.set_global(GlobalColors(Arc::new(Colors::default())));
2286    }
2287}
2288
2289impl AppContext for App {
2290    /// Builds an entity that is owned by the application.
2291    ///
2292    /// The given function will be invoked with a [`Context`] and must return an object representing the entity. An
2293    /// [`Entity`] handle will be returned, which can be used to access the entity in a context.
2294    fn new<T: 'static>(&mut self, build_entity: impl FnOnce(&mut Context<T>) -> T) -> Entity<T> {
2295        self.update(|cx| {
2296            let slot = cx.entities.reserve();
2297            let handle = slot.clone();
2298            let entity = build_entity(&mut Context::new_context(cx, slot.downgrade()));
2299
2300            cx.push_effect(Effect::EntityCreated {
2301                entity: handle.clone().into_any(),
2302                tid: TypeId::of::<T>(),
2303                window: cx.window_update_stack.last().cloned(),
2304            });
2305
2306            cx.entities.insert(slot, entity);
2307            handle
2308        })
2309    }
2310
2311    fn reserve_entity<T: 'static>(&mut self) -> Reservation<T> {
2312        Reservation(self.entities.reserve())
2313    }
2314
2315    fn insert_entity<T: 'static>(
2316        &mut self,
2317        reservation: Reservation<T>,
2318        build_entity: impl FnOnce(&mut Context<T>) -> T,
2319    ) -> Entity<T> {
2320        self.update(|cx| {
2321            let slot = reservation.0;
2322            let entity = build_entity(&mut Context::new_context(cx, slot.downgrade()));
2323            cx.entities.insert(slot, entity)
2324        })
2325    }
2326
2327    /// Updates the entity referenced by the given handle. The function is passed a mutable reference to the
2328    /// entity along with a `Context` for the entity.
2329    fn update_entity<T: 'static, R>(
2330        &mut self,
2331        handle: &Entity<T>,
2332        update: impl FnOnce(&mut T, &mut Context<T>) -> R,
2333    ) -> R {
2334        self.update(|cx| {
2335            let mut entity = cx.entities.lease(handle);
2336            let result = update(
2337                &mut entity,
2338                &mut Context::new_context(cx, handle.downgrade()),
2339            );
2340            cx.entities.end_lease(entity);
2341            result
2342        })
2343    }
2344
2345    fn as_mut<'a, T>(&'a mut self, handle: &Entity<T>) -> GpuiBorrow<'a, T>
2346    where
2347        T: 'static,
2348    {
2349        GpuiBorrow::new(handle.clone(), self)
2350    }
2351
2352    fn read_entity<T, R>(&self, handle: &Entity<T>, read: impl FnOnce(&T, &App) -> R) -> R
2353    where
2354        T: 'static,
2355    {
2356        let entity = self.entities.read(handle);
2357        read(entity, self)
2358    }
2359
2360    fn update_window<T, F>(&mut self, handle: AnyWindowHandle, update: F) -> Result<T>
2361    where
2362        F: FnOnce(AnyView, &mut Window, &mut App) -> T,
2363    {
2364        self.update_window_id(handle.id, update)
2365    }
2366
2367    fn read_window<T, R>(
2368        &self,
2369        window: &WindowHandle<T>,
2370        read: impl FnOnce(Entity<T>, &App) -> R,
2371    ) -> Result<R>
2372    where
2373        T: 'static,
2374    {
2375        let window = self
2376            .windows
2377            .get(window.id)
2378            .context("window not found")?
2379            .as_deref()
2380            .expect("attempted to read a window that is already on the stack");
2381
2382        let root_view = window.root.clone().unwrap();
2383        let view = root_view
2384            .downcast::<T>()
2385            .map_err(|_| anyhow!("root view's type has changed"))?;
2386
2387        Ok(read(view, self))
2388    }
2389
2390    fn background_spawn<R>(&self, future: impl Future<Output = R> + Send + 'static) -> Task<R>
2391    where
2392        R: Send + 'static,
2393    {
2394        self.background_executor.spawn(future)
2395    }
2396
2397    fn read_global<G, R>(&self, callback: impl FnOnce(&G, &App) -> R) -> R
2398    where
2399        G: Global,
2400    {
2401        let mut g = self.global::<G>();
2402        callback(g, self)
2403    }
2404}
2405
2406/// These effects are processed at the end of each application update cycle.
2407pub(crate) enum Effect {
2408    Notify {
2409        emitter: EntityId,
2410    },
2411    Emit {
2412        emitter: EntityId,
2413        event_type: TypeId,
2414        event: ArenaBox<dyn Any>,
2415    },
2416    RefreshWindows,
2417    NotifyGlobalObservers {
2418        global_type: TypeId,
2419    },
2420    Defer {
2421        callback: Box<dyn FnOnce(&mut App) + 'static>,
2422    },
2423    EntityCreated {
2424        entity: AnyEntity,
2425        tid: TypeId,
2426        window: Option<WindowId>,
2427    },
2428}
2429
2430impl std::fmt::Debug for Effect {
2431    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2432        match self {
2433            Effect::Notify { emitter } => write!(f, "Notify({})", emitter),
2434            Effect::Emit { emitter, .. } => write!(f, "Emit({:?})", emitter),
2435            Effect::RefreshWindows => write!(f, "RefreshWindows"),
2436            Effect::NotifyGlobalObservers { global_type } => {
2437                write!(f, "NotifyGlobalObservers({:?})", global_type)
2438            }
2439            Effect::Defer { .. } => write!(f, "Defer(..)"),
2440            Effect::EntityCreated { entity, .. } => write!(f, "EntityCreated({:?})", entity),
2441        }
2442    }
2443}
2444
2445/// Wraps a global variable value during `update_global` while the value has been moved to the stack.
2446pub(crate) struct GlobalLease<G: Global> {
2447    global: Box<dyn Any>,
2448    global_type: PhantomData<G>,
2449}
2450
2451impl<G: Global> GlobalLease<G> {
2452    fn new(global: Box<dyn Any>) -> Self {
2453        GlobalLease {
2454            global,
2455            global_type: PhantomData,
2456        }
2457    }
2458}
2459
2460impl<G: Global> Deref for GlobalLease<G> {
2461    type Target = G;
2462
2463    fn deref(&self) -> &Self::Target {
2464        self.global.downcast_ref().unwrap()
2465    }
2466}
2467
2468impl<G: Global> DerefMut for GlobalLease<G> {
2469    fn deref_mut(&mut self) -> &mut Self::Target {
2470        self.global.downcast_mut().unwrap()
2471    }
2472}
2473
2474/// Contains state associated with an active drag operation, started by dragging an element
2475/// within the window or by dragging into the app from the underlying platform.
2476pub struct AnyDrag {
2477    /// The view used to render this drag
2478    pub view: AnyView,
2479
2480    /// The value of the dragged item, to be dropped
2481    pub value: Arc<dyn Any>,
2482
2483    /// This is used to render the dragged item in the same place
2484    /// on the original element that the drag was initiated
2485    pub cursor_offset: Point<Pixels>,
2486
2487    /// The cursor style to use while dragging
2488    pub cursor_style: Option<CursorStyle>,
2489}
2490
2491/// Contains state associated with a tooltip. You'll only need this struct if you're implementing
2492/// tooltip behavior on a custom element. Otherwise, use [Div::tooltip](crate::Interactivity::tooltip).
2493#[derive(Clone)]
2494pub struct AnyTooltip {
2495    /// The view used to display the tooltip
2496    pub view: AnyView,
2497
2498    /// The absolute position of the mouse when the tooltip was deployed.
2499    pub mouse_position: Point<Pixels>,
2500
2501    /// Given the bounds of the tooltip, checks whether the tooltip should still be visible and
2502    /// updates its state accordingly. This is needed atop the hovered element's mouse move handler
2503    /// to handle the case where the element is not painted (e.g. via use of `visible_on_hover`).
2504    pub check_visible_and_update: Rc<dyn Fn(Bounds<Pixels>, &mut Window, &mut App) -> bool>,
2505}
2506
2507/// A keystroke event, and potentially the associated action
2508#[derive(Debug)]
2509pub struct KeystrokeEvent {
2510    /// The keystroke that occurred
2511    pub keystroke: Keystroke,
2512
2513    /// The action that was resolved for the keystroke, if any
2514    pub action: Option<Box<dyn Action>>,
2515
2516    /// The context stack at the time
2517    pub context_stack: Vec<KeyContext>,
2518}
2519
2520struct NullHttpClient;
2521
2522impl HttpClient for NullHttpClient {
2523    fn send(
2524        &self,
2525        _req: http_client::Request<http_client::AsyncBody>,
2526    ) -> futures::future::BoxFuture<
2527        'static,
2528        anyhow::Result<http_client::Response<http_client::AsyncBody>>,
2529    > {
2530        async move {
2531            anyhow::bail!("No HttpClient available");
2532        }
2533        .boxed()
2534    }
2535
2536    fn user_agent(&self) -> Option<&http_client::http::HeaderValue> {
2537        None
2538    }
2539
2540    fn proxy(&self) -> Option<&Url> {
2541        None
2542    }
2543}
2544
2545/// A mutable reference to an entity owned by GPUI
2546pub struct GpuiBorrow<'a, T> {
2547    inner: Option<Lease<T>>,
2548    app: &'a mut App,
2549}
2550
2551impl<'a, T: 'static> GpuiBorrow<'a, T> {
2552    fn new(inner: Entity<T>, app: &'a mut App) -> Self {
2553        app.start_update();
2554        let lease = app.entities.lease(&inner);
2555        Self {
2556            inner: Some(lease),
2557            app,
2558        }
2559    }
2560}
2561
2562impl<'a, T: 'static> std::borrow::Borrow<T> for GpuiBorrow<'a, T> {
2563    fn borrow(&self) -> &T {
2564        self.inner.as_ref().unwrap().borrow()
2565    }
2566}
2567
2568impl<'a, T: 'static> std::borrow::BorrowMut<T> for GpuiBorrow<'a, T> {
2569    fn borrow_mut(&mut self) -> &mut T {
2570        self.inner.as_mut().unwrap().borrow_mut()
2571    }
2572}
2573
2574impl<'a, T: 'static> std::ops::Deref for GpuiBorrow<'a, T> {
2575    type Target = T;
2576
2577    fn deref(&self) -> &Self::Target {
2578        self.inner.as_ref().unwrap()
2579    }
2580}
2581
2582impl<'a, T: 'static> std::ops::DerefMut for GpuiBorrow<'a, T> {
2583    fn deref_mut(&mut self) -> &mut T {
2584        self.inner.as_mut().unwrap()
2585    }
2586}
2587
2588impl<'a, T> Drop for GpuiBorrow<'a, T> {
2589    fn drop(&mut self) {
2590        let lease = self.inner.take().unwrap();
2591        self.app.notify(lease.id);
2592        self.app.entities.end_lease(lease);
2593        self.app.finish_update();
2594    }
2595}
2596
2597impl Drop for App {
2598    fn drop(&mut self) {
2599        self.foreground_executor.close();
2600        self.background_executor.close();
2601    }
2602}
2603
2604#[cfg(test)]
2605mod test {
2606    use std::{cell::RefCell, rc::Rc};
2607
2608    use crate::{AppContext, TestAppContext};
2609
2610    #[test]
2611    fn test_gpui_borrow() {
2612        let cx = TestAppContext::single();
2613        let observation_count = Rc::new(RefCell::new(0));
2614
2615        let state = cx.update(|cx| {
2616            let state = cx.new(|_| false);
2617            cx.observe(&state, {
2618                let observation_count = observation_count.clone();
2619                move |_, _| {
2620                    let mut count = observation_count.borrow_mut();
2621                    *count += 1;
2622                }
2623            })
2624            .detach();
2625
2626            state
2627        });
2628
2629        cx.update(|cx| {
2630            // Calling this like this so that we don't clobber the borrow_mut above
2631            *std::borrow::BorrowMut::borrow_mut(&mut state.as_mut(cx)) = true;
2632        });
2633
2634        cx.update(|cx| {
2635            state.write(cx, false);
2636        });
2637
2638        assert_eq!(*observation_count.borrow(), 2);
2639    }
2640}