#[cfg(any(feature = "inspector", debug_assertions))]use crate::Inspector;use crate::{ Action, AnyDrag, AnyElement, AnyImageCache, AnyTooltip, AnyView, App, AppContext, Arena, Asset, AsyncWindowContext, AvailableSpace, Background, BorderStyle, Bounds, BoxShadow, Capslock, Context, Corners, 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::*, 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};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::{AtomicUsize, Ordering::SeqCst}, }, time::Duration,};use uuid::Uuid; mod prompts; use crate::util::atomic_incr_if_not_zero;pub use prompts::*; /// Default window size used when no explicit size is provided.pub const DEFAULT_WINDOW_SIZE: Size<Pixels> = size(px(1536.), px(864.)); /// 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>,} #[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(), })), } } pub fn invalidate_view(&self, entity: EntityId, cx: &mut App) -> bool { let mut inner = self.inner.borrow_mut(); inner.dirty_views.insert(entity); if inner.draw_phase == DrawPhase::None { 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) { self.inner.borrow_mut().dirty = dirty } pub fn set_phase(&self, phase: DrawPhase) { self.inner.borrow_mut().draw_phase = phase } 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) };} /// 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) } })} /// RAII guard that sets CURRENT_ELEMENT_ARENA for the duration of a draw operation./// When dropped, restores the previous arena (supporting nested draws).pub(crate) struct ElementArenaScope { previous: Option<*const RefCell<Arena>>,} impl ElementArenaScope { /// Enter a scope where element allocations use the given arena. pub(crate) fn enter(arena: &RefCell<Arena>) -> Self { let previous = CURRENT_ELEMENT_ARENA.with(|current| { let prev = current.get(); current.set(Some(arena as *const RefCell<Arena>)); prev }); Self { previous } }} impl Drop for ElementArenaScope { fn drop(&mut self) { CURRENT_ELEMENT_ARENA.with(|current| { current.set(self.previous); }); }} /// Returned when the element arena has been used and so must be cleared before the next draw.#[must_use]pub struct ArenaClearNeeded { arena: *const RefCell<Arena>,} impl ArenaClearNeeded { /// Create a new ArenaClearNeeded that will clear the given arena. pub(crate) fn new(arena: &RefCell<Arena>) -> Self { Self { arena: arena as *const RefCell<Arena>, } } /// Clear the element arena. pub fn clear(self) { // SAFETY: The arena pointer is valid because ArenaClearNeeded is created // at the end of draw() and must be cleared before the next draw. let arena_cell = unsafe { &*self.arena }; arena_cell.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)?; if atomic_incr_if_not_zero(&focus.ref_count) == 0 { return None; } Some(Self { id, tab_index: focus.tab_index, tab_stop: focus.tab_stop, handles: handles.clone(), }) } /// Sets the tab index of the element associated with this handle. pub fn tab_index(mut self, index: isize) -> Self { self.tab_index = index; if let Some(focus) = self.handles.write().get_mut(self.id) { focus.tab_index = index; } self } /// Sets whether the element associated with this handle is a tab stop. /// /// When `false`, the element will not be included in the tab order. pub fn tab_stop(mut self, tab_stop: bool) -> Self { self.tab_stop = tab_stop; if let Some(focus) = self.handles.write().get_mut(self.id) { focus.tab_stop = tab_stop; } self } /// Converts this focus handle into a weak variant, which does not prevent it from being released. pub fn downgrade(&self) -> WeakFocusHandle { WeakFocusHandle { id: self.id, handles: Arc::downgrade(&self.handles), } } /// Moves the focus to the element associated with this handle. pub fn focus(&self, window: &mut Window, cx: &mut App) { window.focus(self, cx) } /// Obtains whether the element associated with this handle is currently focused. pub fn is_focused(&self, window: &Window) -> bool { self.id.is_focused(window) } /// 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 { self.id.contains_focused(window, cx) } /// 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: &mut App) -> bool { self.id.within_focused(window, cx) } /// Obtains whether this handle contains the given handle in the most recently rendered frame. pub fn contains(&self, other: &Self, window: &Window) -> bool { self.id.contains(other.id, window) } /// Dispatch an action on the element that rendered this focus handle pub fn dispatch_action(&self, action: &dyn Action, window: &mut Window, cx: &mut App) { if let Some(node_id) = window .rendered_frame .dispatch_tree .focusable_node_id(self.id) { window.dispatch_action_on_node(node_id, action, cx) } }} impl Clone for FocusHandle { fn clone(&self) -> Self { Self::for_id(self.id, &self.handles).unwrap() }} impl PartialEq for FocusHandle { fn eq(&self, other: &Self) -> bool { self.id == other.id }} impl Eq for FocusHandle {} impl Drop for FocusHandle { fn drop(&mut self) { self.handles .read() .get(self.id) .unwrap() .ref_count .fetch_sub(1, SeqCst); }} /// A weak reference to a focus handle.#[derive(Clone, Debug)]pub struct WeakFocusHandle { pub(crate) id: FocusId, pub(crate) handles: Weak<FocusMap>,} impl WeakFocusHandle { /// Attempts to upgrade the [WeakFocusHandle] to a [FocusHandle]. pub fn upgrade(&self) -> Option<FocusHandle> { let handles = self.handles.upgrade()?; FocusHandle::for_id(self.id, &handles) }} impl PartialEq for WeakFocusHandle { fn eq(&self, other: &WeakFocusHandle) -> bool { self.id == other.id }} impl Eq for WeakFocusHandle {} impl PartialEq<FocusHandle> for WeakFocusHandle { fn eq(&self, other: &FocusHandle) -> bool { self.id == other.id }} impl PartialEq<WeakFocusHandle> for FocusHandle {Lines 1–500 of 5657. Load more
#[cfg(any(feature = "inspector", debug_assertions))] use crate::Inspector; use crate::{ Action, AnyDrag, AnyElement, AnyImageCache, AnyTooltip, AnyView, App, AppContext, Arena, Asset, AsyncWindowContext, AvailableSpace, Background, BorderStyle, Bounds, BoxShadow, Capslock, Context, Corners, 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::*, 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}; 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::{AtomicUsize, Ordering::SeqCst}, }, time::Duration, }; use uuid::Uuid; mod prompts; use crate::util::atomic_incr_if_not_zero; pub use prompts::*; /// Default window size used when no explicit size is provided. pub const DEFAULT_WINDOW_SIZE: Size<Pixels> = size(px(1536.), px(864.)); /// 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>, } #[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(), })), } } pub fn invalidate_view(&self, entity: EntityId, cx: &mut App) -> bool { let mut inner = self.inner.borrow_mut(); inner.dirty_views.insert(entity); if inner.draw_phase == DrawPhase::None { 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) { self.inner.borrow_mut().dirty = dirty } pub fn set_phase(&self, phase: DrawPhase) { self.inner.borrow_mut().draw_phase = phase } 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) }; } /// 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) } }) } /// RAII guard that sets CURRENT_ELEMENT_ARENA for the duration of a draw operation. /// When dropped, restores the previous arena (supporting nested draws). pub(crate) struct ElementArenaScope { previous: Option<*const RefCell<Arena>>, } impl ElementArenaScope { /// Enter a scope where element allocations use the given arena. pub(crate) fn enter(arena: &RefCell<Arena>) -> Self { let previous = CURRENT_ELEMENT_ARENA.with(|current| { let prev = current.get(); current.set(Some(arena as *const RefCell<Arena>)); prev }); Self { previous } } } impl Drop for ElementArenaScope { fn drop(&mut self) { CURRENT_ELEMENT_ARENA.with(|current| { current.set(self.previous); }); } } /// Returned when the element arena has been used and so must be cleared before the next draw. #[must_use] pub struct ArenaClearNeeded { arena: *const RefCell<Arena>, } impl ArenaClearNeeded { /// Create a new ArenaClearNeeded that will clear the given arena. pub(crate) fn new(arena: &RefCell<Arena>) -> Self { Self { arena: arena as *const RefCell<Arena>, } } /// Clear the element arena. pub fn clear(self) { // SAFETY: The arena pointer is valid because ArenaClearNeeded is created // at the end of draw() and must be cleared before the next draw. let arena_cell = unsafe { &*self.arena }; arena_cell.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)?; if atomic_incr_if_not_zero(&focus.ref_count) == 0 { return None; } Some(Self { id, tab_index: focus.tab_index, tab_stop: focus.tab_stop, handles: handles.clone(), }) } /// Sets the tab index of the element associated with this handle. pub fn tab_index(mut self, index: isize) -> Self { self.tab_index = index; if let Some(focus) = self.handles.write().get_mut(self.id) { focus.tab_index = index; } self } /// Sets whether the element associated with this handle is a tab stop. /// /// When `false`, the element will not be included in the tab order. pub fn tab_stop(mut self, tab_stop: bool) -> Self { self.tab_stop = tab_stop; if let Some(focus) = self.handles.write().get_mut(self.id) { focus.tab_stop = tab_stop; } self } /// Converts this focus handle into a weak variant, which does not prevent it from being released. pub fn downgrade(&self) -> WeakFocusHandle { WeakFocusHandle { id: self.id, handles: Arc::downgrade(&self.handles), } } /// Moves the focus to the element associated with this handle. pub fn focus(&self, window: &mut Window, cx: &mut App) { window.focus(self, cx) } /// Obtains whether the element associated with this handle is currently focused. pub fn is_focused(&self, window: &Window) -> bool { self.id.is_focused(window) } /// 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 { self.id.contains_focused(window, cx) } /// 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: &mut App) -> bool { self.id.within_focused(window, cx) } /// Obtains whether this handle contains the given handle in the most recently rendered frame. pub fn contains(&self, other: &Self, window: &Window) -> bool { self.id.contains(other.id, window) } /// Dispatch an action on the element that rendered this focus handle pub fn dispatch_action(&self, action: &dyn Action, window: &mut Window, cx: &mut App) { if let Some(node_id) = window .rendered_frame .dispatch_tree .focusable_node_id(self.id) { window.dispatch_action_on_node(node_id, action, cx) } } } impl Clone for FocusHandle { fn clone(&self) -> Self { Self::for_id(self.id, &self.handles).unwrap() } } impl PartialEq for FocusHandle { fn eq(&self, other: &Self) -> bool { self.id == other.id } } impl Eq for FocusHandle {} impl Drop for FocusHandle { fn drop(&mut self) { self.handles .read() .get(self.id) .unwrap() .ref_count .fetch_sub(1, SeqCst); } } /// A weak reference to a focus handle. #[derive(Clone, Debug)] pub struct WeakFocusHandle { pub(crate) id: FocusId, pub(crate) handles: Weak<FocusMap>, } impl WeakFocusHandle { /// Attempts to upgrade the [WeakFocusHandle] to a [FocusHandle]. pub fn upgrade(&self) -> Option<FocusHandle> { let handles = self.handles.upgrade()?; FocusHandle::for_id(self.id, &handles) } } impl PartialEq for WeakFocusHandle { fn eq(&self, other: &WeakFocusHandle) -> bool { self.id == other.id } } impl Eq for WeakFocusHandle {} impl PartialEq<FocusHandle> for WeakFocusHandle { fn eq(&self, other: &FocusHandle) -> bool { self.id == other.id } } impl PartialEq<WeakFocusHandle> for FocusHandle {