7080 lines · 264.8 KB · Rust
RawDownload
#[cfg(any(feature = "inspector", debug_assertions))]use crate::Inspector;use crate::{    Action, AnyDrag, AnyElement, AnyImageCache, AnyTooltip, AnyView, App, AppContext, Arena, Asset,    AsyncWindowContext, AtlasTile, AvailableSpace, Background, BorderStyle, Bounds, BoxShadow,    Capslock, Context, Corners, CursorHideMode, CursorStyle, Decorations, DevicePixels,    DispatchActionListener, DispatchNodeId, DispatchTree, DisplayId, Edges, Effect, Entity,    EntityId, EventEmitter, FileDropEvent, FontId, Global, GlobalElementId, GlyphId, GpuSpecs,    Hsla, InputHandler, IsZero, KeyBinding, KeyContext, KeyDownEvent, KeyEvent, Keystroke,    KeystrokeEvent, LayoutId, LineLayoutIndex, Modifiers, ModifiersChangedEvent, MonochromeSprite,    MouseButton, MouseEvent, MouseMoveEvent, MouseUpEvent, Path, Pixels, PlatformAtlas,    PlatformDisplay, PlatformInput, PlatformInputHandler, PlatformWindow, Point, PolychromeSprite,    Priority, PromptButton, PromptLevel, Quad, Render, RenderGlyphParams, RenderImage,    RenderImageParams, RenderSvgParams, Replay, ResizeEdge, SMOOTH_SVG_SCALE_FACTOR,    SUBPIXEL_VARIANTS_X, SUBPIXEL_VARIANTS_Y, ScaledPixels, Scene, Shadow, SharedString, Size,    StrikethroughStyle, Style, SubpixelSprite, SubscriberSet, Subscription, SystemWindowTab,    SystemWindowTabController, TabStopMap, TaffyLayoutEngine, Task, TextRenderingMode, TextStyle,    TextStyleRefinement, ThermalState, TransformationMatrix, Underline, UnderlineStyle,    WindowAppearance, WindowBackgroundAppearance, WindowBounds, WindowControls, WindowDecorations,    WindowOptions, WindowParams, WindowTextSystem, point, prelude::*, profiler, px, rems, size,    transparent_black,}; use anyhow::{Context as _, Result, anyhow};use collections::{FxHashMap, FxHashSet};#[cfg(target_os = "macos")]use core_video::pixel_buffer::CVPixelBuffer;use derive_more::{Deref, DerefMut};use futures::FutureExt;use futures::channel::oneshot;use gpui_util::post_inc;use gpui_util::{ResultExt, measure};#[cfg(feature = "input-latency-histogram")]use hdrhistogram::Histogram;use itertools::FoldWhile::{Continue, Done};use itertools::Itertools;use parking_lot::RwLock;use raw_window_handle::{HandleError, HasDisplayHandle, HasWindowHandle};use refineable::Refineable;use scheduler::Instant;use slotmap::SlotMap;use smallvec::SmallVec;use std::{    any::{Any, TypeId},    borrow::Cow,    cell::{Cell, RefCell},    cmp,    fmt::{Debug, Display},    hash::{Hash, Hasher},    marker::PhantomData,    mem,    ops::{DerefMut, Range},    rc::Rc,    sync::{        Arc, Weak,        atomic::{AtomicBool, AtomicUsize, Ordering::SeqCst},    },    time::Duration,};use uuid::Uuid; pub(crate) mod a11y;mod prompts; pub use a11y::A11ySubtreeBuilder; use self::a11y::A11y;#[cfg(not(target_family = "wasm"))]use self::a11y::ROOT_NODE_ID;use crate::util::{    atomic_incr_if_not_zero, ceil_to_device_pixel, floor_to_device_pixel, round_half_toward_zero,    round_half_toward_zero_f64, round_stroke_to_device_pixel, round_to_device_pixel,};pub use prompts::*; /// Default window size used when no explicit size is provided.pub const DEFAULT_WINDOW_SIZE: Size<Pixels> = size(px(1536.), px(1095.)); /// A 6:5 aspect ratio minimum window size to be used for functional,/// additional-to-main-Zed windows, like the settings and rules library windows.pub const DEFAULT_ADDITIONAL_WINDOW_SIZE: Size<Pixels> = Size {    width: Pixels(900.),    height: Pixels(750.),}; /// Represents the two different phases when dispatching events.#[derive(Default, Copy, Clone, Debug, Eq, PartialEq)]pub enum DispatchPhase {    /// After the capture phase comes the bubble phase, in which mouse event listeners are    /// invoked front to back and keyboard event listeners are invoked from the focused element    /// to the root of the element tree. This is the phase you'll most commonly want to use when    /// registering event listeners.    #[default]    Bubble,    /// During the initial capture phase, mouse event listeners are invoked back to front, and keyboard    /// listeners are invoked from the root of the tree downward toward the focused element. This phase    /// is used for special purposes such as clearing the "pressed" state for click events. If    /// you stop event propagation during this phase, you need to know what you're doing. Handlers    /// outside of the immediate region may rely on detecting non-local events during this phase.    Capture,} impl DispatchPhase {    /// Returns true if this represents the "bubble" phase.    #[inline]    pub fn bubble(self) -> bool {        self == DispatchPhase::Bubble    }     /// Returns true if this represents the "capture" phase.    #[inline]    pub fn capture(self) -> bool {        self == DispatchPhase::Capture    }} struct WindowInvalidatorInner {    pub dirty: bool,    pub draw_phase: DrawPhase,    pub dirty_views: FxHashSet<EntityId>,    pub update_count: usize,    pub frame_dirty: FrameDirtyAccumulator,} /// Per-frame invalidation bookkeeping, drained at draw time and emitted to the/// frame profiler. Tracks when the current frame first became dirty and how/// many invalidations were coalesced into it. Only populated while/// `profiler::frame_trace_enabled()` is set.#[derive(Default)]struct FrameDirtyAccumulator {    dirty_at: Option<Instant>,    invalidations: u64,} #[derive(Clone)]pub(crate) struct WindowInvalidator {    inner: Rc<RefCell<WindowInvalidatorInner>>,} impl WindowInvalidator {    pub fn new() -> Self {        WindowInvalidator {            inner: Rc::new(RefCell::new(WindowInvalidatorInner {                dirty: true,                draw_phase: DrawPhase::None,                dirty_views: FxHashSet::default(),                update_count: 0,                frame_dirty: FrameDirtyAccumulator::default(),            })),        }    }     pub fn invalidate_view(&self, entity: EntityId, cx: &mut App) -> bool {        let mut inner = self.inner.borrow_mut();        inner.update_count += 1;        inner.dirty_views.insert(entity);        if inner.draw_phase == DrawPhase::None {            Self::record_frame_dirty(&mut inner);            inner.dirty = true;            cx.push_effect(Effect::Notify { emitter: entity });            true        } else {            false        }    }     pub fn is_dirty(&self) -> bool {        self.inner.borrow().dirty    }     pub fn set_dirty(&self, dirty: bool) {        let mut inner = self.inner.borrow_mut();        inner.dirty = dirty;        if dirty {            inner.update_count += 1;            Self::record_frame_dirty(&mut inner);        }    }     pub fn set_phase(&self, phase: DrawPhase) {        self.inner.borrow_mut().draw_phase = phase    }     pub fn update_count(&self) -> usize {        self.inner.borrow().update_count    }     fn record_frame_dirty(inner: &mut WindowInvalidatorInner) {        if profiler::frame_trace_enabled() {            inner.frame_dirty.dirty_at.get_or_insert_with(Instant::now);            inner.frame_dirty.invalidations += 1;        }    }     fn take_frame_dirty(&self) -> FrameDirtyAccumulator {        mem::take(&mut self.inner.borrow_mut().frame_dirty)    }     pub fn take_views(&self) -> FxHashSet<EntityId> {        mem::take(&mut self.inner.borrow_mut().dirty_views)    }     pub fn replace_views(&self, views: FxHashSet<EntityId>) {        self.inner.borrow_mut().dirty_views = views;    }     pub fn not_drawing(&self) -> bool {        self.inner.borrow().draw_phase == DrawPhase::None    }     #[track_caller]    pub fn debug_assert_paint(&self) {        debug_assert!(            matches!(self.inner.borrow().draw_phase, DrawPhase::Paint),            "this method can only be called during paint"        );    }     #[track_caller]    pub fn debug_assert_prepaint(&self) {        debug_assert!(            matches!(self.inner.borrow().draw_phase, DrawPhase::Prepaint),            "this method can only be called during request_layout, or prepaint"        );    }     #[track_caller]    pub fn debug_assert_paint_or_prepaint(&self) {        debug_assert!(            matches!(                self.inner.borrow().draw_phase,                DrawPhase::Paint | DrawPhase::Prepaint            ),            "this method can only be called during request_layout, prepaint, or paint"        );    }} type AnyObserver = Box<dyn FnMut(&mut Window, &mut App) -> bool + 'static>; pub(crate) type AnyWindowFocusListener =    Box<dyn FnMut(&WindowFocusEvent, &mut Window, &mut App) -> bool + 'static>; pub(crate) struct WindowFocusEvent {    pub(crate) previous_focus_path: SmallVec<[FocusId; 8]>,    pub(crate) current_focus_path: SmallVec<[FocusId; 8]>,} impl WindowFocusEvent {    pub fn is_focus_in(&self, focus_id: FocusId) -> bool {        !self.previous_focus_path.contains(&focus_id) && self.current_focus_path.contains(&focus_id)    }     pub fn is_focus_out(&self, focus_id: FocusId) -> bool {        self.previous_focus_path.contains(&focus_id) && !self.current_focus_path.contains(&focus_id)    }} /// This is provided when subscribing for `Context::on_focus_out` events.pub struct FocusOutEvent {    /// A weak focus handle representing what was blurred.    pub blurred: WeakFocusHandle,} slotmap::new_key_type! {    /// A globally unique identifier for a focusable element.    pub struct FocusId;} thread_local! {    /// Fallback arena used when no app-specific arena is active.    /// In production, each window draw sets CURRENT_ELEMENT_ARENA to the app's arena.    pub(crate) static ELEMENT_ARENA: RefCell<Arena> = RefCell::new(Arena::new(1024 * 1024));     /// Points to the current App's element arena during draw operations.    /// This allows multiple test Apps to have isolated arenas, preventing    /// cross-session corruption when the scheduler interleaves their tasks.    static CURRENT_ELEMENT_ARENA: Cell<Option<*const RefCell<Arena>>> = const { Cell::new(None) };} /// Whether a window draw is currently in progress on this thread.////// This holds exactly while an `ElementArenaScope` is active: nested scopes/// restore the previous (still set) arena pointer, so `CURRENT_ELEMENT_ARENA`/// is `Some` from the outermost draw's start to its end.////// The `on_request_frame` callback uses this to defer draw requests that/// arrive re-entrantly while a draw is already on the stack (e.g. via nested/// message pumping in the Windows window procedure), instead of running a/// nested draw or panicking on the already-borrowed App.fn draw_in_progress() -> bool {    CURRENT_ELEMENT_ARENA.with(|current| current.get().is_some())} /// Allocates an element in the current arena. Uses the app-specific arena if one/// is active (during draw), otherwise falls back to the thread-local ELEMENT_ARENA.pub(crate) fn with_element_arena<R>(f: impl FnOnce(&mut Arena) -> R) -> R {    CURRENT_ELEMENT_ARENA.with(|current| {        if let Some(arena_ptr) = current.get() {            // SAFETY: The pointer is valid for the duration of the draw operation            // that set it, and we're being called during that same draw.            let arena_cell = unsafe { &*arena_ptr };            f(&mut arena_cell.borrow_mut())        } else {            ELEMENT_ARENA.with_borrow_mut(f)        }    })} /// Scope guard that sets CURRENT_ELEMENT_ARENA for the duration of a draw/// operation and tracks the arena's scope depth, so that a nested draw's/// `ArenaClearNeeded::clear` is deferred rather than freeing memory the outer/// draw still references (see `Arena::clear`).////// Call [`ElementArenaScope::exit`] with the same arena that was entered to/// obtain the [`ArenaClearNeeded`] token the draw now owes; requiring `exit`/// makes it impossible to request a clear before the scope has ended. The/// scope's teardown — restoring the thread-local and balancing `begin_scope`/// with `end_scope` — happens in `Drop`, so the arena's scope depth stays/// balanced on every path, including when a panic unwinds a draw before `exit`/// is reached. (If teardown lived only in `exit`, such a panic would leave the/// scope depth permanently elevated and defer every future clear, leaking/// memory unboundedly.)pub(crate) struct ElementArenaScope {    /// The entered arena: compared against the argument in `exit`, and    /// dereferenced in `Drop` to end its scope (see the SAFETY note there).    entered: *const RefCell<Arena>,    previous: Option<*const RefCell<Arena>>,    exited: bool,} impl ElementArenaScope {    /// Enter a scope where element allocations use the given arena.    pub(crate) fn enter(arena: &RefCell<Arena>) -> Self {        arena.borrow_mut().begin_scope();        let previous = CURRENT_ELEMENT_ARENA.with(|current| {            let prev = current.get();            current.set(Some(arena as *const RefCell<Arena>));            prev        });        Self {            entered: arena as *const RefCell<Arena>,            previous,            exited: false,        }    }     /// End the scope: restores the previously-current arena and ends the    /// arena's clear-deferral scope. Returns the token for the arena clear the    /// draw now owes; producing it here makes it impossible to request a clear    /// before the scope has ended (which would be silently deferred forever).    ///    /// Panics if passed a different arena than was entered: ending the scope    /// of the wrong arena would unbalance two arenas' scope depths, allowing    /// one of them to clear while a draw still references its memory.    pub(crate) fn exit(mut self, arena: &RefCell<Arena>) -> ArenaClearNeeded {        assert!(            std::ptr::eq(self.entered, arena),            "ElementArenaScope::exit called with a different arena than was entered"        );        self.exited = true;        // Teardown (restoring the thread-local and ending the arena's        // clear-deferral scope) runs in `Drop`, which fires both here — `self`        // is dropped as `exit` returns, before the token reaches the caller —        // and when a panic unwinds the draw before `exit` is reached.        ArenaClearNeeded::new(arena)    }} impl Drop for ElementArenaScope {    fn drop(&mut self) {        // Teardown lives here (rather than in `exit`) so it runs exactly once on        // every path: `exit` consumes and drops the guard on the normal path,        // and unwinding drops it on the panic path. Balancing `begin_scope` here        // keeps the arena's scope depth correct even when a draw panics; if this        // only happened in `exit`, a panic between `enter` and `exit` would leave        // the depth elevated and defer every future clear.        CURRENT_ELEMENT_ARENA.with(|current| {            current.set(self.previous);        });        // SAFETY: `entered` came from a `&RefCell<Arena>` in `enter`, and the        // arena (owned by the `App` being drawn) outlives this guard on both the        // normal and unwinding paths, since the guard is a local of the draw.        unsafe { &*self.entered }.borrow_mut().end_scope();        if !self.exited && !std::thread::panicking() {            debug_assert!(false, "ElementArenaScope dropped without calling exit()");            log::error!(                "ElementArenaScope dropped without calling exit(); \                 the arena clear for this draw was never requested"            );        }    }} /// Returned when the element arena has been used and so must be cleared before the next draw.#[must_use]pub struct ArenaClearNeeded {    /// Identity of the arena that was drawn into. Only ever compared against    /// another pointer in `clear`; never dereferenced.    arena: *const RefCell<Arena>,} impl ArenaClearNeeded {    /// Create a new ArenaClearNeeded token for the App whose arena was drawn    /// into. Private: the only way to obtain one is [`ElementArenaScope::exit`].    fn new(arena: &RefCell<Arena>) -> Self {        Self {            arena: arena as *const RefCell<Arena>,        }    }     /// Clear the element arena of the App the draw ran against. If an enclosing    /// draw is still in progress (this draw was nested inside it), the clear is    /// deferred to the enclosing draw's own `ArenaClearNeeded` so that its live    /// allocations aren't freed.    ///    /// Panics if passed a different App than the draw ran against, since    /// clearing another App's arena could free memory its draws still    /// reference.    pub fn clear(self, cx: &mut App) {        assert!(            std::ptr::eq(self.arena, &cx.element_arena),            "ArenaClearNeeded::clear called with a different App than the draw ran against"        );        cx.element_arena.borrow_mut().clear();    }} pub(crate) type FocusMap = RwLock<SlotMap<FocusId, FocusRef>>;pub(crate) struct FocusRef {    pub(crate) ref_count: AtomicUsize,    pub(crate) tab_index: isize,    pub(crate) tab_stop: bool,} impl FocusId {    /// Obtains whether the element associated with this handle is currently focused.    pub fn is_focused(&self, window: &Window) -> bool {        window.focus == Some(*self)    }     /// Obtains whether the element associated with this handle contains the focused    /// element or is itself focused.    pub fn contains_focused(&self, window: &Window, cx: &App) -> bool {        window            .focused(cx)            .is_some_and(|focused| self.contains(focused.id, window))    }     /// Obtains whether the element associated with this handle is contained within the    /// focused element or is itself focused.    pub fn within_focused(&self, window: &Window, cx: &App) -> bool {        let focused = window.focused(cx);        focused.is_some_and(|focused| focused.id.contains(*self, window))    }     /// Obtains whether this handle contains the given handle in the most recently rendered frame.    pub(crate) fn contains(&self, other: Self, window: &Window) -> bool {        window            .rendered_frame            .dispatch_tree            .focus_contains(*self, other)    }} /// A handle which can be used to track and manipulate the focused element in a window.pub struct FocusHandle {    pub(crate) id: FocusId,    handles: Arc<FocusMap>,    /// The index of this element in the tab order.    pub tab_index: isize,    /// Whether this element can be focused by tab navigation.    pub tab_stop: bool,} impl std::fmt::Debug for FocusHandle {    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {        f.write_fmt(format_args!("FocusHandle({:?})", self.id))    }} impl FocusHandle {    pub(crate) fn new(handles: &Arc<FocusMap>) -> Self {        let id = handles.write().insert(FocusRef {            ref_count: AtomicUsize::new(1),            tab_index: 0,            tab_stop: false,        });         Self {            id,            tab_index: 0,            tab_stop: false,            handles: handles.clone(),        }    }     pub(crate) fn for_id(id: FocusId, handles: &Arc<FocusMap>) -> Option<Self> {        let lock = handles.read();        let focus = lock.get(id)?;

Lines 1–500 of 7080.