2971 lines · 105.5 KB · Rust
RawDownload
use scheduler::Instant;use std::{    any::{TypeId, type_name},    cell::{BorrowMutError, Cell, Ref, RefCell, RefMut},    marker::PhantomData,    mem,    ops::{Deref, DerefMut},    path::{Path, PathBuf},    rc::{Rc, Weak},    sync::{Arc, atomic::Ordering::SeqCst},    time::Duration,}; use anyhow::{Context as _, Result, anyhow};use derive_more::{Deref, DerefMut};use futures::{    Future, FutureExt,    channel::oneshot,    future::{LocalBoxFuture, Shared},};use itertools::Itertools;use parking_lot::RwLock;use slotmap::SlotMap; pub use async_context::*;#[cfg(feature = "bench")]pub use bench_context::{BenchAppContext, BenchReport, BenchWindowContext, bench_platform};use collections::{FxHashMap, FxHashSet, HashMap, TypeIdHashMap, TypeIdHashSet, VecDeque};pub use context::*;pub use entity_map::*;use gpui_util::{ResultExt, debug_panic};#[cfg(any(test, feature = "test-support"))]pub use headless_app_context::*;use http_client::{HttpClient, Url};use smallvec::SmallVec;#[cfg(any(test, feature = "test-support"))]pub use test_app::*;#[cfg(any(test, feature = "test-support"))]pub use test_context::*;#[cfg(all(target_os = "macos", any(test, feature = "test-support")))]pub use visual_test_context::*; #[cfg(any(feature = "inspector", debug_assertions))]use crate::InspectorElementRegistry;use crate::{    Action, ActionBuildError, ActionRegistry, Any, AnyView, AnyWindowHandle, AppContext, Arena,    ArenaBox, Asset, AssetSource, BackgroundExecutor, Bounds, ClipboardItem, CursorStyle,    DispatchPhase, DisplayId, EventEmitter, ExternalDragPayload, FocusHandle, FocusMap,    ForegroundExecutor, Global, KeyBinding, KeyContext, Keymap, Keystroke, LayoutId, Menu,    MenuItem, OwnedMenu, PathPromptOptions, Pixels, Platform, PlatformDisplay,    PlatformKeyboardLayout, PlatformKeyboardMapper, Point, Priority, PromptBuilder, PromptButton,    PromptHandle, PromptLevel, Render, RenderImage, RenderablePromptHandle, Reservation,    ScreenCaptureSource, SharedString, SubscriberSet, Subscription, SvgRenderer,    SystemNotification, SystemNotificationResponse, Task, TextRenderingMode, TextSystem,    ThermalState, Window, WindowAppearance, WindowButtonLayout, WindowHandle, WindowId,    WindowInvalidator,    colors::{Colors, GlobalColors},    hash, init_app_menus,}; mod async_context;#[cfg(feature = "bench")]mod bench_context;mod context;mod entity_map;#[cfg(any(test, feature = "test-support"))]mod headless_app_context;#[cfg(any(test, feature = "test-support"))]mod test_app;#[cfg(any(test, feature = "test-support"))]mod test_context;#[cfg(all(target_os = "macos", any(test, feature = "test-support")))]mod visual_test_context; /// The duration for which futures returned from [Context::on_app_quit] can run before the application fully quits.pub const SHUTDOWN_TIMEOUT: Duration = Duration::from_millis(200); /// Temporary(?) wrapper around [`RefCell<App>`] to help us debug any double borrows./// Strongly consider removing after stabilization.#[doc(hidden)]pub struct AppCell {    app: RefCell<App>,} impl AppCell {    #[doc(hidden)]    #[track_caller]    pub fn borrow(&self) -> AppRef<'_> {        if option_env!("TRACK_THREAD_BORROWS").is_some() {            let thread_id = std::thread::current().id();            eprintln!("borrowed {thread_id:?}");        }        AppRef(self.app.borrow())    }     #[doc(hidden)]    #[track_caller]    pub fn borrow_mut(&self) -> AppRefMut<'_> {        if option_env!("TRACK_THREAD_BORROWS").is_some() {            let thread_id = std::thread::current().id();            eprintln!("borrowed {thread_id:?}");        }        AppRefMut(self.app.borrow_mut())    }     #[doc(hidden)]    #[track_caller]    pub fn try_borrow_mut(&self) -> Result<AppRefMut<'_>, BorrowMutError> {        if option_env!("TRACK_THREAD_BORROWS").is_some() {            let thread_id = std::thread::current().id();            eprintln!("borrowed {thread_id:?}");        }        Ok(AppRefMut(self.app.try_borrow_mut()?))    }} #[doc(hidden)]#[derive(Deref, DerefMut)]pub struct AppRef<'a>(Ref<'a, App>); impl Drop for AppRef<'_> {    fn drop(&mut self) {        if option_env!("TRACK_THREAD_BORROWS").is_some() {            let thread_id = std::thread::current().id();            eprintln!("dropped borrow from {thread_id:?}");        }    }} #[doc(hidden)]#[derive(Deref, DerefMut)]pub struct AppRefMut<'a>(RefMut<'a, App>); impl Drop for AppRefMut<'_> {    fn drop(&mut self) {        if option_env!("TRACK_THREAD_BORROWS").is_some() {            let thread_id = std::thread::current().id();            eprintln!("dropped {thread_id:?}");        }    }} /// A reference to a GPUI application, typically constructed in the `main` function of your app./// You won't interact with this type much outside of initial configuration and startup.pub struct Application(Rc<AppCell>); /// A strong handle to an [`Application`] started with [`Application::run_embedded`].////// Dropping this handle releases the app, so an embedder must hold it for as long as the/// app should run. While held, it is the embedder's entry point back into GPUI each time/// the external run loop gives it control.pub struct ApplicationHandle {    app: Rc<AppCell>,} impl ApplicationHandle {    /// Invoke `f` with the app context. Must not be called re-entrantly from code that    /// is already inside an update; the app state is a `RefCell` and will panic on a    /// double borrow.    pub fn update<R>(&self, f: impl FnOnce(&mut App) -> R) -> R {        let cx = &mut *self.app.borrow_mut();        f(cx)    }     /// An [`AsyncApp`] for use across await points. It holds the app weakly; keeping the    /// app alive remains this handle's job.    pub fn to_async(&self) -> AsyncApp {        self.update(|cx| cx.to_async())    }} /// Represents an application before it is fully launched. Once your app is/// configured, you'll start the app with `App::run`.impl Application {    /// Builds an app with a caller-provided platform implementation.    pub fn with_platform(platform: Rc<dyn Platform>) -> Self {        Self(App::new_app(            platform,            Arc::new(()),            Arc::new(NullHttpClient),        ))    }     /// Builds an app with accessibility (AccessKit) integration forcibly    /// disabled.    ///    /// In this mode, accessibility APIs (e.g.    /// [`div().role()`][crate::StatefulInteractiveElement::role]) silently    /// no-op.    ///    /// See the [accessibility guide](crate::_accessibility) for an overview of    /// the features this disables.    pub fn new_inaccessible(platform: Rc<dyn Platform>) -> Self {        let this = Self::with_platform(platform);        this.0.borrow_mut().accessibility_force_disabled = true;        this    }     /// Assigns the source of assets for the application.    pub fn with_assets(self, asset_source: impl AssetSource) -> Self {        let mut context_lock = self.0.borrow_mut();        let asset_source = Arc::new(asset_source);        context_lock.asset_source = asset_source.clone();        context_lock.svg_renderer = SvgRenderer::new(asset_source);        drop(context_lock);        self    }     /// Sets the HTTP client for the application.    pub fn with_http_client(self, http_client: Arc<dyn HttpClient>) -> Self {        let mut context_lock = self.0.borrow_mut();        context_lock.http_client = http_client;        drop(context_lock);        self    }     /// Configures when the application should automatically quit.    /// By default, [`QuitMode::Default`] is used.    pub fn with_quit_mode(self, mode: QuitMode) -> Self {        self.0.borrow_mut().quit_mode = mode;        self    }     /// Start the application. The provided callback will be called once the    /// app is fully launched.    pub fn run<F>(self, on_finish_launching: F)    where        F: 'static + FnOnce(&mut App),    {        let this = self.0.clone();        let platform = self.0.borrow().platform.clone();        platform.run(Box::new(move || {            let cx = &mut *this.borrow_mut();            on_finish_launching(cx);        }));    }     /// Start the application for an embedder that drives the run loop itself.    ///    /// On ordinary platforms `Platform::run` blocks for the lifetime of the app, and the    /// app state is kept alive by [`Application::run`]'s stack frame. Embedded platforms —    /// where the run loop belongs to someone else, e.g. GPUI compiled into a Wasm guest,    /// or a GPUI view hosted inside a foreign native application — implement    /// `Platform::run` to invoke the launch callback and return immediately. This method    /// supports that shape: it returns an [`ApplicationHandle`] that keeps the app alive    /// and lets the embedder re-enter it whenever the external run loop yields control.    pub fn run_embedded<F>(self, on_finish_launching: F) -> ApplicationHandle    where        F: 'static + FnOnce(&mut App),    {        let this = self.0.clone();        let platform = self.0.borrow().platform.clone();        platform.run(Box::new(move || {            let cx = &mut *this.borrow_mut();            on_finish_launching(cx);        }));        ApplicationHandle { app: self.0 }    }     /// Register a handler to be invoked when the platform instructs the application    /// to open one or more URLs.    pub fn on_open_urls<F>(&self, mut callback: F) -> &Self    where        F: 'static + FnMut(Vec<String>),    {        self.0.borrow().platform.on_open_urls(Box::new(callback));        self    }     /// Invokes a handler when an already-running application is launched.    /// On macOS, this can occur when the application icon is double-clicked or the app is launched via the dock.    pub fn on_reopen<F>(&self, mut callback: F) -> &Self    where        F: 'static + FnMut(&mut App),    {        let this = Rc::downgrade(&self.0);        self.0.borrow_mut().platform.on_reopen(Box::new(move || {            if let Some(app) = this.upgrade() {                callback(&mut app.borrow_mut());            }        }));        self    }     /// Invokes a handler when the system wakes from sleep.    pub fn on_system_wake<F>(&self, mut callback: F) -> &Self    where        F: 'static + FnMut(&mut App),    {        let this = Rc::downgrade(&self.0);        self.0            .borrow_mut()            .platform            .on_system_wake(Box::new(move || {                if let Some(app) = this.upgrade() {                    callback(&mut app.borrow_mut());                }            }));        self    }     /// Returns a handle to the [`BackgroundExecutor`] associated with this app, which can be used to spawn futures in the background.    pub fn background_executor(&self) -> BackgroundExecutor {        self.0.borrow().background_executor.clone()    }     /// Returns a handle to the [`ForegroundExecutor`] associated with this app, which can be used to spawn futures in the foreground.    pub fn foreground_executor(&self) -> ForegroundExecutor {        self.0.borrow().foreground_executor.clone()    }     /// Returns a reference to the [`TextSystem`] associated with this app.    pub fn text_system(&self) -> Arc<TextSystem> {        self.0.borrow().text_system.clone()    }     /// Returns the file URL of the executable with the specified name in the application bundle    pub fn path_for_auxiliary_executable(&self, name: &str) -> Result<PathBuf> {        self.0.borrow().path_for_auxiliary_executable(name)    }} type Handler = Box<dyn FnMut(&mut App) -> bool + 'static>;type Listener = Box<dyn FnMut(&dyn Any, &mut App) -> bool + 'static>;pub(crate) type KeystrokeObserver =    Box<dyn FnMut(&KeystrokeEvent, &mut Window, &mut App) -> bool + 'static>;type QuitHandler = Box<dyn FnOnce(&mut App) -> LocalBoxFuture<'static, ()> + 'static>;type WindowClosedHandler = Box<dyn FnMut(&mut App, WindowId)>;type ReleaseListener = Box<dyn FnOnce(&mut dyn Any, &mut App) + 'static>;type NewEntityListener = Box<dyn FnMut(AnyEntity, &mut Option<&mut Window>, &mut App) + 'static>; /// Defines when the application should automatically quit.#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]pub enum QuitMode {    /// Use [`QuitMode::Explicit`] on macOS and [`QuitMode::LastWindowClosed`] on other platforms.    #[default]    Default,    /// Quit automatically when the last window is closed.    LastWindowClosed,    /// Quit only when requested via [`App::quit`].    Explicit,} /// Controls when GPUI hides the mouse cursor in response to keyboard input.////// Restoration on mouse motion is handled by the platform layer; this enum/// only describes the policy for *triggering* a hide.#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]pub enum CursorHideMode {    /// Never hide the cursor automatically.    Never,    /// Hide on character-producing key presses (typing).    OnTyping,    /// Hide on character-producing key presses, *and* when a key binding    /// resolves to an action that consumes the keystroke.    #[default]    OnTypingAndAction,} #[doc(hidden)]#[derive(Clone, PartialEq, Eq)]pub struct SystemWindowTab {    pub id: WindowId,    pub title: SharedString,    pub handle: AnyWindowHandle,    pub last_active_at: Instant,} impl SystemWindowTab {    /// Create a new instance of the window tab.    pub fn new(title: SharedString, handle: AnyWindowHandle) -> Self {        Self {            id: handle.id,            title,            handle,            last_active_at: Instant::now(),        }    }} /// A controller for managing window tabs.#[derive(Default)]pub struct SystemWindowTabController {    visible: Option<bool>,    tab_groups: FxHashMap<usize, Vec<SystemWindowTab>>,} impl Global for SystemWindowTabController {} impl SystemWindowTabController {    /// Create a new instance of the window tab controller.    pub fn new() -> Self {        Self {            visible: None,            tab_groups: FxHashMap::default(),        }    }     /// Initialize the global window tab controller.    pub fn init(cx: &mut App) {        cx.set_global(SystemWindowTabController::new());    }     /// Get all tab groups.    pub fn tab_groups(&self) -> &FxHashMap<usize, Vec<SystemWindowTab>> {        &self.tab_groups    }     /// Get the next tab group window handle.    pub fn get_next_tab_group_window(cx: &mut App, id: WindowId) -> Option<&AnyWindowHandle> {        let controller = cx.global::<SystemWindowTabController>();        let current_group = controller            .tab_groups            .iter()            .find_map(|(group, tabs)| tabs.iter().find(|tab| tab.id == id).map(|_| group));         let current_group = current_group?;        // TODO: `.keys()` returns arbitrary order, what does "next" mean?        let mut group_ids: Vec<_> = controller.tab_groups.keys().collect();        let idx = group_ids.iter().position(|g| *g == current_group)?;        let next_idx = (idx + 1) % group_ids.len();         controller            .tab_groups            .get(group_ids[next_idx])            .and_then(|tabs| {                tabs.iter()                    .max_by_key(|tab| tab.last_active_at)                    .or_else(|| tabs.first())                    .map(|tab| &tab.handle)            })    }     /// Get the previous tab group window handle.    pub fn get_prev_tab_group_window(cx: &mut App, id: WindowId) -> Option<&AnyWindowHandle> {        let controller = cx.global::<SystemWindowTabController>();        let current_group = controller            .tab_groups            .iter()            .find_map(|(group, tabs)| tabs.iter().find(|tab| tab.id == id).map(|_| group));         let current_group = current_group?;        // TODO: `.keys()` returns arbitrary order, what does "previous" mean?        let mut group_ids: Vec<_> = controller.tab_groups.keys().collect();        let idx = group_ids.iter().position(|g| *g == current_group)?;        let prev_idx = if idx == 0 {            group_ids.len() - 1        } else {            idx - 1        };         controller            .tab_groups            .get(group_ids[prev_idx])            .and_then(|tabs| {                tabs.iter()                    .max_by_key(|tab| tab.last_active_at)                    .or_else(|| tabs.first())                    .map(|tab| &tab.handle)            })    }     /// Get all tabs in the same window.    pub fn tabs(&self, id: WindowId) -> Option<&Vec<SystemWindowTab>> {        self.tab_groups            .values()            .find(|tabs| tabs.iter().any(|tab| tab.id == id))    }     /// Initialize the visibility of the system window tab controller.    pub fn init_visible(cx: &mut App, visible: bool) {        let mut controller = cx.global_mut::<SystemWindowTabController>();        if controller.visible.is_none() {            controller.visible = Some(visible);        }    }     /// Get the visibility of the system window tab controller.    pub fn is_visible(&self) -> bool {        self.visible.unwrap_or(false)    }     /// Set the visibility of the system window tab controller.    pub fn set_visible(cx: &mut App, visible: bool) {        let mut controller = cx.global_mut::<SystemWindowTabController>();        controller.visible = Some(visible);    }     /// Update the last active of a window.    pub fn update_last_active(cx: &mut App, id: WindowId) {        let mut controller = cx.global_mut::<SystemWindowTabController>();        for windows in controller.tab_groups.values_mut() {            for tab in windows.iter_mut() {                if tab.id == id {                    tab.last_active_at = Instant::now();                }            }        }    } 

Lines 1–500 of 2971.